refactor dns_client to use loop callbacks

dns_client now uses isc_async_run() internally to post
client-resume events. (a task is still used for
dns_resolver_createfetch(), however.)
This commit is contained in:
Evan Hunt
2022-10-27 11:45:33 -07:00
committed by Ondřej Surý
parent 83593167cd
commit bba46be63d
2 changed files with 52 additions and 63 deletions

View File

@@ -14,6 +14,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <isc/async.h>
#include <isc/buffer.h>
#include <isc/md.h>
#include <isc/mem.h>
@@ -75,10 +76,9 @@ struct dns_client {
unsigned int magic;
unsigned int attributes;
isc_mem_t *mctx;
isc_taskmgr_t *taskmgr;
isc_task_t *task;
isc_loop_t *loop;
isc_nm_t *nm;
isc_loopmgr_t *loopmgr;
dns_dispatchmgr_t *dispatchmgr;
dns_dispatch_t *dispatchv4;
dns_dispatch_t *dispatchv6;
@@ -107,7 +107,6 @@ typedef struct resctx {
bool want_tcp;
ISC_LINK(struct resctx) link;
isc_task_t *task;
dns_view_t *view;
unsigned int restarts;
dns_fixedname_t name;
@@ -115,7 +114,7 @@ typedef struct resctx {
dns_fetch_t *fetch;
dns_namelist_t namelist;
isc_result_t result;
dns_clientresume_t *event;
dns_clientresume_t *rev;
dns_rdataset_t *rdataset;
dns_rdataset_t *sigrdataset;
} resctx_t;
@@ -265,12 +264,11 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
client = isc_mem_get(mctx, sizeof(*client));
*client = (dns_client_t){
.taskmgr = taskmgr,
.loopmgr = loopmgr,
.loop = isc_loop_get(loopmgr, 0),
.nm = nm,
};
result = isc_task_create(client->taskmgr, &client->task, 0);
result = isc_task_create(taskmgr, &client->task, 0);
if (result != ISC_R_SUCCESS) {
goto cleanup_lock;
}
@@ -465,9 +463,8 @@ fetch_done(isc_task_t *task, isc_event_t *event) {
resctx_t *rctx = event->ev_arg;
dns_fetchevent_t *fevent;
REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
REQUIRE(RCTX_VALID(rctx));
REQUIRE(rctx->task == task);
REQUIRE(rctx->client->task == task);
fevent = (dns_fetchevent_t *)event;
client_resfind(rctx, fevent);
@@ -497,8 +494,8 @@ start_fetch(resctx_t *rctx) {
result = dns_resolver_createfetch(
rctx->view->resolver, dns_fixedname_name(&rctx->name),
rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
&rctx->fetch);
rctx->client->task, fetch_done, rctx, rctx->rdataset,
rctx->sigrdataset, &rctx->fetch);
return (result);
}
@@ -860,30 +857,24 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
} while (want_restart);
if (send_event) {
isc_task_t *task;
while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
ISC_LIST_UNLINK(rctx->namelist, name, link);
ISC_LIST_APPEND(rctx->event->answerlist, name, link);
ISC_LIST_APPEND(rctx->rev->answerlist, name, link);
}
rctx->event->result = result;
rctx->event->vresult = vresult;
task = rctx->event->ev_sender;
rctx->event->ev_sender = rctx;
isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
rctx->rev->result = result;
rctx->rev->vresult = vresult;
isc_async_run(rctx->client->loop, rctx->rev->cb, rctx->rev);
}
}
static void
resolve_done(isc_task_t *task, isc_event_t *event) {
resarg_t *resarg = event->ev_arg;
dns_clientresume_t *rev = (dns_clientresume_t *)event;
resolve_done(void *arg) {
dns_clientresume_t *rev = (dns_clientresume_t *)arg;
resarg_t *resarg = rev->arg;
dns_name_t *name = NULL;
isc_result_t result;
UNUSED(task);
resarg->result = rev->result;
resarg->vresult = rev->vresult;
while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
@@ -891,8 +882,7 @@ resolve_done(isc_task_t *task, isc_event_t *event) {
ISC_LIST_APPEND(*resarg->namelist, name, link);
}
isc_event_free(&event);
isc_mem_put(resarg->mctx, rev, sizeof(*rev));
destroyrestrans(&resarg->trans);
result = resarg->result;
@@ -939,8 +929,7 @@ dns_client_resolve(dns_client_t *client, const dns_name_t *name,
isc_mem_attach(client->mctx, &resarg->mctx);
result = dns_client_startresolve(client, name, rdclass, type, options,
client->task, resolve_done, resarg,
&resarg->trans);
resolve_done, resarg, &resarg->trans);
if (result != ISC_R_SUCCESS) {
isc_mem_put(client->mctx, resarg, sizeof(*resarg));
return (result);
@@ -952,15 +941,13 @@ dns_client_resolve(dns_client_t *client, const dns_name_t *name,
isc_result_t
dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int options, isc_task_t *task,
isc_taskaction_t action, void *arg,
unsigned int options, isc_job_cb cb, void *arg,
dns_clientrestrans_t **transp) {
dns_clientresume_t *event = NULL;
dns_clientresume_t *rev = NULL;
resctx_t *rctx = NULL;
isc_task_t *tclone = NULL;
isc_mem_t *mctx;
isc_mem_t *mctx = NULL;
isc_result_t result;
dns_rdataset_t *rdataset, *sigrdataset;
dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
bool want_dnssec, want_validation, want_cdflag, want_tcp;
REQUIRE(DNS_CLIENT_VALID(client));
@@ -968,8 +955,6 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
REQUIRE(rdclass == dns_rdataclass_in);
mctx = client->mctx;
rdataset = NULL;
sigrdataset = NULL;
want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
@@ -978,24 +963,25 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
/*
* Prepare some intermediate resources
*/
tclone = NULL;
isc_task_attach(task, &tclone);
event = (dns_clientresume_t *)isc_event_allocate(
mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg,
sizeof(*event));
event->result = DNS_R_SERVFAIL;
ISC_LIST_INIT(event->answerlist);
rev = isc_mem_get(mctx, sizeof(*rev));
*rev = (dns_clientresume_t){
.result = DNS_R_SERVFAIL,
.answerlist = ISC_LIST_INITIALIZER,
.cb = cb,
.arg = arg,
};
rctx = isc_mem_get(mctx, sizeof(*rctx));
*rctx = (resctx_t){
.client = client,
.task = client->task,
.event = event,
.rev = rev,
.type = type,
.want_dnssec = want_dnssec,
.want_validation = want_validation,
.want_cdflag = want_cdflag,
.want_tcp = want_tcp,
.namelist = ISC_LIST_INITIALIZER,
.link = ISC_LINK_INITIALIZER,
};
result = getrdataset(mctx, &rdataset);
@@ -1015,9 +1001,7 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
dns_fixedname_init(&rctx->name);
dns_name_copy(name, dns_fixedname_name(&rctx->name));
ISC_LINK_INIT(rctx, link);
dns_view_attach(client->view, &rctx->view);
ISC_LIST_INIT(rctx->namelist);
rctx->magic = RCTX_MAGIC;
isc_refcount_increment(&client->references);
@@ -1037,8 +1021,7 @@ cleanup:
putrdataset(client->mctx, &sigrdataset);
}
isc_mem_put(mctx, rctx, sizeof(*rctx));
isc_event_free(ISC_EVENT_PTR(&event));
isc_task_detach(&tclone);
isc_mem_put(mctx, rev, sizeof(*rev));
return (result);
}
@@ -1081,7 +1064,6 @@ destroyrestrans(dns_clientrestrans_t **transp) {
REQUIRE(RCTX_VALID(rctx));
REQUIRE(rctx->fetch == NULL);
REQUIRE(rctx->event == NULL);
client = rctx->client;

View File

@@ -40,6 +40,7 @@
*/
#include <isc/event.h>
#include <isc/loop.h>
#include <isc/sockaddr.h>
#include <dns/tsig.h>
@@ -73,19 +74,26 @@ ISC_LANG_BEGINDECLS
#define DNS_CLIENTVIEW_NAME "_dnsclient"
/*%
* A dns_clientresume_t is sent when name resolution performed by a client
* completes. 'result' stores the result code of the entire resolution
* A dns_clientresume_t holds state for resolution performed by a client,
* and is sent to the callback when the resolution completes.
* 'result' stores the result code of the entire resolution
* procedure. 'vresult' specifically stores the result code of DNSSEC
* validation if it is performed. When name resolution successfully completes,
* 'answerlist' is typically non empty, containing answer names along with
* RRsets. It is the receiver's responsibility to free this list by calling
* dns_client_freeresanswer() before freeing the event structure.
* RRsets. 'cb' is the callback function and 'arg' is the callback argument
* that was specified by the caller.
*
* It is the receiver's responsibility to free 'answerlist' by
* calling dns_client_freeresanswer(), and to free the dns_clientresume
* structure itself.
*/
typedef struct dns_clientresume {
ISC_EVENT_COMMON(struct dns_clientresume);
isc_mem_t *mctx;
isc_result_t result;
isc_result_t vresult;
dns_namelist_t answerlist;
isc_job_cb cb;
void *arg;
} dns_clientresume_t; /* too long? */
isc_result_t
@@ -110,6 +118,8 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
*
*\li 'mctx' is a valid memory context.
*
*\li 'loopmgr' is a valid loop manager.
*\li 'taskmgr' is a valid task manager.
*
*\li 'nm' is a valid network manager.
@@ -202,8 +212,7 @@ dns_client_resolve(dns_client_t *client, const dns_name_t *name,
isc_result_t
dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int options, isc_task_t *task,
isc_taskaction_t action, void *arg,
unsigned int options, isc_job_cb cb, void *arg,
dns_clientrestrans_t **transp);
/*%<
* Perform name resolution for 'name', 'rdclass', and 'type'.
@@ -231,11 +240,11 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
* created via dns_client_create() and has external managers and contexts.
*
* dns_client_startresolve() is an asynchronous version of dns_client_resolve()
* and does not block. When name resolution is completed, 'action' will be
* and does not block. When name resolution is completed, 'cb' will be
* called with the argument of a 'dns_clientresume_t' object, which contains
* the resulting list of answer names (on success). On return, '*transp' is
* set to an opaque transaction ID so that the caller can cancel this
* resolution process.
* the resulting list of answer names (on success), and a also contains
* a pointer to 'arg'. On return, '*transp' is set to an opaque transaction
* ID so that the caller can cancel this resolution process.
*
* Requires:
*
@@ -247,8 +256,6 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
*
*\li 'namelist' != NULL and is not empty.
*
*\li 'task' is a valid task.
*
*\li 'transp' != NULL && *transp == NULL;
*
* Returns: