Merge branch '2401-ISC_R_TIMEDOUT-is-recoverable' into 'main'

netmgr: Make it possible to recover from ISC_R_TIMEDOUT

Closes #2401

See merge request isc-projects/bind9!4845
This commit is contained in:
Ondřej Surý 2021-04-07 14:34:46 +00:00
commit 81c5f5e6a8
19 changed files with 969 additions and 969 deletions

View file

@ -1,3 +1,10 @@
5612. [bug] Continued refactoring of the network manager:
- allow recovery from read and connect timeout events
- ensure that calls to isc_nm_*connect() always
return the connection status via a callback
function.
[GL #2401]
5611. [func] Set "stale-answer-client-timeout" to "off" by default.
[GL #2608]

View file

@ -1541,12 +1541,13 @@ _destroy_lookup(dig_lookup_t *lookup) {
dig_server_t *s;
void *ptr;
REQUIRE(lookup != NULL);
REQUIRE(ISC_LIST_EMPTY(lookup->q));
debug("destroy_lookup");
isc_refcount_destroy(&lookup->references);
REQUIRE(ISC_LIST_EMPTY(lookup->q));
s = ISC_LIST_HEAD(lookup->my_server_list);
while (s != NULL) {
debug("freeing server %p belonging to %p", s, lookup);
@ -2794,12 +2795,11 @@ start_tcp(dig_query_t *query) {
if (query->lookup->tls_mode) {
result = isc_tlsctx_createclient(&query->tlsctx);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = isc_nm_tlsdnsconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query, local_timeout, 0,
query->tlsctx);
check_result(result, "isc_nm_tlsdnsconnect");
isc_nm_tlsdnsconnect(netmgr,
(isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query,
local_timeout, 0, query->tlsctx);
} else if (query->lookup->https_mode) {
char uri[4096] = { 0 };
snprintf(uri, sizeof(uri), "https://%s:%u%s",
@ -2814,18 +2814,16 @@ start_tcp(dig_query_t *query) {
query->tlsctx);
}
result = isc_nm_httpconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr, uri,
!query->lookup->https_get, tcp_connected, query,
query->tlsctx, local_timeout, 0);
check_result(result, "isc_nm_httpconnect");
isc_nm_httpconnect(netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
uri, !query->lookup->https_get,
tcp_connected, query, query->tlsctx,
local_timeout, 0);
} else {
result = isc_nm_tcpdnsconnect(
isc_nm_tcpdnsconnect(
netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
tcp_connected, query, local_timeout, 0);
check_result(result, "isc_nm_tcpdnsconnect");
}
/* XXX: set DSCP */
@ -2900,13 +2898,15 @@ udp_ready(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
query_detach(&query);
return;
} else if (eresult != ISC_R_SUCCESS) {
dig_lookup_t *l = query->lookup;
if (eresult != ISC_R_CANCELED) {
debug("udp setup failed: %s",
isc_result_totext(eresult));
}
if (query->tries == 0) {
query_detach(&query);
}
lookup_detach(&l);
query_detach(&query);
return;
}
@ -2993,24 +2993,9 @@ start_udp(dig_query_t *query) {
}
}
query->tries = 3;
do {
int local_timeout = timeout * 1000;
if (local_timeout == 0) {
local_timeout = UDP_TIMEOUT * 1000;
}
/*
* On FreeBSD the UDP connect() call sometimes results
* in a spurious transient EADDRINUSE. Try a few more times
* before giving up.
*/
debug("isc_nm_udpconnect(): %d tries left", --query->tries);
result = isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr,
udp_ready, query, local_timeout, 0);
} while (result != ISC_R_SUCCESS && query->tries > 0);
check_result(result, "isc_nm_udpconnect");
isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&localaddr,
(isc_nmiface_t *)&query->sockaddr, udp_ready, query,
(timeout ? timeout : UDP_TIMEOUT) * 1000, 0);
}
/*%

View file

@ -208,7 +208,6 @@ struct dig_query {
isc_time_t time_recv;
uint64_t byte_count;
isc_timer_t *timer;
uint8_t tries;
isc_tlsctx_t *tlsctx;
};

View file

@ -574,7 +574,6 @@ rndc_connected(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
static void
rndc_startconnect(isc_sockaddr_t *addr) {
isc_result_t result;
char socktext[ISC_SOCKADDR_FORMATSIZE];
isc_sockaddr_t *local = NULL;
@ -600,10 +599,8 @@ rndc_startconnect(isc_sockaddr_t *addr) {
}
atomic_fetch_add_relaxed(&connects, 1);
DO("create connection",
isc_nm_tcpconnect(netmgr, (isc_nmiface_t *)local,
(isc_nmiface_t *)addr, rndc_connected, &rndc_ccmsg,
10000, 0));
isc_nm_tcpconnect(netmgr, (isc_nmiface_t *)local, (isc_nmiface_t *)addr,
rndc_connected, &rndc_ccmsg, 10000, 0);
}
static void

View file

@ -235,8 +235,6 @@ parse_options(int argc, char **argv) {
}
}
INSIST(optind < argc);
{
struct addrinfo hints = {
.ai_family = family,
@ -281,7 +279,7 @@ parse_options(int argc, char **argv) {
isc_sockaddr_format(&sockaddr_remote, buf, sizeof(buf));
printf("to %s, %d workers\n", buf, workers);
printf(" to %s, %d workers\n", buf, workers);
}
static void
@ -378,16 +376,16 @@ connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nmhandle_t *readhandle = NULL;
REQUIRE(handle != NULL);
REQUIRE(eresult == ISC_R_SUCCESS);
UNUSED(cbarg);
fprintf(stderr, "ECHO_CLIENT:%s:%s\n", __func__,
isc_result_totext(eresult));
if (eresult != ISC_R_SUCCESS) {
kill(getpid(), SIGTERM);
return;
}
fprintf(stderr, "ECHO_CLIENT:%s\n", __func__);
isc_nmhandle_attach(handle, &readhandle);
isc_nm_read(handle, read_cb, readhandle);
isc_nm_send(handle, &message, send_cb, NULL);
@ -422,28 +420,23 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
static void
run(void) {
isc_result_t result;
switch (protocol) {
case UDP:
result = isc_nm_udpconnect(netmgr,
(isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0);
isc_nm_udpconnect(netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, connect_cb,
NULL, timeout, 0);
break;
case TCP:
result = isc_nm_tcpdnsconnect(netmgr,
(isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0);
isc_nm_tcpdnsconnect(netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0);
break;
case DOT: {
isc_tlsctx_createclient(&tls_ctx);
result = isc_nm_tlsdnsconnect(
netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, connect_cb, NULL,
timeout, 0, tls_ctx);
isc_nm_tlsdnsconnect(netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote,
connect_cb, NULL, timeout, 0, tls_ctx);
break;
}
case HTTP_GET:
@ -460,16 +453,15 @@ run(void) {
if (is_https) {
isc_tlsctx_createclient(&tls_ctx);
}
result = isc_nm_httpconnect(
netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, req_url, is_post,
connect_cb, NULL, tls_ctx, timeout, 0);
isc_nm_httpconnect(netmgr, (isc_nmiface_t *)&sockaddr_local,
(isc_nmiface_t *)&sockaddr_remote, req_url,
is_post, connect_cb, NULL, tls_ctx, timeout,
0);
} break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
REQUIRE(result == ISC_R_SUCCESS);
waitforsignal();

View file

@ -894,17 +894,17 @@ xfrin_start(dns_xfrin_ctx_t *xfr) {
*/
switch (transport_type) {
case DNS_TRANSPORT_TCP:
CHECK(isc_nm_tcpdnsconnect(
xfr->netmgr, (isc_nmiface_t *)&xfr->sourceaddr,
(isc_nmiface_t *)&xfr->masteraddr, xfrin_connect_done,
connect_xfr, 30000, 0));
isc_nm_tcpdnsconnect(xfr->netmgr,
(isc_nmiface_t *)&xfr->sourceaddr,
(isc_nmiface_t *)&xfr->masteraddr,
xfrin_connect_done, connect_xfr, 30000, 0);
break;
case DNS_TRANSPORT_TLS:
CHECK(isc_tlsctx_createclient(&xfr->tlsctx));
CHECK(isc_nm_tlsdnsconnect(
isc_nm_tlsdnsconnect(
xfr->netmgr, (isc_nmiface_t *)&xfr->sourceaddr,
(isc_nmiface_t *)&xfr->masteraddr, xfrin_connect_done,
connect_xfr, 30000, 0, xfr->tlsctx));
connect_xfr, 30000, 0, xfr->tlsctx);
break;
default:
INSIST(0);

View file

@ -207,7 +207,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
* can then be freed automatically when the handle is destroyed.
*/
isc_result_t
void
isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
@ -318,7 +318,7 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
*
*/
isc_result_t
void
isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
@ -481,16 +481,16 @@ isc_nm_listentls(isc_nm_t *mgr, isc_nmiface_t *iface,
size_t extrahandlesize, int backlog, isc_quota_t *quota,
isc_tlsctx_t *sslctx, isc_nmsocket_t **sockp);
isc_result_t
void
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, isc_tlsctx_t *ctx,
unsigned int timeout, size_t extrahandlesize);
isc_result_t
void
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize);
isc_result_t
void
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize, isc_tlsctx_t *sslctx);
@ -508,7 +508,7 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
* 'cb'.
*/
isc_result_t
void
isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
const char *uri, bool POST, isc_nm_cb_t cb, void *cbarg,
isc_tlsctx_t *ctx, unsigned int timeout,

View file

