From 2fb6b238958e3d1ff5a3be2079465f330c102bf1 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 12:42:33 -0700 Subject: [PATCH 01/31] BSD Support in Build Scripts Added support for OpenBSD, FreeBSD and NetBSD in the bldscripts/* scripts. Tested on OpenBSD only so far. Also, extracted some bldscripts 'meson "setdir" logic' (which chooses what directory to build in) into a new file, messetdirvarsfinish.sh, which is then invoked by the mes*setdirvars.sh scripts - i.e. reduced code duplication in the scripts by creating the common messetdirvarsfinish.sh file. --- bldscripts/mesdebugflibevsetdirvars.sh | 19 +++++----- bldscripts/mesdebugsetdirvars.sh | 20 ++--------- bldscripts/mesflibevsetdirvars.sh | 19 +++++----- bldscripts/messetdirvars.sh | 21 ++--------- bldscripts/messetdirvarsfinish.sh | 48 ++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 bldscripts/messetdirvarsfinish.sh diff --git a/bldscripts/mesdebugflibevsetdirvars.sh b/bldscripts/mesdebugflibevsetdirvars.sh index d9088a38b..4614078c6 100644 --- a/bldscripts/mesdebugflibevsetdirvars.sh +++ b/bldscripts/mesdebugflibevsetdirvars.sh @@ -15,16 +15,15 @@ if [ "$(uname)" == "Darwin" ]; then exit 1 fi -MY_ARCH_NM=x86 -if [ "$(uname -m)" == "arm64" ]; then - MY_ARCH_NM=a64 -else - if [ "$(uname -m)" == "aarch64" ]; then - MY_ARCH_NM=a64 - fi +if [ "$(uname)" == "OpenBSD" ]; then + echo "Error: Don't force libevent on OpenBSD, libevent is on by default" + exit 1 fi - -MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.flibev.debug -MESON_PREFIX_DIR=/usr/local +if [ "$(uname)" == "NetBSD" ]; then + echo "Error: Don't force libevent on NetBSD, libevent is on by default" + exit 1 +fi +PST_DIR_SUFFIX=".flibev.debug" +source bldscripts/messetdirvarsfinish.sh diff --git a/bldscripts/mesdebugsetdirvars.sh b/bldscripts/mesdebugsetdirvars.sh index cd8ddd412..06fab6f4f 100644 --- a/bldscripts/mesdebugsetdirvars.sh +++ b/bldscripts/mesdebugsetdirvars.sh @@ -10,22 +10,6 @@ # Use by: # source bldscripts/mesdebugsetdirvars.sh - -MY_ARCH_NM=x86 -if [ "$(uname -m)" == "arm64" ]; then - MY_ARCH_NM=a64 -else - if [ "$(uname -m)" == "aarch64" ]; then - MY_ARCH_NM=a64 - fi -fi - - -if [ "$(uname)" == "Darwin" ]; then - MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.mac.debug - MESON_PREFIX_DIR=/usr/local -else - MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.debug - MESON_PREFIX_DIR=/usr/local -fi +PST_DIR_SUFFIX=".debug" +source bldscripts/messetdirvarsfinish.sh diff --git a/bldscripts/mesflibevsetdirvars.sh b/bldscripts/mesflibevsetdirvars.sh index 67acb959a..bead6a7ce 100644 --- a/bldscripts/mesflibevsetdirvars.sh +++ b/bldscripts/mesflibevsetdirvars.sh @@ -15,16 +15,15 @@ if [ "$(uname)" == "Darwin" ]; then exit 1 fi -MY_ARCH_NM=x86 -if [ "$(uname -m)" == "arm64" ]; then - MY_ARCH_NM=a64 -else - if [ "$(uname -m)" == "aarch64" ]; then - MY_ARCH_NM=a64 - fi +if [ "$(uname)" == "OpenBSD" ]; then + echo "Error: Don't force libevent on OpenBSD, libevent is on by default" + exit 1 fi - -MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.flibev -MESON_PREFIX_DIR=/usr/local +if [ "$(uname)" == "NetBSD" ]; then + echo "Error: Don't force libevent on NetBSD, libevent is on by default" + exit 1 +fi +PST_DIR_SUFFIX=".flibev" +source bldscripts/messetdirvarsfinish.sh diff --git a/bldscripts/messetdirvars.sh b/bldscripts/messetdirvars.sh index d5e15fcdb..2a835cc5b 100644 --- a/bldscripts/messetdirvars.sh +++ b/bldscripts/messetdirvars.sh @@ -10,22 +10,5 @@ # Use by: # source bldscripts/messetdirvars.sh - -MY_ARCH_NM=x86 -if [ "$(uname -m)" == "arm64" ]; then - MY_ARCH_NM=a64 -else - if [ "$(uname -m)" == "aarch64" ]; then - MY_ARCH_NM=a64 - fi -fi - - -if [ "$(uname)" == "Darwin" ]; then - MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.mac - MESON_PREFIX_DIR=/usr/local -else - MESON_BUILD_DIR=build${MY_ARCH_NM}.mes - MESON_PREFIX_DIR=/usr/local -fi - +PST_DIR_SUFFIX= +source bldscripts/messetdirvarsfinish.sh diff --git a/bldscripts/messetdirvarsfinish.sh b/bldscripts/messetdirvarsfinish.sh new file mode 100644 index 000000000..3b4ff89f4 --- /dev/null +++ b/bldscripts/messetdirvarsfinish.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# +# SPDX-FileCopyrightText: 2024 Duncan Greatwood +# +# SPDX-License-Identifier: Apache-2.0 +# +# Sets MESON_BUILD_DIR and MESON_PREFIX_DIR +# +# NOT to be invoked directly by user. Ivoked by other set scripts once +# ... has been set +# +# Use by: +# source bldscripts/messetdirvarsfinish.sh + +MY_ARCH_NM=x86 +if [ "$(uname -m)" == "arm64" ]; then + MY_ARCH_NM=a64 +else + if [ "$(uname -m)" == "aarch64" ]; then + MY_ARCH_NM=a64 + fi +fi + + +if [ "$(uname)" == "Darwin" ]; then + MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.mac${PST_DIR_SUFFIX} + MESON_PREFIX_DIR=/usr/local +else + if [[ "$OSTYPE" == "freebsd"* ]]; then + MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.fbd${PST_DIR_SUFFIX} + MESON_PREFIX_DIR=/usr/local + else + if [[ "$OSTYPE" == "openbsd"* ]]; then + MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.obd${PST_DIR_SUFFIX} + MESON_PREFIX_DIR=/usr/local + else + if [[ "$OSTYPE" == "netbsd"* ]]; then + MESON_BUILD_DIR=build${MY_ARCH_NM}.mes.nbd${PST_DIR_SUFFIX} + MESON_PREFIX_DIR=/usr/local + else + MESON_BUILD_DIR=build${MY_ARCH_NM}.mes${PST_DIR_SUFFIX} + MESON_PREFIX_DIR=/usr/local + fi + fi + fi +fi + From 66239a7a69b3ea8b5ac8f66648cef7b5ee7dea63 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 12:52:42 -0700 Subject: [PATCH 02/31] Updating Version --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f9e52323c..e9cf0e954 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.3.1.20240626 +0.4.1.20240712 From 246b5497340f63a66783296d1caf7a341a958e83 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:07:15 -0700 Subject: [PATCH 03/31] Add BSD Support in Meson Build Files For OpenBSD, FreeBSD and NetBSD. Tried solely on OpenBSD so far. --- examples/meson.build | 8 +++++++- meson.build | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index 8ed5e45bc..cfafb201e 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -14,6 +14,12 @@ pistache_example_files = [ threads_dep = dependency('threads') +# In OpenBSD, rapidjson header fles are installed in +# /usr/local/include, not in /usr/include. Consequently, we need +# deps_libpistache in our dependencies, not just pistache_dep +# +# In particular, for rapidjson/prettywriter.h in rest_description.cc + foreach example_name : pistache_example_files - executable('run'+example_name, example_name+'.cc', dependencies: [pistache_dep, threads_dep]) + executable('run'+example_name, example_name+'.cc', dependencies: [pistache_dep, threads_dep, deps_libpistache]) endforeach diff --git a/meson.build b/meson.build index 4e5033f7e..9f2da76af 100644 --- a/meson.build +++ b/meson.build @@ -19,8 +19,8 @@ project( #macOS host_machine.system() is 'darwin' -if host_machine.system() != 'linux' and host_machine.system() != 'darwin' - error('Pistache currenly only supports Linux and macOS. See https://github.com/pistacheio/pistache/issues/6#issuecomment-242398225 for more information') +if host_machine.system() != 'linux' and host_machine.system() != 'darwin' and host_machine.system() != 'freebsd' and host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' + error('Pistache currenly only supports Linux, macOS and Free/Open/NetBSD. See https://github.com/pistacheio/pistache/issues/6#issuecomment-242398225 for more information') endif compiler = meson.get_compiler('cpp') @@ -130,7 +130,7 @@ if get_option('PISTACHE_USE_SSL') deps_libpistache += dependency('openssl') endif -if host_machine.system() == 'darwin' or get_option('PISTACHE_FORCE_LIBEVENT') +if host_machine.system() == 'darwin' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' or get_option('PISTACHE_FORCE_LIBEVENT') deps_libpistache += dependency('libevent') deps_libpistache += dependency('libevent_pthreads') endif From 777dbb93384c0ad19df49f0699345588592dfa90 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:19:44 -0700 Subject: [PATCH 04/31] Move USE_LIBEVENT Detection from eventmeth.h to a New File The code for #defining _USE_LIBEVENT, previously in eventmeth.h, was moved to its own file emosandlibevdefs.h, which can be included without needing to include all the rest of the eventmeth.h capabilities. event2/thread.h (the libevent thread header file) was also removed from eventmeth.h. It doesn't need to be included there, and including it there exposes eventmeth.h users directly to libevent, the opposite of what we intend since eventmeth acts as a wrapper for libevent. --- include/pistache/emosandlibevdefs.h | 65 +++++++++++++++++++++++++++++ include/pistache/eventmeth.h | 36 +--------------- include/pistache/meson.build | 1 + 3 files changed, 68 insertions(+), 34 deletions(-) create mode 100644 include/pistache/emosandlibevdefs.h diff --git a/include/pistache/emosandlibevdefs.h b/include/pistache/emosandlibevdefs.h new file mode 100644 index 000000000..808647127 --- /dev/null +++ b/include/pistache/emosandlibevdefs.h @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2024 Duncan Greatwood + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// Defines, or does not define, _USE_LIBEVENT, _USE_LIBEVENT_LIKE_APPLE and +// _IS_BSD +// +// emosandlibevdefs.h + +#ifndef _EMOSANDLIBEVDEFS_H_ +#define _EMOSANDLIBEVDEFS_H_ + +/* ------------------------------------------------------------------------- */ + +#ifdef PISTACHE_FORCE_LIBEVENT + +// Force libevent even for Linux +#define _USE_LIBEVENT 1 + +// _USE_LIBEVENT_LIKE_APPLE not only forces libevent, but even in Linux causes +// the code to be as similar as possible to the way it is for __APPLE__ +// (e.g. wherever possible, even on Linux it uses solely OS calls that are +// also available on macOS) +// +// Can comment out if not wanted +#define _USE_LIBEVENT_LIKE_APPLE 1 + +#endif // ifdef PISTACHE_FORCE_LIBEVENT + +#ifdef _USE_LIBEVENT_LIKE_APPLE + #ifndef _USE_LIBEVENT + #define _USE_LIBEVENT 1 + #endif +#endif + +#ifdef __APPLE__ + #ifndef _USE_LIBEVENT + #define _USE_LIBEVENT 1 + #endif + #ifndef _USE_LIBEVENT_LIKE_APPLE + #define _USE_LIBEVENT_LIKE_APPLE 1 + #endif +#elif defined(_WIN32) // Defined for both 32-bit and 64-bit environments + #define _USE_LIBEVENT 1 +#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) + #include + #if defined(BSD) + // FreeBSD, NetBSD, OpenBSD, DragonFly BSD + #ifndef _USE_LIBEVENT + #define _USE_LIBEVENT 1 + #endif + #ifndef _USE_LIBEVENT_LIKE_APPLE + #define _USE_LIBEVENT_LIKE_APPLE 1 + #endif + #ifndef _IS_BSD + #define _IS_BSD 1 + #endif + #endif +#endif + +/* ------------------------------------------------------------------------- */ + +#endif // ifndef _EMOSANDLIBEVDEFS_H_ diff --git a/include/pistache/eventmeth.h b/include/pistache/eventmeth.h index d7440a2be..604edba82 100644 --- a/include/pistache/eventmeth.h +++ b/include/pistache/eventmeth.h @@ -12,37 +12,7 @@ /* ------------------------------------------------------------------------- */ -#ifdef PISTACHE_FORCE_LIBEVENT - -// Force libevent even for Linux -#define _USE_LIBEVENT 1 - -// _USE_LIBEVENT_LIKE_APPLE not only forces libevent, but even in Linux causes -// the code to be as similar as possible to the way it is for __APPLE__ -// (e.g. wherever possible, even on Linux it uses solely OS calls that are -// also available on macOS) -// -// Can comment out if not wanted -#define _USE_LIBEVENT_LIKE_APPLE 1 - -#endif // ifdef PISTACHE_FORCE_LIBEVENT - -#ifdef _USE_LIBEVENT_LIKE_APPLE - #ifndef _USE_LIBEVENT - #define _USE_LIBEVENT 1 - #endif -#endif - -#ifdef __APPLE__ - #ifndef _USE_LIBEVENT - #define _USE_LIBEVENT 1 - #endif - #ifndef _USE_LIBEVENT_LIKE_APPLE - #define _USE_LIBEVENT_LIKE_APPLE 1 - #endif -#elif defined(_WIN32) // Defined for both 32-bit and 64-bit environments - #define _USE_LIBEVENT 1 -#endif +#include // Note: eventmeth wraps and abstracts capabilities of the libevent library, // providing interfaces to pistache that are similar to the epoll, eventfd and @@ -203,8 +173,6 @@ namespace Pistache #include #include -#include - #include #include #include @@ -427,4 +395,4 @@ namespace Pistache /* ------------------------------------------------------------------------- */ -#endif // ifdef _USE_LIBEVENT +#endif // ifndef _EVENTMETH_H_ diff --git a/include/pistache/meson.build b/include/pistache/meson.build index deacccf80..1c654ef93 100644 --- a/include/pistache/meson.build +++ b/include/pistache/meson.build @@ -12,6 +12,7 @@ install_headers( 'config.h', 'cookie.h', 'description.h', + 'emosandlibevdefs.h', 'endpoint.h', 'eventmeth.h', 'errors.h', From 9386ae90f915a3d118f782024a14e814a8e9fc16 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:26:37 -0700 Subject: [PATCH 05/31] Replace use of strcpy and strcat Replaced use of strcpy and strcat with strlcpy/strncpy and strlcat/strncat respectively to avoid a clang compiler warning that was showing up in OpenBSD. --- include/pistache/pist_timelog.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/pistache/pist_timelog.h b/include/pistache/pist_timelog.h index 58f660c8d..ae759c925 100644 --- a/include/pistache/pist_timelog.h +++ b/include/pistache/pist_timelog.h @@ -30,6 +30,7 @@ // --------------------------------------------------------------------------- +#include // For _IS_BSD #include #ifdef DEBUG @@ -152,7 +153,13 @@ class __PS_TIMEDBG { for(unsigned int i=0; i<10; i++) marker_chars[i] = the_marker; + #ifdef _IS_BSD + strlcpy(&(marker_chars[10]), "...", 4); + #elif defined(__linux__) + strncpy(&(marker_chars[10]), "...", 4); + #else strcpy(&(marker_chars[10]), "..."); + #endif marker_chars += (10 + 3); for(unsigned int i=0; i<10; i++) @@ -227,7 +234,15 @@ class __PS_TIMEDBG va_end(ap); if (ln >= ((int) sizeof_buf)) + { + #ifdef _IS_BSD + strlcat(buf_ptr, "...", 5); + #elif defined(__linux__) + strncat(buf_ptr, "...", 5); + #else strcat(buf_ptr, "..."); + #endif + } return(buf_ptr); } From 78045da357ccf98c2d45951ee58089b838fc546d Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:33:50 -0700 Subject: [PATCH 06/31] Remove Use of CLOCK_MONOTONIC_RAW in BSD case. Removed Use of CLOCK_MONOTONIC_RAW in BSD case. CLOCK_MONOTONIC_RAW is not defined on FreeBSD13.3 and OpenBSD 7.3. Also, added the include for , which had been removed from eventmeth.h (event2/thread.h being the thread header file for libevent). --- src/common/eventmeth.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/eventmeth.cc b/src/common/eventmeth.cc index 1832af0a5..b305c660e 100644 --- a/src/common/eventmeth.cc +++ b/src/common/eventmeth.cc @@ -11,6 +11,8 @@ #ifdef _USE_LIBEVENT +#include + /* ------------------------------------------------------------------------- */ /* * Event classes - EmEvent, EmEventCtr, EmEventFd and EmEventTmrFd @@ -1888,7 +1890,10 @@ EmEventTmrFd::EmEventTmrFd(clockid_t clock_id, break; case CLOCK_MONOTONIC: + #ifndef _IS_BSD + // CLOCK_MONOTONIC_RAW not defined on FreeBSD13.3 and OpenBSD 7.3 case CLOCK_MONOTONIC_RAW: + #endif #ifdef __APPLE__ case CLOCK_MONOTONIC_RAW_APPROX: case CLOCK_UPTIME_RAW: From 12f9434d6e2241aa8ecb838275cda9b5be747475 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:37:52 -0700 Subject: [PATCH 07/31] Add a Fallback Method of Counting In-Use Filehandles OpenBSD doesn't support either of the existing methods of counting open files hanldes, used with Linux and macOS respectively. Created a brute-force fallback method for use with BSD. Tried on openBSD only so far. --- tests/helpers/fd_utils.cc | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/helpers/fd_utils.cc b/tests/helpers/fd_utils.cc index 601f1dae9..c2854f757 100644 --- a/tests/helpers/fd_utils.cc +++ b/tests/helpers/fd_utils.cc @@ -31,7 +31,10 @@ namespace filesystem = std::experimental::filesystem; // // Return: if buffer non-null, number of proc_fdinfo written, -1 on fail -#endif +#elif ! defined __linux__ +#include // for sysconf and getdtablesize +#endif + namespace Pistache { @@ -67,7 +70,7 @@ namespace Pistache return ((std::size_t)num_fds); } -#else +#elif defined __linux__ using filesystem::directory_iterator; const filesystem::path fds_dir { "/proc/self/fd" }; @@ -78,8 +81,31 @@ namespace Pistache return std::distance(directory_iterator(fds_dir), directory_iterator {}); +#else // fallback case, e.g. *BSD +#ifndef OPEN_MAX +#define OPEN_MAX 4096 +#endif + long maxfd; + + maxfd = sysconf(_SC_OPEN_MAX); + if (maxfd < 0) // or if sysconf not defined at all + maxfd = getdtablesize(); + + if ((maxfd < 0) || (maxfd > 4*OPEN_MAX)) + maxfd = OPEN_MAX; + + int j, n = 0; + for(j = 0; j < maxfd; j++) + { + int fd = dup(j); + if (fd < 0) + continue; + n++; + close(fd); + } -#endif // of ifdef... else... __APPLE__ + return(n); +#endif // of ifdef... elif... else... __APPLE__ } } // namespace Pistache From c6b7a9f26fbd9669dacabf9f575868218d3338df Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:41:46 -0700 Subject: [PATCH 08/31] Include the wait.h Header File in BSD Cases --- tests/listener_test.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/listener_test.cc b/tests/listener_test.cc index 8ff5c3295..142a6ca16 100644 --- a/tests/listener_test.cc +++ b/tests/listener_test.cc @@ -21,6 +21,11 @@ #include #include #include + +#ifdef _IS_BSD +#include // for wait +#endif + class SocketWrapper { From 35739ab93ec8578eae2ff932085a5a9dbda2b6e3 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:43:29 -0700 Subject: [PATCH 09/31] Support pthread_set_name_np Spelling For BSD Added preprocessor directives to use the correct spelling of pthread_set[_]name_np for BSD. In macOS and Linux it is spelt pthread_setname_np, whereas in OpenBSD it is spelt pthread_set_name_np. Tried on OpenBSD only so far. --- src/common/reactor.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/common/reactor.cc b/src/common/reactor.cc index dff153fa9..5da30d480 100644 --- a/src/common/reactor.cc +++ b/src/common/reactor.cc @@ -23,6 +23,12 @@ #include #include +#ifdef _IS_BSD +// For pthread_set_name_np +#include +#include +#endif + using namespace std::string_literals; namespace Pistache::Aio @@ -625,7 +631,11 @@ namespace Pistache::Aio thread = std::thread([=]() { if (!threadsName_.empty()) { +#ifdef _IS_BSD + pthread_set_name_np( +#else pthread_setname_np( +#endif #ifndef __APPLE__ // Apple's macOS version of pthread_setname_np // takes only "const char * name" as parm From 83a84257b0c0444ca4d6a6f79cdadc6834711f0e Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 12 Jul 2024 14:46:30 -0700 Subject: [PATCH 10/31] Support TCP_NOPUSH and sendfile in BSD Case Uses TCP_NOPUSH (like macOS) not TCP_CORK (as Linux) in getsockopt/setsockopt. Small improvement to a couple of debug log messages. Added a my_sendfile function for use by BSD. OpenBSD does not have a sendfile system call. --- src/common/transport.cc | 166 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 8 deletions(-) diff --git a/src/common/transport.cc b/src/common/transport.cc index 63bbaeeeb..3fa4a8336 100644 --- a/src/common/transport.cc +++ b/src/common/transport.cc @@ -25,6 +25,10 @@ #include #endif +#ifdef _IS_BSD +#include // for lseek +#endif + #ifndef _USE_LIBEVENT_LIKE_APPLE // Note: sys/timerfd.h is linux-only (and certainly POSIX only) #include @@ -547,7 +551,7 @@ namespace Pistache::Tcp int tcp_no_push = 0; socklen_t len = sizeof(tcp_no_push); int sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, -#ifdef __APPLE__ +#if defined __APPLE__ || defined _IS_BSD TCP_NOPUSH, #else TCP_CORK, @@ -562,7 +566,7 @@ namespace Pistache::Tcp tcp_no_push = msg_more_style ? 1 : 0; sock_opt_res = setsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, -#ifdef __APPLE__ +#if defined __APPLE__ || defined _IS_BSD TCP_NOPUSH, #else TCP_CORK, @@ -582,8 +586,9 @@ namespace Pistache::Tcp #ifdef DEBUG else { - PS_LOG_DEBUG_ARGS("getsockopt failed for fd %p, actual fd %d", - fd, GET_ACTUAL_FD(fd)); + PS_LOG_DEBUG_ARGS("getsockopt failed for fd %p, actual fd %d, " + "errno %d, err %s", + fd, GET_ACTUAL_FD(fd), errno, strerror(errno)); throw std::runtime_error("getsockopt failed"); } #endif @@ -648,6 +653,134 @@ namespace Pistache::Tcp return bytesWritten; } +#ifdef _IS_BSD + // This is the sendfile function prototype found in Linux. However, + // sendfile does not exist in OpenBSD, so we make our own. + // + // https://www.man7.org/linux/man-pages/man2/sendfile.2.html + // Copies FROM "in_fd" TO "out_fd" + // Returns number of bytes written on success, -1 with errno set on error + // + // If offset is not NULL, then sendfile() does not modify the file offset + // of in_fd; otherwise the file offset is adjusted to reflect the number of + // bytes read from in_fd. + ssize_t my_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) + { + char buff[65536+16]; + + int read_errors = 0; + int write_errors = 0; + ssize_t bytes_written_res = 0; + + off_t in_fd_start_pos = -1; + + if (offset) + { + in_fd_start_pos = lseek(in_fd, 0, SEEK_CUR); + if (in_fd_start_pos < 0) + { + PS_LOG_DEBUG("lseek error"); + return(in_fd_start_pos); + } + + + if (lseek(in_fd, *offset, SEEK_SET) < 0) + { + PS_LOG_DEBUG("lseek error"); + return(-1); + } + } + + for(;;) + { + size_t bytes_to_read = count ? + std::min(sizeof(buff)-16, count) : (sizeof(buff)-16); + + ssize_t bytes_read = read(in_fd, &(buff[0]), bytes_to_read); + if (bytes_read == 0) // End of file + break; + + if (bytes_read < 0) + { + if ((errno == EINTR) || (errno == EAGAIN)) + { + PS_LOG_DEBUG("read-interrupted error"); + + read_errors++; + if (read_errors < 256) + continue; + + PS_LOG_DEBUG("read-interrupted repeatedly error"); + errno = EIO; + } + + bytes_written_res = -1; + break; + } + read_errors = 0; + + bool re_adjust_pos = false; + + if ((count) && (bytes_read > ((ssize_t)count))) + { + bytes_read = ((ssize_t)count); + re_adjust_pos = true; + } + + if (offset) + { + *offset += bytes_read; + if (re_adjust_pos) + lseek(in_fd, *offset, SEEK_SET); + } + + auto p = &(buff[0]); + while (bytes_read > 0) + { + ssize_t bytes_written = write(out_fd, p, bytes_read); + if (bytes_written <= 0) + { + if ((bytes_written == 0) || (errno == EINTR) || + (errno == EAGAIN)) + { + PS_LOG_DEBUG("write-interrupted error"); + + write_errors++; + if (write_errors < 256) + continue; + + PS_LOG_DEBUG("write-interrupted repeatedly error"); + errno = EIO; + } + + bytes_written_res = -1; + break; + } + write_errors = 0; + + bytes_read -= bytes_written; + p += bytes_written; + bytes_written_res += bytes_written; + } + + if (count) + count -= bytes_read; + } + + // if offset non null, set in_fd file pos to pos from start of this + // function + if ((offset) && (bytes_written_res >= 0) && + (lseek(in_fd, in_fd_start_pos, SEEK_SET) < 0)) + { + PS_LOG_DEBUG("lseek error"); + bytes_written_res = -1; + } + + return(bytes_written_res); + } + +#endif // ifdef _IS_BSD + ssize_t Transport::sendFile(Fd fd, int file, off_t offset, size_t len) { ssize_t bytesWritten = 0; @@ -682,12 +815,23 @@ namespace Pistache::Tcp if (it_second_ssl_is_null) { +#ifdef DEBUG + const char * sendfile_fn_name = +#ifdef _IS_BSD + "my_sendfile"; +#else + "::sendfile"; +#endif +#endif + #endif /* PISTACHE_USE_SSL */ - PS_LOG_DEBUG_ARGS("::sendfile fd %" PIST_QUOTE(PS_FD_PRNTFCD) " actual-fd %d, file fd, len %d", + PS_LOG_DEBUG_ARGS( + "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) + " actual-fd %d, file fd %d, len %d", sendfile_fn_name, fd, GET_ACTUAL_FD(fd), file, len); #ifdef _USE_LIBEVENT_LIKE_APPLE - // !!!! Should we do configureMsgMoreStyle for SLL as well? And + // !!!! Should we do configureMsgMoreStyle for SSL as well? And // same question in sendRawBuffer configureMsgMoreStyle(fd, false /*msg_more_style*/); #endif @@ -720,10 +864,16 @@ namespace Pistache::Tcp } #else - bytesWritten = ::sendfile(GET_ACTUAL_FD(fd), file, &offset, len); +#ifdef _IS_BSD + bytesWritten = my_sendfile(GET_ACTUAL_FD(fd), file, &offset, len); +#else + bytesWritten = ::sendfile(GET_ACTUAL_FD(fd), file, &offset, len); +#endif #endif - PS_LOG_DEBUG_ARGS("::sendfile fd %" PIST_QUOTE(PS_FD_PRNTFCD) " , bytesWritten %d", fd, bytesWritten); + PS_LOG_DEBUG_ARGS( + "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) ", bytesWritten %d", + sendfile_fn_name, fd, bytesWritten); #ifdef PISTACHE_USE_SSL } From 8e816a62de59bcf65693d13a84dda6c4d9dccc4d Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 19 Jul 2024 20:41:05 -0700 Subject: [PATCH 11/31] Build For FreeBSD and Fix Client Connect on Success Problem In client.cc, the code was failing to call registerFdOneShot after ::connect returned success. Apparently in all the other *nix we've tried, ::connect returns -1 with errno EINPROGRESS, whereas in FreeBSD ::connect simply returns 0 (success); tweaked the code so registerFdOneShot is called in the "::connect returns 0" case. This makes cookie_test_3 pass, it fails on FreeBSD otherwise. emosandlibevdefs.h: Add comment on why FreeBSD uses libevent and not the FreebSD Linuxulator. .clang-format-ignore: Ignore the formatting in emosandlibevdefs.h (emosandlibevdefs.h uses the same formatting as eventmeth.h - see previous commit for why it was pulled out of eventmeth.h). meson.build: Include execinfo library explicitly for FreeBSD (it is a separate library in FreeBSD, but not in other *nix seemingly). eventmeth.cc: Fixed an indentation issue (no change in functionality). --- .clang-format-ignore | 1 + include/pistache/emosandlibevdefs.h | 9 +++++++++ meson.build | 8 +++++++- src/client/client.cc | 23 ++++++++++++----------- src/common/eventmeth.cc | 10 +++++----- version.txt | 2 +- 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/.clang-format-ignore b/.clang-format-ignore index 53dcd68d7..4ed9bc6c3 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -5,6 +5,7 @@ subprojects/** src/common/eventmeth.cc include/pistache/eventmeth.h +include/pistache/emosandlibevdefs.h src/common/pist_timelog.cc include/pistache/pist_timelog.h src/common/pist_check.cc diff --git a/include/pistache/emosandlibevdefs.h b/include/pistache/emosandlibevdefs.h index 808647127..5cb8baf6a 100644 --- a/include/pistache/emosandlibevdefs.h +++ b/include/pistache/emosandlibevdefs.h @@ -48,6 +48,15 @@ #include #if defined(BSD) // FreeBSD, NetBSD, OpenBSD, DragonFly BSD + // + // Note - FreeBSD may support epoll via FreeBSD's Linux emulation layer + // (see https://wiki.freebsd.org/Linuxulator). We can check for FreeBSD + // using "ifdef __FreeBSD__" and also check __FreeBSD_version (see + // https://docs.freebsd.org/en/books/porters-handbook/versions/). + // However, since FreeBSD's Linuxulator supports Linux binaries, a user + // might perhaps just as well run the Linux version of Pistache if + // using the Linuxulator. So we use libevent (which will likely use + // kqueue on FreeBSD) even in the FreeBSD case. #ifndef _USE_LIBEVENT #define _USE_LIBEVENT 1 #endif diff --git a/meson.build b/meson.build index 9f2da76af..9e6a8e327 100644 --- a/meson.build +++ b/meson.build @@ -130,11 +130,17 @@ if get_option('PISTACHE_USE_SSL') deps_libpistache += dependency('openssl') endif -if host_machine.system() == 'darwin' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' or get_option('PISTACHE_FORCE_LIBEVENT') +if host_machine.system() == 'darwin' or host_machine.system() == 'freebsd' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' or get_option('PISTACHE_FORCE_LIBEVENT') deps_libpistache += dependency('libevent') deps_libpistache += dependency('libevent_pthreads') endif +if host_machine.system() == 'freebsd' + # Does not appear to be necessary for OpenBSD + libexecinfo_dep = compiler.find_library('execinfo') + deps_libpistache += libexecinfo_dep +endif + version_array = [] if meson.version().version_compare('>=0.57.0') version_array = import('fs').read('version.txt').strip().split('.') diff --git a/src/client/client.cc b/src/client/client.cc index 928d0ac1b..06a27968b 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -491,18 +491,19 @@ namespace Pistache::Http::Experimental PS_LOG_DEBUG_ARGS("Calling ::connect fs %d", GET_ACTUAL_FD(fd)); int res = ::connect(GET_ACTUAL_FD(fd), data->getAddr(), data->addr_len); - if (res == -1) + PS_LOG_DEBUG_ARGS("::connect res %d, errno on fail %d (%s)", + res, (res < 0) ? errno : 0, + (res < 0) ? strerror(errno) : "success"); + + if ((res == 0) || ((res == -1) && (errno == EINPROGRESS))) { - if (errno == EINPROGRESS) - { - reactor()->registerFdOneShot(key(), fd, - NotifyOn::Write | NotifyOn::Hangup | NotifyOn::Shutdown); - } - else - { - data->reject(Error::system("Failed to connect")); - continue; - } + reactor()->registerFdOneShot(key(), fd, + NotifyOn::Write | NotifyOn::Hangup | NotifyOn::Shutdown); + } + else + { + data->reject(Error::system("Failed to connect")); + continue; } connections.insert(std::make_pair(fd, std::move(*data))); } diff --git a/src/common/eventmeth.cc b/src/common/eventmeth.cc index b305c660e..663b24549 100644 --- a/src/common/eventmeth.cc +++ b/src/common/eventmeth.cc @@ -1464,12 +1464,12 @@ namespace Pistache "EmEventCtr %p also being activated for write", this); - flags |= EV_WRITE; - } - - event_active(ev_, flags, 0 /* obsolete parm*/); - } + flags |= EV_WRITE; } + + event_active(ev_, flags, 0 /* obsolete parm*/); + } + } std::shared_ptr tmp_cv_sptr( diff --git a/version.txt b/version.txt index e9cf0e954..f3be59418 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.1.20240712 +0.4.1.20240719 From 4b9789400c2e728c88a8007bc631fdc1d0955739 Mon Sep 17 00:00:00 2001 From: DMG Date: Sat, 20 Jul 2024 12:14:24 -0700 Subject: [PATCH 12/31] Allow UTC Suffix in Header Date String In the test "headers_test -> last_modified_test" we allow the last-modified-time string produced to end in either "UTC" or "GMT". Previously, the test required "GMT". As of July/2024, it seems that in macOS, Linux and OpenBSD it produces "GMT", while under FreeBSD it's "UTC". Of course, they mean the same thing, and we allow either. --- tests/headers_test.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/headers_test.cc b/tests/headers_test.cc index 617c167c3..434029951 100644 --- a/tests/headers_test.cc +++ b/tests/headers_test.cc @@ -739,13 +739,23 @@ TEST(headers_test, access_control_allow_methods_test) TEST(headers_test, last_modified_test) { - const std::string ref = "Sun, 06 Nov 1994 08:49:37 GMT"; + // const std::string ref = "Sun, 06 Nov 1994 08:49:37 GMT"; using namespace std::chrono; Pistache::Http::FullDate::time_point expected_time_point = date::sys_days(date::year { 1994 } / 11 / 6) + hours(8) + minutes(49) + seconds(37); Pistache::Http::FullDate fd(expected_time_point); Pistache::Http::Header::LastModified l0(fd); std::ostringstream oss; l0.write(oss); + + // As of July/2024, it seems that in macOS, Linux and OpenBSD this produces + // an OSS ending "GMT", while in FreeBSD it ends "UTC". Of course, they + // mean the same thing, and we allow either. + const bool oss_ends_utc = + ((oss.str().length() >= 3) && + (oss.str().compare(oss.str().length() - 3, 3, "UTC") == 0)); + const std::string ref(std::string("Sun, 06 Nov 1994 08:49:37 ") + + (oss_ends_utc ? "UTC" : "GMT")); + ASSERT_EQ(ref, oss.str()); Pistache::Http::Header::LastModified l1; l1.parse(ref); From d167aa3ff2d4d94395f0004269d91646df5869a9 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:19:13 -0700 Subject: [PATCH 13/31] Remove constexpr from actualFdU64Value in libevent Case Needed for NetBSD when using libevent. actualFdU64Value too complex for constexpr. --- include/pistache/os.h | 6 +++++- version.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/pistache/os.h b/include/pistache/os.h index 5b7ad5bb3..684eba853 100644 --- a/include/pistache/os.h +++ b/include/pistache/os.h @@ -97,7 +97,11 @@ namespace Pistache constexpr TagValue value() const { return value_; } uint64_t valueU64() const { return ((uint64_t)value_); } - constexpr uint64_t actualFdU64Value() const +#ifndef _USE_LIBEVENT + constexpr +#endif + uint64_t + actualFdU64Value() const { #ifdef _USE_LIBEVENT if (value_ == NULL) diff --git a/version.txt b/version.txt index f3be59418..198aaa4da 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.1.20240719 +0.4.1.20240722 From dd5c195f2c34ea86ebff6d082d67fd1fcd734453 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:21:29 -0700 Subject: [PATCH 14/31] Include execinfo library for NetBSD Builds --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9e6a8e327..00e61ffd1 100644 --- a/meson.build +++ b/meson.build @@ -135,7 +135,7 @@ if host_machine.system() == 'darwin' or host_machine.system() == 'freebsd' or ho deps_libpistache += dependency('libevent_pthreads') endif -if host_machine.system() == 'freebsd' +if host_machine.system() == 'freebsd' or host_machine.system() == 'netbsd' # Does not appear to be necessary for OpenBSD libexecinfo_dep = compiler.find_library('execinfo') deps_libpistache += libexecinfo_dep From c7de16b852fc2039f172de49c2243a15af9f63a0 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:23:30 -0700 Subject: [PATCH 15/31] Remove Unneeded Trailing Semicolon gcc gives warning when compiling in NetBSD otherwise --- src/common/eventmeth.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/eventmeth.cc b/src/common/eventmeth.cc index 663b24549..bd5b114c9 100644 --- a/src/common/eventmeth.cc +++ b/src/common/eventmeth.cc @@ -4239,7 +4239,7 @@ EmEventTmrFd::EmEventTmrFd(clockid_t clock_id, // To enable to_string of an Fd std::string to_string(const EmEvent * eme) - {return(std::to_string((unsigned long) eme));}; + {return(std::to_string((unsigned long) eme));} /* ------------------------------------------------------------------------- */ From e10ac7a08270795ce07ebc5fa2d3f017a32de7da Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:24:56 -0700 Subject: [PATCH 16/31] Add Workaround for Apparent NetBSD std::put_time Bug --- src/common/http_defs.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/common/http_defs.cc b/src/common/http_defs.cc index f8500ff37..138f5e8dc 100644 --- a/src/common/http_defs.cc +++ b/src/common/http_defs.cc @@ -131,7 +131,21 @@ namespace Pistache::Http case Type::RFC1123GMT: { // Requires GMT so we must use std::gmtime to convert to GMT time_t t = std::chrono::system_clock::to_time_t(date_); - os << std::put_time(std::gmtime(&t), "%a, %d %b %Y %T %Z"); + + // July/2024. For a std::tm* that comes from std::gmtime, + // std::put_time %Z should always outout the std::tm locale namely + // "GMT" (or "UTC"). However, in NetBSD 10.0, std::put_time appears + // to output the locale of the machine it's running on ("PST") not + // the locale of the std::tm*. We workaround as per the following + // #defines. Since we know the locale of std::gmtime is GMT, the + // workaround is correct in general. + os << std::put_time(std::gmtime(&t), "%a, %d %b %Y %T " +#ifdef __NetBSD__ + "GMT" +#else + "%Z" +#endif + ); } break; case Type::RFC850: From f9ec9687e4ff3797551493f8ec09cfbe8c0174eb Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:26:57 -0700 Subject: [PATCH 17/31] Support for pthread_setname_np As Defined in NetBSD Using #defines to cope with the different definition NetBSD has of pthread_setname_np (different to Linux macOS and to other BSDs). --- src/common/reactor.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/common/reactor.cc b/src/common/reactor.cc index 5da30d480..54e699ebf 100644 --- a/src/common/reactor.cc +++ b/src/common/reactor.cc @@ -26,8 +26,10 @@ #ifdef _IS_BSD // For pthread_set_name_np #include +#ifndef __NetBSD__ #include #endif +#endif using namespace std::string_literals; @@ -631,7 +633,7 @@ namespace Pistache::Aio thread = std::thread([=]() { if (!threadsName_.empty()) { -#ifdef _IS_BSD +#if defined _IS_BSD && ! defined __NetBSD__ pthread_set_name_np( #else pthread_setname_np( @@ -647,6 +649,10 @@ namespace Pistache::Aio // as per macOS, while newer FreeBSD (2021 ?) // behaves as per Linux pthread_self(), +#endif +#ifdef __NetBSD__ + "%s", //NetBSD has 3 parms for pthread_setname_np + (void *) /*cast away const for NetBSD*/ #endif threadsName_.substr(0, 15).c_str()); } From 350483ae7ffe5c74cf38eb39fefcd485eceef171 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:29:13 -0700 Subject: [PATCH 18/31] Address Lack of TCP_NOPUSH/TCP_CORK in NetBSD Since TCP_NOPUSH/TCP_CORK don't exist in NetBSD, we use TCP_NODELAY, with it's sense inverted, instead. ("Inverted" in the sense that, if TCP_NOPUSH would be on, we set TCP_NODELAY off, and vice versa). --- src/common/transport.cc | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/common/transport.cc b/src/common/transport.cc index 3fa4a8336..1278b57b0 100644 --- a/src/common/transport.cc +++ b/src/common/transport.cc @@ -550,13 +550,26 @@ namespace Pistache::Tcp { int tcp_no_push = 0; socklen_t len = sizeof(tcp_no_push); - int sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, + int sock_opt_res = -1; + +#ifdef __NetBSD__ + { // encapsulate + int tcp_nodelay = 0; + sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, + TCP_NODELAY, &tcp_nodelay, &len); + if (sock_opt_res == 0) + tcp_no_push = !tcp_nodelay; + } +#else + sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, #if defined __APPLE__ || defined _IS_BSD - TCP_NOPUSH, + TCP_NOPUSH, #else - TCP_CORK, + TCP_CORK, #endif - &tcp_no_push, &len); + &tcp_no_push, &len); +#endif // of ifdef __NetBSD__ ... else + if (sock_opt_res == 0) { if (((tcp_no_push == 0) && (msg_more_style)) || ((tcp_no_push != 0) && (!msg_more_style))) @@ -564,14 +577,23 @@ namespace Pistache::Tcp PS_LOG_DEBUG_ARGS("Setting MSG_MORE style to %s", (msg_more_style) ? "on" : "off"); + int optval = +#ifdef __NetBSD__ + msg_more_style ? 0 : 1; +#else + msg_more_style ? 1 : 0; +#endif + tcp_no_push = msg_more_style ? 1 : 0; sock_opt_res = setsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, -#if defined __APPLE__ || defined _IS_BSD +#ifdef __NetBSD__ + TCP_NODELAY, +#elif defined __APPLE__ || defined _IS_BSD TCP_NOPUSH, #else TCP_CORK, #endif - &tcp_no_push, len); + &optval, len); if (sock_opt_res < 0) throw std::runtime_error("setsockopt failed"); } @@ -583,7 +605,6 @@ namespace Pistache::Tcp } #endif } -#ifdef DEBUG else { PS_LOG_DEBUG_ARGS("getsockopt failed for fd %p, actual fd %d, " @@ -591,7 +612,6 @@ namespace Pistache::Tcp fd, GET_ACTUAL_FD(fd), errno, strerror(errno)); throw std::runtime_error("getsockopt failed"); } -#endif } #endif // of ifdef _USE_LIBEVENT_LIKE_APPLE From ec07cf1e306b76de1de353ceb9604234e8744790 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:32:29 -0700 Subject: [PATCH 19/31] Add Debug Logging for ReuseAddr Case --- src/server/listener.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/server/listener.cc b/src/server/listener.cc index 3e0a06dcc..a5bc57cdc 100644 --- a/src/server/listener.cc +++ b/src/server/listener.cc @@ -202,12 +202,15 @@ namespace Pistache::Tcp if (options.hasFlag(Options::ReuseAddr)) { + PS_LOG_DEBUG("Set SO_REUSEADDR"); + int one = 1; TRY(::setsockopt(actualFd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))); } if (options.hasFlag(Options::ReusePort)) { + PS_LOG_DEBUG("Set SO_REUSEPORT"); int one = 1; TRY(::setsockopt(actualFd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))); } From ac3ce3f632298226c46f49ff45fb2af546c14cc2 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:33:47 -0700 Subject: [PATCH 20/31] When Binding a Free Port Use an IPv4 Address By Default In listener_test.cc - in Linux and macOS, using AF_UNSPEC leads us to use IPv4 when available. However, in NetBSD, it causes us to use IPv6 when available. Since Pistache itself defaults to IPv4, we try IPv4 first for bind_free_port_helper, and only try AF_UNSPEC if IPv4 fails. --- tests/listener_test.cc | 63 +++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/tests/listener_test.cc b/tests/listener_test.cc index 142a6ca16..706bc37df 100644 --- a/tests/listener_test.cc +++ b/tests/listener_test.cc @@ -82,48 +82,57 @@ class DummyHandler : public Pistache::Http::Handler /* * Will try to get a free port by binding port 0. */ -SocketWrapper bind_free_port() +SocketWrapper bind_free_port_helper(int ai_family) { PS_TIMEDBG_START; - int sockfd; // listen on sock_fd, new connection on new_fd + int sockfd = -1; // listen on sock_fd, new connection on new_fd struct addrinfo hints = {}, *servinfo, *p; int yes = 1; int rv; - hints.ai_family = AF_UNSPEC; + hints.ai_family = ai_family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(nullptr, "0", &hints, &servinfo)) != 0) { - std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n"; - exit(1); + if (ai_family == AF_UNSPEC) + { + std::cerr << "getaddrinfo: " << gai_strerror(rv) << "\n"; + exit(1); + } + throw std::runtime_error("getaddrinfo fail"); } - // loop through all the results and bind to the first we can for (p = servinfo; p != nullptr; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { PS_LOG_DEBUG("server: socket"); - perror("server: socket"); + if (ai_family == AF_UNSPEC) + perror("server: socket"); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { PS_LOG_DEBUG("setsockopt"); - perror("setsockopt"); - exit(1); + if (ai_family == AF_UNSPEC) + { + perror("setsockopt"); + exit(1); + } + throw std::runtime_error("setsockopt fail"); } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { PS_LOG_DEBUG_ARGS("server: bind failed, sockfd %d", sockfd); close(sockfd); - perror("server: bind"); + if (ai_family == AF_UNSPEC) + perror("server: bind"); continue; } @@ -132,14 +141,42 @@ SocketWrapper bind_free_port() freeaddrinfo(servinfo); // all done with this structure - if (p == nullptr) + if (ai_family == AF_UNSPEC) { - fprintf(stderr, "server: failed to bind\n"); - exit(1); + if (p == nullptr) + { + fprintf(stderr, "server: failed to bind\n"); + exit(1); + } + throw std::runtime_error("failed to bind"); } + return SocketWrapper(sockfd); } +/* + * Will try to get a free port by binding port 0. + */ +SocketWrapper bind_free_port() +{ + // As of July/2024, in Linux and macOS, using AF_UNSPEC leads us to use + // IPv4 when available. However, in FreeBSD, it causes us to use IPv6 when + // available. Since Pistache itself defaults to IPv4, we try IPv4 first for + // bind_free_port_helper, and only try AF_UNSPEC if IPv4 fails. + + try + { + return(bind_free_port_helper(AF_INET/*IPv4*/)); + } + catch(...) + { + PS_LOG_DEBUG("bind_free_port_helper failed for IPv4"); + } + + return(bind_free_port_helper(AF_UNSPEC/*any*/)); +} + + // This is just done to get the value of a free port. The socket will be // closed after the closing curly bracket and the port will be free again // (SO_REUSEADDR option). In theory, it is possible that some application grab From 0884fb797ed9af13c4c482d003f55a6137d04974 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:36:15 -0700 Subject: [PATCH 21/31] Increase Test Timeouts In http_server_test.cc - many_client_with_requests_to_multithreaded_server - extended the timeoutsfor the benefit of NetBSD in debug mode (writing to syslog, i.e. debug output, seems to slow things down more in NetBSD). --- tests/http_server_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/http_server_test.cc b/tests/http_server_test.cc index 9b5170622..bbfb984c7 100644 --- a/tests/http_server_test.cc +++ b/tests/http_server_test.cc @@ -476,7 +476,7 @@ TEST(http_server_test, many_client_with_requests_to_multithreaded_server) LOGGER("test", "Server address: " << server_address); const int NO_TIMEOUT = 0; - const int SECONDS_TIMOUT = 12; + const int SECONDS_TIMOUT = 20; const int FIRST_CLIENT_REQUEST_SIZE = 128; std::future result1(std::async(clientLogicFunc, FIRST_CLIENT_REQUEST_SIZE, server_address, @@ -484,7 +484,7 @@ TEST(http_server_test, many_client_with_requests_to_multithreaded_server) const int SECOND_CLIENT_REQUEST_SIZE = 192; std::future result2( std::async(clientLogicFunc, SECOND_CLIENT_REQUEST_SIZE, server_address, - NO_TIMEOUT, 2 * SECONDS_TIMOUT)); + NO_TIMEOUT, 3 * SECONDS_TIMOUT)); int res1 = result1.get(); int res2 = result2.get(); From 078170dbb6b8b768e139c1deabc99025269fa05d Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 22 Jul 2024 18:39:18 -0700 Subject: [PATCH 22/31] Check for Hostname as Synonym for localhost In rest_server_test.cc, the local hostname may be returned as a synonym for "localhost" in NetBSD. Coping with that case. --- tests/rest_server_test.cc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/rest_server_test.cc b/tests/rest_server_test.cc index 4958b525a..1cdc67bd6 100644 --- a/tests/rest_server_test.cc +++ b/tests/rest_server_test.cc @@ -110,10 +110,24 @@ TEST(rest_server_test, basic_test) { ASSERT_EQ(res->body, "ip6-localhost"); // count the passing test. } - else + else if (res->body == "localhost") { ASSERT_EQ(res->body, "localhost"); } + else + { + const unsigned int my_max_hostname_len = 1024; + + // NetBSD showed this case, when hostname was not "localhost" + char name[my_max_hostname_len + 6]; + name[0] = 0; + + int ghn_res = gethostname(&(name[0]), my_max_hostname_len+2); + ASSERT_EQ(ghn_res, 0); + + ASSERT_EQ(res->body, &(name[0])); + } + stats.shutdown(); } From 46d3be1649eba3da0cba7574f20b75f4c53ab264 Mon Sep 17 00:00:00 2001 From: DMG Date: Wed, 24 Jul 2024 15:20:29 -0700 Subject: [PATCH 23/31] Include Execinfo Library For OpenBSD This library is required for some debugging log output in *BSD --- meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 00e61ffd1..c90e44b06 100644 --- a/meson.build +++ b/meson.build @@ -135,8 +135,7 @@ if host_machine.system() == 'darwin' or host_machine.system() == 'freebsd' or ho deps_libpistache += dependency('libevent_pthreads') endif -if host_machine.system() == 'freebsd' or host_machine.system() == 'netbsd' - # Does not appear to be necessary for OpenBSD +if host_machine.system() == 'freebsd' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' libexecinfo_dep = compiler.find_library('execinfo') deps_libpistache += libexecinfo_dep endif From c62e46d1b44360d3a5eccfab8d0536dbeb76cbfa Mon Sep 17 00:00:00 2001 From: DMG Date: Wed, 24 Jul 2024 15:42:53 -0700 Subject: [PATCH 24/31] Protect dispatchPeer and toWrite Queue If Opening Connection Closes Previously, for OpenBSD there was an intermittent issue with Listener::dispatchPeer (which setups a new peer for a new connection) when the client managed to close the connection before dispatchPeer had finished executing. This was causing a throw for peer->fd(), the actual-fd (derived from fd) being used an index into the set of peers, since the peer's fd was empty due to the close. In the changed code, we allow peer-fd() to return an empty fd without a throw, but also use the transport::toWriteLock to guard against the close messing up write attempts and/or new-connection dispatch attempts. Specific changes: peer.h/peer.c: Provide an actualFd() method for peer which can be used when the caller just wants the actual-fd and doesn't need to know the intermediate "fd" value (which the caller would have been previously fetching just to then call getActualFd). Allows us to protect "fd" from getting closed while that actualFd() method is executing. listener.cc: Uses peer->actualFd() as described above. transport.h/transport.cc: Add closeFd(Fd) method to transport.cc. peer.cc then uses this to close the Fd within peer::closeFd(). This allows the transport code to clean its toWrite queue upon the Fd closing. transport.cc: The "clean up buffers" for toWrite is removed from the face of Transport::removePeer, now done in closeFd(Fd). There are also a few places where we check for an Fd being empty, and some comments added pointing out where Fd is now allowed to be empty, where before the empty Fd would have been prevented by a throw. --- include/pistache/peer.h | 3 +- include/pistache/transport.h | 13 ++-- src/common/http.cc | 2 +- src/common/peer.cc | 48 ++++++++++---- src/common/transport.cc | 122 ++++++++++++++++++++++------------- src/server/listener.cc | 33 +++++++++- version.txt | 2 +- 7 files changed, 158 insertions(+), 65 deletions(-) diff --git a/include/pistache/peer.h b/include/pistache/peer.h index 936748d2e..477999bb7 100644 --- a/include/pistache/peer.h +++ b/include/pistache/peer.h @@ -52,7 +52,8 @@ namespace Pistache::Tcp const Address& address() const; const std::string& hostname(); - Fd fd() const; + Fd fd() const; // can return PS_FD_EMPTY + int actualFd() const; // can return -1 void closeFd(); diff --git a/include/pistache/transport.h b/include/pistache/transport.h index 887ae970b..a26009651 100644 --- a/include/pistache/transport.h +++ b/include/pistache/transport.h @@ -12,10 +12,10 @@ #pragma once -#include -#include #include #include +#include +#include #include #include @@ -59,8 +59,11 @@ namespace Pistache::Tcp #endif ) { - // Always enqueue reponses for sending. Giving preference to consumer - // context means chunked responses could be sent out of order. + // Always enqueue reponses for sending. Giving preference to + // consumer context means chunked responses could be sent out of + // order. + // + // Note: fd could be PS_FD_EMPTY return Async::Promise( [=](Async::Deferred deferred) mutable { BufferHolder holder { buffer }; @@ -110,6 +113,8 @@ namespace Pistache::Tcp } #endif + void closeFd(Fd fd); + // !!!! Make protected like removePeer void removeAllPeers(); // cleans up toWrite and does CLOSE_FD on each diff --git a/src/common/http.cc b/src/common/http.cc index dbafafe25..d4293605f 100644 --- a/src/common/http.cc +++ b/src/common/http.cc @@ -1180,7 +1180,7 @@ namespace Pistache::Http auto* transport = writer.transport_; auto peer = writer.peer(); - auto sockFd = peer->fd(); + auto sockFd = peer->fd(); // may be PS_FD_EMPTY auto buffer = buf->buffer(); return transport->asyncWrite(sockFd, buffer, diff --git a/src/common/peer.cc b/src/common/peer.cc index 51002ea5e..82b0c2e2d 100644 --- a/src/common/peer.cc +++ b/src/common/peer.cc @@ -19,8 +19,8 @@ #include #include -#include #include +#include namespace Pistache::Tcp { @@ -40,15 +40,13 @@ namespace Pistache::Tcp , ssl_(ssl) , id_(getUniqueId()) { - PS_LOG_DEBUG_ARGS("peer %p, fd %" PIST_QUOTE(PS_FD_PRNTFCD) - ", Address ptr %p, ssl %p", + PS_LOG_DEBUG_ARGS("peer %p, fd %" PIST_QUOTE(PS_FD_PRNTFCD) ", Address ptr %p, ssl %p", this, fd, &addr, ssl); } Peer::~Peer() { - PS_LOG_DEBUG_ARGS("peer %p, fd %" PIST_QUOTE(PS_FD_PRNTFCD) - ", Address ptr %p, ssl %p", + PS_LOG_DEBUG_ARGS("peer %p, fd %" PIST_QUOTE(PS_FD_PRNTFCD) ", Address ptr %p, ssl %p", this, fd_, &addr, ssl_); closeFd(); // does nothing if already closed @@ -117,24 +115,52 @@ namespace Pistache::Tcp Fd Peer::fd() const { - if (fd_ == PS_FD_EMPTY) + Fd res_fd(fd_); + + if (res_fd == PS_FD_EMPTY) + { + PS_LOG_DEBUG_ARGS("peer %p has no associated fd", this); + return (PS_FD_EMPTY); + } + + return res_fd; + } + + int Peer::actualFd() const // can return -1 + { + Fd this_fd(fd_); + + if (this_fd == PS_FD_EMPTY) { PS_LOG_DEBUG_ARGS("peer %p has no associated fd", this); - throw std::runtime_error("The peer has no associated fd"); + return (-1); } - return fd_; + return (GET_ACTUAL_FD(this_fd)); } void Peer::closeFd() { + PS_LOG_DEBUG_ARGS("peer %p, fd %" PIST_QUOTE(PS_FD_PRNTFCD), this, fd_); - - if (fd_ != PS_FD_EMPTY) + + auto this_fd = fd_; + + if (this_fd != PS_FD_EMPTY) { - CLOSE_FD(fd_); fd_ = PS_FD_EMPTY; + + if (transport_) + { + // Getting transport to do the close allows transport to clean + // up any transport usage of the Fd, e.g. in the write queue + transport_->closeFd(this_fd); + } + else + { + CLOSE_FD(this_fd); + } } } diff --git a/src/common/transport.cc b/src/common/transport.cc index 1278b57b0..e0f4564b6 100644 --- a/src/common/transport.cc +++ b/src/common/transport.cc @@ -127,11 +127,16 @@ namespace Pistache::Tcp { handlePeer(peer); } + + Guard guard(toWriteLock); Fd fd = peer->fd(); + if (fd == PS_FD_EMPTY) { - Guard guard(toWriteLock); - toWrite.emplace(fd, std::deque {}); + PS_LOG_DEBUG("Empty Fd"); + return; } + + toWrite.emplace(fd, std::deque {}); } #ifdef DEBUG @@ -269,10 +274,21 @@ namespace Pistache::Tcp void Transport::handleIncoming(const std::shared_ptr& peer) { + if (!peer) + { + PS_LOG_DEBUG("Null peer"); + return; + } + char buffer[Const::MaxBuffer] = { 0 }; ssize_t totalBytes = 0; - int fdactual = GET_ACTUAL_FD(peer->fd()); + int fdactual = peer->actualFd(); + if (fdactual < 0) + { + PS_LOG_DEBUG_ARGS("Peer %p has no actual Fd", peer.get()); + return; + } for (;;) { @@ -341,7 +357,11 @@ namespace Pistache::Tcp void Transport::removePeer(const std::shared_ptr& peer) { Fd fd = peer->fd(); - + if (fd == PS_FD_EMPTY) + { + PS_LOG_DEBUG("Empty Fd"); + return; + } { // See comment in transport.h on why peers_ must be mutex-protected std::lock_guard l_guard(peers_mutex_); @@ -357,12 +377,6 @@ namespace Pistache::Tcp } } - { - // Clean up buffers - Guard guard(toWriteLock); - toWrite.erase(fd); - } - // Don't rely on close deleting this FD from the epoll "interest" list. // This is needed in case the FD has been shared with another process. // Sharing should no longer happen by accident as SOCK_CLOEXEC is now set on @@ -376,10 +390,24 @@ namespace Pistache::Tcp peer->closeFd(); } + void Transport::closeFd(Fd fd) + { + if (fd == PS_FD_EMPTY) + { + PS_LOG_DEBUG("Trying to close empty Fd"); + return; + } + + Guard guard(toWriteLock); + toWrite.erase(fd); // Clean up write buffers + + CLOSE_FD(fd); + } + void Transport::removeAllPeers() { PS_TIMEDBG_START_THIS; - + for (;;) { std::shared_ptr peer; @@ -399,7 +427,7 @@ namespace Pistache::Tcp } } - removePeer(peer);// removePeer locks mutex, erases peer from peers_ + removePeer(peer); // removePeer locks mutex, erases peer from peers_ } } @@ -554,9 +582,9 @@ namespace Pistache::Tcp #ifdef __NetBSD__ { // encapsulate - int tcp_nodelay = 0; - sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, - TCP_NODELAY, &tcp_nodelay, &len); + int tcp_nodelay = 0; + sock_opt_res = getsockopt(GET_ACTUAL_FD(fd), tcp_prot_num_, + TCP_NODELAY, &tcp_nodelay, &len); if (sock_opt_res == 0) tcp_no_push = !tcp_nodelay; } @@ -569,7 +597,7 @@ namespace Pistache::Tcp #endif &tcp_no_push, &len); #endif // of ifdef __NetBSD__ ... else - + if (sock_opt_res == 0) { if (((tcp_no_push == 0) && (msg_more_style)) || ((tcp_no_push != 0) && (!msg_more_style))) @@ -680,16 +708,16 @@ namespace Pistache::Tcp // https://www.man7.org/linux/man-pages/man2/sendfile.2.html // Copies FROM "in_fd" TO "out_fd" // Returns number of bytes written on success, -1 with errno set on error - // + // // If offset is not NULL, then sendfile() does not modify the file offset // of in_fd; otherwise the file offset is adjusted to reflect the number of // bytes read from in_fd. - ssize_t my_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) + ssize_t my_sendfile(int out_fd, int in_fd, off_t* offset, size_t count) { - char buff[65536+16]; + char buff[65536 + 16]; - int read_errors = 0; - int write_errors = 0; + int read_errors = 0; + int write_errors = 0; ssize_t bytes_written_res = 0; off_t in_fd_start_pos = -1; @@ -700,32 +728,30 @@ namespace Pistache::Tcp if (in_fd_start_pos < 0) { PS_LOG_DEBUG("lseek error"); - return(in_fd_start_pos); + return (in_fd_start_pos); } - if (lseek(in_fd, *offset, SEEK_SET) < 0) { PS_LOG_DEBUG("lseek error"); - return(-1); + return (-1); } } - for(;;) + for (;;) { - size_t bytes_to_read = count ? - std::min(sizeof(buff)-16, count) : (sizeof(buff)-16); - + size_t bytes_to_read = count ? std::min(sizeof(buff) - 16, count) : (sizeof(buff) - 16); + ssize_t bytes_read = read(in_fd, &(buff[0]), bytes_to_read); if (bytes_read == 0) // End of file break; - + if (bytes_read < 0) { if ((errno == EINTR) || (errno == EAGAIN)) { PS_LOG_DEBUG("read-interrupted error"); - + read_errors++; if (read_errors < 256) continue; @@ -740,10 +766,10 @@ namespace Pistache::Tcp read_errors = 0; bool re_adjust_pos = false; - + if ((count) && (bytes_read > ((ssize_t)count))) { - bytes_read = ((ssize_t)count); + bytes_read = ((ssize_t)count); re_adjust_pos = true; } @@ -760,11 +786,10 @@ namespace Pistache::Tcp ssize_t bytes_written = write(out_fd, p, bytes_read); if (bytes_written <= 0) { - if ((bytes_written == 0) || (errno == EINTR) || - (errno == EAGAIN)) + if ((bytes_written == 0) || (errno == EINTR) || (errno == EAGAIN)) { PS_LOG_DEBUG("write-interrupted error"); - + write_errors++; if (write_errors < 256) continue; @@ -777,7 +802,7 @@ namespace Pistache::Tcp break; } write_errors = 0; - + bytes_read -= bytes_written; p += bytes_written; bytes_written_res += bytes_written; @@ -789,16 +814,15 @@ namespace Pistache::Tcp // if offset non null, set in_fd file pos to pos from start of this // function - if ((offset) && (bytes_written_res >= 0) && - (lseek(in_fd, in_fd_start_pos, SEEK_SET) < 0)) + if ((offset) && (bytes_written_res >= 0) && (lseek(in_fd, in_fd_start_pos, SEEK_SET) < 0)) { PS_LOG_DEBUG("lseek error"); bytes_written_res = -1; } - return(bytes_written_res); + return (bytes_written_res); } - + #endif // ifdef _IS_BSD ssize_t Transport::sendFile(Fd fd, int file, off_t offset, size_t len) @@ -836,7 +860,7 @@ namespace Pistache::Tcp if (it_second_ssl_is_null) { #ifdef DEBUG - const char * sendfile_fn_name = + const char* sendfile_fn_name = #ifdef _IS_BSD "my_sendfile"; #else @@ -846,9 +870,8 @@ namespace Pistache::Tcp #endif /* PISTACHE_USE_SSL */ PS_LOG_DEBUG_ARGS( - "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) - " actual-fd %d, file fd %d, len %d", sendfile_fn_name, - fd, GET_ACTUAL_FD(fd), file, len); + "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) " actual-fd %d, file fd %d, len %d", sendfile_fn_name, + fd, GET_ACTUAL_FD(fd), file, len); #ifdef _USE_LIBEVENT_LIKE_APPLE // !!!! Should we do configureMsgMoreStyle for SSL as well? And @@ -885,9 +908,9 @@ namespace Pistache::Tcp #else #ifdef _IS_BSD - bytesWritten = my_sendfile(GET_ACTUAL_FD(fd), file, &offset, len); + bytesWritten = my_sendfile(GET_ACTUAL_FD(fd), file, &offset, len); #else - bytesWritten = ::sendfile(GET_ACTUAL_FD(fd), file, &offset, len); + bytesWritten = ::sendfile(GET_ACTUAL_FD(fd), file, &offset, len); #endif #endif @@ -1002,6 +1025,8 @@ namespace Pistache::Tcp break; auto fd = write->peerFd; + if (fd == PS_FD_EMPTY) + continue; if (!isPeerFd(fd)) continue; @@ -1052,6 +1077,11 @@ namespace Pistache::Tcp PS_TIMEDBG_START_THIS; Fd fd = peer->fd(); + if (fd == PS_FD_EMPTY) + { + PS_LOG_DEBUG("Empty Fd"); + return; + } { // See comment in transport.h on why peers_ must be mutex-protected diff --git a/src/server/listener.cc b/src/server/listener.cc index a5bc57cdc..410c79af9 100644 --- a/src/server/listener.cc +++ b/src/server/listener.cc @@ -878,8 +878,39 @@ namespace Pistache::Tcp { PS_TIMEDBG_START_THIS; + if (!peer) + { + PS_LOG_DEBUG("Null peer"); + return; + } + + // There is some risk that the Fd belonging to the peer could be closed + // in another thread before this dispatchPeer routine completes. In + // particular, that has been seen to happen occasionally in + // rest_server_test.response_status_code_test in OpenBSD. + // + // To guard against that, we simply need to check for an invalid Fd. We + // also check for an invalid actual-fd for safety's sake. + + int actual_fd = -1; + try + { + actual_fd = peer->actualFd(); + } + catch (...) + { + PS_LOG_INFO_ARGS("Failed to get actual fd from peer %p", + peer.get()); + return; + } + if (actual_fd == -1) + { + PS_LOG_INFO_ARGS("No actual fd for peer %p", peer.get()); + return; + } + auto handlers = reactor_->handlers(transportKey); - auto idx = (GET_ACTUAL_FD(peer->fd())) % handlers.size(); + auto idx = actual_fd % handlers.size(); auto transport = std::static_pointer_cast(handlers[idx]); transport->handleNewPeer(peer); diff --git a/version.txt b/version.txt index 198aaa4da..b4aaa9407 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.1.20240722 +0.4.1.20240724 From 7f5e338e1a32546357abff3006e2ef2f1b4f4380 Mon Sep 17 00:00:00 2001 From: DMG Date: Wed, 24 Jul 2024 18:53:06 -0700 Subject: [PATCH 25/31] Adding Basic Build Instructions for *BSD --- ...g on BSD - FreeBSD, OpenBSD and NetBSD.txt | 138 ++++++++++++++++++ version.txt | 2 +- 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 Building on BSD - FreeBSD, OpenBSD and NetBSD.txt diff --git a/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt new file mode 100644 index 000000000..1780b530b --- /dev/null +++ b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt @@ -0,0 +1,138 @@ +# SPDX-FileCopyrightText: 2024 Duncan Greatwood +# +# SPDX-License-Identifier: Apache-2.0 + +Making Pistache on *BSD +======================= + +Pistache has been built and tested on FreeBSD, OpenBSD and NetBSD. As +of July-2024, the versions used for testing were FreeBSD 13.3, +OpenBSD 7.3 and NetBSD 10.0. + +You will need to configure BSD with a working compiler. + +We would recommend that you also have python installed, including pip +(use "python -m ensure-pip" if needed, and add the directory where pip +is installed to your path). Plus, we recommend installing sudo, if not +preinstalled. + +You will need the following Pistache-dependencies installed: + git (and cofigure as needed) + llvm + meson + doxygen + googletest + openssl + rapidjson + howard-hinnant-date + libevent + See BSD-type-specific notes below regarding installing these + dependencies. + +Convenience shell scripts are provided to make the build. Once +dependencies are installed, at the terminal, to build do: + bldscripts/mesbuild.sh +To test: + bldscripts/mestest.sh +To install: + bldscripts/mesinstall.sh + + +FreeBSD +======= + +Typically, required packages are installed using: + sudo pkg install +For instance: + sudo pkg install meson +Do this for each Pistache dependency. + +There is no howard-hinnant-date package for FreeBSD, but it is +straightforward to install manually: + git clone https://github.com/HowardHinnant/date.git + + sudo mkdir /usr/local/include/date + + sudo cp -p date/include/date/date.h /usr/local/include/date/. + + + +OpenBSD +======= + +Typically, required packages are installed using: + sudo pkg_add +For instance: + sudo pkg_add meson +Do this for each Pistache dependency. + +There is no googletest package for OpenBSD, so please install it +manually: + git clone https://github.com/google/googletest.git + + cd googletest + + mkdir build + + cd build + + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. + + make + + sudo make install + + +There is no rapidjson package on OpenBSD, so please install it +manually: + git clone https://github.com/Tencent/rapidjson/ + + cd rapidjson/ + + mkdir build + + cd build + + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. + + make + + sudo make install + + + +NetBSD +====== +Typically, required packages are installed using: + sudo pkg_in install +For instance: + sudo pkg_in install meson +Do this for each Pistache dependency. + +There is no howard-hinnant-date package for FreeBSD, but it is +straightforward to install manually: + git clone https://github.com/HowardHinnant/date.git + + sudo mkdir /usr/local/include/date + + sudo cp -p date/include/date/date.h /usr/local/include/date/. + + +Regarding NetBSD 9.4. NetBSD 9.4 uses gcc 7.5.0, while Pistache's +build files require C++17 support, and Pistache's code uses +std::filesystem. However, gcc 7.5.0 does not work correctly with +std::filesystem when C++17 is specified. Accordingly, we have tested +with NetBSD 10.0, not 9.4. Nonetheless, it is possible that Pistache +could be made to work on NetBSD 9.* with a different compiler or +different compiler version. + +Regarding the test net_test.invalid_address, it may be slow to execute +(about 2 minutes) in NetBSD. The cause is a long time out for the +system function getaddrinfo; it doesn't appear to an issue in +Pistache. + + +How It Works +============ +Pistache on BSD works very much as it does on macOS, i.e. by using the +libevent library to provide the core event loop. diff --git a/version.txt b/version.txt index b4aaa9407..954abd089 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.1.20240724 +0.4.1.20240725 From c5c41503dad3982ad7d88f3115f2ef5a1faa01b2 Mon Sep 17 00:00:00 2001 From: DMG Date: Thu, 25 Jul 2024 12:07:07 -0700 Subject: [PATCH 26/31] Remove Some Spurious Newlines from BSD Build Instructions --- ...g on BSD - FreeBSD, OpenBSD and NetBSD.txt | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt index 1780b530b..50878f6bc 100644 --- a/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt +++ b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt @@ -50,13 +50,10 @@ Do this for each Pistache dependency. There is no howard-hinnant-date package for FreeBSD, but it is straightforward to install manually: git clone https://github.com/HowardHinnant/date.git - sudo mkdir /usr/local/include/date - sudo cp -p date/include/date/date.h /usr/local/include/date/. - OpenBSD ======= @@ -69,38 +66,24 @@ Do this for each Pistache dependency. There is no googletest package for OpenBSD, so please install it manually: git clone https://github.com/google/googletest.git - cd googletest - mkdir build - cd build - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. - make - sudo make install - There is no rapidjson package on OpenBSD, so please install it manually: git clone https://github.com/Tencent/rapidjson/ - cd rapidjson/ - mkdir build - cd build - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. - make - sudo make install - NetBSD ====== Typically, required packages are installed using: @@ -112,12 +95,9 @@ Do this for each Pistache dependency. There is no howard-hinnant-date package for FreeBSD, but it is straightforward to install manually: git clone https://github.com/HowardHinnant/date.git - sudo mkdir /usr/local/include/date - sudo cp -p date/include/date/date.h /usr/local/include/date/. - Regarding NetBSD 9.4. NetBSD 9.4 uses gcc 7.5.0, while Pistache's build files require C++17 support, and Pistache's code uses std::filesystem. However, gcc 7.5.0 does not work correctly with From 353e3857f0868eaebcfcff3857f69eb8f3223b69 Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 26 Jul 2024 16:40:33 -0700 Subject: [PATCH 27/31] Updating Fork's Master Branch --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f9e52323c..edbb57898 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.3.1.20240626 +0.3.1.20240726 From b6793d530459229d75c7067b6c112369e3b973bc Mon Sep 17 00:00:00 2001 From: DMG Date: Fri, 26 Jul 2024 17:10:40 -0700 Subject: [PATCH 28/31] Fix Debug-output Compile Issue in non-SSL Case --- src/common/transport.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/transport.cc b/src/common/transport.cc index e0f4564b6..7839e8b3f 100644 --- a/src/common/transport.cc +++ b/src/common/transport.cc @@ -859,6 +859,8 @@ namespace Pistache::Tcp if (it_second_ssl_is_null) { +#endif /* PISTACHE_USE_SSL */ + #ifdef DEBUG const char* sendfile_fn_name = #ifdef _IS_BSD @@ -867,8 +869,6 @@ namespace Pistache::Tcp "::sendfile"; #endif #endif - -#endif /* PISTACHE_USE_SSL */ PS_LOG_DEBUG_ARGS( "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) " actual-fd %d, file fd %d, len %d", sendfile_fn_name, fd, GET_ACTUAL_FD(fd), file, len); From 5bdd374404191e85c55e93e62c88ec9e8fb728e3 Mon Sep 17 00:00:00 2001 From: DMG Date: Mon, 29 Jul 2024 13:19:05 -0700 Subject: [PATCH 29/31] Updates in Reponse to Tachi107's Comments of July-27-2024 Specific Changes: Building on BSD - FreeBSD, OpenBSD and NetBSD.txt: Correct typo; move manual system-level install instructions of libraries Pistache in any case supplies as subprojects to the end of the file, and make it clear such system-level installs are optional; reflect use of "doas" in OpenBSD. emosandlibevdefs.h: Add comment explaining name meson.build: Use "endswith('bsd')" instead of listing out individual BSDs. include/pistache/meson.build: Use tabs consistently pist_timelog.h: Move strlcpy/strncpy/strcpy handling defines out of the middle of functions where they're used, to improve code readability. Same for strcat. http_defs.cc: Correct comment explaining the use of the string "GMT". transport.cc: - Added comment explaining that TCP_NODELAY has an effect similar to the opposite of TCP_CORK/TCP_NOPUSH. - Added comment explaining buffer sizes in my_sendfile - Created SENDFILE define to abstract the difference between ::sendfile and my_sendfile fdutils.cc: Use getrlimit instead of getdtablesize. Removed tab. Ran clang-format. --- ...g on BSD - FreeBSD, OpenBSD and NetBSD.txt | 91 ++++++++++--------- include/pistache/emosandlibevdefs.h | 2 + include/pistache/meson.build | 10 +- include/pistache/pist_timelog.h | 32 +++---- meson.build | 7 +- src/common/http_defs.cc | 20 ++-- src/common/transport.cc | 27 +++--- tests/helpers/fd_utils.cc | 42 ++++++--- 8 files changed, 136 insertions(+), 95 deletions(-) diff --git a/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt index 50878f6bc..f6643b122 100644 --- a/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt +++ b/Building on BSD - FreeBSD, OpenBSD and NetBSD.txt @@ -17,14 +17,14 @@ is installed to your path). Plus, we recommend installing sudo, if not preinstalled. You will need the following Pistache-dependencies installed: - git (and cofigure as needed) + git (and configure as needed) llvm meson doxygen - googletest + googletest (*) openssl - rapidjson - howard-hinnant-date + rapidjson (*) + howard-hinnant-date (*) libevent See BSD-type-specific notes below regarding installing these dependencies. @@ -45,43 +45,21 @@ Typically, required packages are installed using: sudo pkg install For instance: sudo pkg install meson -Do this for each Pistache dependency. - -There is no howard-hinnant-date package for FreeBSD, but it is -straightforward to install manually: - git clone https://github.com/HowardHinnant/date.git - sudo mkdir /usr/local/include/date - sudo cp -p date/include/date/date.h /usr/local/include/date/. +Do this for each Pistache dependency, excluding howard-hinnant-date. OpenBSD ======= Typically, required packages are installed using: - sudo pkg_add + doas pkg_add For instance: - sudo pkg_add meson -Do this for each Pistache dependency. - -There is no googletest package for OpenBSD, so please install it -manually: - git clone https://github.com/google/googletest.git - cd googletest - mkdir build - cd build - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. - make - sudo make install - -There is no rapidjson package on OpenBSD, so please install it -manually: - git clone https://github.com/Tencent/rapidjson/ - cd rapidjson/ - mkdir build - cd build - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. - make - sudo make install + doas pkg_add meson +Do this for each Pistache dependency, excluding googletest and +rapidjson. +(Note: You may use sudo instead of doas if you have installed the sudo +package and configured sudo; however, doas is often preferred on +OpenBSD.) NetBSD @@ -90,13 +68,7 @@ Typically, required packages are installed using: sudo pkg_in install For instance: sudo pkg_in install meson -Do this for each Pistache dependency. - -There is no howard-hinnant-date package for FreeBSD, but it is -straightforward to install manually: - git clone https://github.com/HowardHinnant/date.git - sudo mkdir /usr/local/include/date - sudo cp -p date/include/date/date.h /usr/local/include/date/. +Do this for each Pistache dependency, excluding howard-hinnant-date. Regarding NetBSD 9.4. NetBSD 9.4 uses gcc 7.5.0, while Pistache's build files require C++17 support, and Pistache's code uses @@ -112,6 +84,43 @@ system function getaddrinfo; it doesn't appear to an issue in Pistache. +(*) Googletest, Rapidjson and Howard-hinnant-date Packages +========================================================== + +These packages are provided as Pistache subprojects, and so do not +have to be installed seperately on the BSD system. Also, note that +there is no howard-hinnant-date package supplied as part of the OS by +FreeBSD 13 nor by NetBSD 10; and no googletest or rapidjson packages +supplied by OpenBSD 7. Nonetheless, if you would like to install +googletest, rapidjson and/or howard-hinnant-date manually on the BSD +system, please proceed as follows: + +Googletest: + git clone https://github.com/google/googletest.git + cd googletest + mkdir build + cd build + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. + make + sudo make install + +Rapidjson: + git clone https://github.com/Tencent/rapidjson/ + cd rapidjson/ + mkdir build + cd build + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. + make + sudo make install + +Howard-hinnant-date: + git clone https://github.com/HowardHinnant/date.git + sudo mkdir /usr/local/include/date + sudo cp -p date/include/date/date.h /usr/local/include/date/. + +(Note: Typically, use doas instead of sudo on OpenBSD). + + How It Works ============ Pistache on BSD works very much as it does on macOS, i.e. by using the diff --git a/include/pistache/emosandlibevdefs.h b/include/pistache/emosandlibevdefs.h index 5cb8baf6a..be5f2ce5a 100644 --- a/include/pistache/emosandlibevdefs.h +++ b/include/pistache/emosandlibevdefs.h @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +// EventMeth Operating System and libevent defines + // Defines, or does not define, _USE_LIBEVENT, _USE_LIBEVENT_LIKE_APPLE and // _IS_BSD // diff --git a/include/pistache/meson.build b/include/pistache/meson.build index 1c654ef93..7331070e5 100644 --- a/include/pistache/meson.build +++ b/include/pistache/meson.build @@ -12,9 +12,9 @@ install_headers( 'config.h', 'cookie.h', 'description.h', - 'emosandlibevdefs.h', + 'emosandlibevdefs.h', 'endpoint.h', - 'eventmeth.h', + 'eventmeth.h', 'errors.h', 'flags.h', 'http_defs.h', @@ -31,10 +31,10 @@ install_headers( 'os.h', 'peer.h', 'pist_quote.h', - 'pist_check.h', - 'pist_syslog.h', + 'pist_check.h', + 'pist_syslog.h', 'prototype.h', - 'pist_timelog.h', + 'pist_timelog.h', 'reactor.h', 'route_bind.h', 'router.h', diff --git a/include/pistache/pist_timelog.h b/include/pistache/pist_timelog.h index ae759c925..71a98ce60 100644 --- a/include/pistache/pist_timelog.h +++ b/include/pistache/pist_timelog.h @@ -33,6 +33,20 @@ #include // For _IS_BSD #include +#ifdef _IS_BSD +#define PS_STRLCPY(__dest, __src, __n) strlcpy(__dest, __src, __n) +#define PS_STRLCAT(__dest, __src, __size) strlcat(__dest, __src, __size) +#elif defined(__linux__) +#define PS_STRLCPY(__dest, __src, __n) strncpy(__dest, __src, __n) +#define PS_STRLCAT(__dest, __src, __size) strncat(__dest, __src, __size) +#elif defined(__APPLE__) +#define PS_STRLCPY(__dest, __src, __n) strlcpy(__dest, __src, __n) +#define PS_STRLCAT(__dest, __src, __size) strlcat(__dest, __src, __size) +#else +#define PS_STRLCPY(__dest, __src, __n) strcpy(__dest, __src) +#define PS_STRLCAT(__dest, __src, __size) strcat(__dest, __src) +#endif + #ifdef DEBUG #define PS_TIMINGS_DBG 1 #endif @@ -153,13 +167,7 @@ class __PS_TIMEDBG { for(unsigned int i=0; i<10; i++) marker_chars[i] = the_marker; - #ifdef _IS_BSD - strlcpy(&(marker_chars[10]), "...", 4); - #elif defined(__linux__) - strncpy(&(marker_chars[10]), "...", 4); - #else - strcpy(&(marker_chars[10]), "..."); - #endif + PS_STRLCPY(&(marker_chars[10]), "...", 4); marker_chars += (10 + 3); for(unsigned int i=0; i<10; i++) @@ -234,15 +242,7 @@ class __PS_TIMEDBG va_end(ap); if (ln >= ((int) sizeof_buf)) - { - #ifdef _IS_BSD - strlcat(buf_ptr, "...", 5); - #elif defined(__linux__) - strncat(buf_ptr, "...", 5); - #else - strcat(buf_ptr, "..."); - #endif - } + PS_STRLCAT(buf_ptr, "...", 5); return(buf_ptr); } diff --git a/meson.build b/meson.build index c90e44b06..913ee1fc5 100644 --- a/meson.build +++ b/meson.build @@ -19,7 +19,7 @@ project( #macOS host_machine.system() is 'darwin' -if host_machine.system() != 'linux' and host_machine.system() != 'darwin' and host_machine.system() != 'freebsd' and host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' +if host_machine.system() != 'linux' and host_machine.system() != 'darwin' and not host_machine.system().endswith('bsd') error('Pistache currenly only supports Linux, macOS and Free/Open/NetBSD. See https://github.com/pistacheio/pistache/issues/6#issuecomment-242398225 for more information') endif @@ -130,12 +130,13 @@ if get_option('PISTACHE_USE_SSL') deps_libpistache += dependency('openssl') endif -if host_machine.system() == 'darwin' or host_machine.system() == 'freebsd' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' or get_option('PISTACHE_FORCE_LIBEVENT') +if host_machine.system() == 'darwin' or host_machine.system().endswith('bsd') or get_option('PISTACHE_FORCE_LIBEVENT') deps_libpistache += dependency('libevent') deps_libpistache += dependency('libevent_pthreads') endif -if host_machine.system() == 'freebsd' or host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' +if host_machine.system().endswith('bsd') + # libexecinfo is included for the 'backtrace' function libexecinfo_dep = compiler.find_library('execinfo') deps_libpistache += libexecinfo_dep endif diff --git a/src/common/http_defs.cc b/src/common/http_defs.cc index 138f5e8dc..42668b528 100644 --- a/src/common/http_defs.cc +++ b/src/common/http_defs.cc @@ -132,13 +132,19 @@ namespace Pistache::Http // Requires GMT so we must use std::gmtime to convert to GMT time_t t = std::chrono::system_clock::to_time_t(date_); - // July/2024. For a std::tm* that comes from std::gmtime, - // std::put_time %Z should always outout the std::tm locale namely - // "GMT" (or "UTC"). However, in NetBSD 10.0, std::put_time appears - // to output the locale of the machine it's running on ("PST") not - // the locale of the std::tm*. We workaround as per the following - // #defines. Since we know the locale of std::gmtime is GMT, the - // workaround is correct in general. + // July/2024. For a std::tm* that comes from std::gmtime, we have + // this: https://en.cppreference.com/w/cpp/chrono/c/gmtime + // which has an example very similar to our code here, and states: + // BSD, GNU and musl C library support two additional members + // [including tm_zone], which are standardized in POSIX.1 2024. + // Then std::put_time should rely on the tm_zone std::tm field. + // + // However, in NetBSD 10.0 (or its version of gcc - nb3 20231008, + // 10.5.0), it appears that this tm_zone capability is not (fully) + // implemented, and so std::put_time instead outputs the local + // machine's timezone for "%Z". We work around that as + // follows. Since we know the locale of std::gmtime is always GMT, + // the workaround is correct in general. os << std::put_time(std::gmtime(&t), "%a, %d %b %Y %T " #ifdef __NetBSD__ "GMT" diff --git a/src/common/transport.cc b/src/common/transport.cc index e0f4564b6..cd3ddbbb4 100644 --- a/src/common/transport.cc +++ b/src/common/transport.cc @@ -607,6 +607,12 @@ namespace Pistache::Tcp int optval = #ifdef __NetBSD__ + // In NetBSD case we're getting/setting (or resetting) the + // TCP_NODELAY socket option, which _stops_ data being held + // prior to send, whereas in Linux, macOS, FreeBSD or + // OpenBSD we're using TCP_CORK/TCP_NOPUSH which may + // _cause_ data to be held prior to send. I.e. they're + // opposites. msg_more_style ? 0 : 1; #else msg_more_style ? 1 : 0; @@ -714,7 +720,10 @@ namespace Pistache::Tcp // bytes read from in_fd. ssize_t my_sendfile(int out_fd, int in_fd, off_t* offset, size_t count) { - char buff[65536 + 16]; + char buff[65536 + 16]; // 64KB is an efficient size for read/write + // blocks in most storage systems. The 16 bytes + // is to reduce risk of buffer overflow in the + // events of a bug. int read_errors = 0; int write_errors = 0; @@ -823,6 +832,9 @@ namespace Pistache::Tcp return (bytes_written_res); } +#define SENDFILE my_sendfile +#else +#define SENDFILE ::sendfile #endif // ifdef _IS_BSD ssize_t Transport::sendFile(Fd fd, int file, off_t offset, size_t len) @@ -860,12 +872,7 @@ namespace Pistache::Tcp if (it_second_ssl_is_null) { #ifdef DEBUG - const char* sendfile_fn_name = -#ifdef _IS_BSD - "my_sendfile"; -#else - "::sendfile"; -#endif + const char* sendfile_fn_name = PIST_QUOTE(SENDFILE); #endif #endif /* PISTACHE_USE_SSL */ @@ -907,11 +914,7 @@ namespace Pistache::Tcp } #else -#ifdef _IS_BSD - bytesWritten = my_sendfile(GET_ACTUAL_FD(fd), file, &offset, len); -#else - bytesWritten = ::sendfile(GET_ACTUAL_FD(fd), file, &offset, len); -#endif + bytesWritten = SENDFILE(GET_ACTUAL_FD(fd), file, &offset, len); #endif PS_LOG_DEBUG_ARGS( diff --git a/tests/helpers/fd_utils.cc b/tests/helpers/fd_utils.cc index c2854f757..c8b700f59 100644 --- a/tests/helpers/fd_utils.cc +++ b/tests/helpers/fd_utils.cc @@ -31,10 +31,16 @@ namespace filesystem = std::experimental::filesystem; // // Return: if buffer non-null, number of proc_fdinfo written, -1 on fail -#elif ! defined __linux__ -#include // for sysconf and getdtablesize -#endif +#elif !defined __linux__ +#include // for sysconf +// For getrlimit +#include // Required in FreeBSD+Open+NetBSD +#include // recommended in FreeBSD, optional for Open+NetBSD +#include // recommended in FreeBSD, optional for Open+NetBSD + +#include // for memset +#endif namespace Pistache { @@ -83,28 +89,42 @@ namespace Pistache directory_iterator {}); #else // fallback case, e.g. *BSD #ifndef OPEN_MAX -#define OPEN_MAX 4096 +#define OPEN_MAX 4096 #endif + // Be careful with portability here. rl.rlim_cur, of type rlim_t, seems + // to be an int on FreeBSD, but a wider data type on OpenBSD ("long + // long" ?). It is signed on FreeBSD and NetBSD, but unsigned on + // OpenBSD. long maxfd; - maxfd = sysconf(_SC_OPEN_MAX); + maxfd = sysconf(_SC_OPEN_MAX); if (maxfd < 0) // or if sysconf not defined at all - maxfd = getdtablesize(); + { + struct rlimit rl; + memset(&rl, 0, sizeof(rl)); + int getrlimit_res = getrlimit(RLIMIT_NOFILE, &rl); + if (getrlimit_res == 0) + { + maxfd = (long)(rl.rlim_cur < 2 * OPEN_MAX) ? rl.rlim_cur : 2 * OPEN_MAX; + if (maxfd == 0) + maxfd = -1; + } + } - if ((maxfd < 0) || (maxfd > 4*OPEN_MAX)) + if ((maxfd < 0) || (maxfd > 4 * OPEN_MAX)) maxfd = OPEN_MAX; - int j, n = 0; - for(j = 0; j < maxfd; j++) + long j, n = 0; + for (j = 0; j < maxfd; j++) { - int fd = dup(j); + int fd = dup((int)j); if (fd < 0) continue; n++; close(fd); } - return(n); + return (n); #endif // of ifdef... elif... else... __APPLE__ } From 879ad611bff1ed9c65bdba58dd717da092869628 Mon Sep 17 00:00:00 2001 From: DMG Date: Sun, 4 Aug 2024 17:28:09 -0700 Subject: [PATCH 30/31] Merge With Upstream --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 827d79ecc..8ef806eb2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.4.1.20240729 +0.4.1.20240804 From c11365f665cda44ce7a59120b12aa68fd9f3ef56 Mon Sep 17 00:00:00 2001 From: DMG Date: Sun, 4 Aug 2024 17:50:29 -0700 Subject: [PATCH 31/31] Reverted examples/meson.build to the version in master The use of deps_libpistache here, rather than just pistache_dep, is no longer needed thanks to fix #1225 (https://github.com/pistacheio/pistache/pull/1225). --- examples/meson.build | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index cfafb201e..8ed5e45bc 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -14,12 +14,6 @@ pistache_example_files = [ threads_dep = dependency('threads') -# In OpenBSD, rapidjson header fles are installed in -# /usr/local/include, not in /usr/include. Consequently, we need -# deps_libpistache in our dependencies, not just pistache_dep -# -# In particular, for rapidjson/prettywriter.h in rest_description.cc - foreach example_name : pistache_example_files - executable('run'+example_name, example_name+'.cc', dependencies: [pistache_dep, threads_dep, deps_libpistache]) + executable('run'+example_name, example_name+'.cc', dependencies: [pistache_dep, threads_dep]) endforeach