xref: /netbsd/external/bsd/nsd/dist/ipc.c (revision 66a1527d)
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 */
26 static void send_stat_to_child(struct main_ipc_handler_data* data, int fd);
27 /* send reload request over the IPC channel */
28 static void xfrd_send_reload_req(xfrd_state_type* xfrd);
29 /* send quit request over the IPC channel */
30 static void xfrd_send_quit_req(xfrd_state_type* xfrd);
31 /* perform read part of handle ipc for xfrd */
32 static void xfrd_handle_ipc_read(struct event* handler, xfrd_state_type* xfrd);
33 static void ipc_child_quit(struct nsd* nsd) ATTR_NORETURN;
34 
35 static void
ipc_child_quit(struct nsd * nsd)36 ipc_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 
57 void
child_handle_parent_command(int fd,short event,void * arg)58 child_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 
119 void
parent_handle_xfrd_command(netio_type * ATTR_UNUSED (netio),netio_handler_type * handler,netio_event_types_type event_types)120 parent_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 
169 static void
send_stat_to_child(struct main_ipc_handler_data * data,int fd)170 send_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
184 int packet_read_query_section(buffer_type *packet, uint8_t* dest, uint16_t* qtype, uint16_t* qclass);
185 static void
debug_print_fwd_name(int ATTR_UNUSED (len),buffer_type * packet,int acl_num)186 debug_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 
208 static void
send_quit_to_child(struct main_ipc_handler_data * data,int fd)209 send_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 */
229 static void
child_is_done(struct nsd * nsd,int fd)230 child_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 */
260 void
stats_add(struct nsdst * total,struct nsdst * s)261 stats_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 */
294 void
stats_subtract(struct nsdst * total,struct nsdst * s)295 stats_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 */
325 static void
read_child_stats(struct nsd * nsd,struct nsd_child * child,int fd)326 read_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 
345 void
parent_handle_child_command(netio_type * ATTR_UNUSED (netio),netio_handler_type * handler,netio_event_types_type event_types)346 parent_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 
502 void
parent_check_all_children_exited(struct nsd * nsd)503 parent_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 
516 void
parent_handle_reload_command(netio_type * ATTR_UNUSED (netio),netio_handler_type * handler,netio_event_types_type event_types)517 parent_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 
569 static void
xfrd_send_reload_req(xfrd_state_type * xfrd)570 xfrd_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 
599 void
ipc_xfrd_set_listening(struct xfrd_state * xfrd,short mode)600 ipc_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 
615 static void
xfrd_send_shutdown_req(xfrd_state_type * xfrd)616 xfrd_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 
629 static void
xfrd_send_quit_req(xfrd_state_type * xfrd)630 xfrd_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 
643 static void
xfrd_send_stats(xfrd_state_type * xfrd)644 xfrd_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 
655 void
xfrd_handle_ipc(int ATTR_UNUSED (fd),short event,void * arg)656 xfrd_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 
691 static void
xfrd_handle_ipc_read(struct event * handler,xfrd_state_type * xfrd)692 xfrd_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