2 * epan working child internals
3 * Child 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.
29 #include "echld-int.h"
32 typedef struct _child
{
39 echld_reader_t parent
;
42 int pipe_from_dumpcap
;
47 struct timeval started
;
59 // capture_file cfile;
64 static echld_epan_stuff_t
* stuff
= NULL
;
66 static echld_child_t child
;
75 static int debug_lvl
= DEBUG_CHILD
;
76 static FILE* debug_fp
= NULL
;
77 #define DBG_BUF_LEN 1024
81 int child_debug(int level
, const char* fmt
, ...) {
83 char str
[DBG_BUF_LEN
];
85 if (debug_lvl
<level
) return 1;
88 vsnprintf(str
,DBG_BUF_LEN
,fmt
,ap
);
91 fprintf(debug_fp
, "child[%d-%d]: reqh_id=%d debug_lvl=%d message='%s'\n",
92 child
.chld_id
, child
.pid
, child
.reqh_id
, level
, str
);
97 static char* param_get_dbg_level(char** err _U_
) {
98 return g_strdup_printf("%d",debug_lvl
);
101 static echld_bool_t
param_set_dbg_level(char* val
, char** err
) {
103 int lvl
= (int)strtol(val
, &p
, 10);
106 *err
= g_strdup("not an integer");
108 } else if (lvl
< 0 || lvl
> 5) {
109 *err
= g_strdup_printf("invalid level=%d (min=0 max=5)",lvl
);
119 static long dbg_resp(GByteArray
* em
, echld_msg_type_t t
) {
120 long st
= echld_write_frame(child
.fds
.pipe_to_parent
, em
, child
.chld_id
, t
, child
.reqh_id
, NULL
);
121 child_debug(1, "SND fd=%d ch=%d ty='%s' rh=%d msg='%s'",
122 child
.fds
.pipe_to_parent
, child
.chld_id
, TY(t
), child
.reqh_id
, (st
>0?"ok":strerror(errno
)) );
126 #define CHILD_DBG(attrs) ( child_debug attrs )
127 #define CHILD_DBG_INIT() do { debug_fp = stderr; DCOM(); } while(0)
128 #define CHILD_DBG_START(fname) do { debug_fp = fopen(fname,"a"); DCOM(); CHILD_DBG((0,"Log Started")); } while(0)
129 #define CHILD_RESP(BA,T) dbg_resp(BA,T)
130 #define CHILD_STATE(ST) do { DISP_DBG((0,"State %s => %s")) } while(0)
132 #define CHILD_DBG(attrs)
133 #define CHILD_DBG_INIT()
134 #define CHILD_DBG_START(fname)
135 #define CHILD_RESP(BA,T) echld_write_frame(child.fds.pipe_to_parent,(BA),child.chld_id,T,child.reqh_id,NULL)
139 static struct timeval close_sleep_time
;
142 static void sig_term(int sig _U_
) {
143 CHILD_DBG((3,"Terminated, Closing"));
147 extern void echld_child_initialize(echld_chld_id_t chld_id
, int pipe_from_parent
, int pipe_to_parent
, int reqh_id
, echld_epan_stuff_t
* es
) {
150 close_sleep_time
.tv_sec
= CHILD_CLOSE_SLEEP_TIME
/ 1000000;
151 close_sleep_time
.tv_usec
= CHILD_CLOSE_SLEEP_TIME
% 1000000;
153 child
.chld_id
= chld_id
;
155 child
.pid
= getpid();
156 child
.dispatcher_pid
= getppid();
157 child
.reqh_id
= reqh_id
;
158 echld_init_reader( &(child
.parent
), pipe_from_parent
,4096);
159 child
.fds
.pipe_to_parent
= pipe_to_parent
;
160 child
.fds
.pipe_from_dumpcap
= -1;
161 child
.fds
.pipe_to_dumpcap
= -1;
162 child
.fds
.file_being_read
= -1;
163 gettimeofday(&child
.started
,NULL
);
164 child
.now
.tv_sec
= child
.started
.tv_sec
;
165 child
.now
.tv_usec
= child
.started
.tv_usec
;
167 echld_get_all_codecs(&(child
.enc
), &(child
.dec
), NULL
, NULL
);
170 CHILD_DBG((5,"Child Initialized ch=%d from=%d to=%d rq=%d",chld_id
, pipe_from_parent
, pipe_to_parent
, reqh_id
));
172 /*clear signal handlers */
173 signal(SIGALRM
,SIG_DFL
);
174 signal(SIGTERM
,sig_term
);
175 signal(SIGPIPE
,SIG_DFL
);
176 signal(SIGINT
,SIG_DFL
);
177 signal(SIGABRT
,SIG_DFL
);
178 signal(SIGHUP
,SIG_DFL
);
185 void child_err(int e
, unsigned reqh_id
, const char* fmt
, ...) {
189 static GByteArray
* ba
;
192 g_vsnprintf(err_str
,len
,fmt
,ap
);
195 CHILD_DBG((0,"error='%s'",err_str
));
197 ba
= child
.enc
->error(e
, err_str
);
198 echld_write_frame(child
.fds
.pipe_to_parent
, ba
, child
.chld_id
, ECHLD_ERROR
, reqh_id
, NULL
);
199 g_byte_array_free(ba
,TRUE
);
203 static char* param_get_cwd(char** err
) {
204 char* pwd
= getcwd(NULL
, 128);
207 *err
= g_strdup(strerror(errno
));
212 static echld_bool_t
param_set_cwd(char* val
, char** err
) {
214 if (chdir(val
) != 0) {
215 *err
= g_strdup_printf("cannot chdir reas='%s'",strerror(errno
));
223 static unsigned packet_count
= 0;
224 static char* param_get_packet_count(char** err
) {
226 if (child
.state
!= CAPTURING
|| child
.state
!= READING
) {
227 *err
= g_strdup("Must be reading or in-capture for packet_count");
230 return g_strdup_printf("%d",packet_count
);
235 static echld_bool_t
param_set_dfilter(char* val
, char** err _U_
) {
236 dfilter_t
*dfn
= NULL
;
238 if (child
.state
!= IDLE
&& child
.state
!= DONE
) {
239 *err
= g_strdup("Only while idle or done");
241 } else if ( dfilter_compile(val
, &dfn
) ) {
242 if (child
.dfilter
) g_free(child
.dfilter
);
243 if (child
.df
) dfilter_free(child
.df
);
245 child
.dfilter
= g_strdup(val
);
248 *err
= g_strdup(dfilter_error_msg
);
253 static char* param_get_dfilter(char** err _U_
) { return g_strdup(child
.dfilter
? child
.dfilter
: ""); }
255 char* param_profile
= NULL
;
257 static echld_bool_t
param_set_profile(char* val
, char** err
) {
259 if (child
.state
!= IDLE
) {
260 *err
= g_strdup_printf("Cannot set Profile \"%s\", too late.", val
);
264 if (profile_exists (val
, FALSE
)) {
265 set_profile_name (val
);
266 if (param_profile
) g_free(param_profile
);
267 param_profile
= g_strdup(val
);
270 *err
= g_strdup_printf("Configuration Profile \"%s\" does not exist", val
);
275 static char* param_get_profile(char** err _U_
) { return g_strdup(param_profile
? param_profile
: ""); }
277 static char* param_get_file_list(char** err
) {
278 GError
* gerror
= NULL
;
279 GDir
* dir
= g_dir_open(".", 0, &gerror
);
280 GString
* str
= g_string_new("{ what='file_list', files=[");
285 *err
= g_strdup_printf("Failed to open curr dir reason='%s'",gerror
->message
);
289 while(( file
= g_dir_read_name(dir
) )) {
290 g_string_append_printf(str
,"{filename='%s'},\n",file
);
294 g_string_truncate(str
, str
->len
-2); /* ',\n' */
295 g_string_append(str
, "]}");
298 g_string_free(str
,FALSE
);
302 #ifdef PCAP_NG_DEFAULT
303 static int out_file_type
= WTAP_FILE_TYPE_SUBTYPE_PCAPNG
;
305 static int out_file_type
= WTAP_FILE_TYPE_SUBTYPE_PCAP
;
308 static echld_bool_t
param_set_out_file_type(char* val
, char** err
) {
309 int oft
= wtap_short_string_to_file_type(val
);
312 *err
= g_strdup_printf("\"%s\" isn't a valid capture file type", val
);
320 static char* param_get_out_file_type(char** err _U_
) {
321 return g_strdup_printf("%s(%d): %s",
322 wtap_file_type_short_string(out_file_type
),
323 out_file_type
, wtap_file_type_string(out_file_type
));
327 static echld_bool_t
param_set_add_hosts_file(char* val
, char** err
) {
328 if (add_hosts_file(val
)) {
331 *err
= g_strdup_printf("Can't read host entries from \"%s\"",val
);
336 PARAM_BOOL(quiet
,FALSE
);
337 PARAM_BOOL(start_capture
,FALSE
);
338 PARAM_BOOL(push_details
,FALSE
);
339 PARAM_BOOL(print_hex
,FALSE
);
341 static char* param_get_params(char** err _U_
);
343 static param_t child_params
[] = {
345 PARAM(dbg_level
,"Debug Level (0<int<5)"),
347 PARAM(profile
,"Configuration Profile (str)"),
348 PARAM(cwd
,"Current Directory (str)"),
349 PARAM(dfilter
,"Dispay Filter (str)"),
350 RO_PARAM(packet_count
,"Packets Read/Captured So Far (str)"),
351 RO_PARAM(file_list
,"List of Files in the Current Dir"),
352 PARAM(start_capture
,"Automatically start capture"),
353 PARAM(quiet
,"Quiet Mode"),
354 PARAM(push_details
,"Whether details of dissection should be passed"),
355 PARAM(print_hex
,"Output in hex"),
356 PARAM(out_file_type
,"Output File Type"),
357 WO_PARAM(add_hosts_file
,"Add a Hosts File"),
358 RO_PARAM(params
,"This List"),
359 {NULL
,NULL
,NULL
,NULL
}
362 static char* param_get_params(char** err _U_
) {
363 return paramset_get_params_list(child_params
,PARAM_LIST_FMT
);
366 static void child_open_file(char* filename
) {
367 CHILD_DBG((2,"CMD open file filename='%s'",filename
));
368 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"open file not implemented yet!");
369 child
.state
= READING
;
372 static void child_open_interface(char* intf
, char* pars
) {
373 CHILD_DBG((2,"CMD open interface intf='%s', params='%s'",intf
,pars
));
374 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"open interface not implemented yet!");
378 static void child_start_capture(void) {
379 CHILD_DBG((2,"CMD start capture"));
380 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"start capture not implemented yet!");
381 child
.state
= CAPTURING
;
384 static void child_stop_capure(void) {
385 CHILD_DBG((2,"CMD stop capture"));
386 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"stop capture not implemented yet!");
390 static void child_get_summary(char* range
) {
391 CHILD_DBG((2,"CMD get summary range='%s'",range
));
392 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"get_summary not implemented yet!");
395 static void child_get_tree(char* range
) {
396 CHILD_DBG((2,"CMD get tree range='%s'",range
));
397 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"get_tree not implemented yet!");
400 static void child_get_buffer(char* name
) {
401 CHILD_DBG((2,"CMD get buffer name='%s'",name
));
402 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"get_buffer not implemented yet!");
405 static void child_add_note(int framenum
, char* note
) {
406 CHILD_DBG((2,"CMD add note framenum=%d note='%s'",framenum
,note
));
407 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"add_note not implemented yet!");
410 static void child_apply_filter(char* filter
) {
411 CHILD_DBG((2,"CMD apply filter filter='%s'",filter
));
412 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"apply_filter not implemented yet!");
415 static void child_save_file(char* filename
, char* pars
) {
416 CHILD_DBG((2,"CMD save file filename='%s' params='%s'",filename
,pars
));
417 child_err(ECHLD_ERR_UNIMPLEMENTED
,child
.reqh_id
,"save_file not implemented yet!");
420 static long child_receive(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_
) {
425 child
.reqh_id
= reqh_id
;
427 CHILD_DBG((2,"RCVD type='%s' len='%d'",TY(type
),len
));
429 // gettimeofday(&(child.now), NULL);
431 if (child
.chld_id
!= chld_id
) {
432 child_err(ECHLD_ERR_WRONG_MSG
,reqh_id
,
433 "chld_id: own:%d given:%d msg_type='%s'",child
.chld_id
,chld_id
,TY(type
));
441 case ECHLD_NEW_CHILD
: {
442 child
.state
= CREATING
;
443 if ( !paramset_apply_em(child_params
,(enc_msg_t
*)&ba
, &err
) ) {
444 child_err(ECHLD_ERR_CRASHED_CHILD
,reqh_id
,
445 "Initial Paramset Error '%s'",err
);
448 CHILD_RESP(NULL
,ECHLD_HELLO
);
453 CHILD_DBG((1,"PONG"));
454 CHILD_RESP(&ba
,ECHLD_PONG
);
456 case ECHLD_SET_PARAM
:{
460 if ( child
.dec
->set_param
&& child
.dec
->set_param(b
,len
,¶m
,&value
) ) {
461 if (! paramset_apply_set (child_params
, param
, value
, &err
) ) {
462 child_err(ECHLD_CANNOT_SET_PARAM
,reqh_id
,"%s",err
);
467 gba
= child
.enc
->param(param
,value
);
468 CHILD_RESP(gba
,ECHLD_PARAM
);
469 g_byte_array_free(gba
,TRUE
);
470 CHILD_DBG((1,"Set Param: param='%s' value='%s'",param
,value
));
477 case ECHLD_GET_PARAM
: {
479 if ( child
.dec
->get_param
&& child
.dec
->get_param(b
,len
,¶m
) ) {
482 if (! (val
= paramset_apply_get (child_params
, param
, &err
)) ) {
483 child_err(ECHLD_CANNOT_GET_PARAM
,reqh_id
,"%s",err
);
488 gba
= child
.enc
->param(param
,val
);
489 CHILD_RESP(gba
,ECHLD_PARAM
);
490 g_byte_array_free(gba
,TRUE
);
491 CHILD_DBG((2,"Get Param: param='%s' value='%s'",param
,val
));
497 case ECHLD_CLOSE_CHILD
:
498 CHILD_RESP(NULL
,ECHLD_CLOSING
);
499 CHILD_DBG((3,"Closing"));
500 select(0,NULL
,NULL
,NULL
,&close_sleep_time
);
501 CHILD_DBG((1,"Bye"));
504 case ECHLD_OPEN_FILE
: {
506 if (child
.state
!= IDLE
) goto wrong_state
;
508 if ( child
.dec
->open_file(b
,len
,&filename
) ) {
509 child_open_file(filename
);
511 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode open_file");
515 case ECHLD_OPEN_INTERFACE
: {
519 if (child
.state
!= IDLE
) goto wrong_state
;
521 if ( child
.dec
->open_interface(b
,len
,&intf
,&pars
) ) {
522 child_open_interface(intf
,pars
);
524 child_err(ECHLD_DECODE_ERROR
,reqh_id
, "cannot decode open_interface");
528 case ECHLD_START_CAPTURE
:{
529 if (child
.state
!= READY
) goto wrong_state
;
530 child_start_capture();
533 case ECHLD_STOP_CAPTURE
: {
534 if (child
.state
!= CAPTURING
) goto wrong_state
;
538 case ECHLD_GET_SUM
: {
541 if (child
.state
!= CAPTURING
|| child
.state
!= READING
|| child
.state
!= DONE
) goto wrong_state
;
543 if ( child
.dec
->get_sum(b
,len
,&range
) ) {
544 child_get_summary(range
);
546 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode get_summary");
550 case ECHLD_GET_TREE
:{
553 if (child
.state
!= CAPTURING
&& child
.state
!= READING
&& child
.state
!= DONE
) goto wrong_state
;
555 if ( child
.dec
->get_tree(b
,len
,&range
) ) {
556 child_get_tree(range
);
558 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode get_tree");
562 case ECHLD_GET_BUFFER
:{
565 if (child
.state
!= CAPTURING
&& child
.state
!= READING
&& child
.state
!= DONE
) goto wrong_state
;
567 if ( child
.dec
->get_buffer(b
,len
,&name
) ) {
568 child_get_buffer(name
);
570 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode get_buffer");
574 case ECHLD_ADD_NOTE
: {
578 if (child
.state
!= CAPTURING
&& child
.state
!= READING
&& child
.state
!= DONE
) goto wrong_state
;
580 if ( child
.dec
->add_note(b
,len
,&framenum
,¬e
) ) {
581 child_add_note(framenum
,note
);
583 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode get_buffer");
587 case ECHLD_APPLY_FILTER
: {
590 if (child
.state
!= DONE
) goto wrong_state
;
592 if ( child
.dec
->apply_filter(b
,len
,&filter
) ) {
593 child_apply_filter(filter
);
595 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode apply_filter");
599 case ECHLD_SAVE_FILE
: {
603 if (child
.state
!= DONE
) goto wrong_state
;
605 if ( child
.dec
->save_file(b
,len
,&filename
,&pars
) ) {
606 child_save_file(filename
,pars
);
608 child_err(ECHLD_DECODE_ERROR
,reqh_id
,"cannot decode save_file");
613 child_err(ECHLD_ERR_WRONG_MSG
,reqh_id
,"wrong message: chld_id=%d msg_type='%s'",chld_id
,TY(type
));
620 // dump the misencoded message (b,blen)
621 child_err(ECHLD_ERR_WRONG_MSG
,reqh_id
,"misencoded msg msg_type='%s'",TY(type
));
625 child_err(ECHLD_ERR_WRONG_MSG
,reqh_id
,"unexpected message: received in wrong state='%s', msg_type='%s'",ST(child
.state
),TY(type
));
630 static int child_dumpcap_read(void) {
631 // this folk manages the reading of dumpcap's pipe
632 // it has to read interface descriptions when doing so
633 // and managing capture during capture
634 CHILD_DBG((2,"child_dumpcap_read"));
638 static void child_file_read(void) {
642 int echld_child_loop(void) {
643 int disp_from
= child
.parent
.fd
;
644 int disp_to
= child
.fds
.pipe_to_parent
;
650 CHILD_DBG((0,"entering child_loop()"));
656 struct timeval timeout
;
658 gboolean captured
= FALSE
;
664 FD_SET(disp_from
,&rfds
);
665 FD_SET(disp_from
,&efds
);
666 FD_SET(disp_to
,&efds
);
669 if (child
.fds
.pipe_from_dumpcap
> 0) {
670 FD_SET(child
.fds
.pipe_from_dumpcap
,&rfds
);
674 if (step
<= 20) CHILD_DBG((4,"child_loop: select()ing step=%d",step
++));
677 timeout
.tv_usec
= 999999;
679 nfds
= select(FD_SETSIZE
, &rfds
, &wfds
, &efds
, &timeout
);
681 if (step
<= 20) CHILD_DBG((4,"child_loop: select()ed nfds=%d",nfds
));
684 if ( FD_ISSET(disp_from
,&efds
) ) {
685 CHILD_DBG((0,"Broken Parent Pipe 'From' step=%d",step
));
689 if ( FD_ISSET(disp_to
,&efds
) ) {
690 CHILD_DBG((0,"Broken Parent Pipe 'To' step=%d",step
));
694 if (child
.fds
.pipe_from_dumpcap
> 0 && FD_ISSET(child
.fds
.pipe_from_dumpcap
,&efds
) ) {
695 CHILD_DBG((0,"Broken Dumpcap Pipe step=%d",step
));
699 if (FD_ISSET(disp_from
, &rfds
)) {
700 long st
= echld_read_frame(&(child
.parent
), child_receive
, &child
);
707 CHILD_DBG((0,"Read Frame Failed step=%d",step
));
712 if (child
.fds
.pipe_from_dumpcap
> 0 && FD_ISSET(child
.fds
.pipe_from_dumpcap
,&rfds
) ) {
717 captured
= child_dumpcap_read();
720 if ( child
.state
== READING
|| captured
) {
726 CHILD_RESP(NULL
,ECHLD_CLOSING
);
727 CHILD_DBG((3,"Closing"));