Update E.212 list to Operational Bulletin No. 1038 (15.X.2013)
[metze/wireshark/wip.git] / echld / dispatcher.c
1 /* echld_dispatcher.c
2  *  epan working child API internals
3  *  Dispatcher process routines and definitions
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copyright (c) 2013 by Luis Ontanon <luis@ontanon.org>
12  *
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.
17  *
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.
22  *
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.
26  */
27
28 #include "echld-int.h"
29 /** 
30   DISPATCHER
31   **/
32
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;
41 };
42
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;
60
61         int dumpcap_pid;
62         gboolean closing;
63         capture_options capture_opts;
64 };
65
66 struct dispatcher* dispatcher;
67
68 #ifdef DEBUG_DISPATCHER
69 static int debug_lvl = DEBUG_DISPATCHER;
70 static FILE* debug_fp = NULL;
71
72 #define DCOM() /*echld_common_set_dbg(debug_lvl,debug_fp,"Disp")*/
73
74 int dispatcher_debug(int level, const char* fmt, ...) {
75         va_list ap;
76         char* str;
77
78         if (debug_lvl<level) return 1;
79
80     va_start(ap, fmt);
81         str = g_strdup_vprintf(fmt,ap);
82         va_end(ap);
83
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);
88         }
89
90         fflush(debug_fp);
91
92         g_free(str);
93
94         return 1;
95 }
96
97
98 static char* param_get_dbg_level(char** err _U_) {
99         return g_strdup_printf("%d",debug_lvl);
100 }
101
102 static echld_bool_t param_set_dbg_level(char* val , char** err ) {
103         char* p;
104         int lvl = (int)strtol(val, &p, 10);
105
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;
112         }
113
114         debug_lvl = lvl;
115         DCOM();
116         return TRUE;
117 }
118
119 static long dbg_r = 0;
120
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
133
134 #define DISP_RESP(B,T) (DISP_WRITE( dispatcher->parent_out, (B), 0, (T), dispatcher->reqh_id))
135
136
137
138 static echld_epan_stuff_t stuff;
139
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
145
146 }
147
148 static void children_massacre(void) {
149         int i;
150         struct dispatcher_child* cc = dispatcher->children;
151         int max_children = dispatcher->max_children;
152
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);
158                 }
159         }
160 }
161
162
163 static void dispatcher_fatal(int cause, const char* fmt, ...) {
164         size_t len= 1024;
165         gchar err_str[len];
166         va_list ap;
167
168         va_start(ap, fmt);
169         g_vsnprintf(err_str,len,fmt,ap);
170         va_end(ap);
171
172         DISP_DBG((0,"fatal cause=%d msg=\"%s\"",cause ,err_str));
173
174         children_massacre();
175
176         exit(cause);
177 }
178
179 #define DISP_FATAL(attrs) dispatcher_fatal attrs
180
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;
186
187         va_start(ap, fmt);
188         g_vsnprintf(err_str,len,fmt,ap);
189         va_end(ap);
190
191         DISP_DBG((0,"error=\"%s\"",err_str));
192
193         ba = dispatcher->enc.to_parent->error(errnum, err_str);
194         DISP_RESP(ba,ECHLD_ERROR);
195         g_byte_array_free(ba,TRUE);
196 }
197
198 /* parameters */
199
200 /* interface listing */
201
202 static char* intflist2json(GList* if_list, char** if_cap_err) {
203 #define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
204
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;
214
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);
220
221         /*
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.
225          */
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);
229
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);
233
234         for (addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
235                     addr = g_slist_next(addr)) {
236
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>',");
245                 }
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>',");
253                 }
254                 break;
255             default:
256                 g_string_append_printf(str,"'<type unknown %u>',", if_addr->ifat_type);
257             }
258         
259         }
260
261             g_string_truncate(str,str->len - 1); /* the last comma or space (on empty list) */
262         g_string_append(str," ]"); /* addrs */
263
264
265         if (if_info->loopback)
266             g_string_append(str,", loopback=1");
267         else
268             g_string_append(str,", loopback=0");
269
270
271
272                 caps = capture_get_if_capabilities(if_info->name, 0, if_cap_err, NULL);
273
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;
278
279                                 g_string_append(str,", data_link_types=[");
280
281                                 for (; lt_entry != NULL; lt_entry = g_list_next(lt_entry) ) {
282
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 : "" );
285                                 }                                   
286
287                                 g_string_truncate(str,str->len - 2); /* the comma and space */
288                                 g_string_append(str,"]");
289                         }       
290
291                         g_string_append_printf(str,", can_set_rfmon=%s", caps->can_set_rfmon ? "1" : "0");
292
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);
296
297                                 if (caps->data_link_types != NULL) {
298                                         GList* lt_entry = caps->data_link_types;
299                                         data_link_info_t *data_link_info;
300
301                                         g_string_append(str,", data_link_types_rfmon=[");
302
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 : "" );
306                                         }
307
308                                     g_string_truncate(str,str->len - 2); /* the comma and space */
309                                         g_string_append(str,"]");
310                                 }
311                         }
312
313                         free_if_capabilities(caps);
314                 }
315                   
316         g_string_append(str,"},\n");
317     }
318
319     g_string_truncate(str,str->len - 2); /* the comma and return */
320     g_string_append(str,"}");
321
322     s=str->str;
323     g_string_free(str,FALSE);
324     return s;
325 }
326
327 static char* intf_list = NULL;
328
329 static void get_interfaces(char** err) {
330         int err_no = 0;
331         GList* if_list;
332         
333         err = NULL;     
334         if_list = capture_interface_list(&err_no, err, NULL);
335
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));
342                 }
343         }
344
345         free_interface_list(if_list);
346 }
347
348
349 static char* param_get_interfaces(char** err _U_) {
350         return g_strdup(intf_list ? intf_list : "");
351 }
352
353 static long disp_loop_timeout_usec = DISPATCHER_WAIT_INITIAL;
354
355 static char* param_get_loop_timeout(char** err _U_) {
356         return g_strdup_printf("%fs", (((float)disp_loop_timeout_usec)/1000000.0) );
357 }
358
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" */
362
363         if (p<=val) {
364                 *err = g_strdup("not an integer");
365                 return FALSE;
366         }
367
368         disp_loop_timeout_usec = usec;
369
370         return TRUE;
371 }
372
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;
377
378
379 static char* param_get_long_version(char** err _U_) {
380         return g_strdup(version_long_str);
381 }
382
383 static char* param_get_version(char** err _U_) {
384         return g_strdup(version_str);
385 }
386
387 static char* param_get_capture_types(char** err _U_) {
388   GString* str = g_string_new("");
389   char* s;
390   int i;
391
392   for (i = 0; i < WTAP_NUM_FILE_TYPES; 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));
396     }
397   }
398
399   s = str->str;
400   g_string_free(str,FALSE);
401   return s;
402 }
403
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;
410         }
411 }
412
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;
419         }
420 }
421
422
423
424
425 static char* param_get_params(char** err _U_);
426
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}
440 };
441
442 static char* param_get_params(char** err _U_) {
443         return paramset_get_params_list(disp_params,PARAM_LIST_FMT);
444 }
445
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;
450
451         for(i = 0; i < max_children; i++) {
452                 struct dispatcher_child* c = &(cc[i]);
453                 if (c->chld_id == chld_id) return c;
454         }
455
456         return NULL;
457 }
458
459
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;
469 }
470
471 static void set_dumpcap_pid(int pid) {
472
473         dispatcher->dumpcap_pid = pid;
474 }
475
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;
484
485         error = init_progfile_dir(argv0, main);
486
487         comp_info_str = g_string_new("Compiled ");      
488         get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info);
489
490         runtime_info_str = g_string_new("Running ");
491         get_runtime_version_info(runtime_info_str, NULL);
492
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);
496
497         if (error) {
498                 DISP_FATAL((CANNOT_PREINIT_EPAN,"Failed epan_preinit: msg='%s'",error));
499         }
500
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);
504
505         init_stuff();
506                 
507         capture_sync_set_fetch_dumpcap_pid_cb(set_dumpcap_pid);
508
509         init_process_policies();
510
511         get_interfaces(&error);
512         
513         if (error) {
514                 DISP_FATAL((CANNOT_PREINIT_EPAN,"Error getting interfaces: %s", error));
515         }
516
517         prefs_apply_all();
518
519         /* disabled protocols as per configuration file */
520         set_disabled_protos_list();
521
522
523         setlocale(LC_ALL, "");
524         DISP_DBG((1,"---5"));
525
526         read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, &dp_path, &dp_open_errno, &dp_read_errno);
527
528         DISP_DBG((1,"---6"));
529
530         cap_file_init(&stuff.cfile);
531         DISP_DBG((1,"---7"));
532
533         DISP_DBG((1,"---8"));
534     timestamp_set_precision(TS_PREC_AUTO_USEC);
535
536         // sleep(10);
537
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
541
542
543         DISP_DBG((2,"epan preinit done"));
544 }
545
546
547 static void dispatcher_clear(void) {
548         DISP_DBG((2,"dispatcher_clear"));
549         /* remove unnecessary stuff for the working child */
550         /* remove signal handlers */
551 }
552
553 void dispatcher_sig(int sig) {
554         DISP_FATAL((TERMINATED,"SIG sig=%d",sig));
555         exit(1);
556 }
557
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;
565
566         dispatcher->reqh_id = 0;
567
568         if (sig != SIGCHLD) {
569                 DISP_DBG((1,"Reaper got wrong signal=%d",sig));
570                 dispatcher->reqh_id = reqh_id_save;
571                 return;
572         }
573
574         DISP_DBG((2,"Child dead pid=%d",pid));
575
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;
584
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");
593
594                                         /*if (WCOREDUMP(status)) { system("analyze_coredump.sh pid=%d") } */
595
596                                 } else if (WIFSTOPPED(status)) {
597                                     s = g_strdup_printf(
598                                         "Unexpected dead: reason='stopped' pid=%d stopsig=%d",
599                                         pid, WSTOPSIG(status));
600                                 }
601
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);
607                         }
608
609                         CHLD_SET_STATE(c,CLOSED);
610                         dispatcher_clear_child(c);
611                         dispatcher->reqh_id = reqh_id_save;
612                         return;
613                 }
614         }
615
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;
621         }
622
623         dispatcher_err(ECHLD_ERR_UNKNOWN_PID, "Unkown child pid: %d", pid);
624         dispatcher->reqh_id = reqh_id_save;
625 }
626
627
628 static void dispatcher_destroy(void) {
629         /* destroy the dispatcher stuff at closing */
630
631         dispatcher->closing = TRUE;
632
633         children_massacre();
634
635         exit(0);
636 }
637
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 */
642
643         GByteArray in_ba;
644
645         struct dispatcher_child* c = (struct dispatcher_child*)data;
646
647         dispatcher->reqh_id = c->reqh_id = reqh_id;
648         
649         in_ba.data = b;
650         in_ba.len = (guint)len;
651
652         if (chld_id != c->chld_id) {
653                 goto misbehabing;
654         }
655
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;
673
674                 case ECHLD_EOF:
675                 case ECHLD_CAPTURE_STOPPED: CHLD_SET_STATE(c,DONE); break;
676
677                 case ECHLD_NOTE_ADDED: break; 
678                 case ECHLD_PACKET_LIST: break;
679                 case ECHLD_FILE_SAVED: break;
680
681                 default:
682                         goto misbehabing;
683         }
684         
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);
687
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;
694
695 }
696
697 static struct timeval start_wait_time; 
698 static long start_wait_time_us = CHILD_START_WAIT_TIME;
699
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; 
704
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];
711
712                 int pipe_to_disp;
713                 int pipe_from_disp;
714                 int pipe_to_child;
715                 int pipe_from_child;
716
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;
721                 }
722
723                 pipe_from_disp = disp_pipe_fds[0];
724                 pipe_to_child = disp_pipe_fds[1];
725
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;
732                 }
733
734                 pipe_from_child = child_pipe_fds[0];
735                 pipe_to_disp = child_pipe_fds[1];
736
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;
746                         }
747                         case 0: {
748                         /* I'm the child */
749                                 dispatcher_clear();
750
751                                 close(pipe_to_child);
752                                 close(pipe_from_child);
753
754                                 echld_child_initialize(chld_id, pipe_from_disp,pipe_to_disp,reqh_id,&stuff);
755
756                                 exit( echld_child_loop() );
757
758                                 /* it won't */
759                                 return; 
760                         }
761                         default: {
762                         /* I'm the parent */
763
764                                 close(pipe_to_disp);
765                                 close(pipe_from_disp);
766
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;
772
773                                 CHLD_SET_STATE(c,CREATING);
774
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));
777
778                                 start_wait_time.tv_sec = (int)(start_wait_time_us / 1000000);
779                                 start_wait_time.tv_usec = (int)(start_wait_time_us % 1000000);
780
781                                 select(0,NULL,NULL,NULL,&start_wait_time);
782
783                                 /* configure child */
784                                 DISP_WRITE(pipe_to_child, em, c->chld_id, ECHLD_NEW_CHILD, dispatcher->reqh_id);
785                                 return;
786                         }
787                 }
788         } else {
789                 dispatcher_err(ECHLD_ERR_CANNOT_FORK, "MAX CHILDREN REACHED: max_children=%d",dispatcher->max_children);
790                 return;
791         }
792 }
793
794
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;
798
799         in_ba.data = b;
800         in_ba.len = (guint)len;
801
802         dispatcher->reqh_id = reqh_id;
803
804         DISP_DBG((1,"RCV<- type='%s' chld_id=%d reqh_id=%d",TY(type),chld_id,reqh_id));
805
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;
826                                         }
827
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));
832
833                                         return 0;
834                                 } else {
835                                         dispatcher_err(ECHLD_CANNOT_SET_PARAM,"reason='decoder error'");
836                                         return 0;
837                                 }
838                         }
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;
845
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;
850                                         }
851                                         
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;
860                                 }
861                         }
862                         default:
863                                 dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message to dispatcher type='%c'", type);
864                                 return 0;
865                 }
866         } else {
867                 struct dispatcher_child* c;
868
869                 DISP_DBG((2,"Parent => Child"));
870
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;
878                         }
879                 } else {
880                         switch(type) {
881                                 case ECHLD_CLOSE_CHILD: 
882                                         CHLD_SET_STATE(c,CLOSED);
883                                         goto relay_frame;
884
885                                 case ECHLD_OPEN_FILE:
886                                         CHLD_SET_STATE(c,READING);
887                                         goto relay_frame;
888
889                                 case ECHLD_OPEN_INTERFACE:
890                                         CHLD_SET_STATE(c,READY);
891                                         goto relay_frame;
892
893                                 case ECHLD_START_CAPTURE:
894                                         CHLD_SET_STATE(c,CAPTURING);
895                                         goto relay_frame;
896
897                                 case ECHLD_STOP_CAPTURE:
898                                         CHLD_SET_STATE(c,DONE);
899                                         goto relay_frame;
900
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);
913                                 }
914                                 default:
915                                         dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message %d %c", reqh_id, type);
916                                         return 0;
917                         }
918                 }
919         }
920 }
921
922
923
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;
928
929         DISP_DBG((5,"LOOP in_fd=%d out_fd=%d",parent_in, parent_out));
930
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;
938
939                 FD_ZERO(&rfds);
940                 FD_ZERO(&efds);
941
942                 FD_SET(parent_in,&rfds);
943                 FD_SET(parent_in,&efds);
944                 FD_SET(parent_out,&efds);
945
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);
951                         }
952                 }
953
954                 DISP_DBG((4,"Select()ing nchld=%d",nchld,disp_loop_timeout.tv_usec));
955
956                 disp_loop_timeout.tv_sec = (int)(disp_loop_timeout_usec / 1000000);
957                 disp_loop_timeout.tv_usec = (int)(disp_loop_timeout_usec % 1000000);
958
959                 nfds = select(FD_SETSIZE, &rfds, NULL, &efds, &disp_loop_timeout);
960
961                 DISP_DBG((5,"Select()ed nfds=%d",nchld,nfds));
962
963                 if (nfds < 0) {
964                         DISP_DBG((1,"select error='%s'",strerror(errno) ));
965                         continue;
966                 }
967
968                 if ( FD_ISSET(parent_in, &rfds)) {
969                         long st = echld_read_frame(&(dispatcher->parent_in), dispatch_to_child, dispatcher);
970
971                         if (st < 0) {
972                                 DISP_DBG((1,"read frame returning < 0 for parent"));
973                                 /* XXX: ??? */
974                                 continue;
975                         }
976                 }
977
978                 if ( FD_ISSET(parent_in, &efds) ) {
979                         DISP_DBG((1,"Parent In Pipe Errored!"));
980                         continue;
981                 }
982
983                 if ( FD_ISSET(parent_out, &efds) ) {
984                         DISP_DBG((1,"Parent Out Pipe Errored!"));
985                         continue;
986                 }
987
988
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;
995
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;       
1001                                 }
1002
1003                                 if (FD_ISSET(c->reader.fd,&rfds)) {
1004                                         long st = echld_read_frame(&(c->reader), dispatch_to_parent, c);
1005
1006                                         if (st < 0) {
1007                                                 DISP_DBG((1,"read_frame returned < 0 for chld_id=%d",c->chld_id));
1008                                                 /* XXX */
1009                                                 continue;
1010                                         }
1011                                         continue;
1012                                 }
1013                         }
1014                 }
1015         } while(1);
1016
1017         /* won't */
1018         return 1;
1019 }
1020
1021 void dispatcher_alrm(int sig _U_) {
1022         DISP_DBG((1,"ALRM received"));
1023 }
1024
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
1031
1032         DISP_DBG_INIT();
1033 #ifdef DEBUG_DISPATCHER
1034         dbg_fd = fileno(debug_fp);
1035 #endif
1036         DISP_DBG((2,"Dispatcher Starting"));
1037
1038
1039         signal(SIGCHLD,dispatcher_reaper);
1040
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);
1048
1049         dispatcher = &d;
1050
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;
1059
1060         for (i=0;i<ECHLD_MAX_CHILDREN;i++) dispatcher_clear_child(&(d.children[i]));
1061
1062         close(out_pipe_fds[0]);
1063         close(in_pipe_fds[1]);
1064
1065         echld_get_all_codecs(&(d.enc.to_parent), &(d.dec.from_parent), &(d.enc.to_child), &(d.dec.from_child));
1066
1067         DISP_DBG((2,"Dispatcher Configured pid=%d parent_in=%d parent_out=%d",d.pid,in_pipe_fds[0],d.parent_out));
1068
1069         preinit_epan(argv0,main);
1070
1071         DISP_WRITE(dispatcher->parent_out, NULL, 0, ECHLD_HELLO, 0);
1072         exit(dispatcher_loop());
1073 }
1074
1075