2 * epan working child API 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;
57 static echld_child_t child;
60 #define CHILD_RESP(BYTEARR,TYPE) echld_write_frame(child.fds.pipe_to_parent, BYTEARR, child.chld_id, TYPE, child.reqh_id, NULL)
64 #define DBG_BUFF_LEN 1024
65 static char dbg_buff[DBG_BUFF_LEN];
67 void child_debug(int level, char* fmt, ...) {
71 if (dbg_level<level) return;
74 str = g_strdup_vprintf(fmt,ap);
77 fprintf(stderr, "child[%d]: reqh_id=%d dbg_level=%d message='%s'", child.pid, child.reqh_id, level, str);
81 #define CHILD_DBG(attrs) ( child_debug attrs )
83 #define CHILD_DBG(attrs)
86 static void child_initialize(int pipe_from_parent, int pipe_to_parent, int reqh_id) {
89 child.ppid = getppid();
91 child.reqh_id = reqh_id;
92 init_reader( &(child.parent), pipe_from_parent);
93 child.fds.pipe_to_parent = pipe_to_parent;
94 child.fds.pipe_from_dumpcap = -1;
95 child.fds.pipe_to_dumpcap = -1;
96 child.fds.file_being_read = -1;
97 gettimeofday(&child.started,NULL);
98 gettimeofday(&child.now,NULL);
99 echld_get_all_codecs(&(child.enc), &(child.dec), NULL, NULL);
103 CHILD_DBG((5,"Child Initialized"));
108 void child_err(int e, unsigned reqh_id, const char* fmt, ...) {
113 static GByteArray* ba;
116 g_vsnprintf(err_str,len,fmt,ap);
119 CHILD_DBG((0,"error='%s'",err_str));
121 ba = (void*)child.enc->error(e, err_str);
122 echld_write_frame(child.fds.pipe_to_parent, ba, child.chld_id, ECHLD_ERROR, reqh_id, NULL);
123 g_byte_array_free(ba,TRUE);
127 static char* intflist2json(GList* if_list) {
128 /* blatantly stolen from print_machine_readable_interfaces in dumpcap.c */
129 #define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
136 char addr_str[ADDRSTRLEN];
137 GString *str = g_string_new("={ ");
140 i = 1; /* Interface id number */
141 for (if_entry = g_list_first(if_list); if_entry != NULL;
142 if_entry = g_list_next(if_entry)) {
143 if_info = (if_info_t *)if_entry->data;
144 g_string_append_printf(str,"%d={ intf='%s',", i++, if_info->name);
147 * Print the contents of the if_entry struct in a parseable format.
148 * Each if_entry element is tab-separated. Addresses are comma-
151 /* XXX - Make sure our description doesn't contain a tab */
152 if (if_info->vendor_description != NULL)
153 g_string_append_printf(str," vnd_desc='%s',", if_info->vendor_description);
155 /* XXX - Make sure our friendly name doesn't contain a tab */
156 if (if_info->friendly_name != NULL)
157 g_string_append_printf(str," name='%s', addrs=[ ", if_info->friendly_name);
159 for (addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
160 addr = g_slist_next(addr)) {
162 if_addr = (if_addr_t *)addr->data;
163 switch(if_addr->ifat_type) {
165 if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str,
167 g_string_append_printf(str,"%s", addr_str);
169 g_string_append(str,"<unknown IPv4>");
173 if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr,
174 addr_str, ADDRSTRLEN)) {
175 g_string_append_printf(str,"%s", addr_str);
177 g_string_append(str,"<unknown IPv6>");
181 g_string_append_printf(str,"<type unknown %u>", if_addr->ifat_type);
185 g_string_append(str," ]"); /* addrs */
188 if (if_info->loopback)
189 g_string_append(str,", loopback=1");
191 g_string_append(str,", loopback=0");
193 g_string_append(str,"}, ");
196 g_string_truncate(str,str->len - 2); /* the comma and space */
197 g_string_append(str,"}");
200 g_string_free(str,FALSE);
204 static void child_start_interface_listing() {}
206 static gboolean child_open_file(int chld_id, int reqh_id, char* filename, guint8* buff, int buff_len) {
207 char* reason = "Unimplemented"; // this ain't a good reason to fail!
208 g_snprintf(buff,buff_len,"Cannot open file=%s reason=%s",filename,reason);
212 static gboolean child_open_interface(int chld_id, int reqh_id, const char* intf_name, const char* params, guint8* err_buf, int errbuff_len) {
213 char* reason = "Unimplemented"; // this ain't a good reason to fail!
214 g_snprintf(err_buf,errbuff_len,"Cannot open interface=%s reason=%s",intf_name,reason);
219 static void child_list_files() {
220 char* file_info = "{glob='*.cap', file_list={'dummy.cap'={type='pcap-ng', size=20300, npackets=502}}}";
222 // foreach file in cur dir
223 GByteArray* ba = (void*)child.enc->file_info(file_info);
224 CHILD_RESP(ba,ECHLD_FILE_INFO);
225 g_byte_array_free(ba,TRUE);
229 static char* param_get_cwd(char** err ) {
230 char* pwd = getcwd(NULL, 128);
233 *err = g_strdup(strerror(errno));
238 static echld_bool_t param_set_cwd(char* val , char** err ) {
240 if (chdir(val) != 0) {
241 *err = g_strdup_printf("(%d)'%s'",errno,strerror(errno));
248 #define COOKIE_SIZE 1024
249 static char* cookie = NULL;
251 static char* param_get_cookie(char** err ) {
253 return g_strdup(cookie);
255 *err = g_strdup("cookie not set");
258 static echld_bool_t param_set_cookie(char* val , char** err ) {
260 if (cookie) g_free(cookie);
262 cookie = g_strdup(val);
267 static char* param_get_dbg_level(char** err ) {
268 return g_strdup_printf("%d",dbg_level);
271 static echld_bool_t param_set_dbg_level(char* val , char** err ) {
273 int lvl = strtol(val, &p, 10);
276 *err = g_strdup("not an integer");
278 } else if (lvl < 0 || lvl > 5) {
279 *err = g_strdup_printf("invalid level=%d (min=0 max=5)",lvl);
289 static param_t params[] = {
291 {"dbg_level", param_get_dbg_level, param_set_dbg_level},
293 {"cookie",param_get_cookie,param_set_cookie},
294 {"cwd",param_get_cwd,param_set_cwd},
298 static param_t* get_paramset(char* name) {
300 for (i = 0; params[i].name != NULL;i++) {
301 if (strcmp(name,params[i].name) == 0 ) return &(params[i]);
307 static gboolean child_set_filter(char* dflt, GString* err) { return FALSE; }
308 static gboolean child_start_capture(GString* msg, GString* err) { return FALSE; }
309 static gboolean child_stop_capture(GString* msg, GString* err) { return FALSE; }
310 static gboolean child_get_packets(GString* msg, GString* err) { return FALSE; }
311 static gboolean child_apply_filter(char* dflt, GString* err) { return FALSE; }
312 static gboolean child_add_note(int packet_num, char* note, GString* err) { return FALSE; }
315 static int child_receive(guint8* b, size_t len, guint16 chld_id, echld_msg_type_t type, guint16 reqh_id, void* data) {
316 GByteArray* ba = NULL;
318 child.chld_id = chld_id;
319 child.reqh_id = reqh_id;
321 CHILD_DBG((2,"Message Received type='%c' len='%d'",type,len));
323 // gettimeofday(&(child.now), NULL);
325 if (child.chld_id != chld_id) {
326 if (child.chld_id == 0) {
327 if ( type == ECHLD_NEW_CHILD) {
328 child.chld_id = chld_id;
329 // more init needed for sure
330 CHILD_DBG((1,"chld_id set, sending HELLO"));
331 CHILD_RESP(ba,ECHLD_HELLO);
334 child_err(ECHLD_ERR_WRONG_MSG,reqh_id,
335 "not yet initialized: chld_id:%d msg_type='%c'",chld_id,type);
340 child_err(ECHLD_ERR_WRONG_MSG,reqh_id,
341 "chld_id: own:%d given:%d msg_type='%c'",child.chld_id,chld_id,type);
348 CHILD_DBG((1,"PONG"));
349 CHILD_RESP(ba,ECHLD_PONG);
351 case ECHLD_SET_PARAM:{
354 if ( child.dec->set_param(b,len,¶m,&value) ) {
355 param_t* p = get_paramset(param);
358 child_err(ECHLD_CANNOT_SET_PARAM,reqh_id,"no such param='%s'",param);
362 if (! p->set(value,&err) ) {
363 child_err(ECHLD_CANNOT_SET_PARAM,reqh_id,"reason='%s'",err);
368 ba = (void*)child.enc->param(param,value);
369 CHILD_RESP(ba,ECHLD_PARAM);
370 g_byte_array_free(ba,TRUE);
371 CHILD_DBG((1,"Set Param: param='%s' value='%s'",param,value));
375 child_err(ECHLD_CANNOT_SET_PARAM,reqh_id,"reason='decoder error'");
379 case ECHLD_GET_PARAM: {
381 if ( child.dec->get_param(b,len,¶m) ) {
385 param_t* p = get_paramset(param);
388 child_err(ECHLD_CANNOT_GET_PARAM,reqh_id,"no such param='%s'",param);
391 if (!(val = p->get(&err))) {
392 child_err(ECHLD_CANNOT_GET_PARAM,reqh_id,"reason='%s'",err);
397 ba = (void*)child.enc->param(param,val);
398 CHILD_RESP(ba,ECHLD_PARAM);
399 g_byte_array_free(ba,TRUE);
400 CHILD_DBG((2,"Get Param: param='%s' value='%s'",param,val));
403 child_err(ECHLD_CANNOT_GET_PARAM,reqh_id,"reason='decoder error'");
407 case ECHLD_CLOSE_CHILD:
408 CHILD_RESP(ba,ECHLD_CLOSING);
409 CHILD_DBG((3,"Closing"));
411 // select(0,NULL,NULL,NULL,sleep_time);
412 CHILD_DBG((1,"Bye"));
415 case ECHLD_LIST_FILES:
416 if (child.state != IDLE) goto wrong_state;
417 CHILD_DBG((3,"Listing Files"));
420 case ECHLD_LIST_INTERFACES:
425 if (child.state != IDLE) goto wrong_state;
427 CHILD_DBG((1,"List Interfaces"));
429 if(( if_list = capture_interface_list(&err, &err_str) )) {
430 char* json_list = intflist2json(if_list);
432 ba = (void*)child.enc->intf_info(json_list);
434 CHILD_RESP(ba,ECHLD_INTERFACE_INFO);
435 g_byte_array_free(ba,TRUE);
436 CHILD_DBG((1,"List interfaces=%s",json_list));
439 /* XXX FREE if_list */
442 child_err(ECHLD_ERR_CANNOT_LIST_INTERFACES, reqh_id,
443 "reason='%s'", err_str);
448 case ECHLD_CHK_FILTER: // first candidate
449 case ECHLD_OPEN_INTERFACE:
450 case ECHLD_OPEN_FILE:
451 case ECHLD_START_CAPTURE:
452 case ECHLD_STOP_CAPTURE:
455 case ECHLD_GET_BUFFER:
457 case ECHLD_APPLY_FILTER:
458 case ECHLD_SAVE_FILE:
459 goto not_implemented;
461 child_err(ECHLD_ERR_WRONG_MSG,reqh_id,"chld_id=%d msg_type='%c'",chld_id,type);
468 // dump the misencoded message (b,blen)
469 child_err(ECHLD_ERR_WRONG_MSG,reqh_id,"misencoded msg msg_type='%c'",type);
473 child_err(ECHLD_ERR_WRONG_MSG,reqh_id,"unexpected message: received in wrong state='%c', msg_type='%c'",child.state,type);
477 child_err(ECHLD_ERR_UNIMPLEMENTED,reqh_id,"unimplemented message: received in wrong state='%c', msg_type='%c'",child.state,type);
482 static void child_dumpcap_read() {
483 // this folk manages the reading of dumpcap's pipe
484 // it has to read interface descriptions when doing so
485 // and managing capture during capture
486 CHILD_DBG((2,"child_dumpcap_read"));
489 static void child_read_file() {
490 // this folk manages the reading of the file after open file has opened it
491 CHILD_DBG((2,"child_read_file"));
495 int parent_fd = child.fds.pipe_to_parent;
503 CHILD_DBG((0,"child_loop()"));
509 struct timeval timeout;
510 struct dispatcher_child* c;
518 FD_SET(parent_fd,&rfds);
520 if (child.fds.pipe_from_dumpcap > 0) {
521 FD_SET(child.fds.pipe_from_dumpcap,&rfds);
524 if (child.fds.file_being_read > 0) {
525 FD_SET(child.fds.file_being_read,&rfds);
528 CHILD_DBG((4,"child_loop: before select() step=%d",step++));
529 nfds = select(nfds, &rfds, &wfds, &efds, &timeout);
530 CHILD_DBG((5,"child_loop: after select() step=%d",step++));
532 if ( FD_ISSET(parent_fd,&efds) ) {
533 CHILD_DBG((0,"Broken Parent Pipe step=%d",step++));
534 return BROKEN_PARENT_PIPE;
536 if (child.fds.pipe_from_dumpcap > 0 && FD_ISSET(child.fds.pipe_from_dumpcap,&efds) ) {
537 CHILD_DBG((0,"Broken Dumpcap Pipe step=%d",step++));
538 return BROKEN_DUMPCAP_PIPE;
540 if (child.fds.file_being_read > 0 && FD_ISSET(child.fds.file_being_read,&efds) ) {
541 CHILD_DBG((0,"Broken Readfile Pipe step=%d",step++));
542 return BROKEN_READFILE;
545 if (FD_ISSET(parent_fd, &rfds)) {
547 int st = echld_read_frame(&r, child_receive, &child);
550 CHILD_DBG((0,"Read Frame Failed step=%d",step++));
555 if (child.fds.pipe_from_dumpcap > 0 && FD_ISSET(child.fds.pipe_from_dumpcap,&rfds) ) {
556 child_dumpcap_read();
559 if (child.fds.file_being_read > 0 && FD_ISSET(child.fds.pipe_from_dumpcap,&rfds) ) {