Main Page | Modules | File List | Globals

server.c

00001 /*
00002  * Copyright (c) 2005, 2006 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: server.c,v 1.62 2008/04/17 10:49:04 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #ifdef HAVE_SYS_WAIT
00015 #include <sys/wait.h>
00016 #endif
00017 #include <u/libu.h>
00018 #include <stdlib.h>
00019 #include <unistd.h>
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <klone/server.h>
00023 #include <klone/backend.h>
00024 #include <klone/os.h>
00025 #include <klone/timer.h>
00026 #include <klone/context.h>
00027 #include <klone/ppc.h>
00028 #include <klone/ppc_cmd.h>
00029 #include <klone/addr.h>
00030 #include <klone/utils.h>
00031 #include <klone/klog.h>
00032 #include <klone/hook.h>
00033 #include <klone/hookprv.h>
00034 #include <klone/server_ppc_cmd.h>
00035 #include "server_s.h"
00036 #include "child.h"
00037 
00038 #define SERVER_MAX_BACKENDS 8
00039 
00040 enum watch_fd_e
00041 {
00042     WATCH_FD_READ   = 1 << 1,
00043     WATCH_FD_WRITE  = 1 << 2,
00044     WATCH_FD_EXCP   = 1 << 3
00045 };
00046 
00047 static void server_watch_fd(server_t *s, int fd, unsigned int mode);
00048 static void server_clear_fd(server_t *s, int fd, unsigned int mode);
00049 static void server_close_fd(server_t *s, int fd);
00050 
00051 static int server_be_listen(backend_t *be)
00052 {
00053     enum { DEFAULT_BACKLOG = 1024 };
00054     int d = 0, backlog = 0, val = 1;
00055     u_config_t *subkey;
00056 
00057     dbg_return_if (be == NULL, ~0);
00058     dbg_return_if (be->addr == NULL, ~0);
00059 
00060     switch(be->addr->type)
00061     {
00062         case ADDR_IPV4:
00063             dbg_err_if((d = socket(AF_INET, SOCK_STREAM, 0)) < 0);
00064             dbg_err_if(setsockopt(d, SOL_SOCKET, SO_REUSEADDR, (void *)&val, 
00065                 sizeof(int)) < 0);
00066             dbg_err_if(bind(d, (void*)&be->addr->sa.sin, 
00067                 sizeof(struct sockaddr_in)));
00068             break;
00069         case ADDR_IPV6:
00070         case ADDR_UNIX:
00071         default:
00072             crit_err_if("unupported addr type");
00073     }
00074 
00075     if(!u_config_get_subkey(be->config, "backlog", &subkey))
00076         backlog = atoi(u_config_get_value(subkey));
00077 
00078     if(!backlog)
00079         backlog = DEFAULT_BACKLOG;
00080 
00081     dbg_err_if(listen(d, backlog));
00082 
00083     be->ld = d;
00084 
00085     return 0;
00086 err:
00087     warn_strerror(errno);
00088     if(d)
00089         close(d);
00090     return ~0;
00091 }
00092 
00093 
00094 #ifdef OS_UNIX
00095 /* remove a child process whose pid is 'pid' to children list */
00096 static int server_reap_child(server_t *s, pid_t pid)
00097 {
00098     child_t *child;
00099     backend_t *be;
00100 
00101     dbg_err_if (s == NULL);
00102     
00103     /* get the child object */
00104     dbg_err_if(children_get_by_pid(s->children, pid, &child));
00105 
00106     /* remove the child from the list */
00107     dbg_err_if(children_del(s->children, child));
00108     be = child->be;
00109 
00110     /* check that the minimum number of process are active */
00111     be->nchild--;
00112     if(be->nchild < be->start_child)
00113         be->fork_child = be->start_child - be->nchild;
00114 
00115     U_FREE(child);
00116 
00117     return 0;
00118 err:
00119     return ~0;
00120 }
00121 
00122 /* add a child to the list */
00123 static int server_add_child(server_t *s, pid_t pid, backend_t *be)
00124 {
00125     child_t *child = NULL;
00126 
00127     dbg_err_if (s == NULL);
00128     dbg_err_if (be == NULL);
00129 
00130     dbg_err_if(child_create(pid, be, &child));
00131 
00132     dbg_err_if(children_add(s->children, child));
00133 
00134     be->nchild++;
00135 
00136     return 0;
00137 err:
00138     return ~0;
00139 }
00140 
00141 /* send 'sig' signal to all children process */
00142 static int server_signal_children(server_t *s, int sig)
00143 {
00144     child_t *child;
00145     ssize_t i;
00146 
00147     dbg_return_if (s == NULL, ~0);
00148     
00149     for(i = children_count(s->children) - 1; i >= 0; --i)
00150     {
00151         if(!children_getn(s->children, i, &child))
00152             dbg_err_if(kill(child->pid, sig) < 0);
00153     }
00154 
00155     return 0;
00156 err:
00157     dbg_strerror(errno);
00158     return ~0;
00159 }
00160 #endif
00161 
00162 static void server_term_children(server_t *s)
00163 {
00164     dbg_ifb(s == NULL) return;
00165 #ifdef OS_UNIX
00166     server_signal_children(s, SIGTERM);
00167 #endif
00168     return;
00169 }
00170 
00171 static void server_kill_children(server_t *s)
00172 {
00173     dbg_ifb(s == NULL) return;
00174 #ifdef OS_UNIX
00175     server_signal_children(s, SIGKILL);
00176 #endif
00177     return;
00178 }
00179 
00180 static void server_sigint(int sig)
00181 {
00182     u_unused_args(sig);
00183 
00184     warn("SIGINT");
00185 
00186     if(ctx && ctx->server)
00187         server_stop(ctx->server);
00188 }
00189 
00190 static void server_sigterm(int sig)
00191 {
00192     u_unused_args(sig);
00193 
00194     /* child process die immediately.
00195      * note: don't call debug functions because the parent process could be
00196      * already dead if the user used the "killall kloned" command */
00197     if(ctx->pipc)
00198         _exit(0); 
00199 
00200     warn("SIGTERM");
00201 
00202     if(ctx && ctx->server)
00203         server_stop(ctx->server);
00204 }
00205 
00206 #ifdef OS_UNIX
00207 static void server_sigchld(int sig)
00208 {
00209     server_t *s = ctx->server;
00210 
00211     u_unused_args(sig);
00212 
00213     s->reap_children = 1;
00214 }
00215 
00216 static void server_waitpid(server_t *s)
00217 {
00218     pid_t pid = -1;
00219     int status;
00220 
00221     dbg_ifb(s == NULL) return;
00222     
00223     u_sig_block(SIGCHLD);
00224 
00225     /* detach from child processes */
00226     while((pid = waitpid(-1, &status, WNOHANG)) > 0) 
00227     {
00228         if(WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS)
00229             warn("pid [%u], exit code [%d]", pid, WEXITSTATUS(status));
00230 
00231         if(WIFSIGNALED(status))
00232             warn("pid [%u], signal [%d]", pid, WTERMSIG(status));
00233 
00234         /* decrement child count */
00235         server_reap_child(s, pid);
00236     }
00237 
00238     s->reap_children = 0;
00239 
00240     u_sig_unblock(SIGCHLD);
00241 }
00242 #endif
00243 
00244 static void server_recalc_hfd(server_t *s)
00245 {
00246     register int i;
00247     fd_set *prdfds, *pwrfds, *pexfds;
00248 
00249     dbg_ifb(s == NULL) return;
00250     
00251     prdfds = &s->rdfds;
00252     pwrfds = &s->wrfds;
00253     pexfds = &s->exfds;
00254 
00255     /* set s->hfd to highest value */
00256     for(i = s->hfd, s->hfd = 0; i > 0; --i)
00257     {
00258         if(FD_ISSET(i, prdfds) || FD_ISSET(i, pwrfds) || FD_ISSET(i, pexfds))
00259         {
00260             s->hfd = i;
00261             break;
00262         }
00263     }
00264 }
00265 
00266 static void server_clear_fd(server_t *s, int fd, unsigned int mode)
00267 {
00268     dbg_ifb(s == NULL) return;
00269 
00270     if(mode & WATCH_FD_READ)
00271         FD_CLR(fd, &s->rdfds);
00272 
00273     if(mode & WATCH_FD_WRITE)
00274         FD_CLR(fd, &s->wrfds);
00275 
00276     if(mode & WATCH_FD_EXCP)
00277         FD_CLR(fd, &s->exfds);
00278 
00279     server_recalc_hfd(s);
00280 }
00281 
00282 static void server_watch_fd(server_t *s, int fd, unsigned int mode)
00283 {
00284     dbg_ifb(s == NULL) return;
00285     dbg_ifb(fd < 0) return;
00286 
00287     if(mode & WATCH_FD_READ)
00288         FD_SET(fd, &s->rdfds);
00289 
00290     if(mode & WATCH_FD_WRITE)
00291         FD_SET(fd, &s->wrfds);
00292 
00293     if(mode & WATCH_FD_EXCP)
00294         FD_SET(fd, &s->exfds);
00295 
00296     s->hfd = MAX(s->hfd, fd);
00297 }
00298 
00299 static void server_close_fd(server_t *s, int fd)
00300 {
00301     dbg_ifb(s == NULL) return;
00302     dbg_ifb(fd < 0) return;
00303 
00304     server_clear_fd(s, fd, WATCH_FD_READ | WATCH_FD_WRITE | WATCH_FD_EXCP);
00305     close(fd);
00306 }
00307 
00308 static int server_be_accept(server_t *s, backend_t *be, int *pfd)
00309 {
00310     struct sockaddr sa;
00311     int sa_len = sizeof(struct sockaddr);
00312     int ad;
00313 
00314     u_unused_args(s);
00315 
00316     dbg_return_if (be == NULL, ~0);
00317     dbg_return_if (pfd == NULL, ~0);
00318 
00319 again:
00320     ad = accept(be->ld, &sa, &sa_len);
00321     if(ad == -1 && errno == EINTR)
00322         goto again; /* interrupted */
00323     dbg_err_if(ad == -1); /* accept error */
00324 
00325     *pfd = ad;
00326 
00327     return 0;
00328 err:
00329     if(ad < 0)
00330         warn_strerror(errno);
00331     return ~0;
00332 }
00333 
00334 static int server_backend_detach(server_t *s, backend_t *be)
00335 {
00336     s->nbackend--;
00337 
00338     dbg_return_if (s == NULL, ~0);
00339     dbg_return_if (be == NULL, ~0);
00340 
00341     addr_free(be->addr);
00342     be->server = NULL;
00343     be->addr = NULL;
00344     be->config = NULL;
00345 
00346     close(be->ld);
00347     be->ld = -1;
00348 
00349     backend_free(be);
00350 
00351     return 0;
00352 }
00353 
00354 #ifdef OS_UNIX
00355 static int server_chroot_to(server_t *s, const char *dir)
00356 {
00357     dbg_return_if (s == NULL, ~0);
00358     dbg_return_if (dir == NULL, ~0);
00359 
00360     u_unused_args(s);
00361 
00362     dbg_err_if(chroot((char*)dir));
00363 
00364     dbg_err_if(chdir("/"));
00365 
00366     info("chroot'd: %s", dir);
00367 
00368     return 0;
00369 err:
00370     warn_strerror(errno);
00371     return ~0;
00372 }
00373 
00374 static int server_foreach_cb(struct dirent *d, const char *path, void *arg)
00375 {
00376     int *pfound = (int*)arg;
00377 
00378     u_unused_args(d, path);
00379 
00380     *pfound = 1;
00381 
00382     return ~0;
00383 }
00384 
00385 static int server_chroot_blind(server_t *s)
00386 {
00387     enum { BLIND_DIR_MODE = 0100 }; /* blind dir mode must be 0100 */
00388     char dir[U_PATH_MAX];
00389     struct stat st;
00390     int fd_dir = -1, found;
00391     pid_t child;
00392     unsigned int mask;
00393 
00394     dbg_err_if (s == NULL);
00395     dbg_err_if (s->chroot == NULL);
00396 
00397     dbg_err_if(u_path_snprintf(dir, U_PATH_MAX, U_PATH_SEPARATOR,
00398         "%s/kloned_blind_chroot_%d.dir", s->chroot, getpid()));
00399 
00400     /* create the blind dir (0100 mode) */
00401     dbg_err_if(mkdir(dir, BLIND_DIR_MODE ));
00402 
00403     /* get the fd of the dir */
00404     dbg_err_if((fd_dir = open(dir, O_RDONLY, 0)) < 0);
00405 
00406     dbg_err_if((child = fork()) < 0);
00407 
00408     if(child == 0)
00409     {   /* child */
00410 
00411         /* delete the chroot dir and exit */
00412         sleep(1); // FIXME use a lock here
00413         dbg("[child] removing dir: %s\n", dir);
00414         rmdir(dir);
00415         _exit(0);
00416     }
00417     /* parent */
00418 
00419     /* do chroot */
00420     dbg_err_if(server_chroot_to(s, dir));
00421 
00422     /* do some dir sanity checks */
00423 
00424     /* get stat values */
00425     dbg_err_if(fstat(fd_dir, &st));
00426 
00427     /* the dir owned must be root */
00428     dbg_err_if(st.st_gid || st.st_uid);
00429 
00430     /* the dir mode must be 0100 */
00431     dbg_err_if((st.st_mode & 07777) != BLIND_DIR_MODE);
00432 
00433     /* the dir must be empty */
00434     found = 0;
00435     mask = S_IFIFO | S_IFCHR | S_IFDIR | S_IFBLK | S_IFREG | S_IFLNK | S_IFSOCK;
00436     dbg_err_if(u_foreach_dir_item("/", mask, server_foreach_cb, &found));
00437 
00438     /* bail out if the dir is not empty */
00439     dbg_err_if(found);
00440 
00441     close(fd_dir);
00442 
00443     return 0;
00444 err:
00445     if(fd_dir >= 0)
00446         close(fd_dir);
00447     warn_strerror(errno);
00448     return ~0;
00449 }
00450 
00451 static int server_chroot(server_t *s)
00452 {
00453     dbg_return_if (s == NULL, ~0);
00454 
00455     if(s->blind_chroot)
00456         return server_chroot_blind(s);
00457     else
00458         return server_chroot_to(s, s->chroot);
00459 }
00460 
00461 static int server_drop_privileges(server_t *s)
00462 {
00463     uid_t uid;
00464     gid_t gid;
00465 
00466     dbg_return_if (s == NULL, ~0);
00467 
00468     if(s->gid > 0)
00469     {
00470         gid = (gid_t)s->gid;
00471 
00472         /* remove all groups except gid */
00473         dbg_err_if(setgroups(1, &gid));
00474 
00475         /* set gid */
00476         dbg_err_if(setgid(gid));
00477         dbg_err_if(setegid(gid));
00478 
00479         /* verify */
00480         dbg_err_if(getgid() != gid || getegid() != gid);
00481     }
00482 
00483     if(s->uid > 0)
00484     {
00485         uid = (uid_t)s->uid;
00486 
00487         /* set uid */
00488         dbg_err_if(setuid(uid));
00489         dbg_err_if(seteuid(uid));
00490 
00491         /* verify */
00492         dbg_err_if(getuid() != uid || geteuid() != uid);
00493     }
00494     
00495     return 0;
00496 err:
00497     warn_strerror(errno);
00498     return ~0;
00499 }
00500 
00501 static int server_fork_child(server_t *s, backend_t *be)
00502 {
00503     backend_t *obe; /* other backed */
00504     pid_t child;
00505     int socks[2];
00506 
00507     dbg_return_if (s == NULL, -1);
00508     dbg_return_if (be == NULL, -1);
00509     /* exit on too much children */
00510     dbg_return_if (children_count(s->children) == s->max_child, -1);
00511     dbg_return_if (be->nchild == be->max_child, -1);
00512 
00513     /* create a parent<->child IPC channel */
00514     dbg_err_if(socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0);
00515 
00516     if((child = fork()) == 0)
00517     {   /* child */
00518 
00519         /* never flush, the parent process will */
00520         s->klog_flush = 0;
00521 
00522         /* reseed the PRNG */
00523         srand(rand() + getpid() + time(0));
00524 
00525         /* close one end of the channel */
00526         close(socks[0]);
00527 
00528         /* save parent PPC socket and close the other */
00529         ctx->pipc = socks[1];
00530         ctx->backend = be;
00531 
00532         /* close listening sockets of other backends */
00533         LIST_FOREACH(obe, &s->bes, np)
00534         {
00535             if(obe == be)
00536                 continue;
00537             close(obe->ld);
00538             obe->ld = -1;
00539         }
00540 
00541         /* clear child copy of children list */
00542         dbg_err_if(children_clear(s->children));
00543 
00544     } else if(child > 0) {
00545         /* parent */
00546 
00547         /* save child pid and increment child count */
00548         server_add_child(s, child, be);
00549 
00550         /* close one end of the channel */
00551         close(socks[1]);
00552 
00553         /* watch the PPC socket connected to the child */
00554         server_watch_fd(s, socks[0], WATCH_FD_READ);
00555     } else {
00556         warn_err("fork error");
00557     }
00558 
00559     return child;
00560 err:
00561     warn_strerror(errno);
00562     return -1;
00563 }
00564 
00565 static int server_child_serve(server_t *s, backend_t *be, int ad)
00566 {
00567     pid_t child;
00568 
00569     dbg_return_if (s == NULL, ~0);
00570     dbg_return_if (be == NULL, ~0);
00571 
00572     dbg_err_if((child = server_fork_child(s, be)) < 0);
00573 
00574     if(child == 0)
00575     {   /* child */
00576 
00577         /* close this be listening descriptor */
00578         close(be->ld);
00579 
00580         hook_call(child_init);
00581 
00582         /* serve the page */
00583         dbg_if(backend_serve(be, ad));
00584 
00585         hook_call(child_term);
00586 
00587         /* close client socket and die */
00588         close(ad);
00589         server_stop(be->server); 
00590     }
00591     /* parent */
00592 
00593     return 0;
00594 err:
00595     warn_strerror(errno);
00596     return ~0;
00597 }
00598 
00599 static int server_cb_spawn_child(talarm_t *al, void *arg)
00600 {
00601     server_t *s = (server_t*)arg;
00602 
00603     u_unused_args(al);
00604 
00605     dbg_err_if (s == NULL);
00606 
00607     /* must be called by a child process */
00608     dbg_err_if(ctx->backend == NULL || ctx->pipc == 0);
00609 
00610     /* ask the parent to create a new worker child process */
00611     dbg_err_if(server_ppc_cmd_fork_child(s, ctx->backend));
00612 
00613     /* mark the current child process so it will die when finishes 
00614        serving this page */
00615     server_stop(s);
00616 
00617     return 0;
00618 err:
00619     return ~0;
00620 }
00621 #endif /* ifdef OS_UNIX */
00622 
00623 static int server_be_serve(server_t *s, backend_t *be, int ad)
00624 {
00625     talarm_t *al = NULL;
00626 
00627     dbg_err_if (s == NULL);
00628     dbg_err_if (be == NULL);
00629     
00630     switch(be->model)
00631     {
00632 #ifdef OS_UNIX
00633     case SERVER_MODEL_FORK:
00634         /* spawn a child to handle the request */
00635         dbg_err_if(server_child_serve(s, be, ad));
00636         break;
00637 
00638     case SERVER_MODEL_PREFORK: 
00639         /* FIXME lower timeout value may be needed */
00640         /* if _serve takes more then 1 second spawn a new worker process */
00641         dbg_err_if(timerm_add(1, server_cb_spawn_child, (void*)s, &al));
00642 
00643         /* serve the page */
00644         dbg_if(backend_serve(be, ad));
00645 
00646         /* remove and free the alarm */
00647         timerm_del(al); /* prefork */
00648         break;
00649 #endif
00650 
00651     case SERVER_MODEL_ITERATIVE:
00652         /* serve the page */
00653         dbg_if(backend_serve(be, ad));
00654         break;
00655 
00656     default:
00657         warn_err_if("server model not supported");
00658     }
00659 
00660     /* close the accepted (already served) socket */
00661     close(ad);
00662 
00663     return 0;
00664 err:
00665     close(ad);
00666     return ~0;
00667 }
00668 
00669 int server_stop(server_t *s)
00670 {
00671     dbg_err_if (s == NULL);
00672     
00673     if(ctx->pipc)
00674     {   /* child process */
00675 
00676         dbg_err_if(ctx->backend == NULL);
00677 
00678         /* close child listening sockets to force accept(2) to exit */
00679         close(ctx->backend->ld);
00680     }
00681 
00682     /* stop the parent process */
00683     s->stop = 1;
00684 
00685     return 0;
00686 err:
00687     return ~0;
00688 }
00689 
00690 static int server_listen(server_t *s)
00691 {
00692     backend_t *be;
00693 
00694     dbg_err_if (s == NULL);
00695     
00696     LIST_FOREACH(be, &s->bes, np)
00697     {
00698         /* bind to be->addr */
00699         dbg_err_if(server_be_listen(be));
00700 
00701         /* watch the listening socket */
00702         if(be->model != SERVER_MODEL_PREFORK)
00703             server_watch_fd(s, be->ld, WATCH_FD_READ);
00704     }
00705 
00706     return 0;
00707 err:
00708     return ~0;
00709 }
00710 
00711 int server_cgi(server_t *s)
00712 {
00713     backend_t *be;
00714 
00715     dbg_err_if (s == NULL);
00716 
00717     /* use the first http backend as the CGI backend */
00718     LIST_FOREACH(be, &s->bes, np)
00719     {
00720         if(strcasecmp(be->proto, "http") == 0)
00721         {
00722             hook_call(server_init);
00723 
00724             dbg_if(backend_serve(be, 0));
00725 
00726             hook_call(server_term);
00727 
00728             return 0;
00729         }
00730     }
00731 
00732 err: /* fall through if search loop exhausted */
00733     return ~0;
00734 }
00735 
00736 ppc_t* server_get_ppc(server_t *s)
00737 {
00738     dbg_return_if (s == NULL, NULL);
00739 
00740     return s->ppc;
00741 }
00742 
00743 static int server_process_ppc(server_t *s, int fd)
00744 {
00745     unsigned char cmd;
00746     char data[PPC_MAX_DATA_SIZE];
00747     ssize_t n;
00748 
00749     dbg_err_if (s == NULL);
00750     dbg_err_if (fd < 0);
00751 
00752     /* get a ppc request */
00753     n = ppc_read(s->ppc, fd, &cmd, data, PPC_MAX_DATA_SIZE); 
00754     if(n > 0)
00755     {   
00756         /* process a ppc (parent procedure call) request */
00757         dbg_err_if(ppc_dispatch(s->ppc, fd, cmd, data, n));
00758     } else if(n == 0) {
00759         /* child has exit or closed the channel. close our side of the sock 
00760            and remove it from the watch list */
00761         server_close_fd(s, fd);
00762     } else {
00763         /* ppc error. close fd and remove it from the watch list */
00764         server_close_fd(s, fd);
00765     }
00766 
00767     return 0;
00768 err:
00769     return ~0;
00770 }
00771 
00772 static int server_set_socket_opts(server_t *s, int sock)
00773 {
00774     int on = 1; 
00775 
00776     u_unused_args(s);
00777 
00778     dbg_err_if (sock < 0);
00779 
00780     /* disable Nagle algorithm */
00781     warn_err_sif(setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 
00782         (void*) &on, sizeof(int)) < 0);
00783 
00784     return 0;
00785 err:
00786     return ~0;
00787 }
00788 
00789 static int server_dispatch(server_t *s, int fd)
00790 {
00791     backend_t *be;
00792     int ad = -1; 
00793 
00794     dbg_err_if (s == NULL);
00795 
00796     /* find the backend that listen on fd */
00797     LIST_FOREACH(be, &s->bes, np)
00798         if(be->ld == fd)
00799             break;
00800 
00801     if(be == NULL) /* a child is ppc-calling */
00802         return server_process_ppc(s, fd);
00803 
00804     /* accept the pending connection */
00805     dbg_err_if(server_be_accept(s, be, &ad));
00806 
00807     /* set socket options on accepted socket */
00808     dbg_err_if(server_set_socket_opts(s, ad));
00809 
00810     /* serve the page */
00811     dbg_err_if(server_be_serve(s, be, ad));
00812 
00813     return 0;
00814 err:
00815     U_CLOSE(ad);
00816     return ~0;
00817 }
00818 
00819 int server_cb_klog_flush(talarm_t *a, void *arg)
00820 {
00821     server_t *s = (server_t*)arg;
00822 
00823     u_unused_args(a);
00824 
00825     dbg_return_if (s == NULL, ~0);
00826 
00827     /* set a flag to flush the klog object in server_loop */
00828     s->klog_flush++;
00829 
00830     return 0;
00831 }
00832 
00833 #ifdef OS_UNIX
00834 int server_spawn_child(server_t *s, backend_t *be)
00835 {
00836     size_t c;
00837     int rc;
00838 
00839     dbg_err_if (s == NULL);
00840     dbg_err_if (be == NULL);
00841 
00842     dbg_err_if((rc = server_fork_child(s, be)) < 0);
00843     if(rc > 0)
00844         return 0; /* parent */
00845 
00846     /* call the hook that runs the on-child user code */
00847     hook_call(child_init);
00848 
00849     /* child main loop: 
00850        close on s->stop or if max # of request limit has reached (the 
00851        server will respawn a new process if needed) */
00852     for(c = 0; !s->stop && c < be->max_rq_xchild; ++c)
00853     {
00854         /* wait for a new client (will block on accept(2)) */
00855         dbg_err_if(server_dispatch(s, be->ld));
00856     }
00857 
00858     /* before child shutdowns call the term hook */
00859     hook_call(child_term);
00860 
00861     server_stop(s);
00862 
00863     return 0;
00864 err:
00865     return ~0;
00866 }
00867 
00868 /* spawn pre-fork child processes */
00869 static int server_spawn_children(server_t *s)
00870 {
00871     backend_t *be;
00872     register size_t i;
00873 
00874     dbg_err_if (s == NULL);
00875 
00876     /* spawn N child process that will sleep asap into accept(2) */
00877     LIST_FOREACH (be, &s->bes, np)
00878     {
00879         if(be->model != SERVER_MODEL_PREFORK || be->fork_child == 0)
00880             continue;
00881 
00882         /* spawn be->fork_child child processes */
00883         for(i = 0; i < be->fork_child; ++i)
00884         {
00885             dbg_err_if(server_spawn_child(s, be));
00886             /* child context? */
00887             if(ctx->pipc)
00888                 break; /* the child previously spawned is dying, exit */
00889             be->fork_child--;
00890         }
00891     }
00892 
00893     return 0;
00894 err:
00895     return ~0;
00896 }
00897 #endif
00898 
00899 int server_loop(server_t *s)
00900 {
00901     struct timeval tv;
00902     int rc, fd;
00903     fd_set rdfds, wrfds, exfds;
00904 
00905     dbg_err_if (s == NULL);
00906     dbg_err_if (s->config == NULL);
00907 
00908     dbg_err_if(server_listen(s));
00909 
00910 #ifdef OS_UNIX
00911     /* if it's configured chroot to the dst dir */
00912     if(s->chroot)
00913         dbg_err_if(server_chroot(s));
00914 
00915     /* set uid/gid to non-root user */
00916     warn_err_sifm(server_drop_privileges(s), "unable to drop priviledges");
00917 
00918     /* if allow_root is not set check that we're not running as root */
00919     if(!s->allow_root)
00920         warn_err_ifm(!getuid() || !geteuid() || !getgid() || !getegid(),
00921             "you must set the allow_root config option to run kloned as root");
00922 #endif
00923 
00924     /* server startup hook */
00925     hook_call(server_init);
00926 
00927     for(; !s->stop; )
00928     {
00929 #ifdef OS_UNIX
00930         /* spawn new child if needed (may fail on resource limits) */
00931         dbg_if(server_spawn_children(s));
00932 #endif
00933 
00934         /* children in pre-fork mode exit here */
00935         if(ctx->pipc)
00936             break;
00937 
00938         memcpy(&rdfds, &s->rdfds, sizeof(fd_set));
00939         memcpy(&wrfds, &s->wrfds, sizeof(fd_set));
00940         memcpy(&exfds, &s->exfds, sizeof(fd_set));
00941 
00942         /* wake up every second */
00943         tv.tv_sec = 1; tv.tv_usec = 0;
00944 
00945     again:
00946         rc = select(1 + s->hfd, &rdfds, &wrfds, &exfds, &tv); 
00947         if(rc == -1 && errno == EINTR)
00948             goto again; /* interrupted */
00949         dbg_err_if(rc == -1); /* select error */
00950 
00951 #ifdef OS_UNIX
00952         if(s->reap_children)
00953             server_waitpid(s);
00954 #endif
00955 
00956         /* call klog_flush if flush timeout has expired and select() timeouts */
00957         if(s->klog_flush && ctx->pipc == 0)
00958         {
00959             /* flush the log buffer */
00960             klog_flush(s->klog);
00961 
00962             /* reset the flag */
00963             s->klog_flush = 0; 
00964 
00965             U_FREE(s->al_klog_flush);
00966 
00967             /* re-set the timer */
00968             dbg_err_if(timerm_add(SERVER_LOG_FLUSH_TIMEOUT, 
00969                 server_cb_klog_flush, s, &s->al_klog_flush));
00970         }
00971 
00972         /* for each signaled listening descriptor */
00973         for(fd = 0; rc && fd < 1 + s->hfd; ++fd)
00974         { 
00975             if(FD_ISSET(fd, &rdfds))
00976             {
00977                 --rc;
00978                 /* dispatch the request to the right backend */
00979                 dbg_if(server_dispatch(s, fd));
00980             } 
00981         } /* for each ready fd */
00982 
00983     } /* !s->stop */
00984 
00985     /* children in fork mode exit here */
00986     if(ctx->pipc)
00987         return 0;
00988 
00989     /* server shutdown hook */
00990     hook_call(server_term);
00991 
00992     /* shutdown all children */
00993     server_term_children(s);
00994 
00995     sleep(1);
00996 
00997     /* brute kill children process */
00998     if(s->nchild)
00999         server_kill_children(s);
01000 
01001     return 0;
01002 err:
01003     return ~0;
01004 }
01005 
01006 int server_free(server_t *s)
01007 {
01008     backend_t *be;
01009 
01010     dbg_err_if (s == NULL);
01011 
01012     /* remove the hook (that needs the server_t object) */
01013     u_log_set_hook(NULL, NULL, NULL, NULL);
01014 
01015     /* remove klog flushing alarm */
01016     if(s->al_klog_flush)
01017     {
01018         timerm_del(s->al_klog_flush);
01019         s->al_klog_flush = NULL;
01020     }
01021 
01022     if(s->klog)
01023     {
01024         /* child processes must not close klog when in 'file' mode, because 
01025            klog_file_t will flush data that the parent already flushed 
01026            (children inherit a "used" FILE* that will usually contain, on close,
01027            not-empty buffer that fclose (called by exit()) flushes). same 
01028            thing may happens with different log devices when buffers are used.
01029          */
01030         if(ctx->pipc == 0)
01031             klog_close(s->klog);
01032         s->klog = NULL;
01033     }
01034 
01035     while((be = LIST_FIRST(&s->bes)) != NULL)
01036     {
01037         LIST_REMOVE(be, np);
01038         server_backend_detach(s, be);
01039     }
01040 
01041     dbg_if(ppc_free(s->ppc));
01042 
01043     dbg_if(children_free(s->children));
01044 
01045 #ifdef OS_WIN
01046     WSACleanup();
01047 #endif
01048 
01049     U_FREE(s);
01050     return 0;
01051 err:
01052     return ~0;
01053 }
01054 
01055 static int server_setup_backend(server_t *s, backend_t *be)
01056 {
01057     u_config_t *subkey;
01058 
01059     dbg_return_if (s == NULL, ~0);
01060     dbg_return_if (be == NULL, ~0);
01061     
01062     /* server count */
01063     s->nbackend++;
01064 
01065     /* parse and create the bind addr_t */
01066     warn_err_ifm(u_config_get_subkey(be->config, "addr", &subkey),
01067         "missing or bad '<servname>.addr' value");
01068 
01069     dbg_err_if(addr_create(&be->addr));
01070 
01071     if(strcasecmp(be->proto, "https") == 0)
01072         dbg_err_if(addr_set_ipv4_port(be->addr, 443)); /* default https port */
01073     else
01074         dbg_err_if(addr_set_ipv4_port(be->addr, 80)); /* default http port */
01075 
01076     dbg_err_if(addr_set_from_config(be->addr, subkey));
01077 
01078     return 0;
01079 err:
01080     if(be->addr)
01081     {
01082         addr_free(be->addr);
01083         be->addr = NULL;
01084     }
01085     return ~0;
01086 }
01087 
01088 static int server_log_hook(void *arg, int level, const char *str)
01089 {
01090     server_t *s = (server_t*)arg;
01091     u_log_hook_t old = NULL;
01092     void *old_arg = NULL;
01093 
01094     dbg_err_if (s == NULL);
01095     dbg_err_if (str == NULL);
01096  
01097     /* if both the server and the calling backend have no log then exit */
01098     if(s->klog == NULL && (ctx->backend == NULL || ctx->backend->klog == NULL))
01099         return 0; /* log is disabled */
01100 
01101     /* disable log hooking in the hook itself otherwise an infinite loop 
01102        may happen if a log function is called from inside the hook */
01103     u_log_set_hook(NULL, NULL, &old, &old_arg);
01104 
01105     /* syslog klog doesn't go through ppc */
01106     if(s->klog->type == KLOG_TYPE_SYSLOG || ctx->pipc == 0)
01107     {   /* syslog klog or parent context */
01108         if(s->klog)
01109             dbg_err_if(klog(s->klog, syslog_to_klog(level), "%s", str));
01110     } else {
01111         /* children context */
01112         dbg_err_if(server_ppc_cmd_log_add(s, level, str));
01113     }
01114 
01115     /* re-set the old hook */
01116     u_log_set_hook(old, old_arg, NULL, NULL);
01117 
01118     return 0;
01119 err:
01120     if(old)
01121         u_log_set_hook(old, old_arg, NULL, NULL);
01122     return ~0;
01123 }
01124 
01125 int server_get_logger(server_t *s, klog_t **pkl)
01126 {
01127     klog_t *kl = NULL;
01128 
01129     dbg_err_if (s == NULL);
01130     dbg_err_if (pkl == NULL);
01131  
01132     if(ctx->backend)
01133         kl = ctx->backend->klog; /* may be NULL */
01134 
01135     if(kl == NULL)
01136         kl = s->klog; /* may be NULL */
01137 
01138     *pkl = kl;
01139 
01140     return 0;
01141 err:
01142     return ~0;
01143 }
01144 
01145 static int server_get_klog_line(server_t *s, klog_t *kl, size_t i, char *line)
01146 {
01147     backend_t *be = ctx->backend;
01148 
01149     dbg_err_if(kl->type != KLOG_TYPE_MEM);
01150     dbg_err_if(be == NULL);
01151 
01152     /* we need ppc just in prefork mode */
01153     if(be->model != SERVER_MODEL_PREFORK)
01154     {
01155         dbg_err_if(klog_getln(kl, i, line));
01156         return 0;
01157     }
01158 
01159     /* send the ppc command and read back the response */
01160     nop_err_if(server_ppc_cmd_log_get(s, i, line));
01161 
01162     return 0;
01163 err:
01164     return ~0;
01165 }
01166 
01167 int server_foreach_memlog_line(server_t *s, 
01168     int (*cb)(const char*, void*), void *arg)
01169 {
01170     klog_t *kl = NULL;  
01171     size_t i;
01172     char line[KLOG_LN_SZ];
01173 
01174     /* get the configured klog object and check that's a in-memory klog */
01175     if(server_get_logger(s, &kl) || kl == NULL || kl->type != KLOG_TYPE_MEM)
01176     {
01177         cb("logging is not configured or is not a in-memory log", arg);
01178         return ~0;
01179     }
01180 
01181     /* for each log line call the user-given callback function */
01182     for(i = 1; server_get_klog_line(s, kl, i, line) == 0; ++i)
01183         cb(line, arg);
01184 
01185     return 0;
01186 err:
01187     cb("klog_getln error", arg);
01188     return ~0;
01189 }
01190 
01191 
01192 int server_get_backend_by_id(server_t *s, int id, backend_t **pbe)
01193 {
01194     backend_t *be;
01195 
01196     dbg_err_if (s == NULL);
01197     dbg_err_if (pbe == NULL);
01198     
01199     LIST_FOREACH(be, &s->bes, np)
01200     {
01201         if(be->id == id)
01202         {
01203             *pbe = be;
01204             return 0;
01205         }
01206     }
01207 
01208 err: /* fall through if search loop exhausted */
01209     return ~0;
01210 }
01211 
01212 int server_create(u_config_t *config, int foreground, server_t **ps)
01213 {
01214     server_t *s = NULL;
01215     u_config_t *bekey = NULL, *log_c = NULL;
01216     backend_t *be = NULL;
01217     const char *list, *type;
01218     char *n = NULL, *name = NULL;
01219     int i, id, iv;
01220 
01221     dbg_return_if (ps == NULL, ~0);
01222     dbg_return_if (config == NULL, ~0);
01223 
01224 #ifdef OS_WIN
01225     WORD ver;
01226     WSADATA wsadata;
01227 
01228     ver = MAKEWORD(1,1);
01229     dbg_err_if(WSAStartup(ver, &wsadata));
01230 #endif
01231 
01232     s = u_zalloc(sizeof(server_t));
01233     dbg_err_if(s == NULL);
01234 
01235     *ps = s; /* we need it before backend inits */
01236 
01237     s->config = config;
01238     s->model = SERVER_MODEL_FORK; /* default */
01239 
01240     dbg_err_if(children_create(&s->children));
01241 
01242     /* init fd_set */
01243     FD_ZERO(&s->rdfds);
01244     FD_ZERO(&s->wrfds);
01245     FD_ZERO(&s->exfds);
01246 
01247     /* init backend list */
01248     LIST_INIT(&s->bes);
01249 
01250     dbg_err_if(ppc_create(&s->ppc));
01251 
01252     /* create the log device if requested */
01253     if(!u_config_get_subkey(config, "log", &log_c))
01254     {
01255         dbg_if(klog_open_from_config(log_c, &s->klog));
01256         s->klog_flush = 1;
01257     }
01258 
01259     /* register the log ppc callbacks */
01260     dbg_err_if(ppc_register(s->ppc, PPC_CMD_NOP, server_ppc_cb_nop, s));
01261     dbg_err_if(ppc_register(s->ppc, PPC_CMD_LOG_ADD, server_ppc_cb_log_add, s));
01262     dbg_err_if(ppc_register(s->ppc, PPC_CMD_LOG_GET, server_ppc_cb_log_get, s));
01263 #ifdef OS_UNIX
01264     dbg_err_if(ppc_register(s->ppc, PPC_CMD_FORK_CHILD, 
01265         server_ppc_cb_fork_child, s));
01266 #endif
01267     dbg_err_if(ppc_register(s->ppc, PPC_CMD_ACCESS_LOG, 
01268                 server_ppc_cb_access_log, s));
01269 
01270     /* redirect logs to the server_log_hook function */
01271     dbg_err_if(u_log_set_hook(server_log_hook, s, NULL, NULL));
01272 
01273     /* parse server list and build s->bes */
01274     list = u_config_get_subkey_value(config, "server_list");
01275     warn_err_ifm(list == NULL, "bad or missing 'server_list' config param");
01276 
01277     /* chroot, uid and gid */
01278     s->chroot = u_config_get_subkey_value(config, "chroot");
01279     dbg_err_if(u_config_get_subkey_value_i(config, "uid", -1, &s->uid));
01280     dbg_err_if(u_config_get_subkey_value_i(config, "gid", -1, &s->gid));
01281     dbg_err_if(u_config_get_subkey_value_b(config, "allow_root", 0, 
01282         &s->allow_root));
01283     dbg_err_if(u_config_get_subkey_value_b(config, "blind_chroot", 0, 
01284         &s->blind_chroot));
01285 
01286     warn_err_ifm(!s->uid || !s->gid, 
01287         "you must set uid and gid config parameters");
01288 
01289     dbg_err_if(u_config_get_subkey_value_i(config, "max_child", 
01290         SERVER_MAX_CHILD, &iv));
01291     s->max_child = iv;
01292 
01293     name = n = u_zalloc(strlen(list) + 1);
01294     dbg_err_if(name == NULL);
01295     
01296     /* load config and init backend for each server in server.list */
01297     for(i = strlen(list), id = 0; 
01298         i > 0 && sscanf(list, "%[^ \t]", name); 
01299         i -= 1 + strlen(name), list += 1 + strlen(name), name[0] = 0)
01300     {
01301         dbg("configuring backend: %s", name);
01302 
01303         /* just SERVER_MAX_BACKENDS supported */
01304         warn_err_if(s->nbackend == SERVER_MAX_BACKENDS);
01305 
01306         /* get config tree of this backend */
01307         warn_err_ifm(u_config_get_subkey(config, name, &bekey),
01308             "missing [%s] backend configuration", name);
01309 
01310         type = u_config_get_subkey_value(bekey, "type");
01311         warn_err_ifm(type == NULL, "missing or bad '<servname>.type' value");
01312 
01313         /* create a new backend and push it into the 'be' list */
01314         warn_err_ifm(backend_create(type, bekey, &be),
01315             "backend \"%s\" startup error", type);
01316 
01317         be->server = s;
01318         be->config = bekey;
01319         be->id = id++;
01320         if(be->model == SERVER_MODEL_UNSET)
01321             be->model = s->model; /* inherit server model */
01322 
01323         if(foreground)
01324             be->model = SERVER_MODEL_ITERATIVE;
01325 
01326         /* create the log device (may fail if logging is not configured) */
01327         if(!u_config_get_subkey(bekey, "log", &log_c))
01328             dbg_if(klog_open_from_config(log_c, &be->klog));
01329 
01330 #ifdef OS_WIN
01331         if(be->model != SERVER_MODEL_ITERATIVE)
01332             warn_err("child-based server model is not "
01333                      "yet supported on Windows");
01334 #endif
01335 
01336         LIST_INSERT_HEAD(&s->bes, be, np);
01337 
01338         dbg_err_if(server_setup_backend(s, be));
01339     }
01340 
01341     U_FREE(n);
01342 
01343     /* init done, set signal handlers */
01344     dbg_err_if(u_signal(SIGINT, server_sigint));
01345     dbg_err_if(u_signal(SIGTERM, server_sigterm));
01346 #ifdef OS_UNIX 
01347     dbg_err_if(u_signal(SIGPIPE, SIG_IGN));
01348     dbg_err_if(u_signal(SIGCHLD, server_sigchld));
01349 #endif
01350 
01351     return 0;
01352 err:
01353     warn("server init error (config error?)");
01354     U_FREE(n);
01355     if(s)
01356     {
01357         server_free(s);
01358         *ps = NULL;
01359     }
01360     return ~0;
01361 }
01362