diff --git a/bin/named/tcpclient.c b/bin/named/tcpclient.c index 9b98286834..09e157dd31 100644 --- a/bin/named/tcpclient.c +++ b/bin/named/tcpclient.c @@ -60,6 +60,7 @@ static void tcp_send(isc_task_t *task, isc_event_t *event); static void tcp_recv_len(isc_task_t *task, isc_event_t *event); static void tcp_recv_req(isc_task_t *task, isc_event_t *event); static void tcp_accept(isc_task_t *task, isc_event_t *event); +static void tcp_listener_free(tcp_listener_t **lp); static tcp_cctx_t * tcp_cctx_allocate(isc_mem_t *mctx) @@ -112,24 +113,26 @@ tcp_restart(isc_task_t *task, tcp_cctx_t *ctx) isc_mem_stats(ctx->mctx, stdout); } +/* + * A worker task is shutting down, presumably because the + * socket has been shut down. + */ static void tcp_shutdown(isc_task_t *task, isc_event_t *event) { tcp_cctx_t *ctx; tcp_listener_t *l; + isc_boolean_t free_listener = ISC_FALSE; ctx = (tcp_cctx_t *)(event->arg); l = ctx->parent; LOCK(&l->lock); - if (ctx->csock != NULL) - isc_socket_detach(&ctx->csock); - REQUIRE(l->nwactive > 0); /* - * remove our task from the list of tasks that the listener + * Remove our task from the list of tasks that the listener * maintains by setting things to NULL, then freeing the * pointers we maintain. */ @@ -139,16 +142,29 @@ tcp_shutdown(isc_task_t *task, isc_event_t *event) l->nwactive--; + if (l->nwactive == 0) + free_listener = ISC_TRUE; + UNLOCK(&l->lock); #ifdef NOISY printf("Final shutdown slot %u\n", ctx->slot); #endif + + /* This is where the pointers are freed. */ tcp_cctx_free(ctx); + isc_task_detach(&task); isc_event_free(&event); + + if (free_listener) + tcp_listener_free(&l); } +/* + * We have received the 2-byte length prefix (or a socket shutdown + * request). + */ static void tcp_recv_len(isc_task_t *task, isc_event_t *event) { @@ -209,6 +225,9 @@ tcp_recv_len(isc_task_t *task, isc_event_t *event) isc_event_free(&event); } +/* + * We have received the actual request data. + */ static void tcp_recv_req(isc_task_t *task, isc_event_t *event) { @@ -419,6 +438,18 @@ tcp_listener_allocate(isc_mem_t *mctx, u_int nwmax) return (l); } +static void +tcp_listener_free(tcp_listener_t **lp) +{ + tcp_listener_t *l = *lp; + isc_mem_put(l->mctx, l->ctxs, sizeof(tcp_cctx_t *) * l->nwmax); + isc_mem_put(l->mctx, l->tasks, sizeof(isc_task_t *) * l->nwmax); + isc_mutex_destroy(&l->lock); + isc_mem_put(l->mctx, l, sizeof(tcp_listener_t)); + *lp = NULL; +} + + isc_result_t tcp_listener_start(tcp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, diff --git a/bin/named/tcpclient.h b/bin/named/tcpclient.h index b24bd4dba2..14816b083c 100644 --- a/bin/named/tcpclient.h +++ b/bin/named/tcpclient.h @@ -55,3 +55,10 @@ isc_result_t tcp_listener_start(tcp_listener_t *l, dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, unsigned int)); +/* + * Notes: + * There is no need to hold on to the udp_listener_t * after starting + * the listener, and here is no need to shut down the listener explicitly. + * It will shut down itself and free its resources when its socket is + * shut down. + */ diff --git a/bin/named/udpclient.c b/bin/named/udpclient.c index 9ccc0e58a0..37099243d4 100644 --- a/bin/named/udpclient.c +++ b/bin/named/udpclient.c @@ -52,7 +52,7 @@ static void udp_cctx_free(udp_cctx_t *ctx); static void udp_send(isc_task_t *task, isc_event_t *event); static void udp_recv(isc_task_t *task, isc_event_t *event); - +static void udp_listener_free(udp_listener_t **lp); static udp_cctx_t * @@ -83,12 +83,16 @@ udp_cctx_free(udp_cctx_t *ctx) isc_mem_put(ctx->mctx, ctx, sizeof(udp_cctx_t)); } +/* + * A worker task is shutting down, presumably because the + * socket has been shut down. + */ static void udp_shutdown(isc_task_t *task, isc_event_t *event) { udp_cctx_t *ctx; udp_listener_t *l; - isc_socket_t *sock; + isc_boolean_t free_listener = ISC_FALSE; ctx = (udp_cctx_t *)(event->arg); l = ctx->parent; @@ -98,29 +102,40 @@ udp_shutdown(isc_task_t *task, isc_event_t *event) REQUIRE(l->nwactive > 0); /* - * remove our task from the list of tasks that the listener + * Remove our task from the list of tasks that the listener * maintains by setting things to NULL, then freeing the * pointers we maintain. */ INSIST(l->tasks[ctx->slot] == task); l->tasks[ctx->slot] = NULL; + INSIST(l->ctxs[ctx->slot] == ctx); l->ctxs[ctx->slot] = NULL; l->nwactive--; - sock = l->sock; - isc_socket_detach(&sock); + if (l->nwactive == 0) + free_listener = ISC_TRUE; UNLOCK(&l->lock); #ifdef NOISY printf("Final shutdown slot %u\n", ctx->slot); #endif + + /* This is where the pointers are freed. */ udp_cctx_free(ctx); + isc_task_detach(&task); isc_event_free(&event); + + if (free_listener) + udp_listener_free(&l); } +/* + * We got the data we were waiting to receive, or + * a socket shutdown request. + */ static void udp_recv(isc_task_t *task, isc_event_t *event) { @@ -157,13 +172,21 @@ udp_recv(isc_task_t *task, isc_event_t *event) result = ctx->parent->dispatch(ctx->mctx, ®ion, 0); if (result == DNS_R_SUCCESS) { + /* Send a reply as soon as the socket is ready to do so. */ isc_socket_sendto(sock, ®ion, task, udp_send, ctx, &dev->address, dev->addrlength); + } else { + /* Send no reply, just wait for the next request. */ + isc_socket_recv(sock, ®ion, ISC_FALSE, task, udp_recv, ctx); } isc_event_free(&event); } +/* + * The data we were waiting to send was sent, or we got a socket + * shutdown request. + */ static void udp_send(isc_task_t *task, isc_event_t *event) { @@ -234,6 +257,19 @@ udp_listener_allocate(isc_mem_t *mctx, u_int nwmax) return (l); } +static void +udp_listener_free(udp_listener_t **lp) +{ + udp_listener_t *l = *lp; + isc_mem_put(l->mctx, l->ctxs, sizeof(udp_cctx_t *) * l->nwmax); + l->ctxs = NULL; + isc_mem_put(l->mctx, l->tasks, sizeof(isc_task_t *) * l->nwmax); + l->tasks = NULL; + isc_mutex_destroy(&l->lock); + isc_mem_put(l->mctx, l, sizeof(udp_listener_t)); + *lp = NULL; +} + isc_result_t udp_listener_start(udp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, diff --git a/bin/named/udpclient.h b/bin/named/udpclient.h index a461bc761c..3aea5f10a7 100644 --- a/bin/named/udpclient.h +++ b/bin/named/udpclient.h @@ -55,3 +55,10 @@ isc_result_t udp_listener_start(udp_listener_t *l, dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, unsigned int)); +/* + * Notes: + * There is no need to hold on to the udp_listener_t * after starting + * the listener, and here is no need to shut down the listener explicitly. + * It will shut down itself and free its resources when its socket is + * shut down. + */