HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / echld / parent.c
blobce48f03547b136c15b7f24598ac9294ca5247881
1 /* parent.c
2 * epan working child API internals
3 * Parent process routines and definitions
5 * $Id$
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.
28 #include "config.h"
30 #include "echld-int.h"
32 /**
33 PARENT and API
34 **/
36 #define MAX_PENDING_REQS 16;
38 typedef struct _req {
39 int reqh_id;
40 echld_msg_cb_t cb;
41 void* cb_data;
42 struct timeval tv;
43 } reqh_t;
45 typedef struct _hdlr {
46 int id;
47 echld_msg_type_t type;
48 echld_msg_cb_t cb;
49 void* cb_data;
50 } hdlr_t;
52 typedef struct _echld_child {
53 int chld_id;
54 void* data;
55 echld_new_cb_t cb;
56 child_state_t state;
57 GArray* handlers;
58 GArray* reqs;
59 } echld_t;
61 struct _echld_parent {
62 echld_t* children;
63 echld_reader_t reader;
64 int dispatcher_fd;
65 int dispatcher_pid;
66 int reqh_id;
67 GByteArray* snd;
68 int closing;
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;
77 #ifdef DEBUG_PARENT
79 static int dbg_level = DEBUG_PARENT;
81 static void parent_dbg(int level, const char* fmt, ...) {
82 va_list ap;
83 char str[1024];
85 if (level > dbg_level) return;
87 va_start(ap,fmt);
88 g_vsnprintf(str,1024,fmt,ap);
89 va_end(ap);
91 fprintf(stderr,"ParentDebug: level=%d msg='%s'\n",level,str);
92 fflush(stderr);
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)
98 #else
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)
101 #endif
103 extern void echld_set_parent_dbg_level(int lvl) {
104 (dbg_level = lvl);
105 if (lvl > 6) {
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, ...) {
115 va_list ap;
116 char str[1024];
118 va_start(ap,fmt);
119 g_vsnprintf(str,1024,fmt,ap);
120 va_end(ap);
122 #ifdef DEBUG_PARENT
123 PARENT_DBG((0,"Fatal error: exit_code=%d str=%s",exit_code,str));
124 #else
125 fprintf(stderr,"Fatal error: exit_code=%d str=%s",exit_code,str);
126 #endif
128 kill(parent.dispatcher_pid,SIGTERM);
129 exit(exit_code);
132 static void echld_cleanup(void) {
133 // int i;
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);
140 // };
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));
153 c->chld_id = -1;
154 c->data = NULL;
155 c->state = FREE;
156 g_array_set_size(c->handlers,0);
157 g_array_set_size(c->reqs,0);
161 void parent_reaper(int sig) {
162 int pid;
163 int status;
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) {
175 /* crashed */
176 sleep(120);
177 PARENT_FATAL((DISPATCHER_DEAD,"Dispatcher process dead"));
180 return;
181 } else {
182 /* XXX: do we care? */
183 return;
186 return;
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;
191 char* err = NULL;
192 int errnum = 0;
194 if (init && init->dispatcher_hello_cb) {
195 switch(type) {
196 case ECHLD_ERROR:
197 parent.dec->error(msg_buff, &errnum ,&err);
198 break;
199 case ECHLD_TIMED_OUT:
200 err = g_strdup("timedout");
201 break;
202 default:
203 err = g_strdup_printf("Wrong MSG 'HELLO' expected, got '%s",TY(type));
204 break;
205 case ECHLD_HELLO:
206 break;
209 init->dispatcher_hello_cb(ud,err);
210 if (err) g_free(err);
213 return TRUE;
218 /* will initialize epan registering protocols and taps */
219 void echld_initialize(echld_init_t* init) {
220 int from_disp[2];
221 int to_disp[2];
222 PARENT_DBG((1,"Echld Starting"));
224 if (!init) {
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"));
236 } else {
237 int pid;
238 int i;
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]));
242 pid = fork();
244 if ( pid < 0 ) {
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;
249 #endif
250 /* child code */
251 echld_cleanup();
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"));
259 } else {
260 /* parent code */
261 #ifdef PARENT_THREADS
262 reader_realloc_buf = parent_realloc_buff;
263 #endif
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);
290 //close(to_disp[0]);
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 */
307 echld_cleanup();
308 close(parent.dispatcher_fd);
309 kill(parent.dispatcher_pid,SIGTERM);
310 return TRUE;
316 static echld_t* get_child(int id) {
317 int i;
318 for (i=0;i<ECHLD_MAX_CHILDREN;i++) {
319 if (parent.children[i].chld_id == id) return &(parent.children[i]);
322 return NULL;
326 /* send a request */
328 int reqh_id_idx(echld_t* c, int reqh_id) {
329 int i;
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)
335 return i;
338 return -1;
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) {
343 int idx;
344 reqh_t* r;
345 int reqh_id = reqh_ids++;
347 if (!c) {
348 PARENT_DBG((1,"REQH_SND: No such child"));
349 return 1;
352 idx = reqh_id_idx(c,-1);
353 if (idx < 0) {
354 reqh_t req;
355 idx = c->reqs->len;
356 g_array_append_val(c->reqs,req);
359 r = &(((reqh_t*)c->reqs->data)[idx]);
361 r->reqh_id = reqh_id;
362 r->cb = resp_cb;
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? */
375 return reqh_id;
379 extern echld_reqh_id_t echld_reqh(
380 echld_chld_id_t child_id,
381 echld_msg_type_t t,
382 int usecs_timeout _U_,
383 enc_msg_t* ba,
384 echld_msg_cb_t resp_cb,
385 void* cb_data) {
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);
392 int idx;
394 if (!c) return NULL;
396 idx = reqh_id_idx(c,reqh_id);
398 if (idx >= 0)
399 return g_array_index(c->reqs, reqh_t, idx).cb_data;
400 else
401 return NULL;
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);
407 int idx;
409 if (!c) return NULL;
411 idx = reqh_id_idx(c,reqh_id);
413 if (idx >= 0)
414 return g_array_index(c->reqs, reqh_t, idx).cb;
415 else
416 return NULL;
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);
422 int idx;
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;
432 return TRUE;
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);
438 int idx;
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;
447 return TRUE;
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);
454 int idx;
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);
464 return TRUE;
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;
470 char* s;
472 if (type != ECHLD_CHILD_DEAD) {
473 PARENT_DBG((1, "Must Be ECHLD_CHILD_DEAD"));
474 return 1;
477 if ( parent.dec->child_dead(ba,&s) ) {
478 PARENT_DBG((1,"Dead Child[%d]: %s",c->chld_id,s));
479 g_free(s);
482 parent_child_cleanup(c);
483 return 0;
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;
488 int err_id;
489 char* err = NULL;
491 switch (type) {
492 case ECHLD_HELLO:
493 PARENT_DBG((1,"Child[%d]: =>IDLE",c->chld_id));
494 c->state = IDLE;
495 break;
496 case ECHLD_ERROR:
497 parent.dec->error(ba,&err_id,&err);
498 break;
499 case ECHLD_TIMED_OUT:
500 err = g_strdup("timedout");
501 break;
502 default:
503 err = g_strdup_printf("Wrong MSG 'HELLO' expected, got '%s",TY(type));
504 break;
507 if (c->cb)
508 c->cb(c->data,err);
510 if (err) g_free(err);
512 return TRUE;
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);
530 if (!c) return -1;
532 c->chld_id = (next_chld_id++);
533 c->data = child_data;
534 c->state = CREATING;
535 c->cb = cb;
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);
542 return c->chld_id;
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);
555 if (c) {
556 c->data = data;
557 return TRUE;
560 return FALSE;
563 static int msgh_idx(echld_t* c, int msgh_id) {
564 int i = 0;
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;
571 return -1;
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) {
576 hdlr_t h;
577 static int msgh_id = 1;
579 h.id = msgh_id++;
580 h.type = t;
581 h.cb = resp_cb;
582 h.cb_data = cb_data;
584 g_array_append_val(c->handlers,h);
585 return 0;
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);
592 else return -1;
596 /* stop it */
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);
604 return 1;
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);
658 hdlr_t* h;
660 if (idx < 0) return -1;
662 h = &(((hdlr_t*)(c->handlers->data))[idx]);
664 if (t) *t = h->type;
665 if (cb) *cb = h->cb;
666 if (data) *data = h->cb_data;
668 return 0;
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);
678 hdlr_t* h;
680 if (idx < 0) return -1;
682 h = &(((hdlr_t*)(c->handlers->data))[idx]);
684 h->type = t;
685 h->cb = cb;
686 h->cb_data = data;
688 return 0;
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;
704 return TRUE;
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;
721 return TRUE;
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;
738 return TRUE;
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) {
749 int i;
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;
765 hdlr_t* r = NULL;
767 for (;(*cookie)<imax;(*cookie)++) {
768 if (((hdlr_t*)(c->handlers->data))[*cookie].type == t) {
769 r = &( ((hdlr_t*)(c->handlers->data))[*cookie] );
770 (*cookie)++;
771 break;
775 return r;
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);
785 if (c) {
786 reqh_t* r = get_req(c, reqh_id);
787 int i;
788 hdlr_t* h;
789 gboolean go_ahead = TRUE;
791 if (r) { /* got that reqh_id */
792 if (r->cb) {
793 go_ahead = r->cb(t,ba,r->cb_data);
796 r->reqh_id = -1;
797 r->cb = NULL;
798 r->cb_data = 0;
799 r->tv.tv_sec = 0;
800 r->tv.tv_usec = 0;
802 PARENT_DBG((2,"handled by reqh_id=%d msg='%s'",reqh_id,go_ahead?"retrying":"done"));
805 i=0;
806 while(go_ahead && ( h = get_next_hdlr_for_type(c,t,&i))) {
807 if (h->cb)
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"));
812 } else {
813 PARENT_DBG((1,"parent_read_frame: No such child"));
816 g_byte_array_free(ba,TRUE);
817 return 1;
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);
824 return 2;
827 extern int echld_fd_read(fd_set* rfds, fd_set* efds) {
828 int r_nfds=0;
829 if (FD_ISSET(parent.reader.fd,efds) || FD_ISSET(parent.dispatcher_fd,efds) ) {
830 /* Handle errored dispatcher */
831 PARENT_DBG((1,"parent errored"));
832 return -1;
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));
840 return r_nfds;
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;
845 int r_nfds;
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);
859 return r_nfds ;
862 extern echld_state_t echld_wait(struct timeval* timeout) {
863 if ( echld_select(0, NULL, NULL, NULL, timeout) < 0) {
864 return -1;
865 } else {
866 return ECHLD_OK;
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;
890 long rem = tot_len;
891 p[rem-1] = '\0'; /* make sure last char is null */
893 while(rem > 2) {
894 char* param = p;
895 long param_len = strlen(param)+1;
896 char* value = p + param_len;
897 long value_len;
899 rem -= param_len;
901 if (rem < 0) {
902 g_string_free(str,TRUE);
903 return NULL;
906 value_len = strlen(value)+1;
908 rem -= value_len;
909 p = value + value_len;
911 if (rem < 0) {
912 g_string_free(str,TRUE);
913 return NULL;
916 g_string_append_printf(str,fmt,param,value);
918 g_string_truncate(str, str->len - trunc_n);
919 g_string_append(str,postfix);
920 p = str->str;
921 g_string_free(str,FALSE);
922 return p;
925 void echld_new_child_params_add_params(enc_msg_t* em, ...) {
926 GByteArray* ba = (GByteArray*) em;
927 va_list ap;
929 va_start(ap,em);
930 do {
931 char* param_str = va_arg(ap, char*);
933 if (param_str) {
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);
938 continue;
941 break;
942 } while(1);
943 va_end(ap);