diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h index 71878f1099..4e5cb33827 100644 --- a/lib/isc/include/isc/netmgr.h +++ b/lib/isc/include/isc/netmgr.h @@ -499,9 +499,11 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, * 'cb'. */ +void +isc_nm_dnspair(isc_nm_t *mgr, isc_nm_cb_t ccb, void *ccbarg, + isc_nm_recv_cb_t scb, void *scbarg); /*%< - * Returns 'true' iff 'handle' is associated with a socket of type - * 'isc_nm_tlsdnssocket'. + * FIXME */ bool diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 1a9114f8ae..23c6cb3df8 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -295,6 +295,8 @@ typedef enum isc__netievent_type { netievent_tcpdnsread, netievent_tcpdnscancel, + netievent_dnspair, + netievent_tlsclose, netievent_tlssend, netievent_tlsstartread, @@ -1573,6 +1575,12 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0); * Callback handlers for asynchronous TCPDNS events. */ +void +isc__nm_async_dnspair(isc__networker_t *worker, isc__netievent_t *ev0); +/*%< + * Callback handlers for asynchronous DNS socket pair events. + */ + void isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg); /* @@ -1956,6 +1964,8 @@ NETIEVENT_SOCKET_REQ_TYPE(tcpdnssend); NETIEVENT_SOCKET_HANDLE_TYPE(tcpdnscancel); NETIEVENT_SOCKET_QUOTA_TYPE(tcpdnsaccept); +NETIEVENT_SOCKET_REQ_TYPE(dnspair); + NETIEVENT_SOCKET_TYPE(tlsdnsclose); NETIEVENT_SOCKET_TYPE(tlsdnsread); NETIEVENT_SOCKET_TYPE(tlsdnsstop); @@ -2026,6 +2036,8 @@ NETIEVENT_SOCKET_REQ_DECL(tcpdnssend); NETIEVENT_SOCKET_HANDLE_DECL(tcpdnscancel); NETIEVENT_SOCKET_QUOTA_DECL(tcpdnsaccept); +NETIEVENT_SOCKET_REQ_DECL(dnspair); + NETIEVENT_SOCKET_DECL(tlsdnsclose); NETIEVENT_SOCKET_DECL(tlsdnsread); NETIEVENT_SOCKET_DECL(tlsdnsstop); diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index ad9dc3d57f..45a42972f8 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -900,6 +900,8 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) { NETIEVENT_CASE(tcpdnsread); NETIEVENT_CASE(tcpdnsstop); + NETIEVENT_CASE(dnspair); + NETIEVENT_CASE(tlsdnscycle); NETIEVENT_CASE(tlsdnsaccept); NETIEVENT_CASE(tlsdnslisten); @@ -1023,6 +1025,8 @@ NETIEVENT_SOCKET_REQ_DEF(tcpdnssend); NETIEVENT_SOCKET_HANDLE_DEF(tcpdnscancel); NETIEVENT_SOCKET_QUOTA_DEF(tcpdnsaccept); +NETIEVENT_SOCKET_REQ_DEF(dnspair); + NETIEVENT_SOCKET_DEF(tlsdnsclose); NETIEVENT_SOCKET_DEF(tlsdnsread); NETIEVENT_SOCKET_DEF(tlsdnsstop); diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c index e896d4ea4f..2e335ab3fe 100644 --- a/lib/isc/netmgr/tcpdns.c +++ b/lib/isc/netmgr/tcpdns.c @@ -387,6 +387,7 @@ start_tcpdns_child(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nmsocket_t *sock, isc__nm_maybe_enqueue_ievent(&mgr->workers[tid], (isc__netievent_t *)ievent); } + isc_result_t isc_nm_listentcpdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface, isc_nm_recv_cb_t recv_cb, void *recv_cbarg, @@ -701,7 +702,8 @@ isc__nm_tcpdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { * This MUST be done asynchronously, no matter which thread we're * in. The callback function for isc_nm_read() often calls * isc_nm_read() again; if we tried to do that synchronously - * we'd clash in processbuffer() and grow the stack indefinitely. + * we'd clash in isc__nm_tcpdns_processbuffer() and grow the + * stack indefinitely. */ isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent); @@ -1460,3 +1462,127 @@ isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) { isc__nm_failed_read_cb(sock, ISC_R_EOF, false); } + +static isc_result_t +pairdns_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) { + isc_result_t result = ISC_R_UNSET; + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(VALID_UVREQ(req)); + + REQUIRE(isc__nm_in_netthread()); + REQUIRE(sock->tid == isc_nm_tid()); + + if (isc__nm_closing(sock)) { + result = ISC_R_SHUTTINGDOWN; + goto error; + } + + atomic_store(&sock->connected, true); + +error: + LOCK(&sock->lock); + sock->result = result; + SIGNAL(&sock->cond); + if (!atomic_load(&sock->active)) { + WAIT(&sock->scond, &sock->lock); + } + INSIST(atomic_load(&sock->active)); + UNLOCK(&sock->lock); + + return (result); +} + +void +isc__nm_async_dnspair(isc__networker_t *worker, isc__netievent_t *ev0) { + isc__netievent_dnspair_t *ievent = + (isc__netievent_dnspair_t *)ev0; + isc_nmsocket_t *sock = ievent->sock; + isc__nm_uvreq_t *req = ievent->req; + isc_result_t result = ISC_R_SUCCESS; + + UNUSED(worker); + + REQUIRE(VALID_NMSOCK(sock)); + REQUIRE(sock->type == isc_nm_tcpdnssocket); + REQUIRE(sock->parent == NULL); + REQUIRE(sock->tid == isc_nm_tid()); + + result = pairdns_direct(sock, req); + if (result != ISC_R_SUCCESS) { + isc__nmsocket_clearcb(sock); + isc__nm_connectcb(sock, req, result, true); + atomic_store(&sock->active, false); + isc__nm_tcpdns_close(sock); + } + + /* + * The sock is now attached to the handle. + */ + isc__nmsocket_detach(&sock); +} + +void +isc_nm_dnspair(isc_nm_t *mgr, isc_nm_cb_t ccb, void *ccbarg, + isc_nm_recv_cb_t scb, void *scbarg) { + uv_os_sock_t fds[2]; + isc_nmsocket_t *csock = NULL, *ssock = NULL; + isc__netievent_tcpdnsconnect_t *cevent = NULL; + isc__netievent_tcpdnslisten_t *sevent = NULL; + isc__nm_uvreq_t *req = NULL; + int r; + + REQUIRE(VALID_NM(mgr)); + + /* XXX: uv_socketpair() was introduced in libuv 1.40 */ + r = socketpair(PF_LOCAL, SOCK_STREAM, 0, fds); + RUNTIME_CHECK(r == 0); + + /* Set up server socket */ + ssock = isc_mem_get(mgr->mctx, sizeof(*ssock)); + isc__nmsocket_init(ssock, mgr, isc_nm_tcpdnssocket, NULL); + ssock->recv_cb = scb; + ssock->recv_cbarg = scbarg; + ssock->fd = fds[1]; + + sevent = isc__nm_get_netievent_tcpdnslisten(mgr, ssock); + + /* Set up client socket */ + csock = isc_mem_get(mgr->mctx, sizeof(*csock)); + isc__nmsocket_init(csock, mgr, isc_nm_tcpdnssocket, NULL); + csock->result = ISC_R_UNSET; + csock->fd = fds[0]; + atomic_init(&csock->client, true); + + req = isc__nm_uvreq_get(mgr, csock); + req->cb.connect = ccb; + req->cbarg = ccbarg; + req->handle = isc__nmhandle_get(csock, NULL, NULL); + + cevent = isc__nm_get_netievent_dnspair(mgr, csock, req); + + if (isc__nm_in_netthread()) { + atomic_store(&csock->active, true); + csock->tid = isc_nm_tid(); + isc__nm_async_dnspair(&mgr->workers[csock->tid], + (isc__netievent_t *)cevent); + isc__nm_put_netievent_dnspair(mgr, cevent); + } else { + atomic_init(&csock->active, false); + csock->tid = isc_random_uniform(mgr->nworkers); + isc__nm_enqueue_ievent(&mgr->workers[csock->tid], + (isc__netievent_t *)cevent); + } + + ssock->tid = isc_random_uniform(mgr->nworkers); + isc__nm_maybe_enqueue_ievent(&mgr->workers[ssock->tid], + (isc__netievent_t *)sevent); + + LOCK(&csock->lock); + while (csock->result == ISC_R_UNSET) { + WAIT(&csock->cond, &csock->lock); + } + atomic_store(&csock->active, true); + BROADCAST(&csock->scond); + UNLOCK(&csock->lock); +} diff --git a/lib/isc/netmgr/tlsdns.c b/lib/isc/netmgr/tlsdns.c index b316449647..466a0b101d 100644 --- a/lib/isc/netmgr/tlsdns.c +++ b/lib/isc/netmgr/tlsdns.c @@ -898,8 +898,8 @@ isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) { * This MUST be done asynchronously, no matter which thread * we're in. The callback function for isc_nm_read() often calls * isc_nm_read() again; if we tried to do that synchronously - * we'd clash in processbuffer() and grow the stack - * indefinitely. + * we'd clash in isc__nm_tlsdns_processbuffer() and grow the + * stack indefinitely. */ isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid], (isc__netievent_t *)ievent);