2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 22:45:39 +00:00

Abort incoming zone transfers on server shutdown. To support

this, zone transfers now use the zone's task, the zone holds a pointer
to any zone transfer in progress, and the zone now registers a shutdown
callback.
This commit is contained in:
Andreas Gustafsson
2000-01-28 23:48:58 +00:00
parent b402f83472
commit 897ba5e120
3 changed files with 186 additions and 100 deletions

View File

@@ -26,15 +26,55 @@
* Incoming zone transfers (AXFR + IXFR). * Incoming zone transfers (AXFR + IXFR).
*/ */
/***
*** Imports
***/
#include <isc/lang.h>
#include <dns/types.h> #include <dns/types.h>
/***
*** Types
***/
typedef struct dns_xfrin_ctx dns_xfrin_ctx_t;
/*** /***
*** Functions *** Functions
***/ ***/
void dns_xfrin_start(dns_zone_t *zone, isc_sockaddr_t *master, ISC_LANG_BEGINDECLS
isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_result_t
dns_xfrindone_t done); dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
isc_mem_t *mctx, isc_timermgr_t *timermgr,
isc_socketmgr_t *socketmgr, isc_task_t *task,
dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp);
/*
* Attempt to start an incoming zone transfer of 'zone'
* from 'masteraddr', creating a dns_xfrin_ctx_t object to
* manage it. Attach '*xfrp' to the newly created object.
*
* Iff ISC_R_SUCCESS is returned, '*done' is guaranteed to be
* called in the context of 'task', with 'zone' and a result
* code as arguments when the transfer finishes.
*/
void dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr);
/*
* If the zone transfer 'xfr' has already finished,
* do nothing. Otherwise, abort it and cause it to call
* its done callback with a status of ISC_R_CANCELLED.
*/
void dns_xfrin_detach(dns_xfrin_ctx_t **xfrp);
/*
* Detach a reference to a zone transfer object.
*
* (Because there is no attach() method, there can currently
* only be one reference).
*/
ISC_LANG_ENDDECLS
#endif /* DNS_XFRIN_H */ #endif /* DNS_XFRIN_H */

View File

