home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Os2 / varios / APACHE / HTTP_MAI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-17  |  27.8 KB  |  1,080 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 "scoreboard.h"
  89. #include <setjmp.h>
  90.  
  91. /*
  92.  * Actual definitions of config globals... here because this is
  93.  * for the most part the only code that acts on 'em.  (Hmmm... mod_main.c?)
  94.  */
  95.  
  96. int standalone;
  97. uid_t user_id;
  98. char *user_name;
  99. gid_t group_id;
  100. int max_requests_per_child;
  101. char *pid_fname;
  102. char *scoreboard_fname;
  103. char *server_argv0;
  104. struct in_addr bind_address;
  105. int daemons_to_start;
  106. int daemons_min_free;
  107. int daemons_max_free;
  108. int daemons_limit;
  109.  
  110. char server_root[MAX_STRING_LEN];
  111. char server_confname[MAX_STRING_LEN];
  112.  
  113. /* *Non*-shared http_main globals... */
  114.  
  115. server_rec *server_conf;
  116. JMP_BUF jmpbuffer;
  117. JMP_BUF restart_buffer;
  118. int sd;
  119. pid_t pgrp;
  120.  
  121. /* one_process --- debugging mode variable; can be set from the command line
  122.  * with the -X flag.  If set, this gets you the child_main loop running
  123.  * in the process which originally started up (no detach, no make_child),
  124.  * which is a pretty nice debugging environment.  (You'll get a SIGHUP
  125.  * early in standalone_main; just continue through.  This is the server
  126.  * trying to kill off any child processes which it might have lying
  127.  * around --- Shambhala doesn't keep track of their pids, it just sends
  128.  * SIGHUP to the process group, ignoring it in the root process.
  129.  * Continue through and you'll be fine.).
  130.  */
  131.  
  132. int one_process = 0;
  133.  
  134. #ifdef FCNTL_SERIALIZED_ACCEPT
  135. static struct flock lock_it = { F_WRLCK, 0, 0, 0 };
  136. static struct flock unlock_it = { F_UNLCK, 0, 0, 0 };
  137.  
  138. static int lock_fd=-1;
  139.  
  140. /*
  141.  * Initialise mutex lock.
  142.  * Must be safe to call this on a restart.
  143.  */
  144. void
  145. accept_mutex_init(pool *p)
  146. {
  147.     char lock_fname[30];
  148.  
  149.     strcpy(lock_fname, "/usr/tmp/htlock.XXXXXX");
  150.     
  151.     if (mktemp(lock_fname) == NULL || lock_fname[0] == '\0')
  152.     {
  153.     fprintf (stderr, "Cannot assign name to lock file!\n");
  154.     exit (1);
  155.     }
  156.  
  157.     lock_fd = popenf(p, lock_fname, O_CREAT | O_WRONLY, 0644);
  158.     if (lock_fd == -1)
  159.     {
  160.     perror ("open");
  161.     fprintf (stderr, "Cannot open lcok file\n");
  162.     exit (1);
  163.     }
  164.     unlink(lock_fname);
  165. }
  166.  
  167. void accept_mutex_on()
  168. {
  169.     int ret;
  170.     
  171.     while ((ret = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
  172.     continue;
  173.  
  174.     if (ret < 0) {
  175.     log_unixerr("fcntl", "F_SETLKW", "Error getting accept lock. Exiting!",
  176.             server_conf);
  177.     exit(1);
  178.     }
  179. }
  180.  
  181. void accept_mutex_off()
  182. {
  183.     if (fcntl (lock_fd, F_SETLKW, &unlock_it) < 0)
  184.     {
  185.     log_unixerr("fcntl", "F_SETLKW", "Error freeing accept lock. Exiting!",
  186.             server_conf);
  187.     exit(1);
  188.     }
  189. }
  190. #else
  191. /* Default --- no serialization.  Other methods *could* go here,
  192.  * as #elifs...
  193.  */
  194. #define accept_mutex_init(x)
  195. #define accept_mutex_on()
  196. #define accept_mutex_off()
  197. #endif
  198.  
  199. void usage(char *bin)
  200. {
  201.     fprintf(stderr,"Usage: %s [-d directory] [-f file] [-v]\n",bin);
  202.     fprintf(stderr,"-d directory : specify an alternate initial ServerRoot\n");
  203.     fprintf(stderr,"-f file : specify an alternate ServerConfigFile\n");
  204.     exit(1);
  205. }
  206.  
  207. /*****************************************************************
  208.  *
  209.  * Timeout handling.  DISTINCTLY not thread-safe, but all this stuff
  210.  * has to change for threads anyway.  Note that this code allows only
  211.  * one timeout in progress at a time...
  212.  */
  213.  
  214. static conn_rec *current_conn;
  215. static request_rec *timeout_req;
  216. static char *timeout_name = NULL;
  217. static int alarms_blocked = 0;
  218. static int alarm_pending = 0;
  219.  
  220. void abort_connection (conn_rec *);
  221.  
  222. void timeout(sig)            /* Also called on SIGPIPE */
  223. int sig;
  224. {
  225.     char errstr[MAX_STRING_LEN];
  226.  
  227.     if (alarms_blocked) {
  228.     alarm_pending = 1;
  229.     return;
  230.     }
  231.     
  232.     if (!current_conn) {
  233. #ifdef NEXT
  234.     longjmp(jmpbuffer,1);
  235. #else
  236.     siglongjmp(jmpbuffer,1);
  237. #endif
  238.     }
  239.     
  240.     if (sig == SIGPIPE) {
  241.         sprintf(errstr,"%s lost connection to client %s",
  242.         timeout_name ? timeout_name : "request",
  243.         current_conn->remote_name);
  244.     } else {
  245.         sprintf(errstr,"%s timed out for %s",
  246.         timeout_name ? timeout_name : "request",
  247.         current_conn->remote_name);
  248.     }
  249.     
  250.     log_error(errstr, current_conn->server);
  251.       
  252.     if (timeout_req) {
  253.     /* Someone has asked for this transaction to just be aborted
  254.      * if it times out...
  255.      */
  256.     
  257.     request_rec *log_req = timeout_req;
  258.     
  259.     while (log_req->main || log_req->prev) {
  260.         /* Get back to original request... */
  261.         if (log_req->main) log_req = log_req->main;
  262.         else log_req = log_req->prev;
  263.     }
  264.     
  265.     log_transaction(log_req);
  266.  
  267.     pfclose (timeout_req->connection->pool,
  268.          timeout_req->connection->client);
  269.     pfclose (timeout_req->connection->pool,
  270.              timeout_req->connection->request_in);
  271.     
  272.     if (!standalone) exit(0);
  273. #ifdef NEXT
  274.     longjmp(jmpbuffer,1);
  275. #else
  276.     siglongjmp(jmpbuffer,1);
  277. #endif
  278.     }
  279.     else {
  280.     abort_connection (current_conn);
  281.     }
  282. }
  283.  
  284. /*
  285.  * These two called from alloc.c to protect its critical sections...
  286.  * Note that they can nest (as when destroying the sub_pools of a pool
  287.  * which is itself being cleared); we have to support that here.
  288.  */
  289.  
  290. void block_alarms() {
  291.     ++alarms_blocked;
  292. }
  293.  
  294. void unblock_alarms() {
  295.     --alarms_blocked;
  296.     if (alarms_blocked == 0 && alarm_pending) {
  297.     alarm_pending = 0;
  298.     timeout(0);
  299.     }
  300. }
  301.  
  302. void hard_timeout (char *name, request_rec *r)
  303. {
  304.     timeout_req = r;
  305.     timeout_name = name;
  306.     
  307.     signal(SIGALRM,(void (*)())timeout);
  308.     alarm (r->server->timeout);
  309. }
  310.  
  311. void soft_timeout (char *name, request_rec *r)
  312. {
  313.     timeout_name = name;
  314.     
  315.     signal(SIGALRM,(void (*)())timeout);
  316.     alarm (r->server->timeout);
  317. }
  318.  
  319. void kill_timeout (request_rec *dummy) {
  320.     alarm (0);
  321.     timeout_req = NULL;
  322.     timeout_name = NULL;
  323. }
  324.  
  325. /* reset_timeout (request_rec *) resets the timeout in effect,
  326.  * as long as it hasn't expired already.
  327.  */
  328.  
  329. void reset_timeout (request_rec *r) {
  330.     int i;
  331.  
  332.     if (timeout_name) { /* timeout has been set */
  333.         i = alarm(r->server->timeout);
  334.         if (i == 0) /* timeout already expired, so set it back to 0 */
  335.         alarm(0);
  336.     }
  337. }
  338.  
  339. /*****************************************************************
  340.  *
  341.  * Dealing with the scoreboard... a lot of these variables are global
  342.  * only to avoid getting clobbered by the longjmp() that happens when
  343.  * a hard timeout expires...
  344.  *
  345.  * We begin with routines which deal with the file itself... 
  346.  */
  347.  
  348. static short_score scoreboard_image[HARD_SERVER_MAX];
  349. static int have_scoreboard_fname = 0;
  350. static int scoreboard_fd;
  351.  
  352. static int force_write (int fd, char *buffer, int bufsz)
  353. {
  354.     int rv, orig_sz = bufsz;
  355.     
  356.     do {
  357.     rv = write (fd, buffer, bufsz);
  358.     if (rv > 0) {
  359.         buffer += rv;
  360.         bufsz -= rv;
  361.     }
  362.     } while (rv > 0 && bufsz > 0);
  363.  
  364.     return rv < 0? rv : orig_sz - bufsz;
  365. }
  366.  
  367. static int force_read (int fd, char *buffer, int bufsz)
  368. {
  369.     int rv, orig_sz = bufsz;
  370.     
  371.     do {
  372.     rv = read (fd, buffer, bufsz);
  373.     if (rv > 0) {
  374.         buffer += rv;
  375.         bufsz -= rv;
  376.     }
  377.     } while (rv > 0 && bufsz > 0);
  378.     
  379.     return rv < 0? rv : orig_sz - bufsz;
  380. }
  381.  
  382. void reinit_scoreboard (pool *p)
  383. {
  384.     scoreboard_fname = server_root_relative (p, scoreboard_fname);
  385.  
  386.     have_scoreboard_fname = 1;
  387.     
  388.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0644);
  389.     if (scoreboard_fd == -1)
  390.     {
  391.     fprintf (stderr, "Cannot open scoreboard file:\n");
  392.     perror (scoreboard_fname);
  393.     exit (1);
  394.     }
  395.  
  396.     memset ((char*)scoreboard_image, 0, sizeof(scoreboard_image));
  397.     force_write (scoreboard_fd, (char*)scoreboard_image,
  398.          sizeof(scoreboard_image));
  399. }
  400.  
  401. void reopen_scoreboard (pool *p)
  402. {
  403.     if (scoreboard_fd != -1) pclosef (p, scoreboard_fd);
  404.     
  405.     scoreboard_fd = popenf(p, scoreboard_fname, O_CREAT|O_RDWR, 0666);
  406.     if (scoreboard_fd == -1)
  407.     {
  408.     fprintf (stderr, "Cannot open scoreboard file:\n");
  409.     perror (scoreboard_fname);
  410.     exit (1);
  411.     }
  412. }
  413.  
  414. void cleanup_scoreboard ()
  415. {
  416.     unlink (scoreboard_fname);
  417. }
  418.  
  419. /* Routines called to deal with the scoreboard image
  420.  * --- note that we do *not* need write locks, since update_child_status
  421.  * only updates a *single* record in place, and only one process writes to
  422.  * a given scoreboard slot at a time (either the child process owning that
  423.  * slot, or the parent, noting that the child has died).
  424.  *
  425.  * As a final note --- setting the score entry to getpid() is always safe,
  426.  * since when the parent is writing an entry, it's only noting SERVER_DEAD
  427.  * anyway.
  428.  */
  429.  
  430. void sync_scoreboard_image ()
  431. {
  432.     lseek (scoreboard_fd, 0L, 0);
  433.     force_read (scoreboard_fd, (char*)scoreboard_image,
  434.         sizeof(scoreboard_image));
  435. }
  436.  
  437. void update_child_status (int child_num, int status)
  438. {
  439.     short_score new_score_rec;
  440.     new_score_rec.pid = getpid();
  441.     new_score_rec.status = status;
  442.  
  443.     lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
  444.     force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
  445. }
  446.  
  447. int count_idle_servers ()
  448. {
  449.     int i;
  450.     int res = 0;
  451.  
  452.     for (i = 0; i < HARD_SERVER_MAX; ++i)
  453.     if (scoreboard_image[i].status == SERVER_READY
  454.       || scoreboard_image[i].status == SERVER_STARTING)
  455.         ++res;
  456.  
  457.     return res;
  458. }
  459.  
  460. int find_free_child_num ()
  461. {
  462.     int i;
  463.  
  464.     for (i = 0; i < HARD_SERVER_MAX; ++i)
  465.     if (scoreboard_image[i].status == SERVER_DEAD)
  466.         return i;
  467.  
  468.     return -1;
  469. }
  470.  
  471. int find_child_by_pid (int pid)
  472. {
  473.     int i;
  474.  
  475.     for (i = 0; i < HARD_SERVER_MAX; ++i)
  476.     if (scoreboard_image[i].pid == pid)
  477.         return i;
  478.  
  479.     return -1;
  480. }
  481.  
  482. void reclaim_child_processes ()
  483. {
  484.     int i, status;
  485.     int my_pid = getpid();
  486.  
  487.     sync_scoreboard_image();
  488.     for (i = 0; i < HARD_SERVER_MAX; ++i) {
  489.     int pid = scoreboard_image[i].pid;
  490.  
  491.     if (pid != my_pid && pid != 0)
  492.         waitpid (scoreboard_image[i].pid, &status, 0);
  493.     }
  494. }
  495.  
  496. /* Finally, this routine is used by the caretaker process to wait for
  497.  * a while...
  498.  */
  499.  
  500. static jmp_buf wait_timeout_buf;
  501. static int wait_or_timeout_retval = -1;
  502.  
  503. static void longjmp_out_of_alarm (int sig) {
  504.     longjmp (wait_timeout_buf, 1);
  505. }
  506.  
  507. int wait_or_timeout (int *status)
  508. {
  509.     wait_or_timeout_retval = -1;
  510.     
  511.     if (setjmp(wait_timeout_buf) != 0) {
  512.     errno = ETIMEDOUT;
  513.     alarm(0);
  514.     return wait_or_timeout_retval;
  515.     }
  516.     
  517.     signal (SIGALRM, longjmp_out_of_alarm);
  518.     alarm(1);
  519. #if defined(NEXT)
  520.     wait_or_timeout_retval = wait((union wait *)status);
  521. #else
  522.     wait_or_timeout_retval = wait(status);
  523. #endif
  524.     alarm(0);
  525.     return wait_or_timeout_retval;
  526. }
  527.  
  528.  
  529. /*****************************************************************
  530.  * Here follows a long bunch of generic server bookkeeping stuff...
  531.  */
  532.  
  533. void detach()
  534. {
  535.     int x;
  536.  
  537.     chdir("/");
  538.     if((x = fork()) > 0)
  539.         exit(0);
  540.     else if(x == -1) {
  541.         fprintf(stderr,"httpd: unable to fork new process\n");
  542.         perror("fork");
  543.         exit(1);
  544.     }
  545. #ifndef NO_SETSID
  546.     if((pgrp=setsid()) == -1) {
  547.         fprintf(stderr,"httpd: setsid failed\n");
  548.         perror("setsid");
  549.         exit(1);
  550.     }
  551. #else
  552. #if defined(NEXT)
  553.     if(setpgrp(0,getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
  554.         fprintf(stderr,"httpd: setpgrp or getpgrp failed\n");
  555.         perror("setpgrp");
  556.         exit(1);
  557.     }
  558. #else
  559. #ifdef __EMX__
  560.     /* OS/2 doesn't support process group IDs */
  561.     pgrp=getpid();
  562. #else
  563.     if((pgrp=setpgrp(getpid(),0)) == -1) {
  564.         fprintf(stderr,"httpd: setpgrp failed\n");
  565.         perror("setpgrp");
  566.         exit(1);
  567.     }
  568. #endif    
  569. #endif    
  570. #endif
  571. }
  572.  
  573. void sig_term() {
  574.     log_error("httpd: caught SIGTERM, shutting down", server_conf);
  575.     cleanup_scoreboard();
  576. #ifndef NO_KILLPG
  577.     killpg(pgrp,SIGKILL);
  578. #else
  579.     kill(-pgrp,SIGKILL);
  580. #endif
  581.     shutdown(sd,2);
  582.     close(sd);
  583.     exit(1);
  584. }
  585.  
  586. void bus_error() {
  587.     log_error("httpd: caught SIGBUS, dumping core", server_conf);
  588.     chdir(server_root);
  589.     abort();         
  590.     exit(1);
  591. }
  592.  
  593. void seg_fault() {
  594.     log_error("httpd: caught SIGSEGV, dumping core", server_conf);
  595.     chdir(server_root);
  596.     abort();
  597.     exit(1);
  598. }
  599.  
  600. void just_die()            /* SIGHUP to child process??? */
  601. {
  602.     exit (0);
  603. }
  604.  
  605. /* Reset group privileges, after rereading the config files
  606.  * (our uid may have changed, and if so, we want the new perms).
  607.  *
  608.  * Don't reset the uid yet --- we do that only in the child process,
  609.  * so as not to lose any root privs.  But we can set the group stuff
  610.  * now, once, as opposed to once per each new child.
  611.  *
  612.  * Note that we use the username as set in the config files, rather than
  613.  * the lookup of to uid --- the same uid may have multiple passwd entries,
  614.  * with different sets of groups for each.
  615.  */
  616.   
  617. static void set_group_privs()
  618. {
  619.   if(!geteuid()) {
  620.     char *name;
  621.   
  622.     /* Get username if passed as a uid */
  623.     
  624.     if (user_name[0] == '#') {
  625.       struct passwd* ent;
  626.       uid_t uid=atoi(&user_name[1]);
  627.  
  628.       if ((ent = getpwuid(uid)) == NULL) {
  629.      log_error("couldn't determine user name from uid", server_conf);
  630.      exit(1);
  631.       }
  632.       
  633.       name = ent->pw_name;
  634.     } else name = user_name;
  635.  
  636. #ifndef __EMX__ 
  637.     /* OS/2 dosen't support groups. */
  638.  
  639.     /* Reset `groups' attributes. */
  640.     
  641.     if (initgroups(name, group_id) == -1) {
  642.     log_unixerr("initgroups", NULL, "unable to set groups", server_conf);
  643.     exit (1);
  644.     }
  645.  
  646.     if (setgid(group_id) == -1) {
  647.     log_unixerr("setgid", NULL, "unable to set group id", server_conf);
  648.     exit (1);
  649.     }
  650. #endif
  651.   }
  652. }
  653.  
  654. void restart() {
  655.     signal (SIGALRM, SIG_IGN);
  656.     alarm (0);
  657. #ifdef NEXT
  658.     longjmp(restart_buffer,1);
  659. #else
  660.     siglongjmp(restart_buffer,1);
  661. #endif
  662. }
  663.  
  664. void set_signals() {
  665.     if(!one_process)
  666.     {
  667.         signal(SIGSEGV,(void (*)())seg_fault);
  668.         signal(SIGBUS,(void (*)())bus_error);
  669.     }
  670.     signal(SIGTERM,(void (*)())sig_term);
  671.     signal(SIGHUP,(void (*)())restart);
  672. }
  673.  
  674. /*****************************************************************
  675.  * Connection structures and accounting...
  676.  * Should these be global?  Only to this file, at least...
  677.  */
  678.  
  679. pool *pconf;            /* Pool for config stuff */
  680. pool *ptrans;            /* Pool for per-transaction stuff */
  681.  
  682. server_rec *find_virtual_server (struct in_addr server_ip, server_rec *server)
  683. {
  684.     server_rec *virt;
  685.  
  686.     for (virt = server->next; virt; virt = virt->next)
  687.     if (virt->host_addr.s_addr == server_ip.s_addr)
  688.         return virt;
  689.  
  690.     return server;
  691. }
  692.  
  693. void default_server_hostnames(server_rec *s)
  694. {
  695.     /* Main host first */
  696.     
  697.     if (!s->server_hostname)
  698.     s->server_hostname = get_local_host(pconf);
  699.  
  700.     /* Then virtual hosts */
  701.     
  702.     for (s = s->next; s; s = s->next)
  703.     if (!s->server_hostname) {
  704.         struct hostent *h = gethostbyaddr ((char *)&(s->host_addr),
  705.                            sizeof (struct in_addr),
  706.                            AF_INET);
  707.         if (h != NULL) {
  708.         s->server_hostname = pstrdup (pconf, (char *)h->h_name);
  709.         }
  710.     }
  711. }
  712.     
  713. void abort_connection (conn_rec *c)
  714. {
  715.     /* Make sure further I/O DOES NOT HAPPEN */
  716.     shutdown (fileno (c->client), 2);
  717.     signal (SIGPIPE, SIG_IGN);    /* Ignore further complaints */
  718.     c->aborted = 1;
  719. }
  720.  
  721. conn_rec *new_connection (pool *p, server_rec *server, FILE *in, FILE *out,
  722.               const struct sockaddr_in *saddr)
  723. {
  724.     conn_rec *conn = (conn_rec *)pcalloc (p, sizeof(conn_rec));
  725.     
  726.     /* Get a connection structure, and initialize what fields we can
  727.      * (the rest are zeroed out by pcalloc).
  728.      */
  729.     
  730.     conn = (conn_rec *)pcalloc(p, sizeof(conn_rec));
  731.     
  732.     conn->pool = p;
  733.     conn->server = find_virtual_server (saddr->sin_addr, server);
  734.     conn->client = out;
  735.     conn->request_in = in;
  736.     
  737.     get_remote_host(conn);
  738.     
  739.     return conn;
  740. }
  741.  
  742. /*****************************************************************
  743.  * Child process main loop.
  744.  * The following vars are static to avoid getting clobbered by longjmp();
  745.  * they are really private to child_main.
  746.  */
  747.  
  748. static int csd;
  749. static int dupped_csd;
  750. static int requests_this_child;
  751. static int child_num;
  752.  
  753. void child_main(int child_num_arg)
  754. {
  755.     int clen;
  756.     struct sockaddr sa_server;
  757.     struct sockaddr sa_client;
  758.  
  759. #ifdef ULTRIX_BRAIN_DEATH
  760.     extern char *rfc931();
  761. #else
  762.     extern char *rfc931 (struct sockaddr_in *, struct sockaddr_in *);
  763. #endif
  764.  
  765.     csd = -1;
  766.     dupped_csd = -1;
  767.     child_num = child_num_arg;
  768.     requests_this_child = 0;
  769.     reopen_scoreboard (pconf);
  770.     update_child_status (child_num, SERVER_READY);
  771.  
  772.     /* Only try to switch if we're running as root */
  773.     if(!geteuid() && setuid(user_id) == -1) {
  774.         log_unixerr("setuid", NULL, "unable to change uid", server_conf);
  775.     exit (1);
  776.     }
  777.  
  778. #ifdef NEXT
  779.     setjmp(jmpbuffer);
  780. #else
  781.     sigsetjmp(jmpbuffer,1);
  782. #endif
  783. #ifndef __EMX__
  784.     signal(SIGURG, timeout);
  785. #endif
  786.  
  787.     while (1) {
  788.     FILE *conn_in, *conn_out;
  789.     request_rec *r;
  790.       
  791.         alarm(0);        /* Cancel any outstanding alarms. */
  792.         timeout_req = NULL;    /* No request in progress */
  793.     current_conn = NULL;
  794.         signal(SIGPIPE, timeout);  
  795.     
  796.     clear_pool (ptrans);
  797.     
  798.     sync_scoreboard_image();
  799.     
  800.     if ((count_idle_servers() >= daemons_max_free)
  801.         || (max_requests_per_child > 0
  802.             && ++requests_this_child >= max_requests_per_child))
  803.     {
  804.         exit(0);
  805.     }
  806.  
  807.     clen=sizeof(sa_client);
  808.     update_child_status (child_num, SERVER_READY);
  809.     
  810.     accept_mutex_on();  /* Lock around "accept", if necessary */
  811.     
  812.     while ((csd=accept(sd, &sa_client, &clen)) == -1) 
  813.            if (errno != EINTR) 
  814.         log_unixerr("accept", "(client socket)", NULL, server_conf);
  815.  
  816.     accept_mutex_off(); /* unlock after "accept" */
  817.  
  818.     clen = sizeof(sa_server);
  819.     if(getsockname(csd, &sa_server, &clen) < 0) {
  820.         log_unixerr("getsockname", NULL, NULL, server_conf);
  821.         continue;
  822.     }
  823.     
  824.     dupped_csd = csd;
  825. #if defined(AUX) || defined(SCO)
  826.     if ((dupped_csd = dup(csd)) < 0) {
  827.         log_unixerr("dup", NULL, "couldn't duplicate csd", server_conf);
  828.         dupped_csd = csd;    /* Oh well... */
  829.     }
  830. #endif
  831.     update_child_status (child_num, SERVER_BUSY);
  832.     conn_in = pfdopen (ptrans, csd, "r");
  833.     conn_out = pfdopen (ptrans, dupped_csd, "w");
  834.  
  835.     current_conn = new_connection (ptrans, server_conf, conn_in, conn_out,
  836.                        (struct sockaddr_in *)&sa_server);
  837.  
  838.     if (current_conn->server->do_rfc931)
  839.         current_conn->remote_logname = 
  840.         rfc931((struct sockaddr_in *)&sa_client,
  841.                (struct sockaddr_in *)&sa_server);
  842.     
  843.     r = read_request (current_conn);
  844.     if (r) process_request (r); /* else premature EOF --- ignore */
  845.         
  846.     if (bytes_in_pool (ptrans) > 80000)
  847.         log_printf(r->server,
  848.                "Memory hog alert: allocated %ld bytes for %s",
  849.                bytes_in_pool (ptrans), r->the_request);
  850.         
  851.     fflush (conn_out);
  852.     pfclose (ptrans,conn_in);
  853.     pfclose (ptrans,conn_out);
  854.     }    
  855. }
  856.  
  857. void make_child(server_rec *server_conf, int child_num)
  858. {
  859.     int pid;
  860.  
  861.     if (one_process) {
  862.     signal (SIGHUP, (void (*)())just_die);
  863.     signal (SIGTERM, (void (*)())just_die);
  864.     child_main (child_num);
  865.     }
  866.  
  867.     if ((pid = fork()) == -1) {
  868.     log_unixerr("fork", NULL, "Unable to fork new process", server_conf);
  869. #ifdef __EMX__
  870.     sig_term();
  871. #endif
  872.     return;
  873.     } 
  874.     
  875.     if (!pid) {
  876.     signal (SIGHUP, (void (*)())just_die);
  877.     signal (SIGTERM, (void (*)())just_die);
  878.     child_main (child_num);
  879.     }
  880. }
  881.  
  882. /*****************************************************************
  883.  * Executive routines.
  884.  */
  885.  
  886. static int keepalive_value = 1;  
  887. static int one = 1;
  888. static int num_children = 0;
  889.  
  890. void standalone_main(int argc, char **argv)
  891. {
  892.     struct sockaddr_in sa_server;
  893.  
  894.     standalone = 1;
  895.     sd = -1;
  896.     
  897.     if (!one_process) detach(); 
  898.     
  899. #ifdef NEXT
  900.     setjmp(restart_buffer);
  901. #else
  902.     sigsetjmp(restart_buffer,1);
  903. #endif
  904.  
  905.     signal (SIGHUP, SIG_IGN);    /* Until we're done (re)reading config */
  906.     
  907.     if(!one_process)
  908. #ifndef NO_KILLPG
  909.       killpg(pgrp,SIGHUP);    /* Kill 'em off */
  910. #else
  911.       kill(-pgrp,SIGHUP);
  912. #endif
  913.     
  914.     if (sd != -1) {
  915.     reclaim_child_processes(); /* Not when just starting up */
  916.     log_error ("SIGHUP received.  Attempting to restart", server_conf);
  917.     }
  918.     
  919.     clear_pool (pconf);
  920.     ptrans = make_sub_pool (pconf);
  921.     
  922.     server_conf = read_config(pconf, ptrans, server_confname); 
  923.     open_logs(server_conf, pconf);
  924.     set_group_privs();
  925.     accept_mutex_init(pconf);
  926.     reinit_scoreboard(pconf);
  927.     
  928.     default_server_hostnames (server_conf);
  929.  
  930.     if ((sd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
  931.         fprintf(stderr,"httpd: could not get socket\n");
  932.         perror("socket");
  933.         exit(1);
  934.     }
  935.  
  936.     note_cleanups_for_fd (pconf, sd); /* arrange to close on exec or restart */
  937.     
  938.     if((setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)))
  939.        == -1) {
  940.         fprintf(stderr,"httpd: could not set socket option\n");
  941.         perror("setsockopt");
  942.         exit(1);
  943.     }
  944.     if((setsockopt(sd,SOL_SOCKET,SO_KEEPALIVE,(void *)&keepalive_value,
  945.         sizeof(keepalive_value))) == -1) {
  946.         fprintf(stderr,"httpd: could not set socket option SO_KEEPALIVE\n"); 
  947.         perror("setsockopt"); 
  948.         exit(1); 
  949.     }
  950.  
  951.     memset((char *) &sa_server, 0, sizeof(sa_server));
  952.     sa_server.sin_family=AF_INET;
  953.     sa_server.sin_addr=bind_address;
  954.     sa_server.sin_port=htons(server_conf->port);
  955.     if(bind(sd,(struct sockaddr *) &sa_server,sizeof(sa_server)) == -1) {
  956.     if (bind_address.s_addr != htonl(INADDR_ANY))
  957.         fprintf(stderr,"httpd: could not bind to address %s port %d\n",
  958.             inet_ntoa(bind_address), server_conf->port);
  959.     else
  960.         fprintf(stderr,"httpd: could not bind to port %d\n",
  961.             server_conf->port);
  962.         perror("bind");
  963.         exit(1);
  964.     }
  965.     listen(sd, 512);
  966.  
  967.     set_signals();
  968.     log_pid(pconf, pid_fname);
  969.  
  970.     num_children = 0;
  971.     
  972.     if (daemons_max_free < daemons_min_free + 1) /* Don't thrash... */
  973.     daemons_max_free = daemons_min_free + 1;
  974.  
  975.     while (num_children < daemons_to_start) {
  976.     make_child(server_conf, num_children++);
  977.     }
  978.  
  979.     log_error ("Server configured -- resuming normal operations", server_conf);
  980.     
  981.     while (1) {
  982.     int status, child_slot;
  983.     int pid = wait_or_timeout(&status);
  984.     
  985.     if (pid >= 0) {
  986.         /* Child died... note that it's gone in the scoreboard. */
  987.         sync_scoreboard_image();
  988.         child_slot = find_child_by_pid (pid);
  989.         if (child_slot >= 0) update_child_status (child_slot, SERVER_DEAD);
  990.         }
  991.  
  992.     sync_scoreboard_image();
  993.     if ((count_idle_servers() < daemons_min_free)
  994.         && (child_slot = find_free_child_num()) >= 0
  995.         && child_slot <= daemons_limit)
  996.         {
  997.         update_child_status(child_slot,SERVER_STARTING);
  998.         make_child(server_conf, child_slot);
  999.         }
  1000.     }
  1001.  
  1002. } /* standalone_main */
  1003.  
  1004. extern char *optarg;
  1005. extern int optind;
  1006.  
  1007. int
  1008. main(int argc, char *argv[])
  1009. {
  1010.     int c;
  1011.  
  1012.     init_alloc();
  1013.     pconf = permanent_pool;
  1014.     ptrans = make_sub_pool(pconf);
  1015.     
  1016.     server_argv0 = argv[0];
  1017.     strcpy (server_root, HTTPD_ROOT);
  1018.     strcpy (server_confname, SERVER_CONFIG_FILE);
  1019.  
  1020.     while((c = getopt(argc,argv,"Xd:f:v")) != -1) {
  1021.         switch(c) {
  1022.           case 'd':
  1023.             strcpy (server_root, optarg);
  1024.             break;
  1025.           case 'f':
  1026.             strcpy (server_confname, optarg);
  1027.             break;
  1028.           case 'v':
  1029.             printf("Server version %s.\n",SERVER_VERSION);
  1030.             exit(1);
  1031.       case 'X':
  1032.         ++one_process;    /* Weird debugging mode. */
  1033.         break;
  1034.           case '?':
  1035.             usage(argv[0]);
  1036.         }
  1037.     }
  1038.  
  1039. #ifdef __EMX__
  1040.     printf("%s \n",SERVER_VERSION);
  1041.     printf("OS/2 port by Garey Smiley <garey@slink.com> \n");
  1042. #endif
  1043.  
  1044.     setup_prelinked_modules();
  1045.     
  1046.     server_conf = read_config (pconf, ptrans, server_confname);
  1047.     
  1048.     if(standalone) {
  1049.         clear_pool (pconf);    /* standalone_main rereads... */
  1050.         standalone_main(argc, argv);
  1051.     }
  1052.     else {
  1053.         conn_rec *conn;
  1054.     request_rec *r;
  1055.     struct sockaddr sa_server;
  1056.       
  1057.     open_logs(server_conf, pconf);
  1058.     set_group_privs();
  1059.     default_server_hostnames (server_conf);
  1060.  
  1061.         user_id = getuid();
  1062.         group_id = getgid();
  1063.  
  1064.     c = sizeof(sa_server);
  1065.     if(getsockname(csd, &sa_server, &c) < 0) {
  1066.         perror("getsockname");
  1067.         fprintf(stderr, "Error getting local address\n");
  1068.         exit(1);
  1069.     }
  1070.     server_conf->port =ntohs(((struct sockaddr_in *)&sa_server)->sin_port);
  1071.     conn = new_connection (ptrans, server_conf, stdin, stdout,
  1072.                    (struct sockaddr_in *)&sa_server);
  1073.     r = read_request (conn);
  1074.     if (r) process_request (r); /* else premature EOF (ignore) */
  1075.     }
  1076.     exit (0);
  1077. }
  1078.  
  1079.  
  1080.