Witness: PIDL_dissect_ipv6address()
[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     GList       *if_entry;
206     if_info_t   *if_info;
207     GSList      *addr;
208     if_addr_t   *if_addr;
209     if_capabilities_t *caps;
210     char        addr_str[ADDRSTRLEN];
211     GString     *str = g_string_new("{ what='interfaces', interfaces={ \n");
212     char* s;
213
214     for (if_entry = g_list_first(if_list); if_entry != NULL;
215          if_entry = g_list_next(if_entry)) {
216         if_info = (if_info_t *)if_entry->data;
217         g_string_append_printf(str,"  %s={ intf='%s',", if_info->name, if_info->name);
218
219         /*
220          * Print the contents of the if_entry struct in a parseable format.
221          * Each if_entry element is tab-separated.  Addresses are comma-
222          * separated.
223          */
224         /* XXX - Make sure our description doesn't contain a tab */
225         if (if_info->vendor_description != NULL)
226             g_string_append_printf(str," vnd_desc='%s',", if_info->vendor_description);
227
228         /* XXX - Make sure our friendly name doesn't contain a tab */
229         if (if_info->friendly_name != NULL)
230             g_string_append_printf(str," name='%s', addrs=[ ", if_info->friendly_name);
231
232         for (addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
233                     addr = g_slist_next(addr)) {
234
235             if_addr = (if_addr_t *)addr->data;
236             switch(if_addr->ifat_type) {
237             case IF_AT_IPv4:
238                 if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str,
239                               ADDRSTRLEN)) {
240                     g_string_append_printf(str,"'%s',", addr_str);
241                 } else {
242                     g_string_append(str,"'<unknown IPv4>',");
243                 }
244                 break;
245             case IF_AT_IPv6:
246                 if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr,
247                               addr_str, ADDRSTRLEN)) {
248                     g_string_append_printf(str,"'%s',", addr_str);
249                 } else {
250                     g_string_append(str,"'<unknown IPv6>',");
251                 }
252                 break;
253             default:
254                 g_string_append_printf(str,"'<type unknown %u>',", if_addr->ifat_type);
255             }
256
257         }
258
259             g_string_truncate(str,str->len - 1); /* the last comma or space (on empty list) */
260         g_string_append(str," ]"); /* addrs */
261
262
263         if (if_info->loopback)
264             g_string_append(str,", loopback=1");
265         else
266             g_string_append(str,", loopback=0");
267
268
269
270                 caps = capture_get_if_capabilities(if_info->name, 0, if_cap_err, NULL);
271
272                 if (caps != NULL) {
273                         if (caps->data_link_types != NULL) {
274                                 GList* lt_entry = caps->data_link_types;
275                             data_link_info_t *data_link_info;
276
277                                 g_string_append(str,", data_link_types=[");
278
279                                 for (; lt_entry != NULL; lt_entry = g_list_next(lt_entry) ) {
280
281                                     data_link_info = (data_link_info_t *)lt_entry->data;
282                                     g_string_append_printf(str,"{ name='%s', desc='%s' }, ", data_link_info->name, (data_link_info->description) ? data_link_info->description : "" );
283                                 }
284
285                                 g_string_truncate(str,str->len - 2); /* the comma and space */
286                                 g_string_append(str,"]");
287                         }
288
289                         g_string_append_printf(str,", can_set_rfmon=%s", caps->can_set_rfmon ? "1" : "0");
290
291                         if (caps->can_set_rfmon) {
292                                 free_if_capabilities(caps);
293                                 caps = capture_get_if_capabilities(if_info->name, 1, if_cap_err, NULL);
294
295                                 if (caps->data_link_types != NULL) {
296                                         GList* lt_entry = caps->data_link_types;
297                                         data_link_info_t *data_link_info;
298
299                                         g_string_append(str,", data_link_types_rfmon=[");
300
301                                         for (; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
302                                             data_link_info = (data_link_info_t *)lt_entry->data;
303                                             g_string_append_printf(str,"{ name='%s', desc='%s' }, ", data_link_info->name, (data_link_info->description) ? data_link_info->description : "" );
304                                         }
305
306                                     g_string_truncate(str,str->len - 2); /* the comma and space */
307                                         g_string_append(str,"]");
308                                 }
309                         }
310
311                         free_if_capabilities(caps);
312                 }
313
314         g_string_append(str,"},\n");
315     }
316
317     g_string_truncate(str,str->len - 2); /* the comma and return */
318     g_string_append(str,"}");
319
320     s=str->str;
321     g_string_free(str,FALSE);
322     return s;
323 }
324
325 static char* intf_list = NULL;
326
327 static void get_interfaces(char** err) {
328         int err_no = 0;
329         GList* if_list;
330
331         err = NULL;
332         if_list = capture_interface_list(&err_no, err, NULL);
333
334         if (err) {
335                 DISP_DBG((1,"Could not get capture interface list: %s",err));
336         } else {
337                 intf_list = intflist2json(if_list,err);
338                 if (err) {
339                         DISP_DBG((1,"get capabilities error: %s",err));
340                 }
341         }
342
343         free_interface_list(if_list);
344 }
345
346
347 static char* param_get_interfaces(char** err _U_) {
348         return g_strdup(intf_list ? intf_list : "");
349 }
350
351 static long disp_loop_timeout_usec = DISPATCHER_WAIT_INITIAL;
352
353 static char* param_get_loop_timeout(char** err _U_) {
354         return g_strdup_printf("%fs", (((float)disp_loop_timeout_usec)/1000000.0) );
355 }
356
357 static echld_bool_t param_set_loop_timeout(char* val , char** err ) {
358         char* p;
359         int usec = (int)strtol(val, &p, 10); /* now usecs  2DO: "10ms" or "500us" or "1s" */
360
361         if (p<=val) {
362                 *err = g_strdup("not an integer");
363                 return FALSE;
364         }
365
366         disp_loop_timeout_usec = usec;
367
368         return TRUE;
369 }
370
371 static GString *comp_info_str;
372 static GString *runtime_info_str;
373 static const char* version_str = "Echld " VERSION;
374 static char* version_long_str = NULL;
375
376
377 static char* param_get_long_version(char** err _U_) {
378         return g_strdup(version_long_str);
379 }
380
381 static char* param_get_version(char** err _U_) {
382         return g_strdup(version_str);
383 }
384
385 static char* param_get_capture_types(char** err _U_) {
386   GString* str = g_string_new("");
387   char* s;
388   int i;
389
390   for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
391     if (wtap_dump_can_open(i)) {
392       g_string_append_printf(str,"%s: %s\n",
393         wtap_file_type_subtype_short_string(i), wtap_file_type_subtype_string(i));
394     }
395   }
396
397   s = str->str;
398   g_string_free(str,FALSE);
399   return s;
400 }
401
402 static echld_bool_t param_set_add_hosts_file(char* val, char** err) {
403         if (add_hosts_file(val)) {
404                 return TRUE;
405         } else {
406                 *err = g_strdup_printf("Can't read host entries from \"%s\"",val);
407                 return FALSE;
408         }
409 }
410
411 static echld_bool_t param_set_x_opt(char* val, char** err) {
412         if (ex_opt_add(val)) {
413                 return TRUE;
414         } else {
415                 *err = g_strdup_printf("Cannot set X opt '%s'",val);
416                 return FALSE;
417         }
418 }
419
420
421
422
423 static char* param_get_params(char** err _U_);
424
425 static param_t disp_params[] = {
426 #ifdef DEBUG_DISPATCHER
427         PARAM(dbg_level,"0>int>5"),
428 # endif
429         RO_PARAM(long_version,"long version string"),
430         RO_PARAM(version,"version string"),
431         PARAM(loop_timeout,"main loop step timeout"),
432         RO_PARAM(interfaces,"interface information"),
433         RO_PARAM(capture_types,"the available capture types"),
434         WO_PARAM(add_hosts_file,"Add a hosts file"),
435         WO_PARAM(x_opt,"Set a -X option"),
436         RO_PARAM(params,"This List"),
437         {NULL,NULL,NULL,NULL}
438 };
439
440 static char* param_get_params(char** err _U_) {
441         return paramset_get_params_list(disp_params,PARAM_LIST_FMT);
442 }
443
444 static struct dispatcher_child* dispatcher_get_child(struct dispatcher* d, int chld_id) {
445         int i;
446         struct dispatcher_child* cc = d->children;
447         int max_children = d->max_children;
448
449         for(i = 0; i < max_children; i++) {
450                 struct dispatcher_child* c = &(cc[i]);
451                 if (c->chld_id == chld_id) return c;
452         }
453
454         return NULL;
455 }
456
457
458 static void dispatcher_clear_child(struct dispatcher_child* c) {
459         echld_reset_reader(&(c->reader), -1, 4096);
460         c->chld_id = -1;
461         c->state = FREE;
462         c->reader.fd = -1;
463         c->write_fd = -1;
464         c->pid = -1;
465         c->reqh_id = -1;
466         c->closing = FALSE;
467 }
468
469 static void set_dumpcap_pid(int pid) {
470
471         dispatcher->dumpcap_pid = pid;
472 }
473
474 static void preinit_epan(char* argv0, int (*main)(int, char **)) {
475         // char *gpf_path, *pf_path;
476         char *gdp_path, *dp_path;
477         // int gpf_open_errno, gpf_read_errno;
478         // int pf_open_errno, pf_read_errno;
479         int gdp_open_errno, gdp_read_errno;
480         int dp_open_errno, dp_read_errno;
481         char* error;
482
483         error = init_progfile_dir(argv0, main);
484
485         comp_info_str = g_string_new("Compiled ");
486         get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info);
487
488         runtime_info_str = g_string_new("Running ");
489         get_runtime_version_info(runtime_info_str, NULL);
490
491         version_long_str = g_strdup_printf("%s%s\n%s\n%s\n%s",
492                 version_str, wireshark_svnversion, get_copyright_info(),
493                 comp_info_str->str, runtime_info_str->str);
494
495         if (error) {
496                 DISP_FATAL((CANNOT_PREINIT_EPAN,"Failed epan_preinit: msg='%s'",error));
497         }
498
499          /* Add it to the information to be reported on a crash. */
500         ws_add_crash_info("Echld " VERSION "%s\n%s\n%s",
501                 wireshark_svnversion, comp_info_str->str, runtime_info_str->str);
502
503         init_stuff();
504
505         capture_sync_set_fetch_dumpcap_pid_cb(set_dumpcap_pid);
506
507         init_process_policies();
508
509         get_interfaces(&error);
510
511         if (error) {
512                 DISP_FATAL((CANNOT_PREINIT_EPAN,"Error getting interfaces: %s", error));
513         }
514
515         prefs_apply_all();
516
517         /* disabled protocols as per configuration file */
518         set_disabled_protos_list();
519
520
521         setlocale(LC_ALL, "");
522         DISP_DBG((1,"---5"));
523
524         read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, &dp_path, &dp_open_errno, &dp_read_errno);
525
526         DISP_DBG((1,"---6"));
527
528         cap_file_init(&stuff.cfile);
529         DISP_DBG((1,"---7"));
530
531         DISP_DBG((1,"---8"));
532     timestamp_set_precision(TS_PREC_AUTO_USEC);
533
534         // sleep(10);
535
536         // initialize_funnel_ops();
537         // stuff.prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path);
538         // check 4 errors
539
540
541         DISP_DBG((2,"epan preinit done"));
542 }
543
544
545 static void dispatcher_clear(void) {
546         DISP_DBG((2,"dispatcher_clear"));
547         /* remove unnecessary stuff for the working child */
548         /* remove signal handlers */
549 }
550
551 void dispatcher_sig(int sig) {
552         DISP_FATAL((TERMINATED,"SIG sig=%d",sig));
553         exit(1);
554 }
555
556 void dispatcher_reaper(int sig) {
557     int    status;
558         int i;
559         struct dispatcher_child* cc = dispatcher->children;
560         int max_children = dispatcher->max_children;
561         int pid =  waitpid(-1, &status, WNOHANG);
562         int reqh_id_save =      dispatcher->reqh_id;
563
564         dispatcher->reqh_id = 0;
565
566         if (sig != SIGCHLD) {
567                 DISP_DBG((1,"Reaper got wrong signal=%d",sig));
568                 dispatcher->reqh_id = reqh_id_save;
569                 return;
570         }
571
572         DISP_DBG((2,"Child dead pid=%d",pid));
573
574         for(i = 0; i < max_children; i++) {
575                 struct dispatcher_child* c = &(cc[i]);
576                 if ( c->pid == pid ) {
577                         if (c->closing || dispatcher->closing) {
578                                 DISP_WRITE(dispatcher->parent_out, NULL, c->chld_id, ECHLD_CLOSING, c->reqh_id);
579                         } else {
580                                 char* s = NULL;
581                                 GByteArray* em;
582
583                                 if (WIFEXITED(status)) {
584                                     s = g_strdup_printf(
585                                                 "Unexpected dead: reason='exited' pid=%d status=%d",
586                                                 pid, WEXITSTATUS(status));
587                                 } else if ( WIFSIGNALED(status) ) {
588                                     s = g_strdup_printf(
589                                         "Unexpected dead: reason='signaled' pid=%d termsig=%d coredump=%s",
590                                         pid, WTERMSIG(status), WCOREDUMP(status) ? "yes":"no");
591
592                                         /*if (WCOREDUMP(status)) { system("analyze_coredump.sh pid=%d") } */
593
594                                 } else if (WIFSTOPPED(status)) {
595                                     s = g_strdup_printf(
596                                         "Unexpected dead: reason='stopped' pid=%d stopsig=%d",
597                                         pid, WSTOPSIG(status));
598                                 }
599
600                                 em = dispatcher->enc.to_parent->child_dead(s);
601                                 dispatcher_err(ECHLD_ERR_CRASHED_CHILD, s);
602                                 if (s) g_free(s);
603                                 DISP_WRITE(dispatcher->parent_out, em, c->chld_id, ECHLD_CHILD_DEAD, 0);
604                                 if (em) g_byte_array_free(em,TRUE);
605                         }
606
607                         CHLD_SET_STATE(c,CLOSED);
608                         dispatcher_clear_child(c);
609                         dispatcher->reqh_id = reqh_id_save;
610                         return;
611                 }
612         }
613
614         if (pid == dispatcher->dumpcap_pid) {
615                 dispatcher->dumpcap_pid = 0;
616                 dispatcher->reqh_id = reqh_id_save;
617                 DISP_DBG((2,"dumpcap dead pid=%d",pid));
618                 return;
619         }
620
621         dispatcher_err(ECHLD_ERR_UNKNOWN_PID, "Unknown child pid: %d", pid);
622         dispatcher->reqh_id = reqh_id_save;
623 }
624
625
626 static void dispatcher_destroy(void) {
627         /* destroy the dispatcher stuff at closing */
628
629         dispatcher->closing = TRUE;
630
631         children_massacre();
632
633         exit(0);
634 }
635
636 /* stuff coming from child going to parent */
637 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) {
638         /* TODO: timeouts, clear them */
639         /* TODO: keep stats */
640
641         GByteArray in_ba;
642
643         struct dispatcher_child* c = (struct dispatcher_child*)data;
644
645         dispatcher->reqh_id = c->reqh_id = reqh_id;
646
647         in_ba.data = b;
648         in_ba.len = (guint)len;
649
650         if (chld_id != c->chld_id) {
651                 goto misbehabing;
652         }
653
654         switch(type) {
655                 case ECHLD_ERROR: break;
656                 case ECHLD_TIMED_OUT: break;
657                 case ECHLD_HELLO: CHLD_SET_STATE(c,IDLE); break;
658                 case ECHLD_CLOSING:
659                         c->closing = TRUE;
660                         CHLD_SET_STATE(c,CLOSING);
661                         break;
662                 case ECHLD_PARAM: break;
663                 case ECHLD_PONG: break;
664                 case ECHLD_FILE_OPENED: CHLD_SET_STATE(c,READING); break;
665                 case ECHLD_INTERFACE_OPENED: CHLD_SET_STATE(c,READY); break;
666                 case ECHLD_CAPTURE_STARTED: CHLD_SET_STATE(c,CAPTURING); break;
667                 case ECHLD_NOTIFY: break;
668                 case ECHLD_PACKET_SUM: break;
669                 case ECHLD_TREE: break;
670                 case ECHLD_BUFFER: break;
671
672                 case ECHLD_EOF:
673                 case ECHLD_CAPTURE_STOPPED: CHLD_SET_STATE(c,DONE); break;
674
675                 case ECHLD_NOTE_ADDED: break;
676                 case ECHLD_PACKET_LIST: break;
677                 case ECHLD_FILE_SAVED: break;
678
679                 default:
680                         goto misbehabing;
681         }
682
683         DISP_DBG((4,"Dispatching to parent reqh_id=%d chld_id=%d type='%c'",reqh_id,c->chld_id,type));
684         return DISP_WRITE(dispatcher->parent_out, &in_ba, chld_id, type, reqh_id);
685
686 misbehabing:
687         CHLD_SET_STATE(c,ERRORED);
688         c->closing = TRUE;
689         kill(c->pid,SIGTERM);
690         dispatcher_err(ECHLD_ERR_CRASHED_CHILD,"chld_id=%d",chld_id);
691         return 0;
692
693 }
694
695 static struct timeval start_wait_time;
696 static long start_wait_time_us = CHILD_START_WAIT_TIME;
697
698 static void detach_new_child(enc_msg_t* em,  echld_chld_id_t chld_id) {
699         struct dispatcher_child* c;
700         int reqh_id = dispatcher->reqh_id;
701         int pid;
702
703         if (( c = dispatcher_get_child(dispatcher, chld_id) )) {
704                 dispatcher_err(ECHLD_ERR_CHILD_EXISTS,"chld_id=%d exists already while creating new child",chld_id);
705                 return;
706         } else if (( c = dispatcher_get_child(dispatcher, -1) )) {
707                 int disp_pipe_fds[2];
708                 int child_pipe_fds[2];
709
710                 int pipe_to_disp;
711                 int pipe_from_disp;
712                 int pipe_to_child;
713                 int pipe_from_child;
714
715                 DISP_DBG((5,"new_child pipe(dispatcher)"));
716                 if( pipe(disp_pipe_fds) < 0) {
717                         dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN PARENT PIPE: %s",strerror(errno));
718                         return;
719                 }
720
721                 pipe_from_disp = disp_pipe_fds[0];
722                 pipe_to_child = disp_pipe_fds[1];
723
724                 DISP_DBG((5,"new_child pipe(child)"));
725                 if( pipe(child_pipe_fds) < 0) {
726                         close(pipe_from_disp);
727                         close(pipe_to_child);
728                         dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN CHILD PIPE: %s",strerror(errno));
729                         return;
730                 }
731
732                 pipe_from_child = child_pipe_fds[0];
733                 pipe_to_disp = child_pipe_fds[1];
734
735                 DISP_DBG((4,"New Child Forking()"));
736                 switch (( pid = fork() )) {
737                         case -1: {
738                                 close(pipe_to_child);
739                                 close(pipe_to_disp);
740                                 close(pipe_from_child);
741                                 close(pipe_from_disp);
742                                 dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT FORK: %s",strerror(errno));
743                                 return;
744                         }
745                         case 0: {
746                         /* I'm the child */
747                                 dispatcher_clear();
748
749                                 close(pipe_to_child);
750                                 close(pipe_from_child);
751
752                                 echld_child_initialize(chld_id, pipe_from_disp,pipe_to_disp,reqh_id,&stuff);
753
754                                 exit( echld_child_loop() );
755
756                                 /* it won't */
757                                 return;
758                         }
759                         default: {
760                         /* I'm the parent */
761
762                                 close(pipe_to_disp);
763                                 close(pipe_from_disp);
764
765                                 echld_reset_reader(&(c->reader), pipe_from_child,4096);
766                                 c->write_fd = pipe_to_child;
767                                 c->pid = pid;
768                                 c->chld_id = chld_id;
769                                 c->closing = FALSE;
770
771                                 CHLD_SET_STATE(c,CREATING);
772
773                                 DISP_DBG((4,"Child Forked pid=%d chld_id=%d from_fd=%d to_fd=%d",
774                                 pid, c->chld_id, pipe_from_child, pipe_to_child));
775
776                                 start_wait_time.tv_sec = (int)(start_wait_time_us / 1000000);
777                                 start_wait_time.tv_usec = (int)(start_wait_time_us % 1000000);
778
779                                 select(0,NULL,NULL,NULL,&start_wait_time);
780
781                                 /* configure child */
782                                 DISP_WRITE(pipe_to_child, em, c->chld_id, ECHLD_NEW_CHILD, dispatcher->reqh_id);
783                                 return;
784                         }
785                 }
786         } else {
787                 dispatcher_err(ECHLD_ERR_CANNOT_FORK, "MAX CHILDREN REACHED: max_children=%d",dispatcher->max_children);
788                 return;
789         }
790 }
791
792
793 /* process signals sent from parent */
794 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_) {
795         GByteArray in_ba;
796
797         in_ba.data = b;
798         in_ba.len = (guint)len;
799
800         dispatcher->reqh_id = reqh_id;
801
802         DISP_DBG((1,"RCV<- type='%s' chld_id=%d reqh_id=%d",TY(type),chld_id,reqh_id));
803
804         if (chld_id == 0) { /* these are messages sent to the dispatcher itself */
805                 DISP_DBG((2,"Message to Dispatcher"));
806                 switch(type) {
807                         case ECHLD_CLOSE_CHILD:
808                                 dispatcher_destroy();
809                                 return 0;
810                         case ECHLD_PING:
811                                 DISP_DBG((2,"PONG reqh_id=%d",reqh_id));
812                                 DISP_WRITE(dispatcher->parent_out, NULL, chld_id, ECHLD_PONG, reqh_id);
813                                 return 0;
814                         case ECHLD_SET_PARAM:{
815                                 char* param;
816                                 char* value;
817                                 if ( dispatcher->dec.from_parent->set_param(b,len,&param,&value) ) {
818                                         GByteArray* ba;
819                                         char* err;
820                                         if (! paramset_apply_set (disp_params, param, value, &err) ) {
821                                                 dispatcher_err(ECHLD_CANNOT_SET_PARAM,"%s",err);
822                                                 g_free(err);
823                                                 return 0;
824                                         }
825
826                                         ba = dispatcher->enc.to_parent->param(param,value);
827                                         DISP_RESP(ba,ECHLD_PARAM);
828                                         g_byte_array_free(ba,TRUE);
829                                         DISP_DBG((1,"Set Param: param='%s' value='%s'",param,value));
830
831                                         return 0;
832                                 } else {
833                                         dispatcher_err(ECHLD_CANNOT_SET_PARAM,"reason='decoder error'");
834                                         return 0;
835                                 }
836                         }
837                         case ECHLD_GET_PARAM: {
838                                 GByteArray* ba;
839                                 char* param;
840                                 if ( dispatcher->dec.from_parent->get_param(b,len,&param) ) {
841                                         char* err;
842                                         char* val;
843
844                                         if (! (val = paramset_apply_get (disp_params, param, &err)) ) {
845                                                 dispatcher_err(ECHLD_CANNOT_GET_PARAM,"%s",err);
846                                                 g_free(err);
847                                                 return 0;
848                                         }
849
850                                         ba = dispatcher->enc.to_parent->param(param,val);
851                                         DISP_RESP(ba,ECHLD_PARAM);
852                                         g_byte_array_free(ba,TRUE);
853                                         DISP_DBG((1,"Get Param: param='%s' value='%s'",param,val));
854                                         return 0;
855                                 } else {
856                                         dispatcher_err(ECHLD_CANNOT_GET_PARAM,"reason='decoder error'");
857                                         return 0;
858                                 }
859                         }
860                         default:
861                                 dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message to dispatcher type='%c'", type);
862                                 return 0;
863                 }
864         } else {
865                 struct dispatcher_child* c;
866
867                 DISP_DBG((2,"Parent => Child"));
868
869                 if (! (c = dispatcher_get_child(dispatcher, chld_id)) ) {
870                         if (type == ECHLD_NEW_CHILD) {
871                                 detach_new_child(&in_ba,chld_id);
872                                 return 0;
873                         } else {
874                                 dispatcher_err(ECHLD_ERR_NO_SUCH_CHILD, "wrong chld_id %d", chld_id);
875                                 return 0;
876                         }
877                 } else {
878                         switch(type) {
879                                 case ECHLD_CLOSE_CHILD:
880                                         CHLD_SET_STATE(c,CLOSED);
881                                         goto relay_frame;
882
883                                 case ECHLD_OPEN_FILE:
884                                         CHLD_SET_STATE(c,READING);
885                                         goto relay_frame;
886
887                                 case ECHLD_OPEN_INTERFACE:
888                                         CHLD_SET_STATE(c,READY);
889                                         goto relay_frame;
890
891                                 case ECHLD_START_CAPTURE:
892                                         CHLD_SET_STATE(c,CAPTURING);
893                                         goto relay_frame;
894
895                                 case ECHLD_STOP_CAPTURE:
896                                         CHLD_SET_STATE(c,DONE);
897                                         goto relay_frame;
898
899                                 case ECHLD_SAVE_FILE:
900                                 case ECHLD_APPLY_FILTER:
901                                 case ECHLD_SET_PARAM:
902                                 case ECHLD_GET_PARAM:
903                                 case ECHLD_PING:
904                                 case ECHLD_GET_SUM:
905                                 case ECHLD_GET_TREE:
906                                 case ECHLD_GET_BUFFER:
907                                 case ECHLD_ADD_NOTE:
908                                 relay_frame: {
909                                         DISP_DBG((3,"Relay to Child chld_id=%d type='%c' req_id=%d",chld_id, type, reqh_id));
910                                         return DISP_WRITE(c->write_fd, &in_ba, chld_id, type, reqh_id);
911                                 }
912                                 default:
913                                         dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message %d %c", reqh_id, type);
914                                         return 0;
915                         }
916                 }
917         }
918 }
919
920
921
922 int dispatcher_loop(void) {
923         int parent_out = dispatcher->parent_out;
924         int parent_in = dispatcher->parent_in.fd;
925         struct dispatcher_child* children = dispatcher->children;
926
927         DISP_DBG((5,"LOOP in_fd=%d out_fd=%d",parent_in, parent_out));
928
929         do {
930                 fd_set rfds;
931                 fd_set efds;
932                 struct dispatcher_child* c;
933                 int nfds;
934                 int nchld = 0;
935                 struct timeval disp_loop_timeout;
936
937                 FD_ZERO(&rfds);
938                 FD_ZERO(&efds);
939
940                 FD_SET(parent_in,&rfds);
941                 FD_SET(parent_in,&efds);
942                 FD_SET(parent_out,&efds);
943
944                 for (c = children; c->pid; c++) {
945                         if (c->chld_id > 0) {
946                                 nchld++;
947                                 FD_SET(c->reader.fd, &rfds);
948                                 FD_SET(c->reader.fd, &efds);
949                         }
950                 }
951
952                 DISP_DBG((4,"Select()ing nchld=%d",nchld,disp_loop_timeout.tv_usec));
953
954                 disp_loop_timeout.tv_sec = (int)(disp_loop_timeout_usec / 1000000);
955                 disp_loop_timeout.tv_usec = (int)(disp_loop_timeout_usec % 1000000);
956
957                 nfds = select(FD_SETSIZE, &rfds, NULL, &efds, &disp_loop_timeout);
958
959                 DISP_DBG((5,"Select()ed nfds=%d",nchld,nfds));
960
961                 if (nfds < 0) {
962                         DISP_DBG((1,"select error='%s'",strerror(errno) ));
963                         continue;
964                 }
965
966                 if ( FD_ISSET(parent_in, &rfds)) {
967                         long st = echld_read_frame(&(dispatcher->parent_in), dispatch_to_child, dispatcher);
968
969                         if (st < 0) {
970                                 DISP_DBG((1,"read frame returning < 0 for parent"));
971                                 /* XXX: ??? */
972                                 continue;
973                         }
974                 }
975
976                 if ( FD_ISSET(parent_in, &efds) ) {
977                         DISP_DBG((1,"Parent In Pipe Errored!"));
978                         continue;
979                 }
980
981                 if ( FD_ISSET(parent_out, &efds) ) {
982                         DISP_DBG((1,"Parent Out Pipe Errored!"));
983                         continue;
984                 }
985
986
987                 for (c=children; c->pid; c++) {
988                         if (c->reader.fd > 0) {
989                                 if ( FD_ISSET(c->reader.fd,&efds) ) {
990                                         struct timeval wait_time;
991                                         wait_time.tv_sec = 0;
992                                         wait_time.tv_usec = DISP_KILLED_CHILD_WAIT;
993
994                                         DISP_DBG((1,"errored child pipe chld_id=%d",c->chld_id));
995                                         kill(c->pid,SIGTERM);
996                                         select(0,NULL,NULL,NULL,&wait_time);
997                                         dispatcher_clear_child(c);
998                                         continue;
999                                 }
1000
1001                                 if (FD_ISSET(c->reader.fd,&rfds)) {
1002                                         long st = echld_read_frame(&(c->reader), dispatch_to_parent, c);
1003
1004                                         if (st < 0) {
1005                                                 DISP_DBG((1,"read_frame returned < 0 for chld_id=%d",c->chld_id));
1006                                                 /* XXX */
1007                                                 continue;
1008                                         }
1009                                         continue;
1010                                 }
1011                         }
1012                 }
1013         } while(1);
1014
1015         /* won't */
1016         return 1;
1017 }
1018
1019 void dispatcher_alrm(int sig _U_) {
1020         DISP_DBG((1,"ALRM received"));
1021 }
1022
1023 void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* argv0, int (*main)(int, char **)) {
1024         static struct dispatcher d;
1025         int i;
1026
1027         DISP_DBG_INIT();
1028         DISP_DBG((2,"Dispatcher Starting"));
1029
1030
1031         signal(SIGCHLD,dispatcher_reaper);
1032
1033         signal(SIGTERM,dispatcher_sig);
1034         signal(SIGPIPE,dispatcher_sig);
1035         signal(SIGINT,SIG_IGN);
1036         signal(SIGCONT,SIG_IGN);
1037         signal(SIGABRT,dispatcher_sig);
1038         signal(SIGHUP,dispatcher_sig);
1039         signal(SIGALRM,dispatcher_alrm);
1040
1041         dispatcher = &d;
1042
1043         echld_init_reader(&(d.parent_in),in_pipe_fds[0],4096);
1044         d.parent_out = out_pipe_fds[1];
1045         d.children = g_new0(struct dispatcher_child,ECHLD_MAX_CHILDREN);
1046         d.max_children = ECHLD_MAX_CHILDREN;
1047         d.nchildren = 0;
1048         d.reqh_id = -1;
1049         d.pid = getpid();
1050         d.dumpcap_pid = 0;
1051
1052         for (i=0;i<ECHLD_MAX_CHILDREN;i++) dispatcher_clear_child(&(d.children[i]));
1053
1054         close(out_pipe_fds[0]);
1055         close(in_pipe_fds[1]);
1056
1057         echld_get_all_codecs(&(d.enc.to_parent), &(d.dec.from_parent), &(d.enc.to_child), &(d.dec.from_child));
1058
1059         DISP_DBG((2,"Dispatcher Configured pid=%d parent_in=%d parent_out=%d",d.pid,in_pipe_fds[0],d.parent_out));
1060
1061         preinit_epan(argv0,main);
1062
1063         DISP_WRITE(dispatcher->parent_out, NULL, 0, ECHLD_HELLO, 0);
1064         exit(dispatcher_loop());
1065 }
1066
1067