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