mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 06:55:30 +00:00
Have the dns_client hold a .references until all external references are removed
so that cleanup can all be done in dns_client_destroy().
(cherry picked from commit e80c4c3431
)
This commit is contained in:
114
lib/dns/client.c
114
lib/dns/client.c
@@ -19,6 +19,7 @@
|
|||||||
#include <isc/mem.h>
|
#include <isc/mem.h>
|
||||||
#include <isc/mutex.h>
|
#include <isc/mutex.h>
|
||||||
#include <isc/portset.h>
|
#include <isc/portset.h>
|
||||||
|
#include <isc/refcount.h>
|
||||||
#include <isc/safe.h>
|
#include <isc/safe.h>
|
||||||
#include <isc/sockaddr.h>
|
#include <isc/sockaddr.h>
|
||||||
#include <isc/socket.h>
|
#include <isc/socket.h>
|
||||||
@@ -94,8 +95,9 @@ struct dns_client {
|
|||||||
unsigned int find_timeout;
|
unsigned int find_timeout;
|
||||||
unsigned int find_udpretries;
|
unsigned int find_udpretries;
|
||||||
|
|
||||||
|
isc_refcount_t references;
|
||||||
|
|
||||||
/* Locked */
|
/* Locked */
|
||||||
unsigned int references;
|
|
||||||
dns_viewlist_t viewlist;
|
dns_viewlist_t viewlist;
|
||||||
ISC_LIST(struct resctx) resctxs;
|
ISC_LIST(struct resctx) resctxs;
|
||||||
ISC_LIST(struct reqctx) reqctxs;
|
ISC_LIST(struct reqctx) reqctxs;
|
||||||
@@ -502,12 +504,13 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx,
|
|||||||
|
|
||||||
client->task = NULL;
|
client->task = NULL;
|
||||||
result = isc_task_create(client->taskmgr, 0, &client->task);
|
result = isc_task_create(client->taskmgr, 0, &client->task);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS) {
|
||||||
goto cleanup;
|
goto cleanup_lock;
|
||||||
|
}
|
||||||
|
|
||||||
result = dns_dispatchmgr_create(mctx, &dispatchmgr);
|
result = dns_dispatchmgr_create(mctx, &dispatchmgr);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
goto cleanup;
|
goto cleanup_task;
|
||||||
client->dispatchmgr = dispatchmgr;
|
client->dispatchmgr = dispatchmgr;
|
||||||
(void)setsourceports(mctx, dispatchmgr);
|
(void)setsourceports(mctx, dispatchmgr);
|
||||||
|
|
||||||
@@ -520,8 +523,9 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx,
|
|||||||
result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
|
result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
|
||||||
taskmgr, true,
|
taskmgr, true,
|
||||||
&dispatchv4, localaddr4);
|
&dispatchv4, localaddr4);
|
||||||
if (result == ISC_R_SUCCESS)
|
if (result == ISC_R_SUCCESS) {
|
||||||
client->dispatchv4 = dispatchv4;
|
client->dispatchv4 = dispatchv4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client->dispatchv6 = NULL;
|
client->dispatchv6 = NULL;
|
||||||
@@ -529,22 +533,27 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx,
|
|||||||
result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
|
result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
|
||||||
taskmgr, true,
|
taskmgr, true,
|
||||||
&dispatchv6, localaddr6);
|
&dispatchv6, localaddr6);
|
||||||
if (result == ISC_R_SUCCESS)
|
if (result == ISC_R_SUCCESS) {
|
||||||
client->dispatchv6 = dispatchv6;
|
client->dispatchv6 = dispatchv6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need at least one of the dispatchers */
|
/* We need at least one of the dispatchers */
|
||||||
if (dispatchv4 == NULL && dispatchv6 == NULL) {
|
if (dispatchv4 == NULL && dispatchv6 == NULL) {
|
||||||
INSIST(result != ISC_R_SUCCESS);
|
INSIST(result != ISC_R_SUCCESS);
|
||||||
goto cleanup;
|
goto cleanup_dispatchmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isc_refcount_init(&client->references, 1);
|
||||||
|
|
||||||
/* Create the default view for class IN */
|
/* Create the default view for class IN */
|
||||||
result = createview(mctx, dns_rdataclass_in, options, taskmgr,
|
result = createview(mctx, dns_rdataclass_in, options, taskmgr,
|
||||||
RESOLVER_NTASKS, socketmgr, timermgr,
|
RESOLVER_NTASKS, socketmgr, timermgr,
|
||||||
dispatchmgr, dispatchv4, dispatchv6, &view);
|
dispatchmgr, dispatchv4, dispatchv6, &view);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS) {
|
||||||
goto cleanup;
|
goto cleanup_references;
|
||||||
|
}
|
||||||
|
|
||||||
ISC_LIST_INIT(client->viewlist);
|
ISC_LIST_INIT(client->viewlist);
|
||||||
ISC_LIST_APPEND(client->viewlist, view, link);
|
ISC_LIST_APPEND(client->viewlist, view, link);
|
||||||
|
|
||||||
@@ -564,32 +573,38 @@ dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx,
|
|||||||
client->find_udpretries = DEF_FIND_UDPRETRIES;
|
client->find_udpretries = DEF_FIND_UDPRETRIES;
|
||||||
client->attributes = 0;
|
client->attributes = 0;
|
||||||
|
|
||||||
client->references = 1;
|
|
||||||
client->magic = DNS_CLIENT_MAGIC;
|
client->magic = DNS_CLIENT_MAGIC;
|
||||||
|
|
||||||
*clientp = client;
|
*clientp = client;
|
||||||
|
|
||||||
return (ISC_R_SUCCESS);
|
return (ISC_R_SUCCESS);
|
||||||
|
|
||||||
cleanup:
|
cleanup_references:
|
||||||
if (dispatchv4 != NULL)
|
isc_refcount_decrement(&client->references);
|
||||||
|
isc_refcount_destroy(&client->references);
|
||||||
|
cleanup_dispatchmgr:
|
||||||
|
if (dispatchv4 != NULL) {
|
||||||
dns_dispatch_detach(&dispatchv4);
|
dns_dispatch_detach(&dispatchv4);
|
||||||
if (dispatchv6 != NULL)
|
}
|
||||||
|
if (dispatchv6 != NULL) {
|
||||||
dns_dispatch_detach(&dispatchv6);
|
dns_dispatch_detach(&dispatchv6);
|
||||||
if (dispatchmgr != NULL)
|
}
|
||||||
dns_dispatchmgr_destroy(&dispatchmgr);
|
dns_dispatchmgr_destroy(&dispatchmgr);
|
||||||
if (client->task != NULL)
|
cleanup_task:
|
||||||
isc_task_detach(&client->task);
|
isc_task_detach(&client->task);
|
||||||
|
cleanup_lock:
|
||||||
|
isc_mutex_destroy(&client->lock);
|
||||||
isc_mem_put(mctx, client, sizeof(*client));
|
isc_mem_put(mctx, client, sizeof(*client));
|
||||||
|
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
destroyclient(dns_client_t **clientp) {
|
destroyclient(dns_client_t *client) {
|
||||||
dns_client_t *client = *clientp;
|
|
||||||
dns_view_t *view;
|
dns_view_t *view;
|
||||||
|
|
||||||
|
isc_refcount_destroy(&client->references);
|
||||||
|
|
||||||
while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
|
while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
|
||||||
ISC_LIST_UNLINK(client->viewlist, view, link);
|
ISC_LIST_UNLINK(client->viewlist, view, link);
|
||||||
dns_view_detach(&view);
|
dns_view_detach(&view);
|
||||||
@@ -621,32 +636,20 @@ destroyclient(dns_client_t **clientp) {
|
|||||||
client->magic = 0;
|
client->magic = 0;
|
||||||
|
|
||||||
isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
|
isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
|
||||||
|
|
||||||
*clientp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_client_destroy(dns_client_t **clientp) {
|
dns_client_destroy(dns_client_t **clientp) {
|
||||||
dns_client_t *client;
|
dns_client_t *client;
|
||||||
bool destroyok = false;
|
|
||||||
|
|
||||||
REQUIRE(clientp != NULL);
|
REQUIRE(clientp != NULL);
|
||||||
client = *clientp;
|
client = *clientp;
|
||||||
|
*clientp = NULL;
|
||||||
REQUIRE(DNS_CLIENT_VALID(client));
|
REQUIRE(DNS_CLIENT_VALID(client));
|
||||||
|
|
||||||
LOCK(&client->lock);
|
if (isc_refcount_decrement(&client->references) == 1) {
|
||||||
client->references--;
|
destroyclient(client);
|
||||||
if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->reqctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->updatectxs)) {
|
|
||||||
destroyok = true;
|
|
||||||
}
|
}
|
||||||
UNLOCK(&client->lock);
|
|
||||||
|
|
||||||
if (destroyok)
|
|
||||||
destroyclient(&client);
|
|
||||||
|
|
||||||
*clientp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
@@ -1436,6 +1439,7 @@ dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
|
|||||||
rctx->event = event;
|
rctx->event = event;
|
||||||
|
|
||||||
rctx->magic = RCTX_MAGIC;
|
rctx->magic = RCTX_MAGIC;
|
||||||
|
isc_refcount_increment(&client->references);
|
||||||
|
|
||||||
LOCK(&client->lock);
|
LOCK(&client->lock);
|
||||||
ISC_LIST_APPEND(client->resctxs, rctx, link);
|
ISC_LIST_APPEND(client->resctxs, rctx, link);
|
||||||
@@ -1506,10 +1510,10 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
|
|||||||
resctx_t *rctx;
|
resctx_t *rctx;
|
||||||
isc_mem_t *mctx;
|
isc_mem_t *mctx;
|
||||||
dns_client_t *client;
|
dns_client_t *client;
|
||||||
bool need_destroyclient = false;
|
|
||||||
|
|
||||||
REQUIRE(transp != NULL);
|
REQUIRE(transp != NULL);
|
||||||
rctx = (resctx_t *)*transp;
|
rctx = (resctx_t *)*transp;
|
||||||
|
*transp = NULL;
|
||||||
REQUIRE(RCTX_VALID(rctx));
|
REQUIRE(RCTX_VALID(rctx));
|
||||||
REQUIRE(rctx->fetch == NULL);
|
REQUIRE(rctx->fetch == NULL);
|
||||||
REQUIRE(rctx->event == NULL);
|
REQUIRE(rctx->event == NULL);
|
||||||
@@ -1531,11 +1535,6 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
|
|||||||
INSIST(ISC_LINK_LINKED(rctx, link));
|
INSIST(ISC_LINK_LINKED(rctx, link));
|
||||||
ISC_LIST_UNLINK(client->resctxs, rctx, link);
|
ISC_LIST_UNLINK(client->resctxs, rctx, link);
|
||||||
|
|
||||||
if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->reqctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->updatectxs))
|
|
||||||
need_destroyclient = true;
|
|
||||||
|
|
||||||
UNLOCK(&client->lock);
|
UNLOCK(&client->lock);
|
||||||
|
|
||||||
INSIST(ISC_LIST_EMPTY(rctx->namelist));
|
INSIST(ISC_LIST_EMPTY(rctx->namelist));
|
||||||
@@ -1545,10 +1544,8 @@ dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
|
|||||||
|
|
||||||
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
isc_mem_put(mctx, rctx, sizeof(*rctx));
|
||||||
|
|
||||||
if (need_destroyclient)
|
dns_client_destroy(&client);
|
||||||
destroyclient(&client);
|
|
||||||
|
|
||||||
*transp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
@@ -1814,6 +1811,7 @@ dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
|
|||||||
|
|
||||||
LOCK(&client->lock);
|
LOCK(&client->lock);
|
||||||
ISC_LIST_APPEND(client->reqctxs, ctx, link);
|
ISC_LIST_APPEND(client->reqctxs, ctx, link);
|
||||||
|
isc_refcount_increment(&client->references);
|
||||||
UNLOCK(&client->lock);
|
UNLOCK(&client->lock);
|
||||||
|
|
||||||
ctx->request = NULL;
|
ctx->request = NULL;
|
||||||
@@ -1828,6 +1826,8 @@ dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
|
|||||||
return (ISC_R_SUCCESS);
|
return (ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isc_refcount_decrement(&client->references);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
LOCK(&client->lock);
|
LOCK(&client->lock);
|
||||||
@@ -1868,10 +1868,10 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
|
|||||||
reqctx_t *ctx;
|
reqctx_t *ctx;
|
||||||
isc_mem_t *mctx;
|
isc_mem_t *mctx;
|
||||||
dns_client_t *client;
|
dns_client_t *client;
|
||||||
bool need_destroyclient = false;
|
|
||||||
|
|
||||||
REQUIRE(transp != NULL);
|
REQUIRE(transp != NULL);
|
||||||
ctx = (reqctx_t *)*transp;
|
ctx = (reqctx_t *)*transp;
|
||||||
|
*transp = NULL;
|
||||||
REQUIRE(REQCTX_VALID(ctx));
|
REQUIRE(REQCTX_VALID(ctx));
|
||||||
client = ctx->client;
|
client = ctx->client;
|
||||||
REQUIRE(DNS_CLIENT_VALID(client));
|
REQUIRE(DNS_CLIENT_VALID(client));
|
||||||
@@ -1886,12 +1886,6 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
|
|||||||
INSIST(ISC_LINK_LINKED(ctx, link));
|
INSIST(ISC_LINK_LINKED(ctx, link));
|
||||||
ISC_LIST_UNLINK(client->reqctxs, ctx, link);
|
ISC_LIST_UNLINK(client->reqctxs, ctx, link);
|
||||||
|
|
||||||
if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->reqctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->updatectxs)) {
|
|
||||||
need_destroyclient = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNLOCK(&client->lock);
|
UNLOCK(&client->lock);
|
||||||
|
|
||||||
isc_mutex_destroy(&ctx->lock);
|
isc_mutex_destroy(&ctx->lock);
|
||||||
@@ -1899,10 +1893,7 @@ dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
|
|||||||
|
|
||||||
isc_mem_put(mctx, ctx, sizeof(*ctx));
|
isc_mem_put(mctx, ctx, sizeof(*ctx));
|
||||||
|
|
||||||
if (need_destroyclient)
|
dns_client_destroy(&client);
|
||||||
destroyclient(&client);
|
|
||||||
|
|
||||||
*transp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*%
|
/*%
|
||||||
@@ -2988,6 +2979,7 @@ dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
|
|||||||
|
|
||||||
LOCK(&client->lock);
|
LOCK(&client->lock);
|
||||||
ISC_LIST_APPEND(client->updatectxs, uctx, link);
|
ISC_LIST_APPEND(client->updatectxs, uctx, link);
|
||||||
|
isc_refcount_increment(&client->references);
|
||||||
UNLOCK(&client->lock);
|
UNLOCK(&client->lock);
|
||||||
|
|
||||||
*transp = (dns_clientupdatetrans_t *)uctx;
|
*transp = (dns_clientupdatetrans_t *)uctx;
|
||||||
@@ -3006,6 +2998,8 @@ dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
|
|||||||
}
|
}
|
||||||
if (result == ISC_R_SUCCESS)
|
if (result == ISC_R_SUCCESS)
|
||||||
return (result);
|
return (result);
|
||||||
|
|
||||||
|
isc_refcount_decrement(&client->references);
|
||||||
*transp = NULL;
|
*transp = NULL;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@@ -3063,11 +3057,11 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
|
|||||||
updatectx_t *uctx;
|
updatectx_t *uctx;
|
||||||
isc_mem_t *mctx;
|
isc_mem_t *mctx;
|
||||||
dns_client_t *client;
|
dns_client_t *client;
|
||||||
bool need_destroyclient = false;
|
|
||||||
isc_sockaddr_t *sa;
|
isc_sockaddr_t *sa;
|
||||||
|
|
||||||
REQUIRE(transp != NULL);
|
REQUIRE(transp != NULL);
|
||||||
uctx = (updatectx_t *)*transp;
|
uctx = (updatectx_t *)*transp;
|
||||||
|
*transp = NULL;
|
||||||
REQUIRE(UCTX_VALID(uctx));
|
REQUIRE(UCTX_VALID(uctx));
|
||||||
client = uctx->client;
|
client = uctx->client;
|
||||||
REQUIRE(DNS_CLIENT_VALID(client));
|
REQUIRE(DNS_CLIENT_VALID(client));
|
||||||
@@ -3088,11 +3082,6 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
|
|||||||
INSIST(ISC_LINK_LINKED(uctx, link));
|
INSIST(ISC_LINK_LINKED(uctx, link));
|
||||||
ISC_LIST_UNLINK(client->updatectxs, uctx, link);
|
ISC_LIST_UNLINK(client->updatectxs, uctx, link);
|
||||||
|
|
||||||
if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->reqctxs) &&
|
|
||||||
ISC_LIST_EMPTY(client->updatectxs))
|
|
||||||
need_destroyclient = true;
|
|
||||||
|
|
||||||
UNLOCK(&client->lock);
|
UNLOCK(&client->lock);
|
||||||
|
|
||||||
isc_mutex_destroy(&uctx->lock);
|
isc_mutex_destroy(&uctx->lock);
|
||||||
@@ -3100,10 +3089,7 @@ dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
|
|||||||
|
|
||||||
isc_mem_put(mctx, uctx, sizeof(*uctx));
|
isc_mem_put(mctx, uctx, sizeof(*uctx));
|
||||||
|
|
||||||
if (need_destroyclient)
|
dns_client_destroy(&client);
|
||||||
destroyclient(&client);
|
|
||||||
|
|
||||||
*transp = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isc_mem_t *
|
isc_mem_t *
|
||||||
|
Reference in New Issue
Block a user