From cc2fcd3ece8453ebcf1b302b02e7863ddf1ca88d Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Tue, 24 Nov 2020 08:09:45 -0500 Subject: [PATCH] [multiple] _WIN32 fdevent_pipe_cloexec() Note: Under _WIN32, serious limitation in Windows APIs: select() and WSAPoll() operate only on sockets (not pipes) (directly affects mod_cgi; not currently handled) --- src/configfile.c | 3 +-- src/fdevent.c | 29 +++++++++++++++++++++++++++++ src/fdevent.h | 1 + src/fdlog_maint.c | 4 +--- src/mod_cgi.c | 24 +++++++----------------- src/mod_rrdtool.c | 6 ++---- src/server.c | 3 +-- 7 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/configfile.c b/src/configfile.c index 409f5e2a..84138845 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -2240,7 +2240,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) { } } - if (pipe(fds)) { + if (fdevent_pipe_cloexec(fds, 65536)) { log_perror(srv->errh, __FILE__, __LINE__, "pipe()"); ret = -1; } @@ -2253,7 +2253,6 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) { *(const char **)&args[2] = cmd; args[3] = NULL; - fdevent_setfd_cloexec(fds[0]); pid = fdevent_fork_execve(args[0], args, NULL, -1, fds[1], -1, -1); if (-1 == pid) { log_perror(srv->errh, __FILE__, __LINE__, "fork/exec(%s)", cmd); diff --git a/src/fdevent.c b/src/fdevent.c index 4635922c..276bb365 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -609,6 +609,35 @@ int fdevent_open_dirname(char *path, int symlinks) { } +#ifdef _WIN32 +#include +#endif + +int fdevent_pipe_cloexec (int * const fds, const unsigned int bufsz_hint) { + #ifdef _WIN32 + return _pipe(fds, bufsz_hint, _O_BINARY | _O_NOINHERIT); + #else + #ifdef HAVE_PIPE2 + if (0 != pipe2(fds, O_CLOEXEC)) + #endif + { + if (0 != pipe(fds) + #ifdef FD_CLOEXEC + || 0 != fcntl(fds[0], F_SETFD, FD_CLOEXEC) + || 0 != fcntl(fds[1], F_SETFD, FD_CLOEXEC) + #endif + ) + return -1; + } + #ifdef F_SETPIPE_SZ + if (bufsz_hint > 65536) + fcntl(fds[1], F_SETPIPE_SZ, bufsz_hint); + #endif + return 0; + #endif +} + + int fdevent_mkostemp(char *path, int flags) { #if defined(HAVE_MKOSTEMP) return mkostemp(path, O_CLOEXEC | flags); diff --git a/src/fdevent.h b/src/fdevent.h index 06de520c..b2f3da48 100644 --- a/src/fdevent.h +++ b/src/fdevent.h @@ -87,6 +87,7 @@ int fdevent_socket_cloexec(int domain, int type, int protocol); int fdevent_socket_nb_cloexec(int domain, int type, int protocol); int fdevent_dup_cloexec(int fd); int fdevent_open_cloexec(const char *pathname, int symlinks, int flags, mode_t mode); +int fdevent_pipe_cloexec (int *fds, unsigned int bufsz_hint); int fdevent_mkostemp(char *path, int flags); int fdevent_rename(const char *oldpath, const char *newpath); diff --git a/src/fdlog_maint.c b/src/fdlog_maint.c index 470e5e11..9f5b9832 100644 --- a/src/fdlog_maint.c +++ b/src/fdlog_maint.c @@ -190,10 +190,8 @@ fdlog_pipe_open (const char * const fn) } int fds[2]; - if (pipe(fds)) + if (fdevent_pipe_cloexec(fds, 65536)) return NULL; - fdevent_setfd_cloexec(fds[0]); - fdevent_setfd_cloexec(fds[1]); pid_t pid = fdlog_pipe_spawn(fn, fds[0]); if (pid > 0) { diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 2214ba89..f7aa53bc 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -27,19 +27,6 @@ #include #include -static int pipe_cloexec(int pipefd[2]) { - #ifdef HAVE_PIPE2 - if (0 == pipe2(pipefd, O_CLOEXEC)) return 0; - #endif - return 0 == pipe(pipefd) - #ifdef FD_CLOEXEC - && 0 == fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) - && 0 == fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) - #endif - ? 0 - : -1; -} - typedef struct { uintptr_t *offsets; size_t osize; @@ -665,8 +652,6 @@ static int cgi_write_request(handler_ctx *hctx, int fd) { chunkqueue_remove_finished_chunks(cq); /* unnecessary? */ /* old comment: windows doesn't support select() on pipes - wouldn't be easy to fix for all platforms. - * solution: if this is still a problem on windows, then substitute - * socketpair() for pipe() and closesocket() for close() on windows. */ for (c = cq->first; c; c = cq->first) { @@ -791,11 +776,16 @@ static int cgi_create_env(request_st * const r, plugin_data * const p, handler_c } #endif - if (-1 == to_cgi_fds[0] && pipe_cloexec(to_cgi_fds)) { + unsigned int bufsz_hint = 16384; + #ifdef _WIN32 + if (r->reqbody_length <= 1048576) + bufsz_hint = (unsigned int)r->reqbody_length; + #endif + if (-1 == to_cgi_fds[0] && fdevent_pipe_cloexec(to_cgi_fds, bufsz_hint)) { log_perror(r->conf.errh, __FILE__, __LINE__, "pipe failed"); return -1; } - if (pipe_cloexec(from_cgi_fds)) { + if (fdevent_pipe_cloexec(from_cgi_fds, bufsz_hint)) { if (0 == r->reqbody_length) { close(to_cgi_fds[0]); } diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c index ea65b933..9c6b7315 100644 --- a/src/mod_rrdtool.c +++ b/src/mod_rrdtool.c @@ -86,18 +86,16 @@ static int mod_rrd_create_pipe(server *srv, plugin_data *p) { * If pipes were to be shared, then existing pipes would need to be * reused here, if they already exist (not -1), and after flushing * existing contents (read and discard from read-end of pipes). */ - if (pipe(to_rrdtool_fds)) { + if (fdevent_pipe_cloexec(to_rrdtool_fds, 4096)) { log_perror(srv->errh, __FILE__, __LINE__, "pipe()"); return 0; } - if (pipe(from_rrdtool_fds)) { + if (fdevent_pipe_cloexec(from_rrdtool_fds, 4096)) { log_perror(srv->errh, __FILE__, __LINE__, "pipe()"); close(to_rrdtool_fds[0]); close(to_rrdtool_fds[1]); return 0; } - fdevent_setfd_cloexec(to_rrdtool_fds[1]); - fdevent_setfd_cloexec(from_rrdtool_fds[0]); const char * const path_rrdtool_bin = p->path_rrdtool_bin ? p->path_rrdtool_bin->ptr : "/usr/bin/rrdtool"; diff --git a/src/server.c b/src/server.c index 71b31dec..0007e246 100644 --- a/src/server.c +++ b/src/server.c @@ -197,7 +197,7 @@ static int daemonize(void) { signal(SIGTSTP, SIG_IGN); #endif - if (pipe(pipefd) < 0) exit(-1); + if (fdevent_pipe_cloexec(pipefd, 64) < 0) exit(-1); if (0 > (pid = fork())) exit(-1); @@ -231,7 +231,6 @@ static int daemonize(void) { if (0 != chdir("/")) exit(0); - fdevent_setfd_cloexec(pipefd[1]); return pipefd[1]; } #endif