2 * epan working child API internals
3 * Dispatcher process routines and definitions
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"
33 struct dispatcher_child
{
34 echld_chld_id_t chld_id
;
36 echld_reader_t reader
;
45 echld_reader_t parent_in
;
46 struct dispatcher_child
* children
;
53 child_encoder_t
* to_parent
;
54 echld_parent_encoder_t
* to_child
;
57 child_decoder_t
* from_parent
;
58 parent_decoder_t
* from_child
;
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
, ...) {
78 if (debug_lvl
<level
) return 1;
81 str
= g_strdup_vprintf(fmt
,ap
);
85 fprintf(debug_fp
, "dispatcher[%d]: reqh_id=%d dbg_level=%d message='%s'\n", dispatcher
->pid
, dispatcher
->reqh_id
, level
, str
);
87 fprintf(debug_fp
, "dispatcher: dbg_level=%d message='%s'\n", level
, str
);
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
) {
104 int lvl
= (int)strtol(val
, &p
, 10);
107 *err
= g_strdup("not an integer");
109 } else if (lvl
< 0 || lvl
> 5) {
110 *err
= g_strdup_printf("invalid level=%d (min=0 max=5)",lvl
);
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)
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))
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) {
142 capture_opts_init(&stuff
.cap_opts
);
143 capture_session_init(&stuff
.cap_sess
, (void *)&stuff
.cfile
);
148 static void children_massacre(void) {
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
]);
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
, ...) {
169 g_vsnprintf(err_str
,len
,fmt
,ap
);
172 DISP_DBG((0,"fatal cause=%d msg=\"%s\"",cause
,err_str
));
179 #define DISP_FATAL(attrs) dispatcher_fatal attrs
181 static void dispatcher_err(int errnum
, const char* fmt
, ...) {
185 static GByteArray
* ba
;
188 g_vsnprintf(err_str
,len
,fmt
,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
);
200 /* interface listing */
202 static char* intflist2json(GList
* if_list
, char** if_cap_err
) {
203 #define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
210 if_capabilities_t
*caps
;
211 char addr_str
[ADDRSTRLEN
];
212 GString
*str
= g_string_new("{ what='interfaces', interfaces={ \n");
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-
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
) {
240 if (inet_ntop(AF_INET
, &if_addr
->addr
.ip4_addr
, addr_str
,
242 g_string_append_printf(str
,"'%s',", addr_str
);
244 g_string_append(str
,"'<unknown IPv4>',");
248 if (inet_ntop(AF_INET6
, &if_addr
->addr
.ip6_addr
,
249 addr_str
, ADDRSTRLEN
)) {
250 g_string_append_printf(str
,"'%s',", addr_str
);
252 g_string_append(str
,"'<unknown IPv6>',");
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");
268 g_string_append(str
,", loopback=0");
272 caps
= capture_get_if_capabilities(if_info
->name
, 0, if_cap_err
, 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
,"}");
323 g_string_free(str
,FALSE
);
327 static char* intf_list
= NULL
;
329 static void get_interfaces(char** err
) {
334 if_list
= capture_interface_list(&err_no
, err
, NULL
);
337 DISP_DBG((1,"Could not get capture interface list: %s",err
));
339 intf_list
= intflist2json(if_list
,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
) {
361 int usec
= (int)strtol(val
, &p
, 10); /* now usecs 2DO: "10ms" or "500us" or "1s" */
364 *err
= g_strdup("not an integer");
368 disp_loop_timeout_usec
= usec
;
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("");
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
));
400 g_string_free(str
,FALSE
);
404 static echld_bool_t
param_set_add_hosts_file(char* val
, char** err
) {
405 if (add_hosts_file(val
)) {
408 *err
= g_strdup_printf("Can't read host entries from \"%s\"",val
);
413 static echld_bool_t
param_set_x_opt(char* val
, char** err
) {
414 if (ex_opt_add(val
)) {
417 *err
= g_strdup_printf("Cannot set X opt '%s'",val
);
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"),
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
) {
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
;
460 static void dispatcher_clear_child(struct dispatcher_child
* c
) {
461 echld_reset_reader(&(c
->reader
), -1, 4096);
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
;
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
);
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
);
507 capture_sync_set_fetch_dumpcap_pid_cb(set_dumpcap_pid
);
509 init_process_policies();
511 get_interfaces(&error
);
514 DISP_FATAL((CANNOT_PREINIT_EPAN
,"Error getting interfaces: %s", error
));
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
);
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);
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
));
558 void dispatcher_reaper(int sig
) {
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
;
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
);
585 if (WIFEXITED(status
)) {
587 "Unexpected dead: reason='exited' pid=%d status=%d",
588 pid
, WEXITSTATUS(status
));
589 } else if ( WIFSIGNALED(status
) ) {
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
)) {
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
);
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
;
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
));
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
;
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 */
645 struct dispatcher_child
* c
= (struct dispatcher_child
*)data
;
647 dispatcher
->reqh_id
= c
->reqh_id
= reqh_id
;
650 in_ba
.len
= (guint
)len
;
652 if (chld_id
!= c
->chld_id
) {
657 case ECHLD_ERROR
: break;
658 case ECHLD_TIMED_OUT
: break;
659 case ECHLD_HELLO
: CHLD_SET_STATE(c
,IDLE
); break;
662 CHLD_SET_STATE(c
,CLOSING
);
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;
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;
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
);
689 CHLD_SET_STATE(c
,ERRORED
);
691 kill(c
->pid
,SIGTERM
);
692 dispatcher_err(ECHLD_ERR_CRASHED_CHILD
,"chld_id=%d",chld_id
);
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
;
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
);
708 } else if (( c
= dispatcher_get_child(dispatcher
, -1) )) {
709 int disp_pipe_fds
[2];
710 int child_pipe_fds
[2];
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
));
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
));
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() )) {
740 close(pipe_to_child
);
742 close(pipe_from_child
);
743 close(pipe_from_disp
);
744 dispatcher_err(ECHLD_ERR_CANNOT_FORK
,"CANNOT FORK: %s",strerror(errno
));
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() );
765 close(pipe_from_disp
);
767 echld_reset_reader(&(c
->reader
), pipe_from_child
,4096);
768 c
->write_fd
= pipe_to_child
;
770 c
->chld_id
= chld_id
;
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
);
789 dispatcher_err(ECHLD_ERR_CANNOT_FORK
, "MAX CHILDREN REACHED: max_children=%d",dispatcher
->max_children
);
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_
) {
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"));
809 case ECHLD_CLOSE_CHILD
:
810 dispatcher_destroy();
813 DISP_DBG((2,"PONG reqh_id=%d",reqh_id
));
814 DISP_WRITE(dispatcher
->parent_out
, NULL
, chld_id
, ECHLD_PONG
, reqh_id
);
816 case ECHLD_SET_PARAM
:{
819 if ( dispatcher
->dec
.from_parent
->set_param(b
,len
,¶m
,&value
) ) {
822 if (! paramset_apply_set (disp_params
, param
, value
, &err
) ) {
823 dispatcher_err(ECHLD_CANNOT_SET_PARAM
,"%s",err
);
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
));
835 dispatcher_err(ECHLD_CANNOT_SET_PARAM
,"reason='decoder error'");
839 case ECHLD_GET_PARAM
: {
842 if ( dispatcher
->dec
.from_parent
->get_param(b
,len
,¶m
) ) {
846 if (! (val
= paramset_apply_get (disp_params
, param
, &err
)) ) {
847 dispatcher_err(ECHLD_CANNOT_GET_PARAM
,"%s",err
);
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
));
858 dispatcher_err(ECHLD_CANNOT_GET_PARAM
,"reason='decoder error'");
863 dispatcher_err(ECHLD_ERR_WRONG_MSG
, "wrong message to dispatcher type='%c'", type
);
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
);
876 dispatcher_err(ECHLD_ERR_NO_SUCH_CHILD
, "wrong chld_id %d", chld_id
);
881 case ECHLD_CLOSE_CHILD
:
882 CHLD_SET_STATE(c
,CLOSED
);
885 case ECHLD_OPEN_FILE
:
886 CHLD_SET_STATE(c
,READING
);
889 case ECHLD_OPEN_INTERFACE
:
890 CHLD_SET_STATE(c
,READY
);
893 case ECHLD_START_CAPTURE
:
894 CHLD_SET_STATE(c
,CAPTURING
);
897 case ECHLD_STOP_CAPTURE
:
898 CHLD_SET_STATE(c
,DONE
);
901 case ECHLD_SAVE_FILE
:
902 case ECHLD_APPLY_FILTER
:
903 case ECHLD_SET_PARAM
:
904 case ECHLD_GET_PARAM
:
908 case ECHLD_GET_BUFFER
:
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
);
915 dispatcher_err(ECHLD_ERR_WRONG_MSG
, "wrong message %d %c", reqh_id
, type
);
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
));
934 struct dispatcher_child
* c
;
937 struct timeval disp_loop_timeout
;
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) {
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
));
964 DISP_DBG((1,"select error='%s'",strerror(errno
) ));
968 if ( FD_ISSET(parent_in
, &rfds
)) {
969 long st
= echld_read_frame(&(dispatcher
->parent_in
), dispatch_to_child
, dispatcher
);
972 DISP_DBG((1,"read frame returning < 0 for parent"));
978 if ( FD_ISSET(parent_in
, &efds
) ) {
979 DISP_DBG((1,"Parent In Pipe Errored!"));
983 if ( FD_ISSET(parent_out
, &efds
) ) {
984 DISP_DBG((1,"Parent Out Pipe Errored!"));
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
);
1003 if (FD_ISSET(c
->reader
.fd
,&rfds
)) {
1004 long st
= echld_read_frame(&(c
->reader
), dispatch_to_parent
, c
);
1007 DISP_DBG((1,"read_frame returned < 0 for chld_id=%d",c
->chld_id
));
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
;
1028 #ifdef DEBUG_DISPATCHER
1033 #ifdef DEBUG_DISPATCHER
1034 dbg_fd
= fileno(debug_fp
);
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
);
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
;
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());