Commit 54256d16 authored by Marek Vavruša's avatar Marek Vavruša

events: reimplemented flush/xfer

- AXFR only
- no TSIG
- AXFR logging is not finished
parent 89ad4954
......@@ -19,6 +19,7 @@
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/updates/xfr-in.h"
#include "knot/zone/zonefile.h"
#include "common/debug.h"
#include "common/descriptor.h"
#include "common/lists.h"
......@@ -84,7 +85,7 @@ static int axfr_process_node_tree(knot_pkt_t *pkt, const void *item, struct xfr_
return ret;
}
static void axfr_answer_cleanup(struct query_data *qdata)
static void axfr_query_cleanup(struct query_data *qdata)
{
struct axfr_proc *axfr = (struct axfr_proc *)qdata->ext;
mm_ctx_t *mm = qdata->mm;
......@@ -96,7 +97,7 @@ static void axfr_answer_cleanup(struct query_data *qdata)
rcu_read_unlock();
}
static int axfr_answer_init(struct query_data *qdata)
static int axfr_query_init(struct query_data *qdata)
{
assert(qdata);
......@@ -121,7 +122,7 @@ static int axfr_answer_init(struct query_data *qdata)
/* Set up cleanup callback. */
qdata->ext = axfr;
qdata->ext_cleanup = &axfr_answer_cleanup;
qdata->ext_cleanup = &axfr_query_cleanup;
/* No zone changes during multipacket answer (unlocked in axfr_answer_cleanup) */
rcu_read_lock();
......@@ -173,10 +174,10 @@ int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb process_item, struct query_data
}
/* AXFR-specific logging (internal, expects 'qdata' variable set). */
#define AXFR_LOG(severity, msg...) \
#define AXFR_QLOG(severity, msg...) \
ANSWER_LOG(severity, qdata, "Outgoing AXFR", msg)
int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
int axfr_query(knot_pkt_t *pkt, struct query_data *qdata)
{
assert(pkt);
assert(qdata);
......@@ -198,12 +199,12 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
NS_NEED_AUTH(qdata->zone->xfr_out, qdata);
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Check expiration. */
ret = axfr_answer_init(qdata);
ret = axfr_query_init(qdata);
if (ret != KNOT_EOK) {
AXFR_LOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
AXFR_QLOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
return ret;
} else {
AXFR_LOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
AXFR_QLOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
}
}
......@@ -218,59 +219,126 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
return NS_PROC_FULL; /* Check for more. */
case KNOT_EOK: /* Last response. */
gettimeofday(&now, NULL);
AXFR_LOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).",
AXFR_QLOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).",
time_diff(&axfr->proc.tstamp, &now) / 1000.0,
axfr->proc.npkts, axfr->proc.nbytes / 1024.0);
return NS_PROC_DONE;
break;
default: /* Generic error. */
AXFR_LOG(LOG_ERR, "%s", knot_strerror(ret));
AXFR_QLOG(LOG_ERR, "%s", knot_strerror(ret));
return NS_PROC_FAIL;
}
}
#undef AXFR_QLOG
int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
static void axfr_answer_cleanup(struct answer_data *data)
{
struct xfr_proc *proc = data->ext;
if (proc) {
zone_contents_deep_free(&proc->zone);
mm_free(data->mm, proc);
data->ext = NULL;
}
}
static int axfr_answer_init(struct answer_data *data)
{
#warning TODO: reimplement axfr_process_answer
#if 0
assert(data);
/* Create new zone contents. */
zone_t *zone = data->param->zone;
zone_contents_t *new_contents = zone_contents_new(zone->name);
if (new_contents == NULL) {
return KNOT_ENOMEM;
}
/* Create new processing context. */
struct xfr_proc *proc = mm_alloc(data->mm, sizeof(struct xfr_proc));
if (proc == NULL) {
zone_contents_deep_free(&new_contents);
return KNOT_ENOMEM;
}
memset(proc, 0, sizeof(struct xfr_proc));
proc->zone = new_contents;
gettimeofday(&proc->tstamp, NULL);
/* Set up cleanup callback. */
data->ext = proc;
data->ext_cleanup = &axfr_answer_cleanup;
return KNOT_EOK;
}
/* AXFR-specific logging (internal, expects 'data' variable set). */
#define AXFR_QRLOG(severity, msg...) \
fprintf(stderr, "Incoming AXFR: " msg)
static int axfr_answer_finalize(struct answer_data *data)
{
struct timeval now;
gettimeofday(&now, NULL);
/*
* Here we assume that 'xfr' contains TSIG information
* and the digest of the query sent to the master or the previous
* digest.
* Adjust zone so that node count is set properly and nodes are
* marked authoritative / delegation point.
*/
struct xfr_proc *proc = data->ext;
int rc = zone_contents_adjust_full(proc->zone, NULL, NULL);
if (rc != KNOT_EOK) {
return rc;
}
/* Write zone file. */
zone_t *zone = data->param->zone;
rc = zonefile_write(zone->conf->file, proc->zone, data->param->remote);
if (rc != KNOT_EOK) {
return rc;
}
/* Switch contents. */
zone_contents_t *old_contents = xfrin_switch_zone(zone, proc->zone);
AXFR_QRLOG(LOG_INFO, "Serial %u -> %u\n",
zone_contents_serial(old_contents),
zone_contents_serial(proc->zone));
AXFR_QRLOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).\n",
time_diff(&proc->tstamp, &now) / 1000.0,
proc->npkts, proc->nbytes / 1024.0);
/* Do not free new contents with cleanup. */
zone_contents_deep_free(&old_contents);
proc->zone = NULL;
return KNOT_EOK;
}
int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
{
/* Initialize processing context. */
int ret = KNOT_EOK;
if (data->ext == NULL) {
ret = axfr_answer_init(data);
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
}
dbg_ns("ns_process_axfrin: incoming packet, wire size: %zu\n",
xfr->wire_size);
int ret = xfrin_process_axfr_packet(pkt, xfr, (zone_contents_t **)&xfr->data);
ret = xfrin_process_axfr_packet(pkt, (struct xfr_proc *)data->ext);
if (ret > 0) { // transfer finished
dbg_ns("ns_process_axfrin: AXFR finished, zone created.\n");
gettimeofday(&xfr->t_end, NULL);
/*
* Adjust zone so that node count is set properly and nodes are
* marked authoritative / delegation point.
*/
zone_contents_t *zone = (zone_contents_t *)xfr->data;
assert(zone != NULL);
log_zone_info("%s Serial %u -> %u\n", xfr->msg,
zone_contents_serial(xfr->zone->contents),
zone_contents_serial(zone));
dbg_ns_verb("ns_process_axfrin: adjusting zone.\n");
int rc = zone_contents_adjust_full(zone, NULL, NULL);
if (rc != KNOT_EOK) {
return rc;
ret = axfr_answer_finalize(data);
if (ret == KNOT_EOK) {
return NS_PROC_DONE;
}
// save the zone contents to the xfr->data
xfr->new_contents = zone;
xfr->flags |= XFR_FLAG_AXFR_FINISHED;
return KNOT_EOK;
}
return ret;
#endif
return KNOT_ENOTSUP;
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
return NS_PROC_MORE;
}
#undef AXFR_LOG
#undef AXFR_QRLOG
......@@ -39,6 +39,7 @@ struct xfr_proc {
unsigned npkts; /* Packets processed. */
unsigned nbytes; /* Bytes processed. */
struct timeval tstamp; /* Start time. */
zone_contents_t *zone; /* Processed zone. */
};
/*! \brief Generic transfer processing (reused for IXFR).
......@@ -57,7 +58,7 @@ int xfr_process_list(knot_pkt_t *pkt, xfr_put_cb put, struct query_data *qdata);
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
*/
int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata);
int axfr_query(knot_pkt_t *pkt, struct query_data *qdata);
/*!
* \brief Processes an AXFR query response.
......
......@@ -28,6 +28,7 @@
#define _KNOT_INTERNET_H_
#include "libknot/packet/pkt.h"
#include "knot/zone/contents.h"
/* Query data (from query processing). */
struct query_data;
......
......@@ -308,7 +308,7 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
case KNOT_ENOENT:
IXFR_LOG(LOG_INFO, "Incomplete history, fallback to AXFR.");
qdata->packet_type = KNOT_QUERY_AXFR; /* Solve as AXFR. */
return axfr_answer(pkt, qdata);
return axfr_query(pkt, qdata);
default: /* Server errors. */
IXFR_LOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
return NS_PROC_FAIL;
......
......@@ -28,7 +28,6 @@
#define _KNOT_IXFR_H_
#include "libknot/packet/pkt.h"
#include "knot/zone/zonedb.h"
struct query_data;
struct answer_data;
......
......@@ -40,25 +40,6 @@
/* API functions */
/*----------------------------------------------------------------------------*/
knot_pkt_t *notify_create_query(const zone_t *zone, mm_ctx_t *mm)
{
if (zone == NULL || zone->contents == NULL) {
return NULL;
}
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, mm);
if (pkt == NULL) {
return NULL;
}
zone_node_t *apex = zone->contents->apex;
knot_wire_set_aa(pkt->wire);
knot_wire_set_opcode(pkt->wire, KNOT_OPCODE_NOTIFY);
knot_pkt_put_question(pkt, apex->owner, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
return pkt;
}
/* NOTIFY-specific logging (internal, expects 'qdata' variable set). */
#define NOTIFY_LOG(severity, msg...) \
QUERY_LOG(severity, qdata, "NOTIFY", msg)
......
......@@ -30,25 +30,13 @@
#include <stdint.h>
#include <string.h>
#include "knot/zone/zone.h"
#include "libknot/packet/pkt.h"
#include "knot/zone/zonedb.h"
#include "common/lists.h"
#include "common/sockaddr.h"
#include "knot/zone/contents.h"
struct query_data;
#define NOTIFY_TIMEOUT 3 /*!< Interval between NOTIFY retries. */
/*!
* \brief Creates a NOTIFY request message for SOA RR of the given zone.
*
* \param zone Zone for which a query should be created.
*
* \return new packet
*/
knot_pkt_t *notify_create_query(const zone_t *zone, mm_ctx_t *mm);
/*!
* \brief Answer IN class zone NOTIFY message (RFC1996).
*
......
......@@ -102,6 +102,7 @@ static int answer_internet(knot_pkt_t *pkt, knot_process_t *ctx)
next_state = internet_answer(pkt, data);
break;
case KNOT_RESPONSE_AXFR:
next_state = axfr_process_answer(pkt, data);
break;
case KNOT_RESPONSE_IXFR:
break;
......
......@@ -369,7 +369,7 @@ static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
next_state = internet_notify(pkt, data);
break;
case KNOT_QUERY_AXFR:
next_state = axfr_answer(pkt, data);
next_state = axfr_query(pkt, data);
break;
case KNOT_QUERY_IXFR:
next_state = ixfr_answer(pkt, data);
......
......@@ -39,6 +39,7 @@
#include "common/descriptor.h"
#include "libknot/util/utils.h"
#include "libknot/rdata/soa.h"
#include "knot/nameserver/axfr.h"
#define KNOT_NS_TSIG_FREQ 100
......@@ -240,44 +241,30 @@ static void xfrin_take_rr(const knot_pktsection_t *answer, const knot_rrset_t **
/*----------------------------------------------------------------------------*/
int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, zone_contents_t **zone)
int xfrin_process_axfr_packet(knot_pkt_t *pkt, struct xfr_proc *proc)
{
if (pkt == NULL) {
return KNOT_EINVAL;
}
int ret = KNOT_EOK;
uint16_t rr_id = 0;
const knot_rrset_t *rr = NULL;
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
xfrin_take_rr(answer, &rr, &rr_id);
if (*zone == NULL) {
if (rr == NULL) {
// Empty transfer.
return KNOT_EMALF;
}
// Transfer start, init zone
if (rr->type != KNOT_RRTYPE_SOA) {
return KNOT_EMALF;
}
*zone = zone_contents_new(rr->owner);
if (*zone == NULL) {
return KNOT_ENOMEM;
}
xfr->packet_nr = 0;
} else {
++xfr->packet_nr;
}
++proc->npkts;
// Init zone creator
zcreator_t zc = {.z = *zone,
zcreator_t zc = {.z = proc->zone,
.master = false, .ret = KNOT_EOK };
while (rr) {
if (rr->type == KNOT_RRTYPE_SOA &&
node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) {
// Last SOA, last message, check TSIG.
int ret = xfrin_check_tsig(pkt, xfr, 1);
// int ret = xfrin_check_tsig(pkt, xfr, 1);
#warning TODO: TSIG API
if (ret != KNOT_EOK) {
return ret;
}
......@@ -293,7 +280,9 @@ int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, zone_contents
}
// Check possible TSIG at the end of DNS message.
return xfrin_check_tsig(pkt, xfr, knot_ns_tsig_required(xfr->packet_nr));
// return xfrin_check_tsig(pkt, xfr, knot_ns_tsig_required(xfr->packet_nr));
#warning TODO: TSIG API
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
......
......@@ -36,6 +36,8 @@
#include "knot/server/xfr-handler.h"
#include "knot/updates/changesets.h"
struct xfr_proc;
/*----------------------------------------------------------------------------*/
typedef enum xfrin_transfer_result {
......@@ -114,7 +116,7 @@ int xfrin_create_ixfr_query(const zone_t *zone, knot_pkt_t *pkt);
*
* \todo Refactor!!!
*/
int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, zone_contents_t **zone);
int xfrin_process_axfr_packet(knot_pkt_t *pkt, struct xfr_proc *proc);
/*!
* \brief Destroys the whole changesets structure.
......
......@@ -28,10 +28,45 @@
#include "knot/zone/zone-load.h"
#include "knot/zone/zonefile.h"
#include "libknot/rdata/soa.h"
#include "libknot/dnssec/random.h"
#include "knot/nameserver/internet.h"
#include "knot/nameserver/notify.h"
#include "knot/nameserver/requestor.h"
#include "knot/nameserver/process_answer.h"
#define BOOTSTRAP_RETRY (30) /*!< Interval between AXFR bootstrap retries. */
#define BOOTSTRAP_MAXTIME (24*60*60) /*!< Maximum AXFR retry interval cap of 24 hours. */
/*! \brief Progressive bootstrap retry timer. */
static void bootstrap_next(uint32_t *timer)
{
*timer *= 2;
*timer += knot_random_uint32_t() % BOOTSTRAP_RETRY;
if (*timer > BOOTSTRAP_MAXTIME) {
*timer = BOOTSTRAP_MAXTIME;
}
}
static knot_pkt_t *zone_query(const zone_t *zone, uint16_t qtype, mm_ctx_t *mm)
{
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, mm);
if (pkt == NULL) {
return NULL;
}
knot_wire_set_aa(pkt->wire);
knot_pkt_put_question(pkt, zone->name, KNOT_CLASS_IN, qtype);
/* Put current SOA in authority (optional). */
zone_contents_t *contents = zone->contents;
if (!zone_contents_is_empty(contents)) {
knot_rrset_t soa_rr = node_rrset(contents->apex, KNOT_RRTYPE_SOA);
knot_pkt_put(pkt, COMPR_HINT_QNAME, &soa_rr, 0);
}
return pkt;
}
/* -- zone events handling callbacks --------------------------------------- */
typedef int (*zone_event_cb)(zone_t *zone);
......@@ -89,8 +124,11 @@ static int event_reload(zone_t *zone)
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
zone_events_schedule(zone, ZONE_EVENT_EXPIRE, knot_soa_expire(soa));
}
zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW + 10);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone_config->dbsync_timeout);
if (!zone_contents_is_empty(contents)) {
zone->xfr_in.bootstrap_retry = ZONE_EVENT_NOW;
zone_events_schedule(zone, ZONE_EVENT_NOTIFY, zone->xfr_in.bootstrap_retry);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone_config->dbsync_timeout);
}
log_zone_info("Zone '%s' loaded.\n", zone_config->name);
return KNOT_EOK;
......@@ -108,7 +146,7 @@ static int event_refresh(zone_t *zone)
zone_contents_t *contents = zone->contents;
if (contents == NULL) {
/* No contents, schedule retransfer now. */
zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW);
zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW);
return KNOT_EOK;
}
......@@ -119,54 +157,109 @@ static int event_refresh(zone_t *zone)
}
/* Create a memory pool for this task. */
int ret = KNOT_EOK;
mm_ctx_t mm;
mm_ctx_mempool(&mm, 4096);
char addr_str[SOCKADDR_STRLEN] = {'\0'};
/* Create a SOA query. */
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &mm);
knot_pkt_t *query = zone_query(zone, KNOT_RRTYPE_SOA, &mm);
if (query == NULL) {
mp_delete(mm.ctx);
return KNOT_ENOMEM;
}
zone_node_t *apex = contents->apex;
knot_pkt_put_question(query, apex->owner, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
/* Create requestor instance. */
struct process_answer_param param;
struct requestor re;
requestor_init(&re, &mm);
re.origin = &master->via;
re.remote = &master->addr;
requestor_init(&re, NS_PROC_ANSWER, &mm);
/* Create a request. */
struct request *req = requestor_make(&re, &master->via, &master->addr, query);
struct process_answer_param param;
param.zone = zone;
param.query = query;
param.remote = &master->addr;
char addr_str[SOCKADDR_STRLEN] = {'\0'};
sockaddr_tostr(&master->addr, addr_str, sizeof(addr_str));
requestor_enqueue(&re, req, &param);
/* Execute the SOA request. */
struct timeval tv = { conf()->max_conn_hs, 0 };
requestor_enqueue(&re, query, NS_PROC_ANSWER, &param);
int ret = requestor_exec(&re, &tv);
ret = requestor_exec(&re, &tv);
if (ret != KNOT_EOK) {
sockaddr_tostr(&master->addr, addr_str, sizeof(addr_str));
log_zone_error("SOA query for '%s' to '%s': %s\n",
zone->conf->name, addr_str, knot_strerror(ret));
}
/*! \todo Try another master if it fails. */
requestor_clear(&re);
/* Reschedule retry. */
knot_rdataset_t *soa = node_rdataset(apex, KNOT_RRTYPE_SOA);
knot_rdataset_t *soa = node_rdataset(contents->apex, KNOT_RRTYPE_SOA);
zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_retry(soa));
mp_delete(mm.ctx);
return KNOT_EOK;
return ret;
}
static int event_xfer(zone_t *zone)
{
assert(zone);
fprintf(stderr, "XFER of '%s'\n", zone->conf->name);
#warning TODO: implement event_xfer
return KNOT_ENOTSUP;
const conf_iface_t *master = zone_master(zone);
if (master == NULL) {
return KNOT_EOK;
}
/* Create a memory pool for this task. */
int ret = KNOT_EOK;
mm_ctx_t mm;
mm_ctx_mempool(&mm, 4096);
char addr_str[SOCKADDR_STRLEN] = {'\0'};
/* Create a zone transfer request. */
/*! \todo Select transfer mode. */
knot_pkt_t *query = zone_query(zone, KNOT_RRTYPE_AXFR, &mm);
if (query == NULL) {
return KNOT_ENOMEM;
}
/* Create requestor instance. */
struct requestor re;
requestor_init(&re, NS_PROC_ANSWER, &mm);
/* Create a request. */
struct request *req = requestor_make(&re, &master->via, &master->addr, query);
struct process_answer_param param;
param.zone = zone;
param.query = query;
param.remote = &master->addr;
requestor_enqueue(&re, req, &param);
/* Execute the request. */
struct timeval tv = { conf()->max_conn_hs, 0 };
ret = requestor_exec(&re, &tv);
if (ret != KNOT_EOK) {
sockaddr_tostr(&master->addr, addr_str, sizeof(addr_str));
log_zone_error("Zone transfer of '%s' to '%s': %s\n",
zone->conf->name, addr_str, knot_strerror(ret));
}
requestor_clear(&re);
/* Reschedule retry. */
if (zone_contents_is_empty(zone->contents)) {
/* Progressive retry interval up to AXFR_RETRY_MAXTIME */
bootstrap_next(&zone->xfr_in.bootstrap_retry);
} else {
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_retry(soa));
zone_events_schedule(zone, ZONE_EVENT_NOTIFY, zone->xfr_in.bootstrap_retry);
zone->xfr_in.bootstrap_retry = 0;
}
mp_delete(mm.ctx);
return ret;
}
static int event_expire(zone_t *zone)
......@@ -187,29 +280,14 @@ static int event_flush(zone_t *zone)
{
assert(zone);
fprintf(stderr, "FLUSH of '%s'\n", zone->conf->name);
#warning TODO: implement event_flush
#if 0
assert(event);
dbg_zones("zone: zonefile SYNC timer event\n");
/* Fetch zone. */
zone_t *zone = (zone_t *)event->data;
if (!zone) {
return KNOT_EINVAL;
}
int ret = zones_zonefile_sync_from_ev(zone);
/* Reschedule. */
rcu_read_lock();
int next_timeout = zone->conf->dbsync_timeout;
if (next_timeout > 0) {
zones_schedule_zonefile_sync(zone, next_timeout * 1000);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, next_timeout);
}
rcu_read_unlock();
return ret;
#endif
return KNOT_ENOTSUP;
return zone_flush_journal(zone);
}
static int event_notify(zone_t *zone)
......@@ -218,44 +296,43 @@ static int event_notify(zone_t *zone)
fprintf(stderr, "NOTIFY of '%s'\n", zone->conf->name);
/* Create a memory pool for this task. */
int ret = KNOT_EOK;
mm_ctx_t mm;
mm_ctx_mempool(&mm, 4096);
char addr_str[SOCKADDR_STRLEN] = {'\0'};
/* Create requestor instance. */
struct process_answer_param param;
struct requestor re;
requestor_init(&re, &mm);
requestor_init(&re, NS_PROC_ANSWER, &mm);
struct process_answer_param param = { '\0' };
param.zone = zone;
/* Walk through configured remotes and send messages. */
int ret = KNOT_EOK;
conf_remote_t *remote = 0;
WALK_LIST(remote, zone->conf->acl.notify_out) {
conf_iface_t *iface = remote->remote;
char addr_str[SOCKADDR_STRLEN] = {'\0'};
sockaddr_tostr(&iface->addr, addr_str, sizeof(addr_str));
/* Create notification message. */
#warning TODO: streamline API so the requestor only gets a function to build a packet
knot_pkt_t *query = notify_create_query(zone, &mm);
knot_pkt_t *query = zone_query(zone, KNOT_RRTYPE_SOA, &mm);
knot_wire_set_opcode(query->wire, KNOT_OPCODE_NOTIFY);
if (query == NULL) {
mp_delete(mm.ctx);
return KNOT_ENOMEM;
ret = KNOT_ENOMEM;
break;
}
#warning TODO: requestor should accept remote/origin/key per-request
#warning this would make an API to allow multiple requests processed at once
re.origin = &iface->via;
re.remote = &iface->addr;
param.zone = zone;
param.query = query;
/* Create a request. */
struct request *req = requestor_make(&re, &iface->via, &iface->addr, query);
param.remote = &iface->addr;
param.query = query;
requestor_enqueue(&re, req, &param);
/* Execute the NOTIFY message. */
struct timeval tv = { zone->conf->notify_timeout, 0 };
requestor_enqueue(&re, query, NS_PROC_ANSWER, &param);
ret = requestor_exec(&re, &tv);
log_zone_error("NOTIFY message for '%s' to '%s': %s\n",
zone->conf->name, addr_str, knot_strerror(ret));
if (ret != KNOT_EOK) {
sockaddr_tostr(&iface->addr, addr_str, sizeof(addr_str));
log_zone_error("NOTIFY message for '%s' to '%s': %s\n",
zone->conf->name, addr_str, knot_strerror(ret));
}
}
requestor_clear(&re);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment