diff options
| author | Erwin Lansing <erwin@FreeBSD.org> | 2014-02-24 13:58:58 +0000 |
|---|---|---|
| committer | Erwin Lansing <erwin@FreeBSD.org> | 2014-02-24 13:58:58 +0000 |
| commit | 989b3b2d6068ce5b525479b7754977baf6364a7d (patch) | |
| tree | dbbce28742bfdb3ea58da4461b1bb3e5c2fcaa28 /lib/dns/dispatch.c | |
| parent | 98ec2cd1facbb6a0e284fd0bacab33fbafb76fb8 (diff) | |
Notes
Diffstat (limited to 'lib/dns/dispatch.c')
| -rw-r--r-- | lib/dns/dispatch.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 5063914a9b296..7af8e644b1971 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -706,8 +706,8 @@ destroy_disp_ok(dns_dispatch_t *disp) /* * Called when refcount reaches 0 (and safe to destroy). * - * The dispatcher must not be locked. - * The manager must be locked. + * The dispatcher must be locked. + * The manager must not be locked. */ static void destroy_disp(isc_task_t *task, isc_event_t *event) { @@ -778,6 +778,7 @@ port_search(dns_dispatch_t *disp, in_port_t port) { static dispportentry_t * new_portentry(dns_dispatch_t *disp, in_port_t port) { dispportentry_t *portentry; + dns_qid_t *qid; REQUIRE(disp->port_table != NULL); @@ -786,10 +787,13 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { return (portentry); portentry->port = port; - portentry->refs = 0; + portentry->refs = 1; ISC_LINK_INIT(portentry, link); + qid = DNS_QID(disp); + LOCK(&qid->lock); ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); + UNLOCK(&qid->lock); return (portentry); } @@ -800,7 +804,6 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) { static void deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { dispportentry_t *portentry = *portentryp; - isc_boolean_t unlink = ISC_FALSE; dns_qid_t *qid; REQUIRE(disp->port_table != NULL); @@ -809,15 +812,14 @@ deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { qid = DNS_QID(disp); LOCK(&qid->lock); portentry->refs--; - unlink = ISC_TF(portentry->refs == 0); - UNLOCK(&qid->lock); - if (unlink) { + if (portentry->refs == 0) { ISC_LIST_UNLINK(disp->port_table[portentry->port % DNS_DISPATCH_PORTTABLESIZE], portentry, link); isc_mempool_put(disp->portpool, portentry); } + UNLOCK(&qid->lock); *portentryp = NULL; } @@ -832,6 +834,7 @@ socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port, { dispsocket_t *dispsock; + REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); @@ -938,8 +941,11 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest, result = ISC_R_NOMEMORY; break; } + } else { + LOCK(&qid->lock); + portentry->refs++; + UNLOCK(&qid->lock); } - portentry->refs++; break; } else if (result == ISC_R_NOPERM) { char buf[ISC_SOCKADDR_FORMATSIZE]; @@ -1076,6 +1082,7 @@ entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id, { dns_dispentry_t *res; + REQUIRE(VALID_QID(qid)); REQUIRE(bucket < qid->qid_nbuckets); res = ISC_LIST_HEAD(qid->qid_table[bucket]); @@ -1428,8 +1435,8 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } /* - * If both dispatches are bound to an address then fail as - * the addresses can't be equal (enforced by the IP stack). + * If each dispatch is bound to a different address + * then fail. * * Note under Linux a packet can be sent out via IPv4 socket * and the response be received via a IPv6 socket. @@ -1444,7 +1451,8 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { } isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); - if (!isc_sockaddr_eqaddr(&a1, &resp->disp->local) && + if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && + !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && !isc_sockaddr_eqaddr(&a2, &disp->local)) { free_buffer(disp, ev->region.base, ev->region.length); goto unlock; @@ -2647,8 +2655,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, * MUST be unlocked, and not used by anything. */ static void -dispatch_free(dns_dispatch_t **dispp) -{ +dispatch_free(dns_dispatch_t **dispp) { dns_dispatch_t *disp; dns_dispatchmgr_t *mgr; int i; @@ -3311,17 +3318,17 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, */ LOCK(&qid->lock); id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp)); - bucket = dns_hash(qid, dest, id, localport); ok = ISC_FALSE; - for (i = 0; i < 64; i++) { + i = 0; + do { + bucket = dns_hash(qid, dest, id, localport); if (entry_search(qid, dest, id, localport, bucket) == NULL) { ok = ISC_TRUE; break; } id += qid->qid_increment; id &= 0x0000ffff; - bucket = dns_hash(qid, dest, id, localport); - } + } while (i++ < 64); UNLOCK(&qid->lock); if (!ok) { @@ -3331,9 +3338,9 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, res = isc_mempool_get(disp->mgr->rpool); if (res == NULL) { - UNLOCK(&disp->lock); if (dispsocket != NULL) destroy_dispsocket(disp, &dispsocket); + UNLOCK(&disp->lock); return (ISC_R_NOMEMORY); } @@ -3708,7 +3715,7 @@ dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { isc_event_free(ISC_EVENT_PTR(&newsevent)); return; } - memcpy(buf, sevent->region.base, sevent->n); + memmove(buf, sevent->region.base, sevent->n); newsevent->region.base = buf; newsevent->region.length = disp->mgr->buffersize; newsevent->n = sevent->n; |
