static void
maybeshutdown(void) {
/* when called from getinput, doshutdown might be already finished */
- if (requestmgr == NULL)
+ if (requestmgr == NULL) {
return;
+ }
ddebug("Shutting down request manager");
dns_requestmgr_shutdown(requestmgr);
/* locked by buffer_lock */
dns_qid_t *qid;
- isc_mutex_t buffer_lock;
- unsigned int buffers;
in_port_t *v4ports; /*%< available ports for IPv4 */
unsigned int nv4ports; /*%< # of available ports for IPv4 */
isc_sockaddr_t peer;
in_port_t port;
dns_messageid_t id;
- isc_nm_cb_t connected;
- isc_nm_cb_t sent;
- isc_nm_recv_cb_t response;
- isc_nm_cb_t timedout;
+ dispatch_cb_t connected;
+ dispatch_cb_t sent;
+ dispatch_cb_t response;
void *arg;
bool canceled;
ISC_LINK(dns_dispentry_t) link;
isc_sockaddr_t peer;
isc_netaddr_t netaddr;
int match;
- isc_nm_recv_cb_t response = NULL;
+ dispatch_cb_t response = NULL;
bool nomore = true;
REQUIRE(VALID_RESPONSE(resp));
LOCK(&disp->lock);
if (isc_log_wouldlog(dns_lctx, LVL(90))) {
- LOCK(&disp->mgr->buffer_lock);
- dispatch_log(disp, LVL(90), "got packet: requests %d",
+ dispatch_log(disp, LVL(90), "got UDP packet: requests %d",
disp->requests);
- UNLOCK(&disp->mgr->buffer_lock);
}
if (eresult == ISC_R_CANCELED) {
peer = isc_nmhandle_peeraddr(handle);
isc_netaddr_fromsockaddr(&netaddr, &peer);
- if (eresult == ISC_R_TIMEDOUT && resp->timedout != NULL) {
- resp->timedout(handle, ISC_R_TIMEDOUT, resp->arg);
- if (isc_nmhandle_timer_running(handle)) {
- nomore = false;
- goto unlock;
- }
- }
+ /* if (eresult == ISC_R_TIMEDOUT && resp->timedout != NULL) { */
+ /* resp->timedout(handle, ISC_R_TIMEDOUT, resp->arg); */
+ /* if (isc_nmhandle_timer_running(handle)) { */
+ /* nomore = false; */
+ /* goto unlock; */
+ /* } */
+ /* } */
if (eresult != ISC_R_SUCCESS) {
/*
UNLOCK(&disp->lock);
if (response != NULL) {
- response(handle, eresult, region, resp->arg);
+ response(eresult, region, resp->arg);
}
if (nomore) {
dispentry_detach(&resp0);
if (resp != NULL) {
- resp->response(handle, eresult, region, resp->arg);
+ resp->response(eresult, region, resp->arg);
}
}
isc_nm_attach(nm, &mgr->nm);
isc_mutex_init(&mgr->lock);
- isc_mutex_init(&mgr->buffer_lock);
ISC_LIST_INIT(mgr->list);
qid_destroy(mgr->mctx, &mgr->qid);
- isc_mutex_destroy(&mgr->buffer_lock);
-
if (mgr->blackhole != NULL) {
dns_acl_detach(&mgr->blackhole);
}
isc_result_t
dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
unsigned int timeout, const isc_sockaddr_t *dest,
- isc_nm_cb_t connected, isc_nm_cb_t sent,
- isc_nm_recv_cb_t response, isc_nm_cb_t timedout,
- void *arg, dns_messageid_t *idp,
- dns_dispentry_t **resp) {
+ dispatch_cb_t connected, dispatch_cb_t sent,
+ dispatch_cb_t response, void *arg,
+ dns_messageid_t *idp, dns_dispentry_t **resp) {
dns_dispentry_t *res = NULL;
dns_qid_t *qid = NULL;
in_port_t localport = 0;
unsigned int bucket;
bool ok = false;
int i = 0;
- isc_nm_recv_cb_t oldest_response = NULL;
+ dispatch_cb_t oldest_response = NULL;
REQUIRE(VALID_DISPATCH(disp));
REQUIRE(dest != NULL);
.peer = *dest,
.connected = connected,
.sent = sent,
- .timedout = timedout,
.response = response,
.arg = arg };
UNLOCK(&disp->lock);
if (oldest_response != NULL) {
- oldest_response(res->handle, ISC_R_CANCELED, NULL, res->arg);
+ oldest_response(ISC_R_CANCELED, NULL, res->arg);
}
*idp = id;
}
if (resp->connected != NULL) {
- resp->connected(handle, eresult, resp->arg);
+ resp->connected(eresult, NULL, resp->arg);
}
detach:
REQUIRE(VALID_RESPONSE(resp));
- resp->sent(handle, result, resp->arg);
+ resp->sent(result, NULL, resp->arg);
if (result != ISC_R_SUCCESS) {
isc_nm_cancelread(handle);
dispentry_detach(&resp);
}
+void
+dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout) {
+ REQUIRE(resp != NULL);
+
+ dns_dispatch_t *disp = resp->disp;
+ isc_nmhandle_t *handle = NULL;
+
+ switch (disp->socktype) {
+ case isc_socktype_udp:
+ REQUIRE(resp->handle != NULL);
+
+ handle = resp->handle;
+
+ break;
+ case isc_socktype_tcp:
+ REQUIRE(disp != NULL && disp->handle == NULL);
+
+ handle = disp->handle;
+ break;
+ default:
+ INSIST(0);
+ ISC_UNREACHABLE();
+ }
+
+ isc_nmhandle_settimeout(handle, timeout);
+ startrecv(disp, resp);
+}
+
void
dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
isc_nmhandle_t *handle = NULL;
*\li 'resp' is valid.
*/
+void
+dns_dispatch_read(dns_dispentry_t *resp, uint16_t timeout);
+
isc_result_t
dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
const isc_sockaddr_t *localaddr, bool *connected,
* if connected == NULL).
*/
+typedef void (*dispatch_cb_t)(isc_result_t eresult, isc_region_t *region,
+ void *cbarg);
+
isc_result_t
dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options,
unsigned int timeout, const isc_sockaddr_t *dest,
- isc_nm_cb_t connected, isc_nm_cb_t sent,
- isc_nm_recv_cb_t response, isc_nm_cb_t timedout,
- void *arg, dns_messageid_t *idp,
- dns_dispentry_t **resp);
+ dispatch_cb_t connected, dispatch_cb_t sent,
+ dispatch_cb_t response, void *arg,
+ dns_messageid_t *idp, dns_dispentry_t **resp);
/*%<
* Add a response entry for this dispatch.
*
req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options,
isc_mem_t *mctx);
static void
-req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
- void *arg);
+req_response(isc_result_t result, isc_region_t *region, void *arg);
static void
-req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
+req_senddone(isc_result_t eresult, isc_region_t *region, void *arg);
static void
req_sendevent(dns_request_t *request, isc_result_t result);
static void
-req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
-static void
-req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
+req_connected(isc_result_t eresult, isc_region_t *region, void *arg);
static void
req_attach(dns_request_t *source, dns_request_t **targetp);
static void
req_attach(request, &rclone);
result = dns_dispatch_addresponse(
request->dispatch, dispopt, request->timeout, destaddr,
- req_connected, req_senddone, req_response, req_timeout, request,
- &id, &request->dispentry);
+ req_connected, req_senddone, req_response, request, &id,
+ &request->dispentry);
if (result != ISC_R_SUCCESS) {
if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
newtcp = true;
req_attach(request, &rclone);
result = dns_dispatch_addresponse(
request->dispatch, 0, request->timeout, destaddr, req_connected,
- req_senddone, req_response, req_timeout, request, &id,
- &request->dispentry);
+ req_senddone, req_response, request, &id, &request->dispentry);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
*** Private: request.
***/
static void
-req_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
+req_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
dns_request_t *request = (dns_request_t *)arg;
- UNUSED(handle);
+ UNUSED(region);
req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request,
isc_result_totext(eresult));
}
static void
-req_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
+req_senddone(isc_result_t eresult, isc_region_t *region, void *arg) {
dns_request_t *request = (dns_request_t *)arg;
REQUIRE(VALID_REQUEST(request));
REQUIRE(DNS_REQUEST_SENDING(request));
- UNUSED(handle);
+ UNUSED(region);
req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
}
static void
-req_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
+req_response(isc_result_t result, isc_region_t *region, void *arg) {
dns_request_t *request = (dns_request_t *)arg;
- REQUIRE(VALID_REQUEST(request));
-
- UNUSED(eresult);
-
- req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
-
- LOCK(&request->requestmgr->locks[request->hash]);
- if (--request->udpcount != 0) {
- isc_nmhandle_settimeout(handle, request->timeout);
- if (!DNS_REQUEST_SENDING(request)) {
- req_send(request);
- }
+ if (result == ISC_R_CANCELED) {
+ return;
}
- UNLOCK(&request->requestmgr->locks[request->hash]);
-}
-static void
-req_response(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
- void *arg) {
- dns_request_t *request = (dns_request_t *)arg;
+ if (result == ISC_R_TIMEDOUT) {
+ req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
- UNUSED(handle);
+ LOCK(&request->requestmgr->locks[request->hash]);
+ if (--request->udpcount != 0) {
+ dns_dispatch_read(request->dispentry, request->timeout);
+ if (!DNS_REQUEST_SENDING(request)) {
+ req_send(request);
+ }
+ UNLOCK(&request->requestmgr->locks[request->hash]);
+ return;
+ }
- if (result == ISC_R_CANCELED) {
- return;
+ /* The lock is unlocked below */
+ goto done;
}
REQUIRE(VALID_REQUEST(request));
dns_result_totext(result));
LOCK(&request->requestmgr->locks[request->hash]);
+
if (result != ISC_R_SUCCESS) {
goto done;
}
static isc_result_t
resquery_send(resquery_t *query);
static void
-resquery_response(isc_nmhandle_t *handle, isc_result_t eresult,
- isc_region_t *region, void *arg);
+resquery_response(isc_result_t eresult, isc_region_t *region, void *arg);
static void
-resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg);
+resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg);
static void
fctx_try(fetchctx_t *fctx, bool retrying, bool badcache);
static isc_result_t
}
/*
- * Check for any outstanding socket events. If they exist,
- * cancel them and let the event handlers finish the cleanup.
- * (XXX: Currently the resolver, rather than dispatch, tracks
- * whether it's sending or connecting; this will be moved into
- * dispatch later.)
+ * Check for any outstanding dispatch responses. If they exist,
+ * cancel them and let their callbacks finish the cleanup.
*/
if (query->dispentry != NULL) {
dns_dispatch_cancel(query->dispentry);
ISC_LIST_UNLINK(fctx->queries, query, link);
}
- /* This is the final detach matching the "init" */
resquery_detach(&query);
}
}
}
-static inline void
-fctx_stopqueries(fetchctx_t *fctx, bool no_response, bool age_untried) {
- FCTXTRACE("stopqueries");
- fctx_cancelqueries(fctx, no_response, age_untried);
-}
-
static inline void
fctx_cleanupall(fetchctx_t *fctx) {
fctx_cleanupfinds(fctx);
fctx->qmin_warning = ISC_R_SUCCESS;
- fctx_stopqueries(fctx, no_response, age_untried);
+ fctx_cancelqueries(fctx, no_response, age_untried);
LOCK(&res->buckets[fctx->bucketnum].lock);
}
static void
-resquery_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
+resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) {
resquery_t *query = (resquery_t *)arg;
fetchctx_t *fctx = NULL;
QTRACE("senddone");
- UNUSED(handle);
+ UNUSED(region);
fctx = query->fctx;
}
detach:
- resquery_detach(&query); /* Detach dispatch query */
+ resquery_detach(&query);
}
static inline isc_result_t
isc_time_nowplusinterval(&fctx->next_timeout, &fctx->interval);
}
-static void
-resquery_timeout(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
- resquery_t *query = (resquery_t *)arg;
+static isc_result_t
+resquery_timeout(resquery_t *query) {
fetchctx_t *fctx = query->fctx;
dns_fetchevent_t *event = NULL, *next = NULL;
uint64_t timeleft;
isc_time_t now;
- REQUIRE(VALID_FCTX(fctx));
-
FCTXTRACE("timeout");
/*
* If not configured for serve-stale, do nothing.
*/
- if (eresult == ISC_R_CANCELED ||
- (fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0)
- {
- return;
+ if ((fctx->options & DNS_FETCHOPT_TRYSTALE_ONTIMEOUT) == 0) {
+ return (ISC_R_SUCCESS);
}
/*
isc_time_now(&now);
timeleft = isc_time_microdiff(&fctx->expires_try_stale, &now);
if (timeleft >= US_PER_MSEC) {
- return;
+ return (ISC_R_SUCCESS);
}
/*
* resume waiting.
*/
timeleft = isc_time_microdiff(&fctx->next_timeout, &now);
- if (timeleft < US_PER_MSEC) {
- isc_nmhandle_settimeout(handle, (timeleft / US_PER_MSEC));
+ if (timeleft >= US_PER_MSEC) {
+ dns_dispatch_read(query->dispentry, (timeleft / US_PER_MSEC));
+ return (ISC_R_COMPLETE);
}
+
+ return (ISC_R_SUCCESS);
}
static isc_result_t
result = dns_dispatch_addresponse(
query->dispatch, 0, isc_interval_ms(&fctx->interval),
&query->addrinfo->sockaddr, resquery_connected,
- resquery_senddone, resquery_response, resquery_timeout, query,
- &query->id, &query->dispentry);
+ resquery_senddone, resquery_response, query, &query->id,
+ &query->dispentry);
if (result != ISC_R_SUCCESS) {
goto cleanup_dispatch;
}
/* Connect the socket */
- resquery_attach(query, &(resquery_t *){ NULL }); /* dispatch query */
+ resquery_attach(query, &(resquery_t *){ NULL });
result = dns_dispatch_connect(query->dispentry);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
static void
-resquery_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
+resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
resquery_t *query = (resquery_t *)arg;
isc_result_t result;
fetchctx_t *fctx = NULL;
QTRACE("connected");
- UNUSED(handle);
+ UNUSED(region);
fctx = query->fctx;
res = fctx->res;
}
detach:
- resquery_detach(&query); /* Detach dispatch query */
+ resquery_detach(&query);
}
static void
* fetch, and clean up finds and addresses. To avoid deadlock
* with the ADB, we must do this before we lock the bucket lock.
*/
- fctx_stopqueries(fctx, false, false);
+ fctx_cancelqueries(fctx, false, false);
fctx_cleanupall(fctx);
LOCK(&res->buckets[bucketnum].lock);
* resquery_send(). Sets up a response context (respctx_t).
*/
static void
-resquery_response(isc_nmhandle_t *handle, isc_result_t eresult,
- isc_region_t *region, void *arg) {
+resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
isc_result_t result;
resquery_t *query = (resquery_t *)arg;
fetchctx_t *fctx = NULL;
respctx_t rctx;
- UNUSED(handle);
-
if (eresult == ISC_R_CANCELED) {
return;
}
QTRACE("response");
+ if (eresult == ISC_R_TIMEDOUT) {
+ result = resquery_timeout(query);
+ if (result == ISC_R_COMPLETE) {
+ return;
+ }
+ }
+
if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) {
inc_stats(fctx->res, dns_resstatscounter_responsev4);
} else {