Merge remote branch 'github/http_and_listener'

This commit is contained in:
Nick Mathewson 2010-10-25 15:13:32 -04:00
commit 9c71a3413a
4 changed files with 83 additions and 22 deletions

38
http.c
View File

@ -2764,23 +2764,35 @@ evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd)
const int flags =
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE;
listener = evconnlistener_new(http->base, NULL, NULL,
flags,
0, /* Backlog is '0' because we already said 'listen' */
fd);
if (!listener)
return (NULL);
bound = evhttp_bind_listener(http, listener);
if (!bound) {
evconnlistener_free(listener);
return (NULL);
}
return (bound);
}
struct evhttp_bound_socket *
evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
{
struct evhttp_bound_socket *bound;
bound = mm_malloc(sizeof(struct evhttp_bound_socket));
if (bound == NULL)
return (NULL);
listener = evconnlistener_new(http->base, accept_socket_cb, http,
flags,
0, /* Backlog is '0' because we already said 'listen' */
fd);
if (!listener) {
mm_free(bound);
return (NULL);
}
bound->listener = listener;
TAILQ_INSERT_TAIL(&http->sockets, bound, next);
return (bound);
evconnlistener_set_cb(listener, accept_socket_cb, http);
return bound;
}
evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
@ -2788,6 +2800,12 @@ evutil_socket_t evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound)
return evconnlistener_get_fd(bound->listener);
}
struct evconnlistener *
evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
{
return bound->listener;
}
void
evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
{

View File

@ -63,6 +63,7 @@ struct evhttp;
struct evhttp_request;
struct evkeyvalq;
struct evhttp_bound_socket;
struct evconnlistener;
/**
* Create a new HTTP server.
@ -130,6 +131,18 @@ int evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd);
*/
struct evhttp_bound_socket *evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd);
/**
* The most low-level evhttp_bind/accept method: takes an evconnlistener, and
* returns an evhttp_bound_socket. The listener will be freed when the bound
* socket is freed.
*/
struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener);
/**
* Return the listener used to implement a bound socket.
*/
struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound);
/**
* Makes an HTTP server stop accepting connections on the specified socket
*

View File

@ -75,7 +75,9 @@ typedef void (*evconnlistener_errorcb)(struct evconnlistener *, void *);
on a given file descriptor.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
@ -93,7 +95,9 @@ struct evconnlistener *evconnlistener_new(struct event_base *base,
on a given address.
@param base The event base to associate the listener with.
@param cb A callback to be invoked when a new connection arrives.
@param cb A callback to be invoked when a new connection arrives. If the
callback is NULL, the listener will be treated as disabled until the
callback is set.
@param ptr A user-supplied pointer to give to the callback.
@param flags Any number of LEV_OPT_* flags
@param backlog Passed to the listen() call to determine the length of the
@ -123,6 +127,11 @@ struct event_base *evconnlistener_get_base(struct evconnlistener *lev);
/** Return the socket that an evconnlistner is listening on. */
evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
/** Change the callback on the listener to cb and its user_data to arg.
*/
void evconnlistener_set_cb(struct evconnlistener *lev,
evconnlistener_cb cb, void *arg);
/** Set an evconnlistener's error callback. */
void evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb);

View File

@ -73,7 +73,8 @@ struct evconnlistener {
evconnlistener_errorcb errorcb;
void *user_data;
unsigned flags;
int refcnt;
short refcnt;
unsigned enabled : 1;
};
struct evconnlistener_event {
@ -89,7 +90,6 @@ struct evconnlistener_iocp {
struct event_iocp_port *port;
short n_accepting;
unsigned shutting_down : 1;
unsigned enabled : 1;
struct accepting_socket **accepting;
};
#endif
@ -185,6 +185,7 @@ evconnlistener_new(struct event_base *base,
event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST,
listener_read_cb, lev);
evconnlistener_enable(&lev->base);
return &lev->base;
@ -268,7 +269,11 @@ evconnlistener_enable(struct evconnlistener *lev)
{
int r;
LOCK(lev);
r = lev->ops->enable(lev);
lev->enabled = 1;
if (lev->cb)
r = lev->ops->enable(lev);
else
r = 0;
UNLOCK(lev);
return r;
}
@ -278,6 +283,7 @@ evconnlistener_disable(struct evconnlistener *lev)
{
int r;
LOCK(lev);
lev->enabled = 0;
r = lev->ops->disable(lev);
UNLOCK(lev);
return r;
@ -335,7 +341,23 @@ event_listener_getbase(struct evconnlistener *lev)
return event_get_base(&lev_e->listener);
}
void evconnlistener_set_error_cb(struct evconnlistener *lev,
void
evconnlistener_set_cb(struct evconnlistener *lev,
evconnlistener_cb cb, void *arg)
{
int enable = 0;
LOCK(lev);
if (lev->enabled && !lev->cb)
enable = 1;
lev->cb = cb;
lev->user_data = arg;
if (enable)
evconnlistener_enable(lev);
UNLOCK(lev);
}
void
evconnlistener_set_error_cb(struct evconnlistener *lev,
evconnlistener_errorcb errorcb)
{
LOCK(lev);
@ -474,7 +496,7 @@ start_accepting(struct accepting_socket *as)
SOCKET s = socket(as->family, SOCK_STREAM, 0);
int error = 0;
if (!as->lev->enabled)
if (!as->lev->base.enabled)
return 0;
if (s == INVALID_SOCKET) {
@ -574,7 +596,7 @@ accepted_socket_invoke_user_cb(struct deferred_cb *dcb, void *arg)
if (errorcb) {
WSASetLastError(error);
errorcb(lev, data);
} else {
} else if (cb) {
cb(lev, sock, sa_remote, socklen_remote, data);
}
@ -638,7 +660,6 @@ iocp_listener_enable(struct evconnlistener *lev)
EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
LOCK(lev);
lev_iocp->enabled = 1;
for (i = 0; i < lev_iocp->n_accepting; ++i) {
struct accepting_socket *as = lev_iocp->accepting[i];
if (!as)
@ -660,7 +681,6 @@ iocp_listener_disable_impl(struct evconnlistener *lev, int shutdown)
EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base);
LOCK(lev);
lev_iocp->enabled = 0;
for (i = 0; i < lev_iocp->n_accepting; ++i) {
struct accepting_socket *as = lev_iocp->accepting[i];
if (!as)
@ -760,11 +780,12 @@ evconnlistener_new_async(struct event_base *base,
lev->base.user_data = ptr;
lev->base.flags = flags;
lev->base.refcnt = 1;
lev->base.enabled = 1;
lev->port = event_base_get_iocp(base);
lev->fd = fd;
lev->event_base = base;
lev->enabled = 1;
if (event_iocp_port_associate(lev->port, fd, 1) < 0)
goto err_free_lev;
@ -784,7 +805,7 @@ evconnlistener_new_async(struct event_base *base,
event_warnx("Couldn't create accepting socket");
goto err_free_accepting;
}
if (start_accepting(lev->accepting[i]) < 0) {
if (cb && start_accepting(lev->accepting[i]) < 0) {
event_warnx("Couldn't start accepting on socket");
EnterCriticalSection(&lev->accepting[i]->lock);
free_and_unlock_accepting_socket(lev->accepting[i]);