@ -1058,7 +1058,7 @@ http_call_connect_cb(isc_nmsocket_t *sock, isc_result_t result) {
req->handle = isc__nmhandle_get(sock, &sock->peer, &sock->iface->addr);
isc__nmsocket_clearcb(sock);
isc__nm_connectcb_force_async(sock, req, result);
isc__nm_connectcb(sock, req, result, true);
}
static void
@ -1147,12 +1147,11 @@ error:
isc__nmsocket_detach(&http_sock);
}
isc_result_t
void
isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
const char *uri, bool post, isc_nm_cb_t cb, void *cbarg,
isc_tlsctx_t *tlsctx, unsigned int timeout,
size_t extrahandlesize) {
isc_result_t result;
isc_nmiface_t local_interface;
isc_nmsocket_t *sock = NULL;
@ -1176,12 +1175,34 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sock->result = ISC_R_DEFAULT;
sock->connect_cb = cb;
sock->connect_cbarg = cbarg;
atomic_init(&sock->client, true);
if (isc__nm_closing(sock)) {
isc__nm_uvreq_t *req = isc__nm_uvreq_get(mgr, sock);
req->cb.connect = cb;
req->cbarg = cbarg;
req->peer = peer->addr;
req->local = local->addr;
req->handle = isc__nmhandle_get(sock, &req->peer,
&sock->iface->addr);
if (isc__nm_in_netthread()) {
sock->tid = isc_nm_tid();
}
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, ISC_R_CANCELED, true);
isc__nmsocket_prep_destroy(sock);
isc__nmsocket_detach(&sock);
return;
}
sock->h2 = (isc_nmsocket_h2_t){ .connect.uri = isc_mem_strdup(mgr->mctx,
uri),
.connect.post = post,
.connect.tlsctx = tlsctx };
ISC_LINK_INIT(&sock->h2, link);
atomic_init(&sock->client, true);
/*
* We need to prevent the interface object data from going out of
@ -1193,16 +1214,12 @@ isc_nm_httpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
}
if (tlsctx != NULL) {
result = isc_nm_tlsconnect(mgr, local, peer,
transport_connect_cb, sock, tlsctx,
timeout, 0);
isc_nm_tlsconnect(mgr, local, peer, transport_connect_cb, sock,
tlsctx, timeout, 0);
} else {
result = isc_nm_tcpconnect(mgr, local, peer,
transport_connect_cb, sock, timeout,
0);
isc_nm_tcpconnect(mgr, local, peer, transport_connect_cb, sock,
timeout, 0);
}
return (result);
}
static isc_result_t

View file

@ -854,8 +854,6 @@ struct isc_nmsocket {
* TCP read/connect timeout timers.
*/
uv_timer_t timer;
bool timer_initialized;
bool timer_running;
uint64_t read_timeout;
uint64_t connect_timeout;
@ -1136,6 +1134,13 @@ isc___nmsocket_prep_destroy(isc_nmsocket_t *sock FLARG);
* if there are no remaining references or active handles.
*/
void
isc__nmsocket_shutdown(isc_nmsocket_t *sock);
/*%<
* Initiate the socket shutdown which actively calls the active
* callbacks.
*/
bool
isc__nmsocket_active(isc_nmsocket_t *sock);
/*%<
@ -1167,17 +1172,15 @@ void
isc__nmsocket_timer_start(isc_nmsocket_t *sock);
void
isc__nmsocket_timer_restart(isc_nmsocket_t *sock);
bool
isc__nmsocket_timer_running(isc_nmsocket_t *sock);
/*%<
* Start/stop/restart the read timeout on the socket
* Start/stop/restart/check the timeout on the socket
*/
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult);
isc_result_t eresult, bool async);
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0);
@ -1850,7 +1853,8 @@ isc__nm_tcp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result);
void
isc__nm_tcpdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result);
void
isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result);
isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async);
isc_result_t
isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock);
@ -1867,6 +1871,8 @@ void
isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
const struct sockaddr *addr, unsigned flags);
void
isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
void
isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
void
isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
@ -1880,7 +1886,9 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock);
void
isc__nm_resume_processing(void *arg);
bool
isc__nm_inactive(isc_nmsocket_t *sock);
isc__nmsocket_closing(isc_nmsocket_t *sock);
bool
isc__nm_closing(isc_nmsocket_t *sock);
void
isc__nm_alloc_dnsbuf(isc_nmsocket_t *sock, size_t len);
@ -1892,8 +1900,11 @@ void
isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult);
void
isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_result_t eresult);
isc_result_t eresult, bool async);
void
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result);
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async);
void
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer);
#define STREAM_CLIENTS_PER_CONN 23

View file

@ -827,7 +827,6 @@ NETIEVENT_SOCKET_REQ_DEF(tcpconnect);
NETIEVENT_SOCKET_REQ_DEF(tcpsend);
NETIEVENT_SOCKET_REQ_DEF(tlssend);
NETIEVENT_SOCKET_REQ_DEF(udpconnect);
NETIEVENT_SOCKET_REQ_RESULT_DEF(connectcb);
NETIEVENT_SOCKET_REQ_RESULT_DEF(readcb);
NETIEVENT_SOCKET_REQ_RESULT_DEF(sendcb);
@ -987,15 +986,6 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
sock->pquota = NULL;
if (sock->timer_initialized) {
sock->timer_initialized = false;
/* We might be in timer callback */
if (!uv_is_closing((uv_handle_t *)&sock->timer)) {
uv_timer_stop(&sock->timer);
uv_close((uv_handle_t *)&sock->timer, NULL);
}
}
isc_astack_destroy(sock->inactivehandles);
while ((uvreq = isc_astack_pop(sock->inactivereqs)) != NULL) {
@ -1031,6 +1021,9 @@ nmsocket_maybe_destroy(isc_nmsocket_t *sock FLARG) {
int active_handles;
bool destroy = false;
NETMGR_TRACE_LOG("%s():%p->references = %" PRIuFAST32 "\n", __func__,
sock, isc_refcount_current(&sock->references));
if (sock->parent != NULL) {
/*
* This is a child socket and cannot be destroyed except
@ -1397,11 +1390,16 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
#endif
UNLOCK(&sock->lock);
if (sock->type == isc_nm_tcpsocket || sock->type == isc_nm_tlssocket ||
(sock->type == isc_nm_udpsocket && atomic_load(&sock->client)) ||
(sock->type == isc_nm_tcpdnssocket && atomic_load(&sock->client)) ||
(sock->type == isc_nm_tlsdnssocket && atomic_load(&sock->client)))
{
switch (sock->type) {
case isc_nm_udpsocket:
case isc_nm_tcpdnssocket:
case isc_nm_tlsdnssocket:
if (!atomic_load(&sock->client)) {
break;
}
/* fallthrough */
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
INSIST(sock->statichandle == NULL);
/*
@ -1411,6 +1409,9 @@ isc___nmhandle_get(isc_nmsocket_t *sock, isc_sockaddr_t *peer,
* handle and socket would never be freed.
*/
sock->statichandle = handle;
break;
default:
break;
}
if (sock->type == isc_nm_httpsocket && sock->h2.session) {
@ -1520,6 +1521,9 @@ isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) {
}
}
void
isc__nmsocket_shutdown(isc_nmsocket_t *sock);
static void
nmhandle_detach_cb(isc_nmhandle_t **handlep FLARG) {
isc_nmsocket_t *sock = NULL;
@ -1658,24 +1662,26 @@ isc__nm_failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) {
void
isc__nm_failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_result_t eresult) {
isc_result_t eresult, bool async) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
REQUIRE(req->cb.connect != NULL);
atomic_store(&sock->connecting, false);
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
INSIST(atomic_compare_exchange_strong(&sock->connecting,
&(bool){ true }, false));
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, eresult);
isc__nm_connectcb(sock, req, eresult, async);
isc__nmsocket_prep_destroy(sock);
}
void
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result, bool async) {
REQUIRE(VALID_NMSOCK(sock));
switch (sock->type) {
case isc_nm_udpsocket:
@ -1688,7 +1694,7 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
isc__nm_tcpdns_failed_read_cb(sock, result);
return;
case isc_nm_tlsdnssocket:
isc__nm_tlsdns_failed_read_cb(sock, result);
isc__nm_tlsdns_failed_read_cb(sock, result, async);
return;
default:
INSIST(0);
@ -1696,6 +1702,39 @@ isc__nm_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
}
}
void
isc__nmsocket_connecttimeout_cb(uv_timer_t *timer) {
uv_connect_t *uvreq = uv_handle_get_data((uv_handle_t *)timer);
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)uvreq->handle);
isc__nm_uvreq_t *req = uv_handle_get_data((uv_handle_t *)uvreq);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
REQUIRE(VALID_UVREQ(req));
REQUIRE(VALID_NMHANDLE(req->handle));
isc__nmsocket_timer_stop(sock);
if (sock->tls.pending_req != NULL) {
REQUIRE(req == sock->tls.pending_req);
sock->tls.pending_req = NULL;
}
/* Call the connect callback directly */
req->cb.connect(req->handle, ISC_R_TIMEDOUT, req->cbarg);
/* Timer is not running, cleanup and shutdown everything */
if (!isc__nmsocket_timer_running(sock)) {
INSIST(atomic_compare_exchange_strong(&sock->connecting,
&(bool){ true }, false));
isc__nm_uvreq_put(&req, sock);
isc__nmsocket_clearcb(sock);
isc__nmsocket_shutdown(sock);
}
}
static void
isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)timer);
@ -1704,27 +1743,62 @@ isc__nmsocket_readtimeout_cb(uv_timer_t *timer) {
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(sock->reading);
isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT);
if (atomic_load(&sock->client)) {
uv_timer_stop(timer);
if (sock->recv_cb != NULL) {
isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
isc__nm_readcb(sock, req, ISC_R_TIMEDOUT);
}
if (!isc__nmsocket_timer_running(sock)) {
isc__nmsocket_clearcb(sock);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
}
} else {
isc__nm_failed_read_cb(sock, ISC_R_TIMEDOUT, false);
}
}
void
isc__nmsocket_timer_restart(isc_nmsocket_t *sock) {
int r = 0;
REQUIRE(VALID_NMSOCK(sock));
if (sock->read_timeout == 0) {
return;
if (atomic_load(&sock->connecting)) {
if (sock->connect_timeout == 0) {
return;
}
r = uv_timer_start(&sock->timer,
isc__nmsocket_connecttimeout_cb,
sock->connect_timeout + 10, 0);
} else {
if (sock->read_timeout == 0) {
return;
}
r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb,
sock->read_timeout, 0);
}
int r = uv_timer_start(&sock->timer, isc__nmsocket_readtimeout_cb,
sock->read_timeout, 0);
RUNTIME_CHECK(r == 0);
}
bool
isc__nmsocket_timer_running(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
return (uv_is_active((uv_handle_t *)&sock->timer));
}
void
isc__nmsocket_timer_start(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
if (uv_is_active((uv_handle_t *)&sock->timer)) {
if (isc__nmsocket_timer_running(sock)) {
return;
}
@ -1735,9 +1809,7 @@ void
isc__nmsocket_timer_stop(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
if (!uv_is_active((uv_handle_t *)&sock->timer)) {
return;
}
/* uv_timer_stop() is idempotent, no need to check if running */
int r = uv_timer_stop(&sock->timer);
RUNTIME_CHECK(r == 0);
@ -1751,13 +1823,21 @@ isc__nm_get_read_req(isc_nmsocket_t *sock, isc_sockaddr_t *sockaddr) {
req->cb.recv = sock->recv_cb;
req->cbarg = sock->recv_cbarg;
if (atomic_load(&sock->client)) {
switch (sock->type) {
case isc_nm_tcpsocket:
case isc_nm_tlssocket:
isc_nmhandle_attach(sock->statichandle, &req->handle);
} else {
req->handle = isc__nmhandle_get(sock, sockaddr, NULL);
break;
default:
if (atomic_load(&sock->client)) {
isc_nmhandle_attach(sock->statichandle, &req->handle);
} else {
req->handle = isc__nmhandle_get(sock, sockaddr, NULL);
}
break;
}
return req;
return (req);
}
/*%<
@ -1779,6 +1859,7 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE);
size = ISC_NETMGR_RECVBUF_SIZE;
break;
case isc_nm_tcpsocket:
case isc_nm_tcpdnssocket:
break;
case isc_nm_tlsdnssocket:
@ -1797,7 +1878,7 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
}
worker = &sock->mgr->workers[sock->tid];
INSIST(!worker->recvbuf_inuse);
INSIST(!worker->recvbuf_inuse || sock->type == isc_nm_udpsocket);
buf->base = worker->recvbuf;
buf->len = size;
@ -1817,6 +1898,10 @@ isc__nm_start_reading(isc_nmsocket_t *sock) {
r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
isc__nm_udp_read_cb);
break;
case isc_nm_tcpsocket:
r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
isc__nm_tcp_read_cb);
break;
case isc_nm_tcpdnssocket:
r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
isc__nm_tcpdns_read_cb);
@ -1845,6 +1930,7 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) {
case isc_nm_udpsocket:
r = uv_udp_recv_stop(&sock->uv_handle.udp);
break;
case isc_nm_tcpsocket:
case isc_nm_tcpdnssocket:
case isc_nm_tlsdnssocket:
r = uv_read_stop(&sock->uv_handle.stream);
@ -1858,7 +1944,12 @@ isc__nm_stop_reading(isc_nmsocket_t *sock) {
}
bool
isc__nm_inactive(isc_nmsocket_t *sock) {
isc__nm_closing(isc_nmsocket_t *sock) {
return (atomic_load(&sock->mgr->closing));
}
bool
isc__nmsocket_closing(isc_nmsocket_t *sock) {
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
atomic_load(&sock->mgr->closing) ||
(sock->server != NULL && !isc__nmsocket_active(sock->server)));
@ -1945,7 +2036,7 @@ isc__nm_resume_processing(void *arg) {
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(!atomic_load(&sock->client));
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return;
}
@ -1987,9 +2078,7 @@ isc_nmhandle_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
return;
default:
handle->sock->read_timeout = timeout;
if (uv_is_active((uv_handle_t *)&handle->sock->timer)) {
isc__nmsocket_timer_restart(handle->sock);
}
isc__nmsocket_timer_restart(handle->sock);
}
}
@ -2241,38 +2330,27 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
}
}
static void
nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc_result_t eresult,
bool force_async) {
isc__netievent_connectcb_t *ievent = NULL;
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult, bool async) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(uvreq));
REQUIRE(VALID_NMHANDLE(uvreq->handle));
ievent = isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
eresult);
if (force_async) {
if (!async) {
isc__netievent_connectcb_t ievent = { .sock = sock,
.req = uvreq,
.result = eresult };
isc__nm_async_connectcb(NULL, (isc__netievent_t *)&ievent);
} else {
isc__netievent_connectcb_t *ievent =
isc__nm_get_netievent_connectcb(sock->mgr, sock, uvreq,
eresult);
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
} else {
isc__nm_maybe_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, false);
}
void
isc__nm_connectcb_force_async(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult) {
nm_connectcb(sock, uvreq, eresult, true);
}
void
isc__nm_async_connectcb(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_connectcb_t *ievent = (isc__netievent_connectcb_t *)ev0;
@ -2403,23 +2481,8 @@ isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0) {
nmhandle_detach_cb(&ievent->handle FLARG_PASS);
}
static void
shutdown_walk_cb(uv_handle_t *handle, void *arg) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
UNUSED(arg);
if (uv_is_closing(handle)) {
return;
}
switch (handle->type) {
case UV_UDP:
case UV_TCP:
break;
default:
return;
}
void
isc__nmsocket_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
switch (sock->type) {
case isc_nm_udpsocket:
@ -2445,6 +2508,26 @@ shutdown_walk_cb(uv_handle_t *handle, void *arg) {
}
}
static void
shutdown_walk_cb(uv_handle_t *handle, void *arg) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
UNUSED(arg);
if (uv_is_closing(handle)) {
return;
}
switch (handle->type) {
case UV_UDP:
case UV_TCP:
break;
default:
return;
}
isc__nmsocket_shutdown(sock);
}
void
isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(ev0);

View file

@ -63,9 +63,6 @@ tcp_connect_cb(uv_connect_t *uvreq, int status);
static void
tcp_connection_cb(uv_stream_t *server, int status);
static void
read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
static void
tcp_close_cb(uv_handle_t *uvhandle);
@ -86,25 +83,6 @@ stop_tcp_parent(isc_nmsocket_t *sock);
static void
stop_tcp_child(isc_nmsocket_t *sock);
static void
start_reading(isc_nmsocket_t *sock);
static void
stop_reading(isc_nmsocket_t *sock);
static isc__nm_uvreq_t *
get_read_req(isc_nmsocket_t *sock);
static void
tcp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf);
static bool
inactive(isc_nmsocket_t *sock) {
return (!isc__nmsocket_active(sock) || atomic_load(&sock->closing) ||
atomic_load(&sock->mgr->closing) ||
(sock->server != NULL && !isc__nmsocket_active(sock->server)));
}
static void
failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) {
REQUIRE(sock->accepting);
@ -135,23 +113,6 @@ failed_accept_cb(isc_nmsocket_t *sock, isc_result_t eresult) {
}
}
static void
failed_connect_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
isc_result_t eresult) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(VALID_UVREQ(req));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
REQUIRE(req->cb.connect != NULL);
atomic_store(&sock->connecting, false);
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, eresult);
isc__nmsocket_prep_destroy(sock);
}
static isc_result_t
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
isc__networker_t *worker = NULL;
@ -164,21 +125,20 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
result = isc__nm_socket_connectiontimeout(sock->fd,
sock->connect_timeout);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
worker = &sock->mgr->workers[sock->tid];
atomic_store(&sock->connecting, true);
/* 2 minute timeout */
result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
RUNTIME_CHECK(r == 0);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_timer_init(&worker->loop, &sock->timer);
RUNTIME_CHECK(r == 0);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
if (r != 0) {
@ -207,11 +167,13 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
done:
result = isc__nm_uverr2result(r);
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
@ -246,7 +208,7 @@ isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
if (sock->fd != (uv_os_sock_t)(-1)) {
isc__nm_tcp_close(sock);
}
isc__nm_uvreq_put(&req, sock);
isc__nm_connectcb(sock, req, result, true);
}
/*
@ -265,20 +227,35 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
if (!atomic_load(&sock->connecting)) {
return;
}
req = uv_handle_get_data((uv_handle_t *)uvreq);
REQUIRE(VALID_UVREQ(req));
REQUIRE(VALID_NMHANDLE(req->handle));
/* Socket was closed midflight by isc__nm_tcp_shutdown() */
if (!isc__nmsocket_active(sock)) {
if (!atomic_load(&sock->connecting)) {
/*
* The connect was cancelled from timeout; just clean up
* the req.
*/
isc__nm_uvreq_put(&req, sock);
return;
} else if (isc__nmsocket_closing(sock)) {
/* Socket was closed midflight by isc__nm_tcp_shutdown() */
result = ISC_R_CANCELED;
goto error;
}
if (status != 0) {
} else if (status == UV_ETIMEDOUT) {
/* Timeout status code here indicates hard error */
result = ISC_R_TIMEDOUT;
goto error;
} else if (status != 0) {
result = isc__nm_uverr2result(status);
goto error;
}
@ -296,15 +273,15 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false);
return;
error:
failed_connect_cb(sock, req, result);
isc__nm_failed_connect_cb(sock, req, result, false);
}
isc_result_t
void
isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
@ -313,7 +290,6 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc__netievent_tcpconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
@ -321,22 +297,13 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(*sock));
isc__nmsocket_init(sock, mgr, isc_nm_tcpsocket, local);
sock->extrahandlesize = extrahandlesize;
sock->connect_timeout = timeout;
sock->result = ISC_R_DEFAULT;
sock->fd = fd;
sock->fd = (uv_os_sock_t)-1;
atomic_init(&sock->client, true);
req = isc__nm_uvreq_get(mgr, sock);
@ -346,6 +313,18 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
req->local = local->addr;
req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr);
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd);
if (result != ISC_R_SUCCESS) {
if (isc__nm_in_netthread()) {
sock->tid = isc_nm_tid();
}
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, result, false);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
return;
}
ievent = isc__nm_get_netievent_tcpconnect(mgr, sock, req);
if (isc__nm_in_netthread()) {
@ -361,17 +340,12 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
(isc__netievent_t *)ievent);
}
LOCK(&sock->lock);
result = sock->result;
while (result == ISC_R_DEFAULT) {
while (sock->result == ISC_R_DEFAULT) {
WAIT(&sock->cond, &sock->lock);
result = sock->result;
}
atomic_store(&sock->active, true);
BROADCAST(&sock->scond);
UNLOCK(&sock->lock);
INSIST(result != ISC_R_DEFAULT);
return (result);
}
static uv_os_sock_t
@ -613,7 +587,7 @@ tcp_connection_cb(uv_stream_t *server, int status) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
result = ISC_R_CANCELED;
goto done;
}
@ -693,7 +667,8 @@ failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->statichandle != NULL);
stop_reading(sock);
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
if (!sock->recv_read) {
goto destroy;
@ -701,7 +676,7 @@ failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
sock->recv_read = false;
if (sock->recv_cb != NULL) {
isc__nm_uvreq_t *req = get_read_req(sock);
isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
isc__nmsocket_clearcb(sock);
isc__nm_readcb(sock, req, result);
}
@ -734,42 +709,6 @@ failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
}
}
static isc__nm_uvreq_t *
get_read_req(isc_nmsocket_t *sock) {
isc__nm_uvreq_t *req = NULL;
req = isc__nm_uvreq_get(sock->mgr, sock);
req->cb.recv = sock->recv_cb;
req->cbarg = sock->recv_cbarg;
isc_nmhandle_attach(sock->statichandle, &req->handle);
return req;
}
static void
start_reading(isc_nmsocket_t *sock) {
if (sock->reading) {
return;
}
int r = uv_read_start(&sock->uv_handle.stream, tcp_alloc_cb, read_cb);
REQUIRE(r == 0);
sock->reading = true;
}
static void
stop_reading(isc_nmsocket_t *sock) {
if (!sock->reading) {
return;
}
int r = uv_read_stop(&sock->uv_handle.stream);
REQUIRE(r == 0);
sock->reading = false;
isc__nmsocket_timer_stop(sock);
}
void
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
@ -807,32 +746,6 @@ isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
return;
}
/*%<
* Allocator for TCP read operations. Limited to size 2^16.
*
* Note this doesn't actually allocate anything, it just assigns the
* worker's receive buffer to a socket, and marks it as "in use".
*/
static void
tcp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
isc__networker_t *worker = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tcpsocket);
REQUIRE(isc__nm_in_netthread());
if (size > 65536) {
size = 65536;
}
worker = &sock->mgr->workers[sock->tid];
INSIST(!worker->recvbuf_inuse);
buf->base = worker->recvbuf;
buf->len = size;
worker->recvbuf_inuse = true;
}
void
isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpstartread_t *ievent =
@ -843,13 +756,13 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
if (inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
sock->reading = true;
failed_read_cb(sock, ISC_R_CANCELED);
return;
}
start_reading(sock);
isc__nm_start_reading(sock);
isc__nmsocket_timer_start(sock);
}
@ -886,7 +799,8 @@ isc__nm_async_tcppauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
stop_reading(sock);
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
}
void
@ -921,8 +835,8 @@ isc__nm_tcp_resumeread(isc_nmhandle_t *handle) {
(isc__netievent_t *)ievent);
}
static void
read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
void
isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
isc__nm_uvreq_t *req = NULL;
@ -931,7 +845,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
REQUIRE(sock->reading);
REQUIRE(buf != NULL);
if (inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
failed_read_cb(sock, ISC_R_CANCELED);
goto free;
}
@ -947,7 +861,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
goto free;
}
req = get_read_req(sock);
req = isc__nm_get_read_req(sock, NULL);
/*
* The callback will be called synchronously because the
@ -1030,7 +944,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
if (quota != NULL) {
isc_quota_detach(&quota);
}
@ -1160,11 +1074,11 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, const isc_region_t *region,
static void
tcp_send_cb(uv_write_t *req, int status) {
isc__nm_uvreq_t *uvreq = (isc__nm_uvreq_t *)req->data;
isc_nmsocket_t *sock = uvreq->sock;
REQUIRE(VALID_UVREQ(uvreq));
REQUIRE(VALID_NMHANDLE(uvreq->handle));
isc_nmsocket_t *sock = uvreq->sock;
if (status < 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]);
failed_send_cb(sock, uvreq, isc__nm_uverr2result(status));
@ -1204,7 +1118,7 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
int r;
if (inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
@ -1240,10 +1154,7 @@ tcp_stop_cb(uv_handle_t *handle) {
}
static void
tcp_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tcp_close_sock(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1265,6 +1176,14 @@ tcp_close_cb(uv_handle_t *handle) {
isc__nmsocket_prep_destroy(sock);
}
static void
tcp_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tcp_close_sock(sock);
}
static void
timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
@ -1272,6 +1191,8 @@ timer_close_cb(uv_handle_t *handle) {
if (sock->parent) {
uv_close(&sock->uv_handle.handle, tcp_stop_cb);
} else if (uv_is_closing(&sock->uv_handle.handle)) {
tcp_close_sock(sock);
} else {
uv_close(&sock->uv_handle.handle, tcp_close_cb);
}
@ -1347,7 +1268,10 @@ tcp_close_direct(isc_nmsocket_t *sock) {
isc_quota_detach(&sock->quota);
}
stop_reading(sock);
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
}
@ -1389,6 +1313,19 @@ isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0) {
tcp_close_direct(sock);
}
static void
tcp_close_connect_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
isc__nmsocket_prep_destroy(sock);
isc__nmsocket_detach(&sock);
}
void
isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
@ -1403,11 +1340,18 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
return;
}
if (atomic_load(&sock->connecting) || sock->accepting) {
if (sock->accepting) {
return;
}
if (sock->statichandle) {
if (atomic_load(&sock->connecting)) {
isc_nmsocket_t *tsock = NULL;
isc__nmsocket_attach(sock, &tsock);
uv_close(&sock->uv_handle.handle, tcp_close_connect_cb);
return;
}
if (sock->statichandle != NULL) {
failed_read_cb(sock, ISC_R_CANCELED);
return;
}
@ -1459,5 +1403,5 @@ isc__nm_tcp_listener_nactive(isc_nmsocket_t *listener) {
nactive = atomic_load(&listener->active_child_connections);
INSIST(nactive >= 0);
return nactive;
return (nactive);
}

View file

@ -104,7 +104,11 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
r = uv_timer_init(&worker->loop, &sock->timer);
RUNTIME_CHECK(r == 0);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_CANCELED;
goto error;
}
r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
if (r != 0) {
@ -137,11 +141,14 @@ tcpdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
done:
result = isc__nm_uverr2result(r);
error:
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
@ -172,9 +179,10 @@ isc__nm_async_tcpdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
result = tcpdns_connect_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);
isc__nm_uvreq_put(&req, sock);
}
/*
@ -193,20 +201,28 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
if (!atomic_load(&sock->connecting)) {
return;
}
req = uv_handle_get_data((uv_handle_t *)uvreq);
REQUIRE(VALID_UVREQ(req));
REQUIRE(VALID_NMHANDLE(req->handle));
/* Socket was closed midflight by isc__nm_tcpdns_shutdown() */
if (!isc__nmsocket_active(sock)) {
if (isc__nmsocket_closing(sock)) {
/* Socket was closed midflight by isc__nm_tcpdns_shutdown() */
result = ISC_R_CANCELED;
goto error;
}
if (status != 0) {
} else if (status == UV_ETIMEDOUT) {
/* Timeout status code here indicates hard error */
result = ISC_R_CANCELED;
goto error;
} else if (status != 0) {
result = isc__nm_uverr2result(status);
goto error;
}
@ -224,15 +240,15 @@ tcpdns_connect_cb(uv_connect_t *uvreq, int status) {
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS, false);
return;
error:
isc__nm_failed_connect_cb(sock, req, result);
isc__nm_failed_connect_cb(sock, req, result, false);
}
isc_result_t
void
isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
@ -241,7 +257,6 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc__netievent_tcpdnsconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
@ -249,27 +264,14 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(*sock));
isc__nmsocket_init(sock, mgr, isc_nm_tcpdnssocket, local);
sock->extrahandlesize = extrahandlesize;
sock->connect_timeout = timeout;
sock->result = ISC_R_DEFAULT;
sock->fd = fd;
atomic_init(&sock->client, true);
result = isc__nm_socket_connectiontimeout(fd, timeout);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
req = isc__nm_uvreq_get(mgr, sock);
req->cb.connect = cb;
req->cbarg = cbarg;
@ -277,6 +279,22 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
req->local = local->addr;
req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr);
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd);
if (result != ISC_R_SUCCESS) {
if (isc__nm_in_netthread()) {
sock->tid = isc_nm_tid();
}
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, result, true);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
return;
}
/* 2 minute timeout */
result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
ievent = isc__nm_get_netievent_tcpdnsconnect(mgr, sock, req);
if (isc__nm_in_netthread()) {
@ -291,18 +309,14 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc__nm_enqueue_ievent(&mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
LOCK(&sock->lock);
result = sock->result;
while (result == ISC_R_DEFAULT) {
while (sock->result == ISC_R_DEFAULT) {
WAIT(&sock->cond, &sock->lock);
result = sock->result;
}
atomic_store(&sock->active, true);
BROADCAST(&sock->scond);
UNLOCK(&sock->lock);
INSIST(result != ISC_R_DEFAULT);
return (result);
}
static uv_os_sock_t
@ -546,7 +560,7 @@ tcpdns_connection_cb(uv_stream_t *server, int status) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (isc__nm_inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
result = ISC_R_CANCELED;
goto done;
}
@ -700,9 +714,9 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
sock->reading = true;
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
@ -727,7 +741,7 @@ isc__nm_tcpdns_processbuffer(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
@ -804,8 +818,8 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
REQUIRE(sock->reading);
REQUIRE(buf != NULL);
if (isc__nm_inactive(sock)) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
if (isc__nmsocket_closing(sock)) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, true);
goto free;
}
@ -815,7 +829,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
sock->statsindex[STATID_RECVFAIL]);
}
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread));
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread), true);
goto free;
}
@ -903,7 +917,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (isc__nm_inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
if (quota != NULL) {
isc_quota_detach(&quota);
}
@ -1097,7 +1111,7 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
result = ISC_R_CANCELED;
goto fail;
}
@ -1167,11 +1181,7 @@ tcpdns_stop_cb(uv_handle_t *handle) {
}
static void
tcpdns_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tcpdns_close_sock(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1194,12 +1204,25 @@ tcpdns_close_cb(uv_handle_t *handle) {
}
static void
timer_close_cb(uv_handle_t *handle) {
tcpdns_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tcpdns_close_sock(sock);
}
static void
timer_close_cb(uv_handle_t *timer) {
isc_nmsocket_t *sock = uv_handle_get_data(timer);
uv_handle_set_data(timer, NULL);
REQUIRE(VALID_NMSOCK(sock));
if (sock->parent) {
uv_close(&sock->uv_handle.handle, tcpdns_stop_cb);
} else if (uv_is_closing(&sock->uv_handle.handle)) {
tcpdns_close_sock(sock);
} else {
uv_close(&sock->uv_handle.handle, tcpdns_close_cb);
}
@ -1271,6 +1294,8 @@ tcpdns_close_direct(isc_nmsocket_t *sock) {
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
}
@ -1313,6 +1338,19 @@ isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
tcpdns_close_direct(sock);
}
static void
tcpdns_close_connect_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
isc__nmsocket_prep_destroy(sock);
isc__nmsocket_detach(&sock);
}
void
isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
@ -1327,12 +1365,19 @@ isc__nm_tcpdns_shutdown(isc_nmsocket_t *sock) {
return;
}
if (atomic_load(&sock->connecting) || sock->accepting) {
if (sock->accepting) {
return;
}
if (sock->statichandle) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
if (atomic_load(&sock->connecting)) {
isc_nmsocket_t *tsock = NULL;
isc__nmsocket_attach(sock, &tsock);
uv_close(&sock->uv_handle.handle, tcpdns_close_connect_cb);
return;
}
if (sock->statichandle != NULL) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
@ -1372,7 +1417,7 @@ isc__nm_async_tcpdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
isc__nm_failed_read_cb(sock, ISC_R_EOF);
isc__nm_failed_read_cb(sock, ISC_R_EOF, false);
}
void

