static bool
filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp);
static ns_hook_t filter_init = {
- .callback = filter_qctx_initialize,
+ .action = filter_qctx_initialize,
};
static bool
filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp);
static ns_hook_t filter_respbegin = {
- .callback = filter_respond_begin,
+ .action = filter_respond_begin,
};
static bool
filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp);
static ns_hook_t filter_respanyfound = {
- .callback = filter_respond_any_found,
+ .action = filter_respond_any_found,
};
static bool
filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp);
static ns_hook_t filter_prepresp = {
- .callback = filter_prep_response_begin,
+ .action = filter_prep_response_begin,
};
static bool
filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp);
static ns_hook_t filter_donesend = {
- .callback = filter_query_done_send,
+ .action = filter_query_done_send,
};
static bool
filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp);
ns_hook_t filter_destroy = {
- .callback = filter_qctx_destroy,
+ .action = filter_qctx_destroy,
};
/**
typedef enum {
NS_QUERY_QCTX_INITIALIZED,
NS_QUERY_QCTX_DESTROYED,
+ NS_QUERY_SETUP,
NS_QUERY_START_BEGIN,
NS_QUERY_LOOKUP_BEGIN,
NS_QUERY_RESUME_BEGIN,
} ns_hookpoint_t;
typedef bool
-(*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp);
+(*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp);
typedef struct ns_hook {
- ns_hook_cb_t callback;
- void *callback_data;
+ ns_hook_action_t action;
+ void *action_data;
ISC_LINK(struct ns_hook) link;
} ns_hook_t;
* the future to pass back driver capabilities or other information.
*/
-/*
- * Run a hook. Calls the function or functions registered at hookpoint 'id'.
- * If one of them returns true, we interrupt processing and return the
- * result that was returned by the hook function. If none of them return
- * true, we continue processing.
- */
-#define _NS_PROCESS_HOOK(table, id, data, ...) \
- if (table != NULL) { \
- ns_hook_t *_hook = ISC_LIST_HEAD((*table)[id]); \
- isc_result_t _result; \
- \
- while (_hook != NULL) { \
- ns_hook_cb_t _callback = _hook->callback; \
- void *_callback_data = _hook->callback_data; \
- if (_callback != NULL && \
- _callback(data, _callback_data, &_result)) \
- { \
- return __VA_ARGS__; \
- } else { \
- _hook = ISC_LIST_NEXT(_hook, link); \
- } \
- } \
- }
-
-#define NS_PROCESS_HOOK(table, id, data, ...) \
- _NS_PROCESS_HOOK(table, id, data, _result)
-#define NS_PROCESS_HOOK_VOID(table, id, data, ...) \
- _NS_PROCESS_HOOK(table, id, data)
-
isc_result_t
ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp);
log_noexistnodata(void *val, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
-#define PROCESS_HOOK(_id, _qctx, ...) \
+
+/*
+ * Return the hooktable in use with 'qctx', or if there isn't one
+ * set, return the default hooktable.
+ */
+static inline ns_hooktable_t *
+get_hooktab(query_ctx_t *qctx) {
+ if (qctx == NULL || qctx->view == NULL ||
+ qctx->view->hooktable == NULL)
+ {
+ return (ns__hook_table);
+ }
+
+ return (qctx->view->hooktable);
+}
+
+/*
+ * Call the specified hook function in every configured module that
+ * implements that function. If any hook function returns 'true', we set
+ * 'result' and terminate processing by jumping to the 'cleanup' tag.
+ *
+ * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but
+ * still terminate processing within the calling function. That's why this
+ * is a macro instead of an inline function; it needs to be able to use
+ * 'goto cleanup' regardless of the return value.)
+ */
+#define PROCESS_HOOK(_id, _qctx) \
do { \
- ns_hooktable_t *_tab = ns__hook_table; \
- query_ctx_t *_q = (_qctx); \
- if (_q != NULL && \
- _q->view != NULL && \
- _q->view->hooktable != NULL) \
- { \
- _tab = _q->view->hooktable; \
+ isc_result_t _res; \
+ ns_hooktable_t *_tab = get_hooktab(_qctx); \
+ ns_hook_t *_hook; \
+ _hook = ISC_LIST_HEAD((*_tab)[_id]); \
+ while (_hook != NULL) { \
+ ns_hook_action_t _func = _hook->action; \
+ void *_data = _hook->action_data; \
+ INSIST(_func != NULL); \
+ if (_func(_qctx, _data, &_res)) { \
+ result = _res; \
+ goto cleanup; \
+ } else { \
+ _hook = ISC_LIST_NEXT(_hook, link); \
+ } \
} \
- NS_PROCESS_HOOK(_tab, _id, _q, __VA_ARGS__); \
} while (false)
-#define PROCESS_HOOK_VOID(_id, _qctx, ...) \
+/*
+ * Call the specified hook function in every configured module that
+ * implements that function. All modules are called; hook function return
+ * codes are ignored. This is intended for use with initialization and
+ * destruction calls which *must* run in every configured module.
+ *
+ * (This could be implemented as an inline void function, but is left as a
+ * macro for symmetry with PROCESS_HOOK above.)
+ */
+#define PROCESS_ALL_HOOKS(_id, _qctx) \
do { \
- ns_hooktable_t *_tab = ns__hook_table; \
- query_ctx_t *_q = (_qctx); \
- if (_q != NULL && \
- _q->view != NULL && \
- _q->view->hooktable != NULL) \
- { \
- _tab = _q->view->hooktable; \
+ isc_result_t _res; \
+ ns_hooktable_t *_tab = get_hooktab(_qctx); \
+ ns_hook_t *_hook; \
+ _hook = ISC_LIST_HEAD((*_tab)[_id]); \
+ while (_hook != NULL) { \
+ ns_hook_action_t _func = _hook->action; \
+ void *_data = _hook->action_data; \
+ INSIST(_func != NULL); \
+ _func(_qctx, _data, &_res); \
+ _hook = ISC_LIST_NEXT(_hook, link); \
} \
- NS_PROCESS_HOOK_VOID(_tab, _id, _q, __VA_ARGS__); \
} while (false)
/*
static void
query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) {
ns_client_t *client = qctx->client;
+ isc_result_t result;
CTRACE(ISC_LOG_DEBUG(3), "query_additional");
(client->query.gluedb != NULL) &&
dns_db_iszone(client->query.gluedb))
{
- isc_result_t result;
ns_dbversion_t *dbversion;
dbversion = ns_client_findversion(client, client->query.gluedb);
}
}
-regular:
+ regular:
/*
* Add other additional data if needed.
* We don't care if dns_rdataset_additionaldata() fails.
qctx->answer_has_ns = false;
qctx->authoritative = false;
- PROCESS_HOOK_VOID(NS_QUERY_QCTX_INITIALIZED, qctx);
+ PROCESS_ALL_HOOKS(NS_QUERY_QCTX_INITIALIZED, qctx);
}
/*%
static void
qctx_destroy(query_ctx_t *qctx) {
- PROCESS_HOOK_VOID(NS_QUERY_QCTX_DESTROYED, qctx);
+ PROCESS_ALL_HOOKS(NS_QUERY_QCTX_DESTROYED, qctx);
+
dns_view_detach(&qctx->view);
}
qctx_init(client, NULL, qtype, &qctx);
query_trace(&qctx);
+ PROCESS_HOOK(NS_QUERY_SETUP, &qctx);
+
/*
* If it's a SIG query, we'll iterate the node.
*/
}
result = ns__query_start(&qctx);
+
+ cleanup:
qctx_destroy(&qctx);
return (result);
}
}
return (query_lookup(qctx));
+
+ cleanup:
+ return (result);
}
/*%
}
return (query_gotanswer(qctx, result));
+
+ cleanup:
+ return (result);
}
/*
qctx->resuming = true;
return (query_gotanswer(qctx, result));
+
+ cleanup:
+ return (result);
}
/*%
* result from the search.
*/
static isc_result_t
-query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
+query_gotanswer(query_ctx_t *qctx, isc_result_t res) {
+ isc_result_t result = res;
char errmsg[256];
CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
QUERY_ERROR(qctx, result);
return (ns_query_done(qctx));
}
+
+ cleanup:
+ return (result);
}
static void
query_addauth(qctx);
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*
query_addauth(qctx);
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
static isc_result_t
}
return (query_delegation(qctx));
+
+ cleanup:
+ return (result);
}
/*%
*/
static isc_result_t
query_prepare_delegation_response(query_ctx_t *qctx) {
+ isc_result_t result;
dns_rdataset_t **sigrdatasetp = NULL;
bool detach = false;
query_addds(qctx);
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*%
}
return (query_prepare_delegation_response(qctx));
+
+ cleanup:
+ return (result);
}
/*%
}
return (query_prepare_delegation_response(qctx));
+
+ cleanup:
+ return (result);
}
/*%
* Handle authoritative NOERROR/NODATA responses.
*/
static isc_result_t
-query_nodata(query_ctx_t *qctx, isc_result_t result) {
+query_nodata(query_ctx_t *qctx, isc_result_t res) {
+ isc_result_t result = res;
+
PROCESS_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
#ifdef dns64_bis_return_excluded_addresses
}
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*%
qctx->client->message->rcode = dns_rcode_nxdomain;
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*
query_addauth(qctx);
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*
query_addauth(qctx);
return (ns_query_done(qctx));
+
+ cleanup:
+ return (result);
}
/*%
*/
static isc_result_t
query_prepresponse(query_ctx_t *qctx) {
+ isc_result_t result = ISC_R_SUCCESS;
+
PROCESS_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
if (WANTDNSSEC(qctx->client) &&
if (qctx->type == dns_rdatatype_any) {
return (query_respond_any(qctx));
- } else {
- return (query_respond(qctx));
}
+
+ return (query_respond(qctx));
+
+ cleanup:
+ return (result);
}
/*%
isc_result_t
ns_query_done(query_ctx_t *qctx) {
+ isc_result_t result;
const dns_namelist_t *secs = qctx->client->message->sections;
CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
ns_client_detach(&qctx->client);
return (qctx->result);
+
+ cleanup:
+ return (result);
}
static inline void
}
/*%
- * A hook callback which stores the query context pointed to by "hook_data" at
- * "callback_data". Causes execution to be interrupted at hook insertion
+ * A hook action which stores the query context pointed to by "arg" at
+ * "data". Causes execution to be interrupted at hook insertion
* point.
*/
static bool
-extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) {
+extract_qctx(void *arg, void *data, isc_result_t *resultp) {
query_ctx_t **qctxp;
query_ctx_t *qctx;
- REQUIRE(hook_data != NULL);
- REQUIRE(callback_data != NULL);
+ REQUIRE(arg != NULL);
+ REQUIRE(data != NULL);
REQUIRE(resultp != NULL);
/*
*/
qctx = isc_mem_get(mctx, sizeof(*qctx));
if (qctx != NULL) {
- memmove(qctx, (query_ctx_t *)hook_data, sizeof(*qctx));
+ memmove(qctx, (query_ctx_t *)arg, sizeof(*qctx));
}
- qctxp = (query_ctx_t **)callback_data;
+ qctxp = (query_ctx_t **)data;
/*
* If memory allocation failed, the supplied pointer will simply be set
* to NULL. We rely on the user of this hook to react properly.
create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) {
ns_hooktable_t *saved_hook_table, query_hooks;
ns_hook_t hook = {
- .callback = extract_qctx,
- .callback_data = qctxp,
+ .action = extract_qctx,
+ .action_data = qctxp,
};
REQUIRE(client != NULL);
*/
ns_hooktable_init(&query_hooks);
- ns_hook_add(&query_hooks, NS_QUERY_QCTX_INITIALIZED, &hook);
+ ns_hook_add(&query_hooks, NS_QUERY_SETUP, &hook);
saved_hook_table = ns__hook_table;
ns__hook_table = &query_hooks;
}
bool
-ns_test_hook_catch_call(void *hook_data, void *callback_data,
- isc_result_t *resultp)
+ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp)
{
- UNUSED(hook_data);
- UNUSED(callback_data);
+ UNUSED(arg);
+ UNUSED(data);
*resultp = ISC_R_UNSET;