mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-10 12:40:00 -04:00
dispatch: Fix several connect-related issues
- startrecv() and getnext() have been rewritten. - Don't set TCP flag when connecting a UDP dispatch. - Prevent TCP connections from trying to connect twice. - dns_dispatch_gettcp() can now find a matching TCP dispatch that has not yet fully connected, and attach to it. when the connection is completed, the connect callbacks are run for all of the pending entries. - An atomic 'state' variable is now used for connection state instead of attributes. - When dns_dispatch_cancel() is called on a TCP dispatch entry, only that one entry is canceled. the dispatch itself should not be shut down until there are no dispatch entries left associated with it. - Other incidental cleanup, including removing DNS_DISPATCHATTR_IPV4 and _IPV6 (they were being set in the dispatch attributes but never used), cleaning up dns_requestmgr_create(), and renaming dns_dispatch_read() to the more descriptive dns_dispatch_resume().
This commit is contained in:
parent
e317386090
commit
8551ad026f
11 changed files with 339 additions and 385 deletions
|
|
@ -1258,7 +1258,6 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
|
|||
isc_result_t result = ISC_R_FAILURE;
|
||||
dns_dispatch_t *disp = NULL;
|
||||
isc_sockaddr_t sa;
|
||||
unsigned int attrs = 0;
|
||||
const cfg_obj_t *obj = NULL;
|
||||
isc_dscp_t dscp = -1;
|
||||
|
||||
|
|
@ -1315,7 +1314,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
|
|||
}
|
||||
}
|
||||
|
||||
result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, attrs, &disp);
|
||||
result = dns_dispatch_createudp(named_g_dispatchmgr, &sa, &disp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_sockaddr_t any;
|
||||
char buf[ISC_SOCKADDR_FORMATSIZE];
|
||||
|
|
@ -10330,7 +10329,6 @@ named_add_reserved_dispatch(named_server_t *server,
|
|||
in_port_t port;
|
||||
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
|
||||
isc_result_t result;
|
||||
unsigned int attrs = 0;
|
||||
|
||||
REQUIRE(NAMED_SERVER_VALID(server));
|
||||
|
||||
|
|
@ -10358,7 +10356,7 @@ named_add_reserved_dispatch(named_server_t *server,
|
|||
dispatch->dispatch = NULL;
|
||||
|
||||
result = dns_dispatch_createudp(named_g_dispatchmgr, &dispatch->addr,
|
||||
attrs, &dispatch->dispatch);
|
||||
&dispatch->dispatch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -936,14 +936,14 @@ setup_system(void) {
|
|||
|
||||
if (have_ipv6) {
|
||||
isc_sockaddr_any6(&bind_any6);
|
||||
result = dns_dispatch_createudp(dispatchmgr, &bind_any6, 0,
|
||||
result = dns_dispatch_createudp(dispatchmgr, &bind_any6,
|
||||
&dispatchv6);
|
||||
check_result(result, "dns_dispatch_createudp (v6)");
|
||||
}
|
||||
|
||||
if (have_ipv4) {
|
||||
isc_sockaddr_any(&bind_any);
|
||||
result = dns_dispatch_createudp(dispatchmgr, &bind_any, 0,
|
||||
result = dns_dispatch_createudp(dispatchmgr, &bind_any,
|
||||
&dispatchv4);
|
||||
check_result(result, "dns_dispatch_createudp (v4)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ main(int argc, char *argv[]) {
|
|||
RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
|
||||
|
||||
RUNCHECK(dns_dispatch_createudp(
|
||||
dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchv4));
|
||||
dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchv4));
|
||||
RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
|
||||
NULL, &requestmgr));
|
||||
|
||||
|
|
|
|||
|
|
@ -228,8 +228,7 @@ main(int argc, char *argv[]) {
|
|||
RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
|
||||
|
||||
isc_sockaddr_any(&bind_any);
|
||||
RUNCHECK(
|
||||
dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4));
|
||||
RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4));
|
||||
RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
|
||||
NULL, &requestmgr));
|
||||
|
||||
|
|
|
|||
|
|
@ -171,8 +171,7 @@ main(int argc, char **argv) {
|
|||
RUNCHECK(isc_task_create(taskmgr, 0, &task));
|
||||
RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
|
||||
isc_sockaddr_any(&bind_any);
|
||||
RUNCHECK(
|
||||
dns_dispatch_createudp(dispatchmgr, &bind_any, 0, &dispatchv4));
|
||||
RUNCHECK(dns_dispatch_createudp(dispatchmgr, &bind_any, &dispatchv4));
|
||||
RUNCHECK(dns_requestmgr_create(mctx, taskmgr, dispatchmgr, dispatchv4,
|
||||
NULL, &requestmgr));
|
||||
|
||||
|
|
|
|||
|
|
@ -2129,7 +2129,7 @@ main(int argc, char *argv[]) {
|
|||
isc_sockaddr_any6(&bind_any);
|
||||
}
|
||||
RUNCHECK(dns_dispatch_createudp(
|
||||
dispatchmgr, have_src ? &srcaddr : &bind_any, 0, &dispatchvx));
|
||||
dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchvx));
|
||||
|
||||
RUNCHECK(dns_requestmgr_create(
|
||||
mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
|
|||
localaddr = &anyaddr;
|
||||
}
|
||||
|
||||
result = dns_dispatch_createudp(dispatchmgr, localaddr, 0, &disp);
|
||||
result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
*dispp = disp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/netmgr.h>
|
||||
|
|
@ -89,6 +90,7 @@ struct dns_dispentry {
|
|||
bool canceled;
|
||||
ISC_LINK(dns_dispentry_t) link;
|
||||
ISC_LINK(dns_dispentry_t) alink;
|
||||
ISC_LINK(dns_dispentry_t) plink;
|
||||
};
|
||||
|
||||
/*%
|
||||
|
|
@ -98,6 +100,12 @@ struct dns_dispentry {
|
|||
#define DNS_DISPATCH_UDPBUFSIZE 4096
|
||||
#endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */
|
||||
|
||||
typedef enum {
|
||||
DNS_DISPATCHSTATE_NONE = 0UL,
|
||||
DNS_DISPATCHSTATE_CONNECTING,
|
||||
DNS_DISPATCHSTATE_CONNECTED
|
||||
} dns_dispatchstate_t;
|
||||
|
||||
struct dns_dispatch {
|
||||
/* Unlocked. */
|
||||
unsigned int magic; /*%< magic */
|
||||
|
|
@ -113,10 +121,11 @@ struct dns_dispatch {
|
|||
/* Locked by "lock". */
|
||||
isc_mutex_t lock; /*%< locks all below */
|
||||
isc_socktype_t socktype;
|
||||
unsigned int attributes;
|
||||
atomic_uint_fast32_t state;
|
||||
isc_refcount_t references;
|
||||
unsigned int shutdown_out : 1;
|
||||
|
||||
ISC_LIST(dns_dispentry_t) pending;
|
||||
ISC_LIST(dns_dispentry_t) active;
|
||||
unsigned int nsockets;
|
||||
|
||||
|
|
@ -193,15 +202,15 @@ static void
|
|||
dispatch_free(dns_dispatch_t **dispp);
|
||||
static isc_result_t
|
||||
dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
unsigned int attributes, dns_dispatch_t **dispp);
|
||||
dns_dispatch_t **dispp);
|
||||
static void
|
||||
qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp);
|
||||
static void
|
||||
qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
|
||||
static inline isc_nmhandle_t *
|
||||
getentryhandle(dns_dispentry_t *resp);
|
||||
static void
|
||||
startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||
startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||
void
|
||||
dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout);
|
||||
|
||||
#define LVL(x) ISC_LOG_DEBUG(x)
|
||||
|
||||
|
|
@ -327,7 +336,13 @@ deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) {
|
|||
ISC_LIST_UNLINK(disp->active, resp, alink);
|
||||
}
|
||||
|
||||
if (ISC_LINK_LINKED(resp, plink)) {
|
||||
ISC_LIST_UNLINK(disp->pending, resp, plink);
|
||||
}
|
||||
|
||||
if (resp->handle != NULL) {
|
||||
INSIST(disp->socktype == isc_socktype_udp);
|
||||
|
||||
isc_nm_cancelread(resp->handle);
|
||||
isc_nmhandle_detach(&resp->handle);
|
||||
}
|
||||
|
|
@ -418,6 +433,11 @@ dispentry_detach(dns_dispentry_t **respp) {
|
|||
* if event queue is not empty, queue. else, send.
|
||||
* restart.
|
||||
*/
|
||||
|
||||
/* FIXME: If we read invalid packet, we never receive next that could be valid
|
||||
* and we also don't notify the read callback
|
||||
*/
|
||||
|
||||
static void
|
||||
udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
||||
void *arg) {
|
||||
|
|
@ -431,7 +451,6 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
isc_netaddr_t netaddr;
|
||||
int match;
|
||||
dispatch_cb_t response = NULL;
|
||||
bool nomore = true;
|
||||
|
||||
REQUIRE(VALID_RESPONSE(resp));
|
||||
REQUIRE(VALID_DISPATCH(resp->disp));
|
||||
|
|
@ -461,14 +480,6 @@ udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
peer = isc_nmhandle_peeraddr(handle);
|
||||
isc_netaddr_fromsockaddr(&netaddr, &peer);
|
||||
|
||||
/* if (eresult == ISC_R_TIMEDOUT && resp->timedout != NULL) { */
|
||||
/* resp->timedout(handle, ISC_R_TIMEDOUT, resp->arg); */
|
||||
/* if (isc_nmhandle_timer_running(handle)) { */
|
||||
/* nomore = false; */
|
||||
/* goto unlock; */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
if (eresult != ISC_R_SUCCESS) {
|
||||
/*
|
||||
* This is most likely a network error on a connected
|
||||
|
|
@ -547,9 +558,7 @@ unlock:
|
|||
response(eresult, region, resp->arg);
|
||||
}
|
||||
|
||||
if (nomore) {
|
||||
dispentry_detach(&resp);
|
||||
}
|
||||
dispentry_detach(&resp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -570,9 +579,8 @@ unlock:
|
|||
static void
|
||||
tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
||||
void *arg) {
|
||||
dns_dispentry_t *resp0 = (dns_dispentry_t *)arg;
|
||||
dns_dispatch_t *disp = (dns_dispatch_t *)arg;
|
||||
dns_dispentry_t *resp = NULL;
|
||||
dns_dispatch_t *disp = NULL;
|
||||
dns_messageid_t id;
|
||||
isc_result_t dres;
|
||||
unsigned int flags;
|
||||
|
|
@ -583,10 +591,7 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
isc_buffer_t source;
|
||||
isc_sockaddr_t peer;
|
||||
|
||||
REQUIRE(VALID_RESPONSE(resp0));
|
||||
REQUIRE(VALID_DISPATCH(resp0->disp));
|
||||
|
||||
disp = resp0->disp;
|
||||
REQUIRE(VALID_DISPATCH(disp));
|
||||
|
||||
qid = disp->mgr->qid;
|
||||
|
||||
|
|
@ -597,46 +602,43 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
|
||||
peer = isc_nmhandle_peeraddr(handle);
|
||||
|
||||
if (eresult != ISC_R_SUCCESS) {
|
||||
switch (eresult) {
|
||||
case ISC_R_CANCELED:
|
||||
dispatch_log(disp, LVL(90), "shutting down on cancel");
|
||||
break;
|
||||
switch (eresult) {
|
||||
case ISC_R_SUCCESS:
|
||||
/* got our answer */
|
||||
break;
|
||||
case ISC_R_CANCELED:
|
||||
dispatch_log(disp, LVL(90), "shutting down on cancel");
|
||||
goto unlock;
|
||||
|
||||
case ISC_R_EOF:
|
||||
dispatch_log(disp, LVL(90), "shutting down on EOF");
|
||||
break;
|
||||
case ISC_R_EOF:
|
||||
dispatch_log(disp, LVL(90), "shutting down on EOF");
|
||||
goto unlock;
|
||||
|
||||
case ISC_R_TIMEDOUT:
|
||||
/*
|
||||
* Time out the first active response for which
|
||||
* no event has already been sent.
|
||||
* FIXME: The code doesn't match the description
|
||||
*/
|
||||
for (resp = ISC_LIST_HEAD(disp->active); resp != NULL;
|
||||
resp = ISC_LIST_NEXT(resp, alink))
|
||||
{
|
||||
ISC_LIST_UNLINK(disp->active, resp, alink);
|
||||
ISC_LIST_APPEND(disp->active, resp, alink);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ISC_R_TIMEDOUT:
|
||||
/*
|
||||
* Time out the first active response for which
|
||||
* no event has already been sent.
|
||||
*/
|
||||
resp = ISC_LIST_HEAD(disp->active);
|
||||
INSIST(resp != NULL);
|
||||
|
||||
default:
|
||||
if (eresult == ISC_R_CONNECTIONRESET) {
|
||||
level = ISC_LOG_INFO;
|
||||
} else {
|
||||
level = ISC_LOG_ERROR;
|
||||
}
|
||||
ISC_LIST_UNLINK(disp->active, resp, alink);
|
||||
ISC_LIST_APPEND(disp->active, resp, alink);
|
||||
|
||||
isc_sockaddr_format(&peer, buf, sizeof(buf));
|
||||
dispatch_log(disp, level,
|
||||
"shutting down due to TCP "
|
||||
"receive error: %s: %s",
|
||||
buf, isc_result_totext(eresult));
|
||||
break;
|
||||
goto unlock;
|
||||
|
||||
default:
|
||||
if (eresult == ISC_R_CONNECTIONRESET) {
|
||||
level = ISC_LOG_INFO;
|
||||
} else {
|
||||
level = ISC_LOG_ERROR;
|
||||
}
|
||||
|
||||
isc_sockaddr_format(&peer, buf, sizeof(buf));
|
||||
dispatch_log(disp, level,
|
||||
"shutting down due to TCP "
|
||||
"receive error: %s: %s",
|
||||
buf, isc_result_totext(eresult));
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
|
|
@ -684,22 +686,18 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
|
|||
bucket, (resp == NULL ? "not found" : "found"));
|
||||
UNLOCK(&qid->lock);
|
||||
|
||||
if (resp == NULL) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
next:
|
||||
startrecv(disp, resp0);
|
||||
/* Restart the reading from the TCP socket */
|
||||
dispatch_getnext(disp, resp, -1);
|
||||
|
||||
unlock:
|
||||
isc_nmhandle_detach(&handle);
|
||||
UNLOCK(&disp->lock);
|
||||
|
||||
dispentry_detach(&resp0);
|
||||
|
||||
if (resp != NULL) {
|
||||
resp->response(eresult, region, resp->arg);
|
||||
}
|
||||
|
||||
dns_dispatch_detach(&disp);
|
||||
}
|
||||
|
||||
/*%
|
||||
|
|
@ -936,8 +934,8 @@ qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
|
|||
* Allocate and set important limits.
|
||||
*/
|
||||
static void
|
||||
dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf,
|
||||
unsigned int attributes, dns_dispatch_t **dispp) {
|
||||
dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type,
|
||||
dns_dispatch_t **dispp) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
|
||||
REQUIRE(VALID_DISPATCHMGR(mgr));
|
||||
|
|
@ -955,38 +953,7 @@ dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, int pf,
|
|||
isc_refcount_init(&disp->references, 1);
|
||||
ISC_LINK_INIT(disp, link);
|
||||
ISC_LIST_INIT(disp->active);
|
||||
|
||||
switch (type) {
|
||||
case isc_socktype_tcp:
|
||||
disp->attributes |= DNS_DISPATCHATTR_TCP;
|
||||
break;
|
||||
case isc_socktype_udp:
|
||||
disp->attributes |= DNS_DISPATCHATTR_UDP;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
switch (pf) {
|
||||
case PF_INET:
|
||||
disp->attributes |= DNS_DISPATCHATTR_IPV4;
|
||||
break;
|
||||
case PF_INET6:
|
||||
disp->attributes |= DNS_DISPATCHATTR_IPV6;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set whatever attributes were passed in that haven't been
|
||||
* reset automatically by the code above.
|
||||
*/
|
||||
attributes &= ~(DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP |
|
||||
DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6);
|
||||
disp->attributes |= attributes;
|
||||
ISC_LIST_INIT(disp->pending);
|
||||
|
||||
isc_mutex_init(&disp->lock);
|
||||
|
||||
|
|
@ -1022,10 +989,9 @@ dispatch_free(dns_dispatch_t **dispp) {
|
|||
|
||||
isc_result_t
|
||||
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
const isc_sockaddr_t *destaddr, unsigned int attributes,
|
||||
isc_dscp_t dscp, dns_dispatch_t **dispp) {
|
||||
const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
|
||||
dns_dispatch_t **dispp) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
int pf;
|
||||
|
||||
REQUIRE(VALID_DISPATCHMGR(mgr));
|
||||
REQUIRE(destaddr != NULL);
|
||||
|
|
@ -1034,14 +1000,15 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
|
||||
LOCK(&mgr->lock);
|
||||
|
||||
pf = isc_sockaddr_pf(destaddr);
|
||||
dispatch_allocate(mgr, isc_socktype_tcp, pf, attributes, &disp);
|
||||
dispatch_allocate(mgr, isc_socktype_tcp, &disp);
|
||||
|
||||
disp->peer = *destaddr;
|
||||
|
||||
if (localaddr != NULL) {
|
||||
disp->local = *localaddr;
|
||||
} else {
|
||||
int pf;
|
||||
pf = isc_sockaddr_pf(destaddr);
|
||||
isc_sockaddr_anyofpf(&disp->local, pf);
|
||||
isc_sockaddr_setport(&disp->local, 0);
|
||||
}
|
||||
|
|
@ -1049,6 +1016,8 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
/*
|
||||
* Append it to the dispatcher list.
|
||||
*/
|
||||
|
||||
/* FIXME: There should be a lookup hashtable here */
|
||||
ISC_LIST_APPEND(mgr->list, disp, link);
|
||||
UNLOCK(&mgr->lock);
|
||||
|
||||
|
|
@ -1062,28 +1031,25 @@ dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
#define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
|
||||
|
||||
isc_result_t
|
||||
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
|
||||
const isc_sockaddr_t *localaddr, bool *connected,
|
||||
dns_dispatch_t **dispp) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
unsigned int attributes, mask;
|
||||
|
||||
REQUIRE(VALID_DISPATCHMGR(mgr));
|
||||
REQUIRE(destaddr != NULL);
|
||||
REQUIRE(connected != NULL);
|
||||
REQUIRE(dispp != NULL && *dispp == NULL);
|
||||
|
||||
/* First pass */
|
||||
attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
|
||||
mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
|
||||
DNS_DISPATCHATTR_CONNECTED;
|
||||
/* First pass, look for connected TCP dispatches */
|
||||
*connected = true;
|
||||
|
||||
LOCK(&mgr->lock);
|
||||
again:
|
||||
disp = ISC_LIST_HEAD(mgr->list);
|
||||
while (disp != NULL && *dispp == NULL) {
|
||||
for (disp = ISC_LIST_HEAD(mgr->list); disp != NULL && *dispp == NULL;
|
||||
disp = ISC_LIST_NEXT(disp, link))
|
||||
{
|
||||
isc_sockaddr_t sockname;
|
||||
isc_sockaddr_t peeraddr;
|
||||
|
||||
|
|
@ -1097,23 +1063,41 @@ again:
|
|||
peeraddr = disp->peer;
|
||||
}
|
||||
|
||||
if (ATTRMATCH(disp->attributes, attributes, mask) &&
|
||||
(localaddr == NULL ||
|
||||
isc_sockaddr_eqaddr(localaddr, &disp->local)))
|
||||
if (*connected == true &&
|
||||
atomic_load(&disp->state) != DNS_DISPATCHSTATE_CONNECTED)
|
||||
{
|
||||
if (isc_sockaddr_equal(destaddr, &peeraddr) &&
|
||||
(localaddr == NULL ||
|
||||
isc_sockaddr_eqaddr(localaddr, &sockname)))
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* We don't reuse UDP sockets */
|
||||
if (disp->socktype != isc_socktype_tcp) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Different destination address */
|
||||
if (!isc_sockaddr_equal(destaddr, &peeraddr)) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Different local addr */
|
||||
if (localaddr != NULL) {
|
||||
/* FIXME: This is weird as sockname == disp-local */
|
||||
if (!isc_sockaddr_eqaddr(localaddr, &disp->local) ||
|
||||
!isc_sockaddr_eqaddr(localaddr, &sockname))
|
||||
{
|
||||
/* attach */
|
||||
dns_dispatch_attach(disp, dispp);
|
||||
if (connected != NULL) {
|
||||
*connected = true;
|
||||
}
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The conditions match:
|
||||
* 1. socktype is TCP
|
||||
* 2. destination address is same
|
||||
* 3. local address is either NULL or same
|
||||
*/
|
||||
dns_dispatch_attach(disp, dispp);
|
||||
unlock:
|
||||
UNLOCK(&disp->lock);
|
||||
disp = ISC_LIST_NEXT(disp, link);
|
||||
}
|
||||
|
||||
if (*dispp != NULL) {
|
||||
|
|
@ -1121,10 +1105,9 @@ again:
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
if (connected != NULL) {
|
||||
/* Second pass, only if connected != NULL */
|
||||
attributes = DNS_DISPATCHATTR_TCP;
|
||||
connected = NULL;
|
||||
if (*connected) {
|
||||
/* Second pass, look also for not-yet-connected dispatch */
|
||||
*connected = false;
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
|
@ -1134,7 +1117,7 @@ again:
|
|||
|
||||
isc_result_t
|
||||
dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
unsigned int attributes, dns_dispatch_t **dispp) {
|
||||
dns_dispatch_t **dispp) {
|
||||
isc_result_t result;
|
||||
dns_dispatch_t *disp = NULL;
|
||||
|
||||
|
|
@ -1143,7 +1126,7 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
REQUIRE(dispp != NULL && *dispp == NULL);
|
||||
|
||||
LOCK(&mgr->lock);
|
||||
result = dispatch_createudp(mgr, localaddr, attributes, &disp);
|
||||
result = dispatch_createudp(mgr, localaddr, &disp);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
*dispp = disp;
|
||||
}
|
||||
|
|
@ -1154,19 +1137,17 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
|
||||
static isc_result_t
|
||||
dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
unsigned int attributes, dns_dispatch_t **dispp) {
|
||||
dns_dispatch_t **dispp) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
dns_dispatch_t *disp = NULL;
|
||||
isc_sockaddr_t sa_any;
|
||||
int pf;
|
||||
|
||||
pf = isc_sockaddr_pf(localaddr);
|
||||
dispatch_allocate(mgr, isc_socktype_udp, pf, attributes, &disp);
|
||||
dispatch_allocate(mgr, isc_socktype_udp, &disp);
|
||||
|
||||
/*
|
||||
* Check whether this address/port is available locally.
|
||||
*/
|
||||
isc_sockaddr_anyofpf(&sa_any, pf);
|
||||
isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
|
||||
if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
|
||||
result = isc_nm_checkaddr(localaddr, isc_socktype_udp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -1207,7 +1188,7 @@ cleanup:
|
|||
}
|
||||
|
||||
static void
|
||||
dns_dispatch_destroy(dns_dispatch_t *disp) {
|
||||
dispatch_destroy(dns_dispatch_t *disp) {
|
||||
dns_dispatchmgr_t *mgr = disp->mgr;
|
||||
|
||||
LOCK(&mgr->lock);
|
||||
|
|
@ -1223,8 +1204,9 @@ dns_dispatch_destroy(dns_dispatch_t *disp) {
|
|||
|
||||
dispatch_free(&disp);
|
||||
|
||||
/* Because dispatch uses mgr->mctx, we must detach after freeing
|
||||
* dispatch, not before
|
||||
/*
|
||||
* Because dispatch uses mgr->mctx, we must detach after freeing
|
||||
* dispatch, not before.
|
||||
*/
|
||||
dns_dispatchmgr_detach(&mgr);
|
||||
}
|
||||
|
|
@ -1253,10 +1235,11 @@ dns_dispatch_detach(dns_dispatch_t **dispp) {
|
|||
dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1);
|
||||
if (ref == 1) {
|
||||
LOCK(&disp->lock);
|
||||
REQUIRE(ISC_LIST_EMPTY(disp->active));
|
||||
INSIST(ISC_LIST_EMPTY(disp->pending));
|
||||
INSIST(ISC_LIST_EMPTY(disp->active));
|
||||
UNLOCK(&disp->lock);
|
||||
|
||||
dns_dispatch_destroy(disp);
|
||||
dispatch_destroy(disp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1321,6 +1304,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
|
|||
|
||||
ISC_LINK_INIT(res, link);
|
||||
ISC_LINK_INIT(res, alink);
|
||||
ISC_LINK_INIT(res, plink);
|
||||
|
||||
if (disp->socktype == isc_socktype_udp) {
|
||||
isc_result_t result = setup_socket(disp, res, dest, &localport);
|
||||
|
|
@ -1393,6 +1377,40 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) {
|
||||
REQUIRE(timeout <= UINT16_MAX);
|
||||
|
||||
/*
|
||||
* FIXME: Since there's no global timeout now, any call to getnext will
|
||||
* always restart the read timer, so it's possible to keep the client
|
||||
* connecting until end of times by just feeding it with invalid
|
||||
* packets.
|
||||
*/
|
||||
switch (disp->socktype) {
|
||||
case isc_socktype_udp:
|
||||
dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
|
||||
|
||||
if (timeout > 0) {
|
||||
isc_nmhandle_settimeout(resp->handle, timeout);
|
||||
}
|
||||
isc_nm_read(resp->handle, udp_recv, resp);
|
||||
|
||||
break;
|
||||
case isc_socktype_tcp:
|
||||
dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
|
||||
|
||||
if (timeout > 0) {
|
||||
isc_nmhandle_settimeout(disp->handle, timeout);
|
||||
}
|
||||
isc_nm_read(disp->handle, tcp_recv, disp);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_dispatch_getnext(dns_dispentry_t *resp) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
|
|
@ -1404,7 +1422,7 @@ dns_dispatch_getnext(dns_dispentry_t *resp) {
|
|||
|
||||
LOCK(&disp->lock);
|
||||
|
||||
startrecv(disp, resp);
|
||||
dispatch_getnext(disp, resp, resp->timeout);
|
||||
|
||||
UNLOCK(&disp->lock);
|
||||
|
||||
|
|
@ -1456,27 +1474,23 @@ dns_dispatch_removeresponse(dns_dispentry_t **respp) {
|
|||
* disp must be locked.
|
||||
*/
|
||||
static void
|
||||
startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) {
|
||||
startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) {
|
||||
switch (disp->socktype) {
|
||||
case isc_socktype_udp:
|
||||
REQUIRE(resp != NULL && resp->handle != NULL);
|
||||
REQUIRE(resp != NULL && resp->handle == NULL);
|
||||
|
||||
isc_nmhandle_attach(handle, &resp->handle);
|
||||
dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
|
||||
isc_nm_read(resp->handle, udp_recv, resp);
|
||||
break;
|
||||
|
||||
case isc_socktype_tcp:
|
||||
REQUIRE(resp != NULL && resp->handle == NULL);
|
||||
REQUIRE(disp->handle != NULL);
|
||||
REQUIRE(disp != NULL && disp->handle == NULL);
|
||||
|
||||
if (isc_nmhandle_timer_running(disp->handle)) {
|
||||
isc_nmhandle_settimeout(disp->handle, resp->timeout);
|
||||
break;
|
||||
}
|
||||
|
||||
isc_nmhandle_attach(disp->handle, &(isc_nmhandle_t *){ NULL });
|
||||
dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
|
||||
isc_nm_read(disp->handle, tcp_recv, resp);
|
||||
isc_nmhandle_attach(handle, &disp->handle);
|
||||
dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
|
||||
isc_nm_read(disp->handle, tcp_recv, disp);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -1485,34 +1499,30 @@ startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: Split into tcp_connected() and udp_connected()
|
||||
*/
|
||||
|
||||
static void
|
||||
disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
||||
dns_dispentry_t *resp = (dns_dispentry_t *)arg;
|
||||
dns_dispentry_t *pending = NULL, *next = NULL;
|
||||
dns_dispatch_t *disp = resp->disp;
|
||||
|
||||
if (resp->canceled && eresult == ISC_R_SUCCESS) {
|
||||
eresult = ISC_R_CANCELED;
|
||||
goto detach;
|
||||
}
|
||||
|
||||
if (eresult == ISC_R_SUCCESS) {
|
||||
switch (disp->socktype) {
|
||||
case isc_socktype_udp:
|
||||
isc_nmhandle_attach(handle, &resp->handle);
|
||||
startrecv(disp, resp);
|
||||
break;
|
||||
case isc_socktype_tcp:
|
||||
REQUIRE(disp->handle == NULL);
|
||||
LOCK(&disp->lock);
|
||||
isc_nmhandle_attach(handle, &disp->handle);
|
||||
disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
|
||||
UNLOCK(&disp->lock);
|
||||
startrecv(disp, resp);
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
if (resp->canceled) {
|
||||
dispentry_detach(&resp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (disp->socktype == isc_socktype_tcp) {
|
||||
REQUIRE(atomic_compare_exchange_strong(
|
||||
&disp->state,
|
||||
&(uint_fast32_t){ DNS_DISPATCHSTATE_CONNECTING },
|
||||
DNS_DISPATCHSTATE_CONNECTED));
|
||||
}
|
||||
|
||||
startrecv(handle, disp, resp);
|
||||
}
|
||||
|
||||
if (MGR_IS_SHUTTINGDOWN(disp->mgr)) {
|
||||
|
|
@ -1523,26 +1533,64 @@ disp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
|
|||
resp->connected(eresult, NULL, resp->arg);
|
||||
}
|
||||
|
||||
detach:
|
||||
for (pending = ISC_LIST_HEAD(disp->pending); pending != NULL;
|
||||
pending = next) {
|
||||
next = ISC_LIST_NEXT(pending, plink);
|
||||
ISC_LIST_UNLINK(disp->pending, pending, plink);
|
||||
|
||||
if (pending->connected != NULL) {
|
||||
pending->connected(eresult, NULL, pending->arg);
|
||||
}
|
||||
dispentry_detach(&pending);
|
||||
}
|
||||
|
||||
dispentry_detach(&resp);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_dispatch_connect(dns_dispentry_t *resp) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
dns_dispentry_t *tmp = NULL;
|
||||
uint_fast32_t state = DNS_DISPATCHSTATE_NONE;
|
||||
|
||||
REQUIRE(VALID_RESPONSE(resp));
|
||||
|
||||
disp = resp->disp;
|
||||
|
||||
dispentry_attach(resp, &tmp); /* detached in disp_connected */
|
||||
/* This will be detached in disp_connected() */
|
||||
dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
|
||||
|
||||
switch (disp->socktype) {
|
||||
case isc_socktype_tcp:
|
||||
INSIST(disp->handle == NULL);
|
||||
isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local, &disp->peer,
|
||||
disp_connected, resp, resp->timeout, 0);
|
||||
/*
|
||||
* Check whether the dispatch was already connecting.
|
||||
* If so, add resp to the pending responses.
|
||||
*/
|
||||
atomic_compare_exchange_strong(&disp->state,
|
||||
(uint_fast32_t *)&state,
|
||||
DNS_DISPATCHSTATE_CONNECTING);
|
||||
|
||||
switch (state) {
|
||||
case DNS_DISPATCHSTATE_NONE:
|
||||
/* First connection, continue with connecting */
|
||||
INSIST(disp->handle == NULL);
|
||||
isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local,
|
||||
&disp->peer, disp_connected, resp,
|
||||
resp->timeout, 0);
|
||||
break;
|
||||
case DNS_DISPATCHSTATE_CONNECTING:
|
||||
ISC_LIST_APPEND(disp->pending, resp, plink);
|
||||
return (ISC_R_SUCCESS);
|
||||
case DNS_DISPATCHSTATE_CONNECTED:
|
||||
/* We are already connected, call the connected cb */
|
||||
if (resp->connected != NULL) {
|
||||
resp->connected(ISC_R_SUCCESS, NULL, resp->arg);
|
||||
}
|
||||
return (ISC_R_SUCCESS);
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
break;
|
||||
case isc_socktype_udp:
|
||||
isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer,
|
||||
|
|
@ -1571,31 +1619,15 @@ send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
|||
}
|
||||
|
||||
void
|
||||
dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout) {
|
||||
REQUIRE(resp != NULL);
|
||||
dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
REQUIRE(VALID_RESPONSE(resp));
|
||||
|
||||
dns_dispatch_t *disp = resp->disp;
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
disp = resp->disp;
|
||||
|
||||
switch (disp->socktype) {
|
||||
case isc_socktype_udp:
|
||||
REQUIRE(resp->handle != NULL);
|
||||
REQUIRE(VALID_DISPATCH(disp));
|
||||
|
||||
handle = resp->handle;
|
||||
|
||||
break;
|
||||
case isc_socktype_tcp:
|
||||
REQUIRE(disp != NULL && disp->handle == NULL);
|
||||
|
||||
handle = disp->handle;
|
||||
break;
|
||||
default:
|
||||
INSIST(0);
|
||||
ISC_UNREACHABLE();
|
||||
}
|
||||
|
||||
isc_nmhandle_settimeout(handle, timeout);
|
||||
startrecv(disp, resp);
|
||||
dispatch_getnext(disp, resp, timeout);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1606,8 +1638,6 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
|
|||
|
||||
UNUSED(dscp);
|
||||
|
||||
handle = getentryhandle(resp);
|
||||
|
||||
#if 0
|
||||
/* XXX: no DSCP support */
|
||||
if (dscp == -1) {
|
||||
|
|
@ -1622,6 +1652,12 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (resp->disp->socktype == isc_socktype_tcp) {
|
||||
handle = resp->disp->handle;
|
||||
} else {
|
||||
handle = resp->handle;
|
||||
}
|
||||
|
||||
dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
|
||||
isc_nm_send(handle, r, send_done, resp);
|
||||
}
|
||||
|
|
@ -1632,28 +1668,30 @@ dns_dispatch_cancel(dns_dispentry_t *resp) {
|
|||
|
||||
resp->canceled = true;
|
||||
|
||||
if (resp->handle) {
|
||||
/* UDP case. */
|
||||
if (resp->handle != NULL) {
|
||||
isc_nm_cancelread(resp->handle);
|
||||
} else if (resp->disp->handle != NULL) {
|
||||
isc_nm_cancelread(resp->disp->handle);
|
||||
}
|
||||
}
|
||||
|
||||
static inline isc_nmhandle_t *
|
||||
getentryhandle(dns_dispentry_t *resp) {
|
||||
isc_nmhandle_t *handle = NULL;
|
||||
|
||||
REQUIRE(VALID_RESPONSE(resp));
|
||||
|
||||
if (resp->disp->socktype == isc_socktype_tcp) {
|
||||
handle = resp->disp->handle;
|
||||
} else {
|
||||
handle = resp->handle;
|
||||
return;
|
||||
}
|
||||
|
||||
INSIST(handle != NULL);
|
||||
|
||||
return (handle);
|
||||
/*
|
||||
* TCP case. We only want to cancel if this is the last resp
|
||||
* listening on this TCP connection.
|
||||
*/
|
||||
if (ISC_LINK_LINKED(resp, plink)) {
|
||||
ISC_LIST_UNLINK(resp->disp->pending, resp, plink);
|
||||
if (resp->connected != NULL) {
|
||||
resp->connected(ISC_R_CANCELED, NULL, resp->arg);
|
||||
}
|
||||
} else if (ISC_LINK_LINKED(resp, alink)) {
|
||||
ISC_LIST_UNLINK(resp->disp->active, resp, alink);
|
||||
if (ISC_LIST_EMPTY(resp->disp->active) &&
|
||||
resp->disp->handle != NULL) {
|
||||
isc_nm_cancelread(resp->disp->handle);
|
||||
} else if (resp->response != NULL) {
|
||||
resp->response(ISC_R_CANCELED, NULL, resp->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
|
|
@ -1686,29 +1724,6 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) {
|
|||
return (ISC_R_NOTIMPLEMENTED);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
dns_dispatch_getattributes(dns_dispatch_t *disp) {
|
||||
REQUIRE(VALID_DISPATCH(disp));
|
||||
|
||||
/*
|
||||
* We don't bother locking disp here; it's the caller's
|
||||
* responsibility to use only non volatile flags.
|
||||
*/
|
||||
return (disp->attributes);
|
||||
}
|
||||
|
||||
void
|
||||
dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes,
|
||||
unsigned int mask) {
|
||||
REQUIRE(VALID_DISPATCH(disp));
|
||||
|
||||
LOCK(&disp->lock);
|
||||
|
||||
disp->attributes &= ~mask;
|
||||
disp->attributes |= (attributes & mask);
|
||||
UNLOCK(&disp->lock);
|
||||
}
|
||||
|
||||
dns_dispatch_t *
|
||||
dns_dispatchset_get(dns_dispatchset_t *dset) {
|
||||
dns_dispatch_t *disp = NULL;
|
||||
|
|
@ -1738,7 +1753,7 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
|
|||
int i, j;
|
||||
|
||||
REQUIRE(VALID_DISPATCH(source));
|
||||
REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
|
||||
REQUIRE(source->socktype == isc_socktype_udp);
|
||||
REQUIRE(dsetp != NULL && *dsetp == NULL);
|
||||
|
||||
mgr = source->mgr;
|
||||
|
|
@ -1759,7 +1774,6 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
|
|||
for (i = 1; i < n; i++) {
|
||||
dset->dispatches[i] = NULL;
|
||||
result = dispatch_createudp(mgr, &source->local,
|
||||
source->attributes,
|
||||
&dset->dispatches[i]);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@
|
|||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <isc/netmgr.h>
|
||||
#pragma once
|
||||
|
||||
#ifndef DNS_DISPATCH_H
|
||||
#define DNS_DISPATCH_H 1
|
||||
#include <isc/netmgr.h>
|
||||
|
||||
/*****
|
||||
***** Module Info
|
||||
|
|
@ -21,12 +20,12 @@
|
|||
/*! \file dns/dispatch.h
|
||||
* \brief
|
||||
* DNS Dispatch Management
|
||||
* Shared UDP and single-use TCP dispatches for queries and responses.
|
||||
* Shared UDP and single-use TCP dispatches for queries and responses.
|
||||
*
|
||||
* MP:
|
||||
*
|
||||
*\li All locking is performed internally to each dispatch.
|
||||
* Restrictions apply to dns_dispatch_removeresponse().
|
||||
*\li All locking is performed internally to each dispatch.
|
||||
* Restrictions apply to dns_dispatch_removeresponse().
|
||||
*
|
||||
* Reliability:
|
||||
*
|
||||
|
|
@ -72,33 +71,6 @@ struct dns_dispatchset {
|
|||
isc_mutex_t lock;
|
||||
};
|
||||
|
||||
/*@{*/
|
||||
/*%
|
||||
* Attributes for added dispatchers.
|
||||
*
|
||||
* Values with the mask 0xffff0000 are application defined.
|
||||
* Values with the mask 0x0000ffff are library defined.
|
||||
*
|
||||
* Insane values (like setting both TCP and UDP) are not caught. Don't
|
||||
* do that.
|
||||
*
|
||||
* _PRIVATE
|
||||
* The dispatcher cannot be shared.
|
||||
*
|
||||
* _TCP, _UDP
|
||||
* The dispatcher is a TCP or UDP socket.
|
||||
*
|
||||
* _IPV4, _IPV6
|
||||
* The dispatcher uses an IPv4 or IPv6 socket.
|
||||
*/
|
||||
#define DNS_DISPATCHATTR_PRIVATE 0x00000001U
|
||||
#define DNS_DISPATCHATTR_TCP 0x00000002U
|
||||
#define DNS_DISPATCHATTR_UDP 0x00000004U
|
||||
#define DNS_DISPATCHATTR_IPV4 0x00000008U
|
||||
#define DNS_DISPATCHATTR_IPV6 0x00000010U
|
||||
#define DNS_DISPATCHATTR_CONNECTED 0x00000080U
|
||||
/*@}*/
|
||||
|
||||
/*
|
||||
*/
|
||||
#define DNS_DISPATCHOPT_FIXEDID 0x00000001U
|
||||
|
|
@ -161,7 +133,7 @@ dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr);
|
|||
* without incrementing its reference count.
|
||||
*
|
||||
* Requires:
|
||||
*\li mgr is a valid dispatchmgr
|
||||
*\li mgr is a valid dispatchmgr
|
||||
* Returns:
|
||||
*\li A pointer to the current blackhole list, or NULL.
|
||||
*/
|
||||
|
|
@ -195,7 +167,7 @@ dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats);
|
|||
|
||||
isc_result_t
|
||||
dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
unsigned int attributes, dns_dispatch_t **dispp);
|
||||
dns_dispatch_t **dispp);
|
||||
/*%<
|
||||
* Create a new UDP dispatch.
|
||||
*
|
||||
|
|
@ -212,8 +184,8 @@ dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
|||
|
||||
isc_result_t
|
||||
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
|
||||
const isc_sockaddr_t *destaddr, unsigned int attributes,
|
||||
isc_dscp_t dscp, dns_dispatch_t **dispp);
|
||||
const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
|
||||
dns_dispatch_t **dispp);
|
||||
/*%<
|
||||
* Create a new dns_dispatch and attach it to the provided isc_socket_t.
|
||||
*
|
||||
|
|
@ -280,7 +252,14 @@ dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp);
|
|||
*/
|
||||
|
||||
void
|
||||
dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout);
|
||||
dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout);
|
||||
/*%<
|
||||
* Reset the read timeout in the socket associated with 'resp' and
|
||||
* continue reading.
|
||||
*
|
||||
* Requires:
|
||||
*\li 'resp' is valid.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
|
||||
|
|
@ -375,41 +354,6 @@ dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp);
|
|||
*\li ISC_R_NOTIMPLEMENTED
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns_dispatch_getattributes(dns_dispatch_t *disp);
|
||||
/*%<
|
||||
* Return the attributes (DNS_DISPATCHATTR_xxx) of this dispatch. Only the
|
||||
* non-changeable attributes are expected to be referenced by the caller.
|
||||
*
|
||||
* Requires:
|
||||
*\li disp is valid.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes,
|
||||
unsigned int mask);
|
||||
/*%<
|
||||
* Set the bits described by "mask" to the corresponding values in
|
||||
* "attributes".
|
||||
*
|
||||
* That is:
|
||||
*
|
||||
* \code
|
||||
* new = (old & ~mask) | (attributes & mask)
|
||||
* \endcode
|
||||
*
|
||||
* This function has a side effect when #DNS_DISPATCHATTR_NOLISTEN changes.
|
||||
* When the flag becomes off, the dispatch will start receiving on the
|
||||
* corresponding socket. When the flag becomes on, receive events on the
|
||||
* corresponding socket will be canceled.
|
||||
*
|
||||
* Requires:
|
||||
*\li disp is valid.
|
||||
*
|
||||
*\li attributes are reasonable for the dispatch. That is, setting the UDP
|
||||
* attribute on a TCP socket isn't reasonable.
|
||||
*/
|
||||
|
||||
dns_dispatch_t *
|
||||
dns_dispatchset_get(dns_dispatchset_t *dset);
|
||||
/*%<
|
||||
|
|
@ -417,7 +361,7 @@ dns_dispatchset_get(dns_dispatchset_t *dset);
|
|||
* the round-robin counter.
|
||||
*
|
||||
* Requires:
|
||||
*\li dset != NULL
|
||||
*\li dset != NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
|
@ -429,8 +373,8 @@ dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
|
|||
* source.
|
||||
*
|
||||
* Requires:
|
||||
*\li source is a valid UDP dispatcher
|
||||
*\li dsetp != NULL, *dsetp == NULL
|
||||
*\li source is a valid UDP dispatcher
|
||||
*\li dsetp != NULL, *dsetp == NULL
|
||||
*/
|
||||
|
||||
void
|
||||
|
|
@ -440,7 +384,7 @@ dns_dispatchset_destroy(dns_dispatchset_t **dsetp);
|
|||
* memory, and set *dsetp to NULL.
|
||||
*
|
||||
* Requires:
|
||||
*\li dset is valid
|
||||
*\li dset is valid
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
|
|
@ -453,5 +397,3 @@ dns_dispatch_getnext(dns_dispentry_t *resp);
|
|||
*/
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* DNS_DISPATCH_H */
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
dns_requestmgr_t **requestmgrp) {
|
||||
dns_requestmgr_t *requestmgr;
|
||||
int i;
|
||||
unsigned int dispattr;
|
||||
|
||||
req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
|
||||
|
||||
|
|
@ -145,39 +144,31 @@ dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
REQUIRE(taskmgr != NULL);
|
||||
REQUIRE(dispatchmgr != NULL);
|
||||
|
||||
if (dispatchv4 != NULL) {
|
||||
dispattr = dns_dispatch_getattributes(dispatchv4);
|
||||
REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
|
||||
}
|
||||
if (dispatchv6 != NULL) {
|
||||
dispattr = dns_dispatch_getattributes(dispatchv6);
|
||||
REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
|
||||
}
|
||||
|
||||
requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
|
||||
*requestmgr = (dns_requestmgr_t){ 0 };
|
||||
|
||||
isc_taskmgr_attach(taskmgr, &requestmgr->taskmgr);
|
||||
dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr);
|
||||
isc_mutex_init(&requestmgr->lock);
|
||||
|
||||
for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
|
||||
isc_mutex_init(&requestmgr->locks[i]);
|
||||
}
|
||||
requestmgr->taskmgr = taskmgr;
|
||||
requestmgr->dispatchmgr = dispatchmgr;
|
||||
requestmgr->dispatchv4 = NULL;
|
||||
if (dispatchv4 != NULL) {
|
||||
dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
|
||||
}
|
||||
requestmgr->dispatchv6 = NULL;
|
||||
if (dispatchv6 != NULL) {
|
||||
dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
|
||||
}
|
||||
requestmgr->mctx = NULL;
|
||||
isc_mem_attach(mctx, &requestmgr->mctx);
|
||||
|
||||
isc_refcount_init(&requestmgr->references, 1);
|
||||
|
||||
ISC_LIST_INIT(requestmgr->whenshutdown);
|
||||
ISC_LIST_INIT(requestmgr->requests);
|
||||
|
||||
atomic_init(&requestmgr->exiting, false);
|
||||
requestmgr->hash = 0;
|
||||
|
||||
requestmgr->magic = REQUESTMGR_MAGIC;
|
||||
|
||||
req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
|
||||
|
|
@ -325,6 +316,12 @@ mgr_destroy(dns_requestmgr_t *requestmgr) {
|
|||
if (requestmgr->dispatchv6 != NULL) {
|
||||
dns_dispatch_detach(&requestmgr->dispatchv6);
|
||||
}
|
||||
if (requestmgr->dispatchmgr != NULL) {
|
||||
dns_dispatchmgr_detach(&requestmgr->dispatchmgr);
|
||||
}
|
||||
if (requestmgr->taskmgr != NULL) {
|
||||
isc_taskmgr_detach(&requestmgr->taskmgr);
|
||||
}
|
||||
requestmgr->magic = 0;
|
||||
isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
|
||||
sizeof(*requestmgr));
|
||||
|
|
@ -417,7 +414,7 @@ tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
|
|||
}
|
||||
|
||||
result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
|
||||
destaddr, 0, dscp, dispatchp);
|
||||
destaddr, dscp, dispatchp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -446,7 +443,7 @@ udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr, 0,
|
||||
return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
|
||||
dispatchp));
|
||||
}
|
||||
|
||||
|
|
@ -589,15 +586,19 @@ again:
|
|||
UNLOCK(&requestmgr->lock);
|
||||
|
||||
request->destaddr = *destaddr;
|
||||
if (!tcp || !connected) {
|
||||
if (tcp && connected) {
|
||||
req_send(request);
|
||||
req_detach(&rclone);
|
||||
} else {
|
||||
result = dns_dispatch_connect(request->dispentry);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto unlink;
|
||||
}
|
||||
request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
|
||||
} else {
|
||||
req_send(request);
|
||||
req_detach(&rclone);
|
||||
request->flags |= DNS_REQUEST_F_CONNECTING;
|
||||
|
||||
if (tcp) {
|
||||
request->flags |= DNS_REQUEST_F_TCP;
|
||||
}
|
||||
}
|
||||
|
||||
req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request);
|
||||
|
|
@ -613,6 +614,9 @@ cleanup:
|
|||
if (tclone != NULL) {
|
||||
isc_task_detach(&tclone);
|
||||
}
|
||||
if (rclone != NULL) {
|
||||
req_detach(&rclone);
|
||||
}
|
||||
req_detach(&request);
|
||||
req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
|
||||
dns_result_totext(result));
|
||||
|
|
@ -755,15 +759,18 @@ use_tcp:
|
|||
UNLOCK(&requestmgr->lock);
|
||||
|
||||
request->destaddr = *destaddr;
|
||||
if (!tcp || !connected) {
|
||||
if (tcp && connected) {
|
||||
req_send(request);
|
||||
req_detach(&rclone);
|
||||
} else {
|
||||
result = dns_dispatch_connect(request->dispentry);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto unlink;
|
||||
}
|
||||
request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
|
||||
} else {
|
||||
req_send(request);
|
||||
req_detach(&rclone);
|
||||
request->flags |= DNS_REQUEST_F_CONNECTING;
|
||||
if (tcp) {
|
||||
request->flags |= DNS_REQUEST_F_TCP;
|
||||
}
|
||||
}
|
||||
|
||||
req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request);
|
||||
|
|
@ -1080,7 +1087,8 @@ req_response(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
|
||||
LOCK(&request->requestmgr->locks[request->hash]);
|
||||
if (--request->udpcount != 0) {
|
||||
dns_dispatch_read(request->dispentry, request->timeout);
|
||||
dns_dispatch_resume(request->dispentry,
|
||||
request->timeout);
|
||||
if (!DNS_REQUEST_SENDING(request)) {
|
||||
req_send(request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1123,12 +1123,14 @@ munge:
|
|||
|
||||
static inline void
|
||||
resquery_destroy(resquery_t *query) {
|
||||
dns_resolver_t *res;
|
||||
fetchctx_t *fctx = query->fctx;
|
||||
dns_resolver_t *res = fctx->res;
|
||||
unsigned int bucket = fctx->bucketnum;
|
||||
bool empty;
|
||||
fetchctx_t *fctx;
|
||||
unsigned int bucket;
|
||||
|
||||
REQUIRE(!ISC_LINK_LINKED(query, link));
|
||||
if (ISC_LINK_LINKED(query, link)) {
|
||||
ISC_LIST_UNLINK(fctx->queries, query, link);
|
||||
}
|
||||
|
||||
if (query->tsig != NULL) {
|
||||
isc_buffer_free(&query->tsig);
|
||||
|
|
@ -1148,10 +1150,6 @@ resquery_destroy(resquery_t *query) {
|
|||
|
||||
isc_refcount_destroy(&query->references);
|
||||
|
||||
fctx = query->fctx;
|
||||
res = fctx->res;
|
||||
bucket = fctx->bucketnum;
|
||||
|
||||
LOCK(&res->buckets[bucket].lock);
|
||||
fctx->nqueries--;
|
||||
empty = fctx_decreference(query->fctx);
|
||||
|
|
@ -1935,7 +1933,7 @@ resquery_timeout(resquery_t *query) {
|
|||
*/
|
||||
timeleft = isc_time_microdiff(&fctx->next_timeout, &now);
|
||||
if (timeleft >= US_PER_MSEC) {
|
||||
dns_dispatch_read(query->dispentry, (timeleft / US_PER_MSEC));
|
||||
dns_dispatch_resume(query->dispentry, (timeleft / US_PER_MSEC));
|
||||
return (ISC_R_COMPLETE);
|
||||
}
|
||||
|
||||
|
|
@ -2061,7 +2059,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
|
|||
}
|
||||
|
||||
result = dns_dispatch_createtcp(res->dispatchmgr, &addr,
|
||||
&addrinfo->sockaddr, 0,
|
||||
&addrinfo->sockaddr,
|
||||
query->dscp, &query->dispatch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_query;
|
||||
|
|
@ -2082,7 +2080,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
|
|||
goto cleanup_query;
|
||||
}
|
||||
result = dns_dispatch_createudp(res->dispatchmgr, &addr,
|
||||
0, &query->dispatch);
|
||||
&query->dispatch);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup_query;
|
||||
}
|
||||
|
|
@ -2795,12 +2793,8 @@ resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
|
|||
switch (eresult) {
|
||||
case ISC_R_SUCCESS:
|
||||
/*
|
||||
* We are connected. Update the dispatcher and
|
||||
* send the query.
|
||||
* We are connected. Send the query.
|
||||
*/
|
||||
dns_dispatch_changeattributes(query->dispatch,
|
||||
DNS_DISPATCHATTR_CONNECTED,
|
||||
DNS_DISPATCHATTR_CONNECTED);
|
||||
|
||||
result = resquery_send(query);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue