From: Marek VavruĊĦa Date: Wed, 7 Oct 2015 09:45:47 +0000 (+0200) Subject: daemon/network: fixed early free with async close X-Git-Tag: v1.0.0-beta1~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9db469c9e862ffdf7cbc7412c52e420a149bfea6;p=thirdparty%2Fknot-resolver.git daemon/network: fixed early free with async close --- diff --git a/daemon/io.c b/daemon/io.c index 79d57bdac..272b589b7 100644 --- a/daemon/io.c +++ b/daemon/io.c @@ -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) { diff --git a/daemon/io.h b/daemon/io.h index 35e882dc1..b47805a60 100644 --- a/daemon/io.h +++ b/daemon/io.h @@ -19,11 +19,8 @@ #include #include -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 diff --git a/daemon/network.c b/daemon/network.c index 81a528fcc..fe76f73e3 100644 --- a/daemon/network.c +++ b/daemon/network.c @@ -36,20 +36,36 @@ 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; } diff --git a/daemon/network.h b/daemon/network.h index 190e84871..93c80ce04 100644 --- a/daemon/network.h +++ b/daemon/network.h @@ -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; };