dns_dispatchopt_t options;
dns_dispatchstate_t state;
+ dns_dispatchtype_t disptype;
bool reading;
const isc_sockaddr_t *local;
const isc_sockaddr_t *peer;
const dns_transport_t *transport;
+ const dns_dispatchtype_t disptype;
};
static uint32_t
isc_sockaddr_equal(&disp->local, key->local));
}
-isc_result_t
-dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
- const isc_sockaddr_t *destaddr,
- dns_transport_t *transport, dns_dispatchopt_t options,
- dns_dispatch_t **dispp) {
- dns_dispatch_t *disp = NULL;
- isc_tid_t tid = isc_tid();
-
- REQUIRE(VALID_DISPATCHMGR(mgr));
- REQUIRE(destaddr != NULL);
-
- dispatch_allocate(mgr, isc_socktype_tcp, tid, &disp);
-
- disp->options = options;
- disp->peer = *destaddr;
- if (transport != NULL) {
- dns_transport_attach(transport, &disp->transport);
- }
-
- 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);
- }
-
- /*
- * Append it to the dispatcher list.
- */
- struct dispatch_key key = {
- .local = &disp->local,
- .peer = &disp->peer,
- .transport = transport,
- };
-
- if ((disp->options & DNS_DISPATCHOPT_UNSHARED) == 0) {
- rcu_read_lock();
- cds_lfht_add(mgr->tcps[tid], dispatch_hash(&key),
- &disp->ht_node);
- rcu_read_unlock();
- }
-
- if (isc_log_wouldlog(90)) {
- char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
- isc_sockaddr_format(&disp->local, addrbuf,
- ISC_SOCKADDR_FORMATSIZE);
-
- mgr_log(mgr, ISC_LOG_DEBUG(90),
- "dns_dispatch_createtcp: created TCP dispatch %p for "
- "%s",
- disp, addrbuf);
- }
- *dispp = disp;
-
- return ISC_R_SUCCESS;
-}
-
-isc_result_t
-dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
- const isc_sockaddr_t *localaddr, dns_transport_t *transport,
- dns_dispatch_t **dispp) {
+static isc_result_t
+dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
+ const isc_sockaddr_t *destaddr, dns_transport_t *transport,
+ dns_dispatchtype_t disptype, dns_dispatch_t **dispp) {
dns_dispatch_t *disp_connected = NULL;
dns_dispatch_t *disp_fallback = NULL;
isc_result_t result = ISC_R_NOTFOUND;
.local = localaddr,
.peer = destaddr,
.transport = transport,
+ .disptype = disptype,
};
rcu_read_lock();
INSIST(disp->tid == isc_tid());
INSIST(disp->socktype == isc_socktype_tcp);
+ if (disp->disptype != disptype) {
+ continue;
+ }
+
switch (disp->state) {
case DNS_DISPATCHSTATE_NONE:
/* A dispatch in indeterminate state, skip it */
break;
case DNS_DISPATCHSTATE_CONNECTED:
- if (ISC_LIST_EMPTY(disp->active)) {
- /* Ignore dispatch with no responses */
- break;
- }
/* We found a connected dispatch */
dns_dispatch_attach(disp, &disp_connected);
break;
case DNS_DISPATCHSTATE_CONNECTING:
- if (ISC_LIST_EMPTY(disp->pending)) {
- /* Ignore dispatch with no responses */
- break;
- }
/* We found "a" dispatch, store it for later */
if (disp_fallback == NULL) {
dns_dispatch_attach(disp, &disp_fallback);
return result;
}
+static void
+dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
+ const isc_sockaddr_t *destaddr, dns_transport_t *transport,
+ dns_dispatchtype_t disptype, dns_dispatchopt_t options,
+ dns_dispatch_t **dispp) {
+ dns_dispatch_t *disp = NULL;
+ isc_tid_t tid = isc_tid();
+
+ dispatch_allocate(mgr, isc_socktype_tcp, tid, &disp);
+
+ disp->disptype = disptype;
+ disp->options = options;
+ disp->peer = *destaddr;
+ if (transport != NULL) {
+ dns_transport_attach(transport, &disp->transport);
+ }
+
+ 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);
+ }
+
+ /*
+ * Append it to the dispatcher list.
+ */
+ if ((options & DNS_DISPATCHOPT_FIXEDID) == 0) {
+ struct dispatch_key key = {
+ .local = &disp->local,
+ .peer = &disp->peer,
+ .transport = transport,
+ .disptype = disptype,
+ };
+ rcu_read_lock();
+ cds_lfht_add(mgr->tcps[tid], dispatch_hash(&key),
+ &disp->ht_node);
+ rcu_read_unlock();
+ }
+
+ *dispp = disp;
+}
+
+isc_result_t
+dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
+ const isc_sockaddr_t *destaddr,
+ dns_transport_t *transport, dns_dispatchtype_t disptype,
+ dns_dispatchopt_t options, dns_dispatch_t **dispp) {
+ REQUIRE(VALID_DISPATCHMGR(mgr));
+ REQUIRE(destaddr != NULL);
+
+ isc_result_t result;
+
+ if ((options & DNS_DISPATCHOPT_FIXEDID) == 0) {
+ result = dispatch_gettcp(mgr, localaddr, destaddr, transport,
+ disptype, dispp);
+ if (result == ISC_R_SUCCESS) {
+ if (isc_log_wouldlog(90)) {
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ isc_sockaddr_format(&(*dispp)->local, addrbuf,
+ ISC_SOCKADDR_FORMATSIZE);
+
+ mgr_log(mgr, ISC_LOG_DEBUG(90),
+ "dns_dispatch_createtcp: reused TCP "
+ "dispatch %p for "
+ "%s",
+ *dispp, addrbuf);
+ }
+ return result;
+ }
+ }
+
+ /*
+ * Otherwise allocate new TCP dispatch.
+ */
+
+ dispatch_createtcp(mgr, localaddr, destaddr, transport, disptype,
+ options, dispp);
+
+ if (isc_log_wouldlog(90)) {
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ isc_sockaddr_format(&(*dispp)->local, addrbuf,
+ ISC_SOCKADDR_FORMATSIZE);
+
+ mgr_log(mgr, ISC_LOG_DEBUG(90),
+ "dns_dispatch_createtcp: created TCP dispatch %p for "
+ "%s",
+ *dispp, addrbuf);
+ }
+
+ return ISC_R_SUCCESS;
+}
+
isc_result_t
dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
dns_dispatch_t **dispp) {
disp->magic = 0;
- if (disp->socktype == isc_socktype_tcp &&
- (disp->options & DNS_DISPATCHOPT_UNSHARED) == 0)
+ if ((disp->options & DNS_DISPATCHOPT_FIXEDID) == 0 &&
+ disp->socktype == isc_socktype_tcp)
{
(void)cds_lfht_del(mgr->tcps[tid], &disp->ht_node);
}
typedef enum dns_dispatchopt {
DNS_DISPATCHOPT_FIXEDID = 1 << 0,
- DNS_DISPATCHOPT_UNSHARED = 1 << 1, /* Don't share this connection */
} dns_dispatchopt_t;
+typedef enum dns_dispatchtype {
+ DNS_DISPATCHTYPE_RESOLVER,
+ DNS_DISPATCHTYPE_REQUEST,
+ DNS_DISPATCHTYPE_XFRIN,
+} dns_dispatchtype_t;
+
isc_result_t
dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp);
/*%<
isc_result_t
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
const isc_sockaddr_t *destaddr,
- dns_transport_t *transport, dns_dispatchopt_t options,
- dns_dispatch_t **dispp);
+ dns_transport_t *transport, dns_dispatchtype_t disptype,
+ dns_dispatchopt_t options, dns_dispatch_t **dispp);
/*%<
* Create a new TCP dns_dispatch.
*
*\li 'resp' is valid.
*/
-isc_result_t
-dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
- const isc_sockaddr_t *localaddr, dns_transport_t *transport,
- dns_dispatch_t **dispp);
-/*
- * Attempt to connect to a existing TCP connection that was created with
- * parameters that match destaddr, localaddr and transport.
- *
- * If localaddr is NULL, we ignore the dispatch's localaddr when looking
- * for a match. However, if transport is NULL, then the matching dispatch
- * must also have been created with a NULL transport.
- *
- * Requires:
- *\li mgr to be valid dispatch manager.
- *
- *\li dstaddr to be a valid sockaddr.
- *
- *\li localaddr to be NULL or a valid sockaddr.
- *
- *\li transport is NULL or a valid transport.
- *
- *\li dispp to be non NULL and *dispp to be NULL
- *
- * Returns:
- *\li ISC_R_SUCCESS -- success.
- *
- *\li Anything else -- failure.
- */
-
typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region,
void *cbarg);
}
static isc_result_t
-tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
- const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
- dns_transport_t *transport, dns_dispatch_t **dispatchp) {
- isc_result_t result;
-
- if (!newtcp) {
- result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
- srcaddr, transport, dispatchp);
- if (result == ISC_R_SUCCESS) {
- char peer[ISC_SOCKADDR_FORMATSIZE];
-
- isc_sockaddr_format(destaddr, peer, sizeof(peer));
- req_log(ISC_LOG_DEBUG(1),
- "attached to TCP connection to %s", peer);
- return result;
- }
- }
-
- result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
- destaddr, transport, 0, dispatchp);
- return result;
+tcp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
+ const isc_sockaddr_t *destaddr, dns_transport_t *transport,
+ dns_dispatch_t **dispatchp) {
+ return dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
+ destaddr, transport,
+ DNS_DISPATCHTYPE_REQUEST, 0, dispatchp);
}
static isc_result_t
}
static isc_result_t
-get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr,
+get_dispatch(bool tcp, dns_requestmgr_t *requestmgr,
const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
dns_transport_t *transport, dns_dispatch_t **dispatchp) {
isc_result_t result;
if (tcp) {
- result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr,
- transport, dispatchp);
+ result = tcp_dispatch(requestmgr, srcaddr, destaddr, transport,
+ dispatchp);
} else {
result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
}
isc_mem_t *mctx = NULL;
dns_messageid_t id;
bool tcp = false;
- bool newtcp = false;
isc_region_t r;
unsigned int dispopt = 0;
isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
CHECK(isc_buffer_copyregion(request->query, &r));
-again:
- CHECK(get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr,
- transport, &request->dispatch));
+ CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
+ &request->dispatch));
if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
id = (r.base[0] << 8) | r.base[1];
dispopt |= DNS_DISPATCHOPT_FIXEDID;
}
- result = dns_dispatch_add(request->dispatch, loop, dispopt,
- request->connect_timeout, request->timeout,
- destaddr, transport, tlsctx_cache,
- req_connected, req_senddone, req_response,
- request, &id, &request->dispentry);
- if (result != ISC_R_SUCCESS) {
- if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
- dns_dispatch_detach(&request->dispatch);
- newtcp = true;
- goto again;
- }
-
- goto cleanup;
- }
+ CHECK(dns_dispatch_add(request->dispatch, loop, dispopt,
+ request->connect_timeout, request->timeout,
+ destaddr, transport, tlsctx_cache, req_connected,
+ req_senddone, req_response, request, &id,
+ &request->dispentry));
/* Add message ID. */
isc_buffer_usedregion(request->query, &r);
CHECK(dns_message_settsigkey(message, request->tsigkey));
again:
- CHECK(get_dispatch(tcp, false, requestmgr, srcaddr, destaddr, transport,
+ CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
&request->dispatch));
CHECK(dns_dispatch_add(request->dispatch, loop, 0,
result = dns_dispatch_createtcp(fctx->dispatchmgr, &addr,
&sockaddr, addrinfo->transport,
- DNS_DISPATCHOPT_UNSHARED,
+ DNS_DISPATCHTYPE_RESOLVER, 0,
&query->dispatch);
if (result != ISC_R_SUCCESS) {
goto cleanup_query;
primaries_timeout = isc_nm_getprimariestimeout();
result = dns_dispatch_createtcp(dispmgr, &xfr->sourceaddr,
&xfr->primaryaddr, xfr->transport,
- DNS_DISPATCHOPT_UNSHARED, &xfr->disp);
+ DNS_DISPATCHTYPE_XFRIN, 0, &xfr->disp);
dns_dispatchmgr_detach(&dispmgr);
CHECK(result);
}
static void
-connected_gettcp(isc_result_t eresult ISC_ATTR_UNUSED,
- isc_region_t *region ISC_ATTR_UNUSED, void *arg) {
- test_dispatch_t *test1 = arg;
-
- /* Client 2 */
- isc_result_t result;
- test_dispatch_t *test2 = isc_mem_get(isc_g_mctx, sizeof(*test2));
- *test2 = (test_dispatch_t){
- .dispatchmgr = dns_dispatchmgr_ref(test1->dispatchmgr),
- };
-
- result = dns_dispatch_gettcp(test2->dispatchmgr, &tcp_server_addr,
- &tcp_connect_addr, NULL, &test2->dispatch);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- assert_ptr_equal(test1->dispatch, test2->dispatch);
-
- result = dns_dispatch_add(
- test2->dispatch, isc_loop_main(), 0, T_CLIENT_CONNECT,
- T_CLIENT_INIT, &tcp_server_addr, NULL, NULL, connected_shutdown,
- client_senddone, response_noop, test2, &test2->id,
- &test2->dispentry);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- dns_dispatch_connect(test2->dispentry);
-
- test_dispatch_done(test1);
-}
-
-static void
-connected_newtcp(isc_result_t eresult ISC_ATTR_UNUSED,
- isc_region_t *region ISC_ATTR_UNUSED, void *arg) {
+connected_sharedtcp(isc_result_t eresult ISC_ATTR_UNUSED,
+ isc_region_t *region ISC_ATTR_UNUSED, void *arg) {
test_dispatch_t *test3 = arg;
- /* Client - unshared */
+ /* Second client — should reuse the first client's TCP dispatch. */
isc_result_t result;
test_dispatch_t *test4 = isc_mem_get(isc_g_mctx, sizeof(*test4));
*test4 = (test_dispatch_t){
.dispatchmgr = dns_dispatchmgr_ref(test3->dispatchmgr),
};
- result = dns_dispatch_gettcp(test4->dispatchmgr, &tcp_server_addr,
- &tcp_connect_addr, NULL, &test4->dispatch);
- assert_int_equal(result, ISC_R_NOTFOUND);
result = dns_dispatch_createtcp(
test4->dispatchmgr, &tcp_connect_addr, &tcp_server_addr, NULL,
- DNS_DISPATCHOPT_UNSHARED, &test4->dispatch);
+ DNS_DISPATCHTYPE_RESOLVER, 0, &test4->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
- assert_ptr_not_equal(test3->dispatch, test4->dispatch);
+ assert_ptr_equal(test3->dispatch, test4->dispatch);
result = dns_dispatch_add(
test4->dispatch, isc_loop_main(), 0, T_CLIENT_CONNECT,
result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_dispatch_createtcp(test->dispatchmgr, &tcp_connect_addr,
- &tcp_server_addr, NULL, 0,
- &test->dispatch);
+ result = dns_dispatch_createtcp(
+ test->dispatchmgr, &tcp_connect_addr, &tcp_server_addr, NULL,
+ DNS_DISPATCHTYPE_RESOLVER, 0, &test->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_add(
result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_dispatch_createtcp(test->dispatchmgr, &tcp_connect_addr,
- &tcp_server_addr, NULL, 0,
- &test->dispatch);
+ result = dns_dispatch_createtcp(
+ test->dispatchmgr, &tcp_connect_addr, &tcp_server_addr, NULL,
+ DNS_DISPATCHTYPE_RESOLVER, 0, &test->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_add(test->dispatch, isc_loop_main(), 0,
result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_dispatch_createtcp(test->dispatchmgr, &tcp_connect_addr,
- &tcp_server_addr, NULL, 0,
- &test->dispatch);
+ result = dns_dispatch_createtcp(
+ test->dispatchmgr, &tcp_connect_addr, &tcp_server_addr, NULL,
+ DNS_DISPATCHTYPE_RESOLVER, 0, &test->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_add(test->dispatch, isc_loop_main(), 0,
result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_dispatch_createtcp(test->dispatchmgr, &tls_connect_addr,
- &tls_server_addr, tls_transport, 0,
- &test->dispatch);
+ result = dns_dispatch_createtcp(
+ test->dispatchmgr, &tls_connect_addr, &tls_server_addr,
+ tls_transport, DNS_DISPATCHTYPE_RESOLVER, 0, &test->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_add(
dns_dispatch_connect(test->dispentry);
}
-ISC_LOOP_TEST_IMPL(dispatch_gettcp) {
+ISC_LOOP_TEST_IMPL(dispatch_sharedtcp) {
isc_result_t result;
test_dispatch_t *test = isc_mem_get(isc_g_mctx, sizeof(*test));
*test = (test_dispatch_t){ 0 };
/* ensure we stop listening after the test is done */
isc_loop_teardown(isc_loop_main(), stop_listening, sock);
- result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- /* Client */
- result = dns_dispatch_createtcp(test->dispatchmgr, &tcp_connect_addr,
- &tcp_server_addr, NULL, 0,
- &test->dispatch);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- result = dns_dispatch_add(
- test->dispatch, isc_loop_main(), 0, T_CLIENT_CONNECT,
- T_CLIENT_INIT, &tcp_server_addr, NULL, NULL, connected_gettcp,
- client_senddone, response_noop, test, &test->id,
- &test->dispentry);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- dns_dispatch_connect(test->dispentry);
-}
-
-ISC_LOOP_TEST_IMPL(dispatch_newtcp) {
- isc_result_t result;
- test_dispatch_t *test = isc_mem_get(isc_g_mctx, sizeof(*test));
- *test = (test_dispatch_t){ 0 };
-
- /* Server */
- result = isc_nm_listenstreamdns(ISC_NM_LISTEN_ONE, &tcp_server_addr,
- nameserver, NULL, accept_cb, NULL, 0,
- NULL, NULL, ISC_NM_PROXY_NONE, &sock);
- assert_int_equal(result, ISC_R_SUCCESS);
-
- /* ensure we stop listening after the test is done */
- isc_loop_teardown(isc_loop_main(), stop_listening, sock);
-
- /* Client - unshared */
+ /* First client — creates the shared TCP dispatch. */
result = dns_dispatchmgr_create(isc_g_mctx, &test->dispatchmgr);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_createtcp(
test->dispatchmgr, &tcp_connect_addr, &tcp_server_addr, NULL,
- DNS_DISPATCHOPT_UNSHARED, &test->dispatch);
+ DNS_DISPATCHTYPE_RESOLVER, 0, &test->dispatch);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dispatch_add(
test->dispatch, isc_loop_main(), 0, T_CLIENT_CONNECT,
- T_CLIENT_INIT, &tcp_server_addr, NULL, NULL, connected_newtcp,
- client_senddone, response_noop, test, &test->id,
- &test->dispentry);
+ T_CLIENT_INIT, &tcp_server_addr, NULL, NULL,
+ connected_sharedtcp, client_senddone, response_noop, test,
+ &test->id, &test->dispentry);
assert_int_equal(result, ISC_R_SUCCESS);
dns_dispatch_connect(test->dispentry);
}
ISC_TEST_LIST_START
-ISC_TEST_ENTRY_CUSTOM(dispatch_gettcp, setup_test, teardown_test)
-ISC_TEST_ENTRY_CUSTOM(dispatch_newtcp, setup_test, teardown_test)
+ISC_TEST_ENTRY_CUSTOM(dispatch_sharedtcp, setup_test, teardown_test)
ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_udp_response, setup_test, teardown_test)
ISC_TEST_ENTRY_CUSTOM(dispatchset_create, setup_test, teardown_test)
ISC_TEST_ENTRY_CUSTOM(dispatchset_get, setup_test, teardown_test)