Changeset 6349
- Timestamp:
- Jul 16, 2008, 11:55:49 PM (14 years ago)
- Location:
- trunk
- Files:
-
- 1 deleted
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/rpc-server.c
r6343 r6349 329 329 if( !server->ctx ) 330 330 { 331 char ports[128]; 331 int i; 332 int argc = 0; 333 char * argv[100]; 332 334 char passwd[MAX_PATH_LENGTH]; 333 335 const char * clutchDir = tr_getClutchDir( server->session ); … … 340 342 edit_passwords( passwd, MY_REALM, server->username, server->password ); 341 343 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 ); 344 371 shttpd_register_uri( server->ctx, "/transmission/rpc", handle_rpc, server ); 345 372 shttpd_register_uri( server->ctx, "/transmission/upload", handle_upload, server ); 346 373 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 370 374 evtimer_set( &server->timer, rpcPulse, server ); 371 375 evtimer_add( &server->timer, &tv ); 376 377 for( i=0; i<argc; ++i ) 378 tr_free( argv[i] ); 372 379 } 373 380 } … … 430 437 431 438 /* 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, 433 440 * shttpd, written by Sergey Lyubka under this license: 434 441 * "THE BEER-WARE LICENSE" (Revision 42): … … 437 444 * this stuff is worth it, you can buy me a beer in return. 438 445 */ 439 440 #define DELIM_CHARS "," /* Separators for lists */441 446 442 447 #define FOR_EACH_WORD_IN_LIST(s,len) \ -
trunk/third-party/shttpd/Makefile.am
r5841 r6349 5 5 6 6 libshttpd_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 \ 8 8 io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c \ 9 9 compat_unix.c -
trunk/third-party/shttpd/README
r5822 r6349 1 1 http://shttpd.sourceforge.net/ 2 2 Sergey Lyubka wrote this software. 3 This snapshot si from shttpd-1.393 This snapshot is from shttpd-1.41 -
trunk/third-party/shttpd/auth.c
r5822 r6349 282 282 if (!memcmp(c->uri, s, p - s)) { 283 283 284 n = s + len - p + 1;284 n = s + len - p; 285 285 if (n > (int) sizeof(protected_path) - 1) 286 286 n = sizeof(protected_path) - 1; 287 287 288 288 my_strlcpy(protected_path, p + 1, n); 289 289 290 290 if ((fp = fopen(protected_path, "r")) == NULL) 291 291 elog(E_LOG, c, "check_auth: cannot open %s: %s", -
trunk/third-party/shttpd/cgi.c
r5822 r6349 19 19 }; 20 20 21 /*22 * UNIX socketpair() implementation. Why? Because Windows does not have it.23 * Return 0 on success, -1 on error.24 */25 static int26 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 _WIN3266 (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 73 21 static void 74 22 addenv(struct env_block *block, const char *fmt, ...) … … 146 94 { 147 95 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]; 149 97 size_t len; 150 98 151 99 blk->len = blk->nvars = 0; 100 101 /* SCRIPT_FILENAME */ 102 fname = prog; 103 if ((s = strrchr(prog, '/'))) 104 fname = s + 1; 152 105 153 106 /* Prepare the environment block */ … … 164 117 addenv(blk, "REQUEST_URI=%s", c->uri); 165 118 addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root)); 166 addenv(blk, "SCRIPT_FILENAME=%s", prog); /* PHP */119 addenv(blk, "SCRIPT_FILENAME=%s", fname); /* PHP */ 167 120 addenv(blk, "PATH_TRANSLATED=%s", prog); 168 121 … … 245 198 } 246 199 247 if ( my_socketpair(c,pair) != 0) {200 if (shttpd_socketpair(pair) != 0) { 248 201 ret = -1; 249 202 } else if (spawn_process(c, prog, blk.buf, blk.vars, pair[1], dir)) { -
trunk/third-party/shttpd/compat_unix.h
r5822 r6349 21 21 #include <dirent.h> 22 22 #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 23 30 #define SSL_LIB "libssl.so" 24 31 #define DIRSEP '/' … … 27 34 #define closesocket(a) close(a) 28 35 #define ERRNO errno 29 #define NO_GUI30 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 12 12 #define CONFIG_HEADER_DEFINED 13 13 14 #undef VERSION 15 #define VERSION "1. 39" /* Version */14 #undef VERSION 15 #define VERSION "1.41" /* Version */ 16 16 #define CONFIG_FILE "shttpd.conf" /* Configuration file */ 17 17 #define HTPASSWD ".htpasswd" /* Passwords file name */ … … 26 26 #define ENV_MAX 4096 /* Size of environment block */ 27 27 #define CGI_ENV_VARS 64 /* Maximum vars passed to CGI */ 28 #define SERVICE_NAME "SHTTPD " VERSION /* NT service name */ 28 29 29 30 #endif /* CONFIG_HEADER_DEFINED */ -
trunk/third-party/shttpd/defs.h
r5841 r6349 15 15 #include "llist.h" 16 16 #include "io.h" 17 #include "shttpd.h"18 17 #include "md5.h" 19 18 #include "config.h" 19 #include "shttpd.h" 20 20 21 21 #define NELEMS(ar) (sizeof(ar) / sizeof(ar[0])) … … 27 27 #endif /* DEBUG */ 28 28 29 #ifdef EMBEDDED30 #include "shttpd.h"31 #endif /* EMBEDDED */32 33 29 /* 34 30 * Darwin prior to 7.0 and Win32 do not have socklen_t … … 46 42 }; 47 43 48 #if !defined( _WIN32)44 #if !defined(FALSE) 49 45 enum {FALSE, TRUE}; 50 #endif /* _WIN32 */ 46 #endif /* !FALSE */ 47 51 48 enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD}; 52 49 enum {HDR_DATE, HDR_INT, HDR_STRING}; /* HTTP header types */ … … 176 173 struct io io; /* IO buffer */ 177 174 const struct io_class *io_class; /* IO class */ 178 int nread_last; /* Bytes last read */179 175 int headers_len; 180 176 big_int_t content_len; … … 187 183 #define FLAG_DONT_CLOSE 32 188 184 #define FLAG_ALWAYS_READY 64 /* File, dir, user_func */ 185 #define FLAG_SUSPEND 128 186 }; 187 188 struct 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 */ 189 195 }; 190 196 191 197 struct conn { 192 198 struct llhead link; /* Connections chain */ 199 struct worker *worker; /* Worker this conn belongs to */ 193 200 struct shttpd_ctx *ctx; /* Context this conn belongs to */ 194 201 struct usa sa; /* Remote socket address */ … … 224 231 OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES, 225 232 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, 227 234 NUM_OPTIONS 228 235 }; … … 232 239 */ 233 240 struct 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 */238 241 SSL_CTX *ssl_ctx; /* SSL context */ 239 struct llhead connections; /* List of connections */240 242 241 243 struct llhead registered_uris;/* User urls */ 242 244 struct llhead error_handlers; /* Embedded error handlers */ 243 245 struct llhead acl; /* Access control list */ 244 #if !defined(NO_SSI)245 246 struct llhead ssi_funcs; /* SSI callback functions */ 246 #endif247 247 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 */ 251 252 252 253 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__) 258 255 rtems_id mutex; 259 256 #endif /* _WIN32 */ 260 257 }; 261 258 262 #define IS_TRUE(ctx, opt) ((ctx)->options[opt] && (ctx)->options[opt][0] =='1') 259 struct 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 */ 267 enum {CTL_PASS_SOCKET, CTL_WAKEUP}; 263 268 264 269 /* … … 301 306 extern int get_headers_len(const char *buf, size_t buflen); 302 307 extern void parse_headers(const char *s, int len, struct headers *parsed); 303 extern void open_listening_ports(struct shttpd_ctx *ctx); 308 extern int is_true(const char *str); 309 extern int shttpd_socketpair(int pair[2]); 304 310 extern 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]) 308 313 309 314 /* … … 343 348 char *envblk, char *envp[], int sock, const char *dir); 344 349 350 extern void set_nt_service(struct shttpd_ctx *, const char *); 351 extern void set_systray(struct shttpd_ctx *, const char *); 352 extern void try_to_run_as_nt_service(void); 353 345 354 /* 346 355 * io_*.c … … 361 370 extern struct registered_uri *is_registered_uri(struct shttpd_ctx *, 362 371 const char *uri); 363 #if !defined(NO_SSI)364 372 extern void do_ssi(struct conn *); 365 373 extern void ssi_func_destructor(struct llhead *lp); 366 #endif367 374 368 375 /* -
trunk/third-party/shttpd/io_emb.c
r5822 r6349 53 53 else 54 54 c->loc.flags |= FLAG_DONT_CLOSE; 55 56 if (arg->flags & SHTTPD_SUSPEND) 57 c->loc.flags |= FLAG_SUSPEND; 55 58 } 56 59 … … 91 94 shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...) 92 95 { 93 struct conn *c = arg->priv;94 struct io *io = &c->loc.io;95 96 char *buf = arg->out.buf + arg->out.num_bytes; 96 97 int buflen = arg->out.len - arg->out.num_bytes, len = 0; 97 98 va_list ap; 98 99 assert(buf <= io->buf + io->size);100 99 101 100 if (buflen > 0) { … … 268 267 } 269 268 269 void 270 shttpd_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 270 285 const struct io_class io_embedded = { 271 286 "embedded", -
trunk/third-party/shttpd/io_file.c
r5822 r6349 21 21 n = write(fd, buf, len); 22 22 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)); 24 24 25 25 if (n <= 0 || (rem->io.total >= (big_int_t) rem->headers_len)) { -
trunk/third-party/shttpd/io_ssl.c
r5822 r6349 34 34 int n; 35 35 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 { 37 40 n = SSL_get_error(stream->chan.ssl.ssl, n); 38 41 if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE) 39 42 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)); 44 44 } 45 45 } … … 48 48 read_ssl(struct stream *stream, void *buf, size_t len) 49 49 { 50 int nread = 0;50 int nread = -1; 51 51 52 52 assert(stream->chan.ssl.ssl != NULL); -
trunk/third-party/shttpd/shttpd.c
r5841 r6349 11 11 /* 12 12 * Small and portable HTTP server, http://shttpd.sourceforge.net 13 * $Id: shttpd.c,v 1. 28 2008/02/17 21:45:09drozd Exp $13 * $Id: shttpd.c,v 1.44 2008/05/31 18:20:02 drozd Exp $ 14 14 */ 15 15 16 16 #include "defs.h" 17 17 18 time_t current_time; /* Current UTC time */ 19 int tz_offset; /* Time zone offset from UTC */ 18 time_t current_time; /* Current UTC time */ 19 int tz_offset; /* Time zone offset from UTC */ 20 int exit_flag; /* Program exit flag */ 20 21 21 22 const struct vec known_http_methods[] = { … … 26 27 {"HEAD", 4}, 27 28 {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 */35 29 }; 36 30 … … 60 54 61 55 int 56 is_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 68 static void 69 free_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 79 static void 80 listener_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 88 static void 89 registered_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 97 static void 98 acl_destructor(struct llhead *lp) 99 { 100 struct acl *acl = LL_ENTRY(lp, struct acl, link); 101 free(acl); 102 } 103 104 int 62 105 url_decode(const char *src, int src_len, char *dst, int dst_len) 63 106 { … … 127 170 stream->conn->rem.chan.sock, 128 171 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))); 130 173 } 131 174 … … 134 177 */ 135 178 static int 136 open_listening_port(int port)179 shttpd_open_listening_port(int port) 137 180 { 138 181 int sock, on = 1; … … 484 527 return (-1); 485 528 } 486 487 529 488 530 static void … … 639 681 } 640 682 641 io_inc_tail(&c->rem.io, req_len);642 643 683 if (req_len == 0) { 644 684 return; … … 653 693 if (c->loc.flags & FLAG_CLOSED) 654 694 return; 695 696 io_inc_tail(&c->rem.io, req_len); 655 697 656 698 DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s)); … … 706 748 } 707 749 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; 750 static void 751 add_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; 714 757 #if !defined(NO_SSL) 715 758 SSL *ssl = NULL; 759 #else 760 is_ssl = is_ssl; /* supress warnings */ 716 761 #endif /* NO_SSL */ 717 762 … … 738 783 elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO)); 739 784 } else { 740 ctx->nrequests++; 741 c->rem.conn = c->loc.conn = c; 785 c->rem.conn = c->loc.conn = c; 742 786 c->ctx = ctx; 787 c->worker = worker; 743 788 c->sa = sa; 744 789 c->birth_time = current_time; … … 769 814 #endif /* NO_SSL */ 770 815 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++; 775 818 776 819 DBG(("%s:%hu connected (socket %d)", … … 780 823 } 781 824 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 { 825 static struct worker * 826 first_worker(struct shttpd_ctx *ctx) 827 { 828 return (LL_ENTRY(ctx->workers.next, struct worker, link)); 829 } 830 831 static void 832 pass_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 854 static void 855 set_ports(struct shttpd_ctx *ctx, const char *p) 856 { 857 int sock, len, is_ssl, port; 794 858 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 } 835 885 } 836 886 … … 849 899 850 900 /* 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); 853 902 854 903 if (n > 0) … … 904 953 905 954 static void 906 disconnect(struct llhead *lp)955 connection_desctructor(struct llhead *lp) 907 956 { 908 957 struct conn *c = LL_ENTRY(lp, struct conn, link); … … 942 991 c->loc.flags = 0; 943 992 c->loc.content_len = 0; 944 c->rem.flags = FLAG_W | FLAG_R ;993 c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED; 945 994 c->query = c->request = c->uri = c->path_info = NULL; 946 995 c->mime_type.len = 0; … … 954 1003 c->rem.io_class->close(&c->rem); 955 1004 956 EnterCriticalSection(&c->ctx->mutex);957 1005 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); 961 1008 962 1009 free(c); 963 1010 } 1011 } 1012 1013 static void 1014 worker_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); 964 1020 } 965 1021 … … 1001 1057 parse_http_request(c); 1002 1058 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))); 1007 1063 1008 1064 /* Read from the local end if it is ready */ … … 1016 1072 if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL) 1017 1073 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;1023 1074 1024 1075 /* Check whether we should close this connection */ … … 1026 1077 (c->rem.flags & FLAG_CLOSED) || 1027 1078 ((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 1082 static int 1083 num_workers(const struct shttpd_ctx *ctx) 1084 { 1085 char *p = ctx->options[OPT_THREADS]; 1086 return (p ? atoi(p) : 1); 1087 } 1088 1089 static void 1090 handle_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 1111 static int 1112 do_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; 1102 1119 1103 1120 /* 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) { 1105 1122 #ifdef _WIN32 1106 1123 /* … … 1113 1130 #endif /* _WIN32 */ 1114 1131 DBG(("select: %d", ERRNO)); 1115 return; 1116 } 1132 } 1133 1134 return (n); 1135 } 1136 1137 static void 1138 multiplex_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 1193 static void 1194 process_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 */ 1234 void 1235 shttpd_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;; 1117 1260 1118 1261 /* Check for incoming connections on listener sockets */ … … 1123 1266 do { 1124 1267 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); 1144 1270 } while (sock != -1); 1145 1271 } 1146 1272 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); 1194 1275 } 1195 1276 … … 1202 1283 size_t i; 1203 1284 1204 free_list(&ctx-> connections, disconnect);1285 free_list(&ctx->workers, worker_destructor); 1205 1286 free_list(&ctx->registered_uris, registered_uri_destructor); 1206 1287 free_list(&ctx->acl, acl_destructor); … … 1208 1289 #if !defined(NO_SSI) 1209 1290 free_list(&ctx->ssi_funcs, ssi_func_destructor); 1210 #endif 1291 #endif /* !NO_SSI */ 1211 1292 1212 1293 for (i = 0; i < NELEMS(ctx->options); i++) … … 1221 1302 free(ctx); 1222 1303 } 1304 1305 /* 1306 * UNIX socketpair() implementation. Why? Because Windows does not have it. 1307 * Return 0 on success, -1 on error. 1308 */ 1309 int 1310 shttpd_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 1354 static int isbyte(int n) { return (n >= 0 && n <= 255); } 1355 1356 static void 1357 set_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 1368 static void 1369 set_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 1387 static void 1388 set_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 */ 1429 static void 1430 set_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 1457 static void 1458 open_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 1471 static void set_alog(struct shttpd_ctx *ctx, const char *path) { 1472 open_log_file(&ctx->access_log, path); 1473 } 1474 1475 static void set_elog(struct shttpd_ctx *ctx, const char *path) { 1476 open_log_file(&ctx->error_log, path); 1477 } 1478 1479 static void show_cfg_page(struct shttpd_arg *arg); 1480 1481 static void 1482 set_cfg_uri(struct shttpd_ctx *ctx, const char *uri) 1483 { 1484 free_list(&ctx->registered_uris, ®istered_uri_destructor); 1485 1486 if (uri != NULL) 1487 shttpd_register_uri(ctx, uri, &show_cfg_page, ctx); 1488 } 1489 1490 static struct worker * 1491 add_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) 1506 static void 1507 poll_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 1524 static void 1525 worker_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 1536 static void 1537 set_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 1569 static 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 1616 static const struct opt * 1617 find_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 1631 void 1632 shttpd_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 1648 static void 1649 show_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 */ 1696 void 1697 usage(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 1719 static void 1720 set_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 1730 static void 1731 process_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 1794 struct shttpd_ctx * 1795 shttpd_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(¤t_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 1 1 /* 2 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> 2 * Copyright (c) 2004-2008 Sergey Lyubka <valenok@gmail.com> 3 * All rights reserved 3 4 * 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. 10 9 * 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 $ 23 11 */ 24 12 … … 42 30 void *priv; /* Private! Do not touch! */ 43 31 void *state; /* User state */ 44 void *user_data; /* User-defined data*/32 void *user_data; /* Data from register_uri() */ 45 33 struct ubuf in; /* Input is here, POST data */ 46 34 struct ubuf out; /* Output goes here */ 35 47 36 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 */ 53 43 }; 54 44 … … 57 47 * requested. These are the requirements to the callback function: 58 48 * 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, 60 50 * and record how many bytes are copied, into 'out.num_bytes' 61 * 2. it must not block the execution62 * 3. it must set SHTTPD_END_OF_OUTPUT flag when finished63 * 4. for POST requests, it must process the incoming data (in.buf) of length51 * 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 64 54 * '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. 66 56 * 5. If callback allocates arg->state, to keep state, it must deallocate it 67 57 * 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. 68 63 */ 69 64 typedef void (*shttpd_callback_t)(struct shttpd_arg *); 70 65 71 66 /* 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 77 71 * shttpd_poll Do connections processing 78 72 * shttpd_version return string with SHTTPD version 79 73 * shttpd_get_var Fetch POST/GET variable value by name. Return value len 80 74 * 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 84 81 */ 85 82 86 83 struct shttpd_ctx; 87 84 88 struct shttpd_ctx *shttpd_init( void);85 struct shttpd_ctx *shttpd_init(int argc, char *argv[]); 89 86 void shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val); 90 87 void shttpd_fini(struct shttpd_ctx *); 91 int shttpd_listen(struct shttpd_ctx *ctx, int port, int is_ssl);92 88 void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri, 93 89 shttpd_callback_t callback, void *const user_data); … … 105 101 void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name, 106 102 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 103 void shttpd_wakeup(const void *priv); 120 104 121 105 #ifdef __cplusplus -
trunk/third-party/shttpd/standalone.c
r5822 r6349 11 11 #include "defs.h" 12 12 13 static int exit_flag;13 static int exit_flag; /* Program termination flag */ 14 14 15 15 static void … … 26 26 break; 27 27 } 28 }29 30 void31 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]);92 28 } 93 29 … … 108 44 usage(argv[0]); 109 45 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 */ 112 49 113 50 #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 }128 51 (void) signal(SIGCHLD, signal_handler); 129 52 (void) signal(SIGPIPE, SIG_IGN); … … 133 56 (void) signal(SIGINT, signal_handler); 134 57 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); 140 59 141 60 elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s", … … 143 62 144 63 while (exit_flag == 0) 145 shttpd_poll(ctx, 5000);64 shttpd_poll(ctx, 10 * 1000); 146 65 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); 151 67 shttpd_fini(ctx); 152 68
Note: See TracChangeset
for help on using the changeset viewer.