}
static void
-fctx_cancelquery(resquery_t *query, isc_time_t *finish, bool no_response,
+fctx_cancelquery(resquery_t **queryp, isc_time_t *finish, bool no_response,
bool age_untried) {
+ resquery_t *query = NULL;
fetchctx_t *fctx = NULL;
unsigned int rtt, rttms;
unsigned int factor;
dns_adbaddrinfo_t *addrinfo;
isc_stdtime_t now;
+ REQUIRE(queryp != NULL);
+
+ query = *queryp;
fctx = query->fctx;
FCTXTRACE("cancelquery");
ISC_LIST_UNLINK(fctx->queries, query, link);
}
- resquery_detach(&query);
+ resquery_detach(queryp);
}
static void
for (query = ISC_LIST_HEAD(fctx->queries); query != NULL;
query = next_query) {
next_query = ISC_LIST_NEXT(query, link);
- fctx_cancelquery(query, NULL, no_response, age_untried);
+ fctx_cancelquery(&query, NULL, no_response, age_untried);
}
}
static void
resquery_senddone(isc_result_t eresult, isc_region_t *region, void *arg) {
resquery_t *query = (resquery_t *)arg;
+ resquery_t *copy = query;
fetchctx_t *fctx = NULL;
QTRACE("senddone");
goto detach;
}
+ /*
+ * See the note in resquery_connected() about reference
+ * counting on error conditions.
+ */
switch (eresult) {
case ISC_R_SUCCESS:
case ISC_R_CANCELED:
case ISC_R_NOPERM:
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNREFUSED:
+ /* No route to remote. */
FCTXTRACE3("query canceled in resquery_senddone(): "
"no route to host; no response",
eresult);
-
- /*
- * No route to remote.
- */
add_bad(fctx, query->rmessage, query->addrinfo, eresult,
badns_unreachable);
- fctx_cancelquery(query, NULL, true, false);
-
+ fctx_cancelquery(©, NULL, true, false);
FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT);
fctx_try(fctx, true, false);
break;
FCTXTRACE3("query canceled in resquery_senddone() "
"due to unexpected result; responding",
eresult);
- fctx_cancelquery(query, NULL, false, false);
+ fctx_cancelquery(©, NULL, false, false);
fctx_done(fctx, eresult, __LINE__);
break;
}
static void
resquery_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
resquery_t *query = (resquery_t *)arg;
+ resquery_t *copy = query;
isc_result_t result;
fetchctx_t *fctx = NULL;
dns_resolver_t *res = NULL;
eresult = ISC_R_SHUTTINGDOWN;
}
+ /*
+ * The reference counting of resquery objects is complex:
+ *
+ * 1. attached in fctx_query()
+ * 2. attached prior to dns_dispatch_connect(), detached in
+ * resquery_connected()
+ * 3. attached prior to dns_dispatch_send(), detached in
+ * resquery_senddone()
+ * 4. finally detached in fctx_cancelquery()
+ *
+ * On error conditions, it's necessary to call fctx_cancelquery()
+ * from resquery_connected() or _senddone(), detaching twice
+ * within the same function. To make it clear that's what's
+ * happening, we cancel-and-detach 'copy' and detach 'query',
+ * which are both pointing to the same object.
+ */
switch (eresult) {
case ISC_R_SUCCESS:
/*
FCTXTRACE("query canceled: resquery_send() failed; "
"responding");
- fctx_cancelquery(query, NULL, false, false);
+ fctx_cancelquery(©, NULL, false, false);
fctx_done(fctx, result, __LINE__);
break;
}
break;
case ISC_R_CANCELED:
- break;
-
case ISC_R_SHUTTINGDOWN:
- FCTXTRACE3("shutdown in resquery_connected(): no response",
- eresult);
- fctx_cancelquery(query, NULL, true, false);
+ FCTXTRACE3("shutdown in resquery_connected()", eresult);
+ fctx_cancelquery(©, NULL, true, false);
fctx_done(fctx, eresult, __LINE__);
break;
case ISC_R_ADDRNOTAVAIL:
case ISC_R_CONNECTIONRESET:
case ISC_R_TIMEDOUT:
- FCTXTRACE3("query canceled in "
- "resquery_connected(): "
- "no route to host; no response",
- eresult);
-
/*
- * Do not query this server again in this fetch
- * context if the server is unavailable over
- * TCP.
+ * Do not query this server again in this fetch context.
*/
+ FCTXTRACE3("query failed in resquery_connected(): "
+ "no response",
+ eresult);
add_bad(fctx, query->rmessage, query->addrinfo, eresult,
badns_unreachable);
- fctx_cancelquery(query, NULL, true, false);
+ fctx_cancelquery(©, NULL, true, false);
FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT);
fctx_try(fctx, true, false);
break;
default:
- FCTXTRACE3("query canceled in "
- "resquery_connected() "
+ FCTXTRACE3("query canceled in resquery_connected() "
"due to unexpected result; responding",
eresult);
- fctx_cancelquery(query, NULL, false, false);
+ fctx_cancelquery(©, NULL, false, false);
fctx_done(fctx, eresult, __LINE__);
break;
}
if (dns_fuzzing_resolver &&
(rctx->next_server || rctx->resend || rctx->nextitem))
{
- fctx_cancelquery(query, rctx->finish, rctx->no_response, false);
+ fctx_cancelquery(&query, rctx->finish, rctx->no_response,
+ false);
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
goto detach;
}
}
/* Cancel the query */
- fctx_cancelquery(query, rctx->finish, rctx->no_response, false);
+ fctx_cancelquery(&query, rctx->finish, rctx->no_response, false);
/*
* If nobody's waiting for results, don't resend.