⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.c

📁 bind 9.3结合mysql数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003  Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: client.c,v 1.176.2.13.4.22 2004/07/23 02:56:51 marka Exp $ */#include <config.h>#include <isc/formatcheck.h>#include <isc/mutex.h>#include <isc/once.h>#include <isc/print.h>#include <isc/stdio.h>#include <isc/string.h>#include <isc/task.h>#include <isc/timer.h>#include <isc/util.h>#include <dns/db.h>#include <dns/dispatch.h>#include <dns/events.h>#include <dns/message.h>#include <dns/rcode.h>#include <dns/resolver.h>#include <dns/rdata.h>#include <dns/rdataclass.h>#include <dns/rdatalist.h>#include <dns/rdataset.h>#include <dns/tsig.h>#include <dns/view.h>#include <dns/zone.h>#include <named/interfacemgr.h>#include <named/log.h>#include <named/notify.h>#include <named/server.h>#include <named/update.h>/*** *** Client ***//* * Important note! * * All client state changes, other than that from idle to listening, occur * as a result of events.  This guarantees serialization and avoids the * need for locking. * * If a routine is ever created that allows someone other than the client's * task to change the client, then the client will have to be locked. */#define NS_CLIENT_TRACE#ifdef NS_CLIENT_TRACE#define CTRACE(m)	ns_client_log(client, \				      NS_LOGCATEGORY_CLIENT, \				      NS_LOGMODULE_CLIENT, \				      ISC_LOG_DEBUG(3), \				      "%s", (m))#define MTRACE(m)	isc_log_write(ns_g_lctx, \				      NS_LOGCATEGORY_GENERAL, \				      NS_LOGMODULE_CLIENT, \				      ISC_LOG_DEBUG(3), \				      "clientmgr @%p: %s", manager, (m))#else#define CTRACE(m)	((void)(m))#define MTRACE(m)	((void)(m))#endif#define TCP_CLIENT(c)	(((c)->attributes & NS_CLIENTATTR_TCP) != 0)#define TCP_BUFFER_SIZE			(65535 + 2)#define SEND_BUFFER_SIZE		4096#define RECV_BUFFER_SIZE		4096struct ns_clientmgr {	/* Unlocked. */	unsigned int			magic;	isc_mem_t *			mctx;	isc_taskmgr_t *			taskmgr;	isc_timermgr_t *		timermgr;	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 */};#define MANAGER_MAGIC			ISC_MAGIC('N', 'S', 'C', 'm')#define VALID_MANAGER(m)		ISC_MAGIC_VALID(m, MANAGER_MAGIC)/* * Client object states.  Ordering is significant: higher-numbered * states are generally "more active", meaning that the client can * have more dynamically allocated data, outstanding events, etc. * In the list below, any such properties listed for state N * also apply to any state > N. * * To force the client into a less active state, set client->newstate * to that state and call exit_check().  This will cause any * activities defined for higher-numbered states to be aborted. */#define NS_CLIENTSTATE_FREED    0/* * The client object no longer exists. */#define NS_CLIENTSTATE_INACTIVE 1/* * The client object exists and has a task and timer. * Its "query" struct and sendbuf are initialized. * It is on the client manager's list of inactive clients. * It has a message and OPT, both in the reset state. */#define NS_CLIENTSTATE_READY    2/* * The client object is either a TCP or a UDP one, and * it is associated with a network interface.  It is on the * client manager's list of active clients. * * If it is a TCP client object, it has a TCP listener socket * and an outstanding TCP listen request. * * If it is a UDP client object, it has a UDP listener socket * and an outstanding UDP receive request. */#define NS_CLIENTSTATE_READING  3/* * The client object is a TCP client object that has received * a connection.  It has a tcpsocket, tcpmsg, TCP quota, and an * outstanding TCP read request.  This state is not used for * UDP client objects. */#define NS_CLIENTSTATE_WORKING  4/* * The client object has received a request and is working * on it.  It has a view, and it may have any of a non-reset OPT, * recursion quota, and an outstanding write request. */#define NS_CLIENTSTATE_MAX      9/* * Sentinel value used to indicate "no state".  When client->newstate * has this value, we are not attempting to exit the current state. * Must be greater than any valid state. */static void client_read(ns_client_t *client);static void client_accept(ns_client_t *client);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);voidns_client_recursing(ns_client_t *client, isc_boolean_t killoldest) {	ns_client_t *oldest;	REQUIRE(NS_CLIENT_VALID(client));	LOCK(&client->manager->lock);	if (killoldest) {		oldest = ISC_LIST_HEAD(client->manager->recursing);		if (oldest != NULL) {			ns_query_cancel(oldest);			ISC_LIST_UNLINK(*oldest->list, oldest, link);			ISC_LIST_APPEND(client->manager->active, oldest, link);			oldest->list = &client->manager->active;		}	}	ISC_LIST_UNLINK(*client->list, client, link);	ISC_LIST_APPEND(client->manager->recursing, client, link);	client->list = &client->manager->recursing;	UNLOCK(&client->manager->lock);}voidns_client_settimeout(ns_client_t *client, unsigned int seconds) {	isc_result_t result;	isc_interval_t interval;	isc_interval_set(&interval, seconds, 0);	result = isc_timer_reset(client->timer, isc_timertype_once, NULL,				 &interval, ISC_FALSE);	client->timerset = ISC_TRUE;	if (result != ISC_R_SUCCESS) {		ns_client_log(client, NS_LOGCATEGORY_CLIENT,			      NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,			      "setting timeout: %s",			      isc_result_totext(result));		/* Continue anyway. */	}}/* * Check for a deactivation or shutdown request and take appropriate * action.  Returns ISC_TRUE if either is in progress; in this case * the caller must no longer use the client object as it may have been * freed. */static isc_boolean_texit_check(ns_client_t *client) {	ns_clientmgr_t *locked_manager = NULL;	ns_clientmgr_t *destroy_manager = NULL;	REQUIRE(NS_CLIENT_VALID(client));	if (client->state <= client->newstate)		return (ISC_FALSE); /* Business as usual. */	INSIST(client->newstate < NS_CLIENTSTATE_WORKING);	/*	 * We need to detach from the view early when shutting down	 * the server to break the following vicious circle:	 *	 *  - The resolver will not shut down until the view refcount is zero	 *  - The view refcount does not go to zero until all clients detach	 *  - The client does not detach from the view until references is zero	 *  - references does not go to zero until the resolver has shut down	 *	 * Keep the view attached until any outstanding updates complete.	 */	if (client->nupdates == 0 && 	    client->newstate == NS_CLIENTSTATE_FREED && client->view != NULL)		dns_view_detach(&client->view);	if (client->state == NS_CLIENTSTATE_WORKING) {		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.		 */		if (client->nsends > 0) {			isc_socket_t *socket;			if (TCP_CLIENT(client))				socket = client->tcpsocket;			else				socket = client->udpsocket;			isc_socket_cancel(socket, client->task,					  ISC_SOCKCANCEL_SEND);		}		if (! (client->nsends == 0 && client->nrecvs == 0 &&		       client->references == 0))		{			/*			 * Still waiting for I/O cancel completion.			 * or lingering references.			 */			return (ISC_TRUE);		}		/*		 * I/O cancel is complete.  Burn down all state		 * related to the current request.		 */		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;			return (ISC_TRUE); /* We're done. */		}	}	if (client->state == NS_CLIENTSTATE_READING) {		/*		 * We are trying to abort the current TCP connection,		 * if any.		 */		INSIST(client->recursionquota == NULL);		INSIST(client->newstate <= NS_CLIENTSTATE_READY);		if (client->nreads > 0)			dns_tcpmsg_cancelread(&client->tcpmsg);		if (! client->nreads == 0) {			/* Still waiting for read cancel completion. */			return (ISC_TRUE);		}		if (client->tcpmsg_valid) {			dns_tcpmsg_invalidate(&client->tcpmsg);			client->tcpmsg_valid = ISC_FALSE;		}		if (client->tcpsocket != NULL) {			CTRACE("closetcp");			isc_socket_detach(&client->tcpsocket);		}		if (client->tcpquota != NULL)			isc_quota_detach(&client->tcpquota);		if (client->timerset) {			(void)isc_timer_reset(client->timer,					      isc_timertype_inactive,					      NULL, NULL, ISC_TRUE);			client->timerset = ISC_FALSE;		}		client->peeraddr_valid = ISC_FALSE;		client->state = NS_CLIENTSTATE_READY;		INSIST(client->recursionquota == NULL);		/*		 * Now the client is ready to accept a new TCP connection		 * 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.		 */		ns_client_checkactive(client);		if (NS_CLIENTSTATE_READY == client->newstate) {			if (TCP_CLIENT(client)) {				client_accept(client);			} else				client_udprecv(client);			client->newstate = NS_CLIENTSTATE_MAX;			return (ISC_TRUE);		}	}	if (client->state == NS_CLIENTSTATE_READY) {		INSIST(client->newstate <= NS_CLIENTSTATE_INACTIVE);		/*		 * We are trying to enter the inactive state.		 */		if (client->naccepts > 0)			isc_socket_cancel(client->tcplistener, client->task,					  ISC_SOCKCANCEL_ACCEPT);		if (! (client->naccepts == 0)) {			/* Still waiting for accept cancel completion. */			return (ISC_TRUE);		}		/* 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. */			return (ISC_TRUE);		}		/* Recv cancel is complete. */		if (client->nctls > 0) {			/* Still waiting for control event to be delivered */			return (ISC_TRUE);		}		/* Deactivate the client. */		if (client->interface)			ns_interface_detach(&client->interface);		INSIST(client->naccepts == 0);		INSIST(client->recursionquota == NULL);		if (client->tcplistener != NULL)			isc_socket_detach(&client->tcplistener);		if (client->udpsocket != NULL)			isc_socket_detach(&client->udpsocket);		if (client->dispatch != NULL)			dns_dispatch_detach(&client->dispatch);		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		 * list shortly, and we need to keep the manager locked until		 * 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;			goto unlock;		}	}	if (client->state == NS_CLIENTSTATE_INACTIVE) {		INSIST(client->newstate == NS_CLIENTSTATE_FREED);		/*		 * We are trying to free the 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->state == NS_CLIENTSTATE_INACTIVE);		INSIST(client->recursionquota == NULL);		ns_query_free(client);		isc_mem_put(client->mctx, client->recvbuf, RECV_BUFFER_SIZE);		isc_event_free((isc_event_t **)&client->sendevent);		isc_event_free((isc_event_t **)&client->recvevent);		isc_timer_detach(&client->timer);		if (client->tcpbuf != NULL)			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_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->exiting &&			    ISC_LIST_EMPTY(manager->active) &&			    ISC_LIST_EMPTY(manager->inactive) &&			    ISC_LIST_EMPTY(manager->recursing))				destroy_manager = manager;		}		/*		 * Detaching the task must be done after unlinking from		 * the manager's lists because the manager accesses		 * client->task.		 */		if (client->task != NULL)			isc_task_detach(&client->task);		CTRACE("free");		client->magic = 0;		isc_mem_put(client->mctx, client, sizeof(*client));		goto unlock;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -