diff --git a/bin/named/client.c b/bin/named/client.c index 4a7b8f2ce7..75db7fd15a 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -1038,20 +1038,17 @@ ns_client_replace(ns_client_t *client) { isc_result_t result; CTRACE("replace"); - if (TCP_CLIENT(client)) { - result = ns_clientmgr_accepttcp(client->manager, - 1, client->interface); - } else { - result = ns_clientmgr_addtodispatch(client->manager, - 1, client->interface); - } + result = ns_clientmgr_createclients(client->manager, + 1, client->interface, + (TCP_CLIENT(client) ? + ISC_TRUE : ISC_FALSE)); if (result != ISC_R_SUCCESS) return (result); /* - * The new client is ready to listen for new requests, therefore we - * should refrain from listening from any more requests when we are - * done with this one. + * The responsibility for listening for new requests is hereby + * transferred to the new client. Therefore, the old client + * should refrain from listening for any more requests. */ client->mortal = ISC_TRUE; @@ -1141,8 +1138,8 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) { } isc_result_t -ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp) +ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, + ns_interface_t *ifp, isc_boolean_t tcp) { isc_result_t result = ISC_R_SUCCESS; unsigned int i; @@ -1151,7 +1148,7 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, REQUIRE(VALID_MANAGER(manager)); REQUIRE(n > 0); - MTRACE("addtodispatch"); + MTRACE("createclients"); /* * We MUST lock the manager lock for the entire client creation @@ -1166,15 +1163,24 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, result = client_create(manager, ifp, &client); if (result != ISC_R_SUCCESS) break; - dns_dispatch_attach(ifp->udpdispatch, &client->dispatch); - result = dns_dispatch_addrequest(client->dispatch, - client->task, - client_request, - client, &client->dispentry); - if (result != ISC_R_SUCCESS) { - client->shuttingdown = ISC_TRUE; - maybe_free(client); /* Will free immediately. */ - break; + if (tcp) { + client->attributes |= NS_CLIENTATTR_TCP; + isc_socket_attach(ifp->tcpsocket, &client->tcplistener); + client_accept(client); + } else { + dns_dispatch_attach(ifp->udpdispatch, &client->dispatch); + result = dns_dispatch_addrequest(client->dispatch, + client->task, + client_request, + client, &client->dispentry); + if (result != ISC_R_SUCCESS) { + isc_log_write(dns_lctx, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), + "dns_dispatch_addrequest() failed: %s", + isc_result_totext(result)); + isc_task_shutdown(client->task); + break; + } } client->manager = manager; ISC_LIST_APPEND(manager->clients, client, link); @@ -1193,63 +1199,6 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, return (result); } -isc_result_t -ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp) -{ - isc_result_t result = ISC_R_SUCCESS; - unsigned int i; - ns_client_t *client; - - REQUIRE(VALID_MANAGER(manager)); - REQUIRE(n > 0); - - MTRACE("accepttcp"); - - /* - * XXXRTH - * - * This does not represent the planned method for TCP support, - * because we are dedicating a few clients to servicing TCP requests - * instead of allocating TCP clients from a pool and applying quotas. - * - * All this will be fixed later, but this code will allow parts of - * the server that need TCP support, e.g. IXFR and AXFR, to progress. - */ - - /* - * We MUST lock the manager lock for the entire client creation - * process. If we didn't do this, then a client could get a - * shutdown event and disappear out from under us. - */ - - LOCK(&manager->lock); - - for (i = 0; i < n; i++) { - client = NULL; - result = client_create(manager, ifp, &client); - if (result != ISC_R_SUCCESS) - break; - client->attributes |= NS_CLIENTATTR_TCP; - isc_socket_attach(ifp->tcpsocket, &client->tcplistener); - client_accept(client); - client->manager = manager; - ISC_LIST_APPEND(manager->clients, client, link); - manager->nclients++; - } - if (i != 0) { - /* - * We managed to create at least one client, so we - * declare victory. - */ - result = ISC_R_SUCCESS; - } - - UNLOCK(&manager->lock); - - return (result); -} - isc_sockaddr_t * ns_client_getsockaddr(ns_client_t *client) { if (TCP_CLIENT(client)) diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index 8aa0a9271b..acf2d3bf2b 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -52,8 +52,8 @@ * * A ns_clientmgr_t manages a number of ns_client_t objects. * New ns_client_t objects are created by calling - * ns_clientmgr_addtodispatch() (UDP) or ns_clientmgr_accepttcp() (TCP). - * They are destroyed by destroying their manager. + * ns_clientmgr_createclients(). They are destroyed by + * destroying their manager. */ /*** @@ -174,19 +174,12 @@ void ns_clientmgr_destroy(ns_clientmgr_t **managerp); isc_result_t -ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp); +ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n, + ns_interface_t *ifp, isc_boolean_t tcp); /* - * Create up to 'n' UDP clients listening for requests through the - * dispatch of interface 'ifp'. - */ - -isc_result_t -ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n, - ns_interface_t *ifp); -/* - * Create up to 'n' TCP clients accepting requests on the - * socket of interface 'ifp'. + * Create up to 'n' clients listening on interface 'ifp'. + * If 'tcp' is ISC_TRUE, the clients will listen for TCP connections, + * otherwise for UDP requests. */ isc_sockaddr_t * diff --git a/bin/named/include/named/interfacemgr.h b/bin/named/include/named/interfacemgr.h index b16776df0b..1c4d2e64df 100644 --- a/bin/named/include/named/interfacemgr.h +++ b/bin/named/include/named/interfacemgr.h @@ -75,7 +75,8 @@ struct ns_interface { dns_dispatch_t * udpdispatch; /* UDP dispatcher. */ isc_socket_t * tcpsocket; /* TCP socket. */ isc_task_t * task; - int ntcptarget; /* Desired # of TCP accepts */ + int ntcptarget; /* Desired number of concurrent + TCP accepts */ int ntcpcurrent; /* Current ditto, locked */ ISC_LINK(ns_interface_t) link; }; diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c index 3863d82b64..b70116e4b9 100644 --- a/bin/named/interfacemgr.c +++ b/bin/named/interfacemgr.c @@ -195,7 +195,13 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, ifp->udpdispatch = NULL; ifp->tcpsocket = NULL; - ifp->ntcptarget = ns_g_cpus; + /* + * Create a single TCP client object. It will replace itself + * with a new one as soon as it gets a connection, so the actual + * connections will be handled in parallel even though there is + * only one client initially. + */ + ifp->ntcptarget = 1; ifp->ntcpcurrent = 0; ns_interfacemgr_attach(mgr, &ifp->mgr); @@ -257,10 +263,11 @@ ns_interface_listenudp(ns_interface_t *ifp) { goto udp_dispatch_failure; } - result = ns_clientmgr_addtodispatch(ifp->mgr->clientmgr, ns_g_cpus, ifp); + result = ns_clientmgr_createclients(ifp->mgr->clientmgr, ns_g_cpus, ifp, + ISC_FALSE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, - "UDP ns_clientmgr_addtodispatch(): %s", + "UDP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto addtodispatch_failure; } @@ -306,11 +313,13 @@ ns_interface_accepttcp(ns_interface_t *ifp) { isc_result_totext(result)); goto tcp_listen_failure; } - result = ns_clientmgr_accepttcp(ifp->mgr->clientmgr, - ifp->ntcptarget, ifp); + + result = ns_clientmgr_createclients(ifp->mgr->clientmgr, + ifp->ntcptarget, ifp, + ISC_TRUE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, - "TCP ns_clientmgr_accepttcp(): %s", + "TCP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto accepttcp_failure; }