]> granicus.if.org Git - libevent/commitdiff
Add a function to change a listener's callback.
authorNick Mathewson <nickm@torproject.org>
Mon, 25 Oct 2010 15:47:05 +0000 (11:47 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 25 Oct 2010 15:47:05 +0000 (11:47 -0400)
You can also now initialize listeners with no callbacks set; if so,
they won't get enabled until the callback is set to non-NULL.

include/event2/listener.h
listener.c

index dededc5060f8ac46d61a9875d9c26d25ba55f43d..0cb8583ccdfa2b55d6c8bff2d64ed8c6e3471fc2 100644 (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);
index 1ff0f491ff891ce74d0bb5a372671e5051efb498..3052169d8701d9c126f8ed44ba2ced253d486180 100644 (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]);