]> granicus.if.org Git - libevent/commitdiff
fix a bug where it was not possible to bind multiple sockets to the same http
authorNiels Provos <provos@gmail.com>
Sun, 4 May 2008 22:21:29 +0000 (22:21 +0000)
committerNiels Provos <provos@gmail.com>
Sun, 4 May 2008 22:21:29 +0000 (22:21 +0000)
server; test that binding multiple sockets works.

svn:r769

evhttp.h
http-internal.h
http.c
test/regress_http.c

index 647697627127b01ee557ae6966d6706448db4b3d..6f53d2e46e80d9b84c05f3e062df541a7fb52d97 100644 (file)
--- 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.
index 96d1f77080303d8f3bbe500bccc250168a99f78d..c5bd5ddfec393c9350419a5aca1431efc0de29d5 100644 (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;
diff --git a/http.c b/http.c
index 8713ea315a4e108ba5b19dd6cd791dc836c261fb..9f0c4f013efe31bf1d91726c51ec0f6bca911a66 100644 (file)
--- 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 */
index 8b3ba674ac783e706c5f83f22c5b1361f0dce5ab..cd3330cfcae8fb4fec3a611c62e3ea9ae3aee80c 100644 (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");
 }