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

📄 resolver.c

📁 bind-3.2.
💻 C
📖 第 1 页 / 共 5 页
字号:
	/*	 * Check for any outstanding socket events.  If they exist, cancel	 * them and let the event handlers finish the cleanup.  The resolver	 * only needs to worry about managing the connect and send events;	 * the dispatcher manages the recv events.	 */	if (RESQUERY_CONNECTING(query))		/*		 * Cancel the connect.		 */		isc_socket_cancel(query->tcpsocket, NULL,				  ISC_SOCKCANCEL_CONNECT);	else if (RESQUERY_SENDING(query))		/*		 * Cancel the pending send.		 */		isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),				  NULL, ISC_SOCKCANCEL_SEND);	if (query->dispatch != NULL)		dns_dispatch_detach(&query->dispatch);	if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))		/*		 * It's safe to destroy the query now.		 */		resquery_destroy(&query);}static voidfctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {	resquery_t *query, *next_query;	FCTXTRACE("cancelqueries");	for (query = ISC_LIST_HEAD(fctx->queries);	     query != NULL;	     query = next_query) {		next_query = ISC_LIST_NEXT(query, link);		fctx_cancelquery(&query, NULL, NULL, no_response);	}}static voidfctx_cleanupfinds(fetchctx_t *fctx) {	dns_adbfind_t *find, *next_find;	REQUIRE(ISC_LIST_EMPTY(fctx->queries));	for (find = ISC_LIST_HEAD(fctx->finds);	     find != NULL;	     find = next_find) {		next_find = ISC_LIST_NEXT(find, publink);		ISC_LIST_UNLINK(fctx->finds, find, publink);		dns_adb_destroyfind(&find);	}	fctx->find = NULL;}static voidfctx_cleanupforwaddrs(fetchctx_t *fctx) {	dns_adbaddrinfo_t *addr, *next_addr;	REQUIRE(ISC_LIST_EMPTY(fctx->queries));	for (addr = ISC_LIST_HEAD(fctx->forwaddrs);	     addr != NULL;	     addr = next_addr) {		next_addr = ISC_LIST_NEXT(addr, publink);		ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);		dns_adb_freeaddrinfo(fctx->adb, &addr);	}}static inline voidfctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {	FCTXTRACE("stopeverything");	fctx_cancelqueries(fctx, no_response);	fctx_cleanupfinds(fctx);	fctx_cleanupforwaddrs(fctx);	fctx_stoptimer(fctx);}static inline voidfctx_sendevents(fetchctx_t *fctx, isc_result_t result) {	dns_fetchevent_t *event, *next_event;	isc_task_t *task;	/*	 * Caller must be holding the appropriate bucket lock.	 */	REQUIRE(fctx->state == fetchstate_done);	FCTXTRACE("sendevents");	for (event = ISC_LIST_HEAD(fctx->events);	     event != NULL;	     event = next_event) {		next_event = ISC_LIST_NEXT(event, ev_link);		ISC_LIST_UNLINK(fctx->events, event, ev_link);		task = event->ev_sender;		event->ev_sender = fctx;		if (!HAVE_ANSWER(fctx))			event->result = result;		INSIST(result != ISC_R_SUCCESS ||		       dns_rdataset_isassociated(event->rdataset) ||		       fctx->type == dns_rdatatype_any ||		       fctx->type == dns_rdatatype_sig);		isc_task_sendanddetach(&task, (isc_event_t **)&event);	}}static voidfctx_done(fetchctx_t *fctx, isc_result_t result) {	dns_resolver_t *res;	isc_boolean_t no_response;	FCTXTRACE("done");	res = fctx->res;	if (result == ISC_R_SUCCESS)		no_response = ISC_TRUE;	else		no_response = ISC_FALSE;	fctx_stopeverything(fctx, no_response);	LOCK(&res->buckets[fctx->bucketnum].lock);	fctx->state = fetchstate_done;	fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;	fctx_sendevents(fctx, result);	UNLOCK(&res->buckets[fctx->bucketnum].lock);}static voidresquery_senddone(isc_task_t *task, isc_event_t *event) {	isc_socketevent_t *sevent = (isc_socketevent_t *)event;	resquery_t *query = event->ev_arg;	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);	QTRACE("senddone");	/*	 * XXXRTH	 *	 * Currently we don't wait for the senddone event before retrying	 * a query.  This means that if we get really behind, we may end	 * up doing extra work!	 */	UNUSED(task);	INSIST(RESQUERY_SENDING(query));	query->sends--;	if (RESQUERY_CANCELED(query)) {		if (query->sends == 0) {			/*			 * This query was canceled while the			 * isc_socket_sendto() was in progress.			 */			if (query->tcpsocket != NULL)				isc_socket_detach(&query->tcpsocket);			resquery_destroy(&query);		}	} else if (sevent->result != ISC_R_SUCCESS)		fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);	isc_event_free(&event);}static inline isc_result_tfctx_addopt(dns_message_t *message) {	dns_rdataset_t *rdataset;	dns_rdatalist_t *rdatalist;	dns_rdata_t *rdata;	isc_result_t result;	rdatalist = NULL;	result = dns_message_gettemprdatalist(message, &rdatalist);	if (result != ISC_R_SUCCESS)		return (result);	rdata = NULL;	result = dns_message_gettemprdata(message, &rdata);	if (result != ISC_R_SUCCESS)		return (result);	rdataset = NULL;	result = dns_message_gettemprdataset(message, &rdataset);	if (result != ISC_R_SUCCESS)		return (result);	dns_rdataset_init(rdataset);	rdatalist->type = dns_rdatatype_opt;	rdatalist->covers = 0;	/*	 * Set Maximum UDP buffer size.	 */	rdatalist->rdclass = SEND_BUFFER_SIZE;	/*	 * Set EXTENDED-RCODE, VERSION, and Z to 0, and the DO bit to 1.	 */#ifdef ISC_RFC2535	rdatalist->ttl = DNS_MESSAGEEXTFLAG_DO;#else	rdatalist->ttl = 0;#endif	/*	 * No EDNS options.	 */	rdata->data = NULL;	rdata->length = 0;	rdata->rdclass = rdatalist->rdclass;	rdata->type = rdatalist->type;	rdata->flags = 0;	ISC_LIST_INIT(rdatalist->rdata);	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);	dns_rdatalist_tordataset(rdatalist, rdataset);	return (dns_message_setopt(message, rdataset));}static inline voidfctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {	unsigned int seconds;	/*	 * We retry every 2 seconds the first two times through the address	 * list, and then we do exponential back-off.	 */	if (fctx->restarts < 3)		seconds = 2;	else		seconds = (2 << (fctx->restarts - 1));	/*	 * Double the round-trip time and convert to seconds.	 */	rtt /= 500000;	/*	 * Always wait for at least the doubled round-trip time.	 */	if (seconds < rtt)		seconds = rtt;	/*	 * But don't ever wait for more than 30 seconds.	 */	if (seconds > 30)		seconds = 30;	isc_interval_set(&fctx->interval, seconds, 0);}static isc_result_tfctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,	   unsigned int options){	dns_resolver_t *res;	isc_task_t *task;	isc_result_t result;	resquery_t *query;	FCTXTRACE("query");	res = fctx->res;	task = res->buckets[fctx->bucketnum].task;	fctx_setretryinterval(fctx, addrinfo->srtt);	result = fctx_startidletimer(fctx);	if (result != ISC_R_SUCCESS)		return (result);	dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);	query = isc_mem_get(res->mctx, sizeof *query);	if (query == NULL) {		result = ISC_R_NOMEMORY;		goto stop_idle_timer;	}	query->mctx = res->mctx;	query->options = options;	query->attributes = 0;	query->sends = 0;	query->connects = 0;	/*	 * Note that the caller MUST guarantee that 'addrinfo' will remain	 * valid until this query is canceled.	 */	query->addrinfo = addrinfo;	result = isc_time_now(&query->start);	if (result != ISC_R_SUCCESS)		goto cleanup_query;	/*	 * If this is a TCP query, then we need to make a socket and	 * a dispatch for it here.  Otherwise we use the resolver's	 * shared dispatch.	 */	query->dispatchmgr = res->dispatchmgr;	query->dispatch = NULL;	query->tcpsocket = NULL;	if ((query->options & DNS_FETCHOPT_TCP) != 0) {		isc_sockaddr_t addr;		int pf;		pf = isc_sockaddr_pf(&addrinfo->sockaddr);		switch (pf) {		case PF_INET:			result = dns_dispatch_getlocaladdress(res->dispatchv4,							      &addr);			break;		case PF_INET6:			result = dns_dispatch_getlocaladdress(res->dispatchv6,							      &addr);			break;		default:			result = ISC_R_NOTIMPLEMENTED;			break;		}		if (result != ISC_R_SUCCESS)			goto cleanup_query;		isc_sockaddr_setport(&addr, 0);		result = isc_socket_create(res->socketmgr, pf,					   isc_sockettype_tcp,					   &query->tcpsocket);		if (result != ISC_R_SUCCESS)			goto cleanup_query;		result = isc_socket_bind(query->tcpsocket, &addr);		if (result != ISC_R_SUCCESS)			goto cleanup_socket;		/*		 * A dispatch will be created once the connect succeeds.		 */	} else {		switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {		case PF_INET:			dns_dispatch_attach(res->dispatchv4, &query->dispatch);			break;		case PF_INET6:			dns_dispatch_attach(res->dispatchv6, &query->dispatch);			break;		default:			result = ISC_R_NOTIMPLEMENTED;			goto cleanup_query;		}		/*		 * We should always have a valid dispatcher here.  If we		 * don't support a protocol family, then its dispatcher		 * will be NULL, but we shouldn't be finding addresses for		 * protocol types we don't support, so the dispatcher		 * we found should never be NULL.		 */		INSIST(query->dispatch != NULL);	}	query->dispentry = NULL;	query->fctx = fctx;	query->tsig = NULL;	query->tsigkey = NULL;	ISC_LINK_INIT(query, link);	query->magic = QUERY_MAGIC;	if ((query->options & DNS_FETCHOPT_TCP) != 0) {		/*		 * Connect to the remote server.		 *		 * XXXRTH  Should we attach to the socket?		 */		result = isc_socket_connect(query->tcpsocket,					    &addrinfo->sockaddr, task,					    resquery_connected, query);		if (result != ISC_R_SUCCESS)			goto cleanup_socket;		query->connects++;		QTRACE("connecting via TCP");	} else {		result = resquery_send(query);		if (result != ISC_R_SUCCESS)			goto cleanup_dispatch;	}	ISC_LIST_APPEND(fctx->queries, query, link);	return (ISC_R_SUCCESS); cleanup_socket:	isc_socket_detach(&query->tcpsocket); cleanup_dispatch:	if (query->dispatch != NULL)		dns_dispatch_detach(&query->dispatch); cleanup_query:	query->magic = 0;	isc_mem_put(res->mctx, query, sizeof *query); stop_idle_timer:	fctx_stopidletimer(fctx);	return (result);}static isc_result_tresquery_send(resquery_t *query) {	fetchctx_t *fctx;	isc_result_t result;	dns_name_t *qname = NULL;	dns_rdataset_t *qrdataset = NULL;	isc_region_t r;	dns_resolver_t *res;	isc_task_t *task;	isc_socket_t *socket;	isc_buffer_t tcpbuffer;	isc_sockaddr_t *address;	isc_buffer_t *buffer;	isc_netaddr_t ipaddr;	dns_tsigkey_t *tsigkey = NULL;	dns_peer_t *peer = NULL;	isc_boolean_t useedns;	dns_compress_t cctx;	isc_boolean_t cleanup_cctx = ISC_FALSE;	fctx = query->fctx;	QTRACE("send");	res = fctx->res;	task = res->buckets[fctx->bucketnum].task;	address = NULL;	if ((query->options & DNS_FETCHOPT_TCP) != 0) {		/*		 * Reserve space for the TCP message length.		 */		isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));		isc_buffer_init(&query->buffer, query->data + 2,				sizeof(query->data) - 2);		buffer = &tcpbuffer;	} else {		isc_buffer_init(&query->buffer, query->data,				sizeof(query->data));		buffer = &query->buffer;	}	result = dns_message_gettempname(fctx->qmessage, &qname);	if (result != ISC_R_SUCCESS)		goto cleanup_temps;	result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);	if (result != ISC_R_SUCCESS)		goto cleanup_temps;	/*	 * Get a query id from the dispatch.	 */	result = dns_dispatch_addresponse(query->dispatch,					  &query->addrinfo->sockaddr,					  task,					  resquery_response,					  query,					  &query->id,					  &query->dispentry);	if (result != ISC_R_SUCCESS)		goto cleanup_temps;	fctx->qmessage->opcode = dns_opcode_query;	/*	 * Set up question.	 */	dns_name_init(qname, NULL);	dns_name_clone(&fctx->name, qname);	dns_rdataset_init(qrdataset);	dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);	ISC_LIST_APPEND(qname->list, qrdataset, link);	dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);	qname = NULL;	qrdataset = NULL;	/*	 * Set RD if the client has requested that we do a recursive query,	 * or if we're sending to a forwarder.	 */	if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||	    ISFORWARDER(query->addrinfo))		fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;	/*	 * We don't have to set opcode because it defaults to query.	 */	fctx->qmessage->id = query->id;	/*	 * Convert the question to wire format.	 */	result = dns_compress_init(&cctx, -1, fctx->res->mctx);	if (result != ISC_R_SUCCESS)		goto cleanup_message;	cleanup_cctx = ISC_TRUE;

⌨️ 快捷键说明

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