summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/ipc.c
diff options
context:
space:
mode:
authorJakob Schlyter <jakob@cvs.openbsd.org>2010-01-15 19:24:59 +0000
committerJakob Schlyter <jakob@cvs.openbsd.org>2010-01-15 19:24:59 +0000
commit54a1a10c8035ff9ec7b252904e0675a1ac7f2d15 (patch)
tree10b07cafeb640e396c3d65c26ff7652109393eab /usr.sbin/nsd/ipc.c
parent81db87de733ad83093fe047ea7411bc8afaa1db0 (diff)
NSD v3.2.4
Diffstat (limited to 'usr.sbin/nsd/ipc.c')
-rw-r--r--usr.sbin/nsd/ipc.c635
1 files changed, 341 insertions, 294 deletions
diff --git a/usr.sbin/nsd/ipc.c b/usr.sbin/nsd/ipc.c
index 1f188e54951..449c0514fc1 100644
--- a/usr.sbin/nsd/ipc.c
+++ b/usr.sbin/nsd/ipc.c
@@ -7,11 +7,10 @@
*
*/
-#include "config.h"
+#include <config.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
-#include <fcntl.h>
#include "ipc.h"
#include "buffer.h"
#include "xfrd-tcp.h"
@@ -19,46 +18,92 @@
#include "namedb.h"
#include "xfrd.h"
#include "xfrd-notify.h"
-#include "difffile.h"
+/* set is_ok for the zone according to the zone message */
+static zone_type* handle_xfrd_zone_state(struct nsd* nsd, buffer_type* packet);
+/* write ipc ZONE_STATE message into the buffer */
+static void write_zone_state_packet(buffer_type* packet, zone_type* zone);
/* attempt to send NSD_STATS command to child fd */
static void send_stat_to_child(struct main_ipc_handler_data* data, int fd);
+/* write IPC expire notification msg to a buffer */
+static void xfrd_write_expire_notification(buffer_type* buffer, xfrd_zone_t* zone);
/* send reload request over the IPC channel */
static void xfrd_send_reload_req(xfrd_state_t* xfrd);
/* send quit request over the IPC channel */
static void xfrd_send_quit_req(xfrd_state_t* xfrd);
+/* get SOA INFO out of IPC packet buffer */
+static void xfrd_handle_ipc_SOAINFO(xfrd_state_t* xfrd, buffer_type* packet);
/* perform read part of handle ipc for xfrd */
-static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd);
+static void xfrd_handle_ipc_read(netio_handler_type *handler, xfrd_state_t* xfrd);
-static void
-ipc_child_quit(struct nsd* nsd)
+static zone_type*
+handle_xfrd_zone_state(struct nsd* nsd, buffer_type* packet)
{
- /* call shutdown and quit routines */
- nsd->mode = NSD_QUIT;
-#ifdef BIND8_STATS
- bind8_stats(nsd);
-#endif /* BIND8_STATS */
-
-#if 0 /* OS collects memory pages */
- event_base_free(event_base);
- region_destroy(server_region);
-#endif
- server_shutdown(nsd);
- exit(0);
+ uint8_t ok;
+ const dname_type *dname;
+ domain_type *domain;
+ zone_type *zone;
+
+ ok = buffer_read_u8(packet);
+ dname = (dname_type*)buffer_current(packet);
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "handler zone state %s is %s",
+ dname_to_string(dname, NULL), ok?"ok":"expired"));
+ /* find in zone_types, if does not exist, we cannot serve anyway */
+ /* find zone in config, since that one always exists */
+ domain = domain_table_find(nsd->db->domains, dname);
+ if(!domain) {
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "zone state msg, empty zone (domain %s)",
+ dname_to_string(dname, NULL)));
+ return NULL;
+ }
+ zone = domain_find_zone(domain);
+ if(!zone || dname_compare(domain_dname(zone->apex), dname) != 0) {
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "zone state msg, empty zone (zone %s)",
+ dname_to_string(dname, NULL)));
+ return NULL;
+ }
+ assert(zone);
+ /* only update zone->is_ok if needed to minimize copy-on-write
+ of memory pages shared after fork() */
+ if(ok && !zone->is_ok)
+ zone->is_ok = 1;
+ if(!ok && zone->is_ok)
+ zone->is_ok = 0;
+ return zone;
}
void
-child_handle_parent_command(int fd, short event, void* arg)
+child_handle_parent_command(netio_type *ATTR_UNUSED(netio),
+ netio_handler_type *handler,
+ netio_event_types_type event_types)
{
sig_atomic_t mode;
int len;
struct ipc_handler_conn_data *data =
- (struct ipc_handler_conn_data *) arg;
- if (!(event & EV_READ)) {
+ (struct ipc_handler_conn_data *) handler->user_data;
+ if (!(event_types & NETIO_EVENT_READ)) {
return;
}
- if ((len = read(fd, &mode, sizeof(mode))) == -1) {
+ if(data->conn->is_reading) {
+ int ret = conn_read(data->conn);
+ if(ret == -1) {
+ log_msg(LOG_ERR, "handle_parent_command: error in conn_read: %s",
+ strerror(errno));
+ data->conn->is_reading = 0;
+ return;
+ }
+ if(ret == 0) {
+ return; /* continue later */
+ }
+ /* completed */
+ data->conn->is_reading = 0;
+ buffer_flip(data->conn->packet);
+ (void)handle_xfrd_zone_state(data->nsd, data->conn->packet);
+ return;
+ }
+
+ if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) {
log_msg(LOG_ERR, "handle_parent_command: read: %s",
strerror(errno));
return;
@@ -66,38 +111,21 @@ child_handle_parent_command(int fd, short event, void* arg)
if (len == 0)
{
/* parent closed the connection. Quit */
- ipc_child_quit(data->nsd);
+ data->nsd->mode = NSD_QUIT;
return;
}
switch (mode) {
case NSD_STATS:
- data->nsd->mode = mode;
- break;
case NSD_QUIT:
- ipc_child_quit(data->nsd);
+ data->nsd->mode = mode;
break;
- case NSD_QUIT_CHILD:
- /* close our listening sockets and ack */
- server_close_all_sockets(data->nsd->udp, data->nsd->ifs);
- server_close_all_sockets(data->nsd->tcp, data->nsd->ifs);
- /* mode == NSD_QUIT_CHILD */
- (void)write(fd, &mode, sizeof(mode));
- ipc_child_quit(data->nsd);
- break;
- case NSD_QUIT_WITH_STATS:
-#ifdef BIND8_STATS
- DEBUG(DEBUG_IPC, 2, (LOG_INFO, "quit QUIT_WITH_STATS"));
- /* reply with ack and stats and then quit */
- if(!write_socket(fd, &mode, sizeof(mode))) {
- log_msg(LOG_ERR, "cannot write quitwst to parent");
- }
- if(!write_socket(fd, &data->nsd->st, sizeof(data->nsd->st))) {
- log_msg(LOG_ERR, "cannot write stats to parent");
- }
- fsync(fd);
-#endif /* BIND8_STATS */
- ipc_child_quit(data->nsd);
+ case NSD_ZONE_STATE:
+ data->conn->is_reading = 1;
+ data->conn->total_bytes = 0;
+ data->conn->msglen = 0;
+ data->conn->fd = handler->fd;
+ buffer_clear(data->conn->packet);
break;
default:
log_msg(LOG_ERR, "handle_parent_command: bad mode %d",
@@ -119,6 +147,38 @@ parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio),
return;
}
+ if(data->conn->is_reading) {
+ /* handle ZONE_STATE forward to children */
+ int ret = conn_read(data->conn);
+ size_t i;
+ zone_type* zone;
+ if(ret == -1) {
+ log_msg(LOG_ERR, "main xfrd listener: error in conn_read: %s",
+ strerror(errno));
+ data->conn->is_reading = 0;
+ return;
+ }
+ if(ret == 0) {
+ return; /* continue later */
+ }
+ /* completed */
+ data->conn->is_reading = 0;
+ buffer_flip(data->conn->packet);
+ zone = handle_xfrd_zone_state(data->nsd, data->conn->packet);
+ if(!zone)
+ return;
+ /* forward to all children */
+ for (i = 0; i < data->nsd->child_count; ++i) {
+ if(!zone->dirty[i]) {
+ zone->dirty[i] = 1;
+ stack_push(data->nsd->children[i].dirty_zones, zone);
+ data->nsd->children[i].handler->event_types |=
+ NETIO_EVENT_WRITE;
+ }
+ }
+ return;
+ }
+
if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) {
log_msg(LOG_ERR, "handle_xfrd_command: read: %s",
strerror(errno));
@@ -126,29 +186,29 @@ parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio),
}
if (len == 0)
{
- /* xfrd closed, we must quit */
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "handle_xfrd_command: xfrd closed channel."));
+ DEBUG(DEBUG_IPC,1, (LOG_ERR, "handle_xfrd_command: xfrd closed channel."));
close(handler->fd);
handler->fd = -1;
- data->nsd->mode = NSD_SHUTDOWN;
return;
}
switch (mode) {
case NSD_RELOAD:
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "parent handle xfrd command RELOAD"));
data->nsd->signal_hint_reload = 1;
break;
case NSD_QUIT:
- case NSD_SHUTDOWN:
data->nsd->mode = mode;
break;
- case NSD_STATS:
- data->nsd->signal_hint_stats = 1;
- break;
case NSD_REAP_CHILDREN:
data->nsd->signal_hint_child = 1;
break;
+ case NSD_ZONE_STATE:
+ data->conn->is_reading = 1;
+ data->conn->total_bytes = 0;
+ data->conn->msglen = 0;
+ data->conn->fd = handler->fd;
+ buffer_clear(data->conn->packet);
+ break;
default:
log_msg(LOG_ERR, "handle_xfrd_command: bad mode %d",
(int) mode);
@@ -157,6 +217,27 @@ parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio),
}
static void
+write_zone_state_packet(buffer_type* packet, zone_type* zone)
+{
+ sig_atomic_t cmd = NSD_ZONE_STATE;
+ uint8_t ok = zone->is_ok;
+ uint16_t sz;
+ if(!zone->apex) {
+ return;
+ }
+ sz = dname_total_size(domain_dname(zone->apex)) + 1;
+ sz = htons(sz);
+
+ buffer_clear(packet);
+ buffer_write(packet, &cmd, sizeof(cmd));
+ buffer_write(packet, &sz, sizeof(sz));
+ buffer_write(packet, &ok, sizeof(ok));
+ buffer_write(packet, domain_dname(zone->apex),
+ dname_total_size(domain_dname(zone->apex)));
+ buffer_flip(packet);
+}
+
+static void
send_stat_to_child(struct main_ipc_handler_data* data, int fd)
{
sig_atomic_t cmd = NSD_STATS;
@@ -170,7 +251,6 @@ send_stat_to_child(struct main_ipc_handler_data* data, int fd)
data->child->need_to_send_STATS = 0;
}
-#ifndef NDEBUG
int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass);
static void
debug_print_fwd_name(int ATTR_UNUSED(len), buffer_type* packet, int acl_num)
@@ -193,16 +273,11 @@ debug_print_fwd_name(int ATTR_UNUSED(len), buffer_type* packet, int acl_num)
buffer_set_position(packet, bufpos);
region_destroy(tempregion);
}
-#endif
static void
send_quit_to_child(struct main_ipc_handler_data* data, int fd)
{
-#ifdef BIND8_STATS
- sig_atomic_t cmd = NSD_QUIT_WITH_STATS;
-#else
sig_atomic_t cmd = NSD_QUIT;
-#endif
if(write(fd, &cmd, sizeof(cmd)) == -1) {
if(errno == EAGAIN || errno == EINTR)
return; /* try again later */
@@ -215,116 +290,6 @@ send_quit_to_child(struct main_ipc_handler_data* data, int fd)
(int)data->child->pid));
}
-/** the child is done, mark it as exited */
-static void
-child_is_done(struct nsd* nsd, int fd)
-{
- size_t i;
- if(fd != -1) close(fd);
- for(i=0; i<nsd->child_count; ++i)
- if(nsd->children[i].child_fd == fd) {
- nsd->children[i].child_fd = -1;
- nsd->children[i].handler->fd = -1;
- if(nsd->children[i].need_to_exit) {
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "server %d is done",
- (int)nsd->children[i].pid));
- nsd->children[i].has_exited = 1;
- } else {
- log_msg(LOG_WARNING,
- "server %d died unexpectedly, restarting",
- (int)nsd->children[i].pid);
- /* this child is now going to be re-forked as
- * a subprocess of this server-main, and if a
- * reload is in progress the other children
- * are subprocesses of reload. Until the
- * reload is done and they are all reforked. */
- nsd->children[i].pid = -1;
- nsd->restart_children = 1;
- }
- }
- parent_check_all_children_exited(nsd);
-}
-
-#ifdef BIND8_STATS
-/** add stats to total */
-void
-stats_add(struct nsdst* total, struct nsdst* s)
-{
- unsigned i;
- for(i=0; i<sizeof(total->qtype)/sizeof(stc_t); i++)
- total->qtype[i] += s->qtype[i];
- for(i=0; i<sizeof(total->qclass)/sizeof(stc_t); i++)
- total->qclass[i] += s->qclass[i];
- total->qudp += s->qudp;
- total->qudp6 += s->qudp6;
- total->ctcp += s->ctcp;
- total->ctcp6 += s->ctcp6;
- for(i=0; i<sizeof(total->rcode)/sizeof(stc_t); i++)
- total->rcode[i] += s->rcode[i];
- for(i=0; i<sizeof(total->opcode)/sizeof(stc_t); i++)
- total->opcode[i] += s->opcode[i];
- total->dropped += s->dropped;
- total->truncated += s->truncated;
- total->wrongzone += s->wrongzone;
- total->txerr += s->txerr;
- total->rxerr += s->rxerr;
- total->edns += s->edns;
- total->ednserr += s->ednserr;
- total->raxfr += s->raxfr;
- total->nona += s->nona;
-
- total->db_disk = s->db_disk;
- total->db_mem = s->db_mem;
-}
-
-/** subtract stats from total */
-void
-stats_subtract(struct nsdst* total, struct nsdst* s)
-{
- unsigned i;
- for(i=0; i<sizeof(total->qtype)/sizeof(stc_t); i++)
- total->qtype[i] -= s->qtype[i];
- for(i=0; i<sizeof(total->qclass)/sizeof(stc_t); i++)
- total->qclass[i] -= s->qclass[i];
- total->qudp -= s->qudp;
- total->qudp6 -= s->qudp6;
- total->ctcp -= s->ctcp;
- total->ctcp6 -= s->ctcp6;
- for(i=0; i<sizeof(total->rcode)/sizeof(stc_t); i++)
- total->rcode[i] -= s->rcode[i];
- for(i=0; i<sizeof(total->opcode)/sizeof(stc_t); i++)
- total->opcode[i] -= s->opcode[i];
- total->dropped -= s->dropped;
- total->truncated -= s->truncated;
- total->wrongzone -= s->wrongzone;
- total->txerr -= s->txerr;
- total->rxerr -= s->rxerr;
- total->edns -= s->edns;
- total->ednserr -= s->ednserr;
- total->raxfr -= s->raxfr;
- total->nona -= s->nona;
-}
-
-#define FINAL_STATS_TIMEOUT 10 /* seconds */
-static void
-read_child_stats(struct nsd* nsd, struct nsd_child* child, int fd)
-{
- struct nsdst s;
- errno=0;
- if(block_read(nsd, fd, &s, sizeof(s), FINAL_STATS_TIMEOUT)!=sizeof(s)) {
- log_msg(LOG_ERR, "problems reading finalstats from server "
- "%d: %s", (int)child->pid, strerror(errno));
- } else {
- stats_add(&nsd->st, &s);
- child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6;
- /* we know that the child is going to close the connection
- * now (this is an ACK of the QUIT_W_STATS so we know the
- * child is done, no longer sending e.g. NOTIFY contents) */
- child_is_done(nsd, fd);
- }
-}
-#endif /* BIND8_STATS */
-
void
parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
netio_handler_type *handler,
@@ -337,14 +302,43 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
/* do a nonblocking write to the child if it is ready. */
if (event_types & NETIO_EVENT_WRITE) {
- if(data->child->need_to_send_STATS &&
- !data->child->need_to_exit) {
+ if(!data->busy_writing_zone_state &&
+ !data->child->need_to_send_STATS &&
+ !data->child->need_to_send_QUIT &&
+ !data->child->need_to_exit &&
+ data->child->dirty_zones->num > 0) {
+ /* create packet from next dirty zone */
+ zone_type* zone = (zone_type*)stack_pop(data->child->dirty_zones);
+ assert(zone);
+ zone->dirty[data->child_num] = 0;
+ data->busy_writing_zone_state = 1;
+ write_zone_state_packet(data->write_conn->packet, zone);
+ data->write_conn->msglen = buffer_limit(data->write_conn->packet);
+ data->write_conn->total_bytes = sizeof(uint16_t); /* len bytes already in packet */
+ data->write_conn->fd = handler->fd;
+ }
+ if(data->busy_writing_zone_state) {
+ /* write more of packet */
+ int ret = conn_write(data->write_conn);
+ if(ret == -1) {
+ log_msg(LOG_ERR, "handle_child_cmd %d: could not write: %s",
+ (int)data->child->pid, strerror(errno));
+ data->busy_writing_zone_state = 0;
+ } else if(ret == 1) {
+ data->busy_writing_zone_state = 0; /* completed */
+ }
+ } else if(data->child->need_to_send_STATS &&
+ !data->child->need_to_exit) {
send_stat_to_child(data, handler->fd);
} else if(data->child->need_to_send_QUIT) {
send_quit_to_child(data, handler->fd);
if(!data->child->need_to_send_QUIT)
handler->event_types = NETIO_EVENT_READ;
- } else {
+ }
+ if(!data->busy_writing_zone_state &&
+ !data->child->need_to_send_STATS &&
+ !data->child->need_to_send_QUIT &&
+ data->child->dirty_zones->num == 0) {
handler->event_types = NETIO_EVENT_READ;
}
}
@@ -402,10 +396,10 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
/* read rest later */
return;
}
- /* read the acl numbers */
+ /* read the acl number */
got_acl = data->got_bytes - sizeof(data->total_bytes) - data->total_bytes;
if((len = read(handler->fd, (char*)&data->acl_num+got_acl,
- sizeof(data->acl_num)+sizeof(data->acl_xfr)-got_acl)) == -1 ) {
+ sizeof(data->acl_num)-got_acl)) == -1 ) {
log_msg(LOG_ERR, "handle_child_command: read: %s",
strerror(errno));
return;
@@ -417,7 +411,7 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
}
got_acl += len;
data->got_bytes += len;
- if(got_acl >= (int)(sizeof(data->acl_num)+sizeof(data->acl_xfr))) {
+ if(got_acl >= (int)sizeof(data->acl_num)) {
uint16_t len = htons(data->total_bytes);
DEBUG(DEBUG_IPC,2, (LOG_INFO,
"main fwd passed packet write %d", (int)data->got_bytes));
@@ -432,9 +426,7 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
!write_socket(*data->xfrd_sock, buffer_begin(data->packet),
data->total_bytes) ||
!write_socket(*data->xfrd_sock, &data->acl_num,
- sizeof(data->acl_num)) ||
- !write_socket(*data->xfrd_sock, &data->acl_xfr,
- sizeof(data->acl_xfr))) {
+ sizeof(data->acl_num))) {
log_msg(LOG_ERR, "error in ipc fwd main2xfrd: %s",
strerror(errno));
}
@@ -450,7 +442,18 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
}
if (len == 0)
{
- child_is_done(data->nsd, handler->fd);
+ size_t i;
+ if(handler->fd > 0) close(handler->fd);
+ for(i=0; i<data->nsd->child_count; ++i)
+ if(data->nsd->children[i].child_fd == handler->fd) {
+ data->nsd->children[i].child_fd = -1;
+ data->nsd->children[i].has_exited = 1;
+ DEBUG(DEBUG_IPC,1, (LOG_INFO,
+ "server %d closed cmd channel",
+ (int) data->nsd->children[i].pid));
+ }
+ handler->fd = -1;
+ parent_check_all_children_exited(data->nsd);
return;
}
@@ -458,11 +461,6 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
case NSD_QUIT:
data->nsd->mode = mode;
break;
-#ifdef BIND8_STATS
- case NSD_QUIT_WITH_STATS:
- read_child_stats(data->nsd, data->child, handler->fd);
- break;
-#endif /* BIND8_STATS */
case NSD_STATS:
data->nsd->signal_hint_stats = 1;
break;
@@ -516,12 +514,11 @@ parent_handle_reload_command(netio_type *ATTR_UNUSED(netio),
}
if (len == 0)
{
- if(handler->fd != -1) {
+ if(handler->fd > 0) {
close(handler->fd);
handler->fd = -1;
}
log_msg(LOG_ERR, "handle_reload_cmd: reload closed cmd channel");
- nsd->reload_failed = 1;
return;
}
switch (mode) {
@@ -531,7 +528,7 @@ parent_handle_reload_command(netio_type *ATTR_UNUSED(netio),
for(i=0; i < nsd->child_count; i++) {
nsd->children[i].need_to_exit = 1;
if(nsd->children[i].pid > 0 &&
- nsd->children[i].child_fd != -1) {
+ nsd->children[i].child_fd > 0) {
nsd->children[i].need_to_send_QUIT = 1;
nsd->children[i].handler->event_types
|= NETIO_EVENT_WRITE;
@@ -550,16 +547,33 @@ parent_handle_reload_command(netio_type *ATTR_UNUSED(netio),
}
static void
+xfrd_write_expire_notification(buffer_type* buffer, xfrd_zone_t* zone)
+{
+ sig_atomic_t cmd = NSD_ZONE_STATE;
+ uint8_t ok = 1;
+ uint16_t sz = dname_total_size(zone->apex) + 1;
+ sz = htons(sz);
+ if(zone->state == xfrd_zone_expired)
+ ok = 0;
+
+ DEBUG(DEBUG_IPC,1, (LOG_INFO,
+ "xfrd encoding ipc zone state msg for zone %s state %d.",
+ zone->apex_str, (int)zone->state));
+
+ buffer_clear(buffer);
+ buffer_write(buffer, &cmd, sizeof(cmd));
+ buffer_write(buffer, &sz, sizeof(sz));
+ buffer_write(buffer, &ok, sizeof(ok));
+ buffer_write(buffer, zone->apex, dname_total_size(zone->apex));
+ buffer_flip(buffer);
+}
+
+static void
xfrd_send_reload_req(xfrd_state_t* xfrd)
{
sig_atomic_t req = NSD_RELOAD;
- uint64_t p = xfrd->last_task->data;
- udb_ptr_unlink(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
- task_process_sync(xfrd->nsd->task[xfrd->nsd->mytask]);
/* ask server_main for a reload */
- if(write(xfrd->ipc_handler.ev_fd, &req, sizeof(req)) == -1) {
- udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
- udb_ptr_set(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask], p);
+ if(write(xfrd->ipc_handler.fd, &req, sizeof(req)) == -1) {
if(errno == EAGAIN || errno == EINTR)
return; /* try again later */
log_msg(LOG_ERR, "xfrd: problems sending reload command: %s",
@@ -567,55 +581,21 @@ xfrd_send_reload_req(xfrd_state_t* xfrd)
return;
}
DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: asked nsd to reload new updates"));
- /* swapped task to other side, start to use other task udb. */
- xfrd->nsd->mytask = 1 - xfrd->nsd->mytask;
- task_remap(xfrd->nsd->task[xfrd->nsd->mytask]);
- udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
- assert(udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0);
-
xfrd_prepare_zones_for_reload();
xfrd->reload_cmd_last_sent = xfrd_time();
xfrd->need_to_send_reload = 0;
xfrd->can_send_reload = 0;
}
-void
-ipc_xfrd_set_listening(struct xfrd_state* xfrd, short mode)
-{
- int fd = xfrd->ipc_handler.ev_fd;
- struct event_base* base = xfrd->event_base;
- event_del(&xfrd->ipc_handler);
- event_set(&xfrd->ipc_handler, fd, mode, xfrd_handle_ipc, xfrd);
- if(event_base_set(base, &xfrd->ipc_handler) != 0)
- log_msg(LOG_ERR, "ipc: cannot set event_base");
- /* no timeout for IPC events */
- if(event_add(&xfrd->ipc_handler, NULL) != 0)
- log_msg(LOG_ERR, "ipc: cannot add event");
- xfrd->ipc_handler_flags = mode;
-}
-
-static void
-xfrd_send_shutdown_req(xfrd_state_t* xfrd)
-{
- sig_atomic_t cmd = NSD_SHUTDOWN;
- xfrd->ipc_send_blocked = 1;
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send shutdown"));
- if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
- log_msg(LOG_ERR, "xfrd: error writing shutdown to main: %s",
- strerror(errno));
- }
- xfrd->need_to_send_shutdown = 0;
-}
-
static void
xfrd_send_quit_req(xfrd_state_t* xfrd)
{
sig_atomic_t cmd = NSD_QUIT;
xfrd->ipc_send_blocked = 1;
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
+ xfrd->ipc_handler.event_types &= (~NETIO_EVENT_WRITE);
+ xfrd->sending_zone_state = 0;
DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send ackreload(quit)"));
- if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
+ if(write_socket(xfrd->ipc_handler.fd, &cmd, sizeof(cmd)) == -1) {
log_msg(LOG_ERR, "xfrd: error writing ack to main: %s",
strerror(errno));
}
@@ -623,55 +603,119 @@ xfrd_send_quit_req(xfrd_state_t* xfrd)
}
static void
-xfrd_send_stats(xfrd_state_t* xfrd)
+xfrd_handle_ipc_SOAINFO(xfrd_state_t* xfrd, buffer_type* packet)
{
- sig_atomic_t cmd = NSD_STATS;
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send stats"));
- if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
- log_msg(LOG_ERR, "xfrd: error writing stats to main: %s",
- strerror(errno));
+ xfrd_soa_t soa;
+ xfrd_soa_t* soa_ptr = &soa;
+ xfrd_zone_t* zone;
+ /* dname is sent in memory format */
+ const dname_type* dname = (const dname_type*)buffer_begin(packet);
+
+ /* find zone and decode SOA */
+ zone = (xfrd_zone_t*)rbtree_search(xfrd->zones, dname);
+ buffer_skip(packet, dname_total_size(dname));
+
+ if(!buffer_available(packet, sizeof(uint32_t)*6 + sizeof(uint8_t)*2)) {
+ /* NSD has zone without any info */
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s lost zone",
+ dname_to_string(dname,0)));
+ soa_ptr = NULL;
+ } else {
+ /* read soa info */
+ memset(&soa, 0, sizeof(soa));
+ /* left out type, klass, count for speed */
+ soa.type = htons(TYPE_SOA);
+ soa.klass = htons(CLASS_IN);
+ soa.ttl = htonl(buffer_read_u32(packet));
+ soa.rdata_count = htons(7);
+ soa.prim_ns[0] = buffer_read_u8(packet);
+ if(!buffer_available(packet, soa.prim_ns[0]))
+ return;
+ buffer_read(packet, soa.prim_ns+1, soa.prim_ns[0]);
+ soa.email[0] = buffer_read_u8(packet);
+ if(!buffer_available(packet, soa.email[0]))
+ return;
+ buffer_read(packet, soa.email+1, soa.email[0]);
+
+ soa.serial = htonl(buffer_read_u32(packet));
+ soa.refresh = htonl(buffer_read_u32(packet));
+ soa.retry = htonl(buffer_read_u32(packet));
+ soa.expire = htonl(buffer_read_u32(packet));
+ soa.minimum = htonl(buffer_read_u32(packet));
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "SOAINFO for %s %u",
+ dname_to_string(dname,0), ntohl(soa.serial)));
+ }
+
+ if(!zone) {
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: zone %s master zone updated",
+ dname_to_string(dname,0)));
+ notify_handle_master_zone_soainfo(xfrd->notify_zones,
+ dname, soa_ptr);
+ return;
}
- xfrd->need_to_send_stats = 0;
+ xfrd_handle_incoming_soa(zone, soa_ptr, xfrd_time());
}
void
-xfrd_handle_ipc(int ATTR_UNUSED(fd), short event, void* arg)
+xfrd_handle_ipc(netio_type* ATTR_UNUSED(netio),
+ netio_handler_type *handler,
+ netio_event_types_type event_types)
{
- xfrd_state_t* xfrd = (xfrd_state_t*)arg;
- if ((event & EV_READ))
+ xfrd_state_t* xfrd = (xfrd_state_t*)handler->user_data;
+ if ((event_types & NETIO_EVENT_READ))
{
/* first attempt to read as a signal from main
* could block further send operations */
- xfrd_handle_ipc_read(&xfrd->ipc_handler, xfrd);
+ xfrd_handle_ipc_read(handler, xfrd);
}
- if ((event & EV_WRITE))
+ if ((event_types & NETIO_EVENT_WRITE))
{
- if(xfrd->ipc_send_blocked) { /* wait for RELOAD_DONE */
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
+ if(xfrd->ipc_send_blocked) { /* wait for SOA_END */
+ handler->event_types = NETIO_EVENT_READ;
return;
}
- if(xfrd->need_to_send_shutdown) {
- xfrd_send_shutdown_req(xfrd);
+ /* if necessary prepare a packet */
+ if(!(xfrd->can_send_reload && xfrd->need_to_send_reload) &&
+ !xfrd->need_to_send_quit &&
+ !xfrd->sending_zone_state &&
+ xfrd->dirty_zones->num > 0) {
+ xfrd_zone_t* zone = (xfrd_zone_t*)stack_pop(xfrd->dirty_zones);
+ assert(zone);
+ zone->dirty = 0;
+ xfrd->sending_zone_state = 1;
+ xfrd_write_expire_notification(xfrd->ipc_conn_write->packet, zone);
+ xfrd->ipc_conn_write->msglen = buffer_limit(xfrd->ipc_conn_write->packet);
+ /* skip length bytes; they are encoded in the packet, after cmd */
+ xfrd->ipc_conn_write->total_bytes = sizeof(uint16_t);
+ }
+ /* write a bit */
+ if(xfrd->sending_zone_state) {
+ /* call conn_write */
+ int ret = conn_write(xfrd->ipc_conn_write);
+ if(ret == -1) {
+ log_msg(LOG_ERR, "xfrd: error in write ipc: %s", strerror(errno));
+ xfrd->sending_zone_state = 0;
+ }
+ else if(ret == 1) { /* done */
+ xfrd->sending_zone_state = 0;
+ }
} else if(xfrd->need_to_send_quit) {
xfrd_send_quit_req(xfrd);
} else if(xfrd->can_send_reload && xfrd->need_to_send_reload) {
xfrd_send_reload_req(xfrd);
- } else if(xfrd->need_to_send_stats) {
- xfrd_send_stats(xfrd);
}
if(!(xfrd->can_send_reload && xfrd->need_to_send_reload) &&
- !xfrd->need_to_send_shutdown &&
!xfrd->need_to_send_quit &&
- !xfrd->need_to_send_stats) {
- /* disable writing for now */
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
+ !xfrd->sending_zone_state &&
+ xfrd->dirty_zones->num == 0) {
+ handler->event_types = NETIO_EVENT_READ; /* disable writing for now */
}
}
}
static void
-xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
+xfrd_handle_ipc_read(netio_handler_type *handler, xfrd_state_t* xfrd)
{
sig_atomic_t cmd;
int len;
@@ -679,7 +723,6 @@ xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
if(xfrd->ipc_conn->is_reading==2) {
buffer_type* tmp = xfrd->ipc_pass;
uint32_t acl_num;
- int32_t acl_xfr;
/* read acl_num */
int ret = conn_read(xfrd->ipc_conn);
if(ret == -1) {
@@ -694,13 +737,11 @@ xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
xfrd->ipc_conn->packet = tmp;
xfrd->ipc_conn->is_reading = 0;
acl_num = buffer_read_u32(xfrd->ipc_pass);
- acl_xfr = (int32_t)buffer_read_u32(xfrd->ipc_pass);
- xfrd_handle_passed_packet(xfrd->ipc_conn->packet, acl_num, acl_xfr);
+ xfrd_handle_passed_packet(xfrd->ipc_conn->packet, acl_num);
return;
}
if(xfrd->ipc_conn->is_reading) {
/* reading an IPC message */
- buffer_type* tmp;
int ret = conn_read(xfrd->ipc_conn);
if(ret == -1) {
log_msg(LOG_ERR, "xfrd: error in read ipc: %s", strerror(errno));
@@ -710,22 +751,26 @@ xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
if(ret == 0)
return;
buffer_flip(xfrd->ipc_conn->packet);
- /* use ipc_conn to read remaining data as well */
- tmp = xfrd->ipc_pass;
- xfrd->ipc_conn->is_reading=2;
- xfrd->ipc_pass = xfrd->ipc_conn->packet;
- xfrd->ipc_conn->packet = tmp;
- xfrd->ipc_conn->total_bytes = sizeof(xfrd->ipc_conn->msglen);
- xfrd->ipc_conn->msglen = 2*sizeof(uint32_t);
- buffer_clear(xfrd->ipc_conn->packet);
- buffer_set_limit(xfrd->ipc_conn->packet, xfrd->ipc_conn->msglen);
+ if(xfrd->ipc_is_soa) {
+ xfrd->ipc_conn->is_reading = 0;
+ xfrd_handle_ipc_SOAINFO(xfrd, xfrd->ipc_conn->packet);
+ } else {
+ /* use ipc_conn to read remaining data as well */
+ buffer_type* tmp = xfrd->ipc_pass;
+ xfrd->ipc_conn->is_reading=2;
+ xfrd->ipc_pass = xfrd->ipc_conn->packet;
+ xfrd->ipc_conn->packet = tmp;
+ xfrd->ipc_conn->total_bytes = sizeof(xfrd->ipc_conn->msglen);
+ xfrd->ipc_conn->msglen = sizeof(uint32_t);
+ buffer_clear(xfrd->ipc_conn->packet);
+ buffer_set_limit(xfrd->ipc_conn->packet, xfrd->ipc_conn->msglen);
+ }
return;
}
- if((len = read(handler->ev_fd, &cmd, sizeof(cmd))) == -1) {
- if(errno != EINTR && errno != EAGAIN)
- log_msg(LOG_ERR, "xfrd_handle_ipc: read: %s",
- strerror(errno));
+ if((len = read(handler->fd, &cmd, sizeof(cmd))) == -1) {
+ log_msg(LOG_ERR, "xfrd_handle_ipc: read: %s",
+ strerror(errno));
return;
}
if(len == 0)
@@ -739,47 +784,48 @@ xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
switch(cmd) {
case NSD_QUIT:
case NSD_SHUTDOWN:
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main sent shutdown cmd."));
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main send shutdown cmd."));
xfrd->shutdown = 1;
break;
- case NSD_RELOAD_DONE:
+ case NSD_SOA_BEGIN:
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv SOA_BEGIN"));
+ /* reload starts sending SOA INFOs; don't block */
+ xfrd->parent_soa_info_pass = 1;
+ /* reset the nonblocking ipc write;
+ the new parent does not want half a packet */
+ xfrd->sending_zone_state = 0;
+ break;
+ case NSD_SOA_INFO:
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv SOA_INFO"));
+ assert(xfrd->parent_soa_info_pass);
+ xfrd->ipc_is_soa = 1;
+ xfrd->ipc_conn->is_reading = 1;
+ break;
+ case NSD_SOA_END:
/* reload has finished */
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_DONE"));
- if(block_read(NULL, handler->ev_fd, &xfrd->reload_pid,
- sizeof(pid_t), -1) != sizeof(pid_t)) {
- log_msg(LOG_ERR, "xfrd cannot get reload_pid");
- }
- /* read the not-mytask for the results and soainfo */
- xfrd_process_task_result(xfrd,
- xfrd->nsd->task[1-xfrd->nsd->mytask]);
- /* reset the IPC, (and the nonblocking ipc write;
- the new parent does not want half a packet) */
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv SOA_END"));
xfrd->can_send_reload = 1;
+ xfrd->parent_soa_info_pass = 0;
xfrd->ipc_send_blocked = 0;
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE);
+ handler->event_types |= NETIO_EVENT_WRITE;
xfrd_reopen_logfile();
xfrd_check_failed_updates();
+ xfrd_send_expy_all_zones();
break;
case NSD_PASS_TO_XFRD:
DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv PASS_TO_XFRD"));
+ xfrd->ipc_is_soa = 0;
xfrd->ipc_conn->is_reading = 1;
break;
- case NSD_RELOAD_REQ:
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_REQ"));
- /* make reload happen, right away, and schedule file check */
- task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask],
- xfrd->last_task, NULL);
- xfrd_set_reload_now(xfrd);
- break;
case NSD_RELOAD:
/* main tells us that reload is done, stop ipc send to main */
DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD"));
- ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE);
+ handler->event_types |= NETIO_EVENT_WRITE;
xfrd->need_to_send_quit = 1;
break;
default:
log_msg(LOG_ERR, "xfrd_handle_ipc: bad mode %d (%d)", (int)cmd,
- (int)ntohl(cmd));
+ ntohl(cmd));
break;
}
@@ -790,3 +836,4 @@ xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
buffer_clear(xfrd->ipc_conn->packet);
}
}
+