Compiles, still incomplete...
svn path=/trunk/; revision=50101
This commit is contained in:
parent
50bc11bc14
commit
74f0f96209
10
echld-int.h
10
echld-int.h
|
@ -121,8 +121,8 @@ typedef struct _child_in {
|
|||
echld_bool_t (*set_param) (guint8*, size_t, char** param, char** value);
|
||||
echld_bool_t (*get_param) (guint8*, size_t, char** param);
|
||||
echld_bool_t (*close_child) (guint8*, size_t, int* mode);
|
||||
echld_bool_t (*chk_filter) (guint8*, size_t, char** flt);
|
||||
echld_bool_t (*list_files) (guint8*, size_t, char** glob);
|
||||
|
||||
|
||||
echld_bool_t (*open_file) (guint8*, size_t, char** filename);
|
||||
echld_bool_t (*open_interface) (guint8*, size_t, char** intf_name, char** params);
|
||||
echld_bool_t (*get_sum) (guint8*, size_t, char** range);
|
||||
|
@ -136,9 +136,6 @@ typedef struct _child_out {
|
|||
enc_msg_t* (*error) (int , const char*);
|
||||
enc_msg_t* (*child_dead) (const char*);
|
||||
enc_msg_t* (*param) (const char*, const char*);
|
||||
enc_msg_t* (*file_info) (const char*); // pre-encoded
|
||||
enc_msg_t* (*filter_chk) (int , const char*);
|
||||
enc_msg_t* (*intf_info) (const char*); // pre-encoded
|
||||
enc_msg_t* (*notify) (const char*); // pre-encoded
|
||||
enc_msg_t* (*packet_sum) (int, const char*); // framenum, sum(pre-encoded)
|
||||
enc_msg_t* (*tree) (int, const char*); // framenum, tree(pre-encoded)
|
||||
|
@ -151,9 +148,6 @@ typedef struct _parent_in {
|
|||
echld_bool_t (*error) (enc_msg_t*, int* , char**);
|
||||
echld_bool_t (*child_dead) (enc_msg_t*, char**);
|
||||
echld_bool_t (*param) (enc_msg_t*, char**, char**);
|
||||
echld_bool_t (*file_info) (enc_msg_t*, char**); // pre-encoded
|
||||
echld_bool_t (*filter_chk) (enc_msg_t*, int* , char**);
|
||||
echld_bool_t (*intf_info) (enc_msg_t*, char**); // pre-encoded
|
||||
echld_bool_t (*notify) (enc_msg_t*, char**); // pre-encoded
|
||||
echld_bool_t (*packet_sum) (enc_msg_t*, int*, char**); // framenum, sum(pre-encoded)
|
||||
echld_bool_t (*packet) (enc_msg_t*, int*, char**); // framenum, tree(pre-encoded)
|
||||
|
|
22
echld.h
22
echld.h
|
@ -98,7 +98,7 @@ echld_chld_id_t echld_new(void* child_data);
|
|||
/* will return NULL on error, if NULL is also ok for you use echld_get_error() */
|
||||
void* echld_get_data(echld_chld_id_t);
|
||||
|
||||
echld_state_t echld_set_data(echld_chld_id_t, void* child_data);
|
||||
echld_state_t echld_set_data(echld_chld_id_t id, void* child_data);
|
||||
|
||||
/* for each child call cb(id,child_data,cb_data) */
|
||||
typedef echld_bool_t (*echld_iter_cb_t)(echld_chld_id_t, void* child_data, void* cb_data);
|
||||
|
@ -135,7 +135,6 @@ typedef struct _parent_out {
|
|||
enc_msg_t* (*error)(int err, const char* text);
|
||||
enc_msg_t* (*set_param)(const char* param, const char* value);
|
||||
enc_msg_t* (*close_child)(int mode);
|
||||
enc_msg_t* (*list_files)(const char* glob);
|
||||
enc_msg_t* (*open_file)(const char* filename);
|
||||
enc_msg_t* (*open_interface)(const char* intf_name, const char* params);
|
||||
enc_msg_t* (*get_sum)(const char* range);
|
||||
|
@ -143,7 +142,6 @@ typedef struct _parent_out {
|
|||
enc_msg_t* (*get_bufer)(const char* name);
|
||||
enc_msg_t* (*add_note)(int packet_number, const char* note);
|
||||
enc_msg_t* (*apply_filter)(const char* filter);
|
||||
enc_msg_t* (*chk_filter)(const char* filter);
|
||||
enc_msg_t* (*save_file)(const char* filename, const char* params);
|
||||
} echld_parent_encoder_t;
|
||||
|
||||
|
@ -271,14 +269,16 @@ echld_state_t echld_wait(tv_t* timeout);
|
|||
to be used in place of select() in the main loop of the parent code
|
||||
it will serve the children pipes and return as if select() was called.
|
||||
*/
|
||||
int echld_select(int nfds, int* rfds, int* wfds, int* efds, tv_t* timeout);
|
||||
int echld_select(int nfds, fd_set* rfds, fd_set* wfds, fd_set* efds, tv_t* timeout);
|
||||
|
||||
/* or fit these two in your select loop */
|
||||
|
||||
/* returns nfds set */
|
||||
int echld_fdset(int* rfds, int* efds);
|
||||
int echld_fdset(fd_set* rfds, fd_set* efds);
|
||||
|
||||
int echld_fd_read(int* rfds, int* efds);
|
||||
int echld_fd_read(fd_set* rfds, fd_set* efds);
|
||||
|
||||
void echld_set_parent_dbg_level(int lvl);
|
||||
|
||||
|
||||
#define ECHLD_MAX_CHILDREN 32
|
||||
|
@ -317,24 +317,20 @@ enum _echld_msg_type_t {
|
|||
/* auto_tree RW: get trees automatically (without a reqh, as msgh) */
|
||||
/* auto_buffer RW: get buffers automatically (without a reqh, as msgh) */
|
||||
/* cwd RW: the current working directory */
|
||||
/* dfilter: other*
|
||||
/* list_files WO: a file listing of the current dir */
|
||||
/* interfaces RO: the interface listing */
|
||||
/* dfilter RW: initial display filter*
|
||||
/* ... */
|
||||
|
||||
ECHLD_PING = '}', /* out: ping the child */
|
||||
ECHLD_PONG = '{', /* out: ping's response, error or TO otherwise */
|
||||
|
||||
ECHLD_LIST_FILES = 'L', /* out: request a file listing of the current directory */
|
||||
ECHLD_FILE_INFO = 'f', /* in: a file listing of a directory */
|
||||
|
||||
ECHLD_CHK_FILTER = 'K', /* out: verify if a (display) filter works */
|
||||
ECHLD_FILTER_CKD = 'k', /* in: yes this filter works, error or TO? otherwise */
|
||||
|
||||
ECHLD_OPEN_FILE = 'O', /* out: open a file */
|
||||
ECHLD_FILE_OPENED = 'o', /* in: the file has being open, error otherwise */
|
||||
|
||||
ECHLD_LIST_INTERFACES = 'I', /* out: request an interface listing (dispatcher's work, chld_id = 0) */
|
||||
ECHLD_INTERFACE_INFO = 'i', /* in: an interface listing, error otherwise */
|
||||
|
||||
ECHLD_OPEN_INTERFACE = 'C', /* out: request an interface to be open (get ready for capture) */
|
||||
ECHLD_INTERFACE_OPENED = 'c', /* in: ready to start_capture, error otherwise */
|
||||
|
||||
|
|
|
@ -214,14 +214,14 @@ static gboolean child_open_interface(int chld_id, int reqh_id, const char* intf_
|
|||
}
|
||||
|
||||
|
||||
static void child_list_files() {
|
||||
char* file_info = "{glob='*.cap', file_list={'dummy.cap'={type='pcap-ng', size=20300, npackets=502}}}";
|
||||
// ls
|
||||
// foreach file in cur dir
|
||||
GByteArray* ba = (void*)child.enc->file_info(file_info);
|
||||
CHILD_RESP(ba,ECHLD_FILE_INFO);
|
||||
g_byte_array_free(ba,TRUE);
|
||||
}
|
||||
// static void child_list_files() {
|
||||
// char* file_info = "{glob='*.cap', file_list={'dummy.cap'={type='pcap-ng', size=20300, npackets=502}}}";
|
||||
// // ls
|
||||
// // foreach file in cur dir
|
||||
// GByteArray* ba = (void*)child.enc->file_info(file_info);
|
||||
// CHILD_RESP(ba,ECHLD_FILE_INFO);
|
||||
// g_byte_array_free(ba,TRUE);
|
||||
// }
|
||||
|
||||
|
||||
static char* param_get_cwd(char** err ) {
|
||||
|
@ -421,40 +421,6 @@ static int child_receive(guint8* b, size_t len, echld_chld_id_t chld_id, echld_m
|
|||
CHILD_DBG((1,"Bye"));
|
||||
exit(0);
|
||||
break;
|
||||
case ECHLD_LIST_FILES:
|
||||
if (child.state != IDLE) goto wrong_state;
|
||||
CHILD_DBG((3,"Listing Files"));
|
||||
child_list_files();
|
||||
break;
|
||||
case ECHLD_LIST_INTERFACES:
|
||||
{
|
||||
char* err_str;
|
||||
int err = 0;
|
||||
GList* if_list;
|
||||
if (child.state != IDLE) goto wrong_state;
|
||||
|
||||
CHILD_DBG((1,"List Interfaces"));
|
||||
|
||||
if(( if_list = capture_interface_list(&err, &err_str) )) {
|
||||
char* json_list = intflist2json(if_list);
|
||||
|
||||
ba = (void*)child.enc->intf_info(json_list);
|
||||
|
||||
CHILD_RESP(ba,ECHLD_INTERFACE_INFO);
|
||||
g_byte_array_free(ba,TRUE);
|
||||
CHILD_DBG((1,"List interfaces=%s",json_list));
|
||||
g_free(json_list);
|
||||
|
||||
/* XXX FREE if_list */
|
||||
break;
|
||||
} else {
|
||||
child_err(ECHLD_ERR_CANNOT_LIST_INTERFACES, reqh_id,
|
||||
"reason='%s'", err_str);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ECHLD_CHK_FILTER: // first candidate
|
||||
case ECHLD_OPEN_INTERFACE:
|
||||
case ECHLD_OPEN_FILE:
|
||||
case ECHLD_START_CAPTURE:
|
||||
|
|
|
@ -395,14 +395,12 @@ static echld_parent_encoder_t parent_encoder = {
|
|||
x2str_enc,
|
||||
int_enc,
|
||||
str_enc,
|
||||
str_enc,
|
||||
x2str_enc,
|
||||
str_enc,
|
||||
str_enc,
|
||||
str_enc,
|
||||
int_str_enc,
|
||||
str_enc,
|
||||
str_enc,
|
||||
x2str_enc
|
||||
};
|
||||
|
||||
|
@ -415,8 +413,9 @@ static child_decoder_t child_decoder = {
|
|||
x2str_dec,
|
||||
str_dec,
|
||||
int_dec,
|
||||
str_dec,
|
||||
str_dec,
|
||||
|
||||
|
||||
|
||||
str_dec,
|
||||
x2str_dec,
|
||||
str_dec,
|
||||
|
@ -432,9 +431,6 @@ static child_encoder_t child_encoder = {
|
|||
x2str_enc,
|
||||
str_enc,
|
||||
int_str_enc,
|
||||
str_enc,
|
||||
str_enc,
|
||||
int_str_enc,
|
||||
int_str_enc,
|
||||
int_3str_enc,
|
||||
x3str_enc
|
||||
|
@ -446,9 +442,6 @@ static parent_decoder_t parent_decoder = {
|
|||
x2str_deca,
|
||||
str_deca,
|
||||
int_str_deca,
|
||||
str_deca,
|
||||
str_deca,
|
||||
int_str_deca,
|
||||
int_str_deca,
|
||||
int_3str_deca,
|
||||
x3str_deca
|
||||
|
@ -688,14 +681,8 @@ static char* decode_json(echld_msg_type_t type, enc_msg_t* m) {
|
|||
case ECHLD_PARAM: return param_set_json(ba);
|
||||
case ECHLD_PING: return g_strdup("{type='ping'}");
|
||||
case ECHLD_PONG: return g_strdup("{type='pong'}");
|
||||
case ECHLD_LIST_FILES: return list_files_json(ba);
|
||||
case ECHLD_FILE_INFO: return file_info_json(ba);
|
||||
case ECHLD_CHK_FILTER: return chk_filter_json(ba);
|
||||
case ECHLD_FILTER_CKD: return filter_ckd_json(ba);
|
||||
case ECHLD_OPEN_FILE: return open_file_json(ba);
|
||||
case ECHLD_FILE_OPENED: return file_opened_json(ba);
|
||||
case ECHLD_LIST_INTERFACES: return g_strdup("{type='list_interfaces'}");
|
||||
case ECHLD_INTERFACE_INFO: return intf_info_json(ba);
|
||||
case ECHLD_OPEN_INTERFACE: return open_interface_json(ba);
|
||||
case ECHLD_INTERFACE_OPENED: return interface_opened_json(ba);
|
||||
case ECHLD_START_CAPTURE: return g_strdup("{type='start_capture'}");
|
||||
|
@ -742,14 +729,8 @@ extern void dummy_switch(echld_msg_type_t type) {
|
|||
case ECHLD_PARAM: break; //SS param,val
|
||||
case ECHLD_PING: break;
|
||||
case ECHLD_PONG: break; //
|
||||
case ECHLD_LIST_FILES: break;
|
||||
case ECHLD_FILE_INFO: break; //SS info (pre-encoded)
|
||||
case ECHLD_CHK_FILTER: break;
|
||||
case ECHLD_FILTER_CKD: break; //IS ok,filter
|
||||
case ECHLD_OPEN_FILE: break;
|
||||
case ECHLD_FILE_OPENED: break; //
|
||||
case ECHLD_LIST_INTERFACES: break;
|
||||
case ECHLD_INTERFACE_INFO: break; //S intf_list (pre-encoded)
|
||||
case ECHLD_OPEN_INTERFACE: break;
|
||||
case ECHLD_INTERFACE_OPENED: break; //
|
||||
case ECHLD_START_CAPTURE: break;
|
||||
|
@ -779,10 +760,7 @@ extern void dummy_switch(echld_msg_type_t type) {
|
|||
case ECHLD_SET_PARAM: break; // set_param(p,v)
|
||||
case ECHLD_GET_PARAM: break; // get_param(p)
|
||||
case ECHLD_PING: break;
|
||||
case ECHLD_LIST_FILES: break; // list_files(glob)
|
||||
case ECHLD_CHK_FILTER: break; // chk_filter(df)
|
||||
case ECHLD_OPEN_FILE: break; // open_file(f,mode)
|
||||
case ECHLD_LIST_INTERFACES: break;
|
||||
case ECHLD_OPEN_INTERFACE: break; // open_interface(if,param)
|
||||
case ECHLD_START_CAPTURE: break;
|
||||
case ECHLD_GET_SUM: break; // get_sum(rng)
|
||||
|
@ -801,10 +779,7 @@ extern void dummy_switch(echld_msg_type_t type) {
|
|||
case ECHLD_CLOSING: break;
|
||||
case ECHLD_PARAM: break;
|
||||
case ECHLD_PONG: break;
|
||||
case ECHLD_FILE_INFO: break; // file_info(pre_encoded)
|
||||
case ECHLD_FILTER_CKD: break; // filter_ckd(ok,df)
|
||||
case ECHLD_FILE_OPENED: break;
|
||||
case ECHLD_INTERFACE_INFO: break; // intf_info(pre-encoded)
|
||||
case ECHLD_INTERFACE_OPENED: break;
|
||||
case ECHLD_CAPTURE_STARTED: break;
|
||||
case ECHLD_NOTIFY: break; // notify(pre-encoded)
|
||||
|
|
|
@ -206,6 +206,7 @@ void dispatcher_reaper(int sig) {
|
|||
guint8* b[len];
|
||||
GByteArray* em;
|
||||
|
||||
|
||||
for(i = 0; i < max_children; i++) {
|
||||
struct dispatcher_child* c = &(cc[i]);
|
||||
if ( c->pid == pid ) {
|
||||
|
@ -213,6 +214,33 @@ void dispatcher_reaper(int sig) {
|
|||
em = (void*)dispatcher->enc.to_parent->child_dead("OK");
|
||||
} else {
|
||||
/* here we do collect crash data !!! */
|
||||
/*
|
||||
WIFEXITED(status)
|
||||
True if the process terminated normally by a call to _exit(2) or exit(3).
|
||||
|
||||
WIFSIGNALED(status)
|
||||
True if the process terminated due to receipt of a signal.
|
||||
|
||||
WIFSTOPPED(status)
|
||||
True if the process has not terminated, but has stopped and can be restarted. This macro can be true only if the wait call speci-
|
||||
fied the WUNTRACED option or if the child process is being traced (see ptrace(2)).
|
||||
|
||||
Depending on the values of those macros, the following macros produce the remaining status information about the child process:
|
||||
|
||||
WEXITSTATUS(status)
|
||||
If WIFEXITED(status) is true, evaluates to the low-order 8 bits of the argument passed to _exit(2) or exit(3) by the child.
|
||||
|
||||
WTERMSIG(status)
|
||||
If WIFSIGNALED(status) is true, evaluates to the number of the signal that caused the termination of the process.
|
||||
|
||||
WCOREDUMP(status)
|
||||
If WIFSIGNALED(status) is true, evaluates as true if the termination of the process was accompanied by the creation of a core file
|
||||
containing an image of the process when the signal was received.
|
||||
|
||||
WSTOPSIG(status)
|
||||
If WIFSTOPPED(status) is true, evaluates to the number of the signal that caused the process to stop.
|
||||
|
||||
*/
|
||||
em = (void*)dispatcher->enc.to_parent->child_dead("Unexpected, probably crashed");
|
||||
dispatcher_err(ECHLD_ERR_CRASHED_CHILD, "Unexpected dead: pid=%d chld_id=%d", pid, c->chld_id);
|
||||
}
|
||||
|
@ -272,10 +300,7 @@ static int dispatch_to_parent(guint8* b, size_t len, echld_chld_id_t chld_id, ec
|
|||
case ECHLD_CLOSING: c->closing = TRUE; c->state = CLOSED; break;
|
||||
case ECHLD_PARAM: break;
|
||||
case ECHLD_PONG: break;
|
||||
case ECHLD_FILE_INFO: break; // file_info(pre_encoded)
|
||||
case ECHLD_FILTER_CKD: break; // filter_ckd(ok,df)
|
||||
case ECHLD_FILE_OPENED: c->state = READING; break;
|
||||
case ECHLD_INTERFACE_INFO: break; // intf_info(pre-encoded)
|
||||
case ECHLD_INTERFACE_OPENED: c->state = READY; break;
|
||||
case ECHLD_CAPTURE_STARTED: c->state = CAPTURING; break;
|
||||
case ECHLD_NOTIFY: break; // notify(pre-encoded)
|
||||
|
@ -522,9 +547,6 @@ static int dispatch_to_child(guint8* b, size_t len, echld_chld_id_t chld_id, ech
|
|||
case ECHLD_SET_PARAM:
|
||||
case ECHLD_GET_PARAM:
|
||||
case ECHLD_PING:
|
||||
case ECHLD_LIST_FILES:
|
||||
case ECHLD_CHK_FILTER:
|
||||
case ECHLD_LIST_INTERFACES:
|
||||
case ECHLD_GET_SUM:
|
||||
case ECHLD_GET_TREE:
|
||||
case ECHLD_GET_BUFFER:
|
||||
|
|
|
@ -0,0 +1,799 @@
|
|||
/* echld_dispatcher.c
|
||||
* epan working child API internals
|
||||
* Parent process routines and definitions ()
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* Copyright (c) 2013 by Luis Ontanon <luis@ontanon.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "echld-int.h"
|
||||
|
||||
/**
|
||||
PARENT and API
|
||||
**/
|
||||
|
||||
#define MAX_PENDING_REQS 16;
|
||||
|
||||
typedef struct _req {
|
||||
int reqh_id;
|
||||
echld_msg_cb_t cb;
|
||||
void* cb_data;
|
||||
struct timeval tv;
|
||||
} reqh_t;
|
||||
|
||||
typedef struct _hdlr {
|
||||
int id;
|
||||
echld_msg_type_t type;
|
||||
echld_msg_cb_t cb;
|
||||
void* cb_data;
|
||||
} hdlr_t;
|
||||
|
||||
typedef struct _echld_child {
|
||||
int chld_id;
|
||||
void* data;
|
||||
child_state_t state;
|
||||
GArray* handlers;
|
||||
GArray* reqs;
|
||||
} echld_t;
|
||||
|
||||
struct _echld_parent {
|
||||
echld_t* children;
|
||||
echld_reader_t reader;
|
||||
int dispatcher_fd;
|
||||
int dispatcher_pid;
|
||||
int reqh_id;
|
||||
GByteArray* snd;
|
||||
int closing;
|
||||
echld_parent_encoder_t* enc;
|
||||
parent_decoder_t* dec;
|
||||
} parent = {NULL,{NULL,0,NULL,-1,NULL,0},-1,-1,1,NULL,0,NULL,NULL};
|
||||
|
||||
#define PARENT_SEND(BYTEARR,CHILDNUM,TYPE) echld_write_frame(parent.dispatcher_fd, BYTEARR, CHILDNUM, TYPE, parent.reqh_id++, NULL)
|
||||
|
||||
|
||||
#define PARENT_FATAL(attrs) parent_fatal attrs
|
||||
|
||||
#ifdef DEBUG_PARENT
|
||||
|
||||
static int dbg_level = 0;
|
||||
|
||||
static void parent_dgb(int level, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
char str[1024];
|
||||
|
||||
if (level > dbg_level) return;
|
||||
|
||||
va_start(ap,fmt);
|
||||
g_snprintf(str,1024,fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr,"ParentDebug: level=%d msg='%s'\n",level,str);
|
||||
}
|
||||
#define PARENT_DBG(attrs) parent_dbg attrs
|
||||
#else
|
||||
#define PARENT_DBG(attrs)
|
||||
#endif
|
||||
|
||||
void echld_set_parent_dbg_level(int lvl) {
|
||||
PARENT_DBG((0,"Debug Level Set: %d",dbg_level = lvl));
|
||||
}
|
||||
|
||||
static void parent_fatal(int exit_code, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
char str[1024];
|
||||
|
||||
va_start(ap,fmt);
|
||||
g_snprintf(str,1024,fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
#ifdef DEBUG_PARENT
|
||||
PARENT_DBG((0,"Fatal error: %s",str));
|
||||
#else
|
||||
fprintf(stderr,"Fatal error: %s",str);
|
||||
#endif
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static echld_state_t echld_cleanup(void) {
|
||||
int i;
|
||||
char b[4];
|
||||
GByteArray ba;
|
||||
|
||||
ba.data = b;
|
||||
ba.len = 0;
|
||||
|
||||
PARENT_DBG((0,"echld_cleanup starting"));
|
||||
PARENT_SEND(&ba,0,ECHLD_CLOSE_CHILD);
|
||||
|
||||
do ; while(sleep(1)); /* wait a full sec without signals */
|
||||
|
||||
for (i=0;i<ECHLD_MAX_CHILDREN;i++) {
|
||||
g_array_free(parent.children[i].handlers,TRUE);
|
||||
g_array_free(parent.children[i].reqs,TRUE);
|
||||
};
|
||||
|
||||
free(parent.children);
|
||||
g_byte_array_free(parent.snd,TRUE);
|
||||
close(parent.dispatcher_fd);
|
||||
PARENT_DBG((0,"echld_cleanup done"));
|
||||
|
||||
}
|
||||
|
||||
static int parent_child_cleanup(echld_t* c) {
|
||||
|
||||
PARENT_DBG((2,"cleanup chld_id=%d",c->chld_id));
|
||||
c->chld_id = -1;
|
||||
c->data = NULL;
|
||||
c->state = FREE;
|
||||
g_array_truncate(c->handlers);
|
||||
g_array_truncate(c->reqs);
|
||||
}
|
||||
|
||||
|
||||
void parent_reaper(int sig) {
|
||||
int pid;
|
||||
int status;
|
||||
|
||||
if (sig != SIGCHLD) {
|
||||
PARENT_FATAL((3333,"Must be SIGCHLD!"));
|
||||
}
|
||||
|
||||
pid = waitpid(-1, &status, WNOHANG);
|
||||
PARENT_DBG((2,"SIGCHLD pid=%d",pid));
|
||||
|
||||
if (pid == parent.dispatcher_pid) {
|
||||
|
||||
if (! parent.closing) {
|
||||
/* crashed */
|
||||
PARENT_FATAL((2222,"Dispatcher process dead"));
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
/* XXX: do we care? */
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* will initialize epan registering protocols and taps */
|
||||
echld_state_t echld_initialize(echld_encoding_t enc) {
|
||||
int from_disp[2];
|
||||
int to_disp[2];
|
||||
|
||||
if (enc != ECHLD_ENCODING_JSON) {
|
||||
PARENT_FATAL((1111,"Only JSON implemented"));
|
||||
}
|
||||
|
||||
if ( pipe(to_disp) ) {
|
||||
PARENT_FATAL((1112,"Failed to open dispatcher pipe"));
|
||||
} else if( pipe(from_disp) ) {
|
||||
PARENT_FATAL((1113,"Failed to open dispatcher pipe"));
|
||||
} else {
|
||||
int pid;
|
||||
int i;
|
||||
if (( pid = fork() < 0)) {
|
||||
PARENT_FATAL((1114,"Failed to fork() reason='%s'",strerror(errno)));
|
||||
} else if ( pid == 0) {
|
||||
#ifdef PARENT_THREADS
|
||||
reader_realloc_buf = child_realloc_buff;
|
||||
#endif
|
||||
/* child code */
|
||||
echld_cleanup();
|
||||
|
||||
|
||||
dispatcher(to_disp,from_disp);
|
||||
PARENT_FATAL((1115,"This shoudln't happen"));
|
||||
}
|
||||
|
||||
/* parent code */
|
||||
#ifdef PARENT_THREADS
|
||||
reader_realloc_buf = parent_realloc_buff;
|
||||
#endif
|
||||
|
||||
PARENT_DBG((3,"Dispatcher forked"));
|
||||
|
||||
echld_get_all_codecs(NULL, NULL, &parent.enc, &parent.dec);
|
||||
parent.children = g_malloc0(ECHLD_MAX_CHILDREN*sizeof(echld_t));
|
||||
parent.snd = g_byte_array_new();
|
||||
parent.dispatcher_fd = to_disp[0];
|
||||
|
||||
init_reader(&(parent.reader),from_disp[1]);
|
||||
|
||||
for (i=0;i<ECHLD_MAX_CHILDREN;i++) {
|
||||
parent.children[i].chld_id = -1;
|
||||
parent.children[i].data = NULL;
|
||||
parent.children[i].state = FREE;
|
||||
parent.children[i].handlers = g_array_new(TRUE,TRUE,sizeof(hdlr_t));
|
||||
}
|
||||
|
||||
signal(SIGCHLD,parent_reaper);
|
||||
close(to_disp[1]);
|
||||
close(from_disp[0]);
|
||||
PARENT_DBG((3,"Ready"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echld_state_t echld_terminate(void) {
|
||||
echld_cleanup();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int reqh_id_idx(echld_t* c, int reqh_id) {
|
||||
int i;
|
||||
int imax = c->reqs->len;
|
||||
|
||||
for(i=0; i < imax ; i++) {
|
||||
if (((reqh_t*)&g_array_index (c->reqs, reqh_t, i))->reqh_id == reqh_id) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static echld_t* get_child(int id) {
|
||||
int i;
|
||||
for (i=0;i<ECHLD_MAX_CHILDREN;i++) {
|
||||
if (parent.children[i].chld_id == id) return &(parent.children[i]);
|
||||
};
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* send a request */
|
||||
|
||||
static int reqh_ids = 1;
|
||||
|
||||
static echld_state_t reqh_snd(echld_t* c, echld_msg_type_t t, GByteArray* ba, echld_msg_cb_t resp_cb, void* cb_data) {
|
||||
reqh_t req;
|
||||
|
||||
if (!c) {
|
||||
PARENT_DBG((1,"REQH_SND: No such child"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
req.reqh_id = reqh_ids++;
|
||||
req.cb = resp_cb;
|
||||
req.cb_data = cb_data;
|
||||
gettimeofday(&(req.tv));
|
||||
|
||||
g_array_append_val(c->reqs,req);
|
||||
|
||||
PARENT_DBG((1,"REQH_SND: type='%c' chld_id=%d reqh_id=%d",t,c->chld_id,req.reqh_id));
|
||||
|
||||
PARENT_SEND(ba,c->chld_id,t);
|
||||
|
||||
if (ba) g_byte_array_free(ba,TRUE);
|
||||
|
||||
return req.reqh_id;
|
||||
}
|
||||
|
||||
|
||||
echld_reqh_id_t echld_reqh(
|
||||
echld_chld_id_t child_id,
|
||||
echld_msg_type_t t,
|
||||
int usecs_timeout,
|
||||
enc_msg_t* ba,
|
||||
echld_msg_cb_t resp_cb,
|
||||
void* cb_data) {
|
||||
return reqh_snd(get_child(child_id),t,(void*)ba,resp_cb,cb_data);
|
||||
}
|
||||
|
||||
/* get callback data for a live request */
|
||||
void* echld_reqh_get_data(int child_id, int reqh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
int idx;
|
||||
|
||||
if (!c) return NULL;
|
||||
|
||||
idx = reqh_id_idx(c,reqh_id);
|
||||
|
||||
if (idx >= 0)
|
||||
return g_array_index(c->reqs, reqh_t, idx).cb_data;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the callback for a live request */
|
||||
echld_msg_cb_t echld_reqh_get_cb(int child_id, int reqh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
int idx;
|
||||
|
||||
if (!c) return NULL;
|
||||
|
||||
idx = reqh_id_idx(c,reqh_id);
|
||||
|
||||
if (idx >= 0)
|
||||
return g_array_index(c->reqs, reqh_t, idx).cb;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* set callback data for a live request */
|
||||
gboolean echld_reqh_set_data(int child_id, int reqh_id, void* cb_data) {
|
||||
echld_t* c = get_child(child_id);
|
||||
int idx;
|
||||
|
||||
if (!c) return FALSE;
|
||||
|
||||
idx = reqh_id_idx(c,reqh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
g_array_index(c->reqs, reqh_t, idx).cb_data = cb_data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* get the callback for a live request */
|
||||
gboolean echld_reqh_set_cb(int child_id, int reqh_id, echld_msg_cb_t cb){
|
||||
echld_t* c = get_child(child_id);
|
||||
int idx;
|
||||
|
||||
if (!c) return FALSE;
|
||||
|
||||
idx = reqh_id_idx(c,reqh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
g_array_index(c->reqs, reqh_t, idx).cb = cb;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* stop receiving a live request */
|
||||
gboolean echld_reqh_detach(int child_id, int reqh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
int idx;
|
||||
|
||||
if (!c) return FALSE;
|
||||
|
||||
idx = reqh_id_idx(c,reqh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
g_array_remove_index(c->reqs,idx);
|
||||
}
|
||||
|
||||
|
||||
static echld_bool_t parent_dead_child(echld_msg_type_t type, enc_msg_t* ba, void* data) {
|
||||
echld_t* c = data;
|
||||
char* str;
|
||||
|
||||
if (type != ECHLD_CHILD_DEAD) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( parent.dec->child_dead((void*)ba,&str) ) {
|
||||
g_string_prepend_printf(str,"Dead Child[%d]: %s",c->chld_id,str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
parent_child_cleanup(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static echld_bool_t parent_get_hello(echld_msg_type_t type, enc_msg_t* ba, void* data) {
|
||||
echld_t* c = data;
|
||||
|
||||
switch (type) {
|
||||
case ECHLD_HELLO:
|
||||
c->state = IDLE;
|
||||
return TRUE;
|
||||
case ECHLD_ERROR:
|
||||
case ECHLD_TIMEOUT:
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int chld_cmp(const void *a, const void *b) {
|
||||
return ((echld_t*)b)->chld_id - ((echld_t*)a)->chld_id;
|
||||
}
|
||||
|
||||
static int msgh_attach(echld_t* c, echld_msg_type_t t, echld_msg_cb_t resp_cb, void* cb_data);
|
||||
|
||||
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->data = child_data;
|
||||
c->state = CREATING;
|
||||
c->handlers = g_array_new(TRUE,TRUE,sizeof(hdlr_t));
|
||||
|
||||
g_byte_array_truncate(parent.snd,0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* XXX these fail silently */
|
||||
void* echld_get_data(int child_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? c->data : NULL;
|
||||
}
|
||||
|
||||
echld_state_t echld_set_data(echld_chld_id_t chld_id, void* data) {
|
||||
echld_t* c = get_child(chld_id);
|
||||
if (c) {
|
||||
c->data = data;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int msgh_idx(echld_t* c, int msgh_id) {
|
||||
int i = 0;
|
||||
int imax = c->handlers->len;
|
||||
|
||||
for (i=0;i<imax;i++) {
|
||||
if (((hdlr_t*)(c->handlers->data))[i].id == msgh_id) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* start a message handler */
|
||||
static int msgh_attach(echld_t* c, echld_msg_type_t t, echld_msg_cb_t resp_cb, void* cb_data) {
|
||||
hdlr_t h;
|
||||
int hdlr_idx;
|
||||
static int msgh_id;
|
||||
|
||||
h.id = msgh_id++;
|
||||
h.type = t;
|
||||
h.cb = resp_cb;
|
||||
h.cb_data = cb_data;
|
||||
|
||||
g_array_append_val(c->handlers,h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int echld_msgh_attach(int child_id, echld_msg_type_t t, echld_msg_cb_t resp_cb, void* cb_data) {
|
||||
echld_t* c = get_child(child_id);
|
||||
|
||||
if (c) return msgh_attach(c,t,resp_cb,cb_data);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
|
||||
/* stop it */
|
||||
static echld_state_t msgh_detach(echld_t* c, int msgh_id) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return -1;
|
||||
|
||||
g_array_remove_index(c->handlers,idx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
echld_state_t echld_msgh_detach(int child_id, int msgh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return msgh_detach(c,msgh_id);
|
||||
}
|
||||
|
||||
/* get a msgh's data */
|
||||
|
||||
static void* msgh_get_data(echld_t* c, int msgh_id) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return NULL;
|
||||
|
||||
return ((hdlr_t*)(c->handlers->data))[idx].cb_data;
|
||||
}
|
||||
|
||||
void* echld_msgh_get_data(int child_id, int msgh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return msgh_get_data(c,msgh_id);
|
||||
}
|
||||
|
||||
/* get a msgh's cb */
|
||||
static echld_msg_cb_t msgh_get_cb(echld_t* c, int msgh_id) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return NULL;
|
||||
|
||||
return ((hdlr_t*)(c->handlers->data))[idx].cb;
|
||||
}
|
||||
|
||||
echld_msg_cb_t echld_msgh_get_cb(int child_id, int msgh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return msgh_get_cb(c,msgh_id);
|
||||
}
|
||||
|
||||
/* get a msgh's type */
|
||||
static echld_msg_type_t msgh_get_type(echld_t* c, int msgh_id) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return EC_ACTUAL_ERROR;
|
||||
|
||||
return ((hdlr_t*)(c->handlers->data))[idx].type;
|
||||
}
|
||||
|
||||
echld_msg_type_t echld_msgh_get_type(int child_id, int msgh_id) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? msgh_get_type(c,msgh_id) : EC_ACTUAL_ERROR;
|
||||
}
|
||||
|
||||
/* get it all from a msgh */
|
||||
static echld_state_t msgh_get_all(echld_t* c, int msgh_id, echld_msg_type_t* t, echld_msg_cb_t* cb, void** data) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
hdlr_t* h;
|
||||
|
||||
if (idx < 0) return -1;
|
||||
|
||||
h = &(((hdlr_t*)(c->handlers->data))[idx]);
|
||||
|
||||
t && (*t = h->type);
|
||||
cb && (*cb = h->cb);
|
||||
data && (*data = h->cb_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean echld_msgh_get_all(int child_id, int msgh_id, echld_msg_type_t* t, echld_msg_cb_t* cb, void** data) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c && msgh_get_all(c,msgh_id,t,cb,data);
|
||||
}
|
||||
|
||||
static echld_state_t msgh_set_all(echld_t* c, int msgh_id, echld_msg_type_t t, echld_msg_cb_t cb, void* data) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
hdlr_t* h;
|
||||
|
||||
if (idx < 0) return -1;
|
||||
|
||||
h = &(((hdlr_t*)(c->handlers->data))[idx]);
|
||||
|
||||
h->type = t;
|
||||
h->cb = cb;
|
||||
h->cb_data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean echld_msgh_set_all(int child_id, int msgh_id, echld_msg_type_t t, echld_msg_cb_t cb, void* data) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? msgh_set_all(c,msgh_id,t,cb,data) : FALSE;
|
||||
}
|
||||
|
||||
/* set a msgh's data */
|
||||
static gboolean msgh_set_data(echld_t* c, int msgh_id, void* data) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
((hdlr_t*)(c->handlers->data))[idx].cb_data = data;
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
gboolean echld_msgh_set_data(int child_id, int msgh_id, void* data){
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? msgh_set_data(c,msgh_id,data) : FALSE;
|
||||
}
|
||||
|
||||
/* set a msgh's cb */
|
||||
gboolean msgh_set_cb(echld_t* c, int msgh_id, echld_msg_cb_t cb) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
((hdlr_t*)(c->handlers->data))[idx].cb = cb;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean echld_msgh_set_cb(int child_id, int msgh_id, echld_msg_cb_t cb) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? msgh_set_cb(c,msgh_id,cb) : FALSE;
|
||||
}
|
||||
|
||||
/* set a msgh's type */
|
||||
|
||||
static gboolean msgh_set_type(echld_t* c, int msgh_id, echld_msg_type_t t) {
|
||||
int idx = msgh_idx(c,msgh_id);
|
||||
|
||||
if (idx < 0) return FALSE;
|
||||
|
||||
((hdlr_t*)(c->handlers->data))[idx].type = t;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean echld_msgh_set_type(int child_id, int msgh_id, echld_msg_type_t t) {
|
||||
echld_t* c = get_child(child_id);
|
||||
return c ? msgh_set_type(c,msgh_id,t) : FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* call cb(id,child_data,cb_data) for each child*/
|
||||
void echld_foreach_child(echld_iter_cb_t cb, void* cb_data) {
|
||||
int i;
|
||||
for(i=0;i<ECHLD_MAX_CHILDREN;i++) {
|
||||
echld_t* c = &(parent.children[i]);
|
||||
cb(c->chld_id,c->data,cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static reqh_t* get_req(echld_t* c, int reqh_id) {
|
||||
int idx = reqh_id_idx(c,reqh_id);
|
||||
reqh_t* r;
|
||||
if(idx < 0) return NULL;
|
||||
|
||||
return ((reqh_t*)(c->reqs->data))+idx;
|
||||
}
|
||||
|
||||
static hdlr_t* get_next_hdlr_for_type(echld_t* c, echld_msg_type_t t, int* cookie) {
|
||||
int imax = c->handlers->len;
|
||||
|
||||
for (;*cookie<imax;(*cookie)++) {
|
||||
if (((hdlr_t*)(c->handlers->data))[*cookie].type == t)
|
||||
return &( ((hdlr_t*)(c->handlers->data))[*cookie] ) ;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int parent_read_frame(GByteArray* ba, guint16 chld_id, echld_msg_type_t t, guint16 reqh_id, void* data) {
|
||||
echld_t* c = get_child(chld_id);
|
||||
|
||||
if (ba == NULL) g_byte_array_new();
|
||||
|
||||
if (c) {
|
||||
reqh_t* r = get_req(c, reqh_id);
|
||||
int i = 0;
|
||||
hdlr_t* h;
|
||||
gboolean go_ahead = TRUE;
|
||||
|
||||
if (r) { /* got that reqh_id */
|
||||
go_ahead = r->cb ? r->cb(t,(void*)ba,r->cb_data) : TRUE;
|
||||
}
|
||||
|
||||
while(go_ahead && ( h = get_next_hdlr_for_type(c,t,&i))) {
|
||||
go_ahead = h->cb(t,(void*)ba,r->cb_data);
|
||||
}
|
||||
} else {
|
||||
/* no such child??? */
|
||||
}
|
||||
|
||||
ba && g_byte_array_free(ba,TRUE);
|
||||
|
||||
}
|
||||
|
||||
int echld_fdset(fd_set* rfds, fd_set* efds) {
|
||||
FD_SET(parent.reader.fd, rfds);
|
||||
FD_SET(parent.reader.fd, efds);
|
||||
FD_SET(parent.dispatcher_fd, efds);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int echld_fd_read(fd_set* rfds, fd_set* efds) {
|
||||
int r_nfds=0;
|
||||
if (FD_ISSET(parent.reader.fd,efds) || FD_ISSET(parent.dispatcher_fd,efds) ) {
|
||||
/* Handle errored dispatcher */
|
||||
r_nfds--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FD_ISSET(parent.reader.fd,rfds)) {
|
||||
r_nfds++;
|
||||
read_frame(&(parent.reader),parent_read_frame,&(parent));
|
||||
}
|
||||
|
||||
return r_nfds;
|
||||
}
|
||||
|
||||
int echld_select(int nfds, fd_set* rfds, fd_set* wfds, fd_set* efds, struct timeval* timeout) {
|
||||
fd_set my_rfds, my_wfds, my_efds;
|
||||
int r_nfds;
|
||||
|
||||
if (rfds == NULL) { rfds = &my_rfds; FD_ZERO(rfds); }
|
||||
if (wfds == NULL) { wfds = &my_wfds; FD_ZERO(wfds); }
|
||||
if (efds == NULL) { efds = &my_efds; FD_ZERO(efds); }
|
||||
|
||||
nfds += echld_fdset(rfds,efds);
|
||||
|
||||
r_nfds = select(nfds, rfds, wfds, efds, timeout);
|
||||
|
||||
r_nfds += echld_fd_read(rfds,efds);
|
||||
|
||||
return r_nfds ;
|
||||
}
|
||||
|
||||
echld_state_t echld_wait(struct timeval* timeout) {
|
||||
if ( echld_select(0, NULL, NULL, NULL, timeout) < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return ECHLD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ping the child */
|
||||
struct _ping {
|
||||
struct timeval tv;
|
||||
echld_t* child;
|
||||
echld_ping_cb_t cb;
|
||||
void* cb_data;
|
||||
};
|
||||
|
||||
static long timevaldiff(struct timeval *starttime, struct timeval *finishtime) {
|
||||
long msec;
|
||||
msec=(finishtime->tv_sec-starttime->tv_sec)*1000;
|
||||
msec+=(finishtime->tv_usec-starttime->tv_usec)/1000;
|
||||
return msec;
|
||||
}
|
||||
|
||||
static gboolean pong(echld_msg_type_t type, GByteArray* ba, void* data) {
|
||||
struct _ping* p = data;
|
||||
struct timeval t;
|
||||
gettimeofday(&t);
|
||||
|
||||
if (p->cb) p->cb(timevaldiff(&(p->tv),&t), p->cb_data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
echld_state_t echld_ping(int child_id, echld_ping_cb_t pcb, void* cb_data) {
|
||||
echld_t* c;
|
||||
struct _ping* p;
|
||||
GByteArray* ba;
|
||||
|
||||
if (!(( c = get_child(child_id) )) ) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = g_malloc0(sizeof(struct _ping));
|
||||
ba = g_byte_array_new();
|
||||
|
||||
p->child = c;
|
||||
p->cb = pcb;
|
||||
p->cb_data = cb_data;
|
||||
gettimeofday(&(p->tv));
|
||||
|
||||
return echld_req(c->chld_id, ECHLD_PING, ba, pong, p);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue