From 79752c5ffe45734261ec49f1d3537a95fe5b1895 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Thu, 1 Jul 2021 14:03:05 -0400 Subject: [tests] _WIN32 fcgi-responder.c, scgi-responder.c --- tests/scgi-responder.c | 126 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 20 deletions(-) (limited to 'tests/scgi-responder.c') diff --git a/tests/scgi-responder.c b/tests/scgi-responder.c index 9ec86dd5..aa1b0aa5 100644 --- a/tests/scgi-responder.c +++ b/tests/scgi-responder.c @@ -3,34 +3,79 @@ * - listens on STDIN_FILENO (socket on STDIN_FILENO must be set up by caller) * - processes a single SCGI request at a time * - arbitrary limitation: reads request headers netstring up to 64k in size - * - expect recv data for request headers netstring every 10ms or less + * - expect recv data for request headers netstring every 25ms or less (or fail) * - no read timeouts for request body; might block reading request body * - no write timeouts; might block writing response + * - no retry if partial send * * Copyright(c) 2017 Glenn Strauss gstrauss()gluelogic.com All rights reserved * License: BSD 3-clause (same as lighttpd) */ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#define _CRT_SECURE_NO_WARNINGS +#ifdef _MSC_VER +#pragma comment(lib, "ws2_32.lib") +#pragma warning(disable:4267) +#pragma warning(disable:5105) /* warning in winbase.h; good job MS */ +#endif +#endif #include -#include #include #include -#include #include -#include #include #include #include + +#ifndef _WIN32 +#include +#include +#include #include +#else +#include +#include +#include /* SSIZE_T */ +#define ssize_t SSIZE_T +#define poll WSAPoll +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#endif #ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 #endif +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + static int finished; static char buf[65536]; +#ifdef _WIN32 +static int +sock_nb_set (SOCKET fd, unsigned int nb) +{ + u_long l = nb; + return ioctlsocket(fd, FIONBIO, &l); +} +#else +static int +sock_nb_set (int fd, unsigned int nb) +{ + return nb + ? fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) + : fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); +} +#endif + + static char * scgi_getenv(char *r, const unsigned long rlen, const char * const name) { @@ -52,20 +97,24 @@ scgi_getenv(char *r, const unsigned long rlen, const char * const name) } +#ifdef _WIN32 +static void +scgi_process (const SOCKET fd) +#else static void scgi_process (const int fd) +#endif { ssize_t rd = 0, offset = 0; char *p = NULL, *r; unsigned long rlen; long long cl; - assert(fd == STDOUT_FILENO); /*(required for response sent with printf())*/ - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + sock_nb_set(fd, 1); do { struct pollfd pfd = { fd, POLLIN, 0 }; - switch (poll(&pfd, 1, 10)) { /* 10ms timeout */ + switch (poll(&pfd, 1, 25)) { /* 25ms timeout */ default: /* 1; the only pfd has revents */ break; case -1: /* error */ @@ -77,14 +126,23 @@ scgi_process (const int fd) break; do { rd = recv(fd, buf+offset, sizeof(buf)-offset, MSG_DONTWAIT); - } while (rd < 0 && errno == EINTR); + } + #ifdef _WIN32 + while (rd < 0 && WSAGetLastError() == WSAEINTR); + #else + while (rd < 0 && errno == EINTR); + #endif if (rd > 0) offset += rd; else if (0 == rd) { p = memchr(buf, ':', offset); break; } + #ifdef _WIN32 + else if (WSAGetLastError() == WSAEWOULDBLOCK) + #else else if (errno == EAGAIN || errno == EWOULDBLOCK) + #endif continue; else break; @@ -96,11 +154,11 @@ scgi_process (const int fd) return; /* invalid netstring (and rlen == ULONG_MAX is too long)*/ if (rlen > sizeof(buf) - (p - buf) - 2) return; /* netstring longer than arbitrary limit we accept here */ - rlen += (p - buf) + 2; + rlen += (unsigned long)(p - buf) + 2; while ((ssize_t)rlen < offset) { struct pollfd pfd = { fd, POLLIN, 0 }; - switch (poll(&pfd, 1, 10)) { /* 10ms timeout */ + switch (poll(&pfd, 1, 25)) { /* 25ms timeout */ default: /* 1; the only pfd has revents */ break; case -1: /* error */ @@ -126,7 +184,7 @@ scgi_process (const int fd) return; /* timeout or error receiving netstring */ if (buf[rlen-1] != ',') return; /* invalid netstring */ - rlen -= (p - buf) + 2; + rlen -= (unsigned long)(p - buf) + 2; r = p+1; /* not checking for empty headers in SCGI request (empty values allowed) */ @@ -145,7 +203,7 @@ scgi_process (const int fd) if (*p != '\0' || p == r+sizeof("CONTENT_LENGTH") || cl < 0 || 0 != errno) return; /* invalid CONTENT_LENGTH */ - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); + sock_nb_set(fd, 0); /* read,discard request body (currently ignored in these SCGI unit tests) * (make basic effort to read body; ignore any timeouts or errors here) */ @@ -168,13 +226,13 @@ scgi_process (const int fd) else if (0 == strcmp(p, "crlf")) cdata = "Status: 200 OK\r\n\r\n"; else if (0 == strcmp(p, "slow-lf")) { - printf("Status: 200 OK\n"); - fflush(stdout); + cdata = "Status: 200 OK\n"; + send(fd, cdata, strlen(cdata), MSG_NOSIGNAL); cdata = "\n"; } else if (0 == strcmp(p,"slow-crlf")) { - printf("Status: 200 OK\r\n"); - fflush(stdout); + cdata = "Status: 200 OK\r\n"; + send(fd, cdata, strlen(cdata), MSG_NOSIGNAL); cdata = "\r\n"; } else if (0 == strcmp(p, "die-at-end")) { @@ -189,7 +247,9 @@ scgi_process (const int fd) p = NULL; } - if (cdata) printf("%s", cdata); + /*(note: *not* buffering to send response header and body together)*/ + + if (cdata) send(fd, cdata, strlen(cdata), MSG_NOSIGNAL); if (NULL == p) cdata = NULL; @@ -198,15 +258,38 @@ scgi_process (const int fd) else cdata = "test123"; - if (cdata) printf("%s", cdata); - - fflush(stdout); + if (cdata) send(fd, cdata, strlen(cdata), MSG_NOSIGNAL); } int main (void) { + #ifdef _WIN32 + + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + if (0 != WSAStartup(wVersionRequested, &wsaData)) + return -1; + + SOCKET lfd = (SOCKET)GetStdHandle(STD_INPUT_HANDLE); + sock_nb_set(lfd, 0); + + SOCKET fd; + do { + fd = accept(lfd, NULL, NULL); + if (fd == INVALID_SOCKET) + continue; + scgi_process(fd); + } while (fd != INVALID_SOCKET + ? 0 == closesocket(fd) && !finished + : WSAGetLastError() == WSAEINTR); + + WSACleanup(); + return 0; + + #else + int fd; fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK); close(STDOUT_FILENO); /*(so that accept() returns fd to STDOUT_FILENO)*/ @@ -220,4 +303,7 @@ main (void) } while (fd > 0 ? 0 == close(fd) && !finished : errno == EINTR); return 0; + + #endif + } -- cgit v1.2.1