]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/network: fixed early free with async close
authorMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 7 Oct 2015 09:45:47 +0000 (11:45 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 7 Oct 2015 09:45:47 +0000 (11:45 +0200)
daemon/io.c
daemon/io.h
daemon/network.c
daemon/network.h

index 79d57bdac4f3ca353f601c75292248713dedae2b..272b589b75033ff0d378aa3d8f94b9d26c75397d 100644 (file)
@@ -66,9 +66,8 @@ void udp_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
        mp_flush(worker->pkt_pool.ctx);
 }
 
-int udp_bind(struct endpoint *ep, struct sockaddr *addr)
+int udp_bind(uv_udp_t *handle, struct sockaddr *addr)
 {
-       uv_udp_t *handle = &ep->udp;
        unsigned flags = UV_UDP_REUSEADDR;
        if (addr->sa_family == AF_INET6) {
                flags |= UV_UDP_IPV6ONLY;
@@ -82,12 +81,6 @@ int udp_bind(struct endpoint *ep, struct sockaddr *addr)
        return io_start_read((uv_handle_t *)handle);
 }
 
-void udp_unbind(struct endpoint *ep)
-{
-       uv_udp_t *handle = &ep->udp;
-       uv_close((uv_handle_t *)handle, NULL);
-}
-
 static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
 {
        uv_loop_t *loop = handle->loop;
@@ -143,9 +136,8 @@ static void tcp_accept(uv_stream_t *master, int status)
        io_start_read((uv_handle_t *)client);
 }
 
-int tcp_bind(struct endpoint *ep, struct sockaddr *addr)
+int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr)
 {
-       uv_tcp_t *handle = &ep->tcp;
        unsigned flags = UV_UDP_REUSEADDR;
        if (addr->sa_family == AF_INET6) {
                flags |= UV_UDP_IPV6ONLY;
@@ -157,7 +149,6 @@ int tcp_bind(struct endpoint *ep, struct sockaddr *addr)
 
        ret = uv_listen((uv_stream_t *)handle, 16, tcp_accept);
        if (ret != 0) {
-               tcp_unbind(ep);
                return ret;
        }
 
@@ -165,11 +156,6 @@ int tcp_bind(struct endpoint *ep, struct sockaddr *addr)
        return 0;
 }
 
-void tcp_unbind(struct endpoint *ep)
-{
-       uv_close((uv_handle_t *)&ep->tcp, NULL);
-}
-
 void io_create(uv_loop_t *loop, uv_handle_t *handle, int type)
 {
        if (type == SOCK_DGRAM) {
index 35e882dc163028b7a4cefe87143ed615f1d39f4e..b47805a6035a16b6721cef4c6975158d6a0b7fa6 100644 (file)
 #include <uv.h>
 #include <libknot/packet/pkt.h>
 
-struct endpoint;
-int udp_bind(struct endpoint *ep, struct sockaddr *addr);
-void udp_unbind(struct endpoint *ep);
-int tcp_bind(struct endpoint *ep, struct sockaddr *addr);
-void tcp_unbind(struct endpoint *ep);
+int udp_bind(uv_udp_t *handle, struct sockaddr *addr);
+int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr);
 void io_create(uv_loop_t *loop, uv_handle_t *handle, int type);
 int io_start_read(uv_handle_t *handle);
 int io_stop_read(uv_handle_t *handle);
\ No newline at end of file
index 81a528fccff4eb61b0b43bb14104b9bd53e2679b..fe76f73e37d8ac528d9928e445c320bc1a0268ae 100644 (file)
 void network_init(struct network *net, uv_loop_t *loop)
 {
        if (net != NULL) {
-               /* No multiplexing now, I/O in single thread. */
                net->loop = loop;
                net->endpoints = map_make();
        }
 }
 
-/** Close endpoint protocols. */
-static int close_endpoint(struct endpoint *ep)
+static void free_handle(uv_handle_t *handle)
 {
-       if (ep->flags & NET_UDP) {
-               udp_unbind(ep);
+       free(handle);
+}
+
+static void close_handle(uv_handle_t *handle, bool force)
+{
+       if (force) { /* Force close if event loop isn't running. */
+               uv_os_fd_t fd = 0;
+               if (uv_fileno(handle, &fd) == 0) {
+                       close(fd);
+               }
+               free_handle(handle);
+       } else { /* Asynchronous close */
+               uv_close(handle, free_handle);
+       }
+}
+
+static int close_endpoint(struct endpoint *ep, bool force)
+{
+       if (ep->udp) {
+               close_handle((uv_handle_t *)ep->udp, force);
        }
-       if (ep->flags & NET_TCP) {
-               tcp_unbind(ep);
+       if (ep->tcp) {
+               close_handle((uv_handle_t *)ep->tcp, force);
        }
 
        free(ep);
@@ -57,12 +73,11 @@ static int close_endpoint(struct endpoint *ep)
 }
 
 /** Endpoint visitor (see @file map.h) */
-static int visit_key(const char *key, void *val, void *ext)
+static int close_key(const char *key, void *val, void *ext)
 {
-       int (*callback)(struct endpoint *) = ext;
        endpoint_array_t *ep_array = val;
        for (size_t i = ep_array->len; i--;) {
-               callback(ep_array->at[i]);
+               close_endpoint(ep_array->at[i], true);
        }
        return 0;
 }
@@ -78,7 +93,7 @@ static int free_key(const char *key, void *val, void *ext)
 void network_deinit(struct network *net)
 {
        if (net != NULL) {
-               map_walk(&net->endpoints, visit_key, close_endpoint);
+               map_walk(&net->endpoints, close_key, 0);
                map_walk(&net->endpoints, free_key, 0);
                map_clear(&net->endpoints);
        }
@@ -111,16 +126,24 @@ static int insert_endpoint(struct network *net, const char *addr, struct endpoin
 static int open_endpoint(struct network *net, struct endpoint *ep, struct sockaddr *sa, uint32_t flags)
 {
        if (flags & NET_UDP) {
-               handle_init(udp, net->loop, &ep->udp, sa->sa_family);
-               int ret = udp_bind(ep, sa);
+               ep->udp = malloc(sizeof(*ep->udp));
+               if (!ep->udp) {
+                       return kr_error(ENOMEM);
+               }
+               handle_init(udp, net->loop, ep->udp, sa->sa_family);
+               int ret = udp_bind(ep->udp, sa);
                if (ret != 0) {
                        return ret;
                }
                ep->flags |= NET_UDP;
        }
        if (flags & NET_TCP) {
-               handle_init(tcp, net->loop, &ep->tcp, sa->sa_family);
-               int ret = tcp_bind(ep, sa);
+               ep->tcp = malloc(sizeof(*ep->tcp));
+               if (!ep->tcp) {
+                       return kr_error(ENOMEM);
+               }
+               handle_init(tcp, net->loop, ep->tcp, sa->sa_family);
+               int ret = tcp_bind(ep->tcp, sa);
                if (ret != 0) {
                        return ret;
                }
@@ -135,6 +158,11 @@ int network_listen(struct network *net, const char *addr, uint16_t port, uint32_
                return kr_error(EINVAL);
        }
 
+       /* Already listening */
+       if (map_get(&net->endpoints, addr)) {
+               return kr_ok();
+       }
+
        /* Parse address. */
        int ret = 0;
        struct sockaddr_storage sa;
@@ -157,7 +185,7 @@ int network_listen(struct network *net, const char *addr, uint16_t port, uint32_
                ret = insert_endpoint(net, addr, ep);
        }
        if (ret != 0) {
-               close_endpoint(ep);
+               close_endpoint(ep, false);
        }
 
        return ret;
@@ -174,7 +202,7 @@ int network_close(struct network *net, const char *addr, uint16_t port)
        for (size_t i = ep_array->len; i--;) {
                struct endpoint *ep = ep_array->at[i];
                if (ep->port == port) {
-                       close_endpoint(ep);
+                       close_endpoint(ep, false);
                        array_del(*ep_array, i);
                        break;
                }
index 190e848711a7e535f156b2398abce67a6c64ecc1..93c80ce04a39b86d884420f66aec1682e7dfba7b 100644 (file)
@@ -28,8 +28,8 @@ enum endpoint_flag {
 };
 
 struct endpoint {
-    uv_udp_t udp;
-    uv_tcp_t tcp;
+    uv_udp_t *udp;
+    uv_tcp_t *tcp;
     uint16_t port;
     uint16_t flags;
 };