Commit 39b415d6 authored by Marek Vavruša's avatar Marek Vavruša

events: UPDATE/IXFR event processing, xfers, cleanup

parent 972e6b9f
......@@ -174,8 +174,8 @@ 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_QLOG(severity, msg...) \
ANSWER_LOG(severity, qdata, "Outgoing AXFR", msg)
#define AXFROUT_LOG(severity, msg...) \
QUERY_LOG(severity, qdata, "Outgoing AXFR", msg)
int axfr_query(knot_pkt_t *pkt, struct query_data *qdata)
{
......@@ -201,10 +201,10 @@ int axfr_query(knot_pkt_t *pkt, struct query_data *qdata)
ret = axfr_query_init(qdata);
if (ret != KNOT_EOK) {
AXFR_QLOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
AXFROUT_LOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
return ret;
} else {
AXFR_QLOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
AXFROUT_LOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
}
}
......@@ -219,13 +219,13 @@ int axfr_query(knot_pkt_t *pkt, struct query_data *qdata)
return NS_PROC_FULL; /* Check for more. */
case KNOT_EOK: /* Last response. */
gettimeofday(&now, NULL);
AXFR_QLOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).",
AXFROUT_LOG(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_QLOG(LOG_ERR, "%s", knot_strerror(ret));
AXFROUT_LOG(LOG_ERR, "%s", knot_strerror(ret));
return NS_PROC_FAIL;
}
}
......@@ -271,8 +271,8 @@ static int axfr_answer_init(struct answer_data *data)
}
/* AXFR-specific logging (internal, expects 'data' variable set). */
#define AXFR_QRLOG(severity, msg...) \
fprintf(stderr, "Incoming AXFR: " msg)
#define AXFRIN_LOG(severity, msg...) \
ANSWER_LOG(severity, data, "Incoming AXFR", msg)
static int axfr_answer_finalize(struct answer_data *data)
{
......@@ -298,11 +298,11 @@ static int axfr_answer_finalize(struct answer_data *data)
/* Switch contents. */
zone_contents_t *old_contents = xfrin_switch_zone(zone, proc->zone);
AXFR_QRLOG(LOG_INFO, "Serial %u -> %u\n",
AXFRIN_LOG(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",
AXFRIN_LOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).\n",
time_diff(&proc->tstamp, &now) / 1000.0,
proc->npkts, proc->nbytes / 1024.0);
......@@ -315,7 +315,7 @@ static int axfr_answer_finalize(struct answer_data *data)
int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
{
/* Initialize processing context. */
/* Initialize processing with first packet. */
int ret = KNOT_EOK;
if (data->ext == NULL) {
ret = axfr_answer_init(data);
......@@ -324,17 +324,22 @@ int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
}
}
/* Process answer packet. */
ret = xfrin_process_axfr_packet(pkt, (struct xfr_proc *)data->ext);
if (ret > 0) { // transfer finished
#warning TODO: this function wraps the old processing interface, hence the retval conversion below
if (ret > 0) {
/* This was the last packet, finalize zone and publish it. */
ret = axfr_answer_finalize(data);
if (ret == KNOT_EOK) {
return NS_PROC_DONE;
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
return KNOT_EOK;
return NS_PROC_DONE;
}
if (ret != KNOT_EOK) {
fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
return NS_PROC_FAIL;
}
......
......@@ -67,7 +67,7 @@ int axfr_query(knot_pkt_t *pkt, struct query_data *qdata);
* \param xfr Persistent transfer-specific data.
*
*/
int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *xfr);
int axfr_process_answer(knot_pkt_t *pkt, struct answer_data *data);
#endif /* _KNOT_AXFR_H_ */
......
......@@ -871,22 +871,29 @@ static int internet_answer_soa(knot_pkt_t *pkt, struct answer_data *data)
return NS_PROC_FAIL;
}
/* Our zone is expired, schedule transfer. */
if (zone_contents_is_empty(zone->contents)) {
zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW);
return NS_PROC_DONE;
}
/* Check if master has newer zone and schedule transfer. */
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
uint32_t our_serial = knot_soa_serial(soa);
uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs);
if (knot_serial_compare(our_serial, their_serial) >= 0) {
zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa));
zone_events_schedule(zone, ZONE_EVENT_EXPIRE, knot_soa_expire(soa));
ANSWER_LOG(LOG_INFO, data, "Refresh", "Zone is up-to-date.");
return NS_PROC_DONE; /* Our zone is up to date. */
}
/* Our zone is outdated, schedule zone transfer. */
ANSWER_LOG(LOG_INFO, data, "Refresh", "master has newer serial %u -> %u.",
our_serial, their_serial);
zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW);
return NS_PROC_DONE;
}
int internet_answer(knot_pkt_t *pkt, struct answer_data *data)
int internet_process_answer(knot_pkt_t *pkt, struct answer_data *data)
{
if (pkt == NULL || data == NULL) {
return NS_PROC_FAIL;
......
......@@ -70,7 +70,7 @@ int internet_query_plan(struct query_plan *plan);
* \retval DONE if finished.
* \retval NOOP if not supported.
*/
int internet_answer(knot_pkt_t *pkt, struct answer_data *data);
int internet_process_answer(knot_pkt_t *pkt, struct answer_data *data);
/*!
* \brief Puts RRSet to packet, will store its RRSIG for later use.
......
......@@ -29,7 +29,7 @@ struct ixfr_proc {
/* IXFR-specific logging (internal, expects 'qdata' variable set). */
#define IXFR_LOG(severity, msg...) \
ANSWER_LOG(severity, qdata, "Outgoing IXFR", msg)
QUERY_LOG(severity, qdata, "Outgoing IXFR", msg)
/*! \brief Helper macro for putting RRs into packet. */
#define IXFR_SAFE_PUT(pkt, rr) \
......@@ -422,7 +422,7 @@ int ixfr_process_answer(knot_pkt_t *pkt, struct answer_data *data)
return ret;
#endif
return KNOT_ENOTSUP;
return NS_PROC_FAIL;
}
#undef IXFR_LOG
......@@ -44,7 +44,7 @@
#define NOTIFY_LOG(severity, msg...) \
QUERY_LOG(severity, qdata, "NOTIFY", msg)
int internet_notify(knot_pkt_t *pkt, struct query_data *qdata)
int notify_query(knot_pkt_t *pkt, struct query_data *qdata)
{
if (pkt == NULL || qdata == NULL) {
return NS_PROC_FAIL;
......@@ -81,3 +81,8 @@ int internet_notify(knot_pkt_t *pkt, struct query_data *qdata)
NOTIFY_LOG(LOG_INFO, "received serial %u.", serial);
return NS_PROC_DONE;
}
int notify_process_answer(knot_pkt_t *pkt, struct answer_data *data)
{
return NS_PROC_DONE; /* No processing. */
}
......@@ -34,6 +34,7 @@
#include "knot/zone/contents.h"
struct query_data;
struct answer_data;
#define NOTIFY_TIMEOUT 3 /*!< Interval between NOTIFY retries. */
......@@ -43,7 +44,15 @@ struct query_data;
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
*/
int internet_notify(knot_pkt_t *pkt, struct query_data *qdata);
int notify_query(knot_pkt_t *pkt, struct query_data *qdata);
/*!
* \brief Process an answer to the NOTIFY query.
*
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
*/
int notify_process_answer(knot_pkt_t *pkt, struct answer_data *data);
#endif /* _KNOTD_NOTIFY_H_ */
......
......@@ -31,8 +31,8 @@ const knot_process_module_t _process_answer = {
&process_answer_reset,
&process_answer_finish,
&process_answer,
&noop,
&noop
&noop, /* No output */
&noop /* No error processing. */
};
/*! \brief Accessor to query-specific data. */
......@@ -83,7 +83,6 @@ int process_answer_reset(knot_process_t *ctx)
int process_answer_finish(knot_process_t *ctx)
{
#warning TODO: finalize multi-packet
process_answer_reset(ctx);
mm_free(&ctx->mm, ctx->data);
ctx->data = NULL;
......@@ -91,70 +90,53 @@ int process_answer_finish(knot_process_t *ctx)
return NS_PROC_NOOP;
}
/*! \brief Process response in IN class zone. */
static int answer_internet(knot_pkt_t *pkt, knot_process_t *ctx)
{
struct answer_data *data = ANSWER_DATA(ctx);
int next_state = NS_PROC_FAIL;
switch(knot_pkt_type(pkt)) {
case KNOT_RESPONSE_NORMAL:
next_state = internet_answer(pkt, data);
break;
case KNOT_RESPONSE_AXFR:
next_state = axfr_process_answer(pkt, data);
break;
case KNOT_RESPONSE_IXFR:
break;
case KNOT_RESPONSE_NOTIFY:
next_state = NS_PROC_DONE; /* No processing. */
break;
default:
next_state = NS_PROC_NOOP;
break;
/* \note Private helper for process_answer repetitive checks. */
#define ANSWER_REQUIRES(condition, ret) \
if (!(condition)) { \
knot_pkt_free(&pkt); \
return ret; \
}
return next_state;
}
int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
{
assert(pkt && ctx);
struct answer_data *data = ANSWER_DATA(ctx);
/* Check parse state. */
int next_state = NS_PROC_DONE;
if (pkt->parsed < KNOT_WIRE_HEADER_SIZE || pkt->parsed < pkt->size) {
next_state = NS_PROC_FAIL;
goto finish;
}
ANSWER_REQUIRES(pkt->parsed >= KNOT_WIRE_HEADER_SIZE, NS_PROC_FAIL);
ANSWER_REQUIRES(pkt->parsed == pkt->size, NS_PROC_FAIL);
/* Accept only responses. */
if (!knot_wire_get_qr(pkt->wire)) {
next_state = NS_PROC_NOOP;
goto finish;
}
ANSWER_REQUIRES(knot_wire_get_qr(pkt->wire), NS_PROC_NOOP);
/* Check if we want answer paired to query. */
const knot_pkt_t *query = data->param->query;
if (query && !is_answer_to_query(query, pkt)) {
next_state = NS_PROC_NOOP; /* Ignore */
goto finish;
}
ANSWER_REQUIRES(query == NULL || is_answer_to_query(query, pkt), NS_PROC_NOOP);
/* Class specific answer processing. */
ANSWER_REQUIRES(knot_pkt_qclass(pkt) == KNOT_CLASS_IN, NS_PROC_NOOP);
#warning TODO: check TSIG here?
/* Class specific answer processing. */
switch (knot_pkt_qclass(pkt)) {
case KNOT_CLASS_IN:
next_state = answer_internet(pkt, ctx);
/* Call appropriate processing handler. */
int next_state = NS_PROC_NOOP;
switch(knot_pkt_type(pkt)) {
case KNOT_RESPONSE_NORMAL:
next_state = internet_process_answer(pkt, data);
break;
default: /* No known processor. */
case KNOT_RESPONSE_AXFR:
next_state = axfr_process_answer(pkt, data);
break;
case KNOT_RESPONSE_IXFR:
next_state = ixfr_process_answer(pkt, data);
break;
case KNOT_RESPONSE_NOTIFY:
next_state = notify_process_answer(pkt, data);
break;
default:
next_state = NS_PROC_NOOP;
break;
}
finish:
knot_pkt_free(&pkt);
return next_state;
}
\ No newline at end of file
}
#undef ANSWER_REQUIRES
\ No newline at end of file
......@@ -23,6 +23,14 @@ extern const knot_process_module_t _process_answer;
#define NS_PROC_ANSWER (&_process_answer)
#define NS_PROC_ANSWER_ID 2
/*! \brief Answer processsing logging base. */
#define ANSWER_LOG(severity, data, what, msg...) do {\
const char *zone_str = (data)->param->zone->conf->name; \
NS_PROC_LOG(severity, LOG_SERVER, (data)->param->remote, zone_str, \
what " of '%s' from '%s': ", msg); \
} while(0)
/* Module load parameters. */
struct process_answer_param {
zone_t *zone;
......
......@@ -366,7 +366,7 @@ static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
next_state = internet_query(pkt, data);
break;
case KNOT_QUERY_NOTIFY:
next_state = internet_notify(pkt, data);
next_state = notify_query(pkt, data);
break;
case KNOT_QUERY_AXFR:
next_state = axfr_query(pkt, data);
......
......@@ -37,22 +37,19 @@ extern const knot_process_module_t _process_query;
#define NS_PROC_QUERY_ID 1
/*! \brief Query processing logging common base. */
#define NS_PROC_LOG(severity, qdata, what, msg, ...) do { \
#define NS_PROC_LOG(severity, log_type, remote, zone_str, what, msg, ...) do { \
char addr_str[SOCKADDR_STRLEN] = {0}; \
sockaddr_tostr((qdata)->param->remote, addr_str, sizeof(addr_str)); \
char *zone_str = knot_dname_to_str(knot_pkt_qname((qdata)->query)); \
log_msg(LOG_SERVER, severity, what msg "\n", \
zone_str, addr_str, ##__VA_ARGS__); \
free(zone_str); \
sockaddr_tostr(remote, addr_str, sizeof(addr_str)); \
log_msg(log_type, severity, what msg "\n", zone_str, addr_str, ##__VA_ARGS__); \
} while (0)
/*! \brief Query logging common base. */
#define QUERY_LOG(severity, qdata, what, msg...) \
NS_PROC_LOG(severity, qdata, what " of '%s' from '%s': ", msg)
/*! \brief Answer logging common base. */
#define ANSWER_LOG(severity, qdata, what, msg...) \
NS_PROC_LOG(severity, qdata, what " of '%s' to '%s': ", msg)
#define QUERY_LOG(severity, qdata, what, msg...) do {\
char *zone_str = knot_dname_to_str(knot_pkt_qname((qdata)->query)); \
NS_PROC_LOG(severity, LOG_SERVER, (qdata)->param->remote, zone_str, \
what " of '%s' with '%s': ", msg); \
free(zone_str); \
} while(0)
/* Query processing specific flags. */
enum process_query_flag {
......
......@@ -20,11 +20,8 @@
#include "knot/server/tcp-handler.h"
struct request {
node_t node;
int fd;
struct request_data data;
int state;
const struct sockaddr_storage *remote, *origin;
knot_pkt_t *query;
knot_process_t process;
uint8_t *pkt_buf;
};
......@@ -55,9 +52,9 @@ static void request_close(mm_ctx_t *mm, struct request *request)
}
knot_process_finish(&request->process);
rem_node(&request->node);
close(request->fd);
knot_pkt_free(&request->query);
rem_node(&request->data.node);
close(request->data.fd);
knot_pkt_free(&request->data.query);
mm_free(mm, request->pkt_buf);
mm_free(mm, request);
}
......@@ -82,7 +79,7 @@ static int request_wait(int fd, int state, struct timeval *timeout)
static int request_send(struct request *request, struct timeval *timeout)
{
/* Wait for writeability. */
int ret = request_wait(request->fd, NS_PROC_FULL, timeout);
int ret = request_wait(request->data.fd, NS_PROC_FULL, timeout);
if (ret <= 0) {
return KNOT_EAGAIN;
}
......@@ -90,14 +87,14 @@ static int request_send(struct request *request, struct timeval *timeout)
/* Check socket error. */
int err = 0;
socklen_t len = sizeof(int);
getsockopt(request->fd, SOL_SOCKET, SO_ERROR, &err, &len);
getsockopt(request->data.fd, SOL_SOCKET, SO_ERROR, &err, &len);
if (err != 0) {
return KNOT_ECONNREFUSED;
}
/* Send query. */
knot_pkt_t *query = request->query;
ret = tcp_send(request->fd, query->wire, query->size);
knot_pkt_t *query = request->data.query;
ret = tcp_send(request->data.fd, query->wire, query->size);
if (ret <= 0) {
return KNOT_ECONN;
}
......@@ -108,13 +105,13 @@ static int request_send(struct request *request, struct timeval *timeout)
static int request_recv(struct request *request, struct timeval *timeout)
{
/* Wait for response. */
int ret = request_wait(request->fd, NS_PROC_MORE, timeout);
int ret = request_wait(request->data.fd, NS_PROC_MORE, timeout);
if (ret <= 0) {
return NS_PROC_FAIL;
}
/* Receive it */
ret = tcp_recv(request->fd, request->pkt_buf, KNOT_WIRE_MAX_PKTSIZE, NULL);
ret = tcp_recv(request->data.fd, request->pkt_buf, KNOT_WIRE_MAX_PKTSIZE, NULL);
if (ret <= 0) {
return NS_PROC_FAIL;
}
......@@ -156,10 +153,11 @@ struct request *requestor_make(struct requestor *requestor,
return NULL;
}
request->origin = from;
request->remote = to;
request->fd = -1;
request->query = query;
request->state = NS_PROC_DONE;
request->data.origin = from;
request->data.remote = to;
request->data.fd = -1;
request->data.query = query;
return request;
}
......@@ -170,20 +168,20 @@ int requestor_enqueue(struct requestor *requestor, struct request * request, voi
}
/* Fetch a bound socket. */
int fd = net_connected_socket(SOCK_STREAM, request->remote,
request->origin, O_NONBLOCK);
int fd = net_connected_socket(SOCK_STREAM, request->data.remote,
request->data.origin, O_NONBLOCK);
if (fd < 0) {
return KNOT_ECONN;
}
/* Form a pending request. */
request->fd = fd;
request->data.fd = fd;
request->state = NS_PROC_FULL; /* We have a query to be sent. */
memcpy(&request->process.mm, requestor->mm, sizeof(mm_ctx_t));
knot_process_begin(&request->process, param, requestor->module);
add_tail(&requestor->pending, &request->node);
add_tail(&requestor->pending, &request->data.node);
return KNOT_EOK;
}
......@@ -221,7 +219,7 @@ static int exec_request(struct request *last, struct timeval *timeout)
last->state = knot_process_in(last->pkt_buf, rcvd, &last->process);
if (last->state == NS_PROC_FAIL) {
return KNOT_ERROR;
return KNOT_EMALF;
}
}
......
......@@ -36,6 +36,14 @@ struct requestor {
mm_ctx_t *mm; /*!< Memory context. */
};
/*! \brief Request data (payload and endpoints). */
struct request_data {
node_t node;
int fd;
const struct sockaddr_storage *remote, *origin;
knot_pkt_t *query;
};
/*!
* \brief Initialize requestor structure.
*/
......
......@@ -10,9 +10,6 @@
#include "libknot/tsig-op.h"
#include "knot/zone/zone.h"
/* Forward decls. */
static int zones_process_update_auth(struct query_data *qdata);
/* AXFR-specific logging (internal, expects 'qdata' variable set). */
#define UPDATE_LOG(severity, msg...) \
QUERY_LOG(severity, qdata, "UPDATE", msg)
......@@ -101,8 +98,8 @@ static int update_process(knot_pkt_t *resp, struct query_data *qdata)
return ret;
}
/*! \todo Reusing the API for compatibility reasons. */
return zones_process_update_auth(qdata);
/* Passed, enqueue it. */
return zone_update_enqueue((zone_t *)qdata->zone, qdata->query, qdata->param);
}
int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
......@@ -123,59 +120,15 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
NS_NEED_AUTH(zone->update_in, qdata);
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Check expiration. */
/*
* Check if UPDATE not running already.
*/
if (pthread_mutex_trylock(&zone->ddns_lock) != 0) {
qdata->rcode = KNOT_RCODE_SERVFAIL;
log_zone_error("Failed to process UPDATE for "
"zone %s: Another UPDATE in progress.\n",
zone->conf->name);
return NS_PROC_FAIL;
}
/* Check if the zone is not discarded. */
if (zone->flags & ZONE_DISCARDED) {
pthread_mutex_unlock(&zone->ddns_lock);
return NS_PROC_FAIL;
}
struct timeval t_start = {0}, t_end = {0};
gettimeofday(&t_start, NULL);
UPDATE_LOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, tsig_wire_maxsize(qdata->sign.tsig_key));
/* Retain zone for the whole processing so it doesn't disappear
* for example during reload.
* @note This is going to be fixed when this is made a zone event. */
zone_retain(zone);
/* Process UPDATE. */
rcu_read_unlock();
int ret = update_process(pkt, qdata);
rcu_read_lock();
/* Since we unlocked RCU read lock, it is possible that the
* zone was modified/removed in the background. Therefore,
* we must NOT touch the zone after we release it here. */
pthread_mutex_unlock(&zone->ddns_lock);
zone_release(zone);
qdata->zone = NULL;
/* Evaluate */
switch(ret) {
case KNOT_EOK: /* Last response. */
gettimeofday(&t_end, NULL);
UPDATE_LOG(LOG_INFO, "Finished in %.02fs.",
time_diff(&t_start, &t_end) / 1000.0);
return NS_PROC_DONE;
break;
default: /* Generic error. */
UPDATE_LOG(LOG_ERR, "%s", knot_strerror(ret));
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
/* No immediate response. */
pkt->size = 0;
return NS_PROC_DONE;
}
static int knot_ns_process_update(const knot_pkt_t *query,
......@@ -243,10 +196,8 @@ static bool zones_nsec3param_changed(const zone_contents_t *old_contents,
* \retval KNOT_EOK if successful.
* \retval error if not.
*/
static int zones_process_update_auth(struct query_data *qdata)
int zones_process_update_auth(zone_t *zone, const knot_pkt_t *query)
{
assert(qdata);
assert(qdata->zone);
#warning TODO: reimplement zones_process_update_auth
#if 0
zone_t *zone = (zone_t *)qdata->zone;
......
......@@ -40,6 +40,10 @@ struct query_data;
*/
int update_answer(knot_pkt_t *pkt, struct query_data *qdata);
/*! \brief Process already authenticated packet. */
int zones_process_update_auth(zone_t *zone, const knot_pkt_t *query);
#endif /* _KNOT_UPDATE_H_ */
/*! @} */
This diff is collapsed.
......@@ -36,6 +36,7 @@ typedef enum zone_event_type {
ZONE_EVENT_RELOAD = 0,
ZONE_EVENT_REFRESH,
ZONE_EVENT_XFER,
ZONE_EVENT_UPDATE,
ZONE_EVENT_EXPIRE,
ZONE_EVENT_FLUSH,
ZONE_EVENT_NOTIFY,
......
......@@ -27,19 +27,12 @@
#include "knot/zone/zonefile.h"
#include "knot/zone/contents.h"
#include "knot/updates/xfr-in.h"
#include "knot/nameserver/requestor.h"
#include "libknot/common.h"
#include "libknot/dname.h"
#include "libknot/dnssec/random.h"
#include "libknot/util/utils.h"
/*!
* \brief Called when the reference count for zone drops to zero.
*/
static void knot_zone_dtor(struct ref_t *p) {
zone_t *z = (zone_t *)p;
zone_free(&z);
}
/*!
* \brief Set ACL list from configuration.
*
......@@ -94,15 +87,12 @@ zone_t* zone_new(conf_zone_t *conf)
return NULL;
}
ref_init(&zone->ref, knot_zone_dtor);
zone_retain(zone);
// Configuration
zone->conf = conf;
// Mutexes
pthread_mutex_init(&zone->lock, 0);
// DDNS
pthread_mutex_init(&zone->ddns_lock, 0);
init_list(&zone->ddns_queue);
// ACLs
set_acl(&zone->xfr_out, &conf->acl.xfr_out);
......@@ -131,7 +121,6 @@ void zone_free(zone_t **zone_ptr)
acl_delete(&zone->xfr_out);
acl_delete(&zone->notify_in);
acl_delete(&zone->update_in);
pthread_mutex_destroy(&zone->lock);
pthread_mutex_destroy(&zone->ddns_lock);
/* Free assigned config. */
......@@ -248,7 +237,15 @@ const conf_iface_t *zone_master(const zone_t *zone)
return master->remote;
}
void zone_master_rotate(const zone_t *zone)
{
if (zone_master(zone) == NULL) {
return;
}
list_t *master_list = &zone->conf->acl.xfr_in;
add_tail(master_list, HEAD(*master_list));
}
int zone_flush_journal(zone_t *zone)
{
......@@ -298,3 +295,50 @@ int zone_flush_journal(zone_t *zone)
return ret;
}
int zone_update_enqueue(zone_t *zone, knot_pkt_t *pkt, struct process_query_param *param)
{
struct request_data *req = malloc(sizeof(struct request_data));
if (req == NULL) {
return KNOT_ENOMEM;
}
memset(req, 0, sizeof(struct request_data));
req->fd = param->socket;
req->origin = param->remote;
req->query = knot_pkt_copy(pkt, NULL);
if (req->query == NULL) {
free(req);
return KNOT_ENOMEM;
}
pthread_mutex_lock(&zone->ddns_lock);
/* Schedule UPDATE event if this is a first item in the list. */
if (EMPTY_LIST(zone->ddns_queue)) {
zone_events_schedule(zone, ZONE_EVENT_UPDATE, ZONE_EVENT_NOW);
}
/* Enqueue created request. */
#warning TODO: scan the queue if the same source/msgid is not already enqueued
add_tail(&zone->ddns_queue, (node_t *)req);
pthread_mutex_unlock(&zone->ddns_lock);
return KNOT_EOK;
}
struct request_data *zone_update_dequeue(zone_t *zone)
{