ipc.c revision 1.3
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 */
25static void send_stat_to_child(struct main_ipc_handler_data* data, int fd);
26/* send reload request over the IPC channel */
27static void xfrd_send_reload_req(xfrd_state_type* xfrd);
28/* send quit request over the IPC channel */
29static void xfrd_send_quit_req(xfrd_state_type* xfrd);
30/* perform read part of handle ipc for xfrd */
31static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd);
32
33static void
34ipc_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
50void
51child_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
112void
113parent_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
162static void
163send_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
177int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass);
178static void
179debug_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
201static void
202send_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 */
222static void
223child_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 */
253void
254stats_add(struct nsdst* total, struct nsdst* s)
255{
256	unsigned i;
257	for(i=0; i<sizeof(total->qtype)/sizeof(stc_type); i++)
258		total->qtype[i] += s->qtype[i];
259	for(i=0; i<sizeof(total->qclass)/sizeof(stc_type); 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_type); i++)
266		total->rcode[i] += s->rcode[i];
267	for(i=0; i<sizeof(total->opcode)/sizeof(stc_type); 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 */
284void
285stats_subtract(struct nsdst* total, struct nsdst* s)
286{
287	unsigned i;
288	for(i=0; i<sizeof(total->qtype)/sizeof(stc_type); i++)
289		total->qtype[i] -= s->qtype[i];
290	for(i=0; i<sizeof(total->qclass)/sizeof(stc_type); 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_type); i++)
297		total->rcode[i] -= s->rcode[i];
298	for(i=0; i<sizeof(total->opcode)/sizeof(stc_type); 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 */
312static void
313read_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
331void
332parent_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
488void
489parent_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
502void
503parent_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
555static void
556xfrd_send_reload_req(xfrd_state_type* 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
585void
586ipc_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
600static void
601xfrd_send_shutdown_req(xfrd_state_type* 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
614static void
615xfrd_send_quit_req(xfrd_state_type* 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
628static void
629xfrd_send_stats(xfrd_state_type* 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
640void
641xfrd_handle_ipc(int ATTR_UNUSED(fd), short event, void* arg)
642{
643	xfrd_state_type* xfrd = (xfrd_state_type*)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
676static void
677xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* 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