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