dns_dispatchstate_t state;
dns_dispatchtype_t disptype;
+ dns_messageid_t nextid; /*%< next sequential QID for TCP */
+
bool reading;
dns_displist_t pending;
return ISC_R_NOTFOUND;
}
-/*
- * NOTE: Must be RCU read locked!
- */
static isc_result_t
tcp_recv_success(dns_dispatch_t *disp, isc_region_t *region,
- isc_sockaddr_t *peer, dns_dispentry_t **respp) {
+ dns_dispentry_t **respp) {
isc_buffer_t source;
dns_messageid_t id;
unsigned int flags;
}
/*
- * We have a valid response; find the associated dispentry object
- * and call the caller back.
+ * We have a valid response; find the associated dispentry by
+ * scanning disp->active. With sequential IDs and a bounded
+ * pipelining limit this is a short linear scan.
*/
- dns_dispentry_t key = {
- .id = id,
- .peer = *peer,
- .port = isc_sockaddr_getport(&disp->local),
- };
- struct cds_lfht_iter iter;
- cds_lfht_lookup(disp->mgr->qids, qid_hash(&key), qid_match, &key,
- &iter);
-
- dns_dispentry_t *resp = cds_lfht_entry(cds_lfht_iter_get_node(&iter),
- dns_dispentry_t, ht_node);
-
- /* Skip responses that are not ours */
- if (resp != NULL && resp->disp == disp) {
- if (!resp->reading) {
- /*
- * We already got a message for this QID and weren't
- * expecting any more.
- */
- result = ISC_R_UNEXPECTED;
- } else {
- *respp = resp;
+ dns_dispentry_t *resp = NULL;
+ ISC_LIST_FOREACH(disp->active, r, alink) {
+ if (r->id == id) {
+ resp = r;
+ break;
}
+ }
+
+ if (resp != NULL) {
+ *respp = resp;
} else {
result = ISC_R_NOTFOUND;
}
- dispatch_log(disp, ISC_LOG_DEBUG(90),
- "search for response in hashtable: %s",
+ dispatch_log(disp, ISC_LOG_DEBUG(90), "search for response: %s",
isc_result_totext(result));
return result;
break;
case ISC_R_SUCCESS:
/* We got an answer */
- result = tcp_recv_success(disp, region, &peer, &resp);
+ result = tcp_recv_success(disp, region, &resp);
break;
default:
dispatch_allocate(mgr, isc_socktype_tcp, tid, &disp);
disp->disptype = disptype;
+ disp->nextid = isc_random16();
disp->options = options;
disp->peer = *destaddr;
if (transport != NULL) {
}
isc_result_t result = ISC_R_NOMORE;
- size_t i = 0;
rcu_read_lock();
- do {
+
+ if (disp->socktype == isc_socktype_tcp) {
/*
- * Try somewhat hard to find a unique ID. Start with
- * a random number unless DNS_DISPATCHOPT_FIXEDID is set,
- * in which case we start with the ID passed in via *idp.
+ * TCP dispentries don't use the global QID hash table.
+ * Responses are matched by scanning disp->active, and
+ * sequential per-dispatch IDs (bounded by the pipelining
+ * limit) are guaranteed to be unique within the dispatch.
+ * FIXEDID TCP dispatches are always fresh and isolated
+ * (see dns_dispatch_createtcp), so the caller-supplied ID
+ * can't collide either.
*/
resp->id = ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
? *idp
- : (dns_messageid_t)isc_random16();
-
- struct cds_lfht_node *node =
- cds_lfht_add_unique(disp->mgr->qids, qid_hash(resp),
- qid_match, resp, &resp->ht_node);
-
- if (node != &resp->ht_node) {
- if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) {
- /*
- * When using fixed ID, we either must
- * use it or fail
- */
- goto fail;
+ : disp->nextid++;
+ result = ISC_R_SUCCESS;
+ } else {
+ size_t i = 0;
+ do {
+ /*
+ * Try somewhat hard to find a unique random ID
+ * (or use the fixed ID if DNS_DISPATCHOPT_FIXEDID
+ * is set).
+ */
+ resp->id = ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
+ ? *idp
+ : (dns_messageid_t)isc_random16();
+
+ struct cds_lfht_node *node = cds_lfht_add_unique(
+ disp->mgr->qids, qid_hash(resp), qid_match,
+ resp, &resp->ht_node);
+
+ if (node != &resp->ht_node) {
+ if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) {
+ /*
+ * When using fixed ID, we either
+ * must use it or fail.
+ */
+ goto fail;
+ }
+ } else {
+ result = ISC_R_SUCCESS;
+ break;
}
- } else {
- result = ISC_R_SUCCESS;
- break;
- }
- } while (i++ < QID_MAX_TRIES);
+ } while (i++ < QID_MAX_TRIES);
+ }
fail:
if (result != ISC_R_SUCCESS) {
isc_mem_put(disp->mctx, resp, sizeof(*resp));
dec_stats(disp->mgr, dns_resstatscounter_dispreqtcp);
- (void)cds_lfht_del(disp->mgr->qids, &resp->ht_node);
-
resp->state = DNS_DISPATCHSTATE_CANCELED;
unlock:
static isc_result_t
tcp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
const isc_sockaddr_t *destaddr, dns_transport_t *transport,
- dns_dispatch_t **dispatchp) {
- return dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
- destaddr, transport,
- DNS_DISPATCHTYPE_REQUEST, 0, dispatchp);
+ unsigned int dispopt, dns_dispatch_t **dispatchp) {
+ return dns_dispatch_createtcp(
+ requestmgr->dispatchmgr, srcaddr, destaddr, transport,
+ DNS_DISPATCHTYPE_REQUEST, dispopt, dispatchp);
}
static isc_result_t
static isc_result_t
get_dispatch(bool tcp, dns_requestmgr_t *requestmgr,
const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
- dns_transport_t *transport, dns_dispatch_t **dispatchp) {
+ dns_transport_t *transport, unsigned int dispopt,
+ dns_dispatch_t **dispatchp) {
isc_result_t result;
if (tcp) {
result = tcp_dispatch(requestmgr, srcaddr, destaddr, transport,
- dispatchp);
+ dispopt, dispatchp);
} else {
result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
}
isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
CHECK(isc_buffer_copyregion(request->query, &r));
- CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
- &request->dispatch));
-
if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
id = (r.base[0] << 8) | r.base[1];
dispopt |= DNS_DISPATCHOPT_FIXEDID;
}
+ CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
+ dispopt, &request->dispatch));
+
CHECK(dns_dispatch_add(request->dispatch, loop, dispopt,
request->connect_timeout, request->timeout,
destaddr, transport, tlsctx_cache, req_connected,
CHECK(dns_message_settsigkey(message, request->tsigkey));
again:
- CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
+ CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport, 0,
&request->dispatch));
CHECK(dns_dispatch_add(request->dispatch, loop, 0,