fix a bug where it was not possible to bind multiple sockets to the same http

server; test that binding multiple sockets works.


svn:r769
This commit is contained in:
Niels Provos 2008-05-04 22:21:29 +00:00
parent 5786d5255a
commit f940eb4b8d
4 changed files with 77 additions and 9 deletions

View File

@ -97,6 +97,9 @@ int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
* descriptor passing in situations where an http servers does not have
* permissions to bind to a low-numbered port.
*
* Can be called multiple times to have the http server listen to
* multiple different sockets.
*
* @param http a pointer to an evhttp object
* @param fd a socket fd that is ready for accepting connections
* @return 0 on success, -1 on failure.

View File

@ -91,8 +91,15 @@ struct evhttp_cb {
/* both the http server as well as the rpc system need to queue connections */
TAILQ_HEAD(evconq, evhttp_connection);
/* each bound socket is stored in one of these */
struct evhttp_bound_socket {
TAILQ_ENTRY(evhttp_bound_socket) (next);
struct event bind_ev;
};
struct evhttp {
struct event bind_ev;
TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
struct evconq connections;

39
http.c
View File

@ -1976,12 +1976,30 @@ evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
int
evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd)
{
struct event *ev = &http->bind_ev;
struct evhttp_bound_socket *bound;
struct event *ev;
int res;
bound = mm_malloc(sizeof(struct evhttp_bound_socket));
if (bound == NULL)
return (-1);
ev = &bound->bind_ev;
/* Schedule the socket for accepting */
event_assign(ev, http->base, fd, EV_READ | EV_PERSIST, accept_socket, http);
event_assign(ev, http->base,
fd, EV_READ | EV_PERSIST, accept_socket, http);
return (event_add(ev, NULL));
res = event_add(ev, NULL);
if (res == -1) {
mm_free(bound);
return (-1);
}
TAILQ_INSERT_TAIL(&http->sockets, bound, next);
return (0);
}
static struct evhttp*
@ -1996,6 +2014,7 @@ evhttp_new_object(void)
http->timeout = -1;
TAILQ_INIT(&http->sockets);
TAILQ_INIT(&http->callbacks);
TAILQ_INIT(&http->connections);
@ -2034,11 +2053,19 @@ evhttp_free(struct evhttp* http)
{
struct evhttp_cb *http_cb;
struct evhttp_connection *evcon;
evutil_socket_t fd = http->bind_ev.ev_fd;
struct evhttp_bound_socket *bound;
evutil_socket_t fd;
/* Remove the accepting part */
event_del(&http->bind_ev);
EVUTIL_CLOSESOCKET(fd);
while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
TAILQ_REMOVE(&http->sockets, bound, next);
fd = bound->bind_ev.ev_fd;
event_del(&bound->bind_ev);
EVUTIL_CLOSESOCKET(fd);
mm_free(bound);
}
while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
/* evhttp_connection_free removes the connection */

View File

@ -261,6 +261,12 @@ http_basic_test(void)
fprintf(stdout, "Testing Basic HTTP Server: ");
http = http_setup(&port, NULL);
/* bind to a second socket */
if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
fprintf(stdout, "FAILED (bind)\n");
exit(1);
}
fd = http_connect("127.0.0.1", port);
@ -278,16 +284,41 @@ http_basic_test(void)
event_dispatch();
if (test_ok != 2) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/* connect to the second port */
bufferevent_free(bev);
close(fd);
fd = http_connect("127.0.0.1", port + 1);
/* Stupid thing to send a request */
bev = bufferevent_new(fd, http_readcb, http_writecb,
http_errorcb, NULL);
http_request =
"GET /test HTTP/1.1\r\n"
"Host: somehost\r\n"
"Connection: close\r\n"
"\r\n";
bufferevent_write(bev, http_request, strlen(http_request));
event_dispatch();
bufferevent_free(bev);
close(fd);
evhttp_free(http);
if (test_ok != 2) {
if (test_ok != 4) {
fprintf(stdout, "FAILED\n");
exit(1);
}
fprintf(stdout, "OK\n");
}