summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/bin/named/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/bin/named/client.c')
-rw-r--r--contrib/bind9/bin/named/client.c500
1 files changed, 280 insertions, 220 deletions
diff --git a/contrib/bind9/bin/named/client.c b/contrib/bind9/bin/named/client.c
index ff4ab69..933abc7 100644
--- a/contrib/bind9/bin/named/client.c
+++ b/contrib/bind9/bin/named/client.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: client.c,v 1.271.10.4 2012/01/31 23:46:39 tbox Exp $ */
+/* $Id$ */
#include <config.h>
@@ -24,6 +24,7 @@
#include <isc/once.h>
#include <isc/platform.h>
#include <isc/print.h>
+#include <isc/queue.h>
#include <isc/stats.h>
#include <isc/stdio.h>
#include <isc/string.h>
@@ -116,15 +117,26 @@
struct ns_clientmgr {
/* Unlocked. */
unsigned int magic;
+
+ /* The queue object has its own locks */
+ client_queue_t inactive; /*%< To be recycled */
+
isc_mem_t * mctx;
isc_taskmgr_t * taskmgr;
isc_timermgr_t * timermgr;
+
+ /* Lock covers manager state. */
isc_mutex_t lock;
- /* Locked by lock. */
isc_boolean_t exiting;
- client_list_t active; /*%< Active clients */
- client_list_t recursing; /*%< Recursing clients */
- client_list_t inactive; /*%< To be recycled */
+
+ /* Lock covers the clients list */
+ isc_mutex_t listlock;
+ client_list_t clients; /*%< All active clients */
+
+ /* Lock covers the recursing list */
+ isc_mutex_t reclock;
+ client_list_t recursing; /*%< Recursing clients */
+
#if NMCTXS > 0
/*%< mctx pool for clients. */
unsigned int nextmctx;
@@ -188,6 +200,12 @@ struct ns_clientmgr {
* recursion quota, and an outstanding write request.
*/
+#define NS_CLIENTSTATE_RECURSING 5
+/*%<
+ * The client object is recursing. It will be on the 'recursing'
+ * list.
+ */
+
#define NS_CLIENTSTATE_MAX 9
/*%<
* Sentinel value used to indicate "no state". When client->newstate
@@ -210,20 +228,21 @@ static void client_udprecv(ns_client_t *client);
static void clientmgr_destroy(ns_clientmgr_t *manager);
static isc_boolean_t exit_check(ns_client_t *client);
static void ns_client_endrequest(ns_client_t *client);
-static void ns_client_checkactive(ns_client_t *client);
static void client_start(isc_task_t *task, isc_event_t *event);
static void client_request(isc_task_t *task, isc_event_t *event);
static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
+static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
+ dns_dispatch_t *disp, isc_boolean_t tcp);
void
ns_client_recursing(ns_client_t *client) {
REQUIRE(NS_CLIENT_VALID(client));
+ REQUIRE(client->state == NS_CLIENTSTATE_WORKING);
- LOCK(&client->manager->lock);
- ISC_LIST_UNLINK(*client->list, client, link);
- ISC_LIST_APPEND(client->manager->recursing, client, link);
- client->list = &client->manager->recursing;
- UNLOCK(&client->manager->lock);
+ LOCK(&client->manager->reclock);
+ client->newstate = client->state = NS_CLIENTSTATE_RECURSING;
+ ISC_LIST_APPEND(client->manager->recursing, client, rlink);
+ UNLOCK(&client->manager->reclock);
}
void
@@ -231,15 +250,14 @@ ns_client_killoldestquery(ns_client_t *client) {
ns_client_t *oldest;
REQUIRE(NS_CLIENT_VALID(client));
- LOCK(&client->manager->lock);
+ LOCK(&client->manager->reclock);
oldest = ISC_LIST_HEAD(client->manager->recursing);
if (oldest != NULL) {
+ ISC_LIST_UNLINK(client->manager->recursing, oldest, rlink);
+ UNLOCK(&client->manager->reclock);
ns_query_cancel(oldest);
- ISC_LIST_UNLINK(*oldest->list, oldest, link);
- ISC_LIST_APPEND(client->manager->active, oldest, link);
- oldest->list = &client->manager->active;
- }
- UNLOCK(&client->manager->lock);
+ } else
+ UNLOCK(&client->manager->reclock);
}
void
@@ -268,15 +286,16 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
*/
static isc_boolean_t
exit_check(ns_client_t *client) {
- ns_clientmgr_t *locked_manager = NULL;
- ns_clientmgr_t *destroy_manager = NULL;
+ isc_boolean_t destroy_manager = ISC_FALSE;
+ ns_clientmgr_t *manager = NULL;
REQUIRE(NS_CLIENT_VALID(client));
+ manager = client->manager;
if (client->state <= client->newstate)
return (ISC_FALSE); /* Business as usual. */
- INSIST(client->newstate < NS_CLIENTSTATE_WORKING);
+ INSIST(client->newstate < NS_CLIENTSTATE_RECURSING);
/*
* We need to detach from the view early when shutting down
@@ -293,13 +312,16 @@ exit_check(ns_client_t *client) {
client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)
dns_view_detach(&client->view);
- if (client->state == NS_CLIENTSTATE_WORKING) {
+ if (client->state == NS_CLIENTSTATE_WORKING ||
+ client->state == NS_CLIENTSTATE_RECURSING)
+ {
INSIST(client->newstate <= NS_CLIENTSTATE_READING);
/*
* Let the update processing complete.
*/
if (client->nupdates > 0)
return (ISC_TRUE);
+
/*
* We are trying to abort request processing.
*/
@@ -322,23 +344,28 @@ exit_check(ns_client_t *client) {
*/
return (ISC_TRUE);
}
+
/*
* I/O cancel is complete. Burn down all state
* related to the current request. Ensure that
- * the client is on the active list and not the
- * recursing list.
+ * the client is no longer on the recursing list.
+ *
+ * We need to check whether the client is still linked,
+ * because it may already have been removed from the
+ * recursing list by ns_client_killoldestquery()
*/
- LOCK(&client->manager->lock);
- if (client->list == &client->manager->recursing) {
- ISC_LIST_UNLINK(*client->list, client, link);
- ISC_LIST_APPEND(client->manager->active, client, link);
- client->list = &client->manager->active;
+ if (client->state == NS_CLIENTSTATE_RECURSING) {
+ LOCK(&manager->reclock);
+ if (ISC_LINK_LINKED(client, rlink))
+ ISC_LIST_UNLINK(manager->recursing,
+ client, rlink);
+ UNLOCK(&manager->reclock);
}
- UNLOCK(&client->manager->lock);
ns_client_endrequest(client);
client->state = NS_CLIENTSTATE_READING;
INSIST(client->recursionquota == NULL);
+
if (NS_CLIENTSTATE_READING == client->newstate) {
client_read(client);
client->newstate = NS_CLIENTSTATE_MAX;
@@ -389,8 +416,27 @@ exit_check(ns_client_t *client) {
* or UDP request, but we may have enough clients doing
* that already. Check whether this client needs to remain
* active and force it to go inactive if not.
+ *
+ * UDP clients go inactive at this point, but TCP clients
+ * may remain active if we have fewer active TCP client
+ * objects than desired due to an earlier quota exhaustion.
*/
- ns_client_checkactive(client);
+ if (client->mortal && TCP_CLIENT(client) && !ns_g_clienttest) {
+ LOCK(&client->interface->lock);
+ if (client->interface->ntcpcurrent <
+ client->interface->ntcptarget)
+ client->mortal = ISC_FALSE;
+ UNLOCK(&client->interface->lock);
+ }
+
+ /*
+ * We don't need the client; send it to the inactive
+ * queue for recycling.
+ */
+ if (client->mortal) {
+ if (client->newstate > NS_CLIENTSTATE_INACTIVE)
+ client->newstate = NS_CLIENTSTATE_INACTIVE;
+ }
if (NS_CLIENTSTATE_READY == client->newstate) {
if (TCP_CLIENT(client)) {
@@ -404,6 +450,7 @@ exit_check(ns_client_t *client) {
if (client->state == NS_CLIENTSTATE_READY) {
INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);
+
/*
* We are trying to enter the inactive state.
*/
@@ -411,25 +458,22 @@ exit_check(ns_client_t *client) {
isc_socket_cancel(client->tcplistener, client->task,
ISC_SOCKCANCEL_ACCEPT);
- if (! (client->naccepts == 0)) {
- /* Still waiting for accept cancel completion. */
+ /* Still waiting for accept cancel completion. */
+ if (! (client->naccepts == 0))
return (ISC_TRUE);
- }
- /* Accept cancel is complete. */
+ /* Accept cancel is complete. */
if (client->nrecvs > 0)
isc_socket_cancel(client->udpsocket, client->task,
ISC_SOCKCANCEL_RECV);
- if (! (client->nrecvs == 0)) {
- /* Still waiting for recv cancel completion. */
+
+ /* Still waiting for recv cancel completion. */
+ if (! (client->nrecvs == 0))
return (ISC_TRUE);
- }
- /* Recv cancel is complete. */
- if (client->nctls > 0) {
- /* Still waiting for control event to be delivered */
+ /* Still waiting for control event to be delivered */
+ if (client->nctls > 0)
return (ISC_TRUE);
- }
/* Deactivate the client. */
if (client->interface)
@@ -449,7 +493,6 @@ exit_check(ns_client_t *client) {
client->attributes = 0;
client->mortal = ISC_FALSE;
- LOCK(&client->manager->lock);
/*
* Put the client on the inactive list. If we are aiming for
* the "freed" state, it will be removed from the inactive
@@ -457,18 +500,18 @@ exit_check(ns_client_t *client) {
* that has been done, lest the manager decide to reactivate
* the dying client inbetween.
*/
- locked_manager = client->manager;
- ISC_LIST_UNLINK(*client->list, client, link);
- ISC_LIST_APPEND(client->manager->inactive, client, link);
- client->list = &client->manager->inactive;
client->state = NS_CLIENTSTATE_INACTIVE;
INSIST(client->recursionquota == NULL);
if (client->state == client->newstate) {
client->newstate = NS_CLIENTSTATE_MAX;
+ if (!ns_g_clienttest && manager != NULL &&
+ !manager->exiting)
+ ISC_QUEUE_PUSH(manager->inactive, client,
+ ilink);
if (client->needshutdown)
isc_task_shutdown(client->task);
- goto unlock;
+ return (ISC_TRUE);
}
}
@@ -485,6 +528,7 @@ exit_check(ns_client_t *client) {
REQUIRE(client->state == NS_CLIENTSTATE_INACTIVE);
INSIST(client->recursionquota == NULL);
+ INSIST(!ISC_QLINK_LINKED(client, ilink));
ns_query_free(client);
isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);
@@ -493,27 +537,27 @@ exit_check(ns_client_t *client) {
isc_timer_detach(&client->timer);
if (client->tcpbuf != NULL)
- isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
+ isc_mem_put(client->mctx, client->tcpbuf,
+ TCP_BUFFER_SIZE);
if (client->opt != NULL) {
INSIST(dns_rdataset_isassociated(client->opt));
dns_rdataset_disassociate(client->opt);
- dns_message_puttemprdataset(client->message, &client->opt);
+ dns_message_puttemprdataset(client->message,
+ &client->opt);
}
+
dns_message_destroy(&client->message);
- if (client->manager != NULL) {
- ns_clientmgr_t *manager = client->manager;
- if (locked_manager == NULL) {
- LOCK(&manager->lock);
- locked_manager = manager;
- }
- ISC_LIST_UNLINK(*client->list, client, link);
- client->list = NULL;
+ if (manager != NULL) {
+ LOCK(&manager->listlock);
+ ISC_LIST_UNLINK(manager->clients, client, link);
+ LOCK(&manager->lock);
if (manager->exiting &&
- ISC_LIST_EMPTY(manager->active) &&
- ISC_LIST_EMPTY(manager->inactive) &&
- ISC_LIST_EMPTY(manager->recursing))
- destroy_manager = manager;
+ ISC_LIST_EMPTY(manager->clients))
+ destroy_manager = ISC_TRUE;
+ UNLOCK(&manager->lock);
+ UNLOCK(&manager->listlock);
}
+
/*
* Detaching the task must be done after unlinking from
* the manager's lists because the manager accesses
@@ -524,6 +568,7 @@ exit_check(ns_client_t *client) {
CTRACE("free");
client->magic = 0;
+
/*
* Check that there are no other external references to
* the memory context.
@@ -533,22 +578,10 @@ exit_check(ns_client_t *client) {
INSIST(0);
}
isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
-
- goto unlock;
- }
-
- unlock:
- if (locked_manager != NULL) {
- UNLOCK(&locked_manager->lock);
- locked_manager = NULL;
}
- /*
- * Only now is it safe to destroy the client manager (if needed),
- * because we have accessed its lock for the last time.
- */
- if (destroy_manager != NULL)
- clientmgr_destroy(destroy_manager);
+ if (destroy_manager && manager != NULL)
+ clientmgr_destroy(manager);
return (ISC_TRUE);
}
@@ -604,6 +637,9 @@ client_shutdown(isc_task_t *task, isc_event_t *event) {
client->shutdown_arg = NULL;
}
+ if (ISC_QLINK_LINKED(client, ilink))
+ ISC_QUEUE_UNLINK(client->manager->inactive, client, ilink);
+
client->newstate = NS_CLIENTSTATE_FREED;
client->needshutdown = ISC_FALSE;
(void)exit_check(client);
@@ -616,7 +652,8 @@ ns_client_endrequest(ns_client_t *client) {
INSIST(client->nsends == 0);
INSIST(client->nrecvs == 0);
INSIST(client->nupdates == 0);
- INSIST(client->state == NS_CLIENTSTATE_WORKING);
+ INSIST(client->state == NS_CLIENTSTATE_WORKING ||
+ client->state == NS_CLIENTSTATE_RECURSING);
CTRACE("endrequest");
@@ -649,46 +686,13 @@ ns_client_endrequest(ns_client_t *client) {
client->attributes &= NS_CLIENTATTR_TCP;
}
-static void
-ns_client_checkactive(ns_client_t *client) {
- if (client->mortal) {
- /*
- * This client object should normally go inactive
- * at this point, but if we have fewer active client
- * objects than desired due to earlier quota exhaustion,
- * keep it active to make up for the shortage.
- */
- isc_boolean_t need_another_client = ISC_FALSE;
- if (TCP_CLIENT(client) && !ns_g_clienttest) {
- LOCK(&client->interface->lock);
- if (client->interface->ntcpcurrent <
- client->interface->ntcptarget)
- need_another_client = ISC_TRUE;
- UNLOCK(&client->interface->lock);
- } else {
- /*
- * The UDP client quota is enforced by making
- * requests fail rather than by not listening
- * for new ones. Therefore, there is always a
- * full set of UDP clients listening.
- */
- }
- if (! need_another_client) {
- /*
- * We don't need this client object. Recycle it.
- */
- if (client->newstate >= NS_CLIENTSTATE_INACTIVE)
- client->newstate = NS_CLIENTSTATE_INACTIVE;
- }
- }
-}
-
void
ns_client_next(ns_client_t *client, isc_result_t result) {
int newstate;
REQUIRE(NS_CLIENT_VALID(client));
REQUIRE(client->state == NS_CLIENTSTATE_WORKING ||
+ client->state == NS_CLIENTSTATE_RECURSING ||
client->state == NS_CLIENTSTATE_READING);
CTRACE("next");
@@ -745,9 +749,6 @@ client_senddone(isc_task_t *task, isc_event_t *event) {
client->tcpbuf = NULL;
}
- if (exit_check(client))
- return;
-
ns_client_next(client, ISC_R_SUCCESS);
}
@@ -1974,6 +1975,11 @@ static isc_result_t
get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) {
isc_mem_t *clientmctx;
isc_result_t result;
+#if NMCTXS > 0
+ unsigned int nextmctx;
+#endif
+
+ MTRACE("clientmctx");
/*
* Caller must be holding the manager lock.
@@ -1985,19 +1991,21 @@ get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) {
return (result);
}
#if NMCTXS > 0
- INSIST(manager->nextmctx < NMCTXS);
- clientmctx = manager->mctxpool[manager->nextmctx];
+ nextmctx = manager->nextmctx++;
+ if (manager->nextmctx == NMCTXS)
+ manager->nextmctx = 0;
+
+ INSIST(nextmctx < NMCTXS);
+
+ clientmctx = manager->mctxpool[nextmctx];
if (clientmctx == NULL) {
result = isc_mem_create(0, 0, &clientmctx);
if (result != ISC_R_SUCCESS)
return (result);
isc_mem_setname(clientmctx, "client", NULL);
- manager->mctxpool[manager->nextmctx] = clientmctx;
+ manager->mctxpool[nextmctx] = clientmctx;
}
- manager->nextmctx++;
- if (manager->nextmctx == NMCTXS)
- manager->nextmctx = 0;
#else
clientmctx = manager->mctx;
#endif
@@ -2118,6 +2126,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
#ifdef ALLOW_FILTER_AAAA_ON_V4
client->filter_aaaa = dns_v4_aaaa_ok;
#endif
+ client->needshutdown = ns_g_clienttest;
+
ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,
NS_EVENT_CLIENTCONTROL, client_start, client, client,
NULL, NULL);
@@ -2129,7 +2139,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
client->formerrcache.time = 0;
client->formerrcache.id = 0;
ISC_LINK_INIT(client, link);
- client->list = NULL;
+ ISC_LINK_INIT(client, rlink);
+ ISC_QLINK_INIT(client, ilink);
/*
* We call the init routines for the various kinds of client here,
@@ -2144,8 +2155,6 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
if (result != ISC_R_SUCCESS)
goto cleanup_query;
- client->needshutdown = ns_g_clienttest;
-
CTRACE("create");
*clientp = client;
@@ -2410,10 +2419,8 @@ ns_client_replace(ns_client_t *client) {
REQUIRE(client != NULL);
REQUIRE(client->manager != NULL);
- result = ns_clientmgr_createclients(client->manager,
- 1, client->interface,
- (TCP_CLIENT(client) ?
- ISC_TRUE : ISC_FALSE));
+ result = get_client(client->manager, client->interface,
+ client->dispatch, TCP_CLIENT(client));
if (result != ISC_R_SUCCESS)
return (result);
@@ -2437,9 +2444,7 @@ clientmgr_destroy(ns_clientmgr_t *manager) {
int i;
#endif
- REQUIRE(ISC_LIST_EMPTY(manager->active));
- REQUIRE(ISC_LIST_EMPTY(manager->inactive));
- REQUIRE(ISC_LIST_EMPTY(manager->recursing));
+ REQUIRE(ISC_LIST_EMPTY(manager->clients));
MTRACE("clientmgr_destroy");
@@ -2450,7 +2455,10 @@ clientmgr_destroy(ns_clientmgr_t *manager) {
}
#endif
+ ISC_QUEUE_DESTROY(manager->inactive);
DESTROYLOCK(&manager->lock);
+ DESTROYLOCK(&manager->listlock);
+ DESTROYLOCK(&manager->reclock);
manager->magic = 0;
isc_mem_put(manager->mctx, manager, sizeof(*manager));
}
@@ -2473,13 +2481,21 @@ ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
if (result != ISC_R_SUCCESS)
goto cleanup_manager;
+ result = isc_mutex_init(&manager->listlock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_lock;
+
+ result = isc_mutex_init(&manager->reclock);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_listlock;
+
manager->mctx = mctx;
manager->taskmgr = taskmgr;
manager->timermgr = timermgr;
manager->exiting = ISC_FALSE;
- ISC_LIST_INIT(manager->active);
- ISC_LIST_INIT(manager->inactive);
+ ISC_LIST_INIT(manager->clients);
ISC_LIST_INIT(manager->recursing);
+ ISC_QUEUE_INIT(manager->inactive, ilink);
#if NMCTXS > 0
manager->nextmctx = 0;
for (i = 0; i < NMCTXS; i++)
@@ -2493,6 +2509,12 @@ ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
return (ISC_R_SUCCESS);
+ cleanup_listlock:
+ (void) isc_mutex_destroy(&manager->listlock);
+
+ cleanup_lock:
+ (void) isc_mutex_destroy(&manager->lock);
+
cleanup_manager:
isc_mem_put(manager->mctx, manager, sizeof(*manager));
@@ -2501,9 +2523,10 @@ ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
void
ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
+ isc_result_t result;
ns_clientmgr_t *manager;
ns_client_t *client;
- isc_boolean_t need_destroy = ISC_FALSE;
+ isc_boolean_t need_destroy = ISC_FALSE, unlock = ISC_FALSE;
REQUIRE(managerp != NULL);
manager = *managerp;
@@ -2511,31 +2534,27 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
MTRACE("destroy");
- LOCK(&manager->lock);
+ /*
+ * Check for success because we may already be task-exclusive
+ * at this point. Only if we succeed at obtaining an exclusive
+ * lock now will we need to relinquish it later.
+ */
+ result = isc_task_beginexclusive(ns_g_server->task);
+ if (result == ISC_R_SUCCESS)
+ unlock = ISC_TRUE;
manager->exiting = ISC_TRUE;
- for (client = ISC_LIST_HEAD(manager->recursing);
- client != NULL;
- client = ISC_LIST_NEXT(client, link))
- isc_task_shutdown(client->task);
-
- for (client = ISC_LIST_HEAD(manager->active);
- client != NULL;
- client = ISC_LIST_NEXT(client, link))
- isc_task_shutdown(client->task);
-
- for (client = ISC_LIST_HEAD(manager->inactive);
+ for (client = ISC_LIST_HEAD(manager->clients);
client != NULL;
client = ISC_LIST_NEXT(client, link))
isc_task_shutdown(client->task);
- if (ISC_LIST_EMPTY(manager->active) &&
- ISC_LIST_EMPTY(manager->inactive) &&
- ISC_LIST_EMPTY(manager->recursing))
+ if (ISC_LIST_EMPTY(manager->clients))
need_destroy = ISC_TRUE;
- UNLOCK(&manager->lock);
+ if (unlock)
+ isc_task_endexclusive(ns_g_server->task);
if (need_destroy)
clientmgr_destroy(manager);
@@ -2543,81 +2562,86 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
*managerp = NULL;
}
-isc_result_t
-ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
- ns_interface_t *ifp, isc_boolean_t tcp)
+static isc_result_t
+get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
+ dns_dispatch_t *disp, isc_boolean_t tcp)
{
isc_result_t result = ISC_R_SUCCESS;
- unsigned int i;
+ isc_event_t *ev;
ns_client_t *client;
+ MTRACE("get client");
- REQUIRE(VALID_MANAGER(manager));
- REQUIRE(n > 0);
+ REQUIRE(manager != NULL);
- MTRACE("createclients");
+ if (manager->exiting)
+ return (ISC_R_SHUTTINGDOWN);
/*
- * 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.
+ * Allocate a client. First try to get a recycled one;
+ * if that fails, make a new one.
*/
+ client = NULL;
+ if (!ns_g_clienttest)
+ ISC_QUEUE_POP(manager->inactive, ilink, client);
- LOCK(&manager->lock);
+ if (client != NULL)
+ MTRACE("recycle");
+ else {
+ MTRACE("create new");
- for (i = 0; i < n; i++) {
- isc_event_t *ev;
- /*
- * Allocate a client. First try to get a recycled one;
- * if that fails, make a new one.
- */
- client = NULL;
- if (!ns_g_clienttest)
- client = ISC_LIST_HEAD(manager->inactive);
- if (client != NULL) {
- MTRACE("recycle");
- ISC_LIST_UNLINK(manager->inactive, client, link);
- client->list = NULL;
- } else {
- MTRACE("create new");
- result = client_create(manager, &client);
- if (result != ISC_R_SUCCESS)
- break;
- }
+ LOCK(&manager->lock);
+ result = client_create(manager, &client);
+ UNLOCK(&manager->lock);
+ if (result != ISC_R_SUCCESS)
+ return (result);
- ns_interface_attach(ifp, &client->interface);
- client->state = NS_CLIENTSTATE_READY;
- INSIST(client->recursionquota == NULL);
+ LOCK(&manager->listlock);
+ ISC_LIST_APPEND(manager->clients, client, link);
+ UNLOCK(&manager->listlock);
+ }
- if (tcp) {
- client->attributes |= NS_CLIENTATTR_TCP;
- isc_socket_attach(ifp->tcpsocket,
- &client->tcplistener);
- } else {
- isc_socket_t *sock;
+ client->manager = manager;
+ ns_interface_attach(ifp, &client->interface);
+ client->state = NS_CLIENTSTATE_READY;
+ INSIST(client->recursionquota == NULL);
- dns_dispatch_attach(ifp->udpdispatch,
- &client->dispatch);
- sock = dns_dispatch_getsocket(client->dispatch);
- isc_socket_attach(sock, &client->udpsocket);
- }
- client->manager = manager;
- ISC_LIST_APPEND(manager->active, client, link);
- client->list = &manager->active;
+ if (tcp) {
+ client->attributes |= NS_CLIENTATTR_TCP;
+ isc_socket_attach(ifp->tcpsocket,
+ &client->tcplistener);
+ } else {
+ isc_socket_t *sock;
- INSIST(client->nctls == 0);
- client->nctls++;
- ev = &client->ctlevent;
- isc_task_send(client->task, &ev);
- }
- if (i != 0) {
- /*
- * We managed to create at least one client, so we
- * declare victory.
- */
- result = ISC_R_SUCCESS;
+ dns_dispatch_attach(disp, &client->dispatch);
+ sock = dns_dispatch_getsocket(client->dispatch);
+ isc_socket_attach(sock, &client->udpsocket);
}
- UNLOCK(&manager->lock);
+ INSIST(client->nctls == 0);
+ client->nctls++;
+ ev = &client->ctlevent;
+ isc_task_send(client->task, &ev);
+
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+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 disp;
+
+ REQUIRE(VALID_MANAGER(manager));
+ REQUIRE(n > 0);
+
+ MTRACE("createclients");
+
+ for (disp = 0; disp < n; disp++) {
+ result = get_client(manager, ifp, ifp->udpdispatch[disp], tcp);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
return (result);
}
@@ -2702,19 +2726,41 @@ ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
{
char msgbuf[2048];
char peerbuf[ISC_SOCKADDR_FORMATSIZE];
- const char *name = "";
- const char *sep = "";
+ char signerbuf[DNS_NAME_FORMATSIZE], qnamebuf[DNS_NAME_FORMATSIZE];
+ const char *viewname = "";
+ const char *sep1 = "", *sep2 = "", *sep3 = "", *sep4 = "";
+ const char *signer = "", *qname = "";
+ dns_name_t *q = NULL;
vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+
ns_client_name(client, peerbuf, sizeof(peerbuf));
+
+ if (client->signer != NULL) {
+ dns_name_format(client->signer, signerbuf, sizeof(signerbuf));
+ sep1 = "/key ";
+ signer = signerbuf;
+ }
+
+ q = client->query.origqname != NULL
+ ? client->query.origqname : client->query.qname;
+ if (q != NULL) {
+ dns_name_format(q, qnamebuf, sizeof(qnamebuf));
+ sep2 = " (";
+ sep3 = ")";
+ qname = qnamebuf;
+ }
+
if (client->view != NULL && strcmp(client->view->name, "_bind") != 0 &&
strcmp(client->view->name, "_default") != 0) {
- name = client->view->name;
- sep = ": view ";
+ sep4 = ": view ";
+ viewname = client->view->name;
}
isc_log_write(ns_g_lctx, category, module, level,
- "client %s%s%s: %s", peerbuf, sep, name, msgbuf);
+ "client %s%s%s%s%s%s%s%s: %s",
+ peerbuf, sep1, signer, sep2, qname, sep3,
+ sep4, viewname, msgbuf);
}
void
@@ -2796,9 +2842,11 @@ ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) {
REQUIRE(VALID_MANAGER(manager));
- LOCK(&manager->lock);
+ LOCK(&manager->reclock);
client = ISC_LIST_HEAD(manager->recursing);
while (client != NULL) {
+ INSIST(client->state == NS_CLIENTSTATE_RECURSING);
+
ns_client_name(client, peerbuf, sizeof(peerbuf));
if (client->view != NULL &&
strcmp(client->view->name, "_bind") != 0 &&
@@ -2809,6 +2857,9 @@ ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) {
name = "";
sep = "";
}
+
+ LOCK(&client->query.fetchlock);
+ INSIST(client->query.qname != NULL);
dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
if (client->query.qname != client->query.origqname &&
client->query.origqname != NULL) {
@@ -2831,20 +2882,19 @@ ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) {
strcpy(typebuf, "-");
strcpy(classbuf, "-");
}
+ UNLOCK(&client->query.fetchlock);
fprintf(f, "; client %s%s%s: id %u '%s/%s/%s'%s%s "
"requesttime %d\n", peerbuf, sep, name,
client->message->id, namebuf, typebuf, classbuf,
origfor, original, client->requesttime);
- client = ISC_LIST_NEXT(client, link);
+ client = ISC_LIST_NEXT(client, rlink);
}
- UNLOCK(&manager->lock);
+ UNLOCK(&manager->reclock);
}
void
ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) {
-
- if (client->manager != NULL)
- LOCK(&client->manager->lock);
+ LOCK(&client->query.fetchlock);
if (client->query.restarts > 0) {
/*
* client->query.qname was dynamically allocated.
@@ -2853,6 +2903,16 @@ ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) {
&client->query.qname);
}
client->query.qname = name;
- if (client->manager != NULL)
- UNLOCK(&client->manager->lock);
+ UNLOCK(&client->query.fetchlock);
+}
+
+isc_result_t
+ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp) {
+ ns_client_t *client = (ns_client_t *) ci->data;
+
+ REQUIRE(NS_CLIENT_VALID(client));
+ REQUIRE(addrp != NULL);
+
+ *addrp = &client->peeraddr;
+ return (ISC_R_SUCCESS);
}
OpenPOWER on IntegriCloud