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