server; test that binding multiple sockets works.
svn:r769
* 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.
/* 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;
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*
http->timeout = -1;
+ TAILQ_INIT(&http->sockets);
TAILQ_INIT(&http->callbacks);
TAILQ_INIT(&http->connections);
{
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 */
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);
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");
}