home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / http_mai.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-01  |  44.2 KB  |  1,585 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * httpd.c: simple http daemon for answering WWW file requests
  57.  *
  58.  *
  59.  * 03-21-93  Rob McCool wrote original code (up to NCSA HTTPd 1.3)
  60.  *
  61.  * 03-06-95  blong
  62.  *  changed server number for child-alone processes to 0 and changed name
  63.  *   of processes
  64.  *
  65.  * 03-10-95  blong
  66.  *         Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu)
  67.  *        including set group before fork, and call gettime before to fork
  68.  *         to set up libraries.
  69.  *
  70.  * 04-14-95  rst / rh
  71.  *      Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
  72.  *      Apache server, and also to have child processes do accept() directly.
  73.  *
  74.  * April-July '95 rst
  75.  *      Extensive rework for Shambhala.
  76.  */
  77.  
  78.  
  79. #define CORE_PRIVATE
  80.  
  81. #include "httpd.h"
  82. #include "http_main.h"
  83. #include "http_log.h"
  84. #include "http_config.h"        /* for read_config */
  85. #include "http_protocol.h"        /* for read_request */
  86. #include "http_request.h"        /* for process_request */
  87. #include "http_conf_globals.h"
  88. #include "http_core.h"          /* for get_remote_host */
  89. #include "scoreboard.h"
  90. #include <setjmp.h>
  91. #ifdef HAVE_SHMGET
  92. #include <sys/types.h>
  93. #include <sys/ipc.h>
  94. #include <sys/shm.h>
  95. #if defined(AUX)                /* Aren't defined anyplace */
  96. extern char *shmat(int, char *, int);
  97. extern int  shmctl(int, int, struct shmid_ds *);
  98. extern int  shmget(key_t, int, int);
  99. extern char *sbrk(int);
  100. #endif
  101. #endif
  102. #ifdef SecureWare
  103. #include <sys/security.h>
  104. #include <sys/audit.h>
  105. #include <prot.h>
  106. #endif
  107.  
  108. /*
  109.  * Actual definitions of config globals... here because this is
  110.  * for the most part the only code that acts on 'em.  (Hmmm... mod_main.c?)
  111.  */
  112.  
  113. int standalone;
  114. uid_t user_id;
  115. char *user_name;
  116. gid_t group_id;
  117. int max_requests_per_child;
  118. char *pid_fname;
  119. char *scoreboard_fname;
  120. char *server_argv0;
  121. struct in_addr bind_address;
  122. listen_rec *listeners;
  123. int daemons_to_start;
  124. int daemons_min_free;
  125. int daemons_max_free;
  126. int daemons_limit;
  127. time_t restart_time;
  128.  
  129. char server_root[MAX_STRING_LEN];
  130. char server_confname[MAX_STRING_LEN];
  131.  
  132. /* *Non*-shared http_main globals... */
  133.  
  134. server_rec *server_conf;
  135. JMP_BUF jmpbuffer;
  136. JMP_BUF restart_buffer;
  137. int sd;
  138. static fd_set listenfds;
  139. static int listenmaxfd;
  140. pid_t pgrp;
  141.  
  142. /* one_process --- debugging mode variable; can be set from the command line
  143.  * with the -X flag.  If set, this gets you the child_main loop running
  144.  * in the process which originally started up (no detach, no make_child),
  145.  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
  146.  * early in standalone_main; just continue through.  This is the server
  147.  * trying to kill off any child processes which it might have lying
  148.  * around --- Shambhala doesn't keep track of their pids, it just sends
  149.  * SIGHUP to the process group, ignoring it in the root process.
  150.  * Continue through and you'll be fine.).
  151.  */
  152.  
  153. int one_process = 0;
  154.  
  155. #if defined(FCNTL_SERIALIZED_ACCEPT)
  156. static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
  157. static struct flock unlock_it = { F_UNLCK, 0, 0, 0 };
  158.  
  159. static int lock_fd=-1;
  160.  
  161. /*
  162.  * Initialize mutex lock.
  163.  * Must be safe to call this on a restart.
  164.  */
  165. void
  166. accept_mutex_init(pool *p)
  167. {
  168.     char lock_fname[30];
  169.  
  170.     strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
  171.  
  172.     if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
  173.     {
  174.         fprintf (stderr, "Cannot assign name to lock file!\n");
  175.         exit (1);
  176.     }
  177.  
  178.     lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
  179.     if (lock_fd == -1)
  180.     {
  181.         perror ("open");
  182.         fprintf (stderr, "Cannot open lock file: %s\n", lock_fname);
  183.         exit (1);
  184.     }
  185.     unlink(lock_fname);
  186. }
  187.  
  188. void accept_mutex_on()
  189. {
  190.     int ret;
  191.  
  192.     while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
  193.         continue;
  194.  
  195.     if (ret < 0) {
  196.         log_unixerr("fcntl", "F_SETLKW", "Error getting accept lock. Exiting!",
  197.                     server_conf);
  198.         exit(1);
  199.     }
  200. }
  201.  
  202. void accept_mutex_off()
  203. {
  204.     if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
  205.     {
  206.         log_unixerr("fcntl", "F_SETLKW", "Error freeing accept lock. Exiting!",
  207.                     server_conf);
  208.         exit(1);
  209.     }
  210. }
  211. #elif defined(FLOCK_SERIALIZED_ACCEPT)
  212.  
  213. static int lock_fd=-1;
  214.  
  215. /*
  216.  * Initialize mutex lock.
  217.  * Must be safe to call this on a restart.
  218.  */
  219. void
  220. accept_mutex_init(pool *p)
  221. {
  222.     char lock_fname[30];
  223.  
  224.     strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
  225.  
  226.     if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
  227.     {
  228.         fprintf (stderr, "Cannot assign name to lock file!\n");
  229.         exit (1);
  230.     }
  231.  
  232.     lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
  233.     if (lock_fd == -1)
  234.     {
  235.         perror ("open");
  236.         fprintf (stderr, "Cannot open lock file\n");
  237.         exit (1);
  238.     }
  239.     unlink(lock_fname);
  240. }
  241.  
  242. void accept_mutex_on()
  243. {
  244.     int ret;
  245.  
  246.     while ((ret = flock(lock_fd, LOCK_EX)) < 0 && errno == EINTR)
  247.         continue;
  248.  
  249.     if (ret < 0) {
  250.         log_unixerr("flock", "LOCK_EX", "Error getting accept lock. Exiting!",
  251.                     server_conf);
  252.         exit(1);
  253.     }
  254. }
  255.  
  256. void accept_mutex_off()
  257. {
  258.     if (flock (lock_fd, LOCK_UN) < 0)
  259.     {
  260.         log_unixerr("flock", "LOCK_UN", "Error freeing accept lock. Exiting!",
  261.                     server_conf);
  262.         exit(1);
  263.     }
  264. }
  265. #else
  266. /* Default --- no serialization.  Other methods *could* go here,
  267.  * as #elifs...
  268.  */
  269. #define accept_mutex_init(x)
  270. #define accept_mutex_on()
  271. #define accept_mutex_off()
  272. #endif
  273.  
  274. void usage(char *bin)
  275. {
  276.     fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin);
  277.     fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n");
  278.     fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n");
  279.     exit(1);
  280. }
  281.  
  282. /*****************************************************************
  283.  *
  284.  * Timeout handling.  DISTINCTLY not thread-safe, but all this stuff
  285.  * has to change for threads anyway.  Note that this code allows only
  286.  * one timeout in progress at a time...
  287.  */
  288.  
  289. static conn_rec *current_conn;
  290. static request_rec *timeout_req;
  291. static char *timeout_name = NULL;
  292. static int alarms_blocked = 0;
  293. static int alarm_pending = 0;
  294.  
  295. void abort_connection (conn_rec *);
  296.  
  297. void timeout(sig)                        /* Also called on SIGPIPE */
  298. int sig;
  299. {
  300.     char errstr[MAX_STRING_LEN];
  301.     void *dirconf;
  302.  
  303.     signal(SIGPIPE, SIG_IGN);                /* Block SIGPIPE */
  304.     if (alarms_blocked) {
  305.         alarm_pending = 1;
  306.         return;
  307.     }
  308.  
  309.     if (!current_conn) {
  310. #ifdef NEXT
  311.         longjmp(jmpbuffer,1);
  312. #else
  313.         siglongjmp(jmpbuffer,1);
  314. #endif
  315.     }
  316.  
  317.     if (timeout_req != NULL) dirconf = timeout_req->per_dir_config;
  318.     else dirconf = current_conn->server->lookup_defaults;
  319.     if (sig == SIGPIPE) {
  320.         sprintf(errstr,"%s lost connection to client %s",
  321.             timeout_name ? timeout_name : "request",
  322.             get_remote_host(current_conn, dirconf, REMOTE_NAME));
  323.     } else {
  324.         sprintf(errstr,"%s timed out for %s",
  325.             timeout_name ? timeout_name : "request",
  326.             get_remote_host(current_conn, dirconf, REMOTE_NAME));
  327.     }
  328.  
  329.     if (!current_conn->keptalive)
  330.        log_error(errstr, current_conn->server);
  331.  
  332.     if (timeout_req) {
  333.         /* Someone has asked for this transaction to just be aborted
  334.          * if it times out...
  335.          */
  336.  
  337.         request_rec *log_req = timeout_req;
  338.  
  339.         while (log_req->main || log_req->prev) {
  340.             /* Get back to original request... */
  341.             if (log_req->main) log_req = log_req->main;
  342.             else log_req = log_req->prev;
  343.         }
  344.  
  345.         if (!current_conn->keptalive)
  346.             log_transaction(log_req);
  347.  
  348.         bclose(timeout_req->connection->client);
  349.  
  350.         if (!standalone) exit(0);
  351. #ifdef NEXT
  352.         longjmp(jmpbuffer,1);
  353. #else
  354.         siglongjmp(jmpbuffer,1);
  355. #endif
  356.     }
  357.     else {
  358.         abort_connection (current_conn);
  359.     }
  360. }
  361.  
  362. /*
  363.  * These two called from alloc.c to protect its critical sections...
  364.  * Note that they can nest (as when destroying the sub_pools of a pool
  365.  * which is itself being cleared); we have to support that here.
  366.  */
  367.  
  368. void block_alarms() {
  369.     ++alarms_blocked;
  370. }
  371.  
  372. void unblock_alarms() {
  373.     --alarms_blocked;
  374.     if (alarms_blocked == 0 && alarm_pending) {
  375.         alarm_pending = 0;
  376.         timeout(0);
  377.     }
  378. }
  379.  
  380. void hard_timeout (char *name, request_rec *r)
  381. {
  382.     timeout_req = r;
  383.     timeout_name = name;
  384.  
  385.     signal(SIGALRM,(void (*)())timeout);
  386.     if (r->connection->keptalive)
  387.        alarm (r->server->keep_alive_timeout);
  388.     else
  389.        alarm (r->server->timeout);
  390. }
  391.  
  392. void soft_timeout (char *name, request_rec *r)
  393. {
  394.     timeout_name = name;
  395.  
  396.     signal(SIGALRM,(void (*)())timeout);
  397.     alarm (r->server->timeout);
  398. }
  399.  
  400. void kill_timeout (request_rec *dummy) {
  401.     alarm (0);
  402.     timeout_req = NULL;
  403.     timeout_name = NULL;
  404. }
  405.  
  406. /* reset_timeout (request_rec *) resets the timeout in effect,
  407.  * as long as it hasn't expired already.
  408.  */
  409.  
  410. void reset_timeout (request_rec *r) {
  411.     int i;
  412.  
  413.     if (timeout_name) { /* timeout has been set */
  414.         i = alarm(r->server->timeout);
  415.         if (i == 0) /* timeout already expired, so set it back to 0 */
  416.             alarm(0);
  417.     }
  418. }
  419.  
  420. /*****************************************************************
  421.  *
  422.  * Dealing with the scoreboard... a lot of these variables are global
  423.  * only to avoid getting clobbered by the longjmp() that happens when
  424.  * a hard timeout expires...
  425.  *
  426.  * We begin with routines which deal with the file itself...
  427.  */
  428.  
  429. #if defined(HAVE_MMAP)
  430. static short_score *scoreboard_image=NULL;
  431.  
  432. static void setup_shared_mem(void)
  433. {
  434.     caddr_t m;
  435. #if defined(MAP_ANON) || defined(MAP_FILE)
  436. /* BSD style */
  437.     m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
  438.              PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
  439.     if (m == (caddr_t)-1)
  440.     {
  441.         perror("mmap");
  442.         fprintf(stderr, "httpd: Could not mmap memory\n");
  443.         exit(1);
  444.     }
  445. #else
  446. /* Sun style */
  447.     int fd;
  448.  
  449.     fd = open("/dev/zero", O_RDWR);
  450.     if (fd == -1)
  451.     {
  452.         perror("open");
  453.         fprintf(stderr, "httpd: Could not open /dev/zero\n");
  454.         exit(1);
  455.     }
  456.     m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
  457.              PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  458.     if (m == (caddr_t)-1)
  459.     {
  460.         perror("mmap");
  461.         fprintf(stderr, "httpd: Could not mmap /dev/zero\n");
  462.         exit(1);
  463.     }
  464.     close(fd);
  465. #endif
  466.     scoreboard_image = (short_score *)m;
  467. }
  468.  
  469. #elif defined(HAVE_SHMGET)
  470. static short_score *scoreboard_image=NULL;
  471. static key_t shmkey = IPC_PRIVATE;
  472. static int shmid = -1;
  473.  
  474. static void setup_shared_mem(void)
  475. {
  476.     int score_size = HARD_SERVER_LIMIT*sizeof(short_score);
  477.     char errstr[MAX_STRING_LEN];
  478.     struct shmid_ds shmbuf;
  479. #ifdef MOVEBREAK
  480.     char *obrk;
  481. #endif
  482.  
  483.     if ((shmid = shmget(shmkey, score_size, IPC_CREAT|SHM_R|SHM_W)) == -1)
  484.     {
  485.         perror("shmget");
  486.         fprintf(stderr, "httpd: Could not call shmget\n");
  487.         exit(1);
  488.     }
  489.  
  490.     sprintf(errstr, "created shared memory segment #%d", shmid);
  491.     log_error(errstr, server_conf);
  492.  
  493. #ifdef MOVEBREAK
  494.     /*
  495.      * Some SysV systems place the shared segment WAY too close
  496.      * to the dynamic memory break point (sbrk(0)). This severely
  497.      * limits the use of malloc/sbrk in the program since sbrk will
  498.      * refuse to move past that point.
  499.      *
  500.      * To get around this, we move the break point "way up there",
  501.      * attach the segment and then move break back down. Ugly
  502.      */
  503.     if ((obrk=sbrk(MOVEBREAK)) == (char *)-1)
  504.     {
  505.         perror("sbrk");
  506.         fprintf(stderr, "httpd: Could not move break\n");
  507.     }
  508. #endif
  509.  
  510. #define BADSHMAT        ((short_score*)(-1))
  511.     if ((scoreboard_image = (short_score*)shmat(shmid, 0, 0)) == BADSHMAT)
  512.     {
  513.         perror("shmat");
  514.         fprintf(stderr, "httpd: Could not call shmat\n");
  515.         /*
  516.          * We exit below, after we try to remove the segment
  517.          */
  518.     }
  519.     else        /* only worry about permissions if we attached the segment */
  520.     {
  521.         if (shmctl(shmid, IPC_STAT, &shmbuf) != 0) {
  522.             perror("shmctl");
  523.             fprintf(stderr, "httpd: Could not stat segment #%d\n", shmid);
  524.         }
  525.         else
  526.         {
  527.             shmbuf.shm_perm.uid = user_id;
  528.             shmbuf.shm_perm.gid = group_id;
  529.             if (shmctl(shmid, IPC_SET, &shmbuf) != 0) {
  530.                 perror("shmctl");
  531.                 fprintf(stderr, "httpd: Could not set segment #%d\n", shmid);
  532.             }
  533.         }
  534.     }
  535.     /*
  536.      * We must avoid leaving segments in the kernel's
  537.      * (small) tables.
  538.      */
  539.     if (shmctl(shmid, IPC_RMID, NULL) != 0) {
  540.         perror("shmctl");
  541.         fprintf(stderr, "httpd: Could not delete segment #%d\n", shmid);
  542.         sprintf(errstr, "could not remove shared memory segment #%d", shmid);
  543.         log_unixerr("shmctl","IPC_RMID",errstr, server_conf);
  544.     }
  545.     if (scoreboard_image == BADSHMAT)        /* now bailout */
  546.         exit(1);
  547.  
  548. #ifdef MOVEBREAK
  549.     if (obrk == (char *)-1)
  550.         return;                /* nothing else to do */
  551.     if (sbrk(-(MOVEBREAK)) == (char *)-1)
  552.     {
  553.         perror("sbrk");
  554.         fprintf(stderr, "httpd: Could not move break back\n");
  555.     }
  556. #endif
  557. }
  558.  
  559. #else
  560. static short_score scoreboard_image[HARD_SERVER_LIMIT];
  561. static int have_scoreboard_fname = 0;
  562. static int scoreboard_fd;
  563.  
  564. static int force_write (int fd, char *buffer, int bufsz)
  565. {
  566.     int rv, orig_sz = bufsz;
  567.  
  568.     do {
  569.         rv = write (fd, buffer, bufsz);
  570.         if (rv > 0) {
  571.             buffer += rv;
  572.             bufsz -= rv;
  573.         }
  574.     } while (rv > 0 && bufsz > 0);
  575.  
  576.     return rv < 0? rv : orig_sz - bufsz;
  577. }
  578.  
  579. static int force_read (int fd, char *buffer, int bufsz)
  580. {
  581.     int rv, orig_sz = bufsz;
  582.  
  583.     do {
  584.         rv = read (fd, buffer, bufsz);
  585.         if (rv > 0) {
  586.             buffer += rv;
  587.             bufsz -= rv;
  588.         }
  589.     } while (rv > 0 && bufsz > 0);
  590.  
  591.     return rv < 0? rv : orig_sz - bufsz;
  592. }
  593. #endif
  594.  
  595. /* Called by parent process */
  596. void reinit_scoreboard (pool *p)
  597. {
  598. #if defined(HAVE_SHMGET) || defined(HAVE_MMAP)
  599.     if (scoreboard_image == NULL)
  600.     {
  601.         setup_shared_mem();
  602.     }
  603.     memset(scoreboard_image, 0, HARD_SERVER_LIMIT*sizeof(short_score));
  604. #else
  605.     scoreboard_fname = server_root_relative (p, scoreboard_fname);
  606.  
  607.     have_scoreboard_fname = 1;
  608.  
  609. #ifdef __EMX__
  610.     /* OS/2 needs binary mode set. */
  611.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0644);
  612. #else
  613.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644);
  614. #endif
  615.     if (scoreboard_fd == -1)
  616.     {
  617.         fprintf (stderr, "Cannot open scoreboard file:\n");
  618.         perror (scoreboard_fname);
  619.         exit (1);
  620.     }
  621.  
  622.     memset ((char*)scoreboard_image, 0, sizeof(scoreboard_image));
  623.     force_write (scoreboard_fd, (char*)scoreboard_image,
  624.                  sizeof(scoreboard_image));
  625. #endif
  626. }
  627.  
  628. /* called by child */
  629. void reopen_scoreboard (pool *p)
  630. {
  631. #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
  632.     if (scoreboard_fd != -1) pclosef (p, scoreboard_fd);
  633.  
  634. #ifdef __EMX__
  635.     /* OS/2 needs binary mode set. */
  636.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_BINARY|O_RDWR, 0666);
  637. #else
  638.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666);
  639. #endif
  640.     if (scoreboard_fd == -1)
  641.     {
  642.         fprintf (stderr, "Cannot open scoreboard file:\n");
  643.         perror (scoreboard_fname);
  644.         exit (1);
  645.     }
  646. #endif
  647. }
  648.  
  649. void cleanup_scoreboard ()
  650. {
  651. #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
  652.     unlink (scoreboard_fname);
  653. #endif
  654. }
  655.  
  656. /* Routines called to deal with the scoreboard image
  657.  * --- note that we do *not* need write locks, since update_child_status
  658.  * only updates a *single* record in place, and only one process writes to
  659.  * a given scoreboard slot at a time (either the child process owning that
  660.  * slot, or the parent, noting that the child has died).
  661.  *
  662.  * As a final note --- setting the score entry to getpid() is always safe,
  663.  * since when the parent is writing an entry, it's only noting SERVER_DEAD
  664.  * anyway.
  665.  */
  666.  
  667. void sync_scoreboard_image ()
  668. {
  669. #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
  670.     lseek (scoreboard_fd, 0L, 0);
  671.     force_read (scoreboard_fd, (char*)scoreboard_image,
  672.                 sizeof(scoreboard_image));
  673. #endif
  674. }
  675.  
  676. int update_child_status (int child_num, int status, request_rec *r)
  677. {
  678.     short_score new_score_rec;
  679.     int old_status;
  680.  
  681.     if (child_num < 0)
  682.         return -1;
  683.  
  684.     memcpy(&new_score_rec,&scoreboard_image[child_num],sizeof new_score_rec);
  685.     new_score_rec.pid = getpid();
  686.     old_status = new_score_rec.status;
  687.     new_score_rec.status = status;
  688.  
  689. #if defined(STATUS)
  690.     new_score_rec.last_used=time(NULL);
  691.     if (status == SERVER_DEAD) {
  692.         /*
  693.          * Reset individual counters
  694.          */
  695.         new_score_rec.my_access_count = 0L;
  696.         new_score_rec.my_bytes_served = 0L;
  697.         new_score_rec.conn_count = (unsigned short)0;
  698.         new_score_rec.conn_bytes = (unsigned long)0;
  699.     }
  700.     if (r) {
  701.         int slot_size;
  702.         conn_rec *c = r->connection;
  703.         slot_size = sizeof(new_score_rec.client) - 1;
  704.         strncpy(new_score_rec.client, get_remote_host(c, r->per_dir_config,
  705.          REMOTE_NAME), slot_size);
  706.         new_score_rec.client[slot_size] = '\0';
  707.         slot_size = sizeof(new_score_rec.request) - 1;
  708.         strncpy(new_score_rec.request, (r->the_request ? r->the_request :
  709.          "NULL"), slot_size);
  710.         new_score_rec.request[slot_size] = '\0';
  711.     }
  712. #endif
  713.  
  714. #if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
  715.     memcpy(&scoreboard_image[child_num], &new_score_rec, sizeof(short_score));
  716. #else
  717.     lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
  718.     force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
  719. #endif
  720.  
  721.     return old_status;
  722. }
  723.  
  724. int get_child_status (int child_num)
  725. {
  726.     if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
  727.             return -1;
  728.     else
  729.         return scoreboard_image[child_num].status;
  730. }
  731.  
  732. int count_busy_servers ()
  733. {
  734.     int i;
  735.     int res = 0;
  736.  
  737.     for (i = 0; i < HARD_SERVER_LIMIT; ++i)
  738.       if (scoreboard_image[i].status == SERVER_BUSY_READ ||
  739.               scoreboard_image[i].status == SERVER_BUSY_WRITE ||
  740.               scoreboard_image[i].status == SERVER_BUSY_KEEPALIVE ||
  741.               scoreboard_image[i].status == SERVER_BUSY_LOG ||
  742.               scoreboard_image[i].status == SERVER_BUSY_DNS)
  743.           ++res;
  744.     return res;
  745. }
  746.  
  747. short_score get_scoreboard_info(int i)
  748. {
  749.     return (scoreboard_image[i]);
  750. }
  751.  
  752. #if defined(STATUS)
  753. void increment_counts (int child_num, request_rec *r, int flag)
  754. {
  755.     long int bs=0;
  756.     short_score new_score_rec=scoreboard_image[child_num];
  757.  
  758.     if (r->sent_bodyct)
  759.         bgetopt(r->connection->client, BO_BYTECT, &bs);
  760.  
  761.     if (flag) {
  762.         new_score_rec.conn_count = (unsigned short)0;
  763.         new_score_rec.conn_bytes = (unsigned long)0;
  764.     }
  765.     new_score_rec.access_count ++;
  766.     new_score_rec.my_access_count ++;
  767.     new_score_rec.conn_count ++;
  768.     new_score_rec.bytes_served += (unsigned long)bs;
  769.     new_score_rec.my_bytes_served += (unsigned long)bs;
  770.     new_score_rec.conn_bytes += (unsigned long)bs;
  771.  
  772.     times(&new_score_rec.times);
  773.  
  774. #if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
  775.     memcpy(&scoreboard_image[child_num], &new_score_rec, sizeof(short_score));
  776. #else
  777.     lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
  778.     force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
  779. #endif
  780. }
  781. #endif
  782.  
  783. int count_idle_servers ()
  784. {
  785.     int i;
  786.     int res = 0;
  787.  
  788.     for (i = 0; i < HARD_SERVER_LIMIT; ++i)
  789.         if (scoreboard_image[i].status == SERVER_READY
  790.           || scoreboard_image[i].status == SERVER_STARTING)
  791.             ++res;
  792.  
  793.     return res;
  794. }
  795.  
  796. int find_free_child_num ()
  797. {
  798.     int i;
  799.  
  800.     for (i = 0; i < HARD_SERVER_LIMIT; ++i)
  801.         if (scoreboard_image[i].status == SERVER_DEAD)
  802.             return i;
  803.  
  804.     return -1;
  805. }
  806.  
  807. int find_child_by_pid (int pid)
  808. {
  809.     int i;
  810.  
  811.     for (i = 0; i < HARD_SERVER_LIMIT; ++i)
  812.         if (scoreboard_image[i].pid == pid)
  813.             return i;
  814.  
  815.     return -1;
  816. }
  817.  
  818. void reclaim_child_processes ()
  819. {
  820.     int i, status;
  821.     int my_pid = getpid();
  822.  
  823.     sync_scoreboard_image();
  824.     for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
  825.         int pid = scoreboard_image[i].pid;
  826.  
  827.         if (pid != my_pid && pid != 0)
  828.             waitpid (scoreboard_image[i].pid, &status, 0);
  829.     }
  830. }
  831.  
  832. /* Finally, this routine is used by the caretaker process to wait for
  833.  * a while...
  834.  */
  835.  
  836. static JMP_BUF wait_timeout_buf;
  837. static int wait_or_timeout_retval = -1;
  838.  
  839. static void longjmp_out_of_alarm (int sig) {
  840. #ifdef NEXT
  841.     longjmp (wait_timeout_buf, 1);
  842. #else
  843.     siglongjmp (wait_timeout_buf, 1);
  844. #endif
  845. }
  846.  
  847. int wait_or_timeout (int *status)
  848. {
  849.     wait_or_timeout_retval = -1;
  850.  
  851. #if defined(NEXT)
  852.     if (setjmp(wait_timeout_buf) != 0) {
  853. #else
  854.     if (sigsetjmp(wait_timeout_buf, 1) != 0) {
  855. #endif
  856.         errno = ETIMEDOUT;
  857.         return wait_or_timeout_retval;
  858.     }
  859.  
  860.     signal (SIGALRM, longjmp_out_of_alarm);
  861.     alarm(1);
  862. #if defined(NEXT)
  863.     wait_or_timeout_retval = wait((union wait *)status);
  864. #else
  865.     wait_or_timeout_retval = wait(status);
  866. #endif
  867.     alarm(0);
  868.     return wait_or_timeout_retval;
  869. }
  870.  
  871.  
  872. /*****************************************************************
  873.  * Here follows a long bunch of generic server bookkeeping stuff...
  874.  */
  875.  
  876. void detach()
  877. {
  878.     int x;
  879.  
  880.     chdir("/");
  881.     if((x = fork()) > 0)
  882.         exit(0);
  883.     else if(x == -1) {
  884.         fprintf(stderr,"httpd: unable to fork new process\n");
  885.         perror("fork");
  886.         exit(1);
  887.     }
  888. #ifndef NO_SETSID
  889.     if((pgrp=setsid()) == -1) {
  890.         fprintf(stderr,"httpd: setsid failed\n");
  891.         perror("setsid");
  892.         exit(1);
  893.     }
  894. #else
  895. #if defined(NEXT)
  896.     if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
  897.         fprintf(stderr,"httpd: setpgrp or getpgrp failed\n");
  898.         perror("setpgrp");
  899.         exit(1);
  900.     }
  901. #else
  902. #ifdef __EMX__
  903.     /* OS/2 doesn't support process group IDs */
  904.     pgrp=getpid();
  905. #else
  906.     if((pgrp=setpgrp(getpid(),0)) == -1) {
  907.         fprintf(stderr,"httpd: setpgrp failed\n");
  908.         perror("setpgrp");
  909.         exit(1);
  910.     }
  911. #endif
  912. #endif
  913. #endif
  914. }
  915.  
  916. void sig_term() {
  917.     log_error("httpd: caught SIGTERM, shutting down", server_conf);
  918.     cleanup_scoreboard();
  919. #ifndef NO_KILLPG
  920.     killpg(pgrp,SIGKILL);
  921. #else
  922.     kill(-pgrp,SIGKILL);
  923. #endif
  924.     shutdown(sd,2);
  925.     close(sd);
  926.     exit(1);
  927. }
  928.  
  929. void bus_error() {
  930.     log_error("httpd: caught SIGBUS, dumping core", server_conf);
  931.     chdir(server_root);
  932.     abort();
  933.     exit(1);
  934. }
  935.  
  936. void seg_fault() {
  937.     log_error("httpd: caught SIGSEGV, dumping core", server_conf);
  938.     chdir(server_root);
  939.     abort();
  940.     exit(1);
  941. }
  942.  
  943. void just_die()                        /* SIGHUP to child process??? */
  944. {
  945.     exit (0);
  946. }
  947.  
  948. /* Reset group privileges, after rereading the config files
  949.  * (our uid may have changed, and if so, we want the new perms).
  950.  *
  951.  * Don't reset the uid yet --- we do that only in the child process,
  952.  * so as not to lose any root privs.  But we can set the group stuff
  953.  * now, once, as opposed to once per each new child.
  954.  *
  955.  * Note that we use the username as set in the config files, rather than
  956.  * the lookup of to uid --- the same uid may have multiple passwd entries,
  957.  * with different sets of groups for each.
  958.  */
  959.  
  960. static void set_group_privs()
  961. {
  962.   if(!geteuid()) {
  963.     char *name;
  964.  
  965.     /* Get username if passed as a uid */
  966.  
  967.     if (user_name[0] == '#') {
  968.       struct passwd* ent;
  969.       uid_t uid=atoi(&user_name[1]);
  970.  
  971.       if ((ent = getpwuid(uid)) == NULL) {
  972.          log_unixerr("getpwuid",NULL,"couldn't determine user name from uid", server_conf);
  973.          exit(1);
  974.       }
  975.  
  976.       name = ent->pw_name;
  977.     } else name = user_name;
  978.  
  979. #ifndef __EMX__
  980.     /* OS/2 dosen't support groups. */
  981.  
  982.     /* Reset `groups' attributes. */
  983.  
  984.     if (initgroups(name, group_id) == -1) {
  985.         log_unixerr("initgroups", NULL, "unable to set groups", server_conf);
  986.         exit (1);
  987.     }
  988.  
  989.     if (setgid(group_id) == -1) {
  990.         log_unixerr("setgid", NULL, "unable to set group id", server_conf);
  991.         exit (1);
  992.     }
  993. #endif
  994.   }
  995. }
  996.  
  997. void restart() {
  998.     signal (SIGALRM, SIG_IGN);
  999.     alarm (0);
  1000. #ifdef NEXT
  1001.     longjmp(restart_buffer,1);
  1002. #else
  1003.     siglongjmp(restart_buffer,1);
  1004. #endif
  1005. }
  1006.  
  1007. void set_signals() {
  1008. #ifndef NO_USE_SIGACTION
  1009.     struct sigaction sa;
  1010. #endif
  1011.     if(!one_process) {
  1012.         signal(SIGSEGV,(void (*)())seg_fault);
  1013.             signal(SIGBUS,(void (*)())bus_error);
  1014.         }
  1015.  
  1016. #ifdef NO_USE_SIGACTION
  1017.     signal(SIGTERM,(void (*)())sig_term);
  1018.     signal(SIGHUP,(void (*)())restart);
  1019. #else
  1020.     memset(&sa,0,sizeof sa);
  1021.     sa.sa_handler=(void (*)())sig_term;
  1022.     if(sigaction(SIGTERM,&sa,NULL) < 0)
  1023.         log_unixerr("sigaction(SIGTERM)", NULL, NULL, server_conf);
  1024.     sa.sa_handler=(void (*)())restart;
  1025.     if(sigaction(SIGHUP,&sa,NULL) < 0)
  1026.         log_unixerr("sigaction(SIGHUP)", NULL, NULL, server_conf);
  1027. #endif
  1028. }
  1029.  
  1030. /*****************************************************************
  1031.  * Connection structures and accounting...
  1032.  * Should these be global?  Only to this file, at least...
  1033.  */
  1034.  
  1035. pool *pconf;                        /* Pool for config stuff */
  1036. pool *ptrans;                        /* Pool for per-transaction stuff */
  1037.  
  1038. server_rec *find_virtual_server (struct in_addr server_ip, int port,
  1039.                                  server_rec *server)
  1040. {
  1041.     server_rec *virt;
  1042.  
  1043.     for (virt = server->next; virt; virt = virt->next)
  1044.         if ((virt->is_virtual == 1) &&        /* VirtualHost */
  1045.             (virt->host_addr.s_addr == htonl(INADDR_ANY) ||
  1046.              virt->host_addr.s_addr == server_ip.s_addr) &&
  1047.             (virt->host_port == 0 || virt->host_port == port))
  1048.             return virt;
  1049.  
  1050.     return server;
  1051. }
  1052.  
  1053. void default_server_hostnames(server_rec *s)
  1054. {
  1055.     struct hostent *h, *main;
  1056.     char *def_hostname;
  1057.     int n;
  1058.  
  1059.     /* Main host first */
  1060.  
  1061.     if (!s->server_hostname)
  1062.         s->server_hostname = get_local_host(pconf);
  1063.  
  1064.     def_hostname = s->server_hostname;
  1065.     main = gethostbyname(def_hostname);
  1066.  
  1067.     /* Then virtual hosts */
  1068.  
  1069.     for (s = s->next; s; s = s->next) {
  1070.         /* Check to see if we might be a HTTP/1.1 virtual host - same IP */
  1071.         for (n = 0; main->h_addr_list[n] != NULL; n++) {
  1072.           if (s->host_addr.s_addr ==
  1073.               (((struct in_addr *)(main->h_addr_list[n]))->s_addr))
  1074.             s->is_virtual = 2;
  1075.         }
  1076.  
  1077.         if (!s->server_hostname) {
  1078.             if (s->is_virtual == 2)
  1079.                 s->server_hostname = s->virthost;
  1080.             else if (s->host_addr.s_addr == htonl(INADDR_ANY))
  1081.                 s->server_hostname = def_hostname;
  1082.             else
  1083.             {
  1084.                 h = gethostbyaddr ((char *)&(s->host_addr),
  1085.                                    sizeof (struct in_addr), AF_INET);
  1086.                 if (h != NULL)
  1087.                     s->server_hostname = pstrdup (pconf, (char *)h->h_name);
  1088.             }
  1089.         }
  1090.     }
  1091. }
  1092.  
  1093. void abort_connection (conn_rec *c)
  1094. {
  1095.     /* Make sure further I/O DOES NOT HAPPEN */
  1096.     shutdown (c->client->fd, 2);
  1097.     signal (SIGPIPE, SIG_IGN);        /* Ignore further complaints */
  1098.     c->aborted = 1;
  1099. }
  1100.  
  1101. conn_rec *new_connection (pool *p, server_rec *server, BUFF *inout,
  1102.                           const struct sockaddr_in *remaddr,
  1103.                           const struct sockaddr_in *saddr,
  1104.                           int child_num)
  1105. {
  1106.     conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec));
  1107.  
  1108.     /* Get a connection structure, and initialize what fields we can
  1109.      * (the rest are zeroed out by pcalloc).
  1110.      */
  1111.  
  1112.     conn = (conn_rec *)pcalloc(p, sizeof(conn_rec));
  1113.     conn->child_num = child_num;
  1114.  
  1115.     conn->pool = p;
  1116.     conn->local_addr = *saddr;
  1117.     conn->server = find_virtual_server(saddr->sin_addr, ntohs(saddr->sin_port),
  1118.                                        server);
  1119.     conn->client = inout;
  1120.  
  1121.     conn->remote_addr = *remaddr;
  1122.     conn->remote_ip = pstrdup (conn->pool,
  1123.                                inet_ntoa(conn->remote_addr.sin_addr));
  1124.  
  1125.     return conn;
  1126. }
  1127.  
  1128. /*****************************************************************
  1129.  * Child process main loop.
  1130.  * The following vars are static to avoid getting clobbered by longjmp();
  1131.  * they are really private to child_main.
  1132.  */
  1133.  
  1134. static int csd;
  1135. static int dupped_csd;
  1136. static int requests_this_child;
  1137. static int child_num;
  1138.  
  1139. void child_main(int child_num_arg)
  1140. {
  1141.     int clen;
  1142.     struct sockaddr sa_server;
  1143.     struct sockaddr sa_client;
  1144.  
  1145.     csd = -1;
  1146.     dupped_csd = -1;
  1147.     child_num = child_num_arg;
  1148.     requests_this_child = 0;
  1149.     reopen_scoreboard (pconf);
  1150.     (void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
  1151.  
  1152.     /* Only try to switch if we're running as root */
  1153.     if(!geteuid() && setuid(user_id) == -1) {
  1154.         log_unixerr("setuid", NULL, "unable to change uid", server_conf);
  1155.         exit (1);
  1156.     }
  1157.  
  1158. #ifdef NEXT
  1159.     setjmp(jmpbuffer);
  1160. #else
  1161.     sigsetjmp(jmpbuffer,1);
  1162. #endif
  1163. #ifndef __EMX__
  1164.     signal(SIGURG, timeout);
  1165. #endif
  1166.  
  1167.     while (1) {
  1168.         BUFF *conn_io;
  1169.         request_rec *r;
  1170.  
  1171.         alarm(0);                /* Cancel any outstanding alarms. */
  1172.         timeout_req = NULL;        /* No request in progress */
  1173.         current_conn = NULL;
  1174.         signal(SIGPIPE, timeout);
  1175.  
  1176.         clear_pool (ptrans);
  1177.  
  1178.         sync_scoreboard_image();
  1179.  
  1180.         if ((count_idle_servers() >= daemons_max_free)
  1181.             || (max_requests_per_child > 0
  1182.                 && ++requests_this_child >= max_requests_per_child))
  1183.         {
  1184.             exit(0);
  1185.         }
  1186.  
  1187.         clen=sizeof(sa_client);
  1188.         (void)update_child_status (child_num, SERVER_READY, (request_rec*)NULL);
  1189.  
  1190.         accept_mutex_on();  /* Lock around "accept", if necessary */
  1191.  
  1192.         if (listeners != NULL)
  1193.         {
  1194.             fd_set fds;
  1195.  
  1196.             for (;;) {
  1197.                 memcpy(&fds, &listenfds, sizeof(fd_set));
  1198. #ifdef HPUX
  1199.                 csd = select(listenmaxfd+1, (int*)&fds, NULL, NULL, NULL);
  1200. #else
  1201.                 csd = select(listenmaxfd+1, &fds, NULL, NULL, NULL);
  1202. #endif
  1203.                 if (csd == -1 && errno != EINTR)
  1204.                     log_unixerr("select",NULL,"select error", server_conf);
  1205.                 if (csd <= 0) continue;
  1206.                 for (sd=listenmaxfd; sd >= 0; sd--)
  1207.                     if (FD_ISSET(sd, &fds)) break;
  1208.                 if (sd < 0) continue;
  1209.  
  1210.                 clen=sizeof(sa_client);
  1211.                 do csd=accept(sd, &sa_client, &clen);
  1212.                 while (csd == -1 && errno == EINTR);
  1213.                 if (csd != -1) break;
  1214.                 log_unixerr("accept", "(client socket)", NULL, server_conf);
  1215.             }
  1216.         } else
  1217.             while ((csd=accept(sd, &sa_client, &clen)) == -1)
  1218.                 if (errno != EINTR)
  1219.                     log_unixerr("accept",NULL,"socket error: accept failed", server_conf);
  1220.  
  1221.         accept_mutex_off(); /* unlock after "accept" */
  1222.  
  1223.         clen = sizeof(sa_server);
  1224.         if(getsockname(csd, &sa_server, &clen) < 0) {
  1225.             log_unixerr("getsockname", NULL, NULL, server_conf);
  1226.             continue;
  1227.         }
  1228.  
  1229.         (void)update_child_status (child_num, SERVER_BUSY_READ, (request_rec*)NULL);
  1230.         conn_io = bcreate(ptrans, B_RDWR);
  1231.         dupped_csd = csd;
  1232. #if defined(NEED_DUPPED_CSD)
  1233.         if ((dupped_csd = dup(csd)) < 0) {
  1234.             log_unixerr("dup", NULL, "couldn't duplicate csd", server_conf);
  1235.             dupped_csd = csd;   /* Oh well... */
  1236.         }
  1237. #endif
  1238.         bpushfd(conn_io, csd, dupped_csd);
  1239.  
  1240.         current_conn = new_connection (ptrans, server_conf, conn_io,
  1241.                                        (struct sockaddr_in *)&sa_client,
  1242.                                        (struct sockaddr_in *)&sa_server,
  1243.                                        child_num);
  1244.  
  1245.         r = read_request (current_conn);
  1246.         (void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
  1247.         if (r) process_request (r); /* else premature EOF --- ignore */
  1248.  
  1249. #if defined(STATUS)
  1250.         if (r) increment_counts(child_num,r,1);
  1251. #endif
  1252.         while (r && current_conn->keepalive) {
  1253.           bflush(conn_io);
  1254.           destroy_pool(r->pool);
  1255.           (void)update_child_status (child_num, SERVER_BUSY_KEEPALIVE, (request_rec*)NULL);
  1256.           r = read_request (current_conn);
  1257.           (void)update_child_status (child_num, SERVER_BUSY_WRITE, r);
  1258.           if (r) process_request (r);
  1259.  
  1260. #if defined(STATUS)
  1261.           if (r) increment_counts(child_num,r,0);
  1262. #endif
  1263.         }
  1264. #if 0
  1265.         if (bytes_in_pool (ptrans) > 80000)
  1266.             log_printf(r->server,
  1267.                        "Memory hog alert: allocated %ld bytes for %s",
  1268.                        bytes_in_pool (ptrans), r->the_request);
  1269. #endif
  1270.         bflush(conn_io);
  1271.         bclose(conn_io);
  1272.     }
  1273. }
  1274.  
  1275. void make_child(server_rec *server_conf, int child_num)
  1276. {
  1277.     int pid;
  1278.  
  1279.     if (one_process) {
  1280.         signal (SIGHUP, (void (*)())just_die);
  1281.         signal (SIGTERM, (void (*)())just_die);
  1282.         child_main (child_num);
  1283.     }
  1284.  
  1285.     if ((pid = fork()) == -1) {
  1286.         log_unixerr("fork", NULL, "Unable to fork new process", server_conf);
  1287.         return;
  1288.     }
  1289.  
  1290.     if (!pid) {
  1291.         signal (SIGHUP, (void (*)())just_die);
  1292.         signal (SIGTERM, (void (*)())just_die);
  1293.         child_main (child_num);
  1294.     }
  1295. }
  1296.  
  1297. static int
  1298. make_sock(pool *pconf, const struct sockaddr_in *server)
  1299. {
  1300.     int s;
  1301.     const int one = 1;
  1302.     const int keepalive_value = 1;
  1303.  
  1304.     if ((s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
  1305.         perror("socket");
  1306.         fprintf(stderr,"httpd: could not get socket\n");
  1307.         exit(1);
  1308.     }
  1309.  
  1310.     note_cleanups_for_fd (pconf, s); /* arrange to close on exec or restart */
  1311.  
  1312.     if((setsockopt(s, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)))
  1313.        == -1) {
  1314.         perror("setsockopt(SO_REUSEADDR)");
  1315.         fprintf(stderr,"httpd: could not set socket option SO_REUSEADDR\n");
  1316.         exit(1);
  1317.     }
  1318.     if((setsockopt(s, SOL_SOCKET,SO_KEEPALIVE,(char *)&keepalive_value,
  1319.         sizeof(keepalive_value))) == -1) {
  1320.         perror("setsockopt(SO_KEEPALIVE)");
  1321.         fprintf(stderr,"httpd: could not set socket option SO_KEEPALIVE\n");
  1322.         exit(1);
  1323.     }
  1324.  
  1325. #ifdef NEED_LINGER   /* If puts don't complete, you could try this. */
  1326.     {
  1327.         struct linger li;
  1328.         li.l_onoff = 1;
  1329.         li.l_linger = 900;
  1330.  
  1331.         if (setsockopt(s, SOL_SOCKET, SO_LINGER,
  1332.             (char *)&li, sizeof(struct linger)) < 0) {
  1333.             perror("setsockopt(SO_LINGER)");
  1334.             fprintf(stderr,"httpd: could not set socket option SO_LINGER\n");
  1335.             exit(1);
  1336.         }
  1337.     }
  1338. #endif  /* NEED_LINGER */
  1339.  
  1340.     if(bind(s, (struct sockaddr *)server,sizeof(struct sockaddr_in)) == -1)
  1341.     {
  1342.         perror("bind");
  1343.         if (server->sin_addr.s_addr != htonl(INADDR_ANY))
  1344.             fprintf(stderr,"httpd: could not bind to address %s port %d\n",
  1345.                     inet_ntoa(server->sin_addr), ntohs(server->sin_port));
  1346.         else
  1347.             fprintf(stderr,"httpd: could not bind to port %d\n",
  1348.                     ntohs(server->sin_port));
  1349.         exit(1);
  1350.     }
  1351.     listen(s, 512);
  1352.     return s;
  1353. }
  1354.  
  1355.  
  1356. /*****************************************************************
  1357.  * Executive routines.
  1358.  */
  1359.  
  1360. static int num_children = 0;
  1361.  
  1362. void standalone_main(int argc, char **argv)
  1363. {
  1364.     struct sockaddr_in sa_server;
  1365.  
  1366.     standalone = 1;
  1367.     sd = listenmaxfd = -1;
  1368.  
  1369.     if (!one_process) detach();
  1370.  
  1371. #ifdef NEXT
  1372.     setjmp(restart_buffer);
  1373. #else
  1374.     sigsetjmp(restart_buffer,1);
  1375. #endif
  1376.  
  1377.     signal (SIGHUP, SIG_IGN);        /* Until we're done (re)reading config */
  1378.  
  1379.     if(!one_process)
  1380.     {
  1381. #ifndef NO_KILLPG
  1382.       if (killpg(pgrp,SIGHUP) < 0)    /* Kill 'em off */
  1383. #else
  1384.       if (kill(-pgrp,SIGHUP) < 0)
  1385. #endif
  1386.         log_unixerr ("killpg SIGHUP", NULL, NULL, server_conf);
  1387.     }
  1388.  
  1389.     if (sd != -1 || listenmaxfd != -1) {
  1390.         reclaim_child_processes(); /* Not when just starting up */
  1391.         log_error ("SIGHUP received.  Attempting to restart", server_conf);
  1392.     }
  1393.  
  1394.     restart_time = time(NULL);
  1395.     clear_pool (pconf);
  1396.     ptrans = make_sub_pool (pconf);
  1397.  
  1398.     server_conf = read_config(pconf, ptrans, server_confname);
  1399.     open_logs(server_conf, pconf);
  1400.     set_group_privs();
  1401.     accept_mutex_init(pconf);
  1402.     reinit_scoreboard(pconf);
  1403.  
  1404.     default_server_hostnames (server_conf);
  1405.  
  1406.     if (listeners == NULL)
  1407.     {
  1408.         memset((char *) &sa_server, 0, sizeof(sa_server));
  1409.         sa_server.sin_family=AF_INET;
  1410.         sa_server.sin_addr=bind_address;
  1411.         sa_server.sin_port=htons(server_conf->port);
  1412.  
  1413.         sd = make_sock(pconf, &sa_server);
  1414.     } else
  1415.     {
  1416.         listen_rec *lr;
  1417.         int fd;
  1418.  
  1419.         listenmaxfd = -1;
  1420.         FD_ZERO(&listenfds);
  1421.         for (lr=listeners; lr != NULL; lr=lr->next)
  1422.         {
  1423.             fd = make_sock(pconf, &lr->local_addr);
  1424.             FD_SET(fd, &listenfds);
  1425.             if (fd > listenmaxfd) listenmaxfd = fd;
  1426.         }
  1427.         sd = -1;
  1428.     }
  1429.  
  1430.     set_signals();
  1431.     log_pid(pconf, pid_fname);
  1432.  
  1433.     num_children = 0;
  1434.  
  1435.     if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
  1436.         daemons_max_free = daemons_min_free + 1;
  1437.  
  1438.     while (num_children < daemons_to_start) {
  1439.         make_child(server_conf, num_children++);
  1440.     }
  1441.  
  1442.     log_error ("Server configured -- resuming normal operations", server_conf);
  1443.  
  1444.     while (1) {
  1445.         int status, child_slot;
  1446.         int pid = wait_or_timeout(&status);
  1447.  
  1448.         if (pid >= 0) {
  1449.             /* Child died... note that it's gone in the scoreboard. */
  1450.             sync_scoreboard_image();
  1451.             child_slot = find_child_by_pid (pid);
  1452.             if (child_slot >= 0)
  1453.                 (void)update_child_status (child_slot, SERVER_DEAD,
  1454.                  (request_rec*)NULL);
  1455.         }
  1456.  
  1457.         sync_scoreboard_image();
  1458.         if ((count_idle_servers() < daemons_min_free)
  1459.          && (child_slot = find_free_child_num()) >= 0
  1460.          && child_slot <= daemons_limit) {
  1461.             (void)update_child_status(child_slot,SERVER_STARTING,
  1462.              (request_rec*)NULL);
  1463.             make_child(server_conf, child_slot);
  1464.         }
  1465.     }
  1466.  
  1467. } /* standalone_main */
  1468.  
  1469. extern char *optarg;
  1470. extern int optind;
  1471.  
  1472. int
  1473. main(int argc, char *argv[])
  1474. {
  1475.     int c;
  1476.  
  1477. #ifdef AUX
  1478.     (void)set42sig();
  1479. #endif
  1480.  
  1481. #ifdef SecureWare
  1482.     if(set_auth_parameters(argc,argv) < 0)
  1483.             perror("set_auth_parameters");
  1484.     if(getluid() < 0)
  1485.         if(setluid(getuid()) < 0)
  1486.             perror("setluid");
  1487.     if(setreuid(0, 0) < 0)
  1488.         perror("setreuid");
  1489. #endif
  1490.  
  1491.     init_alloc();
  1492.     pconf = permanent_pool;
  1493.     ptrans = make_sub_pool(pconf);
  1494.  
  1495.     server_argv0 = argv[0];
  1496.     strcpy (server_root, HTTPD_ROOT);
  1497.     strcpy (server_confname, SERVER_CONFIG_FILE);
  1498.  
  1499.     while((c = getopt(argc,argv,"Xd:f:v")) != -1) {
  1500.         switch(c) {
  1501.           case 'd':
  1502.             strcpy (server_root, optarg);
  1503.             break;
  1504.           case 'f':
  1505.             strcpy (server_confname, optarg);
  1506.             break;
  1507.           case 'v':
  1508.             printf("Server version %s.\n",SERVER_VERSION);
  1509.             exit(1);
  1510.           case 'X':
  1511.             ++one_process;        /* Weird debugging mode. */
  1512.             break;
  1513.           case '?':
  1514.             usage(argv[0]);
  1515.         }
  1516.     }
  1517.  
  1518. #ifdef __EMX__
  1519.     printf("%s \n",SERVER_VERSION);
  1520.     printf("OS/2 port by Garey Smiley <garey@slink.com> \n");
  1521. #endif
  1522.  
  1523.     setup_prelinked_modules();
  1524.  
  1525.     server_conf = read_config (pconf, ptrans, server_confname);
  1526.  
  1527.     if(standalone) {
  1528.         clear_pool (pconf);        /* standalone_main rereads... */
  1529.         standalone_main(argc, argv);
  1530.     }
  1531.     else {
  1532.         conn_rec *conn;
  1533.         request_rec *r;
  1534.         struct sockaddr sa_server, sa_client;
  1535.         BUFF *cio;
  1536.  
  1537.         open_logs(server_conf, pconf);
  1538.         set_group_privs();
  1539.         default_server_hostnames (server_conf);
  1540.  
  1541.       /* Only try to switch if we're running as root */
  1542.       if(!geteuid() && setuid(user_id) == -1) {
  1543.           log_unixerr("setuid", NULL, "unable to change uid", server_conf);
  1544.           exit (1);
  1545.       }
  1546.  
  1547.         c = sizeof(sa_client);
  1548.         if ((getpeername(fileno(stdin), &sa_client, &c)) < 0)
  1549.         {
  1550. /* get peername will fail if the input isn't a socket */
  1551.             perror("getpeername");
  1552.             memset(&sa_client, '\0', sizeof(sa_client));
  1553.         }
  1554.  
  1555.         c = sizeof(sa_server);
  1556.         if(getsockname(fileno(stdin), &sa_server, &c) < 0) {
  1557.             perror("getsockname");
  1558.             fprintf(stderr, "Error getting local address\n");
  1559.             exit(1);
  1560.         }
  1561.         server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port);
  1562.         cio = bcreate(ptrans, B_RDWR);
  1563.         cio->fd = fileno(stdout);
  1564.         cio->fd_in = fileno(stdin);
  1565.         conn = new_connection (ptrans, server_conf, cio,
  1566.                                (struct sockaddr_in *)&sa_client,
  1567.                                (struct sockaddr_in *)&sa_server,-1);
  1568.         r = read_request (conn);
  1569.         if (r) process_request (r); /* else premature EOF (ignore) */
  1570.  
  1571.         while (r && conn->keepalive) {
  1572.           bflush(cio);
  1573.           destroy_pool(r->pool);
  1574.           r = read_request (conn);
  1575.           if (r) process_request (r);
  1576.         }
  1577.  
  1578.         bflush(cio);
  1579.         bclose(cio);
  1580.     }
  1581.     exit (0);
  1582. }
  1583.  
  1584.  
  1585.