HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / echld / dispatcher.c
blob3dbe8f0048939759139f6733bd53aae0c34a8108
1 /* echld_dispatcher.c
2 * epan working child API internals
3 * Dispatcher process routines and definitions
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * Copyright (c) 2013 by Luis Ontanon <luis@ontanon.org>
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "echld-int.h"
29 /**
30 DISPATCHER
31 **/
33 struct dispatcher_child {
34 echld_chld_id_t chld_id;
35 child_state_t state;
36 echld_reader_t reader;
37 int write_fd;
38 int pid;
39 int reqh_id;
40 gboolean closing;
43 struct dispatcher {
44 int parent_out;
45 echld_reader_t parent_in;
46 struct dispatcher_child* children;
47 int max_children;
48 int nchildren;
49 int reqh_id;
50 int pid;
51 int ppid;
52 struct _encs {
53 child_encoder_t* to_parent;
54 echld_parent_encoder_t* to_child;
55 } enc;
56 struct _decs {
57 child_decoder_t* from_parent;
58 parent_decoder_t* from_child;
59 } dec;
61 int dumpcap_pid;
62 gboolean closing;
63 capture_options capture_opts;
66 struct dispatcher* dispatcher;
68 #ifdef DEBUG_DISPATCHER
69 static int debug_lvl = DEBUG_DISPATCHER;
70 static FILE* debug_fp = NULL;
72 #define DCOM() /*echld_common_set_dbg(debug_lvl,debug_fp,"Disp")*/
74 int dispatcher_debug(int level, const char* fmt, ...) {
75 va_list ap;
76 char* str;
78 if (debug_lvl<level) return 1;
80 va_start(ap, fmt);
81 str = g_strdup_vprintf(fmt,ap);
82 va_end(ap);
84 if (dispatcher) {
85 fprintf(debug_fp, "dispatcher[%d]: reqh_id=%d dbg_level=%d message='%s'\n", dispatcher->pid, dispatcher->reqh_id, level, str);
86 } else {
87 fprintf(debug_fp, "dispatcher: dbg_level=%d message='%s'\n", level, str);
90 fflush(debug_fp);
92 g_free(str);
94 return 1;
98 static char* param_get_dbg_level(char** err _U_) {
99 return g_strdup_printf("%d",debug_lvl);
102 static echld_bool_t param_set_dbg_level(char* val , char** err ) {
103 char* p;
104 int lvl = (int)strtol(val, &p, 10);
106 if (p<=val) {
107 *err = g_strdup("not an integer");
108 return FALSE;
109 } else if (lvl < 0 || lvl > 5) {
110 *err = g_strdup_printf("invalid level=%d (min=0 max=5)",lvl);
111 return FALSE;
114 debug_lvl = lvl;
115 DCOM();
116 return TRUE;
119 static long dbg_r = 0;
121 #define DISP_DBG(attrs) ( dispatcher_debug attrs )
122 #define DISP_DBG_INIT() do { debug_fp = stderr; DCOM(); } while(0)
123 #define DISP_DBG_START(fname) do { debug_fp = fopen(fname,"a"); DCOM(); DISP_DBG((0,"Log Started")); } while(0)
124 #define DISP_WRITE(FD,BA,CH,T,RH) ( dbg_r = echld_write_frame(FD,BA,CH,T,RH,NULL), DISP_DBG((1,"SND fd=%d ch=%d ty='%s' rh=%d msg='%s'",FD,CH,TY(T),RH, (dbg_r>0?"ok":strerror(errno)))), dbg_r )
125 #define CHLD_SET_STATE(c,st) do { DISP_DBG((1,"Child[%d] State %s => %s",(c)->chld_id, ST((c)->state), ST((st)) )); (c)->state=(st); } while(0)
126 #else
127 #define DISP_DBG(attrs)
128 #define DISP_DBG_INIT()
129 #define DISP_DBG_START(fname)
130 #define DISP_WRITE(FD,BA,CH,T,RH) echld_write_frame(FD,BA,CH,T,RH,NULL)
131 #define CHLD_SET_STATE(c,st) ((c)->state = (st))
132 #endif
134 #define DISP_RESP(B,T) (DISP_WRITE( dispatcher->parent_out, (B), 0, (T), dispatcher->reqh_id))
138 static echld_epan_stuff_t stuff;
140 static void init_stuff(void) {
141 #ifdef HAVE_LIBPCAP
142 capture_opts_init(&stuff.cap_opts);
143 capture_session_init(&stuff.cap_sess, (void *)&stuff.cfile);
144 #endif
148 static void children_massacre(void) {
149 int i;
150 struct dispatcher_child* cc = dispatcher->children;
151 int max_children = dispatcher->max_children;
153 for(i = 0; i < max_children; i++) {
154 struct dispatcher_child* c = &(cc[i]);
155 if (c->pid > 0) {
156 DISP_DBG((0,"killing ch=%d pid=%d",c->chld_id,c->pid));
157 kill(c->pid,SIGTERM);
163 static void dispatcher_fatal(int cause, const char* fmt, ...) {
164 size_t len= 1024;
165 gchar err_str[len];
166 va_list ap;
168 va_start(ap, fmt);
169 g_vsnprintf(err_str,len,fmt,ap);
170 va_end(ap);
172 DISP_DBG((0,"fatal cause=%d msg=\"%s\"",cause ,err_str));
174 children_massacre();
176 exit(cause);
179 #define DISP_FATAL(attrs) dispatcher_fatal attrs
181 static void dispatcher_err(int errnum, const char* fmt, ...) {
182 size_t len= 1024;
183 gchar err_str[len];
184 va_list ap;
185 static GByteArray* ba;
187 va_start(ap, fmt);
188 g_vsnprintf(err_str,len,fmt,ap);
189 va_end(ap);
191 DISP_DBG((0,"error=\"%s\"",err_str));
193 ba = dispatcher->enc.to_parent->error(errnum, err_str);
194 DISP_RESP(ba,ECHLD_ERROR);
195 g_byte_array_free(ba,TRUE);
198 /* parameters */
200 /* interface listing */
202 static char* intflist2json(GList* if_list, char** if_cap_err) {
203 #define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
205 int i;
206 GList *if_entry;
207 if_info_t *if_info;
208 GSList *addr;
209 if_addr_t *if_addr;
210 if_capabilities_t *caps;
211 char addr_str[ADDRSTRLEN];
212 GString *str = g_string_new("{ what='interfaces', interfaces={ \n");
213 char* s;
215 i = 1; /* Interface id number */
216 for (if_entry = g_list_first(if_list); if_entry != NULL;
217 if_entry = g_list_next(if_entry)) {
218 if_info = (if_info_t *)if_entry->data;
219 g_string_append_printf(str," %s={ intf='%s',", if_info->name, if_info->name);
222 * Print the contents of the if_entry struct in a parseable format.
223 * Each if_entry element is tab-separated. Addresses are comma-
224 * separated.
226 /* XXX - Make sure our description doesn't contain a tab */
227 if (if_info->vendor_description != NULL)
228 g_string_append_printf(str," vnd_desc='%s',", if_info->vendor_description);
230 /* XXX - Make sure our friendly name doesn't contain a tab */
231 if (if_info->friendly_name != NULL)
232 g_string_append_printf(str," name='%s', addrs=[ ", if_info->friendly_name);
234 for (addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
235 addr = g_slist_next(addr)) {
237 if_addr = (if_addr_t *)addr->data;
238 switch(if_addr->ifat_type) {
239 case IF_AT_IPv4:
240 if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str,
241 ADDRSTRLEN)) {
242 g_string_append_printf(str,"'%s',", addr_str);
243 } else {
244 g_string_append(str,"'<unknown IPv4>',");
246 break;
247 case IF_AT_IPv6:
248 if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr,
249 addr_str, ADDRSTRLEN)) {
250 g_string_append_printf(str,"'%s',", addr_str);
251 } else {
252 g_string_append(str,"'<unknown IPv6>',");
254 break;
255 default:
256 g_string_append_printf(str,"'<type unknown %u>',", if_addr->ifat_type);
261 g_string_truncate(str,str->len - 1); /* the last comma or space (on empty list) */
262 g_string_append(str," ]"); /* addrs */
265 if (if_info->loopback)
266 g_string_append(str,", loopback=1");
267 else
268 g_string_append(str,", loopback=0");
272 caps = capture_get_if_capabilities(if_info->name, 0, if_cap_err, NULL);
274 if (caps != NULL) {
275 if (caps->data_link_types != NULL) {
276 GList* lt_entry = caps->data_link_types;
277 data_link_info_t *data_link_info;
279 g_string_append(str,", data_link_types=[");
281 for (; lt_entry != NULL; lt_entry = g_list_next(lt_entry) ) {
283 data_link_info = (data_link_info_t *)lt_entry->data;
284 g_string_append_printf(str,"{ name='%s', desc='%s' }, ", data_link_info->name, (data_link_info->description) ? data_link_info->description : "" );
287 g_string_truncate(str,str->len - 2); /* the comma and space */
288 g_string_append(str,"]");
291 g_string_append_printf(str,", can_set_rfmon=%s", caps->can_set_rfmon ? "1" : "0");
293 if (caps->can_set_rfmon) {
294 free_if_capabilities(caps);
295 caps = capture_get_if_capabilities(if_info->name, 1, if_cap_err, NULL);
297 if (caps->data_link_types != NULL) {
298 GList* lt_entry = caps->data_link_types;
299 data_link_info_t *data_link_info;
301 g_string_append(str,", data_link_types_rfmon=[");
303 for (; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
304 data_link_info = (data_link_info_t *)lt_entry->data;
305 g_string_append_printf(str,"{ name='%s', desc='%s' }, ", data_link_info->name, (data_link_info->description) ? data_link_info->description : "" );
308 g_string_truncate(str,str->len - 2); /* the comma and space */
309 g_string_append(str,"]");
313 free_if_capabilities(caps);
316 g_string_append(str,"},\n");
319 g_string_truncate(str,str->len - 2); /* the comma and return */
320 g_string_append(str,"}");
322 s=str->str;
323 g_string_free(str,FALSE);
324 return s;
327 static char* intf_list = NULL;
329 static void get_interfaces(char** err) {
330 int err_no = 0;
331 GList* if_list;
333 err = NULL;
334 if_list = capture_interface_list(&err_no, err, NULL);
336 if (err) {
337 DISP_DBG((1,"Could not get capture interface list: %s",err));
338 } else {
339 intf_list = intflist2json(if_list,err);
340 if (err) {
341 DISP_DBG((1,"get capabilities error: %s",err));
345 free_interface_list(if_list);
349 static char* param_get_interfaces(char** err _U_) {
350 return g_strdup(intf_list ? intf_list : "");
353 static long disp_loop_timeout_usec = DISPATCHER_WAIT_INITIAL;
355 static char* param_get_loop_timeout(char** err _U_) {
356 return g_strdup_printf("%fs", (((float)disp_loop_timeout_usec)/1000000.0) );
359 static echld_bool_t param_set_loop_timeout(char* val , char** err ) {
360 char* p;
361 int usec = (int)strtol(val, &p, 10); /* now usecs 2DO: "10ms" or "500us" or "1s" */
363 if (p<=val) {
364 *err = g_strdup("not an integer");
365 return FALSE;
368 disp_loop_timeout_usec = usec;
370 return TRUE;
373 static GString *comp_info_str;
374 static GString *runtime_info_str;
375 static const char* version_str = "Echld " VERSION;
376 static char* version_long_str = NULL;
379 static char* param_get_long_version(char** err _U_) {
380 return g_strdup(version_long_str);
383 static char* param_get_version(char** err _U_) {
384 return g_strdup(version_str);
387 static char* param_get_capture_types(char** err _U_) {
388 GString* str = g_string_new("");
389 char* s;
390 int i;
392 for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
393 if (wtap_dump_can_open(i)) {
394 g_string_append_printf(str,"%s: %s\n",
395 wtap_file_type_short_string(i), wtap_file_type_string(i));
399 s = str->str;
400 g_string_free(str,FALSE);
401 return s;
404 static echld_bool_t param_set_add_hosts_file(char* val, char** err) {
405 if (add_hosts_file(val)) {
406 return TRUE;
407 } else {
408 *err = g_strdup_printf("Can't read host entries from \"%s\"",val);
409 return FALSE;
413 static echld_bool_t param_set_x_opt(char* val, char** err) {
414 if (ex_opt_add(val)) {
415 return TRUE;
416 } else {
417 *err = g_strdup_printf("Cannot set X opt '%s'",val);
418 return FALSE;
425 static char* param_get_params(char** err _U_);
427 static param_t disp_params[] = {
428 #ifdef DEBUG_DISPATCHER
429 PARAM(dbg_level,"0>int>5"),
430 # endif
431 RO_PARAM(long_version,"long version string"),
432 RO_PARAM(version,"version string"),
433 PARAM(loop_timeout,"main loop step timeout"),
434 RO_PARAM(interfaces,"interface information"),
435 RO_PARAM(capture_types,"the available capture types"),
436 WO_PARAM(add_hosts_file,"Add a hosts file"),
437 WO_PARAM(x_opt,"Set a -X option"),
438 RO_PARAM(params,"This List"),
439 {NULL,NULL,NULL,NULL}
442 static char* param_get_params(char** err _U_) {
443 return paramset_get_params_list(disp_params,PARAM_LIST_FMT);
446 static struct dispatcher_child* dispatcher_get_child(struct dispatcher* d, int chld_id) {
447 int i;
448 struct dispatcher_child* cc = d->children;
449 int max_children = d->max_children;
451 for(i = 0; i < max_children; i++) {
452 struct dispatcher_child* c = &(cc[i]);
453 if (c->chld_id == chld_id) return c;
456 return NULL;
460 static void dispatcher_clear_child(struct dispatcher_child* c) {
461 echld_reset_reader(&(c->reader), -1, 4096);
462 c->chld_id = -1;
463 c->state = FREE;
464 c->reader.fd = -1;
465 c->write_fd = -1;
466 c->pid = -1;
467 c->reqh_id = -1;
468 c->closing = FALSE;
471 static void set_dumpcap_pid(int pid) {
473 dispatcher->dumpcap_pid = pid;
476 static void preinit_epan(char* argv0, int (*main)(int, char **)) {
477 // char *gpf_path, *pf_path;
478 char *gdp_path, *dp_path;
479 // int gpf_open_errno, gpf_read_errno;
480 // int pf_open_errno, pf_read_errno;
481 int gdp_open_errno, gdp_read_errno;
482 int dp_open_errno, dp_read_errno;
483 char* error;
485 error = init_progfile_dir(argv0, main);
487 comp_info_str = g_string_new("Compiled ");
488 get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info);
490 runtime_info_str = g_string_new("Running ");
491 get_runtime_version_info(runtime_info_str, NULL);
493 version_long_str = g_strdup_printf("%s%s\n%s\n%s\n%s",
494 version_str, wireshark_svnversion, get_copyright_info(),
495 comp_info_str->str, runtime_info_str->str);
497 if (error) {
498 DISP_FATAL((CANNOT_PREINIT_EPAN,"Failed epan_preinit: msg='%s'",error));
501 /* Add it to the information to be reported on a crash. */
502 ws_add_crash_info("Echld " VERSION "%s\n%s\n%s",
503 wireshark_svnversion, comp_info_str->str, runtime_info_str->str);
505 init_stuff();
507 capture_sync_set_fetch_dumpcap_pid_cb(set_dumpcap_pid);
509 init_process_policies();
511 get_interfaces(&error);
513 if (error) {
514 DISP_FATAL((CANNOT_PREINIT_EPAN,"Error getting interfaces: %s", error));
517 prefs_apply_all();
519 /* disabled protocols as per configuration file */
520 set_disabled_protos_list();
523 setlocale(LC_ALL, "");
524 DISP_DBG((1,"---5"));
526 read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, &dp_path, &dp_open_errno, &dp_read_errno);
528 DISP_DBG((1,"---6"));
530 cap_file_init(&stuff.cfile);
531 DISP_DBG((1,"---7"));
533 DISP_DBG((1,"---8"));
534 timestamp_set_precision(TS_PREC_AUTO_USEC);
536 // sleep(10);
538 // initialize_funnel_ops();
539 // stuff.prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path);
540 // check 4 errors
543 DISP_DBG((2,"epan preinit done"));
547 static void dispatcher_clear(void) {
548 DISP_DBG((2,"dispatcher_clear"));
549 /* remove unnecessary stuff for the working child */
550 /* remove signal handlers */
553 void dispatcher_sig(int sig) {
554 DISP_FATAL((TERMINATED,"SIG sig=%d",sig));
555 exit(1);
558 void dispatcher_reaper(int sig) {
559 int status;
560 int i;
561 struct dispatcher_child* cc = dispatcher->children;
562 int max_children = dispatcher->max_children;
563 int pid = waitpid(-1, &status, WNOHANG);
564 int reqh_id_save = dispatcher->reqh_id;
566 dispatcher->reqh_id = 0;
568 if (sig != SIGCHLD) {
569 DISP_DBG((1,"Reaper got wrong signal=%d",sig));
570 dispatcher->reqh_id = reqh_id_save;
571 return;
574 DISP_DBG((2,"Child dead pid=%d",pid));
576 for(i = 0; i < max_children; i++) {
577 struct dispatcher_child* c = &(cc[i]);
578 if ( c->pid == pid ) {
579 if (c->closing || dispatcher->closing) {
580 DISP_WRITE(dispatcher->parent_out, NULL, c->chld_id, ECHLD_CLOSING, c->reqh_id);
581 } else {
582 char* s = NULL;
583 GByteArray* em;
585 if (WIFEXITED(status)) {
586 s = g_strdup_printf(
587 "Unexpected dead: reason='exited' pid=%d status=%d",
588 pid, WEXITSTATUS(status));
589 } else if ( WIFSIGNALED(status) ) {
590 s = g_strdup_printf(
591 "Unexpected dead: reason='signaled' pid=%d termsig=%d coredump=%s",
592 pid, WTERMSIG(status), WCOREDUMP(status) ? "yes":"no");
594 /*if (WCOREDUMP(status)) { system("analyze_coredump.sh pid=%d") } */
596 } else if (WIFSTOPPED(status)) {
597 s = g_strdup_printf(
598 "Unexpected dead: reason='stopped' pid=%d stopsig=%d",
599 pid, WSTOPSIG(status));
602 em = dispatcher->enc.to_parent->child_dead(s);
603 dispatcher_err(ECHLD_ERR_CRASHED_CHILD, s);
604 if (s) g_free(s);
605 DISP_WRITE(dispatcher->parent_out, em, c->chld_id, ECHLD_CHILD_DEAD, 0);
606 if (em) g_byte_array_free(em,TRUE);
609 CHLD_SET_STATE(c,CLOSED);
610 dispatcher_clear_child(c);
611 dispatcher->reqh_id = reqh_id_save;
612 return;
616 if (pid == dispatcher->dumpcap_pid) {
617 dispatcher->dumpcap_pid = 0;
618 dispatcher->reqh_id = reqh_id_save;
619 DISP_DBG((2,"dumpcap dead pid=%d",pid));
620 return;
623 dispatcher_err(ECHLD_ERR_UNKNOWN_PID, "Unkown child pid: %d", pid);
624 dispatcher->reqh_id = reqh_id_save;
628 static void dispatcher_destroy(void) {
629 /* destroy the dispatcher stuff at closing */
631 dispatcher->closing = TRUE;
633 children_massacre();
635 exit(0);
638 /* stuff coming from child going to parent */
639 static long dispatch_to_parent(guint8* b, size_t len, echld_chld_id_t chld_id, echld_msg_type_t type, echld_reqh_id_t reqh_id, void* data) {
640 /* TODO: timeouts, clear them */
641 /* TODO: keep stats */
643 GByteArray in_ba;
645 struct dispatcher_child* c = (struct dispatcher_child*)data;
647 dispatcher->reqh_id = c->reqh_id = reqh_id;
649 in_ba.data = b;
650 in_ba.len = (guint)len;
652 if (chld_id != c->chld_id) {
653 goto misbehabing;
656 switch(type) {
657 case ECHLD_ERROR: break;
658 case ECHLD_TIMED_OUT: break;
659 case ECHLD_HELLO: CHLD_SET_STATE(c,IDLE); break;
660 case ECHLD_CLOSING:
661 c->closing = TRUE;
662 CHLD_SET_STATE(c,CLOSING);
663 break;
664 case ECHLD_PARAM: break;
665 case ECHLD_PONG: break;
666 case ECHLD_FILE_OPENED: CHLD_SET_STATE(c,READING); break;
667 case ECHLD_INTERFACE_OPENED: CHLD_SET_STATE(c,READY); break;
668 case ECHLD_CAPTURE_STARTED: CHLD_SET_STATE(c,CAPTURING); break;
669 case ECHLD_NOTIFY: break;
670 case ECHLD_PACKET_SUM: break;
671 case ECHLD_TREE: break;
672 case ECHLD_BUFFER: break;
674 case ECHLD_EOF:
675 case ECHLD_CAPTURE_STOPPED: CHLD_SET_STATE(c,DONE); break;
677 case ECHLD_NOTE_ADDED: break;
678 case ECHLD_PACKET_LIST: break;
679 case ECHLD_FILE_SAVED: break;
681 default:
682 goto misbehabing;
685 DISP_DBG((4,"Dispatching to parent reqh_id=%d chld_id=%d type='%c'",reqh_id,c->chld_id,type));
686 return DISP_WRITE(dispatcher->parent_out, &in_ba, chld_id, type, reqh_id);
688 misbehabing:
689 CHLD_SET_STATE(c,ERRORED);
690 c->closing = TRUE;
691 kill(c->pid,SIGTERM);
692 dispatcher_err(ECHLD_ERR_CRASHED_CHILD,"chld_id=%d",chld_id);
693 return 0;
697 static struct timeval start_wait_time;
698 static long start_wait_time_us = CHILD_START_WAIT_TIME;
700 static void detach_new_child(enc_msg_t* em, echld_chld_id_t chld_id) {
701 struct dispatcher_child* c;
702 int reqh_id = dispatcher->reqh_id;
703 int pid;
705 if (( c = dispatcher_get_child(dispatcher, chld_id) )) {
706 dispatcher_err(ECHLD_ERR_CHILD_EXISTS,"chld_id=%d exists already while creating new child",chld_id);
707 return;
708 } else if (( c = dispatcher_get_child(dispatcher, -1) )) {
709 int disp_pipe_fds[2];
710 int child_pipe_fds[2];
712 int pipe_to_disp;
713 int pipe_from_disp;
714 int pipe_to_child;
715 int pipe_from_child;
717 DISP_DBG((5,"new_child pipe(dispatcher)"));
718 if( pipe(disp_pipe_fds) < 0) {
719 dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN PARENT PIPE: %s",strerror(errno));
720 return;
723 pipe_from_disp = disp_pipe_fds[0];
724 pipe_to_child = disp_pipe_fds[1];
726 DISP_DBG((5,"new_child pipe(child)"));
727 if( pipe(child_pipe_fds) < 0) {
728 close(pipe_from_disp);
729 close(pipe_to_child);
730 dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN CHILD PIPE: %s",strerror(errno));
731 return;
734 pipe_from_child = child_pipe_fds[0];
735 pipe_to_disp = child_pipe_fds[1];
737 DISP_DBG((4,"New Child Forking()"));
738 switch (( pid = fork() )) {
739 case -1: {
740 close(pipe_to_child);
741 close(pipe_to_disp);
742 close(pipe_from_child);
743 close(pipe_from_disp);
744 dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT FORK: %s",strerror(errno));
745 return;
747 case 0: {
748 /* I'm the child */
749 dispatcher_clear();
751 close(pipe_to_child);
752 close(pipe_from_child);
754 echld_child_initialize(chld_id, pipe_from_disp,pipe_to_disp,reqh_id,&stuff);
756 exit( echld_child_loop() );
758 /* it won't */
759 return;
761 default: {
762 /* I'm the parent */
764 close(pipe_to_disp);
765 close(pipe_from_disp);
767 echld_reset_reader(&(c->reader), pipe_from_child,4096);
768 c->write_fd = pipe_to_child;
769 c->pid = pid;
770 c->chld_id = chld_id;
771 c->closing = FALSE;
773 CHLD_SET_STATE(c,CREATING);
775 DISP_DBG((4,"Child Forked pid=%d chld_id=%d from_fd=%d to_fd=%d",
776 pid, c->chld_id, pipe_from_child, pipe_to_child));
778 start_wait_time.tv_sec = (int)(start_wait_time_us / 1000000);
779 start_wait_time.tv_usec = (int)(start_wait_time_us % 1000000);
781 select(0,NULL,NULL,NULL,&start_wait_time);
783 /* configure child */
784 DISP_WRITE(pipe_to_child, em, c->chld_id, ECHLD_NEW_CHILD, dispatcher->reqh_id);
785 return;
788 } else {
789 dispatcher_err(ECHLD_ERR_CANNOT_FORK, "MAX CHILDREN REACHED: max_children=%d",dispatcher->max_children);
790 return;
795 /* process signals sent from parent */
796 static long dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, echld_msg_type_t type, echld_reqh_id_t reqh_id, void* data _U_) {
797 GByteArray in_ba;
799 in_ba.data = b;
800 in_ba.len = (guint)len;
802 dispatcher->reqh_id = reqh_id;
804 DISP_DBG((1,"RCV<- type='%s' chld_id=%d reqh_id=%d",TY(type),chld_id,reqh_id));
806 if (chld_id == 0) { /* these are messages sent to the dispatcher itself */
807 DISP_DBG((2,"Message to Dispatcher"));
808 switch(type) {
809 case ECHLD_CLOSE_CHILD:
810 dispatcher_destroy();
811 return 0;
812 case ECHLD_PING:
813 DISP_DBG((2,"PONG reqh_id=%d",reqh_id));
814 DISP_WRITE(dispatcher->parent_out, NULL, chld_id, ECHLD_PONG, reqh_id);
815 return 0;
816 case ECHLD_SET_PARAM:{
817 char* param;
818 char* value;
819 if ( dispatcher->dec.from_parent->set_param(b,len,&param,&value) ) {
820 GByteArray* ba;
821 char* err;
822 if (! paramset_apply_set (disp_params, param, value, &err) ) {
823 dispatcher_err(ECHLD_CANNOT_SET_PARAM,"%s",err);
824 g_free(err);
825 return 0;
828 ba = dispatcher->enc.to_parent->param(param,value);
829 DISP_RESP(ba,ECHLD_PARAM);
830 g_byte_array_free(ba,TRUE);
831 DISP_DBG((1,"Set Param: param='%s' value='%s'",param,value));
833 return 0;
834 } else {
835 dispatcher_err(ECHLD_CANNOT_SET_PARAM,"reason='decoder error'");
836 return 0;
839 case ECHLD_GET_PARAM: {
840 GByteArray* ba;
841 char* param;
842 if ( dispatcher->dec.from_parent->get_param(b,len,&param) ) {
843 char* err;
844 char* val;
846 if (! (val = paramset_apply_get (disp_params, param, &err)) ) {
847 dispatcher_err(ECHLD_CANNOT_GET_PARAM,"%s",err);
848 g_free(err);
849 return 0;
852 ba = dispatcher->enc.to_parent->param(param,val);
853 DISP_RESP(ba,ECHLD_PARAM);
854 g_byte_array_free(ba,TRUE);
855 DISP_DBG((1,"Get Param: param='%s' value='%s'",param,val));
856 return 0;
857 } else {
858 dispatcher_err(ECHLD_CANNOT_GET_PARAM,"reason='decoder error'");
859 return 0;
862 default:
863 dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message to dispatcher type='%c'", type);
864 return 0;
866 } else {
867 struct dispatcher_child* c;
869 DISP_DBG((2,"Parent => Child"));
871 if (! (c = dispatcher_get_child(dispatcher, chld_id)) ) {
872 if (type == ECHLD_NEW_CHILD) {
873 detach_new_child(&in_ba,chld_id);
874 return 0;
875 } else {
876 dispatcher_err(ECHLD_ERR_NO_SUCH_CHILD, "wrong chld_id %d", chld_id);
877 return 0;
879 } else {
880 switch(type) {
881 case ECHLD_CLOSE_CHILD:
882 CHLD_SET_STATE(c,CLOSED);
883 goto relay_frame;
885 case ECHLD_OPEN_FILE:
886 CHLD_SET_STATE(c,READING);
887 goto relay_frame;
889 case ECHLD_OPEN_INTERFACE:
890 CHLD_SET_STATE(c,READY);
891 goto relay_frame;
893 case ECHLD_START_CAPTURE:
894 CHLD_SET_STATE(c,CAPTURING);
895 goto relay_frame;
897 case ECHLD_STOP_CAPTURE:
898 CHLD_SET_STATE(c,DONE);
899 goto relay_frame;
901 case ECHLD_SAVE_FILE:
902 case ECHLD_APPLY_FILTER:
903 case ECHLD_SET_PARAM:
904 case ECHLD_GET_PARAM:
905 case ECHLD_PING:
906 case ECHLD_GET_SUM:
907 case ECHLD_GET_TREE:
908 case ECHLD_GET_BUFFER:
909 case ECHLD_ADD_NOTE:
910 relay_frame: {
911 DISP_DBG((3,"Relay to Child chld_id=%d type='%c' req_id=%d",chld_id, type, reqh_id));
912 return DISP_WRITE(c->write_fd, &in_ba, chld_id, type, reqh_id);
914 default:
915 dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message %d %c", reqh_id, type);
916 return 0;
924 int dispatcher_loop(void) {
925 int parent_out = dispatcher->parent_out;
926 int parent_in = dispatcher->parent_in.fd;
927 struct dispatcher_child* children = dispatcher->children;
929 DISP_DBG((5,"LOOP in_fd=%d out_fd=%d",parent_in, parent_out));
931 do {
932 fd_set rfds;
933 fd_set efds;
934 struct dispatcher_child* c;
935 int nfds;
936 int nchld = 0;
937 struct timeval disp_loop_timeout;
939 FD_ZERO(&rfds);
940 FD_ZERO(&efds);
942 FD_SET(parent_in,&rfds);
943 FD_SET(parent_in,&efds);
944 FD_SET(parent_out,&efds);
946 for (c = children; c->pid; c++) {
947 if (c->chld_id > 0) {
948 nchld++;
949 FD_SET(c->reader.fd, &rfds);
950 FD_SET(c->reader.fd, &efds);
954 DISP_DBG((4,"Select()ing nchld=%d",nchld,disp_loop_timeout.tv_usec));
956 disp_loop_timeout.tv_sec = (int)(disp_loop_timeout_usec / 1000000);
957 disp_loop_timeout.tv_usec = (int)(disp_loop_timeout_usec % 1000000);
959 nfds = select(FD_SETSIZE, &rfds, NULL, &efds, &disp_loop_timeout);
961 DISP_DBG((5,"Select()ed nfds=%d",nchld,nfds));
963 if (nfds < 0) {
964 DISP_DBG((1,"select error='%s'",strerror(errno) ));
965 continue;
968 if ( FD_ISSET(parent_in, &rfds)) {
969 long st = echld_read_frame(&(dispatcher->parent_in), dispatch_to_child, dispatcher);
971 if (st < 0) {
972 DISP_DBG((1,"read frame returning < 0 for parent"));
973 /* XXX: ??? */
974 continue;
978 if ( FD_ISSET(parent_in, &efds) ) {
979 DISP_DBG((1,"Parent In Pipe Errored!"));
980 continue;
983 if ( FD_ISSET(parent_out, &efds) ) {
984 DISP_DBG((1,"Parent Out Pipe Errored!"));
985 continue;
989 for (c=children; c->pid; c++) {
990 if (c->reader.fd > 0) {
991 if ( FD_ISSET(c->reader.fd,&efds) ) {
992 struct timeval wait_time;
993 wait_time.tv_sec = 0;
994 wait_time.tv_usec = DISP_KILLED_CHILD_WAIT;
996 DISP_DBG((1,"errored child pipe chld_id=%d",c->chld_id));
997 kill(c->pid,SIGTERM);
998 select(0,NULL,NULL,NULL,&wait_time);
999 dispatcher_clear_child(c);
1000 continue;
1003 if (FD_ISSET(c->reader.fd,&rfds)) {
1004 long st = echld_read_frame(&(c->reader), dispatch_to_parent, c);
1006 if (st < 0) {
1007 DISP_DBG((1,"read_frame returned < 0 for chld_id=%d",c->chld_id));
1008 /* XXX */
1009 continue;
1011 continue;
1015 } while(1);
1017 /* won't */
1018 return 1;
1021 void dispatcher_alrm(int sig _U_) {
1022 DISP_DBG((1,"ALRM received"));
1025 void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* argv0, int (*main)(int, char **)) {
1026 static struct dispatcher d;
1027 int i;
1028 #ifdef DEBUG_DISPATCHER
1029 int dbg_fd;
1030 #endif
1032 DISP_DBG_INIT();
1033 #ifdef DEBUG_DISPATCHER
1034 dbg_fd = fileno(debug_fp);
1035 #endif
1036 DISP_DBG((2,"Dispatcher Starting"));
1039 signal(SIGCHLD,dispatcher_reaper);
1041 signal(SIGTERM,dispatcher_sig);
1042 signal(SIGPIPE,dispatcher_sig);
1043 signal(SIGINT,SIG_IGN);
1044 signal(SIGCONT,SIG_IGN);
1045 signal(SIGABRT,dispatcher_sig);
1046 signal(SIGHUP,dispatcher_sig);
1047 signal(SIGALRM,dispatcher_alrm);
1049 dispatcher = &d;
1051 echld_init_reader(&(d.parent_in),in_pipe_fds[0],4096);
1052 d.parent_out = out_pipe_fds[1];
1053 d.children = g_new0(struct dispatcher_child,ECHLD_MAX_CHILDREN);
1054 d.max_children = ECHLD_MAX_CHILDREN;
1055 d.nchildren = 0;
1056 d.reqh_id = -1;
1057 d.pid = getpid();
1058 d.dumpcap_pid = 0;
1060 for (i=0;i<ECHLD_MAX_CHILDREN;i++) dispatcher_clear_child(&(d.children[i]));
1062 close(out_pipe_fds[0]);
1063 close(in_pipe_fds[1]);
1065 echld_get_all_codecs(&(d.enc.to_parent), &(d.dec.from_parent), &(d.enc.to_child), &(d.dec.from_child));
1067 DISP_DBG((2,"Dispatcher Configured pid=%d parent_in=%d parent_out=%d",d.pid,in_pipe_fds[0],d.parent_out));
1069 preinit_epan(argv0,main);
1071 DISP_WRITE(dispatcher->parent_out, NULL, 0, ECHLD_HELLO, 0);
1072 exit(dispatcher_loop());