mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-26 03:11:56 -05:00
Provide thread safe access to dns_xfrin_t state
dns_xfrin_t state may be accessed from different threads when when reporting transfer state. Ensure access is thread safe by using atomics and locks where appropriate.
This commit is contained in:
parent
42f41f003e
commit
bed4e36c86
2 changed files with 57 additions and 33 deletions
|
|
@ -125,8 +125,8 @@ dns_xfrin_getendserial(const dns_xfrin_t *xfr);
|
|||
*/
|
||||
|
||||
void
|
||||
dns_xfrin_getstats(const dns_xfrin_t *xfr, unsigned int *nmsgp,
|
||||
unsigned int *nrecsp, uint64_t *nbytesp);
|
||||
dns_xfrin_getstats(dns_xfrin_t *xfr, unsigned int *nmsgp, unsigned int *nrecsp,
|
||||
uint64_t *nbytesp);
|
||||
/*%<
|
||||
* Get various statistics values of the xfrin object: number of the received
|
||||
* messages, number of the received records, number of the received bytes.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/result.h>
|
||||
|
|
@ -140,11 +141,14 @@ struct dns_xfrin {
|
|||
dns_diff_t diff; /*%< Pending database changes */
|
||||
int difflen; /*%< Number of pending tuples */
|
||||
|
||||
xfrin_state_t state;
|
||||
_Atomic xfrin_state_t state;
|
||||
uint32_t end_serial;
|
||||
uint32_t expireopt;
|
||||
bool edns, is_ixfr, expireoptset;
|
||||
bool edns, expireoptset;
|
||||
atomic_bool is_ixfr;
|
||||
|
||||
isc_mutex_t statslock;
|
||||
/* Locked by statslock. */
|
||||
unsigned int nmsg; /*%< Number of messages recvd */
|
||||
unsigned int nrecs; /*%< Number of records recvd */
|
||||
uint64_t nbytes; /*%< Number of bytes received */
|
||||
|
|
@ -269,7 +273,7 @@ static isc_result_t
|
|||
axfr_init(dns_xfrin_t *xfr) {
|
||||
isc_result_t result;
|
||||
|
||||
xfr->is_ixfr = false;
|
||||
atomic_store(&xfr->is_ixfr, false);
|
||||
|
||||
if (xfr->db != NULL) {
|
||||
dns_db_detach(&xfr->db);
|
||||
|
|
@ -385,7 +389,7 @@ ixfr_init(dns_xfrin_t *xfr) {
|
|||
return (DNS_R_FORMERR);
|
||||
}
|
||||
|
||||
xfr->is_ixfr = true;
|
||||
atomic_store(&xfr->is_ixfr, true);
|
||||
INSIST(xfr->db != NULL);
|
||||
xfr->difflen = 0;
|
||||
|
||||
|
|
@ -491,7 +495,9 @@ static isc_result_t
|
|||
xfr_rr(dns_xfrin_t *xfr, dns_name_t *name, uint32_t ttl, dns_rdata_t *rdata) {
|
||||
isc_result_t result;
|
||||
|
||||
LOCK(&xfr->statslock);
|
||||
xfr->nrecs++;
|
||||
UNLOCK(&xfr->statslock);
|
||||
|
||||
if (rdata->type == dns_rdatatype_none ||
|
||||
dns_rdatatype_ismeta(rdata->type))
|
||||
|
|
@ -519,7 +525,7 @@ xfr_rr(dns_xfrin_t *xfr, dns_name_t *name, uint32_t ttl, dns_rdata_t *rdata) {
|
|||
}
|
||||
|
||||
redo:
|
||||
switch (xfr->state) {
|
||||
switch (atomic_load(&xfr->state)) {
|
||||
case XFRST_SOAQUERY:
|
||||
if (rdata->type != dns_rdatatype_soa) {
|
||||
xfrin_log(xfr, ISC_LOG_NOTICE,
|
||||
|
|
@ -536,7 +542,7 @@ redo:
|
|||
xfr->ixfr.request_serial, xfr->end_serial);
|
||||
FAIL(DNS_R_UPTODATE);
|
||||
}
|
||||
xfr->state = XFRST_GOTSOA;
|
||||
atomic_store(&xfr->state, XFRST_GOTSOA);
|
||||
break;
|
||||
|
||||
case XFRST_GOTSOA:
|
||||
|
|
@ -578,7 +584,7 @@ redo:
|
|||
xfr->firstsoa_data = isc_mem_allocate(xfr->mctx, rdata->length);
|
||||
memcpy(xfr->firstsoa_data, rdata->data, rdata->length);
|
||||
xfr->firstsoa.data = xfr->firstsoa_data;
|
||||
xfr->state = XFRST_FIRSTDATA;
|
||||
atomic_store(&xfr->state, XFRST_FIRSTDATA);
|
||||
break;
|
||||
|
||||
case XFRST_FIRSTDATA:
|
||||
|
|
@ -593,25 +599,25 @@ redo:
|
|||
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
||||
"got incremental response");
|
||||
CHECK(ixfr_init(xfr));
|
||||
xfr->state = XFRST_IXFR_DELSOA;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_DELSOA);
|
||||
} else {
|
||||
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
||||
"got nonincremental response");
|
||||
CHECK(axfr_init(xfr));
|
||||
xfr->state = XFRST_AXFR;
|
||||
atomic_store(&xfr->state, XFRST_AXFR);
|
||||
}
|
||||
goto redo;
|
||||
|
||||
case XFRST_IXFR_DELSOA:
|
||||
INSIST(rdata->type == dns_rdatatype_soa);
|
||||
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_DEL, name, ttl, rdata));
|
||||
xfr->state = XFRST_IXFR_DEL;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_DEL);
|
||||
break;
|
||||
|
||||
case XFRST_IXFR_DEL:
|
||||
if (rdata->type == dns_rdatatype_soa) {
|
||||
uint32_t soa_serial = dns_soa_getserial(rdata);
|
||||
xfr->state = XFRST_IXFR_ADDSOA;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_ADDSOA);
|
||||
xfr->ixfr.current_serial = soa_serial;
|
||||
goto redo;
|
||||
}
|
||||
|
|
@ -621,7 +627,7 @@ redo:
|
|||
case XFRST_IXFR_ADDSOA:
|
||||
INSIST(rdata->type == dns_rdatatype_soa);
|
||||
CHECK(ixfr_putdata(xfr, DNS_DIFFOP_ADD, name, ttl, rdata));
|
||||
xfr->state = XFRST_IXFR_ADD;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_ADD);
|
||||
break;
|
||||
|
||||
case XFRST_IXFR_ADD:
|
||||
|
|
@ -629,7 +635,7 @@ redo:
|
|||
uint32_t soa_serial = dns_soa_getserial(rdata);
|
||||
if (soa_serial == xfr->end_serial) {
|
||||
CHECK(ixfr_commit(xfr));
|
||||
xfr->state = XFRST_IXFR_END;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_END);
|
||||
break;
|
||||
} else if (soa_serial != xfr->ixfr.current_serial) {
|
||||
xfrin_log(xfr, ISC_LOG_NOTICE,
|
||||
|
|
@ -639,7 +645,7 @@ redo:
|
|||
FAIL(DNS_R_FORMERR);
|
||||
} else {
|
||||
CHECK(ixfr_commit(xfr));
|
||||
xfr->state = XFRST_IXFR_DELSOA;
|
||||
atomic_store(&xfr->state, XFRST_IXFR_DELSOA);
|
||||
goto redo;
|
||||
}
|
||||
}
|
||||
|
|
@ -674,7 +680,7 @@ redo:
|
|||
FAIL(DNS_R_FORMERR);
|
||||
}
|
||||
CHECK(axfr_commit(xfr));
|
||||
xfr->state = XFRST_AXFR_END;
|
||||
atomic_store(&xfr->state, XFRST_AXFR_END);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -778,10 +784,10 @@ dns_xfrin_getstate(const dns_xfrin_t *xfr, const char **statestr,
|
|||
REQUIRE(statestr != NULL && *statestr == NULL);
|
||||
REQUIRE(is_ixfr != NULL);
|
||||
|
||||
state = xfr->state;
|
||||
state = atomic_load(&xfr->state);
|
||||
*statestr = "";
|
||||
*is_first_data_received = (state > XFRST_FIRSTDATA);
|
||||
*is_ixfr = xfr->is_ixfr;
|
||||
*is_ixfr = atomic_load(&xfr->is_ixfr);
|
||||
|
||||
switch (state) {
|
||||
case XFRST_SOAQUERY:
|
||||
|
|
@ -822,14 +828,16 @@ dns_xfrin_getendserial(const dns_xfrin_t *xfr) {
|
|||
}
|
||||
|
||||
void
|
||||
dns_xfrin_getstats(const dns_xfrin_t *xfr, unsigned int *nmsgp,
|
||||
unsigned int *nrecsp, uint64_t *nbytesp) {
|
||||
dns_xfrin_getstats(dns_xfrin_t *xfr, unsigned int *nmsgp, unsigned int *nrecsp,
|
||||
uint64_t *nbytesp) {
|
||||
REQUIRE(VALID_XFRIN(xfr));
|
||||
REQUIRE(nmsgp != NULL && nrecsp != NULL && nbytesp != NULL);
|
||||
|
||||
LOCK(&xfr->statslock);
|
||||
*nmsgp = xfr->nmsg;
|
||||
*nrecsp = xfr->nrecs;
|
||||
*nbytesp = xfr->nbytes;
|
||||
UNLOCK(&xfr->statslock);
|
||||
}
|
||||
|
||||
const isc_sockaddr_t *
|
||||
|
|
@ -925,7 +933,7 @@ xfrin_fail(dns_xfrin_t *xfr, isc_result_t result, const char *msg) {
|
|||
{
|
||||
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", msg,
|
||||
isc_result_totext(result));
|
||||
if (xfr->is_ixfr) {
|
||||
if (atomic_load(&xfr->is_ixfr)) {
|
||||
/*
|
||||
* Pass special result code to force AXFR retry
|
||||
*/
|
||||
|
|
@ -979,7 +987,10 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db,
|
|||
dns_view_weakattach(dns_zone_getview(zone), &xfr->view);
|
||||
dns_name_init(&xfr->name, NULL);
|
||||
|
||||
isc_mutex_init(&xfr->statslock);
|
||||
|
||||
atomic_init(&xfr->shuttingdown, false);
|
||||
atomic_init(&xfr->is_ixfr, false);
|
||||
|
||||
if (db != NULL) {
|
||||
dns_db_attach(db, &xfr->db);
|
||||
|
|
@ -988,9 +999,9 @@ xfrin_create(isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db,
|
|||
dns_diff_init(xfr->mctx, &xfr->diff);
|
||||
|
||||
if (reqtype == dns_rdatatype_soa) {
|
||||
xfr->state = XFRST_SOAQUERY;
|
||||
atomic_init(&xfr->state, XFRST_SOAQUERY);
|
||||
} else {
|
||||
xfr->state = XFRST_INITIALSOA;
|
||||
atomic_init(&xfr->state, XFRST_INITIALSOA);
|
||||
}
|
||||
|
||||
xfr->start = isc_time_now();
|
||||
|
|
@ -1363,9 +1374,11 @@ xfrin_send_request(dns_xfrin_t *xfr) {
|
|||
CHECK(add_opt(msg, udpsize, reqnsid, reqexpire));
|
||||
}
|
||||
|
||||
LOCK(&xfr->statslock);
|
||||
xfr->nmsg = 0;
|
||||
xfr->nrecs = 0;
|
||||
xfr->nbytes = 0;
|
||||
UNLOCK(&xfr->statslock);
|
||||
xfr->start = isc_time_now();
|
||||
msg->id = xfr->id;
|
||||
if (xfr->tsigctx != NULL) {
|
||||
|
|
@ -1497,9 +1510,11 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
|
||||
dns_message_setclass(msg, xfr->rdclass);
|
||||
|
||||
LOCK(&xfr->statslock);
|
||||
if (xfr->nmsg > 0) {
|
||||
msg->tcp_continuation = 1;
|
||||
}
|
||||
UNLOCK(&xfr->statslock);
|
||||
|
||||
isc_buffer_init(&buffer, region->base, region->length);
|
||||
isc_buffer_add(&buffer, region->length);
|
||||
|
|
@ -1523,8 +1538,8 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
{
|
||||
if (result == ISC_R_SUCCESS &&
|
||||
msg->rcode == dns_rcode_formerr && xfr->edns &&
|
||||
(xfr->state == XFRST_SOAQUERY ||
|
||||
xfr->state == XFRST_INITIALSOA))
|
||||
(atomic_load(&xfr->state) == XFRST_SOAQUERY ||
|
||||
atomic_load(&xfr->state) == XFRST_INITIALSOA))
|
||||
{
|
||||
xfr->edns = false;
|
||||
dns_message_detach(&msg);
|
||||
|
|
@ -1559,7 +1574,7 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
dns_message_detach(&msg);
|
||||
xfrin_reset(xfr);
|
||||
xfr->reqtype = dns_rdatatype_soa;
|
||||
xfr->state = XFRST_SOAQUERY;
|
||||
atomic_store(&xfr->state, XFRST_SOAQUERY);
|
||||
try_again:
|
||||
result = xfrin_start(xfr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
|
|
@ -1583,7 +1598,8 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
goto failure;
|
||||
}
|
||||
|
||||
if ((xfr->state == XFRST_SOAQUERY || xfr->state == XFRST_INITIALSOA) &&
|
||||
if ((atomic_load(&xfr->state) == XFRST_SOAQUERY ||
|
||||
atomic_load(&xfr->state) == XFRST_INITIALSOA) &&
|
||||
msg->counts[DNS_SECTION_QUESTION] != 1)
|
||||
{
|
||||
xfrin_log(xfr, ISC_LOG_NOTICE, "missing question section");
|
||||
|
|
@ -1633,7 +1649,7 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
* if the first RR in the answer section is not a SOA record.
|
||||
*/
|
||||
if (xfr->reqtype == dns_rdatatype_ixfr &&
|
||||
xfr->state == XFRST_INITIALSOA &&
|
||||
atomic_load(&xfr->state) == XFRST_INITIALSOA &&
|
||||
msg->counts[DNS_SECTION_ANSWER] == 0)
|
||||
{
|
||||
xfrin_log(xfr, ISC_LOG_DEBUG(3),
|
||||
|
|
@ -1700,24 +1716,29 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig));
|
||||
} else if (dns_message_gettsigkey(msg) != NULL) {
|
||||
xfr->sincetsig++;
|
||||
LOCK(&xfr->statslock);
|
||||
if (xfr->sincetsig > 100 || xfr->nmsg == 0 ||
|
||||
xfr->state == XFRST_AXFR_END ||
|
||||
xfr->state == XFRST_IXFR_END)
|
||||
atomic_load(&xfr->state) == XFRST_AXFR_END ||
|
||||
atomic_load(&xfr->state) == XFRST_IXFR_END)
|
||||
{
|
||||
UNLOCK(&xfr->statslock);
|
||||
result = DNS_R_EXPECTEDTSIG;
|
||||
goto failure;
|
||||
}
|
||||
UNLOCK(&xfr->statslock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the number of messages received.
|
||||
*/
|
||||
LOCK(&xfr->statslock);
|
||||
xfr->nmsg++;
|
||||
|
||||
/*
|
||||
* Update the number of bytes received.
|
||||
*/
|
||||
xfr->nbytes += buffer.used;
|
||||
UNLOCK(&xfr->statslock);
|
||||
|
||||
/*
|
||||
* Take the context back.
|
||||
|
|
@ -1730,10 +1751,10 @@ xfrin_recv_done(isc_result_t result, isc_region_t *region, void *arg) {
|
|||
get_edns_expire(xfr, msg);
|
||||
}
|
||||
|
||||
switch (xfr->state) {
|
||||
switch (atomic_load(&xfr->state)) {
|
||||
case XFRST_GOTSOA:
|
||||
xfr->reqtype = dns_rdatatype_axfr;
|
||||
xfr->state = XFRST_INITIALSOA;
|
||||
atomic_store(&xfr->state, XFRST_INITIALSOA);
|
||||
CHECK(xfrin_send_request(xfr));
|
||||
break;
|
||||
case XFRST_AXFR_END:
|
||||
|
|
@ -1826,6 +1847,7 @@ xfrin_destroy(dns_xfrin_t *xfr) {
|
|||
if (msecs == 0) {
|
||||
msecs = 1;
|
||||
}
|
||||
LOCK(&xfr->statslock);
|
||||
persec = (xfr->nbytes * 1000) / msecs;
|
||||
xfrin_log(xfr, ISC_LOG_INFO,
|
||||
"Transfer completed: %d messages, %d records, "
|
||||
|
|
@ -1834,6 +1856,8 @@ xfrin_destroy(dns_xfrin_t *xfr) {
|
|||
xfr->nmsg, xfr->nrecs, xfr->nbytes,
|
||||
(unsigned int)(msecs / 1000), (unsigned int)(msecs % 1000),
|
||||
(unsigned int)persec, xfr->end_serial);
|
||||
UNLOCK(&xfr->statslock);
|
||||
isc_mutex_destroy(&xfr->statslock);
|
||||
|
||||
if (xfr->dispentry != NULL) {
|
||||
dns_dispatch_done(&xfr->dispentry);
|
||||
|
|
|
|||
Loading…
Reference in a new issue