Changeset 6349


Ignore:
Timestamp:
Jul 16, 2008, 11:55:49 PM (13 years ago)
Author:
charles
Message:

(third-party) upgrade shttpd from 1.39 to the latest, 1.41

Location:
trunk
Files:
1 deleted
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/rpc-server.c

    r6343 r6349  
    329329    if( !server->ctx )
    330330    {
    331         char ports[128];
     331        int i;
     332        int argc = 0;
     333        char * argv[100];
    332334        char passwd[MAX_PATH_LENGTH];
    333335        const char * clutchDir = tr_getClutchDir( server->session );
     
    340342            edit_passwords( passwd, MY_REALM, server->username, server->password );
    341343
    342         server->ctx = shttpd_init( );
    343         tr_snprintf( ports, sizeof( ports ), "%d", server->port );
     344        argv[argc++] = tr_strdup( "appname-unused" );
     345        argv[argc++] = tr_strdup( "-ports" );
     346        argv[argc++] = tr_strdup_printf( "%d", server->port );
     347        argv[argc++] = tr_strdup( "-dir_list" );
     348        argv[argc++] = tr_strdup( "0" );
     349        argv[argc++] = tr_strdup( "-auth_realm" );
     350        argv[argc++] = tr_strdup( MY_REALM );
     351        if( server->acl )
     352        {
     353            argv[argc++] = tr_strdup( "-acl" );
     354            argv[argc++] = tr_strdup( server->acl );
     355        }
     356        if( server->isPasswordEnabled )
     357        {
     358            argv[argc++] = tr_strdup( "-protect" );
     359            argv[argc++] = tr_strdup_printf( "/transmission=%s", passwd );
     360        }
     361        if( clutchDir && *clutchDir )
     362        {
     363            tr_inf( _( "Serving the web interface files from \"%s\"" ), clutchDir );
     364            argv[argc++] = tr_strdup( "-aliases" );
     365            argv[argc++] = tr_strdup_printf( "%s=%s,%s=%s",
     366                                             "/transmission/clutch", clutchDir,
     367                                             "/transmission/web", clutchDir );
     368        }
     369
     370        server->ctx = shttpd_init( argc, argv );
    344371        shttpd_register_uri( server->ctx, "/transmission/rpc", handle_rpc, server );
    345372        shttpd_register_uri( server->ctx, "/transmission/upload", handle_upload, server );
    346373
    347         if( clutchDir && *clutchDir ) {
    348             char * clutchAlias = tr_strdup_printf( "%s=%s,%s=%s",
    349                 "/transmission/clutch", clutchDir,
    350                 "/transmission/web", clutchDir );
    351             tr_inf( _( "Serving the web interface files from \"%s\"" ), clutchDir );
    352             shttpd_set_option( server->ctx, "aliases", clutchAlias );
    353             tr_free( clutchAlias );
    354         }
    355 
    356         shttpd_set_option( server->ctx, "ports", ports );
    357         shttpd_set_option( server->ctx, "dir_list", "0" );
    358         //shttpd_set_option( server->ctx, "root", "/dev/null" );
    359         shttpd_set_option( server->ctx, "auth_realm", MY_REALM );
    360         if( server->acl ) {
    361             dbgmsg( "setting acl [%s]", server->acl );
    362             shttpd_set_option( server->ctx, "acl", server->acl );
    363         }
    364         if( server->isPasswordEnabled ) {
    365             char * buf = tr_strdup_printf( "/transmission=%s", passwd );
    366             shttpd_set_option( server->ctx, "protect", buf );
    367             tr_free( buf );
    368         }
    369 
    370374        evtimer_set( &server->timer, rpcPulse, server );
    371375        evtimer_add( &server->timer, &tv );
     376
     377        for( i=0; i<argc; ++i )
     378            tr_free( argv[i] );
    372379    }
    373380}
     
    430437
    431438/*
    432  * DELIM_CHARS, FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from,
     439 * FOR_EACH_WORD_IN_LIST, isbyte, and testACL are from, or modified from,
    433440 * shttpd, written by Sergey Lyubka under this license:
    434441 * "THE BEER-WARE LICENSE" (Revision 42):
     
    437444 * this stuff is worth it, you can buy me a beer in return.
    438445 */
    439 
    440 #define  DELIM_CHARS "," /* Separators for lists */
    441446
    442447#define FOR_EACH_WORD_IN_LIST(s,len)                                    \
  • trunk/third-party/shttpd/Makefile.am

    r5841 r6349  
    55
    66libshttpd_a_SOURCES = \
    7     string.c shttpd.c log.c auth.c md5.c cgi.c config.c \
     7    string.c shttpd.c log.c auth.c md5.c \
    88    io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c \
    99    compat_unix.c
  • trunk/third-party/shttpd/README

    r5822 r6349  
    11http://shttpd.sourceforge.net/
    22Sergey Lyubka wrote this software.
    3 This snapshot si from shttpd-1.39
     3This snapshot is from shttpd-1.41
  • trunk/third-party/shttpd/auth.c

    r5822 r6349  
    282282                if (!memcmp(c->uri, s, p - s)) {
    283283                       
    284                         n = s + len - p + 1;
     284                        n = s + len - p;
    285285                        if (n > (int) sizeof(protected_path) - 1)
    286286                                n = sizeof(protected_path) - 1;
    287                        
     287
    288288                        my_strlcpy(protected_path, p + 1, n);
    289                        
     289
    290290                        if ((fp = fopen(protected_path, "r")) == NULL)
    291291                                elog(E_LOG, c, "check_auth: cannot open %s: %s",
  • trunk/third-party/shttpd/cgi.c

    r5822 r6349  
    1919};
    2020
    21 /*
    22  * UNIX socketpair() implementation. Why? Because Windows does not have it.
    23  * Return 0 on success, -1 on error.
    24  */
    25 static int
    26 my_socketpair(struct conn *c, int sp[2])
    27 {
    28         struct sockaddr_in      sa;
    29         int                     sock, ret = -1;
    30         socklen_t               len = sizeof(sa);
    31 
    32         (void) memset(&sa, 0, sizeof(sa));
    33         sa.sin_family           = AF_INET;
    34         sa.sin_port             = htons(0);
    35         sa.sin_addr.s_addr      = htonl(INADDR_LOOPBACK);
    36 
    37         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    38                 elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO);
    39         } else if (bind(sock, (struct sockaddr *) &sa, len) != 0) {
    40                 elog(E_LOG, c, "mysocketpair: bind(): %d", ERRNO);
    41                 (void) closesocket(sock);
    42         } else if (listen(sock, 1) != 0) {
    43                 elog(E_LOG, c, "mysocketpair: listen(): %d", ERRNO);
    44                 (void) closesocket(sock);
    45         } else if (getsockname(sock, (struct sockaddr *) &sa, &len) != 0) {
    46                 elog(E_LOG, c, "mysocketpair: getsockname(): %d", ERRNO);
    47                 (void) closesocket(sock);
    48         } else if ((sp[0] = socket(AF_INET, SOCK_STREAM, 6)) == -1) {
    49                 elog(E_LOG, c, "mysocketpair: socket(): %d", ERRNO);
    50                 (void) closesocket(sock);
    51         } else if (connect(sp[0], (struct sockaddr *) &sa, len) != 0) {
    52                 elog(E_LOG, c, "mysocketpair: connect(): %d", ERRNO);
    53                 (void) closesocket(sock);
    54                 (void) closesocket(sp[0]);
    55         } else if ((sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) == -1) {
    56                 elog(E_LOG, c, "mysocketpair: accept(): %d", ERRNO);
    57                 (void) closesocket(sock);
    58                 (void) closesocket(sp[0]);
    59         } else {
    60                 /* Success */
    61                 ret = 0;
    62                 (void) closesocket(sock);
    63         }
    64 
    65 #ifndef _WIN32
    66         (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
    67         (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
    68 #endif /* _WIN32*/
    69 
    70         return (ret);
    71 }
    72 
    7321static void
    7422addenv(struct env_block *block, const char *fmt, ...)
     
    14694{
    14795        const struct headers    *h = &c->ch;
    148         const char              *s, *root = c->ctx->options[OPT_ROOT];
     96        const char              *s, *fname, *root = c->ctx->options[OPT_ROOT];
    14997        size_t                  len;
    15098
    15199        blk->len = blk->nvars = 0;
     100
     101        /* SCRIPT_FILENAME */
     102        fname = prog;
     103        if ((s = strrchr(prog, '/')))
     104                fname = s + 1;
    152105
    153106        /* Prepare the environment block */
     
    164117        addenv(blk, "REQUEST_URI=%s", c->uri);
    165118        addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root));
    166         addenv(blk, "SCRIPT_FILENAME=%s", prog);        /* PHP */
     119        addenv(blk, "SCRIPT_FILENAME=%s", fname);       /* PHP */
    167120        addenv(blk, "PATH_TRANSLATED=%s", prog);
    168121
     
    245198                }
    246199       
    247         if (my_socketpair(c, pair) != 0) {
     200        if (shttpd_socketpair(pair) != 0) {
    248201                ret = -1;
    249202        } else if (spawn_process(c, prog, blk.buf, blk.vars, pair[1], dir)) {
  • trunk/third-party/shttpd/compat_unix.h

    r5822 r6349  
    2121#include <dirent.h>
    2222#include <dlfcn.h>
     23
     24#if !defined(NO_THREADS)
     25#include "pthread.h"
     26#define _beginthread(a, b, c) do { pthread_t tid; \
     27        pthread_create(&tid, NULL, (void *(*)(void *))a, c); } while (0)
     28#endif /* !NO_THREADS */
     29
    2330#define SSL_LIB                         "libssl.so"
    2431#define DIRSEP                          '/'
     
    2734#define closesocket(a)                  close(a)
    2835#define ERRNO                           errno
    29 #define NO_GUI
    30 
    31 #define InitializeCriticalSection(x)    /* FIXME UNIX version is not MT safe */
    32 #define EnterCriticalSection(x)
    33 #define LeaveCriticalSection(x)
  • trunk/third-party/shttpd/config.h

    r6106 r6349  
    1212#define CONFIG_HEADER_DEFINED
    1313
    14 #undef VERSION 
    15 #define VERSION         "1.39"          /* Version                      */
     14#undef VERSION
     15#define VERSION         "1.41"          /* Version                      */
    1616#define CONFIG_FILE     "shttpd.conf"   /* Configuration file           */
    1717#define HTPASSWD        ".htpasswd"     /* Passwords file name          */
     
    2626#define ENV_MAX         4096            /* Size of environment block    */
    2727#define CGI_ENV_VARS    64              /* Maximum vars passed to CGI   */
     28#define SERVICE_NAME    "SHTTPD " VERSION       /* NT service name      */
    2829
    2930#endif /* CONFIG_HEADER_DEFINED */
  • trunk/third-party/shttpd/defs.h

    r5841 r6349  
    1515#include "llist.h"
    1616#include "io.h"
    17 #include "shttpd.h"
    1817#include "md5.h"
    1918#include "config.h"
     19#include "shttpd.h"
    2020
    2121#define NELEMS(ar)      (sizeof(ar) / sizeof(ar[0]))
     
    2727#endif /* DEBUG */
    2828
    29 #ifdef EMBEDDED
    30 #include "shttpd.h"
    31 #endif /* EMBEDDED */
    32 
    3329/*
    3430 * Darwin prior to 7.0 and Win32 do not have socklen_t
     
    4642};
    4743
    48 #if !defined(_WIN32)
     44#if !defined(FALSE)
    4945enum {FALSE, TRUE};
    50 #endif /* _WIN32 */
     46#endif /* !FALSE */
     47
    5148enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
    5249enum {HDR_DATE, HDR_INT, HDR_STRING};   /* HTTP header types            */
     
    176173        struct io               io;             /* IO buffer            */
    177174        const struct io_class   *io_class;      /* IO class             */
    178         int                     nread_last;     /* Bytes last read      */
    179175        int                     headers_len;
    180176        big_int_t               content_len;
     
    187183#define FLAG_DONT_CLOSE         32
    188184#define FLAG_ALWAYS_READY       64              /* File, dir, user_func */
     185#define FLAG_SUSPEND            128
     186};
     187
     188struct worker {
     189        struct llhead   link;
     190        int             num_conns;      /* Num of active connections    */
     191        int             exit_flag;      /* Ditto - exit flag            */
     192        int             ctl[2];         /* Control socket pair          */
     193        struct shttpd_ctx *ctx;         /* Context reference            */
     194        struct llhead   connections;    /* List of connections          */
    189195};
    190196
    191197struct conn {
    192198        struct llhead   link;           /* Connections chain            */
     199        struct worker   *worker;        /* Worker this conn belongs to  */
    193200        struct shttpd_ctx *ctx;         /* Context this conn belongs to */
    194201        struct usa      sa;             /* Remote socket address        */
     
    224231        OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES,
    225232        OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_INETD, OPT_UID,
    226         OPT_CFG_URI, OPT_PROTECT,
     233        OPT_CFG_URI, OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_THREADS,
    227234        NUM_OPTIONS
    228235};
     
    232239 */
    233240struct shttpd_ctx {
    234         time_t          start_time;     /* Start time                   */
    235         int             nactive;        /* # of connections now         */
    236         unsigned long   nrequests;      /* Requests made                */
    237         uint64_t        in, out;        /* IN/OUT traffic counters      */
    238241        SSL_CTX         *ssl_ctx;       /* SSL context                  */
    239         struct llhead   connections;    /* List of connections          */
    240242
    241243        struct llhead   registered_uris;/* User urls                    */
    242244        struct llhead   error_handlers; /* Embedded error handlers      */
    243245        struct llhead   acl;            /* Access control list          */
    244 #if !defined(NO_SSI)
    245246        struct llhead   ssi_funcs;      /* SSI callback functions       */
    246 #endif
    247247        struct llhead   listeners;      /* Listening sockets            */
    248 
    249         FILE    *access_log;            /* Access log stream            */
    250         FILE    *error_log;             /* Error log stream             */
     248        struct llhead   workers;        /* Worker workers               */
     249
     250        FILE            *access_log;    /* Access log stream            */
     251        FILE            *error_log;     /* Error log stream             */
    251252
    252253        char    *options[NUM_OPTIONS];  /* Configurable options         */
    253 
    254 #if defined(_WIN32)
    255         CRITICAL_SECTION mutex;         /* For MT case                  */
    256         HANDLE          ev[2];          /* For thread synchronization */
    257 #elif defined(__rtems__)
     254#if defined(__rtems__)
    258255        rtems_id         mutex;
    259256#endif /* _WIN32 */
    260257};
    261258
    262 #define IS_TRUE(ctx, opt) ((ctx)->options[opt] && (ctx)->options[opt][0] =='1')
     259struct listener {
     260        struct llhead           link;
     261        struct shttpd_ctx       *ctx;   /* Context that socket belongs  */
     262        int                     sock;   /* Listening socket             */
     263        int                     is_ssl; /* Should be SSL-ed             */
     264};
     265
     266/* Types of messages that could be sent over the control socket */
     267enum {CTL_PASS_SOCKET, CTL_WAKEUP};
    263268
    264269/*
     
    301306extern int      get_headers_len(const char *buf, size_t buflen);
    302307extern void     parse_headers(const char *s, int len, struct headers *parsed);
    303 extern void     open_listening_ports(struct shttpd_ctx *ctx);
     308extern int      is_true(const char *str);
     309extern int      shttpd_socketpair(int pair[2]);
    304310extern void get_mime_type(struct shttpd_ctx *, const char *, int, struct vec *);
    305 extern void     free_list(struct llhead *head, void (*)(struct llhead *));
    306 extern void     registered_uri_destructor(struct llhead *);
    307 extern void     listener_destructor(struct llhead *);
     311
     312#define IS_TRUE(ctx, opt)       is_true((ctx)->options[opt])
    308313
    309314/*
     
    343348                char *envblk, char *envp[], int sock, const char *dir);
    344349
     350extern void     set_nt_service(struct shttpd_ctx *, const char *);
     351extern void     set_systray(struct shttpd_ctx *, const char *);
     352extern void     try_to_run_as_nt_service(void);
     353
    345354/*
    346355 * io_*.c
     
    361370extern struct registered_uri *is_registered_uri(struct shttpd_ctx *,
    362371                const char *uri);
    363 #if !defined(NO_SSI)
    364372extern void     do_ssi(struct conn *);
    365373extern void     ssi_func_destructor(struct llhead *lp);
    366 #endif
    367374
    368375/*
  • trunk/third-party/shttpd/io_emb.c

    r5822 r6349  
    5353        else
    5454                c->loc.flags |= FLAG_DONT_CLOSE;
     55
     56        if (arg->flags & SHTTPD_SUSPEND)
     57                c->loc.flags |= FLAG_SUSPEND;
    5558}
    5659
     
    9194shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
    9295{
    93         struct conn     *c = arg->priv;
    94         struct io       *io = &c->loc.io;
    9596        char            *buf = arg->out.buf + arg->out.num_bytes;
    9697        int             buflen = arg->out.len - arg->out.num_bytes, len = 0;
    9798        va_list         ap;
    98 
    99         assert(buf <= io->buf + io->size);
    10099
    101100        if (buflen > 0) {
     
    268267}
    269268
     269void
     270shttpd_wakeup(const void *priv)
     271{
     272        const struct conn       *conn = priv;
     273        char                    buf[sizeof(int) + sizeof(void *)];
     274        int                     cmd = CTL_WAKEUP;
     275
     276#if 0
     277        conn->flags &= ~SHTTPD_SUSPEND;
     278#endif
     279        (void) memcpy(buf, &cmd, sizeof(cmd));
     280        (void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
     281
     282        (void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
     283}
     284
    270285const struct io_class   io_embedded =  {
    271286        "embedded",
  • trunk/third-party/shttpd/io_file.c

    r5822 r6349  
    2121        n = write(fd, buf, len);
    2222
    23         DBG(("put_file(%p, %d): %d bytes", (void *) stream, len, n));
     23        DBG(("put_file(%p, %d): %d bytes", (void *) stream, (int) len, n));
    2424
    2525        if (n <= 0 || (rem->io.total >= (big_int_t) rem->headers_len)) {
  • trunk/third-party/shttpd/io_ssl.c

    r5822 r6349  
    3434        int     n;
    3535
    36         if ((n = SSL_accept(stream->chan.ssl.ssl)) == 0) {
     36        if ((n = SSL_accept(stream->chan.ssl.ssl)) == 1) {
     37                DBG(("handshake: SSL accepted"));
     38                stream->flags |= FLAG_SSL_ACCEPTED;
     39        } else {
    3740                n = SSL_get_error(stream->chan.ssl.ssl, n);
    3841                if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
    3942                        stream->flags |= FLAG_CLOSED;
    40                 elog(E_LOG, stream->conn, "SSL_accept error %d", n);
    41         } else {
    42                 DBG(("handshake: SSL accepted"));
    43                 stream->flags |= FLAG_SSL_ACCEPTED;
     43                DBG(("SSL_accept error %d", n));
    4444        }
    4545}
     
    4848read_ssl(struct stream *stream, void *buf, size_t len)
    4949{
    50         int     nread = 0;
     50        int     nread = -1;
    5151
    5252        assert(stream->chan.ssl.ssl != NULL);
  • trunk/third-party/shttpd/shttpd.c

    r5841 r6349  
    1111/*
    1212 * Small and portable HTTP server, http://shttpd.sourceforge.net
    13  * $Id: shttpd.c,v 1.28 2008/02/17 21:45:09 drozd Exp $
     13 * $Id: shttpd.c,v 1.44 2008/05/31 18:20:02 drozd Exp $
    1414 */
    1515
    1616#include "defs.h"
    1717
    18 time_t          current_time;   /* Current UTC time             */
    19 int             tz_offset;      /* Time zone offset from UTC    */
     18time_t  current_time;   /* Current UTC time             */
     19int     tz_offset;      /* Time zone offset from UTC    */
     20int     exit_flag;      /* Program exit flag            */
    2021
    2122const struct vec known_http_methods[] = {
     
    2627        {"HEAD",        4},
    2728        {NULL,          0}
    28 };
    29 
    30 struct listener {
    31         struct llhead   link;
    32         struct shttpd_ctx *ctx;         /* Context that socket belongs  */
    33         int             sock;           /* Listening socket             */
    34         int             is_ssl;         /* Should be SSL-ed             */
    3529};
    3630
     
    6054
    6155int
     56is_true(const char *str)
     57{
     58        static const char       *trues[] = {"1", "yes", "true", "jawohl", NULL};
     59        const char              **p;
     60
     61        for (p = trues; *p != NULL; p++)
     62                if (str && !strcmp(str, *p))
     63                        return (TRUE);
     64
     65        return (FALSE);
     66}
     67
     68static void
     69free_list(struct llhead *head, void (*dtor)(struct llhead *))
     70{
     71        struct llhead   *lp, *tmp;
     72
     73        LL_FOREACH_SAFE(head, lp, tmp) {
     74                LL_DEL(lp);
     75                dtor(lp);
     76        }
     77}
     78
     79static void
     80listener_destructor(struct llhead *lp)
     81{
     82        struct listener *listener = LL_ENTRY(lp, struct listener, link);
     83
     84        (void) closesocket(listener->sock);
     85        free(listener);
     86}
     87
     88static void
     89registered_uri_destructor(struct llhead *lp)
     90{
     91        struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
     92
     93        free((void *) ruri->uri);
     94        free(ruri);
     95}
     96
     97static void
     98acl_destructor(struct llhead *lp)
     99{
     100        struct acl      *acl = LL_ENTRY(lp, struct acl, link);
     101        free(acl);
     102}
     103
     104int
    62105url_decode(const char *src, int src_len, char *dst, int dst_len)
    63106{
     
    127170            stream->conn->rem.chan.sock,
    128171            stream->io_class ? stream->io_class->name : "(null)",
    129             (unsigned long) stream->io.total, io_data_len(&stream->io)));
     172            (unsigned long) stream->io.total, (int) io_data_len(&stream->io)));
    130173}
    131174
     
    134177 */
    135178static int
    136 open_listening_port(int port)
     179shttpd_open_listening_port(int port)
    137180{
    138181        int             sock, on = 1;
     
    484527        return (-1);
    485528}
    486 
    487529
    488530static void
     
    639681        }
    640682
    641         io_inc_tail(&c->rem.io, req_len);
    642 
    643683        if (req_len == 0) {
    644684                return;
     
    653693        if (c->loc.flags & FLAG_CLOSED)
    654694                return;
     695
     696        io_inc_tail(&c->rem.io, req_len);
    655697
    656698        DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s));
     
    706748}
    707749
    708 void
    709 shttpd_add_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
    710 {
    711         struct conn     *c;
    712         struct usa      sa;
    713         int             l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
     750static void
     751add_socket(struct worker *worker, int sock, int is_ssl)
     752{
     753        struct shttpd_ctx       *ctx = worker->ctx;
     754        struct conn             *c;
     755        struct usa              sa;
     756        int                     l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
    714757#if !defined(NO_SSL)
    715758        SSL             *ssl = NULL;
     759#else
     760        is_ssl = is_ssl;        /* supress warnings */
    716761#endif /* NO_SSL */
    717762
     
    738783                elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO));
    739784        } else {
    740                 ctx->nrequests++;
    741                 c->rem.conn = c->loc.conn = c;
     785                c->rem.conn     = c->loc.conn = c;
    742786                c->ctx          = ctx;
     787                c->worker       = worker;
    743788                c->sa           = sa;
    744789                c->birth_time   = current_time;
     
    769814#endif /* NO_SSL */
    770815
    771                 EnterCriticalSection(&ctx->mutex);
    772                 LL_TAIL(&ctx->connections, &c->link);
    773                 ctx->nactive++;
    774                 LeaveCriticalSection(&ctx->mutex);
     816                LL_TAIL(&worker->connections, &c->link);
     817                worker->num_conns++;
    775818               
    776819                DBG(("%s:%hu connected (socket %d)",
     
    780823}
    781824
    782 int
    783 shttpd_active(struct shttpd_ctx *ctx)
    784 {
    785         return (ctx->nactive);
    786 }
    787 
    788 /*
    789  * Setup a listening socket on given port. Return opened socket or -1
    790  */
    791 int
    792 shttpd_listen(struct shttpd_ctx *ctx, int port, int is_ssl)
    793 {
     825static struct worker *
     826first_worker(struct shttpd_ctx *ctx)
     827{
     828        return (LL_ENTRY(ctx->workers.next, struct worker, link));
     829}
     830
     831static void
     832pass_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
     833{
     834        struct llhead   *lp;
     835        struct worker   *worker, *lazy;
     836        int             buf[3];
     837
     838        lazy = first_worker(ctx);
     839
     840        /* Find least busy worker */
     841        LL_FOREACH(&ctx->workers, lp) {
     842                worker = LL_ENTRY(lp, struct worker, link);
     843                if (worker->num_conns < lazy->num_conns)
     844                        lazy = worker;
     845        }
     846
     847        buf[0] = CTL_PASS_SOCKET;
     848        buf[1] = sock;
     849        buf[2] = is_ssl;
     850
     851        (void) send(lazy->ctl[1], (void *) buf, sizeof(buf), 0);
     852}
     853
     854static void
     855set_ports(struct shttpd_ctx *ctx, const char *p)
     856{
     857        int             sock, len, is_ssl, port;
    794858        struct listener *l;
    795         int             sock;
    796 
    797         if ((sock = open_listening_port(port)) == -1) {
    798                 elog(E_FATAL, NULL, "cannot open port %d", port);
    799         } else if ((l = calloc(1, sizeof(*l))) == NULL) {
    800                 (void) closesocket(sock);
    801                 elog(E_FATAL, NULL, "cannot allocate listener");
    802         } else if (is_ssl && ctx->ssl_ctx == NULL) {
    803                 (void) closesocket(sock);
    804                 elog(E_FATAL, NULL, "cannot add SSL socket, "
    805                     "please specify certificate file");
    806         } else {
    807                 l->is_ssl = is_ssl;
    808                 l->sock = sock;
    809                 l->ctx  = ctx;
    810                 LL_TAIL(&ctx->listeners, &l->link);
    811                 DBG(("shttpd_listen: added socket %d", sock));
    812         }
    813 
    814         return (sock);
    815 }
    816 
    817 int
    818 shttpd_accept(int lsn_sock, int milliseconds)
    819 {
    820         struct timeval  tv;
    821         struct usa      sa;
    822         fd_set          read_set;
    823         int             sock = -1;
    824        
    825         tv.tv_sec       = milliseconds / 1000;
    826         tv.tv_usec      = milliseconds % 1000;
    827         sa.len          = sizeof(sa.u.sin);
    828         FD_ZERO(&read_set);
    829         FD_SET(lsn_sock, &read_set);
    830        
    831         if (select(lsn_sock + 1, &read_set, NULL, NULL, &tv) == 1)
    832                 sock = accept(lsn_sock, &sa.u.sa, &sa.len);
    833 
    834         return (sock);
     859
     860
     861        free_list(&ctx->listeners, &listener_destructor);
     862
     863        FOR_EACH_WORD_IN_LIST(p, len) {
     864
     865                is_ssl  = p[len - 1] == 's' ? 1 : 0;
     866                port    = atoi(p);
     867
     868                if ((sock = shttpd_open_listening_port(port)) == -1) {
     869                        elog(E_FATAL, NULL, "cannot open port %d", port);
     870                } else if ((l = calloc(1, sizeof(*l))) == NULL) {
     871                        (void) closesocket(sock);
     872                        elog(E_FATAL, NULL, "cannot allocate listener");
     873                } else if (is_ssl && ctx->ssl_ctx == NULL) {
     874                        (void) closesocket(sock);
     875                        elog(E_FATAL, NULL, "cannot add SSL socket, "
     876                            "please specify certificate file");
     877                } else {
     878                        l->is_ssl = is_ssl;
     879                        l->sock = sock;
     880                        l->ctx  = ctx;
     881                        LL_TAIL(&ctx->listeners, &l->link);
     882                        DBG(("shttpd_listen: added socket %d", sock));
     883                }
     884        }
    835885}
    836886
     
    849899
    850900        /* Read from underlying channel */
    851         n = stream->nread_last = stream->io_class->read(stream,
    852             io_space(&stream->io), len);
     901        n = stream->io_class->read(stream, io_space(&stream->io), len);
    853902
    854903        if (n > 0)
     
    904953
    905954static void
    906 disconnect(struct llhead *lp)
     955connection_desctructor(struct llhead *lp)
    907956{
    908957        struct conn             *c = LL_ENTRY(lp, struct conn, link);
     
    942991                c->loc.flags = 0;
    943992                c->loc.content_len = 0;
    944                 c->rem.flags = FLAG_W | FLAG_R;
     993                c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED;
    945994                c->query = c->request = c->uri = c->path_info = NULL;
    946995                c->mime_type.len = 0;
     
    9541003                        c->rem.io_class->close(&c->rem);
    9551004
    956                 EnterCriticalSection(&c->ctx->mutex);
    9571005                LL_DEL(&c->link);
    958                 c->ctx->nactive--;
    959                 assert(c->ctx->nactive >= 0);
    960                 LeaveCriticalSection(&c->ctx->mutex);
     1006                c->worker->num_conns--;
     1007                assert(c->worker->num_conns >= 0);
    9611008
    9621009                free(c);
    9631010        }
     1011}
     1012
     1013static void
     1014worker_destructor(struct llhead *lp)
     1015{
     1016        struct worker   *worker = LL_ENTRY(lp, struct worker, link);
     1017
     1018        free_list(&worker->connections, connection_desctructor);
     1019        free(worker);
    9641020}
    9651021
     
    10011057                parse_http_request(c);
    10021058
    1003         DBG(("loc: %u [%.*s]", io_data_len(&c->loc.io),
    1004             io_data_len(&c->loc.io), io_data(&c->loc.io)));
    1005         DBG(("rem: %u [%.*s]", io_data_len(&c->rem.io),
    1006             io_data_len(&c->rem.io), io_data(&c->rem.io)));
     1059        DBG(("loc: %d [%.*s]", (int) io_data_len(&c->loc.io),
     1060            (int) io_data_len(&c->loc.io), io_data(&c->loc.io)));
     1061        DBG(("rem: %d [%.*s]", (int) io_data_len(&c->rem.io),
     1062            (int) io_data_len(&c->rem.io), io_data(&c->rem.io)));
    10071063
    10081064        /* Read from the local end if it is ready */
     
    10161072        if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL)
    10171073                write_stream(&c->loc, &c->rem);
    1018 
    1019         if (c->rem.nread_last > 0)
    1020                 c->ctx->in += c->rem.nread_last;
    1021         if (c->loc.nread_last > 0)
    1022                 c->ctx->out += c->loc.nread_last;
    10231074
    10241075        /* Check whether we should close this connection */
     
    10261077            (c->rem.flags & FLAG_CLOSED) ||
    10271078            ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io)))
    1028                 disconnect(&c->link);
    1029 }
    1030 
    1031 /*
    1032  * One iteration of server loop. This is the core of the data exchange.
    1033  */
    1034 void
    1035 shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
    1036 {
    1037         struct llhead   *lp, *tmp;
    1038         struct listener *l;
    1039         struct conn     *c;
    1040         struct timeval  tv;                     /* Timeout for select() */
    1041         fd_set          read_set, write_set;
    1042         int             sock, max_fd = -1, msec = milliseconds;
    1043         struct usa      sa;
    1044 
    1045         current_time = time(0);
    1046         FD_ZERO(&read_set);
    1047         FD_ZERO(&write_set);
    1048 
    1049         /* Add listening sockets to the read set */
    1050         LL_FOREACH(&ctx->listeners, lp) {
    1051                 l = LL_ENTRY(lp, struct listener, link);
    1052                 FD_SET(l->sock, &read_set);
    1053                 if (l->sock > max_fd)
    1054                         max_fd = l->sock;
    1055                 DBG(("FD_SET(%d) (listening)", l->sock));
    1056         }
    1057 
    1058         /* Multiplex streams */
    1059         LL_FOREACH(&ctx->connections, lp) {
    1060                 c = LL_ENTRY(lp, struct conn, link);
    1061                
    1062                 /* If there is a space in remote IO, check remote socket */
    1063                 if (io_space_len(&c->rem.io))
    1064                         add_to_set(c->rem.chan.fd, &read_set, &max_fd);
    1065 
    1066 #if !defined(NO_CGI)
    1067                 /*
    1068                  * If there is a space in local IO, and local endpoint is
    1069                  * CGI, check local socket for read availability
    1070                  */
    1071                 if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
    1072                     c->loc.io_class == &io_cgi)
    1073                         add_to_set(c->loc.chan.fd, &read_set, &max_fd);
    1074 
    1075                 /*
    1076                  * If there is some data read from remote socket, and
    1077                  * local endpoint is CGI, check local for write availability
    1078                  */
    1079                 if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
    1080                     c->loc.io_class == &io_cgi)
    1081                         add_to_set(c->loc.chan.fd, &write_set, &max_fd);
    1082 #endif /* NO_CGI */
    1083 
    1084                 /*
    1085                  * If there is some data read from local endpoint, check the
    1086                  * remote socket for write availability
    1087                  */
    1088                 if (io_data_len(&c->loc.io))
    1089                         add_to_set(c->rem.chan.fd, &write_set, &max_fd);
    1090 
    1091                 if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
    1092                     (c->loc.flags & FLAG_ALWAYS_READY))
    1093                         msec = 0;
    1094                
    1095                 if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
    1096                     (c->loc.flags & FLAG_ALWAYS_READY))
    1097                         msec = 0;
    1098         }
    1099 
    1100         tv.tv_sec = msec / 1000;
    1101         tv.tv_usec = (msec % 1000) * 1000;
     1079                connection_desctructor(&c->link);
     1080}
     1081
     1082static int
     1083num_workers(const struct shttpd_ctx *ctx)
     1084{
     1085        char    *p = ctx->options[OPT_THREADS];
     1086        return (p ? atoi(p) : 1);
     1087}
     1088
     1089static void
     1090handle_connected_socket(struct shttpd_ctx *ctx,
     1091                struct usa *sap, int sock, int is_ssl)
     1092{
     1093#if !defined(_WIN32)
     1094        if (sock >= (int) FD_SETSIZE) {
     1095                elog(E_LOG, NULL, "ctx %p: discarding "
     1096                    "socket %d, too busy", ctx, sock);
     1097                (void) closesocket(sock);
     1098        } else
     1099#endif /* !_WIN32 */
     1100                if (!is_allowed(ctx, sap)) {
     1101                elog(E_LOG, NULL, "%s is not allowed to connect",
     1102                    inet_ntoa(sap->u.sin.sin_addr));
     1103                (void) closesocket(sock);
     1104        } else if (num_workers(ctx) > 1) {
     1105                pass_socket(ctx, sock, is_ssl);
     1106        } else {
     1107                add_socket(first_worker(ctx), sock, is_ssl);
     1108        }
     1109}
     1110
     1111static int
     1112do_select(int max_fd, fd_set *read_set, fd_set *write_set, int milliseconds)
     1113{
     1114        struct timeval  tv;
     1115        int             n;
     1116
     1117        tv.tv_sec = milliseconds / 1000;
     1118        tv.tv_usec = (milliseconds % 1000) * 1000;
    11021119
    11031120        /* Check IO readiness */
    1104         if (select(max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) {
     1121        if ((n = select(max_fd + 1, read_set, write_set, NULL, &tv)) < 0) {
    11051122#ifdef _WIN32
    11061123                /*
     
    11131130#endif /* _WIN32 */
    11141131                DBG(("select: %d", ERRNO));
    1115                 return;
    1116         }
     1132        }
     1133
     1134        return (n);
     1135}
     1136
     1137static void
     1138multiplex_worker_sockets(const struct worker *worker, int *max_fd,
     1139                fd_set *read_set, fd_set *write_set, int *milliseconds)
     1140{
     1141        struct llhead   *lp;
     1142        struct conn     *c;
     1143
     1144        /* Add control socket */
     1145        add_to_set(worker->ctl[0], read_set, max_fd);
     1146
     1147        /* Multiplex streams */
     1148        LL_FOREACH(&worker->connections, lp) {
     1149                c = LL_ENTRY(lp, struct conn, link);
     1150               
     1151                /* If there is a space in remote IO, check remote socket */
     1152                if (io_space_len(&c->rem.io))
     1153                        add_to_set(c->rem.chan.fd, read_set, max_fd);
     1154
     1155#if !defined(NO_CGI)
     1156                /*
     1157                 * If there is a space in local IO, and local endpoint is
     1158                 * CGI, check local socket for read availability
     1159                 */
     1160                if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
     1161                    c->loc.io_class == &io_cgi)
     1162                        add_to_set(c->loc.chan.fd, read_set, max_fd);
     1163
     1164                /*
     1165                 * If there is some data read from remote socket, and
     1166                 * local endpoint is CGI, check local for write availability
     1167                 */
     1168                if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
     1169                    c->loc.io_class == &io_cgi)
     1170                        add_to_set(c->loc.chan.fd, write_set, max_fd);
     1171#endif /* NO_CGI */
     1172
     1173                /*
     1174                 * If there is some data read from local endpoint, check the
     1175                 * remote socket for write availability
     1176                 */
     1177                if (io_data_len(&c->loc.io) && !(c->loc.flags & FLAG_SUSPEND))
     1178                        add_to_set(c->rem.chan.fd, write_set, max_fd);
     1179
     1180                /*
     1181                 * Set select wait interval to zero if FLAG_ALWAYS_READY set
     1182                 */
     1183                if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
     1184                    (c->loc.flags & FLAG_ALWAYS_READY))
     1185                        *milliseconds = 0;
     1186               
     1187                if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
     1188                    (c->loc.flags & FLAG_ALWAYS_READY))
     1189                        *milliseconds = 0;
     1190        }
     1191}
     1192
     1193static void
     1194process_worker_sockets(struct worker *worker, fd_set *read_set)
     1195{
     1196        struct llhead   *lp, *tmp;
     1197        int             cmd, skt[2], sock = worker->ctl[0];
     1198        struct conn     *c;
     1199
     1200        /* Check if new socket is passed to us over the control socket */
     1201        if (FD_ISSET(worker->ctl[0], read_set))
     1202                while (recv(sock, (void *) &cmd, sizeof(cmd), 0) == sizeof(cmd))
     1203                        switch (cmd) {
     1204                        case CTL_PASS_SOCKET:
     1205                                (void)recv(sock, (void *) &skt, sizeof(skt), 0);
     1206                                add_socket(worker, skt[0], skt[1]);
     1207                                break;
     1208                        case CTL_WAKEUP:
     1209                                (void)recv(sock, (void *) &c, sizeof(c), 0);
     1210                                c->loc.flags &= FLAG_SUSPEND;
     1211                                break;
     1212                        default:
     1213                                elog(E_FATAL, NULL, "ctx %p: ctl cmd %d",
     1214                                    worker->ctx, cmd);
     1215                                break;
     1216                        }
     1217
     1218        /* Process all connections */
     1219        LL_FOREACH_SAFE(&worker->connections, lp, tmp) {
     1220                c = LL_ENTRY(lp, struct conn, link);
     1221                process_connection(c, FD_ISSET(c->rem.chan.fd, read_set),
     1222                    ((c->loc.flags & FLAG_ALWAYS_READY)
     1223#if !defined(NO_CGI)
     1224                    || (c->loc.io_class == &io_cgi &&
     1225                     FD_ISSET(c->loc.chan.fd, read_set))
     1226#endif /* NO_CGI */
     1227                    ));
     1228        }
     1229}
     1230
     1231/*
     1232 * One iteration of server loop. This is the core of the data exchange.
     1233 */
     1234void
     1235shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
     1236{
     1237        struct llhead   *lp;
     1238        struct listener *l;
     1239        fd_set          read_set, write_set;
     1240        int             sock, max_fd = -1;
     1241        struct usa      sa;
     1242
     1243        current_time = time(0);
     1244        FD_ZERO(&read_set);
     1245        FD_ZERO(&write_set);
     1246
     1247        /* Add listening sockets to the read set */
     1248        LL_FOREACH(&ctx->listeners, lp) {
     1249                l = LL_ENTRY(lp, struct listener, link);
     1250                add_to_set(l->sock, &read_set, &max_fd);
     1251                DBG(("FD_SET(%d) (listening)", l->sock));
     1252        }
     1253
     1254        if (num_workers(ctx) == 1)
     1255                multiplex_worker_sockets(first_worker(ctx), &max_fd,
     1256                                &read_set, &write_set, &milliseconds);
     1257
     1258        if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
     1259                return;;
    11171260
    11181261        /* Check for incoming connections on listener sockets */
     
    11231266                do {
    11241267                        sa.len = sizeof(sa.u.sin);
    1125                         if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1) {
    1126 #if defined(_WIN32)
    1127                                 shttpd_add_socket(ctx, sock, l->is_ssl);
    1128 #else
    1129                                 if (sock >= (int) FD_SETSIZE) {
    1130                                         elog(E_LOG, NULL,
    1131                                            "shttpd_poll: ctx %p: disarding "
    1132                                            "socket %d, too busy", ctx, sock);
    1133                                         (void) closesocket(sock);
    1134                                 } else if (!is_allowed(ctx, &sa)) {
    1135                                         elog(E_LOG, NULL, "shttpd_poll: %s "
    1136                                             "is not allowed to connect",
    1137                                            inet_ntoa(sa.u.sin.sin_addr));
    1138                                         (void) closesocket(sock);
    1139                                 } else {
    1140                                         shttpd_add_socket(ctx, sock, l->is_ssl);
    1141                                 }
    1142 #endif /* _WIN32 */
    1143                         }
     1268                        if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
     1269                                handle_connected_socket(ctx,&sa,sock,l->is_ssl);
    11441270                } while (sock != -1);
    11451271        }
    11461272
    1147         /* Process all connections */
    1148         LL_FOREACH_SAFE(&ctx->connections, lp, tmp) {
    1149                 c = LL_ENTRY(lp, struct conn, link);
    1150                 process_connection(c, FD_ISSET(c->rem.chan.fd, &read_set),
    1151                     ((c->loc.flags & FLAG_ALWAYS_READY)
    1152 #if !defined(NO_CGI)
    1153                     || (c->loc.io_class == &io_cgi &&
    1154                      FD_ISSET(c->loc.chan.fd, &read_set))
    1155 #endif /* NO_CGI */
    1156                     ));
    1157         }
    1158 }
    1159 
    1160 void
    1161 free_list(struct llhead *head, void (*dtor)(struct llhead *))
    1162 {
    1163         struct llhead   *lp, *tmp;
    1164 
    1165         LL_FOREACH_SAFE(head, lp, tmp) {
    1166                 LL_DEL(lp);
    1167                 dtor(lp);
    1168         }
    1169 }
    1170 
    1171 void
    1172 listener_destructor(struct llhead *lp)
    1173 {
    1174         struct listener *listener = LL_ENTRY(lp, struct listener, link);
    1175 
    1176         (void) closesocket(listener->sock);
    1177         free(listener);
    1178 }
    1179 
    1180 void
    1181 registered_uri_destructor(struct llhead *lp)
    1182 {
    1183         struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
    1184 
    1185         free((void *) ruri->uri);
    1186         free(ruri);
    1187 }
    1188 
    1189 static void
    1190 acl_destructor(struct llhead *lp)
    1191 {
    1192         struct acl      *acl = LL_ENTRY(lp, struct acl, link);
    1193         free(acl);
     1273        if (num_workers(ctx) == 1)
     1274                process_worker_sockets(first_worker(ctx), &read_set);
    11941275}
    11951276
     
    12021283        size_t  i;
    12031284
    1204         free_list(&ctx->connections, disconnect);
     1285        free_list(&ctx->workers, worker_destructor);
    12051286        free_list(&ctx->registered_uris, registered_uri_destructor);
    12061287        free_list(&ctx->acl, acl_destructor);
     
    12081289#if !defined(NO_SSI)
    12091290        free_list(&ctx->ssi_funcs, ssi_func_destructor);
    1210 #endif
     1291#endif /* !NO_SSI */
    12111292
    12121293        for (i = 0; i < NELEMS(ctx->options); i++)
     
    12211302        free(ctx);
    12221303}
     1304
     1305/*
     1306 * UNIX socketpair() implementation. Why? Because Windows does not have it.
     1307 * Return 0 on success, -1 on error.
     1308 */
     1309int
     1310shttpd_socketpair(int sp[2])
     1311{
     1312        struct sockaddr_in      sa;
     1313        int                     sock, ret = -1;
     1314        socklen_t               len = sizeof(sa);
     1315
     1316        sp[0] = sp[1] = -1;
     1317
     1318        (void) memset(&sa, 0, sizeof(sa));
     1319        sa.sin_family           = AF_INET;
     1320        sa.sin_port             = htons(0);
     1321        sa.sin_addr.s_addr      = htonl(INADDR_LOOPBACK);
     1322
     1323        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1 &&
     1324            !bind(sock, (struct sockaddr *) &sa, len) &&
     1325            !listen(sock, 1) &&
     1326            !getsockname(sock, (struct sockaddr *) &sa, &len) &&
     1327            (sp[0] = socket(AF_INET, SOCK_STREAM, 6)) != -1 &&
     1328            !connect(sp[0], (struct sockaddr *) &sa, len) &&
     1329            (sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) != -1) {
     1330
     1331                /* Success */
     1332                ret = 0;
     1333        } else {
     1334
     1335                /* Failure, close descriptors */
     1336                if (sp[0] != -1)
     1337                        (void) closesocket(sp[0]);
     1338                if (sp[1] != -1)
     1339                        (void) closesocket(sp[1]);
     1340        }
     1341
     1342        (void) closesocket(sock);
     1343        (void) set_non_blocking_mode(sp[0]);
     1344        (void) set_non_blocking_mode(sp[1]);
     1345
     1346#ifndef _WIN32
     1347        (void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
     1348        (void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
     1349#endif /* _WIN32*/
     1350
     1351        return (ret);
     1352}
     1353
     1354static int isbyte(int n) { return (n >= 0 && n <= 255); }
     1355
     1356static void
     1357set_inetd(struct shttpd_ctx *ctx, const char *flag)
     1358{
     1359        ctx = NULL; /* Unused */
     1360
     1361        if (is_true(flag)) {
     1362                shttpd_set_option(ctx, "ports", NULL);
     1363                (void) freopen("/dev/null", "a", stderr);
     1364                add_socket(first_worker(ctx), 0, 0);
     1365        }
     1366}
     1367
     1368static void
     1369set_uid(struct shttpd_ctx *ctx, const char *uid)
     1370{
     1371        struct passwd   *pw;
     1372
     1373        ctx = NULL; /* Unused */
     1374
     1375#if !defined(_WIN32)
     1376        if ((pw = getpwnam(uid)) == NULL)
     1377                elog(E_FATAL, 0, "%s: unknown user [%s]", __func__, uid);
     1378        else if (setgid(pw->pw_gid) == -1)
     1379                elog(E_FATAL, NULL, "%s: setgid(%s): %s",
     1380                    __func__, uid, strerror(errno));
     1381        else if (setuid(pw->pw_uid) == -1)
     1382                elog(E_FATAL, NULL, "%s: setuid(%s): %s",
     1383                    __func__, uid, strerror(errno));
     1384#endif /* !_WIN32 */
     1385}
     1386
     1387static void
     1388set_acl(struct shttpd_ctx *ctx, const char *s)
     1389{
     1390        struct acl      *acl = NULL;
     1391        char            flag;
     1392        int             len, a, b, c, d, n, mask;
     1393        struct llhead   *lp, *tmp;
     1394
     1395        /* Delete the old ACLs if any */
     1396        LL_FOREACH_SAFE(&ctx->acl, lp, tmp)
     1397                free(LL_ENTRY(lp, struct acl, link));
     1398
     1399        FOR_EACH_WORD_IN_LIST(s, len) {
     1400
     1401                mask = 32;
     1402
     1403                if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
     1404                        elog(E_FATAL, NULL, "[%s]: subnet must be "
     1405                            "[+|-]x.x.x.x[/x]", s);
     1406                } else if (flag != '+' && flag != '-') {
     1407                        elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
     1408                } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
     1409                        elog(E_FATAL, NULL, "bad ip address: [%s]", s);
     1410                } else  if ((acl = malloc(sizeof(*acl))) == NULL) {
     1411                        elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
     1412                } else if (sscanf(s + n, "/%d", &mask) == 0) {
     1413                        /* Do nothing, no mask specified */
     1414                } else if (mask < 0 || mask > 32) {
     1415                        elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
     1416                }
     1417
     1418                acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
     1419                acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
     1420                acl->flag = flag;
     1421                LL_TAIL(&ctx->acl, &acl->link);
     1422        }
     1423}
     1424
     1425#ifndef NO_SSL
     1426/*
     1427 * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
     1428 */
     1429static void
     1430set_ssl(struct shttpd_ctx *ctx, const char *pem)
     1431{
     1432        SSL_CTX         *CTX;
     1433        void            *lib;
     1434        struct ssl_func *fp;
     1435
     1436        /* Load SSL library dynamically */
     1437        if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL)
     1438                elog(E_FATAL, NULL, "set_ssl: cannot load %s", SSL_LIB);
     1439
     1440        for (fp = ssl_sw; fp->name != NULL; fp++)
     1441                if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL)
     1442                        elog(E_FATAL, NULL,"set_ssl: cannot find %s", fp->name);
     1443
     1444        /* Initialize SSL crap */
     1445        SSL_library_init();
     1446
     1447        if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
     1448                elog(E_FATAL, NULL, "SSL_CTX_new error");
     1449        else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
     1450                elog(E_FATAL, NULL, "cannot open %s", pem);
     1451        else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
     1452                elog(E_FATAL, NULL, "cannot open %s", pem);
     1453        ctx->ssl_ctx = CTX;
     1454}
     1455#endif /* NO_SSL */
     1456
     1457static void
     1458open_log_file(FILE **fpp, const char *path)
     1459{
     1460        if (*fpp != NULL)
     1461                (void) fclose(*fpp);
     1462
     1463        if (path == NULL) {
     1464                *fpp = NULL;
     1465        } else if ((*fpp = fopen(path, "a")) == NULL) {
     1466                elog(E_FATAL, NULL, "cannot open log file %s: %s",
     1467                    path, strerror(errno));
     1468        }
     1469}
     1470
     1471static void set_alog(struct shttpd_ctx *ctx, const char *path) {
     1472        open_log_file(&ctx->access_log, path);
     1473}
     1474
     1475static void set_elog(struct shttpd_ctx *ctx, const char *path) {
     1476        open_log_file(&ctx->error_log, path);
     1477}
     1478
     1479static void show_cfg_page(struct shttpd_arg *arg);
     1480
     1481static void
     1482set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
     1483{
     1484        free_list(&ctx->registered_uris, &registered_uri_destructor);
     1485
     1486        if (uri != NULL)
     1487                shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
     1488}
     1489
     1490static struct worker *
     1491add_worker(struct shttpd_ctx *ctx)
     1492{
     1493        struct worker   *worker;
     1494
     1495        if ((worker = calloc(1, sizeof(*worker))) == NULL)
     1496                elog(E_FATAL, NULL, "Cannot allocate worker");
     1497        LL_INIT(&worker->connections);
     1498        worker->ctx = ctx;
     1499        (void) shttpd_socketpair(worker->ctl);
     1500        LL_TAIL(&ctx->workers, &worker->link);
     1501
     1502        return (worker);
     1503}
     1504
     1505#if !defined(NO_THREADS)
     1506static void
     1507poll_worker(struct worker *worker, int milliseconds)
     1508{
     1509        fd_set          read_set, write_set;
     1510        int             max_fd = -1;
     1511
     1512        FD_ZERO(&read_set);
     1513        FD_ZERO(&write_set);
     1514
     1515        multiplex_worker_sockets(worker, &max_fd,
     1516                        &read_set, &write_set, &milliseconds);
     1517
     1518        if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
     1519                return;;
     1520
     1521        process_worker_sockets(worker, &read_set);
     1522}
     1523
     1524static void
     1525worker_function(void *param)
     1526{
     1527        struct worker *worker = param;
     1528
     1529        while (worker->exit_flag == 0)
     1530                poll_worker(worker, 1000 * 10);
     1531
     1532        free_list(&worker->connections, connection_desctructor);
     1533        free(worker);
     1534}
     1535
     1536static void
     1537set_workers(struct shttpd_ctx *ctx, const char *value)
     1538{
     1539        int             new_num, old_num;
     1540        struct llhead   *lp, *tmp;
     1541        struct worker   *worker;
     1542
     1543        new_num = atoi(value);
     1544        old_num = 0;
     1545        LL_FOREACH(&ctx->workers, lp)
     1546                old_num++;
     1547
     1548        if (new_num == 1) {
     1549                if (old_num > 1)
     1550                        /* Stop old threads */
     1551                        LL_FOREACH_SAFE(&ctx->workers, lp, tmp) {
     1552                                worker = LL_ENTRY(lp, struct worker, link);
     1553                                LL_DEL(&worker->link);
     1554                                worker = LL_ENTRY(lp, struct worker, link);
     1555                                worker->exit_flag = 1;
     1556                        }
     1557                (void) add_worker(ctx);
     1558        } else {
     1559                /* FIXME: we cannot here reduce the number of threads */
     1560                while (new_num > 1 && new_num > old_num) {
     1561                        worker = add_worker(ctx);
     1562                        _beginthread(worker_function, 0, worker);
     1563                        old_num++;
     1564                }
     1565        }
     1566}
     1567#endif /* NO_THREADS */
     1568
     1569static const struct opt {
     1570        int             index;          /* Index in shttpd_ctx          */
     1571        const char      *name;          /* Option name in config file   */
     1572        const char      *description;   /* Description                  */
     1573        const char      *default_value; /* Default option value         */
     1574        void (*setter)(struct shttpd_ctx *, const char *);
     1575} known_options[] = {
     1576        {OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
     1577        {OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
     1578#ifndef NO_SSL
     1579        {OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
     1580#endif /* NO_SSL */
     1581        {OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
     1582        {OPT_DIR_LIST, "dir_list", "Directory listing", "yes", NULL},
     1583        {OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
     1584        {OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
     1585#ifndef NO_CGI
     1586        {OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
     1587        {OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
     1588        {OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
     1589#endif /* NO_CGI */
     1590        {OPT_SSI_EXTENSIONS, "ssi_ext", "SSI extensions", SSI_EXT, NULL},
     1591#ifndef NO_AUTH
     1592        {OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
     1593        {OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
     1594        {OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
     1595#endif /* !NO_AUTH */
     1596#ifdef _WIN32
     1597        {OPT_SERVICE, "service", "Manage WinNNT service (install"
     1598            "|uninstall)", NULL, set_nt_service},
     1599        {OPT_HIDE, "systray", "Hide console, show icon on systray",
     1600                "no", set_systray},
     1601#else
     1602        {OPT_INETD, "inetd", "Inetd mode", "no", set_inetd},
     1603        {OPT_UID, "uid", "\tRun as user", NULL, set_uid},
     1604#endif /* _WIN32 */
     1605        {OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
     1606        {OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
     1607        {OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
     1608        {OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
     1609        {OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
     1610#if !defined(NO_THREADS)
     1611        {OPT_THREADS, "threads", "Number of worker threads", "1", set_workers},
     1612#endif /* !NO_THREADS */
     1613        {-1, NULL, NULL, NULL, NULL}
     1614};
     1615
     1616static const struct opt *
     1617find_opt(const char *opt_name)
     1618{
     1619        int     i;
     1620
     1621        for (i = 0; known_options[i].name != NULL; i++)
     1622                if (!strcmp(opt_name, known_options[i].name))
     1623                        return (known_options + i);
     1624
     1625        elog(E_FATAL, NULL, "no such option: [%s]", opt_name);
     1626
     1627        /* UNREACHABLE */
     1628        return (NULL);
     1629}
     1630
     1631void
     1632shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
     1633{
     1634        const struct opt        *o = find_opt(opt);
     1635
     1636        /* Call option setter first, so it can use both new and old values */
     1637        if (o->setter != NULL)
     1638                o->setter(ctx, val);
     1639
     1640        /* Free old value if any */
     1641        if (ctx->options[o->index] != NULL)
     1642                free(ctx->options[o->index]);
     1643       
     1644        /* Set new option value */
     1645        ctx->options[o->index] = val ? my_strdup(val) : NULL;
     1646}
     1647
     1648static void
     1649show_cfg_page(struct shttpd_arg *arg)
     1650{
     1651        struct shttpd_ctx       *ctx = arg->user_data;
     1652        char                    opt_name[20], value[BUFSIZ];
     1653        const struct opt        *o;
     1654
     1655        opt_name[0] = value[0] = '\0';
     1656
     1657        if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
     1658                if (arg->flags & SHTTPD_MORE_POST_DATA)
     1659                        return;
     1660                (void) shttpd_get_var("o", arg->in.buf, arg->in.len,
     1661                    opt_name, sizeof(opt_name));
     1662                (void) shttpd_get_var("v", arg->in.buf, arg->in.len,
     1663                    value, sizeof(value));
     1664                shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
     1665        }
     1666
     1667        shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
     1668            "<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
     1669
     1670        shttpd_printf(arg, "%s", "<table border=1"
     1671            "<tr><th>Option</th><th>Description</th>"
     1672            "<th colspan=2>Value</th></tr>");
     1673
     1674        if (opt_name[0] != '\0' && value[0] != '\0')
     1675                shttpd_printf(arg, "<p style='color: green'>Saved: %s=%s</p>",
     1676                    opt_name, value[0] ? value : "NULL");
     1677
     1678
     1679        for (o = known_options; o->name != NULL; o++) {
     1680                shttpd_printf(arg,
     1681                    "<form method=post><tr><td>%s</td><td>%s</td>"
     1682                    "<input type=hidden name=o value='%s'>"
     1683                    "<td><input type=text name=v value='%s'></td>"
     1684                    "<td><input type=submit value=save></td></form></tr>",
     1685                    o->name, o->description, o->name,
     1686                    ctx->options[o->index] ? ctx->options[o->index] : "");
     1687        }
     1688
     1689        shttpd_printf(arg, "%s", "</table></body></html>");
     1690        arg->flags |= SHTTPD_END_OF_OUTPUT;
     1691}
     1692
     1693/*
     1694 * Show usage string and exit.
     1695 */
     1696void
     1697usage(const char *prog)
     1698{
     1699        const struct opt        *o;
     1700
     1701        (void) fprintf(stderr,
     1702            "SHTTPD version %s (c) Sergey Lyubka\n"
     1703            "usage: %s [options] [config_file]\n", VERSION, prog);
     1704
     1705#if !defined(NO_AUTH)
     1706        fprintf(stderr, "  -A <htpasswd_file> <realm> <user> <passwd>\n");
     1707#endif /* NO_AUTH */
     1708
     1709        for (o = known_options; o->name != NULL; o++) {
     1710                (void) fprintf(stderr, "  -%s\t%s", o->name, o->description);
     1711                if (o->default_value != NULL)
     1712                        fprintf(stderr, " (default: %s)", o->default_value);
     1713                fputc('\n', stderr);
     1714        }
     1715
     1716        exit(EXIT_FAILURE);
     1717}
     1718
     1719static void
     1720set_opt(struct shttpd_ctx *ctx, const char *opt, const char *value)
     1721{
     1722        const struct opt        *o;
     1723
     1724        o = find_opt(opt);
     1725        if (ctx->options[o->index] != NULL)
     1726                free(ctx->options[o->index]);
     1727        ctx->options[o->index] = my_strdup(value);
     1728}
     1729
     1730static void
     1731process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
     1732{
     1733        const char              *config_file = CONFIG_FILE;
     1734        char                    line[BUFSIZ], opt[BUFSIZ],
     1735                                val[BUFSIZ], path[FILENAME_MAX], *p;
     1736        FILE                    *fp;
     1737        size_t                  i, line_no = 0;
     1738
     1739        /* First find out, which config file to open */
     1740        for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
     1741                if (argv[i + 1] == NULL)
     1742                        usage(argv[0]);
     1743
     1744        if (argv[i] != NULL && argv[i + 1] != NULL) {
     1745                /* More than one non-option arguments are given w*/
     1746                usage(argv[0]);
     1747        } else if (argv[i] != NULL) {
     1748                /* Just one non-option argument is given, this is config file */
     1749                config_file = argv[i];
     1750        } else {
     1751                /* No config file specified. Look for one where shttpd lives */
     1752                if ((p = strrchr(argv[0], DIRSEP)) != 0) {
     1753                        my_snprintf(path, sizeof(path), "%.*s%s",
     1754                            p - argv[0] + 1, argv[0], config_file);
     1755                        config_file = path;
     1756                }
     1757        }
     1758
     1759        fp = fopen(config_file, "r");
     1760
     1761        /* If config file was set in command line and open failed, exit */
     1762        if (fp == NULL && argv[i] != NULL)
     1763                elog(E_FATAL, NULL, "cannot open config file %s: %s",
     1764                    config_file, strerror(errno));
     1765
     1766        if (fp != NULL) {
     1767
     1768                elog(E_LOG, NULL, "Loading config file %s", config_file);
     1769
     1770                /* Loop over the lines in config file */
     1771                while (fgets(line, sizeof(line), fp) != NULL) {
     1772
     1773                        line_no++;
     1774
     1775                        /* Ignore empty lines and comments */
     1776                        if (line[0] == '#' || line[0] == '\n')
     1777                                continue;
     1778
     1779                        if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
     1780                                elog(E_FATAL, NULL, "line %d in %s is invalid",
     1781                                    line_no, config_file);
     1782
     1783                        set_opt(ctx, opt, val);
     1784                }
     1785
     1786                (void) fclose(fp);
     1787        }
     1788
     1789        /* Now pass through the command line options */
     1790        for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
     1791                set_opt(ctx, &argv[i][1], argv[i + 1]);
     1792}
     1793
     1794struct shttpd_ctx *
     1795shttpd_init(int argc, char *argv[])
     1796{
     1797        struct shttpd_ctx       *ctx;
     1798        struct tm               *tm;
     1799        const struct opt        *o;
     1800
     1801        if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
     1802                elog(E_FATAL, NULL, "cannot allocate shttpd context");
     1803
     1804        LL_INIT(&ctx->registered_uris);
     1805        LL_INIT(&ctx->error_handlers);
     1806        LL_INIT(&ctx->acl);
     1807        LL_INIT(&ctx->ssi_funcs);
     1808        LL_INIT(&ctx->listeners);
     1809        LL_INIT(&ctx->workers);
     1810
     1811        /* Initialize options. First pass: set default option values */
     1812        for (o = known_options; o->name != NULL; o++)
     1813                ctx->options[o->index] = o->default_value ?
     1814                        my_strdup(o->default_value) : NULL;
     1815
     1816        /* Second and third passes: config file and argv */
     1817        if (argc > 0 && argv != NULL)
     1818                process_command_line_arguments(ctx, argv);
     1819
     1820        /* Call setter functions */
     1821        for (o = known_options; o->name != NULL; o++)
     1822                if (o->setter && ctx->options[o->index] != NULL)
     1823                        o->setter(ctx, ctx->options[o->index]);
     1824
     1825        current_time = time(NULL);
     1826        tm = localtime(&current_time);
     1827        tz_offset = 0;
     1828
     1829        if (num_workers(ctx) == 1)
     1830                (void) add_worker(ctx);
     1831#if 0
     1832        tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
     1833#endif
     1834
     1835#ifdef _WIN32
     1836        {WSADATA data;  WSAStartup(MAKEWORD(2,2), &data);}
     1837#endif /* _WIN32 */
     1838
     1839        return (ctx);
     1840}
  • trunk/third-party/shttpd/shttpd.h

    r5822 r6349  
    11/*
    2  * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
     2 * Copyright (c) 2004-2008 Sergey Lyubka <valenok@gmail.com>
     3 * All rights reserved
    34 *
    4  * Permission is hereby granted, free of charge, to any person obtaining a
    5  * copy of this software and associated documentation files (the "Software"),
    6  * to deal in the Software without restriction, including without limitation
    7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    8  * and/or sell copies of the Software, and to permit persons to whom the
    9  * Software is furnished to do so, subject to the following conditions:
     5 * "THE BEER-WARE LICENSE" (Revision 42):
     6 * Sergey Lyubka wrote this file.  As long as you retain this notice you
     7 * can do whatever you want with this stuff. If we meet some day, and you think
     8 * this stuff is worth it, you can buy me a beer in return.
    109 *
    11  * The above copyright notice and this permission notice shall be included
    12  * in all copies or substantial portions of the Software.
    13  *
    14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    20  * DEALINGS IN THE SOFTWARE.
    21  *
    22  * $Id: shttpd.h,v 1.9 2008/02/13 20:44:32 drozd Exp $
     10 * $Id: shttpd.h,v 1.16 2008/05/31 09:02:02 drozd Exp $
    2311 */
    2412
     
    4230        void            *priv;          /* Private! Do not touch!       */
    4331        void            *state;         /* User state                   */
    44         void            *user_data;     /* User-defined data            */
     32        void            *user_data;     /* Data from register_uri()     */
    4533        struct ubuf     in;             /* Input is here, POST data     */
    4634        struct ubuf     out;            /* Output goes here             */
     35
    4736        unsigned int    flags;
    48 #define SHTTPD_END_OF_OUTPUT    1
    49 #define SHTTPD_CONNECTION_ERROR 2
    50 #define SHTTPD_MORE_POST_DATA   4
    51 #define SHTTPD_POST_BUFFER_FULL 8
    52 #define SHTTPD_SSI_EVAL_TRUE    16
     37#define SHTTPD_END_OF_OUTPUT    1       /* No more data do send         */
     38#define SHTTPD_CONNECTION_ERROR 2       /* Server closed the connection */
     39#define SHTTPD_MORE_POST_DATA   4       /* arg->in has incomplete data  */
     40#define SHTTPD_POST_BUFFER_FULL 8       /* arg->in has max data         */
     41#define SHTTPD_SSI_EVAL_TRUE    16      /* SSI eval callback must set it*/
     42#define SHTTPD_SUSPEND          32      /* User wants to suspend output */
    5343};
    5444
     
    5747 * requested. These are the requirements to the callback function:
    5848 *
    59  * 1. it must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
     49 * 1. It must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
    6050 *      and record how many bytes are copied, into 'out.num_bytes'
    61  * 2. it must not block the execution
    62  * 3. it must set SHTTPD_END_OF_OUTPUT flag when finished
    63  * 4. for POST requests, it must process the incoming data (in.buf) of length
     51 * 2. It must not call any blocking functions
     52 * 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
     53 * 4. For POST requests, it must process the incoming data (in.buf) of length
    6454 *      'in.len', and set 'in.num_bytes', which is how many bytes of POST
    65  *      data is read and can be discarded by SHTTPD.
     55 *      data was processed and can be discarded by SHTTPD.
    6656 * 5. If callback allocates arg->state, to keep state, it must deallocate it
    6757 *    at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
     58 * 6. If callback function wants to suspend until some event, it must store
     59 *      arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
     60 *      the event happens, user code should call shttpd_wakeup(priv).
     61 *      It is safe to call shttpd_wakeup() from any thread. User code must
     62 *      not call shttpd_wakeup once the connection is closed.
    6863 */
    6964typedef void (*shttpd_callback_t)(struct shttpd_arg *);
    7065
    7166/*
    72  * shttpd_init          Initialize shttpd context.
    73  * shttpd_set_option    Set new value for option.
    74  * shttpd_fini          Dealocate the context
    75  * shttpd_register_uri  Setup the callback function for specified URL.
    76  * shtppd_listen        Setup a listening socket in the SHTTPD context
     67 * shttpd_init          Initialize shttpd context
     68 * shttpd_fini          Dealocate the context, close all connections
     69 * shttpd_set_option    Set new value for option
     70 * shttpd_register_uri  Setup the callback function for specified URL
    7771 * shttpd_poll          Do connections processing
    7872 * shttpd_version       return string with SHTTPD version
    7973 * shttpd_get_var       Fetch POST/GET variable value by name. Return value len
    8074 * shttpd_get_header    return value of the specified HTTP header
    81  * shttpd_get_env       return string values for the following
    82  *                      pseudo-variables: "REQUEST_METHOD", "REQUEST_URI",
    83  *                      "REMOTE_USER" and "REMOTE_ADDR".
     75 * shttpd_get_env       return values for the following pseudo-variables:
     76                        "REQUEST_METHOD", "REQUEST_URI",
     77 *                      "REMOTE_USER" and "REMOTE_ADDR"
     78 * shttpd_printf        helper function to output data
     79 * shttpd_handle_error  register custom HTTP error handler
     80 * shttpd_wakeup        clear SHTTPD_SUSPEND state for the connection
    8481 */
    8582
    8683struct shttpd_ctx;
    8784
    88 struct shttpd_ctx *shttpd_init(void);
     85struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
    8986void shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
    9087void shttpd_fini(struct shttpd_ctx *);
    91 int shttpd_listen(struct shttpd_ctx *ctx, int port, int is_ssl);
    9288void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
    9389                shttpd_callback_t callback, void *const user_data);
     
    105101void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
    106102                shttpd_callback_t func, void *const user_data);
    107 
    108 /*
    109  * The following three functions are for applications that need to
    110  * load-balance the connections on their own. Many threads may be spawned
    111  * with one SHTTPD context per thread. Boss thread may only wait for
    112  * new connections by means of shttpd_accept(). Then it may scan thread
    113  * pool for the idle thread by means of shttpd_active(), and add new
    114  * connection to the context by means of shttpd_add().
    115  */
    116 void shttpd_add_socket(struct shttpd_ctx *, int sock, int is_ssl);
    117 int shttpd_accept(int lsn_sock, int milliseconds);
    118 int shttpd_active(struct shttpd_ctx *);
    119 
     103void shttpd_wakeup(const void *priv);
    120104
    121105#ifdef __cplusplus
  • trunk/third-party/shttpd/standalone.c

    r5822 r6349  
    1111#include "defs.h"
    1212
    13 static int              exit_flag;
     13static int      exit_flag;      /* Program termination flag     */
    1414
    1515static void
     
    2626                break;
    2727        }
    28 }
    29 
    30 void
    31 process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
    32 {
    33         const char      *config_file = CONFIG_FILE;
    34         char            line[BUFSIZ], opt[BUFSIZ],
    35                         val[BUFSIZ], path[FILENAME_MAX], *p;
    36         FILE            *fp;
    37         size_t          i, line_no = 0;
    38 
    39         /* First find out, which config file to open */
    40         for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
    41                 if (argv[i + 1] == NULL)
    42                         usage(argv[0]);
    43 
    44         if (argv[i] != NULL && argv[i + 1] != NULL) {
    45                 /* More than one non-option arguments are given w*/
    46                 usage(argv[0]);
    47         } else if (argv[i] != NULL) {
    48                 /* Just one non-option argument is given, this is config file */
    49                 config_file = argv[i];
    50         } else {
    51                 /* No config file specified. Look for one where shttpd lives */
    52                 if ((p = strrchr(argv[0], DIRSEP)) != 0) {
    53                         my_snprintf(path, sizeof(path), "%.*s%s",
    54                             p - argv[0] + 1, argv[0], config_file);
    55                         config_file = path;
    56                 }
    57         }
    58 
    59         fp = fopen(config_file, "r");
    60 
    61         /* If config file was set in command line and open failed, exit */
    62         if (fp == NULL && argv[i] != NULL)
    63                 elog(E_FATAL, NULL, "cannot open config file %s: %s",
    64                     config_file, strerror(errno));
    65 
    66         if (fp != NULL) {
    67 
    68                 elog(E_LOG, NULL, "Loading config file %s", config_file);
    69 
    70                 /* Loop over the lines in config file */
    71                 while (fgets(line, sizeof(line), fp) != NULL) {
    72 
    73                         line_no++;
    74 
    75                         /* Ignore empty lines and comments */
    76                         if (line[0] == '#' || line[0] == '\n')
    77                                 continue;
    78 
    79                         if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
    80                                 elog(E_FATAL, NULL, "line %d in %s is invalid",
    81                                     line_no, config_file);
    82 
    83                         shttpd_set_option(ctx, opt, val);
    84                 }
    85 
    86                 (void) fclose(fp);
    87         }
    88 
    89         /* Now pass through the command line options */
    90         for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
    91                 shttpd_set_option(ctx, &argv[i][1], argv[i + 1]);
    9228}
    9329
     
    10844                usage(argv[0]);
    10945
    110         ctx = shttpd_init();
    111         process_command_line_arguments(ctx, argv);
     46#if defined(_WIN32)
     47        try_to_run_as_nt_service();
     48#endif /* _WIN32 */
    11249
    11350#ifndef _WIN32
    114         /* Switch to alternate UID, it is safe now, after shttpd_listen() */
    115         if (ctx->options[OPT_UID] != NULL) {
    116                 struct passwd   *pw;
    117 
    118                 if ((pw = getpwnam(ctx->options[OPT_UID])) == NULL)
    119                         elog(E_FATAL, 0, "main: unknown user [%s]",
    120                             ctx->options[OPT_UID]);
    121                 else if (setgid(pw->pw_gid) == -1)
    122                         elog(E_FATAL, NULL, "main: setgid(%s): %s",
    123                             ctx->options[OPT_UID], strerror(errno));
    124                 else if (setuid(pw->pw_uid) == -1)
    125                         elog(E_FATAL, NULL, "main: setuid(%s): %s",
    126                             ctx->options[OPT_UID], strerror(errno));
    127         }
    12851        (void) signal(SIGCHLD, signal_handler);
    12952        (void) signal(SIGPIPE, SIG_IGN);
     
    13356        (void) signal(SIGINT, signal_handler);
    13457
    135         if (IS_TRUE(ctx, OPT_INETD)) {
    136                 shttpd_set_option(ctx, "ports", NULL);
    137                 (void) freopen("/dev/null", "a", stderr);
    138                 shttpd_add_socket(ctx, fileno(stdin), 0);
    139         }
     58        ctx = shttpd_init(argc, argv);
    14059
    14160        elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s",
     
    14362
    14463        while (exit_flag == 0)
    145                 shttpd_poll(ctx, 5000);
     64                shttpd_poll(ctx, 10 * 1000);
    14665
    147         elog(E_LOG, NULL, "%d requests %.2lf Mb in %.2lf Mb out. "
    148             "Exit on signal %d", ctx->nrequests, (double) (ctx->in / 1048576),
    149             (double) ctx->out / 1048576, exit_flag);
    150 
     66        elog(E_LOG, NULL, "Exit on signal %d", exit_flag);
    15167        shttpd_fini(ctx);
    15268
Note: See TracChangeset for help on using the changeset viewer.