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