View file

@ -110,6 +110,10 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
atomic_store(&sock->connecting, true);
/* 2 minute timeout */
result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
RUNTIME_CHECK(r == 0);
uv_handle_set_data(&sock->uv_handle.handle, sock);
@ -118,6 +122,11 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
RUNTIME_CHECK(r == 0);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
if (isc__nm_closing(sock)) {
result = ISC_R_CANCELED;
goto error;
}
r = uv_tcp_open(&sock->uv_handle.tcp, sock->fd);
if (r != 0) {
isc__nm_closesocket(sock->fd);
@ -149,11 +158,14 @@ tlsdns_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_CONNECT]);
uv_handle_set_data((uv_handle_t *)&sock->timer, &req->uv_req.connect);
isc__nmsocket_timer_start(sock);
atomic_store(&sock->connected, true);
done:
result = isc__nm_uverr2result(r);
error:
LOCK(&sock->lock);
sock->result = result;
SIGNAL(&sock->cond);
@ -184,9 +196,12 @@ isc__nm_async_tlsdnsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
result = tlsdns_connect_direct(sock, req);
if (result != ISC_R_SUCCESS) {
INSIST(atomic_compare_exchange_strong(&sock->connecting,
&(bool){ true }, false));
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, result, true);
atomic_store(&sock->active, false);
isc__nm_tlsdns_close(sock);
isc__nm_uvreq_put(&req, sock);
}
/*
@ -205,20 +220,25 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->connecting));
if (!atomic_load(&sock->connecting)) {
return;
}
req = uv_handle_get_data((uv_handle_t *)uvreq);
REQUIRE(VALID_UVREQ(req));
REQUIRE(VALID_NMHANDLE(req->handle));
/* Socket was closed midflight by isc__nm_tlsdns_shutdown() */
if (!isc__nmsocket_active(sock)) {
if (isc__nmsocket_closing(sock)) {
/* Socket was closed midflight by isc__nm_tlsdns_shutdown() */
result = ISC_R_CANCELED;
goto error;
}
if (status != 0) {
} else if (status == UV_ETIMEDOUT) {
/* Timeout status code here indicates hard error */
result = ISC_R_CANCELED;
goto error;
} else if (status != 0) {
result = isc__nm_uverr2result(status);
goto error;
}
@ -248,10 +268,11 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
#if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO
/*
* Note that if the rbio and wbio are the same then SSL_set0_rbio() and
* SSL_set0_wbio() each take ownership of one reference. Therefore it
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
* Note that if the rbio and wbio are the same then
* SSL_set0_rbio() and SSL_set0_wbio() each take ownership of
* one reference. Therefore it may be necessary to increment the
* number of references available using BIO_up_ref(3) before
* calling the set0 functions.
*/
SSL_set0_rbio(sock->tls.tls, sock->tls.ssl_rbio);
SSL_set0_wbio(sock->tls.tls, sock->tls.ssl_wbio);
@ -264,23 +285,24 @@ tlsdns_connect_cb(uv_connect_t *uvreq, int status) {
result = isc_sockaddr_fromsockaddr(&sock->peer, (struct sockaddr *)&ss);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
/* Setting pending req */
sock->tls.pending_req = req;
isc__nm_process_sock_buffer(sock);
result = tls_cycle(sock);
if (result != ISC_R_SUCCESS) {
sock->tls.pending_req = NULL;
goto error;
}
return;
error:
sock->tls.pending_req = NULL;
isc__nm_failed_connect_cb(sock, req, result);
isc__nm_failed_connect_cb(sock, req, result, false);
}
isc_result_t
void
isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize, isc_tlsctx_t *sslctx) {
@ -289,7 +311,6 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc__netievent_tlsdnsconnect_t *ievent = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
@ -298,28 +319,15 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we need to
* handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(*sock));
isc__nmsocket_init(sock, mgr, isc_nm_tlsdnssocket, local);
sock->extrahandlesize = extrahandlesize;
sock->connect_timeout = timeout;
sock->result = ISC_R_DEFAULT;
sock->fd = fd;
sock->tls.ctx = sslctx;
atomic_init(&sock->client, true);
result = isc__nm_socket_connectiontimeout(fd, timeout);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
atomic_init(&sock->connecting, true);
req = isc__nm_uvreq_get(mgr, sock);
req->cb.connect = cb;
@ -328,6 +336,19 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
req->local = local->addr;
req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface->addr);
result = isc__nm_socket(sa_family, SOCK_STREAM, 0, &sock->fd);
if (result != ISC_R_SUCCESS) {
goto failure;
}
if (isc__nm_closing(sock)) {
goto failure;
}
/* 2 minute timeout */
result = isc__nm_socket_connectiontimeout(sock->fd, 120 * 1000);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
ievent = isc__nm_get_netievent_tlsdnsconnect(mgr, sock, req);
if (isc__nm_in_netthread()) {
@ -343,17 +364,24 @@ isc_nm_tlsdnsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
(isc__netievent_t *)ievent);
}
LOCK(&sock->lock);
result = sock->result;
while (result == ISC_R_DEFAULT) {
while (sock->result == ISC_R_DEFAULT) {
WAIT(&sock->cond, &sock->lock);
result = sock->result;
}
atomic_store(&sock->active, true);
BROADCAST(&sock->scond);
UNLOCK(&sock->lock);
INSIST(result != ISC_R_DEFAULT);
return;
failure:
if (isc__nm_in_netthread()) {
sock->tid = isc_nm_tid();
}
return (result);
INSIST(atomic_compare_exchange_strong(&sock->connecting,
&(bool){ true }, false));
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, result, true);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
}
static uv_os_sock_t
@ -552,8 +580,9 @@ isc__nm_async_tlsdnslisten(isc__networker_t *worker, isc__netievent_t *ev0) {
#endif
/*
* The callback will run in the same thread uv_listen() was called
* from, so a race with tlsdns_connection_cb() isn't possible.
* The callback will run in the same thread uv_listen() was
* called from, so a race with tlsdns_connection_cb() isn't
* possible.
*/
r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
tlsdns_connection_cb);
@ -600,7 +629,7 @@ tlsdns_connection_cb(uv_stream_t *server, int status) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (isc__nm_inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
result = ISC_R_CANCELED;
goto done;
}
@ -742,7 +771,8 @@ isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) {
}
/*
* If network manager is interlocked, re-enqueue the event for later.
* If network manager is interlocked, re-enqueue the event for
* later.
*/
if (!isc__nm_acquire_interlocked(sock->mgr)) {
enqueue_stoplistening(sock);
@ -753,7 +783,8 @@ isc__nm_async_tlsdnsstop(isc__networker_t *worker, isc__netievent_t *ev0) {
}
void
isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
bool async) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(result != ISC_R_SUCCESS);
@ -763,7 +794,7 @@ isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
if (sock->tls.pending_req != NULL) {
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED);
isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED, async);
}
if (!sock->recv_read) {
@ -780,8 +811,8 @@ isc__nm_tlsdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
destroy:
isc__nmsocket_prep_destroy(sock);
/* We need to detach from quota after the read callback function had a
* chance to be executed. */
/* We need to detach from quota after the read callback function
* had a chance to be executed. */
if (sock->quota) {
isc_quota_detach(&sock->quota);
}
@ -813,10 +844,11 @@ isc__nm_tlsdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
ievent = isc__nm_get_netievent_tlsdnsread(sock->mgr, sock);
/*
* This MUST be done asynchronously, no matter which thread we're
* in. The callback function for isc_nm_read() often calls
* 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 processbuffer() and grow the stack
* indefinitely.
*/
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
@ -836,15 +868,15 @@ isc__nm_async_tlsdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
sock->reading = true;
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
result = tls_cycle(sock);
if (result != ISC_R_SUCCESS) {
isc__nm_failed_read_cb(sock, result);
isc__nm_failed_read_cb(sock, result, false);
}
}
@ -866,7 +898,7 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
@ -892,7 +924,8 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) {
/*
* We need to launch the resume_processing after the buffer has
* been consumed, thus we need to delay the detaching the handle.
* been consumed, thus we need to delay the detaching the
* handle.
*/
isc_nmhandle_attach(req->handle, &handle);
@ -905,15 +938,16 @@ isc__nm_tlsdns_processbuffer(isc_nmsocket_t *sock) {
req->uvbuf.len = len;
/*
* If isc__nm_tlsdns_read() was called, it will be satisfied by single
* DNS message in the next call.
* If isc__nm_tlsdns_read() was called, it will be satisfied by
* single DNS message in the next call.
*/
sock->recv_read = false;
/*
* The assertion failure here means that there's a errnoneous extra
* nmhandle detach happening in the callback and resume_processing gets
* called while we are still processing the buffer.
* The assertion failure here means that there's a errnoneous
* extra nmhandle detach happening in the callback and
* resume_processing gets called while we are still processing
* the buffer.
*/
REQUIRE(sock->processing == false);
sock->processing = true;
@ -958,14 +992,19 @@ tls_cycle_input(isc_nmsocket_t *sock) {
sock->buf + sock->buf_len,
sock->buf_size - sock->buf_len, &len);
if (rv != 1) {
/* Process what's in the buffer so far */
/*
* Process what's in the buffer so far
*/
isc__nm_process_sock_buffer(sock);
/* FIXME: Should we call failed_read_cb()? */
/*
* FIXME: Should we call
* isc__nm_failed_read_cb()?
*/
break;
}
REQUIRE((size_t)pending == len);
INSIST((size_t)pending == len);
sock->buf_len += len;
@ -1030,9 +1069,12 @@ tls_cycle_input(isc_nmsocket_t *sock) {
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
atomic_store(&sock->connecting, false);
isc__nmsocket_timer_stop(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS);
INSIST(atomic_compare_exchange_strong(
&sock->connecting, &(bool){ true }, false));
isc__nm_connectcb(sock, req, ISC_R_SUCCESS, true);
}
async_tlsdns_cycle(sock);
}
@ -1045,7 +1087,14 @@ tls_error(isc_nmsocket_t *sock, isc_result_t result) {
switch (sock->tls.state) {
case TLS_STATE_HANDSHAKE:
case TLS_STATE_IO:
isc__nm_tlsdns_failed_read_cb(sock, result);
if (atomic_load(&sock->connecting)) {
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
isc__nm_failed_connect_cb(sock, req, result, false);
} else {
isc__nm_tlsdns_failed_read_cb(sock, result, false);
}
break;
case TLS_STATE_ERROR:
return;
@ -1056,7 +1105,7 @@ tls_error(isc_nmsocket_t *sock, isc_result_t result) {
sock->tls.state = TLS_STATE_ERROR;
sock->tls.pending_error = result;
/* tlsdns_close_direct(sock); */
isc__nmsocket_shutdown(sock);
}
static void
@ -1141,7 +1190,8 @@ tls_cycle_output(isc_nmsocket_t *sock) {
req->uvbuf.len - err);
req->uvbuf.len = req->uvbuf.len - err;
} else if (err == UV_ENOSYS || err == UV_EAGAIN) {
/* uv_try_write is not supported, send asynchronously */
/* uv_try_write is not supported, send
* asynchronously */
} else {
result = isc__nm_uverr2result(err);
isc__nm_uvreq_put(&req, sock);
@ -1182,6 +1232,10 @@ static isc_result_t
tls_cycle(isc_nmsocket_t *sock) {
isc_result_t result;
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
result = tls_pop_error(sock);
if (result != ISC_R_SUCCESS) {
goto done;
@ -1212,7 +1266,7 @@ async_tlsdns_cycle(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
/* Socket was closed midflight by isc__nm_tlsdns_shutdown() */
if (!isc__nmsocket_active(sock)) {
if (isc__nmsocket_closing(sock)) {
return;
}
@ -1255,8 +1309,8 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread,
REQUIRE(sock->reading);
REQUIRE(buf != NULL);
if (isc__nm_inactive(sock)) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
if (isc__nmsocket_closing(sock)) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, true);
goto free;
}
@ -1266,7 +1320,7 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread,
sock->statsindex[STATID_RECVFAIL]);
}
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread));
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nread), true);
goto free;
}
@ -1281,13 +1335,13 @@ isc__nm_tlsdns_read_cb(uv_stream_t *stream, ssize_t nread,
rv = BIO_write_ex(sock->tls.app_wbio, buf->base, (size_t)nread, &len);
if (rv <= 0 || (size_t)nread != len) {
isc__nm_failed_read_cb(sock, ISC_R_TLSERROR);
isc__nm_failed_read_cb(sock, ISC_R_TLSERROR, true);
goto free;
}
result = tls_cycle(sock);
if (result != ISC_R_SUCCESS) {
isc__nm_failed_read_cb(sock, result);
isc__nm_failed_read_cb(sock, result, true);
}
free:
async_tlsdns_cycle(sock);
@ -1301,7 +1355,8 @@ quota_accept_cb(isc_quota_t *quota, void *sock0) {
REQUIRE(VALID_NMSOCK(sock));
/*
* Create a tlsdnsaccept event and pass it using the async channel.
* Create a tlsdnsaccept event and pass it using the async
* channel.
*/
isc__netievent_tlsdnsaccept_t *ievent =
@ -1351,7 +1406,7 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (isc__nm_inactive(ssock)) {
if (isc__nmsocket_closing(ssock)) {
if (quota != NULL) {
isc_quota_detach(&quota);
}
@ -1418,8 +1473,8 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
}
/*
* The handle will be either detached on acceptcb failure or in the
* readcb.
* The handle will be either detached on acceptcb failure or in
* the readcb.
*/
handle = isc__nmhandle_get(csock, NULL, &local);
@ -1444,10 +1499,11 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
#if HAVE_SSL_SET0_RBIO && HAVE_SSL_SET0_WBIO
/*
* Note that if the rbio and wbio are the same then SSL_set0_rbio() and
* SSL_set0_wbio() each take ownership of one reference. Therefore it
* may be necessary to increment the number of references available
* using BIO_up_ref(3) before calling the set0 functions.
* Note that if the rbio and wbio are the same then
* SSL_set0_rbio() and SSL_set0_wbio() each take ownership of
* one reference. Therefore it may be necessary to increment the
* number of references available using BIO_up_ref(3) before
* calling the set0 functions.
*/
SSL_set0_rbio(csock->tls.tls, csock->tls.ssl_rbio);
SSL_set0_wbio(csock->tls.tls, csock->tls.ssl_wbio);
@ -1468,15 +1524,15 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
csock->closehandle_cb = isc__nm_resume_processing;
/*
* We need to keep the handle alive until we fail to read or connection
* is closed by the other side, it will be detached via
* prep_destroy()->tlsdns_close_direct().
* We need to keep the handle alive until we fail to read or
* connection is closed by the other side, it will be detached
* via prep_destroy()->tlsdns_close_direct().
*/
isc_nmhandle_attach(handle, &csock->recv_handle);
/*
* The initial timer has been set, update the read timeout for the next
* reads.
* The initial timer has been set, update the read timeout for
* the next reads.
*/
csock->read_timeout = (atomic_load(&csock->keepalive)
? atomic_load(&csock->mgr->keepalive)
@ -1583,7 +1639,7 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
return (result);
}
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
@ -1593,8 +1649,8 @@ tlsdns_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
}
/*
* There's no SSL_writev(), so we need to use a local buffer to assemble
* the whole message
* There's no SSL_writev(), so we need to use a local buffer to
* assemble the whole message
*/
worker = &sock->mgr->workers[sock->tid];
sendlen = req->uvbuf.len + sizeof(uint16_t);
@ -1664,10 +1720,7 @@ tlsdns_stop_cb(uv_handle_t *handle) {
}
static void
tlsdns_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tlsdns_close_sock(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->closing));
@ -1698,14 +1751,25 @@ tlsdns_close_cb(uv_handle_t *handle) {
isc__nmsocket_prep_destroy(sock);
}
static void
tlsdns_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
tlsdns_close_sock(sock);
}
static void
timer_close_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
uv_handle_set_data(handle, NULL);
REQUIRE(VALID_NMSOCK(sock));
if (sock->parent) {
uv_close(&sock->uv_handle.handle, tlsdns_stop_cb);
} else if (uv_is_closing(&sock->uv_handle.handle)) {
tlsdns_close_sock(sock);
} else {
uv_close(&sock->uv_handle.handle, tlsdns_close_cb);
}
@ -1780,6 +1844,8 @@ tlsdns_close_direct(isc_nmsocket_t *sock) {
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
uv_handle_set_data((uv_handle_t *)&sock->timer, sock);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
}
@ -1798,7 +1864,8 @@ isc__nm_tlsdns_close(isc_nmsocket_t *sock) {
tlsdns_close_direct(sock);
} else {
/*
* We need to create an event and pass it using async channel
* We need to create an event and pass it using async
* channel
*/
isc__netievent_tlsdnsclose_t *ievent =
isc__nm_get_netievent_tlsdnsclose(sock->mgr, sock);
@ -1822,6 +1889,19 @@ isc__nm_async_tlsdnsclose(isc__networker_t *worker, isc__netievent_t *ev0) {
tlsdns_close_direct(sock);
}
static void
tlsdns_close_connect_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->tid == isc_nm_tid());
isc__nmsocket_prep_destroy(sock);
isc__nmsocket_detach(&sock);
}
void
isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
@ -1836,18 +1916,39 @@ isc__nm_tlsdns_shutdown(isc_nmsocket_t *sock) {
return;
}
if (sock->tls.pending_req != NULL) {
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED);
if (sock->tls.tls) {
/* Shutdown any active TLS connections */
(void)SSL_shutdown(sock->tls.tls);
}
if (atomic_load(&sock->connecting) || sock->accepting) {
if (sock->accepting) {
return;
}
if (sock->statichandle) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
/* TLS handshake hasn't been completed yet */
if (atomic_load(&sock->connecting)) {
/*
* TCP connection has been established, now waiting on
* TLS handshake to complete
*/
if (sock->tls.pending_req != NULL) {
isc__nm_uvreq_t *req = sock->tls.pending_req;
sock->tls.pending_req = NULL;
isc__nm_failed_connect_cb(sock, req, ISC_R_CANCELED,
false);
return;
}
/* The TCP connection hasn't been established yet */
isc_nmsocket_t *tsock = NULL;
isc__nmsocket_attach(sock, &tsock);
uv_close(&sock->uv_handle.handle, tlsdns_close_connect_cb);
return;
}
if (sock->statichandle != NULL) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
@ -1887,7 +1988,7 @@ isc__nm_async_tlsdnscancel(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
isc__nm_failed_read_cb(sock, ISC_R_EOF);
isc__nm_failed_read_cb(sock, ISC_R_EOF, false);
}
void

View file

@ -835,13 +835,12 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
}
}
isc_result_t
void
isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, SSL_CTX *ctx,
unsigned int timeout, size_t extrahandlesize) {
isc_nmsocket_t *nsock = NULL, *tsock = NULL;
isc__netievent_tlsconnect_t *ievent = NULL;
isc_result_t result = ISC_R_DEFAULT;
#if defined(NETMGR_TRACE) && defined(NETMGR_TRACE_VERBOSE)
fprintf(stderr, "TLS: isc_nm_tlsconnect(): in net thread: %s\n",
isc__nm_in_netthread() ? "yes" : "no");
@ -880,20 +879,14 @@ isc_nm_tlsconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
}
LOCK(&nsock->lock);
result = nsock->result;
while (result == ISC_R_DEFAULT) {
while (nsock->result == ISC_R_DEFAULT) {
WAIT(&nsock->cond, &nsock->lock);
result = nsock->result;
}
atomic_store(&nsock->active, true);
BROADCAST(&nsock->scond);
UNLOCK(&nsock->lock);
INSIST(VALID_NMSOCK(nsock));
isc__nmsocket_detach(&tsock);
INSIST(result != ISC_R_DEFAULT);
return (result);
}
static void
@ -936,6 +929,11 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
if (isc__nm_closing(tlssock)) {
result = ISC_R_CANCELED;
goto error;
}
/*
* We need to initialize SSL now to reference SSL_CTX properly.
*/
@ -948,20 +946,11 @@ isc__nm_async_tlsconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
tlssock->tid = isc_nm_tid();
tlssock->tlsstream.state = TLS_INIT;
result = isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
(isc_nmiface_t *)&ievent->peer,
tcp_connected, tlssock,
tlssock->connect_timeout, 0);
isc_nm_tcpconnect(worker->mgr, (isc_nmiface_t *)&ievent->local,
(isc_nmiface_t *)&ievent->peer, tcp_connected,
tlssock, tlssock->connect_timeout, 0);
/*
* Sometimes on Linux, socket creation might fail if there are
* already too many socket descriptors. In such a case the
* connect callback is not going to be called.
*/
if (result != ISC_R_SUCCESS) {
goto error;
}
update_result(tlssock, result);
update_result(tlssock, ISC_R_SUCCESS);
return;
error:

