From 08d93839d7051eb9749151c7c1971df0eafc2fbf Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Fri, 7 Jan 2000 19:20:25 +0000 Subject: [PATCH] support multiple simultaneous clients by creating new client objects in place of busy ones, in preparation for client quotas --- bin/named/client.c | 55 +++++++++++++++++++++++++++++++- bin/named/include/named/client.h | 17 ++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/bin/named/client.c b/bin/named/client.c index 310829d1d1..e8f6e7c82d 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -106,6 +106,13 @@ maybe_free(ns_client_t *client) { isc_boolean_t need_clientmgr_destroy = ISC_FALSE; REQUIRE(NS_CLIENT_VALID(client)); + + /* + * When "shuttingdown" is true, either the task has received + * its shutdown event or no shutdown event has ever been + * set up. Thus, we have no outstanding shutdown + * event at this point. + */ REQUIRE(client->shuttingdown == ISC_TRUE); if (client->naccepts > 0) @@ -224,8 +231,16 @@ ns_client_next(ns_client_t *client, isc_result_t result) { dns_rdataset_disassociate(client->opt); dns_message_puttemprdataset(client->message, &client->opt); } + client->udpsize = 512; dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); + + if (client->oneshot) { + /* XXX should put in "idle client pool" instead. */ + isc_task_shutdown(client->task); + return; + } + if (client->dispevent != NULL) { dns_dispatch_freeevent(client->dispatch, client->dispentry, &client->dispevent); @@ -672,6 +687,9 @@ client_request(isc_task_t *task, isc_event_t *event) { } if (ra == ISC_TRUE) client->attributes |= NS_CLIENTATTR_RA; + + /* XXX conditionally */ + (void) ns_client_replace(client); /* * Dispatch the request. @@ -791,6 +809,7 @@ client_create(ns_clientmgr_t *manager, ns_clienttype_t type, client->udpsize = 512; client->next = NULL; dns_name_init(&client->signername, NULL); + client->oneshot = ISC_FALSE; ISC_LINK_INIT(client, link); /* @@ -855,7 +874,7 @@ client_newconn(isc_task_t *task, isc_event_t *event) { INSIST(client->naccepts == 1); client->naccepts--; - + if (client->shuttingdown) { maybe_free(client); } else if (nevent->result == ISC_R_SUCCESS) { @@ -864,6 +883,15 @@ client_newconn(isc_task_t *task, isc_event_t *event) { dns_tcpmsg_init(client->mctx, client->tcpsocket, &client->tcpmsg); client->tcpmsg_valid = ISC_TRUE; + + /* + * Let a new client take our place immediately, before + * we wait for a request packet. If we don't, + * telnetting to port 35 (once per CPU) will + * deny service to legititmate TCP clients. + */ + (void) ns_client_replace(client); + client_read(client); } else { /* @@ -923,6 +951,31 @@ ns_client_unwait(ns_client_t *client) { maybe_free(client); } + +isc_result_t +ns_client_replace(ns_client_t *client) { + isc_result_t result; + CTRACE("replace"); + + /* XXX Check quota here. */ + + if (TCP_CLIENT(client)) { + result = ns_clientmgr_accepttcp(client->manager, client->tcplistener, 1); + } else { + result = ns_clientmgr_addtodispatch(client->manager, 1, client->dispatch); + } + if (result != ISC_R_SUCCESS) + return (result); + + /* + * The new client is ready to listen for new requests, so we + * should refrain from doing so. + */ + client->oneshot = ISC_TRUE; + + return (ISC_R_SUCCESS); +} + /*** *** Client Manager ***/ diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index cf1fe10114..c17c7967b3 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -69,6 +69,7 @@ struct ns_client { isc_stdtime_t now; dns_name_t signername; /* [T]SIG key name */ dns_name_t * signer; /* NULL if not valid sig */ + isc_boolean_t oneshot; ISC_LINK(struct ns_client) link; }; @@ -106,9 +107,25 @@ ns_client_shuttingdown(ns_client_t *client); void ns_client_wait(ns_client_t *client); +/* + * Increment reference count. + */ void ns_client_unwait(ns_client_t *client); +/* + * Decrement reference count. + */ + +isc_result_t +ns_client_replace(ns_client_t *client); +/* + * Try to replace the current client with a new one, so that the + * current one can go off and do some lengthy work without + * leaving the dispatch/socket without service. + * + * If doing so would exceed a quota, return ISC_R_QUOTA. + */ isc_result_t ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,