KLone APIs | Modules | Data Structures | File List | Data Fields | Globals

server.c

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