📄 dispatch.c
字号:
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);}voiddns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr, dns_portlist_t *portlist){ REQUIRE(VALID_DISPATCHMGR(mgr)); if (mgr->portlist != NULL) dns_portlist_detach(&mgr->portlist); if (portlist != NULL) dns_portlist_attach(portlist, &mgr->portlist);}dns_portlist_t *dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) { REQUIRE(VALID_DISPATCHMGR(mgr)); return (mgr->portlist);}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);}static isc_boolean_tblacklisted(dns_dispatchmgr_t *mgr, isc_socket_t *sock) { isc_sockaddr_t sockaddr; isc_result_t result; if (mgr->portlist == NULL) return (ISC_FALSE); result = isc_socket_getsockname(sock, &sockaddr); if (result != ISC_R_SUCCESS) return (ISC_FALSE); if (mgr->portlist != NULL && dns_portlist_match(mgr->portlist, isc_sockaddr_pf(&sockaddr), isc_sockaddr_getport(&sockaddr))) return (ISC_TRUE); return (ISC_FALSE);}#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))static isc_boolean_tlocal_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) { isc_sockaddr_t sockaddr; isc_result_t result; if (addr == NULL) return (ISC_TRUE); /* * Don't match wildcard ports against newly blacklisted ports. */ if (disp->mgr->portlist != NULL && isc_sockaddr_getport(addr) == 0 && isc_sockaddr_getport(&disp->local) == 0 && blacklisted(disp->mgr, disp->socket)) return (ISC_FALSE); /* * Check if we match the binding <address,port>. * Wildcard ports match/fail here. */ if (isc_sockaddr_equal(&disp->local, addr)) return (ISC_TRUE); if (isc_sockaddr_getport(addr) == 0) return (ISC_FALSE); /* * Check if we match a bound wildcard port <address,port>. */ if (!isc_sockaddr_eqaddr(&disp->local, addr)) return (ISC_FALSE); result = isc_socket_getsockname(disp->socket, &sockaddr); if (result != ISC_R_SUCCESS) return (ISC_FALSE); return (isc_sockaddr_equal(&sockaddr, 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++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -