From 1924fe8c26de2861744fd576631ad15da2759f51 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Fri, 28 Jan 2011 02:37:28 +0100 Subject: [PATCH] lib: Added more indirection for child handling. If at first you don't succceed, just add another layer of indirection. :) --- lib/cf.c | 127 +++++++++++++++++++++++++++++++++++++++-------------- lib/cf.h | 13 ++++-- src/dirplex/conf.c | 17 +------ src/patplex.c | 11 +---- 4 files changed, 106 insertions(+), 62 deletions(-) diff --git a/lib/cf.c b/lib/cf.c index fd53c54..38d9808 100644 --- a/lib/cf.c +++ b/lib/cf.c @@ -37,7 +37,16 @@ #define CH_SOCKET 0 #define CH_FORK 1 +struct stdchild { + int type; + char **argv; + int fd; +}; + static int parsefile(struct cfstate *s, FILE *in); +static void stdmerge(struct child *old, struct child *new); +static int stdhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata); +static void stddestroy(struct child *ch); static int doinclude(struct cfstate *s, char *spec) { @@ -242,28 +251,40 @@ char *findstdconf(char *name) return(NULL); } -static struct child *newchild(char *name, int type) +struct child *newchild(char *name, struct chandler *iface, void *pdata) { struct child *ch; omalloc(ch); ch->name = sstrdup(name); - ch->type = type; - ch->fd = -1; + ch->iface = iface; + ch->pdata = pdata; return(ch); } void freechild(struct child *ch) { - if(ch->fd != -1) - close(ch->fd); + if(ch->iface->destroy != NULL) + ch->iface->destroy(ch); if(ch->name != NULL) free(ch->name); - if(ch->argv != NULL) - freeca(ch->argv); free(ch); } +void mergechildren(struct child *dst, struct child *src) +{ + struct child *ch1, *ch2; + + for(ch1 = dst; ch1 != NULL; ch1 = ch1->next) { + for(ch2 = src; ch2 != NULL; ch2 = ch2->next) { + if(ch1->iface->merge && !strcmp(ch1->name, ch2->name)) { + ch1->iface->merge(ch1, ch2); + break; + } + } + } +} + void skipcfblock(struct cfstate *s) { char **w; @@ -275,9 +296,66 @@ void skipcfblock(struct cfstate *s) } } +static struct chandler stdhandler = { + .handle = stdhandle, + .merge = stdmerge, + .destroy = stddestroy, +}; + +static int stdhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata) +{ + struct stdchild *i = ch->pdata; + + if(i->type == CH_SOCKET) { + if(i->fd < 0) + i->fd = stdmkchild(i->argv, chinit, idata); + if(sendreq(i->fd, req, fd)) { + if((errno == EPIPE) || (errno == ECONNRESET)) { + /* Assume that the child has crashed and restart it. */ + close(i->fd); + i->fd = stdmkchild(i->argv, chinit, idata); + if(!sendreq(i->fd, req, fd)) + return(0); + } + flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno)); + close(i->fd); + i->fd = -1; + return(-1); + } + } else if(i->type == CH_FORK) { + if(stdforkserve(i->argv, req, fd, chinit, idata) < 0) + return(-1); + } + return(0); +} + +static void stdmerge(struct child *dst, struct child *src) +{ + struct stdchild *od, *nd; + + if(src->iface == &stdhandler) { + nd = dst->pdata; + od = src->pdata; + nd->fd = od->fd; + od->fd = -1; + } +} + +static void stddestroy(struct child *ch) +{ + struct stdchild *d = ch->pdata; + + if(d->fd >= 0) + close(d->fd); + if(d->argv) + freeca(d->argv); + free(d); +} + struct child *parsechild(struct cfstate *s) { struct child *ch; + struct stdchild *d; int i; int sl; @@ -289,7 +367,8 @@ struct child *parsechild(struct cfstate *s) skipcfblock(s); return(NULL); } - ch = newchild(s->argv[1], CH_SOCKET); + ch = newchild(s->argv[1], &stdhandler, omalloc(d)); + d->type = CH_SOCKET; } else if(!strcmp(s->argv[0], "fchild")) { s->expstart = 1; if(s->argc < 2) { @@ -297,10 +376,12 @@ struct child *parsechild(struct cfstate *s) skipcfblock(s); return(NULL); } - ch = newchild(s->argv[1], CH_FORK); + ch = newchild(s->argv[1], &stdhandler, omalloc(d)); + d->type = CH_FORK; } else { return(NULL); } + d->fd = -1; while(1) { getcfline(s); @@ -309,16 +390,16 @@ struct child *parsechild(struct cfstate *s) flog(LOG_WARNING, "%s:%i: too few parameters to `exec'", s->file, s->lno); continue; } - ch->argv = szmalloc(sizeof(*ch->argv) * s->argc); + d->argv = szmalloc(sizeof(*d->argv) * s->argc); for(i = 0; i < s->argc - 1; i++) - ch->argv[i] = sstrdup(s->argv[i + 1]); + d->argv[i] = sstrdup(s->argv[i + 1]); } else if(!strcmp(s->argv[0], "end") || !strcmp(s->argv[0], "eof")) { break; } else { flog(LOG_WARNING, "%s:%i: unknown directive `%s' in child declaration", s->file, s->lno, s->argv[0]); } } - if(ch->argv == NULL) { + if(d->argv == NULL) { flog(LOG_WARNING, "%s:%i: missing `exec' in child declaration %s", s->file, sl, ch->name); freechild(ch); return(NULL); @@ -328,25 +409,5 @@ struct child *parsechild(struct cfstate *s) int childhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata) { - if(ch->type == CH_SOCKET) { - if(ch->fd < 0) - ch->fd = stdmkchild(ch->argv, chinit, idata); - if(sendreq(ch->fd, req, fd)) { - if((errno == EPIPE) || (errno == ECONNRESET)) { - /* Assume that the child has crashed and restart it. */ - close(ch->fd); - ch->fd = stdmkchild(ch->argv, chinit, idata); - if(!sendreq(ch->fd, req, fd)) - return(0); - } - flog(LOG_ERR, "could not pass on request to child %s: %s", ch->name, strerror(errno)); - close(ch->fd); - ch->fd = -1; - return(-1); - } - } else if(ch->type == CH_FORK) { - if(stdforkserve(ch->argv, req, fd, chinit, idata) < 0) - return(-1); - } - return(0); + return(ch->iface->handle(ch, req, fd, chinit, idata)); } diff --git a/lib/cf.h b/lib/cf.h index a1eadb0..35529c2 100644 --- a/lib/cf.h +++ b/lib/cf.h @@ -15,9 +15,14 @@ struct cfstate { struct child { struct child *next; char *name; - int type; - char **argv; - int fd; + struct chandler *iface; + void *pdata; +}; + +struct chandler { + int (*handle)(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata); + void (*merge)(struct child *dst, struct child *src); + void (*destroy)(struct child *ch); }; void skipcfblock(struct cfstate *s); @@ -26,7 +31,9 @@ void freecfparser(struct cfstate *s); char **getcfline(struct cfstate *s); char *findstdconf(char *name); +struct child *newchild(char *name, struct chandler *iface, void *pdata); void freechild(struct child *ch); +void mergechildren(struct child *dst, struct child *src); struct child *parsechild(struct cfstate *s); int childhandle(struct child *ch, struct hthead *req, int fd, void (*chinit)(void *), void *idata); diff --git a/src/dirplex/conf.c b/src/dirplex/conf.c index 8494050..b90163a 100644 --- a/src/dirplex/conf.c +++ b/src/dirplex/conf.c @@ -252,21 +252,6 @@ struct config *readconfig(char *file) return(cf); } -static void mergechildren(struct config *dst, struct config *src) -{ - struct child *ch1, *ch2; - - for(ch1 = dst->children; ch1 != NULL; ch1 = ch1->next) { - for(ch2 = src->children; ch2 != NULL; ch2 = ch2->next) { - if(!strcmp(ch1->name, ch2->name)) { - ch1->fd = ch2->fd; - ch2->fd = -1; - break; - } - } - } -} - struct config *getconfig(char *path) { struct config *cf, *ocf; @@ -295,7 +280,7 @@ struct config *getconfig(char *path) mtime = sb.st_mtime; } if(ocf != NULL) { - mergechildren(cf, ocf); + mergechildren(cf->children, ocf->children); freeconfig(ocf); } cf->path = sstrdup(path); diff --git a/src/patplex.c b/src/patplex.c index 3b3d7f9..bf4fda9 100644 --- a/src/patplex.c +++ b/src/patplex.c @@ -446,21 +446,12 @@ static void serve(struct hthead *req, int fd) static void reloadconf(char *nm) { struct config *cf; - struct child *ch1, *ch2; if((cf = readconfig(nm)) == NULL) { flog(LOG_WARNING, "could not reload configuration file `%s'", nm); return; } - for(ch1 = cf->children; ch1 != NULL; ch1 = ch1->next) { - for(ch2 = lconfig->children; ch2 != NULL; ch2 = ch2->next) { - if(!strcmp(ch1->name, ch2->name)) { - ch1->fd = ch2->fd; - ch2->fd = -1; - break; - } - } - } + mergechildren(cf->children, lconfig->children); freeconfig(lconfig); lconfig = cf; } -- 2.11.0