📄 dispatch.c
字号:
disp->recv_pending = 0; } if (disp->shutting_down) { /* * This dispatcher is shutting down. */ free_buffer(disp, ev->region.base, ev->region.length); isc_event_free(&ev_in); ev = NULL; killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) isc_task_send(disp->task, &disp->ctlevent); return; } if (ev->result != ISC_R_SUCCESS) { free_buffer(disp, ev->region.base, ev->region.length); if (ev->result != ISC_R_CANCELED) dispatch_log(disp, ISC_LOG_ERROR, "odd socket result in udp_recv(): %s", isc_result_totext(ev->result)); UNLOCK(&disp->lock); isc_event_free(&ev_in); return; } /* * If this is from a blackholed address, drop it. */ isc_netaddr_fromsockaddr(&netaddr, &ev->address); if (disp->mgr->blackhole != NULL && dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match, NULL) == ISC_R_SUCCESS && match > 0) { if (isc_log_wouldlog(dns_lctx, LVL(10))) { char netaddrstr[ISC_NETADDR_FORMATSIZE]; isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); dispatch_log(disp, LVL(10), "blackholed packet from %s", netaddrstr); } free_buffer(disp, ev->region.base, ev->region.length); goto restart; } /* * Peek into the buffer to see what we can see. */ isc_buffer_init(&source, ev->region.base, ev->region.length); isc_buffer_add(&source, ev->n); dres = dns_message_peekheader(&source, &id, &flags); if (dres != ISC_R_SUCCESS) { free_buffer(disp, ev->region.base, ev->region.length); dispatch_log(disp, LVL(10), "got garbage packet"); goto restart; } dispatch_log(disp, LVL(92), "got valid DNS message header, /QR %c, id %u", ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id); /* * Look at flags. If query, drop it. If response, * look to see where it goes. */ queue_response = ISC_FALSE; if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* query */ free_buffer(disp, ev->region.base, ev->region.length); goto restart; } /* response */ bucket = dns_hash(qid, &ev->address, id); LOCK(&qid->lock); resp = bucket_search(qid, &ev->address, id, bucket); dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; } queue_response = resp->item_out; rev = allocate_event(resp->disp); if (rev == NULL) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; } /* * At this point, rev contains the event we want to fill in, and * resp contains the information on the place to send it to. * Send the event off. */ isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length); isc_buffer_add(&rev->buffer, ev->n); rev->result = ISC_R_SUCCESS; rev->id = id; rev->addr = ev->address; rev->pktinfo = ev->pktinfo; rev->attributes = ev->attributes; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, resp->action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[a] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); resp->item_out = ISC_TRUE; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } unlock: UNLOCK(&qid->lock); /* * Restart recv() to get the next packet. */ restart: startrecv(disp); UNLOCK(&disp->lock); isc_event_free(&ev_in);}/* * General flow: * * If I/O result == CANCELED, EOF, or error, notify everyone as the * various queues drain. * * If query, restart. * * If response: * Allocate event, fill in details. * If cannot allocate, restart. * find target. If not found, restart. * if event queue is not empty, queue. else, send. * restart. */static voidtcp_recv(isc_task_t *task, isc_event_t *ev_in) { dns_dispatch_t *disp = ev_in->ev_arg; dns_tcpmsg_t *tcpmsg = &disp->tcpmsg; dns_messageid_t id; isc_result_t dres; unsigned int flags; dns_dispentry_t *resp; dns_dispatchevent_t *rev; unsigned int bucket; isc_boolean_t killit; isc_boolean_t queue_response; dns_qid_t *qid; int level; char buf[ISC_SOCKADDR_FORMATSIZE]; UNUSED(task); REQUIRE(VALID_DISPATCH(disp)); qid = disp->qid; dispatch_log(disp, LVL(90), "got TCP packet: requests %d, buffers %d, recvs %d", disp->requests, disp->tcpbuffers, disp->recv_pending); LOCK(&disp->lock); INSIST(disp->recv_pending != 0); disp->recv_pending = 0; if (disp->refcount == 0) { /* * This dispatcher is shutting down. Force cancelation. */ tcpmsg->result = ISC_R_CANCELED; } if (tcpmsg->result != ISC_R_SUCCESS) { switch (tcpmsg->result) { case ISC_R_CANCELED: break; case ISC_R_EOF: dispatch_log(disp, LVL(90), "shutting down on EOF"); do_cancel(disp); break; case ISC_R_CONNECTIONRESET: level = ISC_LOG_INFO; goto logit; default: level = ISC_LOG_ERROR; logit: isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf)); dispatch_log(disp, level, "shutting down due to TCP " "receive error: %s: %s", buf, isc_result_totext(tcpmsg->result)); do_cancel(disp); break; } /* * The event is statically allocated in the tcpmsg * structure, and destroy_disp() frees the tcpmsg, so we must * free the event *before* calling destroy_disp(). */ isc_event_free(&ev_in); disp->shutting_down = 1; disp->shutdown_why = tcpmsg->result; /* * If the recv() was canceled pass the word on. */ killit = destroy_disp_ok(disp); UNLOCK(&disp->lock); if (killit) isc_task_send(disp->task, &disp->ctlevent); return; } dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", tcpmsg->result, tcpmsg->buffer.length, tcpmsg->buffer.base); /* * Peek into the buffer to see what we can see. */ dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags); if (dres != ISC_R_SUCCESS) { dispatch_log(disp, LVL(10), "got garbage packet"); goto restart; } dispatch_log(disp, LVL(92), "got valid DNS message header, /QR %c, id %u", ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id); /* * Allocate an event to send to the query or response client, and * allocate a new buffer for our use. */ /* * Look at flags. If query, drop it. If response, * look to see where it goes. */ queue_response = ISC_FALSE; if ((flags & DNS_MESSAGEFLAG_QR) == 0) { /* * Query. */ goto restart; } /* * Response. */ bucket = dns_hash(qid, &tcpmsg->address, id); LOCK(&qid->lock); resp = bucket_search(qid, &tcpmsg->address, id, bucket); dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", bucket, (resp == NULL ? "not found" : "found")); if (resp == NULL) goto unlock; queue_response = resp->item_out; rev = allocate_event(disp); if (rev == NULL) goto unlock; /* * At this point, rev contains the event we want to fill in, and * resp contains the information on the place to send it to. * Send the event off. */ dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer); disp->tcpbuffers++; rev->result = ISC_R_SUCCESS; rev->id = id; rev->addr = tcpmsg->address; if (queue_response) { ISC_LIST_APPEND(resp->items, rev, ev_link); } else { ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, resp->action, resp->arg, resp, NULL, NULL); request_log(disp, resp, LVL(90), "[b] Sent event %p buffer %p len %d to task %p", rev, rev->buffer.base, rev->buffer.length, resp->task); resp->item_out = ISC_TRUE; isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); } unlock: UNLOCK(&qid->lock); /* * Restart recv() to get the next packet. */ restart: startrecv(disp); UNLOCK(&disp->lock); isc_event_free(&ev_in);}/* * disp must be locked. */static voidstartrecv(dns_dispatch_t *disp) { isc_result_t res; isc_region_t region; if (disp->shutting_down == 1) return; if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) return; if (disp->recv_pending != 0) return; if (disp->mgr->buffers >= disp->mgr->maxbuffers) return; switch (disp->socktype) { /* * UDP reads are always maximal. */ case isc_sockettype_udp: region.length = disp->mgr->buffersize; region.base = allocate_udp_buffer(disp); if (region.base == NULL) return; res = isc_socket_recv(disp->socket, ®ion, 1, disp->task, udp_recv, disp); if (res != ISC_R_SUCCESS) { free_buffer(disp, region.base, region.length); disp->shutdown_why = res; disp->shutting_down = 1; do_cancel(disp); return; } INSIST(disp->recv_pending == 0); disp->recv_pending = 1; break; case isc_sockettype_tcp: res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task, tcp_recv, disp); if (res != ISC_R_SUCCESS) { disp->shutdown_why = res; disp->shutting_down = 1; do_cancel(disp); return; } INSIST(disp->recv_pending == 0); disp->recv_pending = 1; break; }}/* * Mgr must be locked when calling this function. */static isc_boolean_tdestroy_mgr_ok(dns_dispatchmgr_t *mgr) { mgr_log(mgr, LVL(90), "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, " "epool=%d, rpool=%d, dpool=%d", MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list), isc_mempool_getallocated(mgr->epool), isc_mempool_getallocated(mgr->rpool), isc_mempool_getallocated(mgr->dpool)); if (!MGR_IS_SHUTTINGDOWN(mgr)) return (ISC_FALSE); if (!ISC_LIST_EMPTY(mgr->list)) return (ISC_FALSE); if (isc_mempool_getallocated(mgr->epool) != 0) return (ISC_FALSE); if (isc_mempool_getallocated(mgr->rpool) != 0) return (ISC_FALSE); if (isc_mempool_getallocated(mgr->dpool) != 0) return (ISC_FALSE); return (ISC_TRUE);}/* * Mgr must be unlocked when calling this function. */static voiddestroy_mgr(dns_dispatchmgr_t **mgrp) { isc_mem_t *mctx; dns_dispatchmgr_t *mgr; mgr = *mgrp; *mgrp = NULL; mctx = mgr->mctx; mgr->magic = 0; mgr->mctx = NULL; DESTROYLOCK(&mgr->lock); mgr->state = 0; isc_mempool_destroy(&mgr->epool); isc_mempool_destroy(&mgr->rpool); isc_mempool_destroy(&mgr->dpool); isc_mempool_destroy(&mgr->bpool); DESTROYLOCK(&mgr->pool_lock); if (mgr->entropy != NULL) isc_entropy_detach(&mgr->entropy); if (mgr->qid != NULL) qid_destroy(mctx, &mgr->qid); DESTROYLOCK(&mgr->buffer_lock); if (mgr->blackhole != NULL) dns_acl_detach(&mgr->blackhole); if (mgr->portlist != NULL) dns_portlist_detach(&mgr->portlist); isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t)); isc_mem_detach(&mctx);}static isc_result_tcreate_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local, isc_socket_t **sockp){ isc_socket_t *sock; isc_result_t result; sock = NULL; result = isc_socket_create(mgr, isc_sockaddr_pf(local), isc_sockettype_udp, &sock); if (result != ISC_R_SUCCESS) return (result);#ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(sock, ISC_TRUE);#endif result = isc_socket_bind(sock, local); if (result != ISC_R_SUCCESS) { isc_socket_detach(&sock); return (result); } *sockp = sock; return (ISC_R_SUCCESS);}/* * Publics. */isc_result_tdns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy, dns_dispatchmgr_t **mgrp){ dns_dispatchmgr_t *mgr; isc_result_t result; REQUIRE(mctx != NULL); REQUIRE(mgrp != NULL && *mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); if (mgr == NULL) return (ISC_R_NOMEMORY); mgr->mctx = NULL; isc_mem_attach(mctx, &mgr->mctx); mgr->blackhole = NULL; mgr->portlist = NULL; result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) goto deallocate; result = isc_mutex_init(&mgr->buffer_lock); if (result != ISC_R_SUCCESS) goto kill_lock; result = isc_mutex_init(&mgr->pool_lock); if (result != ISC_R_SUCCESS) goto kill_buffer_lock; mgr->epool = NULL; if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t), &mgr->epool) != ISC_R_SUCCESS) { result = ISC_R_NOMEMORY; goto kill_pool_lock; } mgr->rpool = NULL; if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t), &mgr->rpool) != ISC_R_SUCCESS) { result = ISC_R_NOMEMORY; goto kill_epool; } mgr->dpool = NULL; if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t), &mgr->dpool) != ISC_R_SUCCESS) { result = ISC_R_NOMEMORY; goto kill_rpool; } isc_mempool_setname(mgr->epool, "dispmgr_epool"); isc_mempool_setfreemax(mgr->epool, 1024); isc_mempool_associatelock(mgr->epool, &mgr->pool_lock); isc_mempool_setname(mgr->rpool, "dispmgr_rpool"); isc_mempool_setfreemax(mgr->rpool, 1024); isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock); isc_mempool_setname(mgr->dpool, "dispmgr_dpool"); isc_mempool_setfreemax(mgr->dpool, 1024); isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock); mgr->buffers = 0; mgr->buffersize = 0; mgr->maxbuffers = 0; mgr->bpool = NULL; mgr->entropy = NULL; mgr->qid = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -