xref: /openbsd-src/usr.sbin/nsd/ipc.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*
2  * ipc.c - Interprocess communication routines. Handlers read and write.
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 #include <errno.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <fcntl.h>
15 #include "ipc.h"
16 #include "buffer.h"
17 #include "xfrd-tcp.h"
18 #include "nsd.h"
19 #include "namedb.h"
20 #include "xfrd.h"
21 #include "xfrd-notify.h"
22 #include "difffile.h"
23 
24 /* attempt to send NSD_STATS command to child fd */
25 static void send_stat_to_child(struct main_ipc_handler_data* data, int fd);
26 /* send reload request over the IPC channel */
27 static void xfrd_send_reload_req(xfrd_state_t* xfrd);
28 /* send quit request over the IPC channel */
29 static void xfrd_send_quit_req(xfrd_state_t* xfrd);
30 /* perform read part of handle ipc for xfrd */
31 static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd);
32 
33 static void
34 ipc_child_quit(struct nsd* nsd)
35 {
36 	/* call shutdown and quit routines */
37 	nsd->mode = NSD_QUIT;
38 #ifdef	BIND8_STATS
39 	bind8_stats(nsd);
40 #endif /* BIND8_STATS */
41 
42 #if 0 /* OS collects memory pages */
43 	event_base_free(event_base);
44 	region_destroy(server_region);
45 #endif
46 	server_shutdown(nsd);
47 	exit(0);
48 }
49 
50 void
51 child_handle_parent_command(int fd, short event, void* arg)
52 {
53 	sig_atomic_t mode;
54 	int len;
55 	struct ipc_handler_conn_data *data =
56 		(struct ipc_handler_conn_data *) arg;
57 	if (!(event & EV_READ)) {
58 		return;
59 	}
60 
61 	if ((len = read(fd, &mode, sizeof(mode))) == -1) {
62 		log_msg(LOG_ERR, "handle_parent_command: read: %s",
63 			strerror(errno));
64 		return;
65 	}
66 	if (len == 0)
67 	{
68 		/* parent closed the connection. Quit */
69 		ipc_child_quit(data->nsd);
70 		return;
71 	}
72 
73 	switch (mode) {
74 	case NSD_STATS:
75 		data->nsd->mode = mode;
76 		break;
77 	case NSD_QUIT:
78 		ipc_child_quit(data->nsd);
79 		break;
80 	case NSD_QUIT_CHILD:
81 		/* close our listening sockets and ack */
82 		server_close_all_sockets(data->nsd->udp, data->nsd->ifs);
83 		server_close_all_sockets(data->nsd->tcp, data->nsd->ifs);
84 		/* mode == NSD_QUIT_CHILD */
85 		if(write(fd, &mode, sizeof(mode)) == -1) {
86 			VERBOSITY(3, (LOG_INFO, "quit child write: %s",
87 				strerror(errno)));
88 		}
89 		ipc_child_quit(data->nsd);
90 		break;
91 	case NSD_QUIT_WITH_STATS:
92 #ifdef BIND8_STATS
93 		DEBUG(DEBUG_IPC, 2, (LOG_INFO, "quit QUIT_WITH_STATS"));
94 		/* reply with ack and stats and then quit */
95 		if(!write_socket(fd, &mode, sizeof(mode))) {
96 			log_msg(LOG_ERR, "cannot write quitwst to parent");
97 		}
98 		if(!write_socket(fd, &data->nsd->st, sizeof(data->nsd->st))) {
99 			log_msg(LOG_ERR, "cannot write stats to parent");
100 		}
101 		fsync(fd);
102 #endif /* BIND8_STATS */
103 		ipc_child_quit(data->nsd);
104 		break;
105 	default:
106 		log_msg(LOG_ERR, "handle_parent_command: bad mode %d",
107 			(int) mode);
108 		break;
109 	}
110 }
111 
112 void
113 parent_handle_xfrd_command(netio_type *ATTR_UNUSED(netio),
114 		      netio_handler_type *handler,
115 		      netio_event_types_type event_types)
116 {
117 	sig_atomic_t mode;
118 	int len;
119 	struct ipc_handler_conn_data *data =
120 		(struct ipc_handler_conn_data *) handler->user_data;
121 	if (!(event_types & NETIO_EVENT_READ)) {
122 		return;
123 	}
124 
125 	if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) {
126 		log_msg(LOG_ERR, "handle_xfrd_command: read: %s",
127 			strerror(errno));
128 		return;
129 	}
130 	if (len == 0)
131 	{
132 		/* xfrd closed, we must quit */
133 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "handle_xfrd_command: xfrd closed channel."));
134 		close(handler->fd);
135 		handler->fd = -1;
136 		data->nsd->mode = NSD_SHUTDOWN;
137 		return;
138 	}
139 
140 	switch (mode) {
141 	case NSD_RELOAD:
142 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "parent handle xfrd command RELOAD"));
143 		data->nsd->signal_hint_reload = 1;
144 		break;
145 	case NSD_QUIT:
146 	case NSD_SHUTDOWN:
147 		data->nsd->mode = mode;
148 		break;
149 	case NSD_STATS:
150 		data->nsd->signal_hint_stats = 1;
151 		break;
152 	case NSD_REAP_CHILDREN:
153 		data->nsd->signal_hint_child = 1;
154 		break;
155 	default:
156 		log_msg(LOG_ERR, "handle_xfrd_command: bad mode %d",
157 			(int) mode);
158 		break;
159 	}
160 }
161 
162 static void
163 send_stat_to_child(struct main_ipc_handler_data* data, int fd)
164 {
165 	sig_atomic_t cmd = NSD_STATS;
166 	if(write(fd, &cmd, sizeof(cmd)) == -1) {
167 		if(errno == EAGAIN || errno == EINTR)
168 			return; /* try again later */
169 		log_msg(LOG_ERR, "svrmain: problems sending stats to child %d command: %s",
170 			(int)data->child->pid, strerror(errno));
171 		return;
172 	}
173 	data->child->need_to_send_STATS = 0;
174 }
175 
176 #ifndef NDEBUG
177 int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass);
178 static void
179 debug_print_fwd_name(int ATTR_UNUSED(len), buffer_type* packet, int acl_num)
180 {
181 	uint8_t qnamebuf[MAXDOMAINLEN];
182 	uint16_t qtype, qclass;
183 	const dname_type* dname;
184 	region_type* tempregion = region_create(xalloc, free);
185 
186 	size_t bufpos = buffer_position(packet);
187 	buffer_rewind(packet);
188 	buffer_skip(packet, 12);
189 	if(packet_read_query_section(packet, qnamebuf, &qtype, &qclass)) {
190 		dname = dname_make(tempregion, qnamebuf, 1);
191 		log_msg(LOG_INFO, "main: fwd packet for %s, acl %d",
192 			dname_to_string(dname,0), acl_num);
193 	} else {
194 		log_msg(LOG_INFO, "main: fwd packet badqname, acl %d", acl_num);
195 	}
196 	buffer_set_position(packet, bufpos);
197 	region_destroy(tempregion);
198 }
199 #endif
200 
201 static void
202 send_quit_to_child(struct main_ipc_handler_data* data, int fd)
203 {
204 #ifdef BIND8_STATS
205 	sig_atomic_t cmd = NSD_QUIT_WITH_STATS;
206 #else
207 	sig_atomic_t cmd = NSD_QUIT;
208 #endif
209 	if(write(fd, &cmd, sizeof(cmd)) == -1) {
210 		if(errno == EAGAIN || errno == EINTR)
211 			return; /* try again later */
212 		log_msg(LOG_ERR, "svrmain: problems sending quit to child %d command: %s",
213 			(int)data->child->pid, strerror(errno));
214 		return;
215 	}
216 	data->child->need_to_send_QUIT = 0;
217 	DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: sent quit to child %d",
218 		(int)data->child->pid));
219 }
220 
221 /** the child is done, mark it as exited */
222 static void
223 child_is_done(struct nsd* nsd, int fd)
224 {
225 	size_t i;
226 	if(fd != -1) close(fd);
227 	for(i=0; i<nsd->child_count; ++i)
228 		if(nsd->children[i].child_fd == fd) {
229 			nsd->children[i].child_fd = -1;
230 			nsd->children[i].handler->fd = -1;
231 			if(nsd->children[i].need_to_exit) {
232 				DEBUG(DEBUG_IPC,1, (LOG_INFO, "server %d is done",
233 					(int)nsd->children[i].pid));
234 				nsd->children[i].has_exited = 1;
235 			} else {
236 				log_msg(LOG_WARNING,
237 				       "server %d died unexpectedly, restarting",
238 				       (int)nsd->children[i].pid);
239 				/* this child is now going to be re-forked as
240 				 * a subprocess of this server-main, and if a
241 				 * reload is in progress the other children
242 				 * are subprocesses of reload.  Until the
243 				 * reload is done and they are all reforked. */
244 				nsd->children[i].pid = -1;
245 				nsd->restart_children = 1;
246 			}
247 		}
248 	parent_check_all_children_exited(nsd);
249 }
250 
251 #ifdef BIND8_STATS
252 /** add stats to total */
253 void
254 stats_add(struct nsdst* total, struct nsdst* s)
255 {
256 	unsigned i;
257 	for(i=0; i<sizeof(total->qtype)/sizeof(stc_t); i++)
258 		total->qtype[i] += s->qtype[i];
259 	for(i=0; i<sizeof(total->qclass)/sizeof(stc_t); i++)
260 		total->qclass[i] += s->qclass[i];
261 	total->qudp += s->qudp;
262 	total->qudp6 += s->qudp6;
263 	total->ctcp += s->ctcp;
264 	total->ctcp6 += s->ctcp6;
265 	for(i=0; i<sizeof(total->rcode)/sizeof(stc_t); i++)
266 		total->rcode[i] += s->rcode[i];
267 	for(i=0; i<sizeof(total->opcode)/sizeof(stc_t); i++)
268 		total->opcode[i] += s->opcode[i];
269 	total->dropped += s->dropped;
270 	total->truncated += s->truncated;
271 	total->wrongzone += s->wrongzone;
272 	total->txerr += s->txerr;
273 	total->rxerr += s->rxerr;
274 	total->edns += s->edns;
275 	total->ednserr += s->ednserr;
276 	total->raxfr += s->raxfr;
277 	total->nona += s->nona;
278 
279 	total->db_disk = s->db_disk;
280 	total->db_mem = s->db_mem;
281 }
282 
283 /** subtract stats from total */
284 void
285 stats_subtract(struct nsdst* total, struct nsdst* s)
286 {
287 	unsigned i;
288 	for(i=0; i<sizeof(total->qtype)/sizeof(stc_t); i++)
289 		total->qtype[i] -= s->qtype[i];
290 	for(i=0; i<sizeof(total->qclass)/sizeof(stc_t); i++)
291 		total->qclass[i] -= s->qclass[i];
292 	total->qudp -= s->qudp;
293 	total->qudp6 -= s->qudp6;
294 	total->ctcp -= s->ctcp;
295 	total->ctcp6 -= s->ctcp6;
296 	for(i=0; i<sizeof(total->rcode)/sizeof(stc_t); i++)
297 		total->rcode[i] -= s->rcode[i];
298 	for(i=0; i<sizeof(total->opcode)/sizeof(stc_t); i++)
299 		total->opcode[i] -= s->opcode[i];
300 	total->dropped -= s->dropped;
301 	total->truncated -= s->truncated;
302 	total->wrongzone -= s->wrongzone;
303 	total->txerr -= s->txerr;
304 	total->rxerr -= s->rxerr;
305 	total->edns -= s->edns;
306 	total->ednserr -= s->ednserr;
307 	total->raxfr -= s->raxfr;
308 	total->nona -= s->nona;
309 }
310 
311 #define FINAL_STATS_TIMEOUT 10 /* seconds */
312 static void
313 read_child_stats(struct nsd* nsd, struct nsd_child* child, int fd)
314 {
315 	struct nsdst s;
316 	errno=0;
317 	if(block_read(nsd, fd, &s, sizeof(s), FINAL_STATS_TIMEOUT)!=sizeof(s)) {
318 		log_msg(LOG_ERR, "problems reading finalstats from server "
319 			"%d: %s", (int)child->pid, strerror(errno));
320 	} else {
321 		stats_add(&nsd->st, &s);
322 		child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6;
323 		/* we know that the child is going to close the connection
324 		 * now (this is an ACK of the QUIT_W_STATS so we know the
325 		 * child is done, no longer sending e.g. NOTIFY contents) */
326 		child_is_done(nsd, fd);
327 	}
328 }
329 #endif /* BIND8_STATS */
330 
331 void
332 parent_handle_child_command(netio_type *ATTR_UNUSED(netio),
333 		      netio_handler_type *handler,
334 		      netio_event_types_type event_types)
335 {
336 	sig_atomic_t mode;
337 	int len;
338 	struct main_ipc_handler_data *data =
339 		(struct main_ipc_handler_data*)handler->user_data;
340 
341 	/* do a nonblocking write to the child if it is ready. */
342 	if (event_types & NETIO_EVENT_WRITE) {
343 		if(data->child->need_to_send_STATS &&
344 			!data->child->need_to_exit) {
345 			send_stat_to_child(data, handler->fd);
346 		} else if(data->child->need_to_send_QUIT) {
347 			send_quit_to_child(data, handler->fd);
348 			if(!data->child->need_to_send_QUIT)
349 				handler->event_types = NETIO_EVENT_READ;
350 		} else {
351 			handler->event_types = NETIO_EVENT_READ;
352 		}
353 	}
354 
355 	if (!(event_types & NETIO_EVENT_READ)) {
356 		return;
357 	}
358 
359 	if (data->forward_mode) {
360 		int got_acl;
361 		/* forward the data to xfrd */
362 		DEBUG(DEBUG_IPC,2, (LOG_INFO,
363 			"main passed packet readup %d", (int)data->got_bytes));
364 		if(data->got_bytes < sizeof(data->total_bytes))
365 		{
366 			if ((len = read(handler->fd,
367 				(char*)&data->total_bytes+data->got_bytes,
368 				sizeof(data->total_bytes)-data->got_bytes)) == -1) {
369 				log_msg(LOG_ERR, "handle_child_command: read: %s",
370 					strerror(errno));
371 				return;
372 			}
373 			if(len == 0) {
374 				/* EOF */
375 				data->forward_mode = 0;
376 				return;
377 			}
378 			data->got_bytes += len;
379 			if(data->got_bytes < sizeof(data->total_bytes))
380 				return;
381 			data->total_bytes = ntohs(data->total_bytes);
382 			buffer_clear(data->packet);
383 			if(data->total_bytes > buffer_capacity(data->packet)) {
384 				log_msg(LOG_ERR, "internal error: ipc too large");
385 				exit(1);
386 			}
387 			return;
388 		}
389 		/* read the packet */
390 		if(data->got_bytes-sizeof(data->total_bytes) < data->total_bytes) {
391 			if((len = read(handler->fd, buffer_current(data->packet),
392 				data->total_bytes - (data->got_bytes-sizeof(data->total_bytes))
393 				)) == -1 ) {
394 				log_msg(LOG_ERR, "handle_child_command: read: %s",
395 					strerror(errno));
396 				return;
397 			}
398 			if(len == 0) {
399 				/* EOF */
400 				data->forward_mode = 0;
401 				return;
402 			}
403 			data->got_bytes += len;
404 			buffer_skip(data->packet, len);
405 			/* read rest later */
406 			return;
407 		}
408 		/* read the acl numbers */
409 		got_acl = data->got_bytes - sizeof(data->total_bytes) - data->total_bytes;
410 		if((len = read(handler->fd, (char*)&data->acl_num+got_acl,
411 			sizeof(data->acl_num)+sizeof(data->acl_xfr)-got_acl)) == -1 ) {
412 			log_msg(LOG_ERR, "handle_child_command: read: %s",
413 				strerror(errno));
414 			return;
415 		}
416 		if(len == 0) {
417 			/* EOF */
418 			data->forward_mode = 0;
419 			return;
420 		}
421 		got_acl += len;
422 		data->got_bytes += len;
423 		if(got_acl >= (int)(sizeof(data->acl_num)+sizeof(data->acl_xfr))) {
424 			uint16_t len = htons(data->total_bytes);
425 			DEBUG(DEBUG_IPC,2, (LOG_INFO,
426 				"main fwd passed packet write %d", (int)data->got_bytes));
427 #ifndef NDEBUG
428 			if(nsd_debug_level >= 2)
429 				debug_print_fwd_name(len, data->packet, data->acl_num);
430 #endif
431 			data->forward_mode = 0;
432 			mode = NSD_PASS_TO_XFRD;
433 			if(!write_socket(*data->xfrd_sock, &mode, sizeof(mode)) ||
434 			   !write_socket(*data->xfrd_sock, &len, sizeof(len)) ||
435 			   !write_socket(*data->xfrd_sock, buffer_begin(data->packet),
436 				data->total_bytes) ||
437 			   !write_socket(*data->xfrd_sock, &data->acl_num,
438 			   	sizeof(data->acl_num)) ||
439 			   !write_socket(*data->xfrd_sock, &data->acl_xfr,
440 			   	sizeof(data->acl_xfr))) {
441 				log_msg(LOG_ERR, "error in ipc fwd main2xfrd: %s",
442 					strerror(errno));
443 			}
444 		}
445 		return;
446 	}
447 
448 	/* read command from ipc */
449 	if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) {
450 		log_msg(LOG_ERR, "handle_child_command: read: %s",
451 			strerror(errno));
452 		return;
453 	}
454 	if (len == 0)
455 	{
456 		child_is_done(data->nsd, handler->fd);
457 		return;
458 	}
459 
460 	switch (mode) {
461 	case NSD_QUIT:
462 		data->nsd->mode = mode;
463 		break;
464 #ifdef BIND8_STATS
465 	case NSD_QUIT_WITH_STATS:
466 		read_child_stats(data->nsd, data->child, handler->fd);
467 		break;
468 #endif /* BIND8_STATS */
469 	case NSD_STATS:
470 		data->nsd->signal_hint_stats = 1;
471 		break;
472 	case NSD_REAP_CHILDREN:
473 		data->nsd->signal_hint_child = 1;
474 		break;
475 	case NSD_PASS_TO_XFRD:
476 		/* set mode for handle_child_command; echo to xfrd. */
477 		data->forward_mode = 1;
478 		data->got_bytes = 0;
479 		data->total_bytes = 0;
480 		break;
481 	default:
482 		log_msg(LOG_ERR, "handle_child_command: bad mode %d",
483 			(int) mode);
484 		break;
485 	}
486 }
487 
488 void
489 parent_check_all_children_exited(struct nsd* nsd)
490 {
491 	size_t i;
492 	for(i=0; i < nsd->child_count; i++) {
493 		if(!nsd->children[i].need_to_exit)
494 		      return;
495 		if(!nsd->children[i].has_exited)
496 		      return;
497 	}
498 	nsd->mode = NSD_QUIT_SYNC;
499 	DEBUG(DEBUG_IPC,2, (LOG_INFO, "main: all children exited. quit sync."));
500 }
501 
502 void
503 parent_handle_reload_command(netio_type *ATTR_UNUSED(netio),
504 		      netio_handler_type *handler,
505 		      netio_event_types_type event_types)
506 {
507 	sig_atomic_t mode;
508 	int len;
509 	size_t i;
510 	struct nsd *nsd = (struct nsd*) handler->user_data;
511 	if (!(event_types & NETIO_EVENT_READ)) {
512 		return;
513 	}
514 	/* read command from ipc */
515 	if ((len = read(handler->fd, &mode, sizeof(mode))) == -1) {
516 		log_msg(LOG_ERR, "handle_reload_command: read: %s",
517 			strerror(errno));
518 		return;
519 	}
520 	if (len == 0)
521 	{
522 		if(handler->fd != -1) {
523 			close(handler->fd);
524 			handler->fd = -1;
525 		}
526 		log_msg(LOG_ERR, "handle_reload_cmd: reload closed cmd channel");
527 		nsd->reload_failed = 1;
528 		return;
529 	}
530 	switch (mode) {
531 	case NSD_QUIT_SYNC:
532 		/* set all children to exit, only then notify xfrd. */
533 		/* so that buffered packets to pass to xfrd can arrive. */
534 		for(i=0; i < nsd->child_count; i++) {
535 			nsd->children[i].need_to_exit = 1;
536 			if(nsd->children[i].pid > 0 &&
537 			   nsd->children[i].child_fd != -1) {
538 				nsd->children[i].need_to_send_QUIT = 1;
539 				nsd->children[i].handler->event_types
540 					|= NETIO_EVENT_WRITE;
541 			} else {
542 				if(nsd->children[i].child_fd == -1)
543 					nsd->children[i].has_exited = 1;
544 			}
545 		}
546 		parent_check_all_children_exited(nsd);
547 		break;
548 	default:
549 		log_msg(LOG_ERR, "handle_reload_command: bad mode %d",
550 			(int) mode);
551 		break;
552 	}
553 }
554 
555 static void
556 xfrd_send_reload_req(xfrd_state_t* xfrd)
557 {
558 	sig_atomic_t req = NSD_RELOAD;
559 	uint64_t p = xfrd->last_task->data;
560 	udb_ptr_unlink(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
561 	task_process_sync(xfrd->nsd->task[xfrd->nsd->mytask]);
562 	/* ask server_main for a reload */
563 	if(write(xfrd->ipc_handler.ev_fd, &req, sizeof(req)) == -1) {
564 		udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
565 		udb_ptr_set(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask], p);
566 		if(errno == EAGAIN || errno == EINTR)
567 			return; /* try again later */
568 		log_msg(LOG_ERR, "xfrd: problems sending reload command: %s",
569 			strerror(errno));
570 		return;
571 	}
572 	DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: asked nsd to reload new updates"));
573 	/* swapped task to other side, start to use other task udb. */
574 	xfrd->nsd->mytask = 1 - xfrd->nsd->mytask;
575 	task_remap(xfrd->nsd->task[xfrd->nsd->mytask]);
576 	udb_ptr_init(xfrd->last_task, xfrd->nsd->task[xfrd->nsd->mytask]);
577 	assert(udb_base_get_userdata(xfrd->nsd->task[xfrd->nsd->mytask])->data == 0);
578 
579 	xfrd_prepare_zones_for_reload();
580 	xfrd->reload_cmd_last_sent = xfrd_time();
581 	xfrd->need_to_send_reload = 0;
582 	xfrd->can_send_reload = 0;
583 }
584 
585 void
586 ipc_xfrd_set_listening(struct xfrd_state* xfrd, short mode)
587 {
588 	int fd = xfrd->ipc_handler.ev_fd;
589 	struct event_base* base = xfrd->event_base;
590 	event_del(&xfrd->ipc_handler);
591 	event_set(&xfrd->ipc_handler, fd, mode, xfrd_handle_ipc, xfrd);
592 	if(event_base_set(base, &xfrd->ipc_handler) != 0)
593 		log_msg(LOG_ERR, "ipc: cannot set event_base");
594 	/* no timeout for IPC events */
595 	if(event_add(&xfrd->ipc_handler, NULL) != 0)
596 		log_msg(LOG_ERR, "ipc: cannot add event");
597 	xfrd->ipc_handler_flags = mode;
598 }
599 
600 static void
601 xfrd_send_shutdown_req(xfrd_state_t* xfrd)
602 {
603 	sig_atomic_t cmd = NSD_SHUTDOWN;
604 	xfrd->ipc_send_blocked = 1;
605 	ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
606 	DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send shutdown"));
607 	if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
608 		log_msg(LOG_ERR, "xfrd: error writing shutdown to main: %s",
609 			strerror(errno));
610 	}
611 	xfrd->need_to_send_shutdown = 0;
612 }
613 
614 static void
615 xfrd_send_quit_req(xfrd_state_t* xfrd)
616 {
617 	sig_atomic_t cmd = NSD_QUIT;
618 	xfrd->ipc_send_blocked = 1;
619 	ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
620 	DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send ackreload(quit)"));
621 	if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
622 		log_msg(LOG_ERR, "xfrd: error writing ack to main: %s",
623 			strerror(errno));
624 	}
625 	xfrd->need_to_send_quit = 0;
626 }
627 
628 static void
629 xfrd_send_stats(xfrd_state_t* xfrd)
630 {
631 	sig_atomic_t cmd = NSD_STATS;
632 	DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc send stats"));
633 	if(!write_socket(xfrd->ipc_handler.ev_fd, &cmd, sizeof(cmd))) {
634 		log_msg(LOG_ERR, "xfrd: error writing stats to main: %s",
635 			strerror(errno));
636 	}
637 	xfrd->need_to_send_stats = 0;
638 }
639 
640 void
641 xfrd_handle_ipc(int ATTR_UNUSED(fd), short event, void* arg)
642 {
643 	xfrd_state_t* xfrd = (xfrd_state_t*)arg;
644         if ((event & EV_READ))
645 	{
646 		/* first attempt to read as a signal from main
647 		 * could block further send operations */
648 		xfrd_handle_ipc_read(&xfrd->ipc_handler, xfrd);
649 	}
650         if ((event & EV_WRITE))
651 	{
652 		if(xfrd->ipc_send_blocked) { /* wait for RELOAD_DONE */
653 			ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
654 			return;
655 		}
656 		if(xfrd->need_to_send_shutdown) {
657 			xfrd_send_shutdown_req(xfrd);
658 		} else if(xfrd->need_to_send_quit) {
659 			xfrd_send_quit_req(xfrd);
660 		} else if(xfrd->can_send_reload && xfrd->need_to_send_reload) {
661 			xfrd_send_reload_req(xfrd);
662 		} else if(xfrd->need_to_send_stats) {
663 			xfrd_send_stats(xfrd);
664 		}
665 		if(!(xfrd->can_send_reload && xfrd->need_to_send_reload) &&
666 			!xfrd->need_to_send_shutdown &&
667 			!xfrd->need_to_send_quit &&
668 			!xfrd->need_to_send_stats) {
669 			/* disable writing for now */
670 			ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ);
671 		}
672 	}
673 
674 }
675 
676 static void
677 xfrd_handle_ipc_read(struct event* handler, xfrd_state_t* xfrd)
678 {
679         sig_atomic_t cmd;
680         int len;
681 
682 	if(xfrd->ipc_conn->is_reading==2) {
683 		buffer_type* tmp = xfrd->ipc_pass;
684 		uint32_t acl_num;
685 		int32_t acl_xfr;
686 		/* read acl_num */
687 		int ret = conn_read(xfrd->ipc_conn);
688 		if(ret == -1) {
689 			log_msg(LOG_ERR, "xfrd: error in read ipc: %s", strerror(errno));
690 			xfrd->ipc_conn->is_reading = 0;
691 			return;
692 		}
693 		if(ret == 0)
694 			return;
695 		buffer_flip(xfrd->ipc_conn->packet);
696 		xfrd->ipc_pass = xfrd->ipc_conn->packet;
697 		xfrd->ipc_conn->packet = tmp;
698 		xfrd->ipc_conn->is_reading = 0;
699 		acl_num = buffer_read_u32(xfrd->ipc_pass);
700 		acl_xfr = (int32_t)buffer_read_u32(xfrd->ipc_pass);
701 		xfrd_handle_passed_packet(xfrd->ipc_conn->packet, acl_num, acl_xfr);
702 		return;
703 	}
704 	if(xfrd->ipc_conn->is_reading) {
705 		/* reading an IPC message */
706 		buffer_type* tmp;
707 		int ret = conn_read(xfrd->ipc_conn);
708 		if(ret == -1) {
709 			log_msg(LOG_ERR, "xfrd: error in read ipc: %s", strerror(errno));
710 			xfrd->ipc_conn->is_reading = 0;
711 			return;
712 		}
713 		if(ret == 0)
714 			return;
715 		buffer_flip(xfrd->ipc_conn->packet);
716 		/* use ipc_conn to read remaining data as well */
717 		tmp = xfrd->ipc_pass;
718 		xfrd->ipc_conn->is_reading=2;
719 		xfrd->ipc_pass = xfrd->ipc_conn->packet;
720 		xfrd->ipc_conn->packet = tmp;
721 		xfrd->ipc_conn->total_bytes = sizeof(xfrd->ipc_conn->msglen);
722 		xfrd->ipc_conn->msglen = 2*sizeof(uint32_t);
723 		buffer_clear(xfrd->ipc_conn->packet);
724 		buffer_set_limit(xfrd->ipc_conn->packet, xfrd->ipc_conn->msglen);
725 		return;
726 	}
727 
728         if((len = read(handler->ev_fd, &cmd, sizeof(cmd))) == -1) {
729 		if(errno != EINTR && errno != EAGAIN)
730                 	log_msg(LOG_ERR, "xfrd_handle_ipc: read: %s",
731                         	strerror(errno));
732                 return;
733         }
734         if(len == 0)
735         {
736 		/* parent closed the connection. Quit */
737 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main closed connection."));
738 		xfrd->shutdown = 1;
739 		return;
740         }
741 
742         switch(cmd) {
743         case NSD_QUIT:
744         case NSD_SHUTDOWN:
745 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: main sent shutdown cmd."));
746                 xfrd->shutdown = 1;
747                 break;
748 	case NSD_RELOAD_DONE:
749 		/* reload has finished */
750 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_DONE"));
751 		if(block_read(NULL, handler->ev_fd, &xfrd->reload_pid,
752 			sizeof(pid_t), -1) != sizeof(pid_t)) {
753 			log_msg(LOG_ERR, "xfrd cannot get reload_pid");
754 		}
755 		/* read the not-mytask for the results and soainfo */
756 		xfrd_process_task_result(xfrd,
757 			xfrd->nsd->task[1-xfrd->nsd->mytask]);
758 		/* reset the IPC, (and the nonblocking ipc write;
759 		   the new parent does not want half a packet) */
760 		xfrd->can_send_reload = 1;
761 		xfrd->ipc_send_blocked = 0;
762 		ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE);
763 		xfrd_reopen_logfile();
764 		xfrd_check_failed_updates();
765 		break;
766 	case NSD_PASS_TO_XFRD:
767 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv PASS_TO_XFRD"));
768 		xfrd->ipc_conn->is_reading = 1;
769 		break;
770 	case NSD_RELOAD_REQ:
771 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD_REQ"));
772 		/* make reload happen, right away, and schedule file check */
773 		task_new_check_zonefiles(xfrd->nsd->task[xfrd->nsd->mytask],
774 			xfrd->last_task, NULL);
775 		xfrd_set_reload_now(xfrd);
776 		break;
777 	case NSD_RELOAD:
778 		/* main tells us that reload is done, stop ipc send to main */
779 		DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: ipc recv RELOAD"));
780 		ipc_xfrd_set_listening(xfrd, EV_PERSIST|EV_READ|EV_WRITE);
781 		xfrd->need_to_send_quit = 1;
782 		break;
783         default:
784                 log_msg(LOG_ERR, "xfrd_handle_ipc: bad mode %d (%d)", (int)cmd,
785 			(int)ntohl(cmd));
786                 break;
787         }
788 
789 	if(xfrd->ipc_conn->is_reading) {
790 		/* setup read of info */
791 		xfrd->ipc_conn->total_bytes = 0;
792 		xfrd->ipc_conn->msglen = 0;
793 		buffer_clear(xfrd->ipc_conn->packet);
794 	}
795 }
796