View file

@ -383,7 +383,7 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
* we can free the buffer and bail.
*/
if (addr == NULL) {
isc__nm_failed_read_cb(sock, ISC_R_EOF);
isc__nm_failed_read_cb(sock, ISC_R_EOF, false);
goto free;
}
@ -391,12 +391,13 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
* - If the socket is no longer active.
*/
if (!isc__nmsocket_active(sock)) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
goto free;
}
if (nrecv < 0) {
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv));
isc__nm_failed_read_cb(sock, isc__nm_uverr2result(nrecv),
false);
goto free;
}
@ -523,7 +524,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->tid == isc_nm_tid());
UNUSED(worker);
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
isc__nm_failed_send_cb(sock, uvreq, ISC_R_CANCELED);
return;
}
@ -567,7 +568,7 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(sock->type == isc_nm_udpsocket);
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
return (ISC_R_CANCELED);
}
@ -597,6 +598,7 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
isc__networker_t *worker = NULL;
int uv_bind_flags = UV_UDP_REUSEADDR;
isc_result_t result = ISC_R_DEFAULT;
int tries = 3;
int r;
REQUIRE(isc__nm_in_netthread());
@ -616,7 +618,6 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
r = uv_udp_open(&sock->uv_handle.udp, sock->fd);
if (r != 0) {
isc__nm_closesocket(sock->fd);
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
goto done;
}
@ -642,7 +643,15 @@ udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
&(int){ ISC_SEND_BUFFER_SIZE });
#endif
r = isc_uv_udp_connect(&sock->uv_handle.udp, &req->peer.type.sa);
/*
* On FreeBSD the UDP connect() call sometimes results in a
* spurious transient EADDRINUSE. Try a few more times before
* giving up.
*/
do {
r = isc_uv_udp_connect(&sock->uv_handle.udp,
&req->peer.type.sa);
} while (r == UV_EADDRINUSE && --tries > 0);
if (r != 0) {
isc__nm_incstats(sock->mgr,
sock->statsindex[STATID_CONNECTFAIL]);
@ -693,13 +702,13 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->active, false);
isc__nm_udp_close(sock);
isc__nm_uvreq_put(&req, sock);
isc__nm_connectcb(sock, req, result, true);
} else {
/*
* The callback has to be called after the socket has been
* initialized
*/
isc__nm_connectcb(sock, req, ISC_R_SUCCESS);
isc__nm_connectcb(sock, req, ISC_R_SUCCESS, true);
}
/*
@ -708,7 +717,7 @@ isc__nm_async_udpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__nmsocket_detach(&sock);
}
isc_result_t
void
isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
size_t extrahandlesize) {
@ -717,7 +726,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
isc__netievent_udpconnect_t *event = NULL;
isc__nm_uvreq_t *req = NULL;
sa_family_t sa_family;
uv_os_sock_t fd;
REQUIRE(VALID_NM(mgr));
REQUIRE(local != NULL);
@ -725,15 +733,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sa_family = peer->addr.type.sa.sa_family;
/*
* The socket() call can fail spuriously on FreeBSD 12, so we
* need to handle the failure early and gracefully.
*/
result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &fd);
if (result != ISC_R_SUCCESS) {
return (result);
}
sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(sock, mgr, isc_nm_udpsocket, local);
@ -742,10 +741,27 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
sock->read_timeout = timeout;
sock->extrahandlesize = extrahandlesize;
sock->peer = peer->addr;
sock->fd = fd;
sock->result = ISC_R_DEFAULT;
atomic_init(&sock->client, true);
req = isc__nm_uvreq_get(mgr, sock);
req->cb.connect = cb;
req->cbarg = cbarg;
req->peer = peer->addr;
req->local = local->addr;
result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &sock->fd);
if (result != ISC_R_SUCCESS) {
if (isc__nm_in_netthread()) {
sock->tid = isc_nm_tid();
}
isc__nmsocket_clearcb(sock);
isc__nm_connectcb(sock, req, result, true);
atomic_store(&sock->closed, true);
isc__nmsocket_detach(&sock);
return;
}
result = isc__nm_socket_reuse(sock->fd);
RUNTIME_CHECK(result == ISC_R_SUCCESS ||
result == ISC_R_NOTIMPLEMENTED);
@ -758,12 +774,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
(void)isc__nm_socket_dontfrag(sock->fd, sa_family);
req = isc__nm_uvreq_get(mgr, sock);
req->cb.connect = cb;
req->cbarg = cbarg;
req->peer = peer->addr;
req->local = local->addr;
event = isc__nm_get_netievent_udpconnect(mgr, sock, req);
if (isc__nm_in_netthread()) {
@ -779,17 +789,12 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_nmiface_t *local, isc_nmiface_t *peer,
(isc__netievent_t *)event);
}
LOCK(&sock->lock);
result = sock->result;
while (sock->result == ISC_R_DEFAULT) {
WAIT(&sock->cond, &sock->lock);
result = sock->result;
}
atomic_store(&sock->active, true);
BROADCAST(&sock->scond);
UNLOCK(&sock->lock);
ENSURE(result != ISC_R_DEFAULT);
return (result);
}
void
@ -868,9 +873,9 @@ isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
if (isc__nm_inactive(sock)) {
if (isc__nmsocket_closing(sock)) {
sock->reading = true;
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
@ -1084,8 +1089,8 @@ isc__nm_udp_shutdown(isc_nmsocket_t *sock) {
* sock->statichandle would be NULL, in that case, nobody is
* interested in the callback.
*/
if (sock->statichandle) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED);
if (sock->statichandle != NULL) {
isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
return;
}
@ -1129,5 +1134,5 @@ isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(atomic_load(&sock->client));
isc__nm_failed_read_cb(sock, ISC_R_EOF);
isc__nm_failed_read_cb(sock, ISC_R_EOF, false);
}

View file

@ -55,7 +55,7 @@ static uint64_t stop_magic = 0;
static uv_buf_t send_msg = { .base = (char *)&send_magic,
.len = sizeof(send_magic) };
static atomic_uint_fast64_t nsends;
static atomic_int_fast64_t nsends;
static atomic_uint_fast64_t ssends;
static atomic_uint_fast64_t sreads;
@ -71,6 +71,8 @@ static bool reuse_supported = true;
static atomic_bool POST = ATOMIC_VAR_INIT(true);
static atomic_bool slowdown = ATOMIC_VAR_INIT(false);
static atomic_bool use_TLS = ATOMIC_VAR_INIT(false);
static isc_tlsctx_t *server_tlsctx = NULL;
static isc_tlsctx_t *client_tlsctx = NULL;
@ -117,6 +119,7 @@ connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
memmove(&data, arg, sizeof(data));
isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data));
if (result != ISC_R_SUCCESS) {
atomic_store(&slowdown, true);
goto error;
}
@ -135,11 +138,10 @@ error:
data.region.length);
}
static isc_result_t
static void
connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg,
bool tls, unsigned int timeout) {
isc_result_t result;
isc_region_t copy;
csdata_t *data = NULL;
isc_tlsctx_t *ctx = NULL;
@ -153,10 +155,8 @@ connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri, post,
connect_send_cb, data, ctx, timeout, 0);
return (result);
isc_nm_httpconnect(mgr, NULL, (isc_nmiface_t *)&tcp_listen_addr, uri,
post, connect_send_cb, data, ctx, timeout, 0);
}
static int
@ -372,28 +372,18 @@ sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
static void
doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint_fast64_t sends = atomic_load(&nsends);
assert_non_null(handle);
UNUSED(cbarg);
UNUSED(region);
(void)atomic_fetch_sub(&nsends, 1);
if (eresult == ISC_R_SUCCESS) {
atomic_fetch_add(&csends, 1);
atomic_fetch_add(&creads, 1);
if (sends > 0) {
atomic_fetch_sub(&nsends, 1);
}
isc_nm_resumeread(handle);
} else {
/* We failed to connect; try again */
while (sends > 0) {
/* Continue until we subtract or we are done */
if (atomic_compare_exchange_weak(&nsends, &sends,
sends - 1)) {
sends--;
break;
}
}
atomic_store(&was_error, true);
}
}
@ -486,11 +476,10 @@ doh_noop(void **state) {
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
connect_send_request(connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_closedown(connect_nm);
@ -531,11 +520,10 @@ doh_noresponse(void **state) {
sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
DOH_PATH);
(void)connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
connect_send_request(connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
@ -558,7 +546,7 @@ doh_noresponse_GET(void **state) {
static void
doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
isc_region_t *region, void *cbarg) {
uint_fast64_t sends = atomic_load(&nsends);
int_fast64_t sends = atomic_fetch_sub(&nsends, 1);
assert_non_null(handle);
UNUSED(region);
@ -567,7 +555,6 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
atomic_fetch_add(&creads, 1);
if (sends > 0) {
size_t i;
atomic_fetch_sub(&nsends, 1);
for (i = 0; i < NWRITES / 2; i++) {
eresult = isc__nm_http_request(
handle,
@ -579,15 +566,6 @@ doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
}
}
} else {
/* We failed to connect; try again */
while (sends > 0) {
/* Continue until we subtract or we are done */
if (atomic_compare_exchange_weak(&nsends, &sends,
sends - 1)) {
sends--;
break;
}
}
atomic_store(&was_error, true);
}
}
@ -596,25 +574,27 @@ static isc_threadresult_t
doh_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
char req_url[256];
isc_result_t result;
int64_t sends = atomic_load(&nsends);
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
while (atomic_load(&nsends) > 0) {
result = connect_send_request(
while (sends > 0) {
/*
* We need to back off and slow down if we start getting
* errors, to prevent a thundering herd problem.
*/
if (atomic_load(&slowdown)) {
usleep(1000 * workers);
atomic_store(&slowdown, false);
}
connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS),
30000);
/* protection against "too many open files" */
#ifndef _WIN32
if (result != ISC_R_SUCCESS) {
INSIST(result == ISC_R_TOOMANYOPENFILES);
usleep(1000 * workers);
}
#endif
sends = atomic_load(&nsends);
}
return ((isc_threadresult_t)0);
@ -642,13 +622,11 @@ doh_recv_one(void **state) {
sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
sizeof(req_url), DOH_PATH);
result = connect_send_request(
connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_reply_cb, NULL, atomic_load(&use_TLS), 30000);
assert_int_equal(result, ISC_R_SUCCESS);
connect_send_request(connect_nm, req_url, atomic_load(&POST),
&(isc_region_t){ .base = (uint8_t *)send_msg.base,
.length = send_msg.len },
doh_receive_reply_cb, NULL, atomic_load(&use_TLS),
30000);
while (atomic_load(&nsends) > 0) {
if (atomic_load(&was_error)) {
@ -766,12 +744,10 @@ doh_recv_two(void **state) {
ctx = client_tlsctx;
}
result = isc_nm_httpconnect(
connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr, req_url,
atomic_load(&POST), doh_connect_send_two_requests_cb, NULL, ctx,
5000, 0);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_httpconnect(connect_nm, NULL, (isc_nmiface_t *)&tcp_listen_addr,
req_url, atomic_load(&POST),
doh_connect_send_two_requests_cb, NULL, ctx, 5000,
0);
while (atomic_load(&nsends) > 0) {
if (atomic_load(&was_error)) {

View file

@ -99,7 +99,8 @@ static bool skip_long_tests = false;
#define T_ADVERTISED 120 * 1000
#define T_CONNECT 30 * 1000
#define WAIT_REPEATS 100
/* Wait for 1 second (1000 * 1000 microseconds) */
#define WAIT_REPEATS 1000
#define T_WAIT 1000 /* In microseconds */
#define WAIT_FOR(v, op, val) \
@ -191,18 +192,29 @@ _setup(void **state __attribute__((unused))) {
signal(SIGPIPE, SIG_IGN);
if (getenv("CI_ENABLE_ALL_TESTS") != NULL) {
if (getenv("CI") == NULL || getenv("CI_ENABLE_ALL_TESTS") != NULL) {
esends = NSENDS * workers;
} else {
esends = workers;
skip_long_tests = true;
}
if (isc_tlsctx_createserver(NULL, NULL, &tcp_listen_tlsctx) !=
ISC_R_SUCCESS) {
return (-1);
}
if (isc_tlsctx_createclient(&tcp_connect_tlsctx) != ISC_R_SUCCESS) {
return (-1);
}
return (0);
}
static int
_teardown(void **state __attribute__((unused))) {
isc_tlsctx_free(&tcp_connect_tlsctx);
isc_tlsctx_free(&tcp_listen_tlsctx);
isc_test_end();
return (0);
@ -279,14 +291,6 @@ nm_setup(void **state __attribute__((unused))) {
isc__nm_closesocket(tcp_listen_sock);
tcp_listen_sock = -1;
if (isc_tlsctx_createserver(NULL, NULL, &tcp_listen_tlsctx) !=
ISC_R_SUCCESS) {
return (-1);
}
if (isc_tlsctx_createclient(&tcp_connect_tlsctx) != ISC_R_SUCCESS) {
return (-1);
}
atomic_store(&do_send, true);
atomic_store(&nsends, esends);
@ -330,27 +334,24 @@ static int
nm_teardown(void **state __attribute__((unused))) {
UNUSED(state);
WAIT_FOR_EQ(active_cconnects, 0);
WAIT_FOR_EQ(active_csends, 0);
WAIT_FOR_EQ(active_csends, 0);
WAIT_FOR_EQ(active_ssends, 0);
WAIT_FOR_EQ(active_sreads, 0);
isc_nm_destroy(&connect_nm);
assert_null(connect_nm);
isc_nm_destroy(&listen_nm);
assert_null(listen_nm);
WAIT_FOR_EQ(active_cconnects, 0);
WAIT_FOR_EQ(active_csends, 0);
WAIT_FOR_EQ(active_csends, 0);
WAIT_FOR_EQ(active_ssends, 0);
WAIT_FOR_EQ(active_sreads, 0);
isc_refcount_destroy(&active_cconnects);
isc_refcount_destroy(&active_csends);
isc_refcount_destroy(&active_creads);
isc_refcount_destroy(&active_ssends);
isc_refcount_destroy(&active_sreads);
isc_tlsctx_free(&tcp_connect_tlsctx);
isc_tlsctx_free(&tcp_listen_tlsctx);
return (0);
}
@ -456,12 +457,15 @@ unref:
static void
connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nmhandle_t *readhandle = NULL;
UNUSED(cbarg);
F();
isc_refcount_decrement(&active_cconnects);
if (eresult != ISC_R_SUCCESS) {
goto unref;
return;
}
atomic_fetch_add(&cconnects, 1);
@ -471,9 +475,6 @@ connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
isc_nm_read(handle, connect_read_cb, NULL);
connect_send(handle);
unref:
isc_refcount_decrement(&active_cconnects);
}
static void
@ -564,12 +565,11 @@ stream_accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
return (ISC_R_SUCCESS);
}
typedef isc_result_t (*connect_func)(isc_nm_t *);
typedef void (*connect_func)(isc_nm_t *);
static isc_threadresult_t
connect_thread(isc_threadarg_t arg) {
connect_func connect = (connect_func)arg;
isc_result_t result;
isc_sockaddr_t connect_addr;
connect_addr = (isc_sockaddr_t){ .length = 0 };
@ -578,26 +578,15 @@ connect_thread(isc_threadarg_t arg) {
while (atomic_load(&do_send)) {
uint_fast32_t active =
isc_refcount_increment0(&active_cconnects);
if (active >= workers) {
if (active > workers) {
/*
* If we have more active connections than workers start
* slowing down the connections to prevent the
* If we have more active connections than workers,
* start slowing down the connections to prevent the
* thundering herd problem.
*/
usleep((active - workers) * 1000);
}
result = connect(connect_nm);
if (result != ISC_R_SUCCESS) {
/*
* Also back-off and slow down if we start getting
* errors to prevent the thundering herd problem. This
* could especially happen on FreeBSD where socket()
* call can fail because of system limits and in such
* case it's not such good idea to try again quickly.
*/
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
connect(connect_nm);
}
return ((isc_threadresult_t)0);
@ -605,11 +594,11 @@ connect_thread(isc_threadarg_t arg) {
/* UDP */
static isc_result_t
static void
udp_connect(isc_nm_t *nm) {
return (isc_nm_udpconnect(nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0));
isc_nm_udpconnect(nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
}
static void
@ -659,20 +648,12 @@ mock_listenudp_uv_udp_recv_start(void **state __attribute__((unused))) {
static void
mock_udpconnect_uv_udp_open(void **state __attribute__((unused))) {
isc_result_t result = ISC_R_SUCCESS;
WILL_RETURN(uv_udp_open, UV_ENOMEM);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_not_equal(result, ISC_R_SUCCESS);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
RESET_RETURN;
@ -680,20 +661,12 @@ mock_udpconnect_uv_udp_open(void **state __attribute__((unused))) {
static void
mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) {
isc_result_t result = ISC_R_SUCCESS;
WILL_RETURN(uv_udp_bind, UV_ENOMEM);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_not_equal(result, ISC_R_SUCCESS);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
RESET_RETURN;
@ -702,20 +675,12 @@ mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) {
#if HAVE_UV_UDP_CONNECT
static void
mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) {
isc_result_t result = ISC_R_SUCCESS;
WILL_RETURN(uv_udp_connect, UV_ENOMEM);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_not_equal(result, ISC_R_SUCCESS);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
RESET_RETURN;
@ -724,20 +689,12 @@ mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) {
static void
mock_udpconnect_uv_recv_buffer_size(void **state __attribute__((unused))) {
isc_result_t result = ISC_R_SUCCESS;
WILL_RETURN(uv_recv_buffer_size, UV_ENOMEM);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_equal(result, ISC_R_SUCCESS); /* FIXME: should fail */
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
RESET_RETURN;
@ -745,20 +702,12 @@ mock_udpconnect_uv_recv_buffer_size(void **state __attribute__((unused))) {
static void
mock_udpconnect_uv_send_buffer_size(void **state __attribute__((unused))) {
isc_result_t result = ISC_R_SUCCESS;
WILL_RETURN(uv_send_buffer_size, UV_ENOMEM);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_equal(result, ISC_R_SUCCESS); /* FIXME: should fail */
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
RESET_RETURN;
@ -777,17 +726,10 @@ udp_noop(void **state __attribute__((unused))) {
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(connect_nm,
(isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
atomic_assert_int_eq(cconnects, 0);
@ -806,16 +748,10 @@ udp_noresponse(void **state __attribute__((unused))) {
noop_recv_cb, NULL, 0, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(
connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -849,16 +785,10 @@ udp_recv_one(void **state __attribute__((unused))) {
listen_read_cb, NULL, 0, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(
connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -896,29 +826,17 @@ udp_recv_two(void **state __attribute__((unused))) {
listen_read_cb, NULL, 0, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(
connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_udpconnect(
connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_udpconnect(connect_nm, (isc_nmiface_t *)&udp_connect_addr,
(isc_nmiface_t *)&udp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 2);
WAIT_FOR_LE(nsends, 0);
@ -1135,11 +1053,11 @@ udp_half_recv_half_send(void **state __attribute__((unused))) {
static isc_quota_t *
tcp_listener_init_quota(size_t nthreads);
static isc_result_t
static void
tcp_connect(isc_nm_t *nm) {
return (isc_nm_tcpconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, 1, 0));
isc_nm_tcpconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
}
static void
@ -1156,17 +1074,10 @@ tcp_noop(void **state __attribute__((unused))) {
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpconnect(connect_nm,
(isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
noop_connect_cb, NULL, 1, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
atomic_assert_int_eq(cconnects, 0);
@ -1186,16 +1097,10 @@ tcp_noresponse(void **state __attribute__((unused))) {
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpconnect(connect_nm,
(isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, 1, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -1231,16 +1136,10 @@ tcp_recv_one(void **state __attribute__((unused))) {
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -1280,29 +1179,17 @@ tcp_recv_two(void **state __attribute__((unused))) {
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 2);
WAIT_FOR_LE(nsends, 0);
@ -1532,7 +1419,7 @@ tcp_listener_init_quota(size_t nthreads) {
isc_quota_max(&listener_quota, max_quota);
quotap = &listener_quota;
}
return quotap;
return (quotap);
}
static void
@ -1577,11 +1464,11 @@ tcp_half_recv_half_send_quota(void **state) {
/* TCPDNS */
static isc_result_t
static void
tcpdns_connect(isc_nm_t *nm) {
return (isc_nm_tcpdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0));
isc_nm_tcpdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
}
static void
@ -1599,15 +1486,9 @@ tcpdns_noop(void **state __attribute__((unused))) {
assert_null(listen_sock);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpdnsconnect(connect_nm,
(isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
noop_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0);
isc_nm_closedown(connect_nm);
atomic_assert_int_eq(cconnects, 0);
@ -1632,11 +1513,9 @@ tcpdns_noresponse(void **state __attribute__((unused))) {
}
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_tcpdnsconnect(connect_nm,
(isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -1672,14 +1551,9 @@ tcpdns_recv_one(void **state __attribute__((unused))) {
assert_int_equal(result, ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpdnsconnect(connect_nm,
(isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -1718,31 +1592,17 @@ tcpdns_recv_two(void **state __attribute__((unused))) {
NULL, listen_accept_cb, NULL, 0, 0, NULL, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
assert_int_equal(result, ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 1);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tcpdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
}
} while (result != ISC_R_SUCCESS);
assert_int_equal(result, ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tcpdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0);
WAIT_FOR_EQ(cconnects, 2);
@ -1961,12 +1821,12 @@ tcpdns_half_recv_half_send(void **state __attribute__((unused))) {
/* TLSDNS */
static isc_result_t
static void
tlsdns_connect(isc_nm_t *nm) {
return (isc_nm_tlsdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx));
isc_nm_tlsdnsconnect(nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
}
static void
@ -1984,17 +1844,10 @@ tlsdns_noop(void **state __attribute__((unused))) {
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0, tcp_connect_tlsctx);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, noop_connect_cb,
NULL, T_CONNECT, 0, tcp_connect_tlsctx);
isc_nm_closedown(connect_nm);
@ -2020,17 +1873,11 @@ tlsdns_noresponse(void **state __attribute__((unused))) {
&listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
do {
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb,
NULL, T_CONNECT, 0, tcp_connect_tlsctx);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
} while (result != ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_EQ(csends, 1);
@ -2067,15 +1914,10 @@ tlsdns_recv_one(void **state __attribute__((unused))) {
assert_int_equal(result, ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL,
T_CONNECT, 0, tcp_connect_tlsctx);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
WAIT_FOR_EQ(cconnects, 1);
WAIT_FOR_LE(nsends, 0);
@ -2116,28 +1958,18 @@ tlsdns_recv_two(void **state __attribute__((unused))) {
assert_int_equal(result, ISC_R_SUCCESS);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL,
T_CONNECT, 0, tcp_connect_tlsctx);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
WAIT_FOR_EQ(cconnects, 1);
isc_refcount_increment0(&active_cconnects);
result = isc_nm_tlsdnsconnect(
connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr, connect_connect_cb, NULL,
T_CONNECT, 0, tcp_connect_tlsctx);
if (result != ISC_R_SUCCESS) {
isc_refcount_decrement(&active_cconnects);
usleep(1000);
}
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tlsdnsconnect(connect_nm, (isc_nmiface_t *)&tcp_connect_addr,
(isc_nmiface_t *)&tcp_listen_addr,
connect_connect_cb, NULL, T_CONNECT, 0,
tcp_connect_tlsctx);
WAIT_FOR_EQ(cconnects, 2);

View file

@ -66,13 +66,23 @@ static atomic_uint_fast64_t csends;
static atomic_uint_fast64_t creads;
static atomic_uint_fast64_t ctimeouts;
static unsigned int workers = 0;
static atomic_bool slowdown = ATOMIC_VAR_INIT(false);
static bool reuse_supported = true;
static unsigned int workers = 0;
static isc_tlsctx_t *server_tlsctx = NULL;
static isc_tlsctx_t *client_tlsctx = NULL;
static atomic_bool was_error = ATOMIC_VAR_INIT(false);
static bool skip_long_tests = false;
#define SKIP_IN_CI \
if (skip_long_tests) { \
skip(); \
return; \
}
#define NSENDS 100
#define NWRITES 10
@ -145,9 +155,6 @@ setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
close(fd);
return (-1);
}
if (result == ISC_R_NOTIMPLEMENTED) {
reuse_supported = false;
}
#if IPV6_RECVERR
#define setsockopt_on(socket, level, name) \
@ -185,6 +192,10 @@ _setup(void **state) {
signal(SIGPIPE, SIG_IGN);
if (getenv("CI") != NULL && getenv("CI_ENABLE_ALL_TESTS") == NULL) {
skip_long_tests = true;
}
return (0);
}
@ -241,6 +252,8 @@ nm_setup(void **state) {
atomic_store(&ctimeouts, 0);
atomic_store(&cconnects, 0);
atomic_store(&was_error, false);
isc_nonce_buf(&send_magic, sizeof(send_magic));
isc_nonce_buf(&stop_magic, sizeof(stop_magic));
if (send_magic == stop_magic) {
@ -389,6 +402,8 @@ tls_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
if (eresult != ISC_R_SUCCESS) {
uint_fast64_t sends = atomic_load(&nsends);
atomic_store(&slowdown, true);
atomic_store(&was_error, true);
/* We failed to connect; try again */
while (sends > 0) {
@ -431,10 +446,9 @@ tls_noop(void **state) {
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
(void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
noop_connect_cb, NULL, client_tlsctx, 1, 0);
isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr, noop_connect_cb,
NULL, client_tlsctx, 1, 0);
isc_nm_closedown(connect_nm);
assert_int_equal(0, atomic_load(&cconnects));
@ -462,10 +476,9 @@ tls_noresponse(void **state) {
server_tlsctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
noop_connect_cb, NULL, client_tlsctx, 1, 0);
isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr, noop_connect_cb,
NULL, client_tlsctx, 1, 0);
isc_nm_stoplistening(listen_sock);
isc_nmsocket_close(&listen_sock);
assert_null(listen_sock);
@ -479,21 +492,23 @@ static isc_threadresult_t
tls_connect_thread(isc_threadarg_t arg) {
isc_nm_t *connect_nm = (isc_nm_t *)arg;
isc_sockaddr_t tls_connect_addr;
isc_result_t result;
tls_connect_addr = (isc_sockaddr_t){ .length = 0 };
isc_sockaddr_fromin6(&tls_connect_addr, &in6addr_loopback, 0);
while (atomic_load(&nsends) > 0) {
result = isc_nm_tlsconnect(
/*
* We need to back off and slow down if we start getting
* errors, to prevent a thundering herd problem.
*/
if (atomic_load(&slowdown)) {
usleep(1000 * workers);
atomic_store(&slowdown, false);
}
isc_nm_tlsconnect(
connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
tls_connect_connect_cb, NULL, client_tlsctx, 1, 0);
/* protection against "too many open files" */
if (result != ISC_R_SUCCESS) {
atomic_fetch_sub(&nsends, 1);
usleep(1000 * workers);
}
}
return ((isc_threadresult_t)0);
@ -518,12 +533,14 @@ tls_recv_one(void **state) {
server_tlsctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
(void)isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
tls_connect_connect_cb, NULL, client_tlsctx,
1000, 0);
isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
tls_connect_connect_cb, NULL, client_tlsctx, 1000, 0);
while (atomic_load(&nsends) > 0) {
if (atomic_load(&was_error)) {
break;
}
isc_thread_yield();
}
@ -531,6 +548,9 @@ tls_recv_one(void **state) {
atomic_load(&sreads) != 1 || atomic_load(&creads) != 0 ||
atomic_load(&csends) != 1)
{
if (atomic_load(&was_error)) {
break;
}
isc_thread_yield();
}
@ -573,19 +593,24 @@ tls_recv_two(void **state) {
server_tlsctx, &listen_sock);
assert_int_equal(result, ISC_R_SUCCESS);
result = isc_nm_tlsconnect(
connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr, tls_connect_connect_cb, NULL,
client_tlsctx, 100000, 0);
assert_int_equal(result, ISC_R_SUCCESS);
isc_nm_tlsconnect(connect_nm, (isc_nmiface_t *)&tls_connect_addr,
(isc_nmiface_t *)&tls_listen_addr,
tls_connect_connect_cb, NULL, client_tlsctx, 100000,
0);
while (atomic_load(&nsends) > 0) {
if (atomic_load(&was_error)) {
break;
}
isc_thread_yield();
}
while (atomic_load(&sreads) < 2 || atomic_load(&ssends) < 1 ||
atomic_load(&csends) < 2 || atomic_load(&creads) < 1)
{
if (atomic_load(&was_error)) {
break;
}
isc_thread_yield();
}
@ -619,10 +644,7 @@ tls_recv_send(void **state) {
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
SKIP_IN_CI;
result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr,
tls_listen_accept_cb, NULL, 0, 0, NULL,
@ -665,10 +687,7 @@ tls_recv_half_send(void **state) {
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
SKIP_IN_CI;
result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr,
tls_listen_accept_cb, NULL, 0, 0, NULL,
@ -716,10 +735,7 @@ tls_half_recv_send(void **state) {
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
SKIP_IN_CI;
result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr,
tls_listen_accept_cb, NULL, 0, 0, NULL,
@ -767,10 +783,7 @@ tls_half_recv_half_send(void **state) {
size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
isc_thread_t threads[32] = { 0 };
if (!reuse_supported) {
skip();
return;
}
SKIP_IN_CI;
result = isc_nm_listentls(listen_nm, (isc_nmiface_t *)&tls_listen_addr,
tls_listen_accept_cb, NULL, 0, 0, NULL,

View file

@ -111,7 +111,9 @@ __wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
return (atomic_load(&__state_uv_udp_bind));
}
static atomic_int __state_uv_udp_connect = ATOMIC_VAR_INIT(0);
static atomic_int __state_uv_udp_connect
__attribute__((unused)) = ATOMIC_VAR_INIT(0);
#if HAVE_UV_UDP_CONNECT
int
__wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
@ -122,7 +124,9 @@ __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
}
#endif /* HAVE_UV_UDP_CONNECT */
static atomic_int __state_uv_udp_getpeername = ATOMIC_VAR_INIT(0);
static atomic_int __state_uv_udp_getpeername
__attribute__((unused)) = ATOMIC_VAR_INIT(0);
#if HAVE_UV_UDP_CONNECT
int
__wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,