2 * epan working child API internals
3 * Parent 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.
30 #include "echld-int.h"
36 #define MAX_PENDING_REQS 16;
45 typedef struct _hdlr
{
47 echld_msg_type_t type
;
52 typedef struct _echld_child
{
61 struct _echld_parent
{
63 echld_reader_t reader
;
69 echld_parent_encoder_t
* enc
;
70 parent_decoder_t
* dec
;
71 } parent
= {NULL
,{NULL
,0,NULL
,-1,NULL
,0},-1,-1,1,NULL
,0,NULL
,NULL
};
74 static int reqh_ids
= 1;
79 static int dbg_level
= DEBUG_PARENT
;
81 static void parent_dbg(int level
, const char* fmt
, ...) {
85 if (level
> dbg_level
) return;
88 g_vsnprintf(str
,1024,fmt
,ap
);
91 fprintf(stderr
,"ParentDebug: level=%d msg='%s'\n",level
,str
);
95 #define PARENT_DBG(attrs) parent_dbg attrs
96 #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)
99 #define PARENT_DBG(attrs)
100 #define PARENT_SEND(BYTEARR,CHILDNUM,TYPE,R_ID) echld_write_frame(parent.dispatcher_fd, BYTEARR, CHILDNUM, TYPE, R_ID, NULL)
103 extern void echld_set_parent_dbg_level(int lvl
) {
106 echld_common_set_dbg(lvl
,stderr
,"parent");
108 PARENT_DBG((0,"Debug Level Set: %d",lvl
));
112 #define PARENT_FATAL(attrs) parent_fatal attrs
114 static void parent_fatal(int exit_code
, const char* fmt
, ...) {
119 g_vsnprintf(str
,1024,fmt
,ap
);
123 PARENT_DBG((0,"Fatal error: exit_code=%d str=%s",exit_code
,str
));
125 fprintf(stderr
,"Fatal error: exit_code=%d str=%s",exit_code
,str
);
128 kill(parent
.dispatcher_pid
,SIGTERM
);
132 static void echld_cleanup(void) {
135 PARENT_DBG((4,"echld_cleanup starting"));
137 // for (i=0;i<ECHLD_MAX_CHILDREN;i++) {
138 // if ( parent.children[i].handlers ) g_array_free(parent.children[i].handlers,TRUE);
139 // if ( parent.children[i].reqs ) g_array_free(parent.children[i].reqs,TRUE);
142 // g_free(parent.children);
144 // g_byte_array_free(parent.snd,TRUE);
146 PARENT_DBG((3,"echld_cleanup done"));
150 static void parent_child_cleanup(echld_t
* c
) {
152 PARENT_DBG((2,"cleanup chld_id=%d",c
->chld_id
));
156 g_array_set_size(c
->handlers
,0);
157 g_array_set_size(c
->reqs
,0);
161 void parent_reaper(int sig
) {
165 if (sig
== SIGCHLD
) {
166 PARENT_FATAL((3333,"Must be SIGCHLD!"));
169 pid
= waitpid(-1, &status
, WNOHANG
);
170 PARENT_DBG((2,"SIGCHLD pid=%d",pid
));
172 if (pid
== parent
.dispatcher_pid
) {
174 if (! parent
.closing
) {
177 PARENT_FATAL((DISPATCHER_DEAD
,"Dispatcher process dead"));
182 /* XXX: do we care? */
189 static echld_bool_t
hello_cb(echld_msg_type_t type
, enc_msg_t
* msg_buff
, void* ud
) {
190 echld_init_t
* init
= (echld_init_t
*)ud
;
194 if (init
&& init
->dispatcher_hello_cb
) {
197 parent
.dec
->error(msg_buff
, &errnum
,&err
);
199 case ECHLD_TIMED_OUT
:
200 err
= g_strdup("timedout");
203 err
= g_strdup_printf("Wrong MSG 'HELLO' expected, got '%s",TY(type
));
209 init
->dispatcher_hello_cb(ud
,err
);
210 if (err
) g_free(err
);
218 /* will initialize epan registering protocols and taps */
219 void echld_initialize(echld_init_t
* init
) {
222 PARENT_DBG((1,"Echld Starting"));
225 PARENT_FATAL((NO_INITIALIZER
,"Missing Initializer"));
228 if (init
->encoding
!= ECHLD_ENCODING_JSON
) {
229 PARENT_FATAL((UNIMPLEMENTED
,"Only JSON implemented"));
232 if ( pipe(to_disp
) ) {
233 PARENT_FATAL((DISPATCHER_PIPE_FAILED
,"Failed to open pipe to dispatcher"));
234 } else if( pipe(from_disp
) ) {
235 PARENT_FATAL((DISPATCHER_PIPE_FAILED
,"Failed to open pipe from dispatcher"));
240 PARENT_DBG((3,"Pipes Opened fr[0]=%d fr[1]=%d to[0]=%d to[1]=%d",from_disp
[0],from_disp
[1],to_disp
[0],to_disp
[1]));
245 PARENT_FATAL((CANNOT_FORK
,"Failed to fork() reason='%s'",strerror(errno
)));
246 } else if ( pid
== 0) {
247 #ifdef PARENT_THREADS
248 reader_realloc_buf
= child_realloc_buff
;
253 if (init
->after_fork_cb
)
254 init
->after_fork_cb(init
->after_fork_cb_data
);
256 echld_dispatcher_start(to_disp
,from_disp
,init
->argv0
,init
->main
);
258 PARENT_FATAL((SHOULD_HAVE_EXITED_BEFORE
,"This shoudln't happen"));
261 #ifdef PARENT_THREADS
262 reader_realloc_buf
= parent_realloc_buff
;
265 /* echld_common_set_dbg(9,stderr,"parent"); */
267 PARENT_DBG((3,"Dispatcher forked"));
269 echld_get_all_codecs(NULL
, NULL
, &parent
.enc
, &parent
.dec
);
270 parent
.children
= g_new0(echld_t
,ECHLD_MAX_CHILDREN
);
271 parent
.snd
= g_byte_array_new();
272 parent
.dispatcher_fd
= to_disp
[1];
273 parent
.dispatcher_pid
= pid
;
275 echld_init_reader(&(parent
.reader
),from_disp
[0],4096);
278 for (i
=0;i
<ECHLD_MAX_CHILDREN
;i
++) {
279 parent
.children
[i
].chld_id
= -1;
280 parent
.children
[i
].data
= NULL
;
281 parent
.children
[i
].state
= FREE
;
282 parent
.children
[i
].handlers
= g_array_new(TRUE
,TRUE
,sizeof(hdlr_t
));
283 parent
.children
[i
].reqs
= g_array_new(TRUE
,TRUE
,sizeof(reqh_t
));
286 parent
.children
[0].chld_id
= 0;
287 parent
.children
[0].state
= IDLE
;
289 signal(SIGCHLD
,parent_reaper
);
291 //close(from_disp[1]);
292 if (init
->dispatcher_hello_cb
) echld_msgh(0, ECHLD_HELLO
, hello_cb
, init
);
294 PARENT_DBG((3,"Ready"));
300 extern echld_state_t
echld_terminate(void) {
302 parent
.closing
= TRUE
;
303 PARENT_SEND(NULL
,0,ECHLD_CLOSE_CHILD
,++reqh_ids
);
305 do {;} while(sleep(1)); /* wait a full sec without signals */
308 close(parent
.dispatcher_fd
);
309 kill(parent
.dispatcher_pid
,SIGTERM
);
316 static echld_t
* get_child(int id
) {
318 for (i
=0;i
<ECHLD_MAX_CHILDREN
;i
++) {
319 if (parent
.children
[i
].chld_id
== id
) return &(parent
.children
[i
]);
328 int reqh_id_idx(echld_t
* c
, int reqh_id
) {
330 int imax
= c
->reqs
->len
;
331 reqh_t
* rr
= (reqh_t
*)c
->reqs
->data
;
333 for(i
=0; i
< imax
; i
++) {
334 if (rr
[i
].reqh_id
== reqh_id
)
342 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
) {
345 int reqh_id
= reqh_ids
++;
348 PARENT_DBG((1,"REQH_SND: No such child"));
352 idx
= reqh_id_idx(c
,-1);
356 g_array_append_val(c
->reqs
,req
);
359 r
= &(((reqh_t
*)c
->reqs
->data
)[idx
]);
361 r
->reqh_id
= reqh_id
;
363 r
->cb_data
= cb_data
;
365 gettimeofday(&(r
->tv
),NULL
);
367 PARENT_DBG((4,"reqh_add: idx='%d'",idx
));
369 PARENT_DBG((3,"REQH_SND: type='%s' chld_id=%d reqh_id=%d",TY(t
), c
->chld_id
,reqh_id
));
371 PARENT_SEND(ba
,c
->chld_id
,t
,reqh_id
);
373 if (ba
) g_byte_array_free(ba
,TRUE
); /* do we? */
379 extern echld_reqh_id_t
echld_reqh(
380 echld_chld_id_t child_id
,
382 int usecs_timeout _U_
,
384 echld_msg_cb_t resp_cb
,
386 return reqh_snd(get_child(child_id
),t
,ba
,resp_cb
,cb_data
);
389 /* get callback data for a live request */
390 extern void* echld_reqh_get_data(int child_id
, int reqh_id
) {
391 echld_t
* c
= get_child(child_id
);
396 idx
= reqh_id_idx(c
,reqh_id
);
399 return g_array_index(c
->reqs
, reqh_t
, idx
).cb_data
;
404 /* get the callback for a live request */
405 extern echld_msg_cb_t
echld_reqh_get_cb(int child_id
, int reqh_id
) {
406 echld_t
* c
= get_child(child_id
);
411 idx
= reqh_id_idx(c
,reqh_id
);
414 return g_array_index(c
->reqs
, reqh_t
, idx
).cb
;
419 /* set callback data for a live request */
420 extern gboolean
echld_reqh_set_data(int child_id
, int reqh_id
, void* cb_data
) {
421 echld_t
* c
= get_child(child_id
);
424 if (!c
) return FALSE
;
426 idx
= reqh_id_idx(c
,reqh_id
);
428 if (idx
< 0) return FALSE
;
430 g_array_index(c
->reqs
, reqh_t
, idx
).cb_data
= cb_data
;
435 /* get the callback for a live request */
436 extern gboolean
echld_reqh_set_cb(int child_id
, int reqh_id
, echld_msg_cb_t cb
){
437 echld_t
* c
= get_child(child_id
);
440 if (!c
) return FALSE
;
442 idx
= reqh_id_idx(c
,reqh_id
);
444 if (idx
< 0) return FALSE
;
446 g_array_index(c
->reqs
, reqh_t
, idx
).cb
= cb
;
451 /* stop receiving a live request */
452 extern gboolean
echld_reqh_detach(int child_id
, int reqh_id
) {
453 echld_t
* c
= get_child(child_id
);
456 if (!c
) return FALSE
;
458 idx
= reqh_id_idx(c
,reqh_id
);
460 if (idx
< 0) return FALSE
;
462 g_array_remove_index(c
->reqs
,idx
);
468 static echld_bool_t
parent_dead_child(echld_msg_type_t type
, enc_msg_t
* ba
, void* data
) {
469 echld_t
* c
= (echld_t
*)data
;
472 if (type
!= ECHLD_CHILD_DEAD
) {
473 PARENT_DBG((1, "Must Be ECHLD_CHILD_DEAD"));
477 if ( parent
.dec
->child_dead(ba
,&s
) ) {
478 PARENT_DBG((1,"Dead Child[%d]: %s",c
->chld_id
,s
));
482 parent_child_cleanup(c
);
486 static echld_bool_t
parent_get_hello(echld_msg_type_t type
, enc_msg_t
* ba
, void* data
) {
487 echld_t
* c
= (echld_t
*)data
;
493 PARENT_DBG((1,"Child[%d]: =>IDLE",c
->chld_id
));
497 parent
.dec
->error(ba
,&err_id
,&err
);
499 case ECHLD_TIMED_OUT
:
500 err
= g_strdup("timedout");
503 err
= g_strdup_printf("Wrong MSG 'HELLO' expected, got '%s",TY(type
));
510 if (err
) g_free(err
);
519 int chld_cmp(const void *a
, const void *b
) {
520 return ((echld_t
*)b
)->chld_id
- ((echld_t
*)a
)->chld_id
;
523 static int msgh_attach(echld_t
* c
, echld_msg_type_t t
, echld_msg_cb_t resp_cb
, void* cb_data
);
525 static int next_chld_id
= 1;
527 extern int echld_new(enc_msg_t
* new_child_em
, echld_new_cb_t cb
, void* child_data
) {
528 echld_t
* c
= get_child(-1);
532 c
->chld_id
= (next_chld_id
++);
533 c
->data
= child_data
;
537 PARENT_DBG((1,"Child[%d]: =>CREATING",c
->chld_id
));
539 msgh_attach(c
,ECHLD_CHILD_DEAD
, parent_dead_child
, c
);
540 reqh_snd(c
, ECHLD_NEW_CHILD
, (GByteArray
*)new_child_em
, parent_get_hello
, c
);
547 /* XXX these fail silently */
548 extern void* echld_get_data(int child_id
) {
549 echld_t
* c
= get_child(child_id
);
550 return c
? c
->data
: NULL
;
553 extern echld_state_t
echld_set_data(echld_chld_id_t chld_id
, void* data
) {
554 echld_t
* c
= get_child(chld_id
);
563 static int msgh_idx(echld_t
* c
, int msgh_id
) {
565 int imax
= c
->handlers
->len
;
567 for (i
=0;i
<imax
;i
++) {
568 if (((hdlr_t
*)(c
->handlers
->data
))[i
].id
== msgh_id
) return i
;
574 /* start a message handler */
575 static int msgh_attach(echld_t
* c
, echld_msg_type_t t
, echld_msg_cb_t resp_cb
, void* cb_data
) {
577 static int msgh_id
= 1;
584 g_array_append_val(c
->handlers
,h
);
588 extern int echld_msgh(int child_id
, echld_msg_type_t t
, echld_msg_cb_t resp_cb
, void* cb_data
) {
589 echld_t
* c
= get_child(child_id
);
591 if (c
) return msgh_attach(c
,t
,resp_cb
,cb_data
);
597 static echld_state_t
msgh_detach(echld_t
* c
, int msgh_id
) {
598 int idx
= msgh_idx(c
,msgh_id
);
600 if (idx
< 0) return -1;
602 g_array_remove_index(c
->handlers
,idx
);
607 extern echld_state_t
echld_msgh_detach(int child_id
, int msgh_id
) {
608 echld_t
* c
= get_child(child_id
);
609 return msgh_detach(c
,msgh_id
);
612 /* get a msgh's data */
614 static void* msgh_get_data(echld_t
* c
, int msgh_id
) {
615 int idx
= msgh_idx(c
,msgh_id
);
617 if (idx
< 0) return NULL
;
619 return ((hdlr_t
*)(c
->handlers
->data
))[idx
].cb_data
;
622 extern void* echld_msgh_get_data(int child_id
, int msgh_id
) {
623 echld_t
* c
= get_child(child_id
);
624 return msgh_get_data(c
,msgh_id
);
627 /* get a msgh's cb */
628 static echld_msg_cb_t
msgh_get_cb(echld_t
* c
, int msgh_id
) {
629 int idx
= msgh_idx(c
,msgh_id
);
631 if (idx
< 0) return NULL
;
633 return ((hdlr_t
*)(c
->handlers
->data
))[idx
].cb
;
636 extern echld_msg_cb_t
echld_msgh_get_cb(int child_id
, int msgh_id
) {
637 echld_t
* c
= get_child(child_id
);
638 return msgh_get_cb(c
,msgh_id
);
641 /* get a msgh's type */
642 static echld_msg_type_t
msgh_get_type(echld_t
* c
, int msgh_id
) {
643 int idx
= msgh_idx(c
,msgh_id
);
645 if (idx
< 0) return EC_ACTUAL_ERROR
;
647 return ((hdlr_t
*)(c
->handlers
->data
))[idx
].type
;
650 extern echld_msg_type_t
echld_msgh_get_type(int child_id
, int msgh_id
) {
651 echld_t
* c
= get_child(child_id
);
652 return c
? msgh_get_type(c
,msgh_id
) : EC_ACTUAL_ERROR
;
655 /* get it all from a msgh */
656 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
) {
657 int idx
= msgh_idx(c
,msgh_id
);
660 if (idx
< 0) return -1;
662 h
= &(((hdlr_t
*)(c
->handlers
->data
))[idx
]);
666 if (data
) *data
= h
->cb_data
;
671 extern gboolean
echld_msgh_get_all(int child_id
, int msgh_id
, echld_msg_type_t
* t
, echld_msg_cb_t
* cb
, void** data
) {
672 echld_t
* c
= get_child(child_id
);
673 return c
&& msgh_get_all(c
,msgh_id
,t
,cb
,data
);
676 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
) {
677 int idx
= msgh_idx(c
,msgh_id
);
680 if (idx
< 0) return -1;
682 h
= &(((hdlr_t
*)(c
->handlers
->data
))[idx
]);
691 extern gboolean
echld_msgh_set_all(int child_id
, int msgh_id
, echld_msg_type_t t
, echld_msg_cb_t cb
, void* data
) {
692 echld_t
* c
= get_child(child_id
);
693 return c
? msgh_set_all(c
,msgh_id
,t
,cb
,data
) : FALSE
;
696 /* set a msgh's data */
697 static gboolean
msgh_set_data(echld_t
* c
, int msgh_id
, void* data
) {
698 int idx
= msgh_idx(c
,msgh_id
);
700 if (idx
< 0) return FALSE
;
702 ((hdlr_t
*)(c
->handlers
->data
))[idx
].cb_data
= data
;
708 extern gboolean
echld_msgh_set_data(int child_id
, int msgh_id
, void* data
){
709 echld_t
* c
= get_child(child_id
);
710 return c
? msgh_set_data(c
,msgh_id
,data
) : FALSE
;
713 /* set a msgh's cb */
714 extern gboolean
msgh_set_cb(echld_t
* c
, int msgh_id
, echld_msg_cb_t cb
) {
715 int idx
= msgh_idx(c
,msgh_id
);
717 if (idx
< 0) return FALSE
;
719 ((hdlr_t
*)(c
->handlers
->data
))[idx
].cb
= cb
;
724 extern gboolean
echld_msgh_set_cb(int child_id
, int msgh_id
, echld_msg_cb_t cb
) {
725 echld_t
* c
= get_child(child_id
);
726 return c
? msgh_set_cb(c
,msgh_id
,cb
) : FALSE
;
729 /* set a msgh's type */
731 static gboolean
msgh_set_type(echld_t
* c
, int msgh_id
, echld_msg_type_t t
) {
732 int idx
= msgh_idx(c
,msgh_id
);
734 if (idx
< 0) return FALSE
;
736 ((hdlr_t
*)(c
->handlers
->data
))[idx
].type
= t
;
741 extern gboolean
echld_msgh_set_type(int child_id
, int msgh_id
, echld_msg_type_t t
) {
742 echld_t
* c
= get_child(child_id
);
743 return c
? msgh_set_type(c
,msgh_id
,t
) : FALSE
;
747 /* call cb(id,child_data,cb_data) for each child*/
748 extern void echld_foreach_child(echld_iter_cb_t cb
, void* cb_data
) {
750 for(i
=0;i
<ECHLD_MAX_CHILDREN
;i
++) {
751 echld_t
* c
= &(parent
.children
[i
]);
752 cb(c
->chld_id
,c
->data
,cb_data
);
756 static reqh_t
* get_req(echld_t
* c
, int reqh_id
) {
757 int idx
= reqh_id_idx(c
,reqh_id
);
758 if(idx
< 0) return NULL
;
760 return ((reqh_t
*)(c
->reqs
->data
))+idx
;
763 static hdlr_t
* get_next_hdlr_for_type(echld_t
* c
, echld_msg_type_t t
, int* cookie
) {
764 int imax
= c
->handlers
->len
;
767 for (;(*cookie
)<imax
;(*cookie
)++) {
768 if (((hdlr_t
*)(c
->handlers
->data
))[*cookie
].type
== t
) {
769 r
= &( ((hdlr_t
*)(c
->handlers
->data
))[*cookie
] );
778 static long parent_read_frame(guint8
* b
, size_t len
, echld_chld_id_t chld_id
, echld_msg_type_t t
, echld_reqh_id_t reqh_id
, void* data _U_
) {
779 echld_t
* c
= get_child(chld_id
);
780 GByteArray
* ba
= g_byte_array_new();
782 PARENT_DBG((1,"MSG_IN<- ch=%d t='%s' rh=%d",chld_id
,TY(t
),reqh_id
));
783 g_byte_array_append(ba
,b
, (guint
)len
);
786 reqh_t
* r
= get_req(c
, reqh_id
);
789 gboolean go_ahead
= TRUE
;
791 if (r
) { /* got that reqh_id */
793 go_ahead
= r
->cb(t
,ba
,r
->cb_data
);
802 PARENT_DBG((2,"handled by reqh_id=%d msg='%s'",reqh_id
,go_ahead
?"retrying":"done"));
806 while(go_ahead
&& ( h
= get_next_hdlr_for_type(c
,t
,&i
))) {
808 go_ahead
= h
->cb(t
,ba
,h
->cb_data
);
810 PARENT_DBG((2,"handled by t='%s' msgh_id=%d msg='%s'",TY(h
->type
), h
->id
,go_ahead
?"retrying":"done"));
813 PARENT_DBG((1,"parent_read_frame: No such child"));
816 g_byte_array_free(ba
,TRUE
);
820 extern int echld_fdset(fd_set
* rfds
, fd_set
* efds
) {
821 FD_SET(parent
.reader
.fd
, rfds
);
822 FD_SET(parent
.reader
.fd
, efds
);
823 FD_SET(parent
.dispatcher_fd
, efds
);
827 extern int echld_fd_read(fd_set
* rfds
, fd_set
* efds
) {
829 if (FD_ISSET(parent
.reader
.fd
,efds
) || FD_ISSET(parent
.dispatcher_fd
,efds
) ) {
830 /* Handle errored dispatcher */
831 PARENT_DBG((1,"parent errored"));
835 if (FD_ISSET(parent
.reader
.fd
,rfds
)) {
836 PARENT_DBG((3,"reading from dispatcher"));
837 echld_read_frame(&(parent
.reader
),parent_read_frame
,&(parent
));
843 extern int echld_select(int nfds _U_
, fd_set
* rfds
, fd_set
* wfds
, fd_set
* efds
, struct timeval
* timeout
) {
844 fd_set my_rfds
, my_wfds
, my_efds
;
848 if (rfds
== NULL
) { rfds
= &my_rfds
; FD_ZERO(rfds
); }
849 if (wfds
== NULL
) { wfds
= &my_wfds
; FD_ZERO(wfds
); }
850 if (efds
== NULL
) { efds
= &my_efds
; FD_ZERO(efds
); }
852 echld_fdset(rfds
,efds
);
854 PARENT_DBG((5,"Select()"));
855 r_nfds
= select(FD_SETSIZE
, rfds
, wfds
, efds
, timeout
);
857 echld_fd_read(rfds
,efds
);
862 extern echld_state_t
echld_wait(struct timeval
* timeout
) {
863 if ( echld_select(0, NULL
, NULL
, NULL
, timeout
) < 0) {
870 enc_msg_t
* echld_new_child_params(void) {
871 return (enc_msg_t
*)g_byte_array_new();
874 enc_msg_t
* echld_new_child_params_merge(enc_msg_t
* em1
, enc_msg_t
* em2
) {
875 GByteArray
* ba
= g_byte_array_new();
876 GByteArray
* b1
= (GByteArray
*)em1
;
877 GByteArray
* b2
= (GByteArray
*)em2
;
879 g_byte_array_append(ba
,b1
->data
,b1
->len
);
880 g_byte_array_append(ba
,b2
->data
,b2
->len
);
882 return (enc_msg_t
*)ba
;
885 char* echld_new_child_params_str(enc_msg_t
* em
, const char* prefix
, const char* postfix
, int trunc_n
, const char* fmt
) {
886 GByteArray
* ba
= (GByteArray
*)em
;
887 GString
* str
= g_string_new(prefix
);
888 char* p
= (char*) ba
->data
;
889 int tot_len
= ba
->len
;
891 p
[rem
-1] = '\0'; /* make sure last char is null */
895 long param_len
= strlen(param
)+1;
896 char* value
= p
+ param_len
;
902 g_string_free(str
,TRUE
);
906 value_len
= strlen(value
)+1;
909 p
= value
+ value_len
;
912 g_string_free(str
,TRUE
);
916 g_string_append_printf(str
,fmt
,param
,value
);
918 g_string_truncate(str
, str
->len
- trunc_n
);
919 g_string_append(str
,postfix
);
921 g_string_free(str
,FALSE
);
925 void echld_new_child_params_add_params(enc_msg_t
* em
, ...) {
926 GByteArray
* ba
= (GByteArray
*) em
;
931 char* param_str
= va_arg(ap
, char*);
934 char* val_str
= va_arg(ap
, char*);
936 g_byte_array_append(ba
, (guint8
*) param_str
, (guint
)strlen(param_str
)+1);
937 g_byte_array_append(ba
, (guint8
*) val_str
, (guint
)strlen(val_str
)+1);