📄 dispatch.c
字号:
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; mgr->state = 0; ISC_LIST_INIT(mgr->list); mgr->magic = DNS_DISPATCHMGR_MAGIC; if (entropy != NULL) isc_entropy_attach(entropy, &mgr->entropy); *mgrp = mgr; return (ISC_R_SUCCESS); kill_rpool: isc_mempool_destroy(&mgr->rpool); kill_epool: isc_mempool_destroy(&mgr->epool); kill_pool_lock: DESTROYLOCK(&mgr->pool_lock); kill_buffer_lock: DESTROYLOCK(&mgr->buffer_lock); kill_lock: DESTROYLOCK(&mgr->lock); deallocate: isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t)); isc_mem_detach(&mctx); return (result);}voiddns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) { REQUIRE(VALID_DISPATCHMGR(mgr)); if (mgr->blackhole != NULL) dns_acl_detach(&mgr->blackhole); dns_acl_attach(blackhole, &mgr->blackhole);}dns_acl_t *dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { REQUIRE(VALID_DISPATCHMGR(mgr)); return (mgr->blackhole);}static isc_result_tdns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, unsigned int maxbuffers, unsigned int buckets, unsigned int increment){ isc_result_t result; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); REQUIRE(maxbuffers > 0); REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ REQUIRE(increment > buckets); /* * Keep some number of items around. This should be a config * option. For now, keep 8, but later keep at least two even * if the caller wants less. This allows us to ensure certain * things, like an event can be "freed" and the next allocation * will always succeed. * * Note that if limits are placed on anything here, we use one * event internally, so the actual limit should be "wanted + 1." * * XXXMLG */ if (maxbuffers < 8) maxbuffers = 8; LOCK(&mgr->buffer_lock); if (mgr->bpool != NULL) { isc_mempool_setmaxalloc(mgr->bpool, maxbuffers); mgr->maxbuffers = maxbuffers; UNLOCK(&mgr->buffer_lock); return (ISC_R_SUCCESS); } if (isc_mempool_create(mgr->mctx, buffersize, &mgr->bpool) != ISC_R_SUCCESS) { return (ISC_R_NOMEMORY); } isc_mempool_setname(mgr->bpool, "dispmgr_bpool"); isc_mempool_setmaxalloc(mgr->bpool, maxbuffers); isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock); result = qid_allocate(mgr, buckets, increment, &mgr->qid); if (result != ISC_R_SUCCESS) goto cleanup; mgr->buffersize = buffersize; mgr->maxbuffers = maxbuffers; UNLOCK(&mgr->buffer_lock); return (ISC_R_SUCCESS); cleanup: isc_mempool_destroy(&mgr->bpool); UNLOCK(&mgr->buffer_lock); return (ISC_R_NOMEMORY);}voiddns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { dns_dispatchmgr_t *mgr; isc_boolean_t killit; REQUIRE(mgrp != NULL); REQUIRE(VALID_DISPATCHMGR(*mgrp)); mgr = *mgrp; *mgrp = NULL; LOCK(&mgr->lock); mgr->state |= MGR_SHUTTINGDOWN; killit = destroy_mgr_ok(mgr); UNLOCK(&mgr->lock); mgr_log(mgr, LVL(90), "destroy: killit=%d", killit); if (killit) destroy_mgr(&mgr);}#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))static isc_boolean_tlocal_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) { if (addr == NULL) return (ISC_TRUE); return (isc_sockaddr_equal(&disp->local, addr));}/* * Requires mgr be locked. * * No dispatcher can be locked by this thread when calling this function. * * * NOTE: * If a matching dispatcher is found, it is locked after this function * returns, and must be unlocked by the caller. */static isc_result_tdispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local, unsigned int attributes, unsigned int mask, dns_dispatch_t **dispp){ dns_dispatch_t *disp; isc_result_t result; /* * Make certain that we will not match a private dispatch. */ attributes &= ~DNS_DISPATCHATTR_PRIVATE; mask |= DNS_DISPATCHATTR_PRIVATE; disp = ISC_LIST_HEAD(mgr->list); while (disp != NULL) { LOCK(&disp->lock); if ((disp->shutting_down == 0) && ATTRMATCH(disp->attributes, attributes, mask) && local_addr_match(disp, local)) break; UNLOCK(&disp->lock); disp = ISC_LIST_NEXT(disp, link); } if (disp == NULL) { result = ISC_R_NOTFOUND; goto out; } *dispp = disp; result = ISC_R_SUCCESS; out: return (result);}static isc_result_tqid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, unsigned int increment, dns_qid_t **qidp){ dns_qid_t *qid; unsigned int i; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ REQUIRE(increment > buckets); REQUIRE(qidp != NULL && *qidp == NULL); qid = isc_mem_get(mgr->mctx, sizeof(*qid)); if (qid == NULL) return (ISC_R_NOMEMORY); qid->qid_table = isc_mem_get(mgr->mctx, buckets * sizeof(dns_displist_t)); if (qid->qid_table == NULL) { isc_mem_put(mgr->mctx, qid, sizeof(*qid)); return (ISC_R_NOMEMORY); } if (isc_mutex_init(&qid->lock) != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed"); isc_mem_put(mgr->mctx, qid->qid_table, buckets * sizeof(dns_displist_t)); isc_mem_put(mgr->mctx, qid, sizeof(*qid)); return (ISC_R_UNEXPECTED); } for (i = 0 ; i < buckets ; i++) ISC_LIST_INIT(qid->qid_table[i]); qid->qid_nbuckets = buckets; qid->qid_increment = increment; qid->magic = QID_MAGIC; /* * Initialize to a 32-bit LFSR. Both of these are from Applied * Cryptography. * * lfsr1: * x^32 + x^7 + x^5 + x^3 + x^2 + x + 1 * * lfsr2: * x^32 + x^7 + x^6 + x^2 + 1 */ isc_lfsr_init(&qid->qid_lfsr1, 0, 32, 0x80000057U, 0, reseed_lfsr, mgr); isc_lfsr_init(&qid->qid_lfsr2, 0, 32, 0x80000062U, 0, reseed_lfsr, mgr); *qidp = qid; return (ISC_R_SUCCESS);}static voidqid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { dns_qid_t *qid; REQUIRE(qidp != NULL); qid = *qidp; REQUIRE(VALID_QID(qid)); *qidp = NULL; qid->magic = 0; isc_mem_put(mctx, qid->qid_table, qid->qid_nbuckets * sizeof(dns_displist_t)); DESTROYLOCK(&qid->lock); isc_mem_put(mctx, qid, sizeof(*qid));}/* * Allocate and set important limits. */static isc_result_tdispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, dns_dispatch_t **dispp){ dns_dispatch_t *disp; isc_result_t res; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(dispp != NULL && *dispp == NULL); /* * Set up the dispatcher, mostly. Don't bother setting some of * the options that are controlled by tcp vs. udp, etc. */ disp = isc_mempool_get(mgr->dpool); if (disp == NULL) return (ISC_R_NOMEMORY); disp->magic = 0; disp->mgr = mgr; disp->maxrequests = maxrequests; disp->attributes = 0; ISC_LINK_INIT(disp, link); disp->refcount = 1; disp->recv_pending = 0; memset(&disp->local, 0, sizeof disp->local); disp->shutting_down = 0; disp->shutdown_out = 0; disp->connected = 0; disp->tcpmsg_valid = 0; disp->shutdown_why = ISC_R_UNEXPECTED; disp->requests = 0; disp->tcpbuffers = 0; disp->qid = NULL; if (isc_mutex_init(&disp->lock) != ISC_R_SUCCESS) { res = ISC_R_UNEXPECTED; UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed"); goto deallocate; } disp->failsafe_ev = allocate_event(disp); if (disp->failsafe_ev == NULL) { res = ISC_R_NOMEMORY; goto kill_lock; } disp->magic = DISPATCH_MAGIC; *dispp = disp; return (ISC_R_SUCCESS); /* * error returns */ kill_lock: DESTROYLOCK(&disp->lock); deallocate: isc_mempool_put(mgr->dpool, disp); return (res);}/* * MUST be unlocked, and not used by anthing. */static voiddispatch_free(dns_dispatch_t **dispp){ dns_dispatch_t *disp; dns_dispatchmgr_t *mgr; REQUIRE(VALID_DISPATCH(*dispp)); disp = *dispp; *dispp = NULL; mgr = disp->mgr; REQUIRE(VALID_DISPATCHMGR(mgr)); if (disp->tcpmsg_valid) { dns_tcpmsg_invalidate(&disp->tcpmsg); disp->tcpmsg_valid = 0; } INSIST(disp->tcpbuffers == 0); INSIST(disp->requests == 0); INSIST(disp->recv_pending == 0); isc_mempool_put(mgr->epool, disp->failsafe_ev); disp->failsafe_ev = NULL; if (disp->qid != NULL) qid_destroy(mgr->mctx, &disp->qid); disp->mgr = NULL; DESTROYLOCK(&disp->lock); disp->magic = 0; isc_mempool_put(mgr->dpool, disp);}isc_result_tdns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, isc_taskmgr_t *taskmgr, unsigned int buffersize, unsigned int maxbuffers, unsigned int maxrequests, unsigned int buckets, unsigned int increment, unsigned int attributes, dns_dispatch_t **dispp){ isc_result_t result; dns_dispatch_t *disp; UNUSED(maxbuffers); UNUSED(buffersize); REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp); REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0); REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0); attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */ LOCK(&mgr->lock); /* * dispatch_allocate() checks mgr for us. * qid_allocate() checks buckets and increment for us. */ disp = NULL; result = dispatch_allocate(mgr, maxrequests, &disp); if (result != ISC_R_SUCCESS) { UNLOCK(&mgr->lock); return (result); } result = qid_allocate(mgr, buckets, increment, &disp->qid); if (result != ISC_R_SUCCESS) goto deallocate_dispatch; disp->socktype = isc_sockettype_tcp; disp->socket = NULL; isc_socket_attach(sock, &disp->socket); disp->task = NULL; result = isc_task_create(taskmgr, 0, &disp->task); if (result != ISC_R_SUCCESS) goto kill_socket; disp->ctlevent = isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, destroy_disp, disp, sizeof(isc_event_t)); if (disp->ctlevent == NULL) goto kill_task; isc_task_setname(disp->task, "tcpdispatch", disp); dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); disp->tcpmsg_valid = 1; disp->attributes = attributes; /* * Append it to the dispatcher list. */ ISC_LIST_APPEND(mgr->list, disp, link); UNLOCK(&mgr->lock); mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp); dispatch_log(disp, LVL(90), "created task %p", disp->task); *dispp = disp; return (ISC_R_SUCCESS); /* * Error returns. */ kill_task: isc_task_detach(&disp->task); kill_socket: isc_socket_detach(&disp->socket); deallocate_dispatch: dispatch_free(&disp); UNLOCK(&mgr->lock); return (result);}isc_result_tdns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr, unsigned int buffersize, unsigned int maxbuffers, unsigned int maxrequests, unsigned int buckets, unsigned int increment, unsigned int attributes, unsigned int mask, dns_dispatch_t **dispp){ isc_result_t result; dns_dispatch_t *disp; REQUIRE(VALID_DISPATCHMGR(mgr)); REQUIRE(sockmgr != NULL); REQUIRE(localaddr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); REQUIRE(maxbuffers > 0); REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ REQUIRE(increment > buckets); REQUIRE(dispp != NULL && *dispp == NULL); REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0); result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers, buckets, increment); if (result != ISC_R_SUCCESS) return (result); LOCK(&mgr->lock); /* * First, see if we have a dispatcher that matches. */ disp = NULL; result = dispatch_find(mgr, localaddr, attributes, mask, &disp); if (result == ISC_R_SUCCESS) { disp->refcount++; if (disp->maxrequests < maxrequests) disp->maxrequests = maxrequests; if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0 && (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) { disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; if (disp->recv_pending != 0) isc_socket_cancel(disp->socket, disp->task, ISC_SOCKCANCEL_RECV); } UNLOCK(&disp->lock); UNLOCK(&mgr->lock); *dispp = disp; return (ISC_R_SUCCESS); } /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -