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