From f940eb4b8d26f677af4bcaa21ed98cfdb9db0acc Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sun, 4 May 2008 22:21:29 +0000 Subject: [PATCH] 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 --- evhttp.h | 3 +++ http-internal.h | 9 ++++++++- http.c | 39 +++++++++++++++++++++++++++++++++------ test/regress_http.c | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/evhttp.h b/evhttp.h index 64769762..6f53d2e4 100644 --- a/evhttp.h +++ b/evhttp.h @@ -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. diff --git a/http-internal.h b/http-internal.h index 96d1f770..c5bd5ddf 100644 --- a/http-internal.h +++ b/http-internal.h @@ -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; diff --git a/http.c b/http.c index 8713ea31..9f0c4f01 100644 --- a/http.c +++ b/http.c @@ -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); + + res = event_add(ev, NULL); + + if (res == -1) { + mm_free(bound); + return (-1); + } - return (event_add(ev, NULL)); + 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 */ diff --git a/test/regress_http.c b/test/regress_http.c index 8b3ba674..cd3330cf 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -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"); } -- 2.40.0