@@ -15,7 +15,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* $Id: xfrin.c,v 1.40 2000/01/28 01:12:01 gson Exp $ */ /* $Id: xfrin.c,v 1.41 2000/01/28 23:48:57 gson Exp $ */
#include <config.h> #include <config.h>
@@ -65,8 +65,6 @@
if (result != DNS_R_SUCCESS) goto failure; \ if (result != DNS_R_SUCCESS) goto failure; \
} while (0) } while (0)
typedef struct xfrin_ctx xfrin_ctx_t;
/* /*
* The states of the *XFR state machine. We handle both IXFR and AXFR * The states of the *XFR state machine. We handle both IXFR and AXFR
* with a single integrated state machine because they cannot be distinguished * with a single integrated state machine because they cannot be distinguished
@@ -90,10 +88,12 @@ typedef enum {
* Incoming zone transfer context. * Incoming zone transfer context.
*/ */
struct xfrin_ctx { struct dns_xfrin_ctx {
isc_mem_t *mctx; isc_mem_t *mctx;
dns_zone_t *zone; dns_zone_t *zone;
int refcount;
isc_task_t *task; isc_task_t *task;
isc_timer_t *timer; isc_timer_t *timer;
isc_socketmgr_t *socketmgr; isc_socketmgr_t *socketmgr;
@@ -173,44 +173,43 @@ xfrin_create(isc_mem_t *mctx,
isc_task_t *task, isc_task_t *task,
isc_timermgr_t *timermgr, isc_timermgr_t *timermgr,
isc_socketmgr_t *socketmgr, isc_socketmgr_t *socketmgr,
dns_xfrindone_t done,
dns_name_t *zonename, dns_name_t *zonename,
dns_rdataclass_t rdclass, dns_rdataclass_t rdclass,
dns_rdatatype_t reqtype, dns_rdatatype_t reqtype,
isc_sockaddr_t *masteraddr, isc_sockaddr_t *masteraddr,
dns_tsigkey_t *tsigkey, dns_tsigkey_t *tsigkey,
xfrin_ctx_t **xfrp); dns_xfrin_ctx_t **xfrp);
static isc_result_t axfr_init(xfrin_ctx_t *xfr); static isc_result_t axfr_init(dns_xfrin_ctx_t *xfr);
static isc_result_t axfr_makedb(xfrin_ctx_t *xfr, dns_db_t **dbp); static isc_result_t axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp);
static isc_result_t axfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op, static isc_result_t axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
dns_name_t *name, dns_ttl_t ttl, dns_name_t *name, dns_ttl_t ttl,
dns_rdata_t *rdata); dns_rdata_t *rdata);
static isc_result_t axfr_apply(xfrin_ctx_t *xfr); static isc_result_t axfr_apply(dns_xfrin_ctx_t *xfr);
static isc_result_t axfr_commit(xfrin_ctx_t *xfr); static isc_result_t axfr_commit(dns_xfrin_ctx_t *xfr);
static isc_result_t ixfr_init(xfrin_ctx_t *xfr); static isc_result_t ixfr_init(dns_xfrin_ctx_t *xfr);
static isc_result_t ixfr_apply(xfrin_ctx_t *xfr); static isc_result_t ixfr_apply(dns_xfrin_ctx_t *xfr);
static isc_result_t ixfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op, static isc_result_t ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
dns_name_t *name, dns_ttl_t ttl, dns_name_t *name, dns_ttl_t ttl,
dns_rdata_t *rdata); dns_rdata_t *rdata);
static isc_result_t ixfr_commit(xfrin_ctx_t *xfr); static isc_result_t ixfr_commit(dns_xfrin_ctx_t *xfr);
static isc_result_t xfr_rr(xfrin_ctx_t *xfr, dns_name_t *name, static isc_result_t xfr_rr(dns_xfrin_ctx_t *xfr, dns_name_t *name,
isc_uint32_t ttl, dns_rdata_t *rdata); isc_uint32_t ttl, dns_rdata_t *rdata);
void xfrin_start(xfrin_ctx_t *xfr); static isc_result_t xfrin_start(dns_xfrin_ctx_t *xfr);
static void xfrin_connect_done(isc_task_t *task, isc_event_t *event); static void xfrin_connect_done(isc_task_t *task, isc_event_t *event);
static isc_result_t xfrin_send_request(xfrin_ctx_t *xfr); static isc_result_t xfrin_send_request(dns_xfrin_ctx_t *xfr);
static void xfrin_send_done(isc_task_t *task, isc_event_t *event); static void xfrin_send_done(isc_task_t *task, isc_event_t *event);
static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event); static void xfrin_sendlen_done(isc_task_t *task, isc_event_t *event);
static void xfrin_recv_done(isc_task_t *task, isc_event_t *event); static void xfrin_recv_done(isc_task_t *task, isc_event_t *event);
static void xfrin_timeout(isc_task_t *task, isc_event_t *event); static void xfrin_timeout(isc_task_t *task, isc_event_t *event);
static isc_boolean_t maybe_free(xfrin_ctx_t *xfr); static void maybe_free(dns_xfrin_ctx_t *xfr);
static void xfrin_fail(xfrin_ctx_t *xfr, isc_result_t result, char *msg); static void xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, char *msg);
static isc_result_t render(dns_message_t *msg, isc_buffer_t *buf); static isc_result_t render(dns_message_t *msg, isc_buffer_t *buf);
static void static void
@@ -220,7 +219,7 @@ static void
xfrin_log1(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr, xfrin_log1(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
const char *fmt, ...); const char *fmt, ...);
static void static void
xfrin_log(xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...); xfrin_log(dns_xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...);
/**************************************************************************/ /**************************************************************************/
@@ -229,7 +228,7 @@ xfrin_log(xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...);
*/ */
static isc_result_t static isc_result_t
axfr_init(xfrin_ctx_t *xfr) { axfr_init(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
xfr->is_ixfr = ISC_FALSE; xfr->is_ixfr = ISC_FALSE;
@@ -245,7 +244,7 @@ axfr_init(xfrin_ctx_t *xfr) {
} }
static isc_result_t static isc_result_t
axfr_makedb(xfrin_ctx_t *xfr, dns_db_t **dbp) { axfr_makedb(dns_xfrin_ctx_t *xfr, dns_db_t **dbp) {
return (dns_db_create(xfr->mctx, /* XXX */ return (dns_db_create(xfr->mctx, /* XXX */
"rbt", /* XXX guess */ "rbt", /* XXX guess */
&xfr->name, &xfr->name,
@@ -256,7 +255,7 @@ axfr_makedb(xfrin_ctx_t *xfr, dns_db_t **dbp) {
} }
static isc_result_t static isc_result_t
axfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op, axfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
{ {
isc_result_t result; isc_result_t result;
@@ -273,7 +272,7 @@ axfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op,
/* Store a set of AXFR RRs in the database. */ /* Store a set of AXFR RRs in the database. */
static isc_result_t static isc_result_t
axfr_apply(xfrin_ctx_t *xfr) { axfr_apply(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
CHECK(dns_diff_load(&xfr->diff, CHECK(dns_diff_load(&xfr->diff,
xfr->axfr.add_func, xfr->axfr.add_private)); xfr->axfr.add_func, xfr->axfr.add_private));
@@ -285,7 +284,7 @@ axfr_apply(xfrin_ctx_t *xfr) {
} }
static isc_result_t static isc_result_t
axfr_commit(xfrin_ctx_t *xfr) { axfr_commit(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
CHECK(axfr_apply(xfr)); CHECK(axfr_apply(xfr));
@@ -303,7 +302,7 @@ axfr_commit(xfrin_ctx_t *xfr) {
*/ */
static isc_result_t static isc_result_t
ixfr_init(xfrin_ctx_t *xfr) { ixfr_init(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
xfr->is_ixfr = ISC_TRUE; xfr->is_ixfr = ISC_TRUE;
INSIST(xfr->db != NULL); INSIST(xfr->db != NULL);
@@ -316,7 +315,7 @@ ixfr_init(xfrin_ctx_t *xfr) {
} }
static isc_result_t static isc_result_t
ixfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op, ixfr_putdata(dns_xfrin_ctx_t *xfr, dns_diffop_t op,
dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata)
{ {
isc_result_t result; isc_result_t result;
@@ -333,7 +332,7 @@ ixfr_putdata(xfrin_ctx_t *xfr, dns_diffop_t op,
/* Apply a set of IXFR changes to the database. */ /* Apply a set of IXFR changes to the database. */
static isc_result_t static isc_result_t
ixfr_apply(xfrin_ctx_t *xfr) { ixfr_apply(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
if (xfr->ver == NULL) { if (xfr->ver == NULL) {
CHECK(dns_db_newversion(xfr->db, &xfr->ver)); CHECK(dns_db_newversion(xfr->db, &xfr->ver));
@@ -349,7 +348,7 @@ ixfr_apply(xfrin_ctx_t *xfr) {
} }
static isc_result_t static isc_result_t
ixfr_commit(xfrin_ctx_t *xfr) { ixfr_commit(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
ixfr_apply(xfr); ixfr_apply(xfr);
if (xfr->ver != NULL) { if (xfr->ver != NULL) {
@@ -372,7 +371,7 @@ ixfr_commit(xfrin_ctx_t *xfr) {
* state. * state.
*/ */
static isc_result_t static isc_result_t
xfr_rr(xfrin_ctx_t *xfr, xfr_rr(dns_xfrin_ctx_t *xfr,
dns_name_t *name, isc_uint32_t ttl, dns_rdata_t *rdata) dns_name_t *name, isc_uint32_t ttl, dns_rdata_t *rdata)
{ {
isc_result_t result; isc_result_t result;
@@ -490,19 +489,19 @@ xfr_rr(xfrin_ctx_t *xfr,
return (result); return (result);
} }
void isc_result_t
dns_xfrin_start(dns_zone_t *zone, isc_sockaddr_t *masteraddr, dns_xfrin_create(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_mem_t *mctx, isc_timermgr_t *timermgr,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr, isc_socketmgr_t *socketmgr, isc_task_t *task,
dns_xfrindone_t done) dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
{ {
dns_name_t *zonename; dns_name_t *zonename;
isc_task_t *task; dns_xfrin_ctx_t *xfr;
xfrin_ctx_t *xfr;
isc_result_t result; isc_result_t result;
dns_db_t *db = NULL; dns_db_t *db = NULL;
dns_rdatatype_t xfrtype; dns_rdatatype_t xfrtype;
dns_tsigkey_t *key = NULL; dns_tsigkey_t *key = NULL;
REQUIRE(xfrp != NULL && *xfrp == NULL);
zonename = dns_zone_getorigin(zone); zonename = dns_zone_getorigin(zone);
@@ -514,10 +513,6 @@ dns_xfrin_start(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
else else
CHECK(result); CHECK(result);
task = NULL;
CHECK(isc_task_create(taskmgr, mctx, 0, &task));
isc_task_setname(task, "xfrin", zone);
if (db == NULL) { if (db == NULL) {
xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr, xfrin_log1(ISC_LOG_DEBUG(3), zonename, masteraddr,
"no database exists yet, " "no database exists yet, "
@@ -535,34 +530,44 @@ dns_xfrin_start(dns_zone_t *zone, isc_sockaddr_t *masteraddr,
task, task,
timermgr, timermgr,
socketmgr, socketmgr,
done,
zonename, zonename,
dns_zone_getclass(zone), xfrtype, dns_zone_getclass(zone), xfrtype,
masteraddr, key, &xfr)); masteraddr, key, &xfr));
xfrin_start(xfr); CHECK(xfrin_start(xfr));
goto cleanup;
xfr->done = done;
xfr->refcount++;
*xfrp = xfr;
failure: failure:
if (done != NULL)
(done)(zone, result);
cleanup:
if (db != NULL) if (db != NULL)
dns_db_detach(&db); dns_db_detach(&db);
if (result != DNS_R_SUCCESS) if (result != DNS_R_SUCCESS)
xfrin_log1(ISC_LOG_ERROR, zonename, masteraddr, xfrin_log1(ISC_LOG_ERROR, zonename, masteraddr,
"zone transfer setup failed"); "zone transfer setup failed");
return; return (result);
}
void dns_xfrin_shutdown(dns_xfrin_ctx_t *xfr) {
if (! xfr->shuttingdown)
xfrin_fail(xfr, ISC_R_CANCELED, "shut down");
}
void dns_xfrin_detach(dns_xfrin_ctx_t **xfrp) {
dns_xfrin_ctx_t *xfr = *xfrp;
INSIST(xfr->refcount > 0);
xfr->refcount--;
maybe_free(xfr);
*xfrp = NULL;
} }
static void static void
xfrin_fail(xfrin_ctx_t *xfr, isc_result_t result, char *msg) { xfrin_fail(dns_xfrin_ctx_t *xfr, isc_result_t result, char *msg) {
if (result != DNS_R_UPTODATE) { if (result != DNS_R_UPTODATE) {
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s", xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
msg, isc_result_totext(result)); msg, isc_result_totext(result));
} }
xfr->shuttingdown = ISC_TRUE;
if (xfr->connects > 0) { if (xfr->connects > 0) {
isc_socket_cancel(xfr->socket, xfr->task, isc_socket_cancel(xfr->socket, xfr->task,
ISC_SOCKCANCEL_CONNECT); ISC_SOCKCANCEL_CONNECT);
@@ -572,8 +577,11 @@ xfrin_fail(xfrin_ctx_t *xfr, isc_result_t result, char *msg) {
isc_socket_cancel(xfr->socket, xfr->task, isc_socket_cancel(xfr->socket, xfr->task,
ISC_SOCKCANCEL_SEND); ISC_SOCKCANCEL_SEND);
} }
if (xfr->done != NULL) xfr->shuttingdown = ISC_TRUE;
if (xfr->done != NULL) {
(xfr->done)(xfr->zone, result); (xfr->done)(xfr->zone, result);
xfr->done = NULL;
}
maybe_free(xfr); maybe_free(xfr);
} }
@@ -584,15 +592,14 @@ xfrin_create(isc_mem_t *mctx,
isc_task_t *task, isc_task_t *task,
isc_timermgr_t *timermgr, isc_timermgr_t *timermgr,
isc_socketmgr_t *socketmgr, isc_socketmgr_t *socketmgr,
dns_xfrindone_t done,
dns_name_t *zonename, dns_name_t *zonename,
dns_rdataclass_t rdclass, dns_rdataclass_t rdclass,
dns_rdatatype_t reqtype, dns_rdatatype_t reqtype,
isc_sockaddr_t *masteraddr, isc_sockaddr_t *masteraddr,
dns_tsigkey_t *tsigkey, dns_tsigkey_t *tsigkey,
xfrin_ctx_t **xfrp) dns_xfrin_ctx_t **xfrp)
{ {
xfrin_ctx_t *xfr = NULL; dns_xfrin_ctx_t *xfr = NULL;
isc_result_t result; isc_result_t result;
isc_interval_t interval; isc_interval_t interval;
@@ -600,12 +607,14 @@ xfrin_create(isc_mem_t *mctx,
if (xfr == NULL) if (xfr == NULL)
return (DNS_R_NOMEMORY); return (DNS_R_NOMEMORY);
xfr->mctx = mctx; xfr->mctx = mctx;
xfr->refcount = 0;
xfr->zone = NULL; xfr->zone = NULL;
dns_zone_attach(zone, &xfr->zone); dns_zone_attach(zone, &xfr->zone);
xfr->task = task; xfr->task = NULL;
isc_task_attach(task, &xfr->task);
xfr->timer = NULL; xfr->timer = NULL;
xfr->socketmgr = socketmgr; xfr->socketmgr = socketmgr;
xfr->done = done; xfr->done = NULL;
xfr->connects = 0; xfr->connects = 0;
xfr->sends = 0; xfr->sends = 0;
@@ -672,8 +681,8 @@ xfrin_create(isc_mem_t *mctx,
return (result); return (result);
} }
void isc_result_t
xfrin_start(xfrin_ctx_t *xfr) { xfrin_start(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
CHECK(isc_socket_create(xfr->socketmgr, CHECK(isc_socket_create(xfr->socketmgr,
isc_sockaddr_pf(&xfr->masteraddr), isc_sockaddr_pf(&xfr->masteraddr),
@@ -683,9 +692,10 @@ xfrin_start(xfrin_ctx_t *xfr) {
CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task, CHECK(isc_socket_connect(xfr->socket, &xfr->masteraddr, xfr->task,
xfrin_connect_done, xfr)); xfrin_connect_done, xfr));
xfr->connects++; xfr->connects++;
return; return (ISC_R_SUCCESS);
failure: failure:
xfrin_fail(xfr, result, "setting up socket"); xfrin_fail(xfr, result, "setting up socket");
return (result);
} }
/* XXX the resolver could use this, too */ /* XXX the resolver could use this, too */
@@ -711,7 +721,7 @@ render(dns_message_t *msg, isc_buffer_t *buf) {
static void static void
xfrin_connect_done(isc_task_t *task, isc_event_t *event) { xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
isc_socket_connev_t *cev = (isc_socket_connev_t *) event; isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->arg;
isc_result_t evresult = cev->result; isc_result_t evresult = cev->result;
isc_result_t result; isc_result_t result;
task = task; /* Unused */ task = task; /* Unused */
@@ -719,8 +729,10 @@ xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event); isc_event_free(&event);
xfr->connects--; xfr->connects--;
if (maybe_free(xfr)) if (xfr->shuttingdown) {
maybe_free(xfr);
return; return;
}
CHECK(evresult); CHECK(evresult);
xfrin_log(xfr, ISC_LOG_DEBUG(3), "connected"); xfrin_log(xfr, ISC_LOG_DEBUG(3), "connected");
@@ -779,7 +791,7 @@ tuple2msgname(dns_difftuple_t *tuple, dns_message_t *msg, dns_name_t **target)
* Build an *XFR request and send its length prefix. * Build an *XFR request and send its length prefix.
*/ */
static isc_result_t static isc_result_t
xfrin_send_request(xfrin_ctx_t *xfr) { xfrin_send_request(dns_xfrin_ctx_t *xfr) {
isc_result_t result; isc_result_t result;
isc_region_t region; isc_region_t region;
isc_region_t lregion; isc_region_t lregion;
@@ -858,7 +870,7 @@ static void
xfrin_sendlen_done(isc_task_t *task, isc_event_t *event) xfrin_sendlen_done(isc_task_t *task, isc_event_t *event)
{ {
isc_socketevent_t *sev = (isc_socketevent_t *) event; isc_socketevent_t *sev = (isc_socketevent_t *) event;
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->arg;
isc_result_t evresult = sev->result; isc_result_t evresult = sev->result;
isc_result_t result; isc_result_t result;
isc_region_t region; isc_region_t region;
@@ -868,8 +880,10 @@ xfrin_sendlen_done(isc_task_t *task, isc_event_t *event)
isc_event_free(&event); isc_event_free(&event);
xfr->sends--; xfr->sends--;
if (maybe_free(xfr)) if (xfr->shuttingdown) {
maybe_free(xfr);
return; return;
}
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix"); xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
CHECK(evresult); CHECK(evresult);
@@ -888,7 +902,7 @@ static void
xfrin_send_done(isc_task_t *task, isc_event_t *event) xfrin_send_done(isc_task_t *task, isc_event_t *event)
{ {
isc_socketevent_t *sev = (isc_socketevent_t *) event; isc_socketevent_t *sev = (isc_socketevent_t *) event;
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->arg;
isc_result_t result; isc_result_t result;
task = task; /* Unused */ task = task; /* Unused */
@@ -910,7 +924,7 @@ xfrin_send_done(isc_task_t *task, isc_event_t *event)
static void static void
xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
xfrin_ctx_t *xfr = (xfrin_ctx_t *) ev->arg; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) ev->arg;
isc_result_t result; isc_result_t result;
dns_message_t *msg = NULL; dns_message_t *msg = NULL;
dns_name_t *name; dns_name_t *name;
@@ -923,8 +937,10 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
isc_event_free(&ev); isc_event_free(&ev);
xfr->recvs--; xfr->recvs--;
if (maybe_free(xfr)) if (xfr->shuttingdown) {
maybe_free(xfr);
return; return;
}
CHECK(tcpmsg->result); CHECK(tcpmsg->result);
@@ -1032,13 +1048,15 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
/* /*
* Inform the caller we succeeded. * Inform the caller we succeeded.
*/ */
if (xfr->done != NULL) if (xfr->done != NULL) {
(xfr->done)(xfr->zone, ISC_R_SUCCESS); (xfr->done)(xfr->zone, ISC_R_SUCCESS);
xfr->done = NULL;
}
/* /*
* We should have no outstanding events at this * We should have no outstanding events at this
* point, thus maybe_free() should succeed. * point, thus maybe_free() should succeed.
*/ */
RUNTIME_CHECK(maybe_free(xfr) == ISC_TRUE); maybe_free(xfr);
} else { } else {
/* Read the next message. */ /* Read the next message. */
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task, CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
@@ -1058,18 +1076,19 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) {
static void static void
xfrin_timeout(isc_task_t *task, isc_event_t *event) { xfrin_timeout(isc_task_t *task, isc_event_t *event) {
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg; dns_xfrin_ctx_t *xfr = (dns_xfrin_ctx_t *) event->arg;
task = task; /* Unused */ task = task; /* Unused */
isc_event_free(&event); isc_event_free(&event);
/* This will log "giving up: timeout". */ /* This will log "giving up: timeout". */
xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up"); xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
} }
static isc_boolean_t static void
maybe_free(xfrin_ctx_t *xfr) { maybe_free(dns_xfrin_ctx_t *xfr) {
if (! xfr->shuttingdown || xfr->connects != 0 || if (! xfr->shuttingdown || xfr->refcount != 0 ||
xfr->sends != 0 || xfr->recvs != 0) xfr->connects != 0 || xfr->sends != 0 ||
return (ISC_FALSE); xfr->recvs != 0)
return;
xfrin_log(xfr, ISC_LOG_INFO, "end of transfer"); xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
@@ -1080,7 +1099,7 @@ maybe_free(xfrin_ctx_t *xfr) {
isc_timer_detach(&xfr->timer); isc_timer_detach(&xfr->timer);
if (xfr->task != NULL) if (xfr->task != NULL)
isc_task_destroy(&xfr->task); isc_task_detach(&xfr->task);
if (xfr->lasttsig != NULL) { if (xfr->lasttsig != NULL) {
dns_rdata_freestruct(xfr->lasttsig); dns_rdata_freestruct(xfr->lasttsig);
@@ -1111,8 +1130,6 @@ maybe_free(xfrin_ctx_t *xfr) {
dns_zone_detach(&xfr->zone); dns_zone_detach(&xfr->zone);
isc_mem_put(xfr->mctx, xfr, sizeof(*xfr)); isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
return (ISC_TRUE);
} }
/* /*
@@ -1167,7 +1184,7 @@ xfrin_log1(int level, dns_name_t *zonename, isc_sockaddr_t *masteraddr,
/* Logging function for use when there is a xfin_ctx_t. */ /* Logging function for use when there is a xfin_ctx_t. */
static void static void
xfrin_log(xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...) xfrin_log(dns_xfrin_ctx_t *xfr, unsigned int level, const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);

View File

@@ -15,7 +15,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
/* $Id: zone.c,v 1.70 2000/01/28 16:10:47 bwelling Exp $ */ /* $Id: zone.c,v 1.71 2000/01/28 23:48:58 gson Exp $ */
#include <config.h> #include <config.h>
@@ -142,6 +142,7 @@ struct dns_zone {
isc_sockaddr_t notifyfrom; isc_sockaddr_t notifyfrom;
isc_task_t * task; isc_task_t * task;
isc_sockaddr_t xfrsource; isc_sockaddr_t xfrsource;
dns_xfrin_ctx_t * xfr;
/* Access Control Lists */ /* Access Control Lists */
dns_acl_t *update_acl; dns_acl_t *update_acl;
dns_acl_t *query_acl; dns_acl_t *query_acl;
@@ -209,11 +210,11 @@ static isc_result_t default_journal(dns_zone_t *zone);
static void releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); static void releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
static void xfrin_start_temporary_kludge(dns_zone_t *zone); static void xfrin_start_temporary_kludge(dns_zone_t *zone);
static void xfrdone(dns_zone_t *zone, isc_result_t result); static void xfrdone(dns_zone_t *zone, isc_result_t result);
static void zone_shutdown(isc_task_t *, isc_event_t *);
#ifdef notyet #ifdef notyet
static void refresh_callback(isc_task_t *, isc_event_t *); static void refresh_callback(isc_task_t *, isc_event_t *);
static void soa_query(dns_zone_t *, isc_taskaction_t); static void soa_query(dns_zone_t *, isc_taskaction_t);
static void checkservers_callback(isc_task_t *task, isc_event_t *event); static void checkservers_callback(isc_task_t *task, isc_event_t *event);
static void zone_shutdown(isc_task_t *, isc_event_t *);
static int message_count(dns_message_t *msg, dns_section_t section, static int message_count(dns_message_t *msg, dns_section_t section,
dns_rdatatype_t type); dns_rdatatype_t type);
static void add_address_tocheck(dns_message_t *msg, static void add_address_tocheck(dns_message_t *msg,
@@ -315,6 +316,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->idleout = DNS_DEFAULT_IDLEOUT; zone->idleout = DNS_DEFAULT_IDLEOUT;
ISC_LIST_INIT(zone->checkservers); ISC_LIST_INIT(zone->checkservers);
zone->xfrsource = sockaddr_any; zone->xfrsource = sockaddr_any;
zone->xfr = NULL;
zone->maxxfrin = MAX_XFER_TIME; zone->maxxfrin = MAX_XFER_TIME;
zone->maxxfrout = MAX_XFER_TIME; zone->maxxfrout = MAX_XFER_TIME;
zone->diff_on_reload = ISC_FALSE; zone->diff_on_reload = ISC_FALSE;
@@ -2130,15 +2132,16 @@ soa_query(dns_zone_t *zone, isc_taskaction_t callback) {
} }
#endif #endif
#ifdef notyet
static void static void
zone_shutdown(isc_task_t *task, isc_event_t *event) { zone_shutdown(isc_task_t *task, isc_event_t *event) {
dns_zone_t *zone = (dns_zone_t *)event->arg; dns_zone_t *zone = (dns_zone_t *) event->arg;
isc_event_free(&event); isc_event_free(&event);
task = task; /* XXX */ UNUSED(task);
zone = zone; /* XXX */ REQUIRE(DNS_ZONE_VALID(zone));
zone_log(zone, "zone_shutdown", ISC_LOG_DEBUG(3), "shutting down");
if (zone->xfr != NULL)
dns_xfrin_shutdown(zone->xfr);
} }
#endif
static void static void
zone_timer(isc_task_t *task, isc_event_t *event) { zone_timer(isc_task_t *task, isc_event_t *event) {
@@ -2911,6 +2914,7 @@ xfrdone(dns_zone_t *zone, isc_result_t result) {
LOCK(&zone->lock); LOCK(&zone->lock);
INSIST((zone->flags & DNS_ZONE_F_REFRESH) != 0); INSIST((zone->flags & DNS_ZONE_F_REFRESH) != 0);
zone->flags &= ~DNS_ZONE_F_REFRESH; zone->flags &= ~DNS_ZONE_F_REFRESH;
switch (result) { switch (result) {
case DNS_R_UPTODATE: case DNS_R_UPTODATE:
case DNS_R_SUCCESS: case DNS_R_SUCCESS:
@@ -2934,6 +2938,20 @@ xfrdone(dns_zone_t *zone, isc_result_t result) {
break; break;
} }
UNLOCK(&zone->lock); UNLOCK(&zone->lock);
/*
* If creating the transfer object failed, zone->xfr is NULL.
* Otherwise, we are called as the done callback of a zone
* transfer object that just entered its shutting-down
* state. Since we are no longer responsible for shutting
* it down, we can detach our reference.
*/
if (zone->xfr != NULL)
dns_xfrin_detach(&zone->xfr);
/*
* Retry with a different server if necessary.
*/
if (again) if (again)
xfrin_start_temporary_kludge(zone); xfrin_start_temporary_kludge(zone);
} }
@@ -2944,8 +2962,10 @@ xfrdone(dns_zone_t *zone, isc_result_t result) {
static void static void
xfrin_start_temporary_kludge(dns_zone_t *zone) { xfrin_start_temporary_kludge(dns_zone_t *zone) {
isc_result_t result;
isc_sockaddr_t sa; isc_sockaddr_t sa;
in_port_t port; in_port_t port;
if (zone->masterscnt < 1) if (zone->masterscnt < 1)
return; return;
port = zone->masterport; port = zone->masterport;
@@ -2954,10 +2974,12 @@ xfrin_start_temporary_kludge(dns_zone_t *zone) {
isc_sockaddr_fromin(&sa, isc_sockaddr_fromin(&sa,
&zone->masters[zone->curmaster].type.sin.sin_addr, &zone->masters[zone->curmaster].type.sin.sin_addr,
port); port);
dns_xfrin_start(zone, &sa, zone->mctx, result = dns_xfrin_create(zone, &sa, zone->mctx,
zone->zmgr->taskmgr, zone->zmgr->timermgr, zone->zmgr->timermgr, zone->zmgr->socketmgr,
zone->zmgr->socketmgr, zone->task,
xfrdone); xfrdone, &zone->xfr);
if (result != DNS_R_SUCCESS)
xfrdone(zone, result);
} }
isc_result_t isc_result_t
@@ -3054,18 +3076,25 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
zmgr->task, zone_timer, zone, zmgr->task, zone_timer, zone,
&zone->timer); &zone->timer);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto failure; goto cleanup_task;
result = isc_task_onshutdown(zone->task, zone_shutdown, zone);
if (result != ISC_R_SUCCESS)
goto cleanup_timer;
zone->zmgr = zmgr; zone->zmgr = zmgr;
ISC_LIST_APPEND(zmgr->zones, zone, link); ISC_LIST_APPEND(zmgr->zones, zone, link);
goto cleanup; goto unlock;
failure: cleanup_timer:
isc_timer_detach(&zone->timer);
cleanup_task:
if (zone->task != NULL) if (zone->task != NULL)
isc_task_detach(&zone->task); isc_task_detach(&zone->task);
cleanup: unlock:
UNLOCK(&zone->lock); UNLOCK(&zone->lock);
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
return (result); return (result);