* SOFTWARE.
*/
- /* $Id: xfrin.c,v 1.29 1999/12/02 05:11:28 gson Exp $ */
+ /* $Id: xfrin.c,v 1.30 1999/12/02 22:33:15 gson Exp $ */
#include <config.h>
isc_timer_t *timer;
isc_socketmgr_t *socketmgr;
- int recvs; /* Number of receives in progress */
- int tasks; /* Number of active tasks (0 or 1) */
+ int connects; /* Connect in progress */
+ int sends; /* Send in progress */
+ int recvs; /* Receive in progress */
+ isc_boolean_t shuttingdown;
- dns_name_t name; /* Name of zone to transfer */
+ dns_name_t name; /* Name of zone to transfer */
dns_rdataclass_t rdclass;
/*
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_timeout(isc_task_t *task, isc_event_t *event);
-static void xfrin_shutdown(isc_task_t *task, isc_event_t *event);
static isc_boolean_t maybe_free(xfrin_ctx_t *xfr);
return;
}
-static void xfrin_cleanup(xfrin_ctx_t *xfr) {
- xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
- isc_socket_cancel(xfr->socket, xfr->task, ISC_SOCKSHUT_ALL); /* XXX? */
- isc_socket_detach(&xfr->socket);
- isc_timer_detach(&xfr->timer);
- isc_task_destroy(&xfr->task);
- if (xfr->lasttsig != NULL) {
- dns_rdata_freestruct(xfr->lasttsig);
- isc_mem_put(xfr->mctx, xfr->lasttsig, sizeof(*xfr->lasttsig));
- }
- /* The rest will be done when the task runs its shutdown event. */
-}
-
static void
xfrin_fail(xfrin_ctx_t *xfr, isc_result_t result, char *msg) {
if (result != DNS_R_UPTODATE) {
xfrin_log(xfr, ISC_LOG_ERROR, "%s: %s",
msg, isc_result_totext(result));
}
- xfrin_cleanup(xfr);
+ xfr->shuttingdown = ISC_TRUE;
+ if (xfr->connects > 0) {
+ isc_socket_cancel(xfr->socket, xfr->task,
+ ISC_SOCKCANCEL_CONNECT);
+ } else if (xfr->recvs > 0) {
+ dns_tcpmsg_cancelread(&xfr->tcpmsg);
+ } else if (xfr->sends > 0) {
+ isc_socket_cancel(xfr->socket, xfr->task,
+ ISC_SOCKCANCEL_SEND);
+ }
+ maybe_free(xfr);
}
static dns_result_t
xfr->timer = NULL;
xfr->socketmgr = socketmgr;
+ xfr->connects = 0;
+ xfr->sends = 0;
xfr->recvs = 0;
- xfr->tasks = 1;
+ xfr->shuttingdown = ISC_FALSE;
dns_name_init(&xfr->name, NULL);
xfr->rdclass = rdclass;
xfr->axfr.add_func = NULL;
xfr->axfr.add_private = NULL;
- isc_task_onshutdown(xfr->task, xfrin_shutdown, xfr);
-
CHECK(dns_name_dup(zonename, mctx, &xfr->name));
isc_interval_set(&interval, dns_zone_getxfrtime(xfr->zone), 0);
return (DNS_R_SUCCESS);
failure:
- xfrin_cleanup(xfr);
+ xfrin_fail(xfr, result, "creating transfer context");
return (result);
}
&xfr->socket));
CHECK(isc_socket_connect(xfr->socket, &xfr->master, xfr->task,
xfrin_connect_done, xfr));
+ xfr->connects++;
return;
failure:
xfrin_fail(xfr, result, "setting up socket");
xfrin_connect_done(isc_task_t *task, isc_event_t *event) {
isc_socket_connev_t *cev = (isc_socket_connev_t *) event;
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg;
+ dns_result_t evresult = cev->result;
dns_result_t result;
task = task; /* Unused */
INSIST(event->type == ISC_SOCKEVENT_CONNECT);
+ isc_event_free(&event);
- CHECK(cev->result);
+ xfr->connects--;
+ if (maybe_free(xfr))
+ return;
+
+ CHECK(evresult);
xfrin_log(xfr, ISC_LOG_DEBUG(3), "connected");
dns_tcpmsg_init(xfr->mctx, xfr->socket, &xfr->tcpmsg);
CHECK(xfrin_send_request(xfr));
failure:
- isc_event_free(&event);
if (result != DNS_R_SUCCESS)
xfrin_fail(xfr, result, "connect");
}
lregion.length = 2;
CHECK(isc_socket_send(xfr->socket, &lregion, xfr->task,
xfrin_sendlen_done, xfr));
+ xfr->sends++;
failure:
if (msg != NULL)
{
isc_socketevent_t *sev = (isc_socketevent_t *) event;
xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg;
+ dns_result_t evresult = sev->result;
dns_result_t result;
isc_region_t region;
task = task; /* Unused */
INSIST(event->type == ISC_SOCKEVENT_SENDDONE);
+ isc_event_free(&event);
+
+ xfr->sends--;
+ if (maybe_free(xfr))
+ return;
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request length prefix");
- CHECK(sev->result);
+ CHECK(evresult);
isc_buffer_used(&xfr->qbuffer, ®ion);
CHECK(isc_socket_send(xfr->socket, ®ion, xfr->task,
xfrin_send_done, xfr));
+ xfr->sends++;
failure:
- isc_event_free(&event);
if (result != DNS_R_SUCCESS)
xfrin_fail(xfr, result, "sending request length prefix");
}
task = task; /* Unused */
INSIST(event->type == ISC_SOCKEVENT_SENDDONE);
-
+
+ xfr->sends--;
xfrin_log(xfr, ISC_LOG_DEBUG(3), "sent request data");
CHECK(sev->result);
dns_message_destroy(&msg);
if (xfr->state == XFRST_END) {
- xfrin_cleanup(xfr);
+ xfr->shuttingdown = ISC_TRUE;
+ /*
+ * We should have no outstanding events at this
+ * point, thus maybe_free() should succeed.
+ */
+ RUNTIME_CHECK(maybe_free(xfr) == ISC_TRUE);
} else {
/* Read the next message. */
CHECK(dns_tcpmsg_readmessage(&xfr->tcpmsg, xfr->task,
xfrin_fail(xfr, ISC_R_TIMEDOUT, "giving up");
}
-static void
-xfrin_shutdown(isc_task_t *task, isc_event_t *event) {
- xfrin_ctx_t *xfr = (xfrin_ctx_t *) event->arg;
- task = task; /* Unused */
- INSIST(event->type == ISC_TASKEVENT_SHUTDOWN);
- isc_event_free(&event);
- xfrin_log(xfr, ISC_LOG_DEBUG(3), "shutting down");
- xfr->tasks--;
- maybe_free(xfr);
-}
-
static isc_boolean_t
maybe_free(xfrin_ctx_t *xfr) {
- INSIST(xfr->tasks >= 0);
- INSIST(xfr->recvs >= 0);
- if (xfr->tasks != 0 || xfr->recvs != 0)
+ if (! xfr->shuttingdown || xfr->connects != 0 ||
+ xfr->sends != 0 || xfr->recvs != 0)
return (ISC_FALSE);
- xfrin_log(xfr, ISC_LOG_DEBUG(3), "freeing context");
-
+ xfrin_log(xfr, ISC_LOG_INFO, "end of transfer");
+
+ if (xfr->socket != NULL)
+ isc_socket_detach(&xfr->socket);
+
+ if (xfr->timer != NULL)
+ isc_timer_detach(&xfr->timer);
+
+ if (xfr->task != NULL)
+ isc_task_destroy(&xfr->task);
+
+ if (xfr->lasttsig != NULL) {
+ dns_rdata_freestruct(xfr->lasttsig);
+ isc_mem_put(xfr->mctx, xfr->lasttsig, sizeof(*xfr->lasttsig));
+ }
+
dns_diff_clear(&xfr->diff);
if (xfr->ixfr.journal != NULL)
xfrin_logv(level, &xfr->name, &xfr->master, fmt, ap);
va_end(ap);
}
-