diff options
author | Luis Ontanon <luis.ontanon@gmail.com> | 2013-06-28 21:10:52 +0000 |
---|---|---|
committer | Luis Ontanon <luis.ontanon@gmail.com> | 2013-06-28 21:10:52 +0000 |
commit | cf647de6a1aa54bfbe0be1c43726d065b436ccac (patch) | |
tree | bc0d0aa418cf9b43776e1c313c4ddd6e2e27bddd /echld | |
parent | 8ccfc17cf203f7f5d11f15af2ca43ef7fbbdbb14 (diff) |
MS: new child
MS: ping child
MS: set/get child parameter
svn path=/trunk/; revision=50218
Diffstat (limited to 'echld')
-rw-r--r-- | echld/child.c | 179 | ||||
-rw-r--r-- | echld/common.c | 83 | ||||
-rw-r--r-- | echld/dispatcher.c | 365 | ||||
-rw-r--r-- | echld/echld-int.h | 16 | ||||
-rw-r--r-- | echld/echld-util.h | 1 | ||||
-rw-r--r-- | echld/echld.h | 1 | ||||
-rw-r--r-- | echld/parent.c | 16 |
7 files changed, 395 insertions, 266 deletions
diff --git a/echld/child.c b/echld/child.c index 5b8e89021f..1823cd2c24 100644 --- a/echld/child.c +++ b/echld/child.c @@ -33,7 +33,7 @@ typedef struct _child { child_state_t state; int pid; - int ppid; + int dispatcher_pid; int chld_id; int reqh_id; echld_reader_t parent; @@ -56,36 +56,88 @@ typedef struct _child { static echld_child_t child; +struct _st_map { + child_state_t id; + const char* str; +}; -#define CHILD_RESP(BYTEARR,TYPE) echld_write_frame(child.fds.pipe_to_parent, BYTEARR, child.chld_id, TYPE, child.reqh_id, NULL) #ifdef DEBUG_CHILD -static int dbg_level = DEBUG_CHILD; +static int debug_lvl = DEBUG_CHILD; +static FILE* debug_fp = NULL; +#define DBG_BUF_LEN 1024 + +#define DCOM() -void child_debug(int level, const char* fmt, ...) { +int child_debug(int level, const char* fmt, ...) { va_list ap; - char* str; + char str[DBG_BUF_LEN]; - if (dbg_level<level) return; + if (debug_lvl<level) return 1; va_start(ap, fmt); - str = g_strdup_vprintf(fmt,ap); + vsnprintf(str,DBG_BUF_LEN,fmt,ap); va_end(ap); - fprintf(stderr, "child[%d]: reqh_id=%d dbg_level=%d message='%s'", child.pid, child.reqh_id, level, str); - g_free(str); + fprintf(debug_fp, "child[%d-%d]: reqh_id=%d debug_lvl=%d message='%s'\n", + child.chld_id, child.pid, child.reqh_id, level, str); + + return 1; +} + +static char* param_get_dbg_level(char** err _U_) { + return g_strdup_printf("%d",debug_lvl); +} + +static echld_bool_t param_set_dbg_level(char* val , char** err ) { + char* p; + int lvl = (int)strtol(val, &p, 10); + + if (p<=val) { + *err = g_strdup("not an integer"); + return FALSE; + } else if (lvl < 0 || lvl > 5) { + *err = g_strdup_printf("invalid level=%d (min=0 max=5)",lvl); + return FALSE; + } + + debug_lvl = lvl; + DCOM(); + return TRUE; +} + + +static long dbg_resp(GByteArray* em, echld_msg_type_t t) { + long st = echld_write_frame(child.fds.pipe_to_parent, em, child.chld_id, t, child.reqh_id, NULL); + child_debug(1, "SND fd=%d ch=%d ty='%c' rh=%d msg='%s'", + child.fds.pipe_to_parent, child.chld_id, t, child.reqh_id, (st>0?"ok":strerror(errno)) ); + return st; } #define CHILD_DBG(attrs) ( child_debug attrs ) +#define CHILD_DBG_INIT() do { debug_fp = stderr; DCOM(); } while(0) +#define CHILD_DBG_START(fname) do { debug_fp = fopen(fname,"a"); DCOM(); CHILD_DBG((0,"Log Started")); } while(0) +#define CHILD_RESP(BA,T) dbg_resp(BA,T) +#define CHILD_STATE(ST) do { DISP_DBG((0,"State %s => %s")) } while(0) #else #define CHILD_DBG(attrs) +#define CHILD_DBG_INIT() +#define CHILD_DBG_START(fname) +#define CHILD_RESP(BA,T) echld_write_frame(child.fds.pipe_to_parent,(BA),child.chld_id,T,child.reqh_id,NULL) #endif -void echld_child_initialize(int pipe_from_parent, int pipe_to_parent, int reqh_id) { + +static struct timeval close_sleep_time; + +void echld_child_initialize(echld_chld_id_t chld_id, int pipe_from_parent, int pipe_to_parent, int reqh_id) { + + close_sleep_time.tv_sec = CHILD_CLOSE_SLEEP_TIME / 1000000; + close_sleep_time.tv_usec = CHILD_CLOSE_SLEEP_TIME % 1000000; + + child.chld_id = chld_id; child.state = IDLE; child.pid = getpid(); - child.ppid = getppid(); - child.chld_id = 0; + child.dispatcher_pid = getppid(); child.reqh_id = reqh_id; echld_init_reader( &(child.parent), pipe_from_parent,4096); child.fds.pipe_to_parent = pipe_to_parent; @@ -93,12 +145,15 @@ void echld_child_initialize(int pipe_from_parent, int pipe_to_parent, int reqh_i child.fds.pipe_to_dumpcap = -1; child.fds.file_being_read = -1; gettimeofday(&child.started,NULL); - gettimeofday(&child.now,NULL); + child.now.tv_sec = child.started.tv_sec; + child.now.tv_usec = child.started.tv_usec; + echld_get_all_codecs(&(child.enc), &(child.dec), NULL, NULL); - /* epan stuff */ + CHILD_DBG_INIT(); + CHILD_DBG((5,"Child Initialized ch=%d from=%d to=%d rq=%d",chld_id, pipe_from_parent, pipe_to_parent, reqh_id)); - CHILD_DBG((5,"Child Initialized")); + /* epan stuff */ } @@ -253,28 +308,6 @@ static echld_bool_t param_set_cookie(char* val , char** err _U_) { return TRUE; } -#ifdef DEBUG_CHILD -static char* param_get_dbg_level(char** err _U_) { - return g_strdup_printf("%d",dbg_level); -} - -static echld_bool_t param_set_dbg_level(char* val , char** err ) { - char* p; - int lvl = (int)strtol(val, &p, 10); - - if (p<=val) { - *err = g_strdup("not an integer"); - return FALSE; - } else if (lvl < 0 || lvl > 5) { - *err = g_strdup_printf("invalid level=%d (min=0 max=5)",lvl); - return FALSE; - } - - dbg_level = lvl; - return TRUE; -} -#endif - static param_t params[] = { #ifdef DEBUG_CHILD @@ -294,14 +327,13 @@ static param_t* get_paramset(char* name) { } - 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_) { - GByteArray* ba = NULL; + GByteArray ba; + GByteArray* gba; - child.chld_id = chld_id; child.reqh_id = reqh_id; - CHILD_DBG((2,"Message Received type='%c' len='%d'",type,len)); + CHILD_DBG((2,"RCVD type='%s' len='%d'",TY(type),len)); // gettimeofday(&(child.now), NULL); @@ -311,7 +343,7 @@ static long child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_ child.chld_id = chld_id; // more init needed for sure CHILD_DBG((1,"chld_id set, sending HELLO")); - CHILD_RESP(ba,ECHLD_HELLO); + CHILD_RESP(NULL,ECHLD_HELLO); return 0; } else { child_err(ECHLD_ERR_WRONG_MSG,reqh_id, @@ -328,15 +360,19 @@ static long child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_ switch(type) { case ECHLD_PING: + ba.data = b; + ba.len = (guint)len; CHILD_DBG((1,"PONG")); - CHILD_RESP(ba,ECHLD_PONG); + CHILD_RESP(&ba,ECHLD_PONG); break; case ECHLD_SET_PARAM:{ char* param; char* value; + if ( child.dec->set_param && child.dec->set_param(b,len,¶m,&value) ) { param_t* p = get_paramset(param); char* err; + if (!p) { child_err(ECHLD_CANNOT_SET_PARAM,reqh_id,"no such param='%s'",param); break; @@ -353,9 +389,9 @@ static long child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_ break; } - ba = child.enc->param(param,value); - CHILD_RESP(ba,ECHLD_PARAM); - g_byte_array_free(ba,TRUE); + gba = child.enc->param(param,value); + CHILD_RESP(gba,ECHLD_PARAM); + g_byte_array_free(gba,TRUE); CHILD_DBG((1,"Set Param: param='%s' value='%s'",param,value)); break; @@ -387,9 +423,9 @@ static long child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_ break; } - ba = child.enc->param(param,val); - CHILD_RESP(ba,ECHLD_PARAM); - g_byte_array_free(ba,TRUE); + gba = child.enc->param(param,val); + CHILD_RESP(gba,ECHLD_PARAM); + g_byte_array_free(gba,TRUE); CHILD_DBG((2,"Get Param: param='%s' value='%s'",param,val)); break; } else { @@ -397,10 +433,9 @@ static long child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_ } } case ECHLD_CLOSE_CHILD: - CHILD_RESP(ba,ECHLD_CLOSING); + CHILD_RESP(NULL,ECHLD_CLOSING); CHILD_DBG((3,"Closing")); - - // select(0,NULL,NULL,NULL,sleep_time); + select(0,NULL,NULL,NULL,&close_sleep_time); CHILD_DBG((1,"Bye")); exit(0); break; @@ -459,61 +494,67 @@ static void child_read_file(void) { } int echld_child_loop(void) { - int parent_fd = child.fds.pipe_to_parent; + int disp_from = child.parent.fd; + int disp_to = child.fds.pipe_to_parent; #ifdef DEBUG_CHILD int step = 0; #endif - CHILD_DBG((0,"child_loop()")); + CHILD_DBG((0,"entering child_loop()")); do { fd_set rfds; fd_set wfds; fd_set efds; struct timeval timeout; - int nfds = 0; - + int nfds; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); - FD_SET(parent_fd,&rfds); + FD_SET(disp_from,&rfds); + FD_SET(disp_from,&efds); + FD_SET(disp_to,&efds); if (child.fds.pipe_from_dumpcap > 0) { FD_SET(child.fds.pipe_from_dumpcap,&rfds); - nfds++; } if (child.fds.file_being_read > 0) { FD_SET(child.fds.file_being_read,&rfds); - nfds++; } - CHILD_DBG((4,"child_loop: before select() step=%d",step++)); - nfds = select(nfds, &rfds, &wfds, &efds, &timeout); - CHILD_DBG((5,"child_loop: after select() step=%d",step++)); + CHILD_DBG((4,"child_loop: select()ing step=%d",step++)); + nfds = select(FD_SETSIZE, &rfds, &wfds, &efds, &timeout); + CHILD_DBG((4,"child_loop: select()ed nfds=%d",nfds)); + + if ( FD_ISSET(disp_from,&efds) ) { + CHILD_DBG((0,"Broken Parent Pipe 'From' step=%d",step)); + break; + } - if ( FD_ISSET(parent_fd,&efds) ) { - CHILD_DBG((0,"Broken Parent Pipe step=%d",step++)); + if ( FD_ISSET(disp_to,&efds) ) { + CHILD_DBG((0,"Broken Parent Pipe 'To' step=%d",step)); break; } + if (child.fds.pipe_from_dumpcap > 0 && FD_ISSET(child.fds.pipe_from_dumpcap,&efds) ) { - CHILD_DBG((0,"Broken Dumpcap Pipe step=%d",step++)); + CHILD_DBG((0,"Broken Dumpcap Pipe step=%d",step)); break; } + if (child.fds.file_being_read > 0 && FD_ISSET(child.fds.file_being_read,&efds) ) { - CHILD_DBG((0,"Broken Readfile Pipe step=%d",step++)); + CHILD_DBG((0,"Broken Readfile Pipe step=%d",step)); break; } - if (FD_ISSET(parent_fd, &rfds)) { - + if (FD_ISSET(disp_from, &rfds)) { long st = echld_read_frame(&(child.parent), child_receive, &child); if (st < 0) { - CHILD_DBG((0,"Read Frame Failed step=%d",step++)); + CHILD_DBG((0,"Read Frame Failed step=%d",step)); return (int)st; } } diff --git a/echld/common.c b/echld/common.c index 548fd8127b..20fbe874fc 100644 --- a/echld/common.c +++ b/echld/common.c @@ -59,6 +59,89 @@ extern void echld_common_set_dbg(int level, FILE* fp, const char* prefix) { #endif +struct _st_map +{ + child_state_t id; + const char* str; +}; + +static struct _st_map st_map[] = { + { FREE, "FREE"}, + { CREATING, "CREATING"}, + { IDLE, "IDLE"}, + { READY, "READY"}, + { READING, "READING"}, + { CAPTURING, "CAPTURING"}, + { DONE, "DONE"}, + { CLOSED, "CLOSED"}, + { ERRORED, "ERRORED"}, + {0,NULL} +}; + +const char* echld_state_str(child_state_t id) { + int i = 0; + + for (;st_map[i].str;i++) { + if (id == st_map[i].id) return st_map[i].str; + } + + return "UNKNOWN"; +} + + +struct _t_map +{ + echld_msg_type_t type; + const char* str; +}; + +static struct _t_map t_map[] = { + {ECHLD_ERROR,"ERROR"}, + {ECHLD_TIMED_OUT,"TIMED_OUT"}, + {ECHLD_NEW_CHILD,"NEW_CHILD"}, + {ECHLD_HELLO,"HELLO"}, + {ECHLD_CHILD_DEAD,"CHILD_DEAD"}, + {ECHLD_CLOSE_CHILD,"CLOSE_CHILD"}, + {ECHLD_CLOSING,"CLOSING"}, + {ECHLD_SET_PARAM,"SET_PARAM"}, + {ECHLD_GET_PARAM,"GET_PARAM"}, + {ECHLD_PARAM,"PARAM"}, + {ECHLD_PING,"PING"}, + {ECHLD_PONG,"PONG"}, + {ECHLD_OPEN_FILE,"OPEN_FILE"}, + {ECHLD_FILE_OPENED,"FILE_OPENED"}, + {ECHLD_OPEN_INTERFACE,"OPEN_INTERFACE"}, + {ECHLD_INTERFACE_OPENED,"INTERFACE_OPENED"}, + {ECHLD_START_CAPTURE,"START_CAPTURE"}, + {ECHLD_CAPTURE_STARTED,"CAPTURE_STARTED"}, + {ECHLD_NOTIFY,"NOTIFY"}, + {ECHLD_GET_SUM,"GET_SUM"}, + {ECHLD_PACKET_SUM,"PACKET_SUM"}, + {ECHLD_GET_TREE,"GET_TREE"}, + {ECHLD_TREE,"TREE"}, + {ECHLD_GET_BUFFER,"GET_BUFFER"}, + {ECHLD_BUFFER,"BUFFER"}, + {ECHLD_EOF,"EOF"}, + {ECHLD_STOP_CAPTURE,"STOP_CAPTURE"}, + {ECHLD_CAPTURE_STOPPED,"CAPTURE_STOPPED"}, + {ECHLD_ADD_NOTE,"ADD_NOTE"}, + {ECHLD_NOTE_ADDED,"NOTE_ADDED"}, + {ECHLD_APPLY_FILTER,"APPLY_FILTER"}, + {ECHLD_PACKET_LIST,"PACKET_LIST"}, + {ECHLD_SAVE_FILE,"SAVE_FILE"}, + {ECHLD_FILE_SAVED,"FILE_SAVED"}, + {0,NULL} +}; + +const char* echld_msg_type_str(echld_msg_type_t id) { + int i = 0; + + for (;t_map[i].str;i++) { + if (id == t_map[i].type) return t_map[i].str; + } + + return "UNKNOWN"; +} /** diff --git a/echld/dispatcher.c b/echld/dispatcher.c index d139c6ac6d..6357c2d49e 100644 --- a/echld/dispatcher.c +++ b/echld/dispatcher.c @@ -68,7 +68,7 @@ struct dispatcher* dispatcher; static int debug_lvl = DEBUG_DISPATCHER; static FILE* debug_fp = NULL; -#define DCOM() echld_common_set_dbg(debug_lvl,debug_fp,"Disp") +#define DCOM() /*echld_common_set_dbg(debug_lvl,debug_fp,"Disp")*/ int dispatcher_debug(int level, const char* fmt, ...) { va_list ap; @@ -120,23 +120,38 @@ static long dbg_r = 0; #define DISP_DBG(attrs) ( dispatcher_debug attrs ) #define DISP_DBG_INIT() do { debug_fp = stderr; DCOM(); } while(0) #define DISP_DBG_START(fname) do { debug_fp = fopen(fname,"a"); DCOM(); DISP_DBG((0,"Log Started")); } while(0) -#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='%c' rh=%d msg='%s'",FD,CH,T,RH, (dbg_r>0?"ok":strerror(errno)))), dbg_r ) +#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 ) +#define CHLD_SET_STATE(c,st) DISP_DBG((1,"Child[%d] State %s => %s",(c)->chld_id,ST((c)->state),ST((c)->state=(st)) )) #else #define DISP_DBG(attrs) #define DISP_DBG_INIT() #define DISP_DBG_START(fname) #define DISP_WRITE(FD,BA,CH,T,RH) echld_write_frame(FD,BA,CH,T,RH,NULL) +#define CHLD_SET_STATE(c,st) ((c)->state=(st)) #endif #define DISP_RESP(B,T) (DISP_WRITE( dispatcher->parent_out, (B), 0, (T), dispatcher->reqh_id)) + +static void children_massacre(void) { + int i; + struct dispatcher_child* cc = dispatcher->children; + int max_children = dispatcher->max_children; + + for(i = 0; i < max_children; i++) { + struct dispatcher_child* c = &(cc[i]); + if (c->pid > 0) { + DISP_DBG((0,"killing ch=%d pid=%d",c->chld_id,c->pid)); + kill(c->pid,SIGTERM); + } + } +} + + static void dispatcher_fatal(int cause, const char* fmt, ...) { size_t len= 1024; gchar err_str[len]; va_list ap; - int i; - struct dispatcher_child* cc = dispatcher->children; - int max_children = dispatcher->max_children; va_start(ap, fmt); g_vsnprintf(err_str,len,fmt,ap); @@ -144,11 +159,7 @@ static void dispatcher_fatal(int cause, const char* fmt, ...) { DISP_DBG((0,"fatal cause=%d msg=\"%s\"",cause ,err_str)); - /* the massacre */ - for(i = 0; i < max_children; i++) { - struct dispatcher_child* c = &(cc[i]); - if (c->chld_id > 0) kill(c->pid,SIGTERM); - } + children_massacre(); exit(cause); } @@ -186,14 +197,14 @@ static char* intflist2json(GList* if_list) { GSList *addr; if_addr_t *if_addr; char addr_str[ADDRSTRLEN]; - GString *str = g_string_new("={ "); + GString *str = g_string_new("{ what='interfaces', interfaces={ \n"); char* s; i = 1; /* Interface id number */ for (if_entry = g_list_first(if_list); if_entry != NULL; if_entry = g_list_next(if_entry)) { if_info = (if_info_t *)if_entry->data; - g_string_append_printf(str,"%d={ intf='%s',", i++, if_info->name); + g_string_append_printf(str," %s={ intf='%s',", if_info->name, if_info->name); /* * Print the contents of the if_entry struct in a parseable format. @@ -216,25 +227,27 @@ static char* intflist2json(GList* if_list) { case IF_AT_IPv4: if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str, ADDRSTRLEN)) { - g_string_append_printf(str,"%s", addr_str); + g_string_append_printf(str,"'%s',", addr_str); } else { - g_string_append(str,"<unknown IPv4>"); + g_string_append(str,"'<unknown IPv4>',"); } break; case IF_AT_IPv6: if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr, addr_str, ADDRSTRLEN)) { - g_string_append_printf(str,"%s", addr_str); + g_string_append_printf(str,"'%s',", addr_str); } else { - g_string_append(str,"<unknown IPv6>"); + g_string_append(str,"'<unknown IPv6>',"); } break; default: - g_string_append_printf(str,"<type unknown %u>", if_addr->ifat_type); + g_string_append_printf(str,"'<type unknown %u>',", if_addr->ifat_type); } + } - g_string_append(str," ]"); /* addrs */ + g_string_truncate(str,str->len - 1); /* the last comma or space (on empty list) */ + g_string_append(str," ],"); /* addrs */ if (if_info->loopback) @@ -242,10 +255,10 @@ static char* intflist2json(GList* if_list) { else g_string_append(str,", loopback=0"); - g_string_append(str,"}, "); + g_string_append(str,"},\n"); } - g_string_truncate(str,str->len - 2); /* the comma and space */ + g_string_truncate(str,str->len - 2); /* the comma and return */ g_string_append(str,"}"); s=str->str; @@ -259,6 +272,11 @@ static char* param_get_interfaces(char** err) { char* s; *err = NULL; + if (dispatcher->dumpcap_pid) { + *err = g_strdup_printf("Dumpcap already running"); + return NULL; + } + if_list = capture_interface_list(&err_no, err, NULL); if (*err) { @@ -275,7 +293,7 @@ static char* param_get_interfaces(char** err) { static struct timeval disp_loop_timeout; static char* param_get_loop_to(char** err _U_) { - return g_strdup_printf("%d.%6ds",(int)disp_loop_timeout.tv_sec, (int)disp_loop_timeout.tv_usec ); + return g_strdup_printf("%d.%06ds",(int)disp_loop_timeout.tv_sec, (int)disp_loop_timeout.tv_usec ); } static echld_bool_t param_set_loop_to(char* val , char** err ) { @@ -311,7 +329,8 @@ static param_t* get_paramset(char* name) { } -static struct dispatcher_child* dispatcher_get_child(struct dispatcher* d, guint16 chld_id) { + +static struct dispatcher_child* dispatcher_get_child(struct dispatcher* d, int chld_id) { int i; struct dispatcher_child* cc = d->children; int max_children = d->max_children; @@ -326,12 +345,13 @@ static struct dispatcher_child* dispatcher_get_child(struct dispatcher* d, guint static void dispatcher_clear_child(struct dispatcher_child* c) { - DISP_DBG((5,"dispatcher_clear_child chld_id=%d",c->chld_id)); echld_reset_reader(&(c->reader), -1, 4096); - c->chld_id = 0; - c->write_fd = 0; - c->pid = 0; - c->closing = 0; + c->chld_id = -1; + c->state = FREE; + c->reader.fd = -1; + c->write_fd = -1; + c->pid = -1; + c->closing = FALSE; } static void set_dumpcap_pid(int pid) { @@ -356,7 +376,7 @@ static void preinit_epan(char* argv0, int (*main)(int, char **)) { static void dispatcher_clear(void) { - DISP_DBG((2,"Child chld_id=%d ->CAPTURING")); + DISP_DBG((2,"dispatcher_clear")); /* remove unnecessary stuff for the working child */ } @@ -415,6 +435,7 @@ void dispatcher_reaper(int sig) { if (s) g_free(s); } + CHLD_SET_STATE(c,CLOSED); DISP_WRITE(dispatcher->parent_out, em, c->chld_id, ECHLD_CHILD_DEAD, 0); dispatcher_clear_child(c); g_byte_array_free(em,TRUE); @@ -426,33 +447,21 @@ void dispatcher_reaper(int sig) { if (pid == dispatcher->dumpcap_pid) { dispatcher->dumpcap_pid = 0; dispatcher->reqh_id = reqh_id_save; + DISP_DBG((2,"dumpcap dead pid=%d",pid)); return; } dispatcher_err(ECHLD_ERR_UNKNOWN_PID, "Unkown child pid: %d", pid); dispatcher->reqh_id = reqh_id_save; - } - static void dispatcher_destroy(void) { - int i; - int max_children = dispatcher->max_children; - struct dispatcher_child* cc = dispatcher->children; /* destroy the dispatcher stuff at closing */ dispatcher->closing = TRUE; - /* kill all alive children */ - for(i = 0; i < max_children; i++) { - struct dispatcher_child* c = &(cc[i]); - if ( c->chld_id ) { - kill(c->pid,SIGTERM); - DISP_DBG((1,"Killing chld_id=%d pid=%d")); - continue; - } - } + children_massacre(); exit(0); } @@ -477,51 +486,34 @@ static long dispatch_to_parent(guint8* b, size_t len, echld_chld_id_t chld_id, e switch(type) { case ECHLD_ERROR: break; case ECHLD_TIMED_OUT: break; - case ECHLD_HELLO: - c->state = IDLE; - DISP_DBG((2,"Child chld_id=%d ->IDLE",c->chld_id)); - break; - case ECHLD_CLOSING: - c->closing = TRUE; - c->state = CLOSED; - DISP_DBG((2,"Child chld_id=%d ->CLOSED",c->chld_id)); - break; + case ECHLD_HELLO: CHLD_SET_STATE(c,IDLE); break; + case ECHLD_CLOSING: CHLD_SET_STATE(c,CLOSED); break; case ECHLD_PARAM: break; case ECHLD_PONG: break; - case ECHLD_FILE_OPENED: - c->state = READING; - DISP_DBG((2,"Child chld_id=%d ->READING",c->chld_id)); - break; - case ECHLD_INTERFACE_OPENED: - c->state = READY; - DISP_DBG((2,"Child chld_id=%d ->READY",c->chld_id)); - break; - case ECHLD_CAPTURE_STARTED: - c->state = CAPTURING; - DISP_DBG((2,"Child chld_id=%d ->CAPTURING",c->chld_id)); - break; - case ECHLD_NOTIFY: break; // notify(pre-encoded) - case ECHLD_PACKET_SUM: break; // packet_sum(pre-encoded) - case ECHLD_TREE: break; //tree(framenum, tree(pre-encoded) ) - case ECHLD_BUFFER: break; // buffer (name,range,totlen,data) + case ECHLD_FILE_OPENED: CHLD_SET_STATE(c,READING); break; + case ECHLD_INTERFACE_OPENED: CHLD_SET_STATE(c,READY); break; + case ECHLD_CAPTURE_STARTED: CHLD_SET_STATE(c,CAPTURING); break; + case ECHLD_NOTIFY: break; + case ECHLD_PACKET_SUM: break; + case ECHLD_TREE: break; + case ECHLD_BUFFER: break; + case ECHLD_EOF: - case ECHLD_CAPTURE_STOPPED: - c->state = DONE; - DISP_DBG((2,"Child chld_id=%d ->DONE",c->chld_id)); - break; + case ECHLD_CAPTURE_STOPPED: CHLD_SET_STATE(c,DONE); break; + case ECHLD_NOTE_ADDED: break; - case ECHLD_PACKET_LIST: break; // packet_list(name,filter,range); + case ECHLD_PACKET_LIST: break; case ECHLD_FILE_SAVED: break; default: goto misbehabing; } - DISP_DBG((4,"Dispatching to child reqh_id=%d chld_id=%d type='%c'",reqh_id,c->chld_id,type)); + DISP_DBG((4,"Dispatching to parent reqh_id=%d chld_id=%d type='%c'",reqh_id,c->chld_id,type)); return DISP_WRITE(dispatcher->parent_out, &in_ba, chld_id, type, reqh_id); misbehabing: - c->state = ERRORED; + CHLD_SET_STATE(c,ERRORED); c->closing = TRUE; kill(c->pid,SIGTERM); dispatcher_err(ECHLD_ERR_CRASHED_CHILD,"chld_id=%d",chld_id); @@ -529,65 +521,64 @@ misbehabing: } -void dispatch_new_child(struct dispatcher* dd) { - struct dispatcher_child* c = dispatcher_get_child(dd, 0); - int reqh_id = dd->reqh_id; +static struct timeval start_wait_time; +static long start_wait_time_us = CHILD_START_WAIT_TIME; + +static void detach_new_child(enc_msg_t* em, echld_chld_id_t chld_id) { + struct dispatcher_child* c; + int reqh_id = dispatcher->reqh_id; int pid; - if ( c ) { - int parent_pipe_fds[2]; + if (( c = dispatcher_get_child(dispatcher, chld_id) )) { + dispatcher_err(ECHLD_ERR_CHILD_EXISTS,"chld_id=%d exists already while creating new child",chld_id); + return; + } else if (( c = dispatcher_get_child(dispatcher, -1) )) { + int disp_pipe_fds[2]; int child_pipe_fds[2]; - int pipe_to_parent; - int pipe_from_parent; + int pipe_to_disp; + int pipe_from_disp; int pipe_to_child; int pipe_from_child; - DISP_DBG((5,"new_child pipe(parent)")); - if( pipe(parent_pipe_fds) < 0) { + DISP_DBG((5,"new_child pipe(dispatcher)")); + if( pipe(disp_pipe_fds) < 0) { dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN PARENT PIPE: %s",strerror(errno)); return; } - pipe_from_parent = parent_pipe_fds[0]; - pipe_to_child = parent_pipe_fds[1]; + pipe_from_disp = disp_pipe_fds[0]; + pipe_to_child = disp_pipe_fds[1]; DISP_DBG((5,"new_child pipe(child)")); if( pipe(child_pipe_fds) < 0) { - close(pipe_from_parent); + close(pipe_from_disp); close(pipe_to_child); dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT OPEN CHILD PIPE: %s",strerror(errno)); return; } pipe_from_child = child_pipe_fds[0]; - pipe_to_parent = child_pipe_fds[1]; + pipe_to_disp = child_pipe_fds[1]; DISP_DBG((4,"New Child Forking()")); switch (( pid = fork() )) { case -1: { close(pipe_to_child); - close(pipe_to_parent); + close(pipe_to_disp); close(pipe_from_child); - close(pipe_from_parent); + close(pipe_from_disp); dispatcher_err(ECHLD_ERR_CANNOT_FORK,"CANNOT FORK: %s",strerror(errno)); return; } - case 0: { /* I'm the child */ - int i; - int fdt_len = getdtablesize(); - + case 0: { + /* I'm the child */ dispatcher_clear(); - for(i=0;i<fdt_len;i++) { - if ( i != pipe_from_parent - && i != pipe_to_parent - && i != STDERR_FILENO ) { - close(i); - } - } + close(pipe_to_child); + close(pipe_from_child); - echld_child_initialize(pipe_from_parent,pipe_to_parent,reqh_id); + echld_child_initialize(chld_id, pipe_from_disp,pipe_to_disp,reqh_id); exit( echld_child_loop() ); @@ -595,25 +586,28 @@ void dispatch_new_child(struct dispatcher* dd) { return; } default: { - /* I'm the parent */ - guint8 buf[4]; - GByteArray out_ba; + /* I'm the parent */ - out_ba.data = buf; - out_ba.len = 0; - - close(pipe_to_parent); - close(pipe_from_parent); + close(pipe_to_disp); + close(pipe_from_disp); echld_reset_reader(&(c->reader), pipe_from_child,4096); c->write_fd = pipe_to_child; c->pid = pid; - c->chld_id = dispatcher->nchildren++; + c->chld_id = chld_id; + c->state = CREATING; + c->closing = FALSE; + + DISP_DBG((4,"Child Forked pid=%d chld_id=%d from_fd=%d to_fd=%d", + pid, c->chld_id, pipe_from_child, pipe_to_child)); - DISP_DBG((4,"Child Forked pid=%d chld_id=%d",pid,c->chld_id)); + start_wait_time.tv_sec = (int)(start_wait_time_us / 1000000); + start_wait_time.tv_usec = (int)(start_wait_time_us % 1000000); + + select(0,NULL,NULL,NULL,&start_wait_time); /* configure child */ - DISP_WRITE(pipe_to_child, &out_ba, c->chld_id, ECHLD_NEW_CHILD, dispatcher->reqh_id); + DISP_WRITE(pipe_to_child, em, c->chld_id, ECHLD_NEW_CHILD, dispatcher->reqh_id); return; } } @@ -625,29 +619,30 @@ void dispatch_new_child(struct dispatcher* dd) { /* process signals sent from parent */ -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) { - struct dispatcher* disp = (struct dispatcher*)data; +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_) { + GByteArray in_ba; - disp->reqh_id = reqh_id; + in_ba.data = b; + in_ba.len = (guint)len; + dispatcher->reqh_id = reqh_id; - if (chld_id == 0) { /* these are messages to the dispatcher itself */ - DISP_DBG((2,"Parent => Dispatcher")); + DISP_DBG((1,"RCV<- type='%s' chld_id=%d reqh_id=%d",TY(type),chld_id,reqh_id)); + + if (chld_id == 0) { /* these are messages sent to the dispatcher itself */ + DISP_DBG((2,"Message to Dispatcher")); switch(type) { case ECHLD_CLOSE_CHILD: dispatcher_destroy(); return 0; case ECHLD_PING: DISP_DBG((2,"PONG reqh_id=%d",reqh_id)); - DISP_WRITE(disp->parent_out, NULL, chld_id, ECHLD_PONG, reqh_id); - return 0; - case ECHLD_NEW_CHILD: - dispatch_new_child(disp); + DISP_WRITE(dispatcher->parent_out, NULL, chld_id, ECHLD_PONG, reqh_id); return 0; case ECHLD_SET_PARAM:{ char* param; char* value; - if ( disp->dec.from_parent->set_param(b,len,¶m,&value) ) { + if ( dispatcher->dec.from_parent->set_param(b,len,¶m,&value) ) { GByteArray* ba; param_t* p = get_paramset(param); char* err; @@ -667,7 +662,7 @@ static long dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, ec return 0; } - ba = disp->enc.to_parent->param(param,value); + ba = dispatcher->enc.to_parent->param(param,value); DISP_RESP(ba,ECHLD_PARAM); g_byte_array_free(ba,TRUE); DISP_DBG((1,"Set Param: param='%s' value='%s'",param,value)); @@ -681,7 +676,7 @@ static long dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, ec case ECHLD_GET_PARAM: { GByteArray* ba; char* param; - if ( disp->dec.from_parent->get_param(b,len,¶m) ) { + if ( dispatcher->dec.from_parent->get_param(b,len,¶m) ) { char* err; char* val; @@ -703,10 +698,10 @@ static long dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, ec return 0; } - ba = disp->enc.to_parent->param(param,val); + ba = dispatcher->enc.to_parent->param(param,val); DISP_RESP(ba,ECHLD_PARAM); g_byte_array_free(ba,TRUE); - DISP_DBG((2,"Get Param: param='%s' value='%s'",param,val)); + DISP_DBG((1,"Get Param: param='%s' value='%s'",param,val)); return 0; } else { dispatcher_err(ECHLD_CANNOT_GET_PARAM,"reason='decoder error'"); @@ -723,58 +718,52 @@ static long dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, ec DISP_DBG((2,"Parent => Child")); if (! (c = dispatcher_get_child(dispatcher, chld_id)) ) { - dispatcher_err(ECHLD_ERR_NO_SUCH_CHILD, "wrong chld_id %d", chld_id); - return 0; - } - - switch(type) { - case ECHLD_CLOSE_CHILD: - c->closing = TRUE; - c->state = CLOSED; - DISP_DBG((2,"Child chld_id=%d ->CLOSED",chld_id)); - goto relay_frame; - - case ECHLD_OPEN_FILE: - c->state = READING; - DISP_DBG((2,"Child chld_id=%d ->READING",chld_id)); - goto relay_frame; - - case ECHLD_OPEN_INTERFACE: - c->state = READY; - DISP_DBG((2,"Child chld_id=%d ->READY",chld_id)); - goto relay_frame; - - case ECHLD_START_CAPTURE: - DISP_DBG((2,"Child chld_id=%d ->CAPTURING",chld_id)); - c->state = CAPTURING; - goto relay_frame; - - case ECHLD_STOP_CAPTURE: - DISP_DBG((2,"Child chld_id=%d ->DONE",chld_id)); - c->state = DONE; - goto relay_frame; - - case ECHLD_SAVE_FILE: - case ECHLD_APPLY_FILTER: - case ECHLD_SET_PARAM: - case ECHLD_GET_PARAM: - case ECHLD_PING: - case ECHLD_GET_SUM: - case ECHLD_GET_TREE: - case ECHLD_GET_BUFFER: - case ECHLD_ADD_NOTE: - relay_frame: { - GByteArray in_ba; - - in_ba.data = b; - in_ba.len = (guint)len; - - DISP_DBG((3,"Relay to Child chld_id=%d type='%c' req_id=%d",chld_id, type, reqh_id)); - return DISP_WRITE(c->write_fd, &in_ba, chld_id, type, reqh_id); - } - default: - dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message %d %c", reqh_id, type); + if (type == ECHLD_NEW_CHILD) { + detach_new_child(&in_ba,chld_id); + return 0; + } else { + dispatcher_err(ECHLD_ERR_NO_SUCH_CHILD, "wrong chld_id %d", chld_id); return 0; + } + } else { + switch(type) { + case ECHLD_CLOSE_CHILD: + CHLD_SET_STATE(c,CLOSED); + goto relay_frame; + + case ECHLD_OPEN_FILE: + CHLD_SET_STATE(c,READING); + goto relay_frame; + + case ECHLD_OPEN_INTERFACE: + CHLD_SET_STATE(c,READY); + goto relay_frame; + + case ECHLD_START_CAPTURE: + CHLD_SET_STATE(c,CAPTURING); + goto relay_frame; + + case ECHLD_STOP_CAPTURE: + CHLD_SET_STATE(c,DONE); + goto relay_frame; + + case ECHLD_SAVE_FILE: + case ECHLD_APPLY_FILTER: + case ECHLD_SET_PARAM: + case ECHLD_GET_PARAM: + case ECHLD_PING: + case ECHLD_GET_SUM: + case ECHLD_GET_TREE: + case ECHLD_GET_BUFFER: + case ECHLD_ADD_NOTE: + relay_frame: { + DISP_DBG((3,"Relay to Child chld_id=%d type='%c' req_id=%d",chld_id, type, reqh_id)); + return DISP_WRITE(c->write_fd, &in_ba, chld_id, type, reqh_id); + } + default: + dispatcher_err(ECHLD_ERR_WRONG_MSG, "wrong message %d %c", reqh_id, type); + return 0; + } } } } @@ -844,12 +833,18 @@ int dispatcher_loop(void) { for (c=children; c->pid; c++) { - if (c->chld_id) { - // if ( FD_ISSET(c->reader.fd,&efds) ) { - // DISP_DBG((1,"errored child pipe chld_id=%d",c->chld_id)); - // dispatcher_clear_child(c); - // continue; - // } + if (c->reader.fd > 0) { + if ( FD_ISSET(c->reader.fd,&efds) ) { + struct timeval wait_time; + wait_time.tv_sec = 0; + wait_time.tv_usec = DISP_KILLED_CHILD_WAIT; + + DISP_DBG((1,"errored child pipe chld_id=%d",c->chld_id)); + kill(c->pid,SIGTERM); + select(0,NULL,NULL,NULL,&wait_time); + dispatcher_clear_child(c); + continue; + } if (FD_ISSET(c->reader.fd,&rfds)) { long st = echld_read_frame(&(c->reader), dispatch_to_parent, c); @@ -872,6 +867,7 @@ int dispatcher_loop(void) { void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* argv0, int (*main)(int, char **)) { static struct dispatcher d; + int i; #ifdef DEBUG_DISPATCHER int dbg_fd; #endif @@ -880,7 +876,6 @@ void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* argv0, in disp_loop_timeout.tv_usec = DISPATCHER_WAIT_INITIAL; DISP_DBG_INIT(); - DISP_DBG_START("dispatcher.debug"); #ifdef DEBUG_DISPATCHER dbg_fd = fileno(debug_fp); #endif @@ -906,6 +901,8 @@ void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* argv0, in d.pid = getpid(); d.dumpcap_pid = 0; + for (i=0;i<ECHLD_MAX_CHILDREN;i++) dispatcher_clear_child(&(d.children[i])); + close(out_pipe_fds[0]); close(in_pipe_fds[1]); diff --git a/echld/echld-int.h b/echld/echld-int.h index bb530fc960..5cdbef2a3a 100644 --- a/echld/echld-int.h +++ b/echld/echld-int.h @@ -108,6 +108,10 @@ typedef enum _cst { ERRORED=-2 } child_state_t; +extern const char* echld_state_str(child_state_t); +extern const char* echld_msg_type_str(echld_msg_type_t id); +#define ST(st) echld_state_str(st) +#define TY(ty) echld_msg_type_str(ty) /* these manage the de-framing machine in the receiver side */ typedef struct _echld_reader { @@ -191,7 +195,7 @@ extern long echld_read_frame(echld_reader_t* r, read_cb_t cb, void* cb_data); extern long echld_write_frame(int fd, GByteArray* ba, guint16 chld_id, echld_msg_type_t type, guint16 reqh_id, void* data); -extern void echld_child_initialize(int pipe_from_parent, int pipe_to_parent, int reqh_id); +extern void echld_child_initialize(echld_chld_id_t chld_id, int pipe_from_parent, int pipe_to_parent, int reqh_id); extern int echld_child_loop(void); /* never returns*/ @@ -201,16 +205,20 @@ extern void echld_dispatcher_start(int* in_pipe_fds, int* out_pipe_fds, char* ar extern void dummy_switch(echld_msg_type_t type); extern void echld_unused(void); -/* initial debug levels */ +/* config stuff */ +/* initial debug levels */ +/* undefine to avoid debugging */ #define DEBUG_BASE 5 #define DEBUG_CHILD 5 #define DEBUG_DISPATCHER 5 #define DEBUG_PARENT 5 -/* config stuff */ +/* timers */ #define DISPATCHER_WAIT_INITIAL 999999 /* almost 1s */ - +#define CHILD_CLOSE_SLEEP_TIME 2000000 /* 2s */ +#define CHILD_START_WAIT_TIME 100000 /* 0.1s */ +#define DISP_KILLED_CHILD_WAIT 100000 /* 0.1s */ /* fatalities */ #define BROKEN_PARENT_PIPE 123 diff --git a/echld/echld-util.h b/echld/echld-util.h index 4c236b5854..a1a625d570 100644 --- a/echld/echld-util.h +++ b/echld/echld-util.h @@ -41,6 +41,7 @@ typedef void (*echild_get_packet_summary_cb_t)(char* summary, void* data); WS_DLL_PUBLIC echld_state_t echld_open_file(int child_id, const char* filename,echild_get_packet_summary_cb_t,void*); + WS_DLL_PUBLIC echld_state_t echld_open_interface(int child_id, const char* intf_name, const char* params); WS_DLL_PUBLIC echld_state_t echld_start_capture(int child_id, echild_get_packet_summary_cb_t); WS_DLL_PUBLIC echld_state_t echld_stop_capture(int child_id); diff --git a/echld/echld.h b/echld/echld.h index c757760992..23c8f24f7c 100644 --- a/echld/echld.h +++ b/echld/echld.h @@ -366,6 +366,7 @@ enum _echld_error { ECHLD_ERR_UNIMPLEMENTED, ECHLD_ERR_WRONG_MSG, ECHLD_ERR_NO_SUCH_CHILD, + ECHLD_ERR_CHILD_EXISTS, ECHLD_ERR_UNKNOWN_PID, ECHLD_ERR_CANNOT_FORK, ECHLD_ERR_SET_FILTER, diff --git a/echld/parent.c b/echld/parent.c index 6496e4f6e8..6c518907dd 100644 --- a/echld/parent.c +++ b/echld/parent.c @@ -90,7 +90,7 @@ static void parent_dbg(int level, const char* fmt, ...) { } #define PARENT_DBG(attrs) parent_dbg attrs -#define PARENT_SEND(BYTEARR,CHILDNUM,TYPE,R_ID) do { long st = echld_write_frame(parent.dispatcher_fd, BYTEARR, CHILDNUM, TYPE, R_ID, NULL); PARENT_DBG((1,"SEND type='%c' chld_id=%d reqh_id=%d msg='%s'",TYPE,CHILDNUM,R_ID, ( st >= 8 ? "ok" : ((st<0)?strerror(errno):"?") ) )); } while(0) +#define PARENT_SEND(BYTEARR,CHILDNUM,TYPE,R_ID) do { long st = echld_write_frame(parent.dispatcher_fd, BYTEARR, CHILDNUM, TYPE, R_ID, NULL); PARENT_DBG((1,"SEND type='%s' chld_id=%d reqh_id=%d err_msg='%s'",TY(TYPE),CHILDNUM,R_ID, ( st >= 8 ? "ok" : ((st<0)?strerror(errno):"?") ) )); } while(0) #else #define PARENT_DBG(attrs) @@ -221,7 +221,7 @@ void echld_initialize(echld_encoding_t enc, char* argv0, int (*main)(int, char * reader_realloc_buf = parent_realloc_buff; #endif - echld_common_set_dbg(9,stderr,"parent"); + /* echld_common_set_dbg(9,stderr,"parent"); */ PARENT_DBG((3,"Dispatcher forked")); @@ -323,7 +323,7 @@ static echld_state_t reqh_snd(echld_t* c, echld_msg_type_t t, GByteArray* ba, ec PARENT_DBG((4,"reqh_add: idx='%d'",idx)); - PARENT_DBG((1,"REQH_SND: type='%c' chld_id=%d reqh_id=%d",t, c->chld_id,reqh_id)); + PARENT_DBG((3,"REQH_SND: type='%s' chld_id=%d reqh_id=%d",TY(t), c->chld_id,reqh_id)); PARENT_SEND(ba,c->chld_id,t,reqh_id); @@ -466,16 +466,16 @@ int chld_cmp(const void *a, const void *b) { static int msgh_attach(echld_t* c, echld_msg_type_t t, echld_msg_cb_t resp_cb, void* cb_data); +static int next_chld_id = 1; + extern int echld_new(void* child_data) { - int next_chld_id = 1; echld_t* c = get_child(-1); if (!c) return -1; - c->chld_id = next_chld_id++; + c->chld_id = (next_chld_id++); c->data = child_data; c->state = CREATING; - c->handlers = g_array_new(TRUE,TRUE,sizeof(hdlr_t)); g_byte_array_set_size(parent.snd,0); @@ -484,8 +484,6 @@ extern int echld_new(void* child_data) { msgh_attach(c,ECHLD_CHILD_DEAD, parent_dead_child , c); reqh_snd(c, ECHLD_NEW_CHILD, parent.snd, parent_get_hello, c); - qsort(parent.children,ECHLD_MAX_CHILDREN,sizeof(echld_t),chld_cmp); - return c->chld_id; } @@ -722,7 +720,7 @@ static long parent_read_frame(guint8* b, size_t len, echld_chld_id_t chld_id, ec echld_t* c = get_child(chld_id); GByteArray* ba = g_byte_array_new(); - PARENT_DBG((3,"parent_read_frame ch=%d t='%c' rh=%d",chld_id,t,reqh_id)); + PARENT_DBG((1,"MSG_IN<- ch=%d t='%s' rh=%d",chld_id,TY(t),reqh_id)); g_byte_array_append(ba,b, (guint)len); if (c) { |