diff options
author | Ron Yorston <rmy@pobox.com> | 2020-04-05 09:51:56 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-04-05 10:05:01 +0100 |
commit | fbfb02e8637409f1367cb0d8a3d02f6366261ab4 (patch) | |
tree | bc930441e13d7e27c2aa60436a8346dde0d31ec5 | |
parent | 2b4c25bd2cac034cdc52d29d6bb8c675c87a731c (diff) | |
download | busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.tar.gz busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.tar.bz2 busybox-w32-fbfb02e8637409f1367cb0d8a3d02f6366261ab4.zip |
httpd: WIN32 port
Use mingw_spawn_detach() to daemonize the server. Pass the open
socket to the child process on the command line.
Omit handling of SIGHUP and SIGALRM. Timeouts are handled using
poll(2) instead of alarm(2).
-rw-r--r-- | networking/httpd.c | 135 |
1 files changed, 133 insertions, 2 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index 1757e09c9..7e1c187a5 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -229,7 +229,12 @@ | |||
229 | //usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" | 229 | //usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" |
230 | //usage:#define httpd_full_usage "\n\n" | 230 | //usage:#define httpd_full_usage "\n\n" |
231 | //usage: "Listen for incoming HTTP requests\n" | 231 | //usage: "Listen for incoming HTTP requests\n" |
232 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
232 | //usage: "\n -i Inetd mode" | 233 | //usage: "\n -i Inetd mode" |
234 | //usage: ) | ||
235 | //usage: IF_PLATFORM_MINGW32( | ||
236 | //usage: "\n -i fd Inetd mode file descriptor" | ||
237 | //usage: ) | ||
233 | //usage: "\n -f Don't daemonize" | 238 | //usage: "\n -f Don't daemonize" |
234 | //usage: "\n -v[v] Verbose" | 239 | //usage: "\n -v[v] Verbose" |
235 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" | 240 | //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" |
@@ -267,6 +272,8 @@ | |||
267 | 272 | ||
268 | #define HEADER_READ_TIMEOUT 60 | 273 | #define HEADER_READ_TIMEOUT 60 |
269 | 274 | ||
275 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
276 | |||
270 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; | 277 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; |
271 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; | 278 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; |
272 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; | 279 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; |
@@ -652,8 +659,16 @@ static void parse_conf(const char *path, int flag) | |||
652 | 659 | ||
653 | filename = opt_c_configFile; | 660 | filename = opt_c_configFile; |
654 | if (flag == SUBDIR_PARSE || filename == NULL) { | 661 | if (flag == SUBDIR_PARSE || filename == NULL) { |
662 | #if !ENABLE_PLATFORM_MINGW32 | ||
655 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); | 663 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); |
656 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); | 664 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); |
665 | #else | ||
666 | char *sd = get_system_drive(); | ||
667 | |||
668 | filename = auto_string(xasprintf("%s%s/%s", | ||
669 | (sd && path[0] == '/' && root_len(path) == 0) ? sd : "", | ||
670 | path, HTTPD_CONF)); | ||
671 | #endif | ||
657 | } | 672 | } |
658 | 673 | ||
659 | while ((f = fopen_for_read(filename)) == NULL) { | 674 | while ((f = fopen_for_read(filename)) == NULL) { |
@@ -702,6 +717,7 @@ static void parse_conf(const char *path, int flag) | |||
702 | * without needless copying, therefore we don't merge | 717 | * without needless copying, therefore we don't merge |
703 | * this operation into next while loop. */ | 718 | * this operation into next while loop. */ |
704 | while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' | 719 | while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' |
720 | IF_PLATFORM_MINGW32(&& ch != '\r') | ||
705 | && ch != ' ' && ch != '\t' | 721 | && ch != ' ' && ch != '\t' |
706 | ) { | 722 | ) { |
707 | p0++; | 723 | p0++; |
@@ -709,7 +725,11 @@ static void parse_conf(const char *path, int flag) | |||
709 | p = p0; | 725 | p = p0; |
710 | /* if we enter this loop, we have some whitespace. | 726 | /* if we enter this loop, we have some whitespace. |
711 | * discard it */ | 727 | * discard it */ |
728 | #if !ENABLE_PLATFORM_MINGW32 | ||
712 | while (ch != '\0' && ch != '\n' && ch != '#') { | 729 | while (ch != '\0' && ch != '\n' && ch != '#') { |
730 | #else | ||
731 | while (ch != '\0' && ch != '\n' && ch != '\r' && ch != '#') { | ||
732 | #endif | ||
713 | if (ch != ' ' && ch != '\t') { | 733 | if (ch != ' ' && ch != '\t') { |
714 | *p++ = ch; | 734 | *p++ = ch; |
715 | } | 735 | } |
@@ -1249,7 +1269,21 @@ static unsigned get_line(void) | |||
1249 | count = 0; | 1269 | count = 0; |
1250 | while (1) { | 1270 | while (1) { |
1251 | if (hdr_cnt <= 0) { | 1271 | if (hdr_cnt <= 0) { |
1272 | #if ENABLE_PLATFORM_MINGW32 | ||
1273 | int nfds = 1; | ||
1274 | struct pollfd fds = {STDIN_FILENO, POLLIN, 0}; | ||
1275 | |||
1276 | switch (poll(&fds, nfds, HEADER_READ_TIMEOUT*1000)) { | ||
1277 | case 0: | ||
1278 | send_REQUEST_TIMEOUT_and_exit(0); | ||
1279 | break; | ||
1280 | case -1: | ||
1281 | bb_simple_perror_msg_and_die("poll"); | ||
1282 | break; | ||
1283 | } | ||
1284 | #else | ||
1252 | alarm(HEADER_READ_TIMEOUT); | 1285 | alarm(HEADER_READ_TIMEOUT); |
1286 | #endif | ||
1253 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); | 1287 | hdr_cnt = safe_read(STDIN_FILENO, hdr_buf, sizeof_hdr_buf); |
1254 | if (hdr_cnt <= 0) | 1288 | if (hdr_cnt <= 0) |
1255 | goto ret; | 1289 | goto ret; |
@@ -2090,7 +2124,6 @@ static Htaccess_Proxy *find_proxy_entry(const char *url) | |||
2090 | /* | 2124 | /* |
2091 | * Handle timeouts | 2125 | * Handle timeouts |
2092 | */ | 2126 | */ |
2093 | static void send_REQUEST_TIMEOUT_and_exit(int sig) NORETURN; | ||
2094 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) | 2127 | static void send_REQUEST_TIMEOUT_and_exit(int sig UNUSED_PARAM) |
2095 | { | 2128 | { |
2096 | send_headers_and_exit(HTTP_REQUEST_TIMEOUT); | 2129 | send_headers_and_exit(HTTP_REQUEST_TIMEOUT); |
@@ -2134,11 +2167,21 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2134 | remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); | 2167 | remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr); |
2135 | } | 2168 | } |
2136 | #if ENABLE_FEATURE_IPV6 | 2169 | #if ENABLE_FEATURE_IPV6 |
2170 | # if !ENABLE_PLATFORM_MINGW32 | ||
2137 | if (fromAddr->u.sa.sa_family == AF_INET6 | 2171 | if (fromAddr->u.sa.sa_family == AF_INET6 |
2138 | && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 | 2172 | && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0 |
2139 | && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 | 2173 | && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0 |
2140 | && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) | 2174 | && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff) |
2141 | remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); | 2175 | remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]); |
2176 | # else | ||
2177 | if (fromAddr->u.sa.sa_family == AF_INET6 | ||
2178 | && fromAddr->u.sin6.sin6_addr.s6_words[0] == 0 | ||
2179 | && fromAddr->u.sin6.sin6_addr.s6_words[1] == 0 | ||
2180 | && fromAddr->u.sin6.sin6_addr.s6_words[2] == 0 | ||
2181 | && fromAddr->u.sin6.sin6_addr.s6_words[3] == 0 | ||
2182 | && ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+4)) == 0xffff) | ||
2183 | remote_ip = ntohl(*(uint32_t *)(fromAddr->u.sin6.sin6_addr.s6_words+6)); | ||
2184 | # endif | ||
2142 | #endif | 2185 | #endif |
2143 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { | 2186 | if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) { |
2144 | /* NB: can be NULL (user runs httpd -i by hand?) */ | 2187 | /* NB: can be NULL (user runs httpd -i by hand?) */ |
@@ -2153,8 +2196,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2153 | } | 2196 | } |
2154 | if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); | 2197 | if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip); |
2155 | 2198 | ||
2199 | #ifdef SIGALRM | ||
2156 | /* Install timeout handler. get_line() needs it. */ | 2200 | /* Install timeout handler. get_line() needs it. */ |
2157 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); | 2201 | signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit); |
2202 | #endif | ||
2158 | 2203 | ||
2159 | if (!get_line()) /* EOF or error or empty line */ | 2204 | if (!get_line()) /* EOF or error or empty line */ |
2160 | send_headers_and_exit(HTTP_BAD_REQUEST); | 2205 | send_headers_and_exit(HTTP_BAD_REQUEST); |
@@ -2527,12 +2572,14 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2527 | #endif | 2572 | #endif |
2528 | } | 2573 | } |
2529 | 2574 | ||
2575 | |||
2530 | /* | 2576 | /* |
2531 | * The main http server function. | 2577 | * The main http server function. |
2532 | * Given a socket, listen for new connections and farm out | 2578 | * Given a socket, listen for new connections and farm out |
2533 | * the processing as a [v]forked process. | 2579 | * the processing as a [v]forked process. |
2534 | * Never returns. | 2580 | * Never returns. |
2535 | */ | 2581 | */ |
2582 | # if !ENABLE_PLATFORM_MINGW32 | ||
2536 | #if BB_MMU | 2583 | #if BB_MMU |
2537 | static void mini_httpd(int server_socket) NORETURN; | 2584 | static void mini_httpd(int server_socket) NORETURN; |
2538 | static void mini_httpd(int server_socket) | 2585 | static void mini_httpd(int server_socket) |
@@ -2614,6 +2661,39 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) | |||
2614 | /* never reached */ | 2661 | /* never reached */ |
2615 | } | 2662 | } |
2616 | #endif | 2663 | #endif |
2664 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2665 | static void mini_httpd_win32(int fg, int sock, int argc, char **argv) NORETURN; | ||
2666 | static void mini_httpd_win32(int fg, int sock, int argc, char **argv) | ||
2667 | { | ||
2668 | char *argv_copy[argc + 5]; | ||
2669 | |||
2670 | argv_copy[0] = (char *)bb_busybox_exec_path; | ||
2671 | argv_copy[1] = (char *)"--busybox"; | ||
2672 | argv_copy[2] = (char *)"httpd"; | ||
2673 | argv_copy[3] = (char *)"-i"; | ||
2674 | memcpy(&argv_copy[5], &argv[1], argc * sizeof(argv[0])); | ||
2675 | |||
2676 | while (1) { | ||
2677 | int n; | ||
2678 | |||
2679 | /* Wait for connections... */ | ||
2680 | n = accept(sock, NULL, NULL); | ||
2681 | if (n < 0) | ||
2682 | continue; | ||
2683 | |||
2684 | /* set the KEEPALIVE option to cull dead connections */ | ||
2685 | setsockopt_keepalive(n); | ||
2686 | |||
2687 | argv_copy[4] = itoa(n); | ||
2688 | if ((fg ? spawn(argv_copy) : mingw_spawn_detach(argv_copy)) == -1) | ||
2689 | bb_perror_msg_and_die("can't execute 'httpd'"); | ||
2690 | |||
2691 | /* parent, or spawn failed */ | ||
2692 | close(n); | ||
2693 | } /* while (1) */ | ||
2694 | /* never reached */ | ||
2695 | } | ||
2696 | #endif | ||
2617 | 2697 | ||
2618 | /* | 2698 | /* |
2619 | * Process a HTTP connection on stdin/out. | 2699 | * Process a HTTP connection on stdin/out. |
@@ -2631,12 +2711,39 @@ static void mini_httpd_inetd(void) | |||
2631 | handle_incoming_and_exit(&fromAddr); | 2711 | handle_incoming_and_exit(&fromAddr); |
2632 | } | 2712 | } |
2633 | 2713 | ||
2714 | #if ENABLE_PLATFORM_MINGW32 | ||
2715 | static void mingw_daemonize(char **argv) | ||
2716 | { | ||
2717 | char **new_argv; | ||
2718 | int argc, fd; | ||
2719 | |||
2720 | argc = string_array_len((char **)argv); | ||
2721 | new_argv = xmalloc(sizeof(*argv)*(argc+3)); | ||
2722 | new_argv[0] = (char *)bb_busybox_exec_path; | ||
2723 | new_argv[1] = (char *)"--busybox"; | ||
2724 | new_argv[2] = (char *)"-httpd"; | ||
2725 | memcpy(&new_argv[3], &argv[1], sizeof(*argv)*argc); | ||
2726 | |||
2727 | fd = xopen(bb_dev_null, O_RDWR); | ||
2728 | xdup2(fd, 0); | ||
2729 | xdup2(fd, 1); | ||
2730 | xdup2(fd, 2); | ||
2731 | close(fd); | ||
2732 | |||
2733 | if (mingw_spawn_detach(new_argv)) | ||
2734 | exit(EXIT_SUCCESS); /* parent */ | ||
2735 | exit(EXIT_FAILURE); /* parent */ | ||
2736 | } | ||
2737 | #endif | ||
2738 | |||
2739 | #ifdef SIGHUP | ||
2634 | static void sighup_handler(int sig UNUSED_PARAM) | 2740 | static void sighup_handler(int sig UNUSED_PARAM) |
2635 | { | 2741 | { |
2636 | int sv = errno; | 2742 | int sv = errno; |
2637 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); | 2743 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); |
2638 | errno = sv; | 2744 | errno = sv; |
2639 | } | 2745 | } |
2746 | #endif | ||
2640 | 2747 | ||
2641 | enum { | 2748 | enum { |
2642 | c_opt_config_file = 0, | 2749 | c_opt_config_file = 0, |
@@ -2674,6 +2781,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2674 | IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) | 2781 | IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;) |
2675 | IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) | 2782 | IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;) |
2676 | IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) | 2783 | IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;) |
2784 | IF_PLATFORM_MINGW32(int fd;) | ||
2677 | 2785 | ||
2678 | INIT_G(); | 2786 | INIT_G(); |
2679 | 2787 | ||
@@ -2692,7 +2800,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2692 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") | 2800 | IF_FEATURE_HTTPD_BASIC_AUTH("r:") |
2693 | IF_FEATURE_HTTPD_AUTH_MD5("m:") | 2801 | IF_FEATURE_HTTPD_AUTH_MD5("m:") |
2694 | IF_FEATURE_HTTPD_SETUID("u:") | 2802 | IF_FEATURE_HTTPD_SETUID("u:") |
2695 | "p:ifv" | 2803 | IF_NOT_PLATFORM_MINGW32("p:ifv") |
2804 | IF_PLATFORM_MINGW32("p:i:+fv") | ||
2696 | "\0" | 2805 | "\0" |
2697 | /* -v counts, -i implies -f */ | 2806 | /* -v counts, -i implies -f */ |
2698 | "vv:if", | 2807 | "vv:if", |
@@ -2702,6 +2811,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2702 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) | 2811 | IF_FEATURE_HTTPD_AUTH_MD5(, &pass) |
2703 | IF_FEATURE_HTTPD_SETUID(, &s_ugid) | 2812 | IF_FEATURE_HTTPD_SETUID(, &s_ugid) |
2704 | , &bind_addr_or_port | 2813 | , &bind_addr_or_port |
2814 | IF_PLATFORM_MINGW32(, &fd) | ||
2705 | , &verbose | 2815 | , &verbose |
2706 | ); | 2816 | ); |
2707 | if (opt & OPT_DECODE_URL) { | 2817 | if (opt & OPT_DECODE_URL) { |
@@ -2731,15 +2841,22 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2731 | } | 2841 | } |
2732 | #endif | 2842 | #endif |
2733 | 2843 | ||
2844 | #if !ENABLE_PLATFORM_MINGW32 | ||
2734 | #if !BB_MMU | 2845 | #if !BB_MMU |
2735 | if (!(opt & OPT_FOREGROUND)) { | 2846 | if (!(opt & OPT_FOREGROUND)) { |
2736 | bb_daemonize_or_rexec(0, argv); /* don't change current directory */ | 2847 | bb_daemonize_or_rexec(0, argv); /* don't change current directory */ |
2737 | } | 2848 | } |
2738 | #endif | 2849 | #endif |
2850 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2851 | if (!(opt & OPT_FOREGROUND) && argv[0][0] != '-') | ||
2852 | mingw_daemonize(argv); | ||
2853 | #endif | ||
2739 | 2854 | ||
2740 | xchdir(home_httpd); | 2855 | xchdir(home_httpd); |
2741 | if (!(opt & OPT_INETD)) { | 2856 | if (!(opt & OPT_INETD)) { |
2857 | #ifdef SIGCHLD | ||
2742 | signal(SIGCHLD, SIG_IGN); | 2858 | signal(SIGCHLD, SIG_IGN); |
2859 | #endif | ||
2743 | server_socket = openServer(); | 2860 | server_socket = openServer(); |
2744 | #if ENABLE_FEATURE_HTTPD_SETUID | 2861 | #if ENABLE_FEATURE_HTTPD_SETUID |
2745 | /* drop privileges */ | 2862 | /* drop privileges */ |
@@ -2773,12 +2890,23 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2773 | #endif | 2890 | #endif |
2774 | 2891 | ||
2775 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); | 2892 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); |
2893 | #ifdef SIGHUP | ||
2776 | if (!(opt & OPT_INETD)) | 2894 | if (!(opt & OPT_INETD)) |
2777 | signal(SIGHUP, sighup_handler); | 2895 | signal(SIGHUP, sighup_handler); |
2896 | #endif | ||
2778 | 2897 | ||
2779 | xfunc_error_retval = 0; | 2898 | xfunc_error_retval = 0; |
2899 | #if ENABLE_PLATFORM_MINGW32 | ||
2900 | if (opt & OPT_INETD) { | ||
2901 | xmove_fd(fd, 0); | ||
2902 | xdup2(0, 1); | ||
2903 | while (--fd > 2) | ||
2904 | close(fd); | ||
2905 | } | ||
2906 | #endif | ||
2780 | if (opt & OPT_INETD) | 2907 | if (opt & OPT_INETD) |
2781 | mini_httpd_inetd(); /* never returns */ | 2908 | mini_httpd_inetd(); /* never returns */ |
2909 | #if !ENABLE_PLATFORM_MINGW32 | ||
2782 | #if BB_MMU | 2910 | #if BB_MMU |
2783 | if (!(opt & OPT_FOREGROUND)) | 2911 | if (!(opt & OPT_FOREGROUND)) |
2784 | bb_daemonize(0); /* don't change current directory */ | 2912 | bb_daemonize(0); /* don't change current directory */ |
@@ -2786,5 +2914,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2786 | #else | 2914 | #else |
2787 | mini_httpd_nommu(server_socket, argc, argv); /* never returns */ | 2915 | mini_httpd_nommu(server_socket, argc, argv); /* never returns */ |
2788 | #endif | 2916 | #endif |
2917 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
2918 | mini_httpd_win32(opt & OPT_FOREGROUND, server_socket, argc, argv); | ||
2919 | #endif | ||
2789 | /* return 0; */ | 2920 | /* return 0; */ |
2790 | } | 2921 | } |