#include <inttypes.h>
#include <stdbool.h>
+#include <isc/atomic.h>
#include <isc/mem.h>
#include <isc/random.h>
#include <isc/result.h>
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 */
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);
return (DNS_R_FORMERR);
}
- xfr->is_ixfr = true;
+ atomic_store(&xfr->is_ixfr, true);
INSIST(xfr->db != NULL);
xfr->difflen = 0;
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))
}
redo:
- switch (xfr->state) {
+ switch (atomic_load(&xfr->state)) {
case XFRST_SOAQUERY:
if (rdata->type != dns_rdatatype_soa) {
xfrin_log(xfr, ISC_LOG_NOTICE,
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:
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:
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;
}
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:
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,
FAIL(DNS_R_FORMERR);
} else {
CHECK(ixfr_commit(xfr));
- xfr->state = XFRST_IXFR_DELSOA;
+ atomic_store(&xfr->state, XFRST_IXFR_DELSOA);
goto redo;
}
}
FAIL(DNS_R_FORMERR);
}
CHECK(axfr_commit(xfr));
- xfr->state = XFRST_AXFR_END;
+ atomic_store(&xfr->state, XFRST_AXFR_END);
break;
}
break;
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:
}
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 *
{
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
*/
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);
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();
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) {
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);
{
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);
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) {
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");
* 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),
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.
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:
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, "
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);