Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BSD Support (FreeBSD, OpenBSD and NetBSD) #1221

Merged
merged 36 commits into from
Aug 16, 2024

Conversation

dgreatwood
Copy link
Contributor

Extends the previous macOS support to cover FreeBSD, OpenBSD NetBSD

There are 4 substantive changes:

  • commit c62e46d
    Fix a race condition if the client closes the connection before server-side dispatchPeer function has completed. Small change, but needed for reliable behaviour in this scenario.
  • commit 350483a
    Address Lack of TCP_NOPUSH/TCP_CORK in NetBSD
  • commit 8e816a6
    Proceed when client ::connect(...) returns success (old client code assumed ::connect would return -1). 
  • commit 83a8425
    Added a my_sendfile function for use by BSD (BSD not having sendfile)

Other changes are tiny, dealing with small compiler-syntax or OS-API-syntax differences and build file needs.

The new file "Building on BSD - FreeBSD, OpenBSD and NetBSD.txt" gives brief instructions on how to build.

Comments welcome, of course.
Thanks!

dgreatwood and others added 29 commits July 12, 2024 12:42
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.
For OpenBSD, FreeBSD and NetBSD. Tried solely on OpenBSD so far.
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.
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.
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 <event2/thread.h>, which had been removed
from eventmeth.h (event2/thread.h being the thread header file for
libevent).
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.
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.
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.
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).
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.
Needed for NetBSD when using libevent. actualFdU64Value too complex
for constexpr.
gcc gives warning when compiling in NetBSD otherwise
Using #defines to cope with the different definition NetBSD has of
pthread_setname_np (different to Linux macOS and to other BSDs).
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).
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.
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).
In rest_server_test.cc, the local hostname may be returned as a
synonym for "localhost" in NetBSD. Coping with that case.
This library is required for some debugging log output in *BSD
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.
@kiplingw kiplingw self-requested a review July 27, 2024 00:02
@kiplingw
Copy link
Member

Hey @dgreatwood. Great work. There's some issues popping up in CI. In particular, on Debian stable (linuxflibev):

[21/83] Compiling C++ object src/libpistache.so.0.4.1.p/common_transport.cc.o
FAILED: src/libpistache.so.0.4.1.p/common_transport.cc.o 
g++ -Isrc/libpistache.so.0.4.1.p -Isrc -I../src -Iinclude -I../include -I/usr/include -fdiagnostics-color=always -fsanitize=address -fno-omit-frame-pointer --coverage -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -std=c++17 -O0 -g -Wconversion -Wno-sign-conversion -Wno-missing-field-initializers -fstack-protector-all --param=ssp-buffer-size=4 -DDEBUG=1 -DPISTACHE_FORCE_LIBEVENT -fPIC -DHAS_STRING_VIEW=1 -DONLY_C_LOCALE=1 -pthread -DPISTACHE_USE_CONTENT_ENCODING_DEFLATE -MD -MQ src/libpistache.so.0.4.1.p/common_transport.cc.o -MF src/libpistache.so.0.4.1.p/common_transport.cc.o.d -o src/libpistache.so.0.4.1.p/common_transport.cc.o -c ../src/common/transport.cc
In file included from ../include/pistache/pist_check.h:19,
                 from ../include/pistache/common.h:25,
                 from ../include/pistache/eventmeth.h:173,
                 from ../src/common/transport.cc:14:
../src/common/transport.cc: In member function 'ssize_t Pistache::Tcp::Transport::sendFile(Pistache::Fd, int, off_t, size_t)':
../src/common/transport.cc:873:90: error: 'sendfile_fn_name' was not declared in this scope
  873 |                 "%s fd %" PIST_QUOTE(PS_FD_PRNTFCD) " actual-fd %d, file fd %d, len %d", sendfile_fn_name,
      |                                                                                          ^~~~~~~~~~~~~~~~
../include/pistache/pist_syslog.h:62:20: note: in definition of macro 'PS_LOG_DEBUG_ARGS'
   62 |             __fmt, __VA_ARGS__)
      |                    ^~~~~~~~~~~

@dgreatwood
Copy link
Contributor Author

dgreatwood commented Jul 27, 2024 via email

@kiplingw
Copy link
Member

@dennisjenkins75, this is something we're going to need your help on reviewing when you have time because you know much more about the BSD family of OSes than I do.

Copy link
Member

@Tachi107 Tachi107 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Duncan, wow! You're back again with yet another Pistache port! What are you going to push next, Windows support? ;)

Anyway, I've left some comments below. And please, let's try to keep the Git history clean this time :)

Building on BSD - FreeBSD, OpenBSD and NetBSD.txt Outdated Show resolved Hide resolved
Building on BSD - FreeBSD, OpenBSD and NetBSD.txt Outdated Show resolved Hide resolved
Building on BSD - FreeBSD, OpenBSD and NetBSD.txt Outdated Show resolved Hide resolved
Building on BSD - FreeBSD, OpenBSD and NetBSD.txt Outdated Show resolved Hide resolved
examples/meson.build Outdated Show resolved Hide resolved
tests/helpers/fd_utils.cc Outdated Show resolved Hide resolved
tests/listener_test.cc Show resolved Hide resolved
tests/rest_server_test.cc Show resolved Hide resolved
include/pistache/pist_timelog.h Outdated Show resolved Hide resolved
include/pistache/pist_timelog.h Outdated Show resolved Hide resolved
@kiplingw
Copy link
Member

kiplingw commented Jul 29, 2024 via email

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.
@dgreatwood dgreatwood dismissed Tachi107’s stale review July 30, 2024 00:55

Addressed in the push earlier this pm

@kiplingw kiplingw merged commit 975b0a2 into pistacheio:master Aug 16, 2024
58 of 60 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants