diff options
Diffstat (limited to 'bin/named/client.c')
| -rw-r--r-- | bin/named/client.c | 500 | 
1 files changed, 280 insertions, 220 deletions
| diff --git a/bin/named/client.c b/bin/named/client.c index ff4ab691c1840..933abc7631e27 100644 --- a/bin/named/client.c +++ b/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);  } | 
