#include <isc/formatcheck.h>
#include <isc/mem.h>
+#include <isc/netmgr.h>
#include <isc/print.h>
#include <isc/stats.h>
#include <isc/util.h>
const char *mnemonic; /* Style of transfer */
uint32_t end_serial; /* Serial number after XFR is done */
struct xfr_stats stats; /*%< Transfer statistics */
+
+ /* Timeouts */
+ uint64_t maxtime; /*%< Maximum XFR timeout (in ms) */
+ isc_nm_timer_t *maxtime_timer;
+
+ uint64_t idletime; /*%< XFR idle timeout (in ms) */
} xfrout_ctx_t;
static void
static void
xfrout_ctx_destroy(xfrout_ctx_t **xfrp);
+static void
+xfrout_client_timeout(void *arg, isc_result_t result);
+
static void
xfrout_log1(ns_client_t *client, dns_name_t *zonename, dns_rdataclass_t rdclass,
int level, const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
}
}
+ /* Start the timers */
+ if (xfr->maxtime > 0) {
+ xfrout_log(xfr, ISC_LOG_ERROR,
+ "starting maxtime timer %" PRIu64 " ms",
+ xfr->maxtime);
+ isc_nm_timer_start(xfr->maxtime_timer, xfr->maxtime);
+ }
+
/*
* Hand the context over to sendstream(). Set xfr to NULL;
* sendstream() is responsible for either passing the
bool verified_tsig, unsigned int maxtime,
unsigned int idletime, bool many_answers,
xfrout_ctx_t **xfrp) {
- xfrout_ctx_t *xfr;
- unsigned int len;
- void *mem;
+ xfrout_ctx_t *xfr = NULL;
+ unsigned int len = NS_CLIENT_TCP_BUFFER_SIZE;
+ void *mem = NULL;
REQUIRE(xfrp != NULL && *xfrp == NULL);
- UNUSED(maxtime);
- UNUSED(idletime);
-
xfr = isc_mem_get(mctx, sizeof(*xfr));
- xfr->mctx = NULL;
+ *xfr = (xfrout_ctx_t){
+ .client = client,
+ .id = id,
+ .qname = qname,
+ .qtype = qtype,
+ .qclass = qclass,
+ .maxtime = maxtime * 1000, /* in milliseconds */
+ .idletime = idletime * 1000, /* In milliseconds */
+ .tsigkey = tsigkey,
+ .lasttsig = lasttsig,
+ .verified_tsig = verified_tsig,
+ .many_answers = many_answers,
+ };
+
isc_mem_attach(mctx, &xfr->mctx);
- xfr->client = client;
- xfr->id = id;
- xfr->qname = qname;
- xfr->qtype = qtype;
- xfr->qclass = qclass;
- xfr->zone = NULL;
- xfr->db = NULL;
- xfr->ver = NULL;
+
if (zone != NULL) { /* zone will be NULL if it's DLZ */
dns_zone_attach(zone, &xfr->zone);
}
dns_db_attach(db, &xfr->db);
dns_db_attachversion(db, ver, &xfr->ver);
- xfr->question_added = false;
- xfr->end_of_stream = false;
- xfr->tsigkey = tsigkey;
- xfr->lasttsig = lasttsig;
- xfr->verified_tsig = verified_tsig;
- xfr->many_answers = many_answers;
- xfr->sends = 0;
- xfr->shuttingdown = false;
- xfr->poll = false;
- xfr->mnemonic = NULL;
- xfr->buf.base = NULL;
- xfr->buf.length = 0;
- xfr->txmem = NULL;
- xfr->txmemlen = 0;
- xfr->stream = NULL;
- xfr->quota = NULL;
-
- xfr->stats.nmsg = 0;
- xfr->stats.nrecs = 0;
- xfr->stats.nbytes = 0;
+
isc_time_now(&xfr->stats.start);
+ isc_nm_timer_create(xfr->client->handle, xfrout_client_timeout, xfr,
+ &xfr->maxtime_timer);
+
/*
* Allocate a temporary buffer for the uncompressed response
- * message data. The size should be no more than 65535 bytes
- * so that the compressed data will fit in a TCP message,
- * and no less than 65535 bytes so that an almost maximum-sized
- * RR will fit. Note that although 65535-byte RRs are allowed
- * in principle, they cannot be zone-transferred (at least not
- * if uncompressible), because the message and RR headers would
- * push the size of the TCP message over the 65536 byte limit.
+ * message data. The buffer size must be 65535 bytes
+ * (NS_CLIENT_TCP_BUFFER_SIZE): small enough that compressed
+ * data will fit in a single TCP message, and big enough to
+ * hold a maximum-sized RR.
+ *
+ * Note that although 65535-byte RRs are allowed in principle, they
+ * cannot be zone-transferred (at least not if uncompressible),
+ * because the message and RR headers would push the size of the
+ * TCP message over the 65536 byte limit.
*/
- len = 65535;
mem = isc_mem_get(mctx, len);
isc_buffer_init(&xfr->buf, mem, len);
* Allocate another temporary buffer for the compressed
* response message.
*/
- len = NS_CLIENT_TCP_BUFFER_SIZE;
mem = isc_mem_get(mctx, len);
isc_buffer_init(&xfr->txbuf, (char *)mem, len);
xfr->txmem = mem;
isc_nmhandle_attach(xfr->client->handle,
&xfr->client->sendhandle);
+ if (xfr->idletime > 0) {
+ isc_nmhandle_setwritetimeout(xfr->client->sendhandle,
+ xfr->idletime);
+ }
isc_nm_send(xfr->client->sendhandle, &used, xfrout_senddone,
xfr);
xfr->sends++;
INSIST(xfr->sends == 0);
+ isc_nm_timer_stop(xfr->maxtime_timer);
+ isc_nm_timer_detach(&xfr->maxtime_timer);
+
if (xfr->stream != NULL) {
xfr->stream->methods->destroy(&xfr->stream);
}
xfrout_ctx_destroy(&xfr);
}
+static void
+xfrout_client_timeout(void *arg, isc_result_t result) {
+ xfrout_ctx_t *xfr = (xfrout_ctx_t *)arg;
+
+ xfr->shuttingdown = true;
+ xfrout_log(xfr, ISC_LOG_ERROR, "%s: %s", "aborted",
+ isc_result_totext(result));
+}
+
/*
* Log outgoing zone transfer messages in a format like
* <client>: transfer of <zone>: <message>