diff --git a/include/event2/listener.h b/include/event2/listener.h index dededc50..0cb8583c 100644 --- a/include/event2/listener.h +++ b/include/event2/listener.h @@ -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); diff --git a/listener.c b/listener.c index 1ff0f491..3052169d 100644 --- a/listener.c +++ b/listener.c @@ -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]);