spiped-1.6.3/000755 001751 001751 00000000000 14745266145 014457 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/README.md000644 001751 001751 00000007056 13561473171 015740 0ustar00cpercivacperciva000000 000000 spiped ====== Official signed releases are published at: > https://www.tarsnap.com/spiped.html **`spiped`** (pronounced "ess-pipe-dee") is a utility for creating symmetrically encrypted and authenticated pipes between socket addresses, so that one may connect to one address (e.g., a UNIX socket on localhost) and transparently have a connection established to another address (e.g., a UNIX socket on a different system). This is similar to `ssh -L` functionality, but does not use SSH and requires a pre-shared symmetric key. **`spipe`** (pronounced "ess-pipe") is a utility which acts as an spiped protocol client (i.e., connects to an spiped daemon), taking input from the standard input and writing data read back to the standard output. Note that spiped: 1. Requires a strong key file: The file specified via the `-k` option should have at least 256 bits of entropy. (`dd if=/dev/urandom bs=32 count=1` is your friend.) 2. Requires strong entropy from `/dev/urandom`. (Make sure your kernel's random number generator is seeded at boot time!) 3. Does not provide any protection against information leakage via packet timing: Running telnet over spiped will protect a password from being directly read from the network, but will not obscure the typing rhythm. 4. Can significantly increase bandwidth usage for interactive sessions: It sends data in packets of 1024 bytes, and pads smaller messages up to this length, so a 1 byte write could be expanded to 1024 bytes if it cannot be coalesced with adjacent bytes. 5. Uses a symmetric key -- so anyone who can connect to an spiped "server" is also able to impersonate it. Example usage ------------- Examples of spiped protecting SMTP and SSH are given on: > https://www.tarsnap.com/spiped.html For a detailed list of the command-line options to spiped and spipe, see the man pages. Security requirements --------------------- The user is responsible for ensuring that: 1. The key file contains 256 or more bits of entropy. 2. The same key file is not used for more than 2^64 connections. 3. Any individual connection does not transmit more than 2^64 bytes. Building -------- The official releases should build and install on almost any POSIX-compliant operating system, using the included Makefiles: make BINDIR=/path/to/target/directory install See the [BUILDING](BUILDING) file for more details (e.g. how to install man pages). Testing ------- A small test suite can be run with: make test Memory-testing with valgrind (takes approximately twice as long as without valgrind) can be enabled with: make test USE_VALGRIND=1 Code layout ----------- ``` spiped/* -- Code specific to the spiped utility. main.c -- Command-line parsing, initialization, and event loop. dispatch.c -- Accepts connections and hands them off to protocol code. spipe/* -- Code specific to the spipe utility. main.c -- Command-line parsing, initialization, and event loop. pushbits.c -- Copies data between standard input/output and a socket. proto/* -- Implements the spiped protocol. _conn.c -- Manages the lifecycle of a connection. _handshake.c -- Performs the handshaking portion of the protocol. _pipe.c -- Performs the data-shuttling portion of the protocol. _crypt.c -- Does the cryptographic bits needed by _handshake and _pipe. lib/dnsthread -- Spawns a thread for background DNS (re)resolution. libcperciva/* -- Library code from libcperciva ``` More info --------- For more details about spiped, read the [DESIGN.md](DESIGN.md) file. spiped-1.6.3/CHANGELOG000644 001751 001751 00000006411 14745205620 015662 0ustar00cpercivacperciva000000 000000 spiped-1.6.3 * Add -b (spiped and spipe) to bind the outgoing address. spiped-1.6.2 * Warn if the maximum number of connections is reached in spiped. * Add --syslog (spiped) to send warnings to syslog when daemonized. * Significantly improve performance of AES-CTR and SHA256 on amd64 and aarch64. * Add ability to suppress POSIX runtime checks during compilation to simplify cross-compiling. spiped-1.6.1 * New option -u username:groupname (spiped): change the user and/or group ownership of the process. * Use RDRAND as an additional source of entropy on CPUs which support it. * Use SHANI instructions on CPUs which support them. * Warn about failed connections and exit with non-zero status (spipe). spiped-1.6.0 * The -n option (spiped) is no longer limited to a maximum limit of 500 simultaneous connections. * The -k option now accepts "-" as a synonym for standard input. * New option -v (spipe/spiped): Print version number. * Add workaround for docker signal-handling bug in spiped. * Perform a graceful shutdown on SIGTERM. spiped-1.5.0 * Attempt to set the TCP_NODELAY socket option on connections, in order to avoid punishing latencies from TCP nagling. spiped-1.4.2 * Fix crash on platforms which support AESNI (i386, amd64) but do not automatically provide 16-byte alignment to large memory allocations (glibc, possibly others). spiped-1.4.1 * Fix build on OS X, and improve strict POSIX compliance. * Improved zeroing of sensitive cryptographic data. spiped-1.4.0 * Add automatic detection of compiler support (at compile-time) and CPU support (at run-time) for x86 "AES New Instructions"; and when available, use these to improve cryptographic performance. * Add support for -g option, which makes {spiped, spipe} require perfect forward secrecy by dropping connections if the peer endpoint is detected to be running using the -f option. spiped-1.3.1 * Fix build by adding missing #include. * Minor code cleanups. spiped-1.3.0 * Bug fix: spiped now correctly closes connections which have been reset; in earlier versions spiped could erroneously hold "dead" connections open as long as they remained idle. * Man pages added. * Protocol-layer keep-alives are now enabled by default. * New option -j (spipe/spiped): Disable protocol-layer keep-alives. * In spiped the target address is now re-resolved every 60 seconds by default. * New option -R (spiped): Do not re-resolve target address. * New option -r (spiped): Re-resolve target address every seconds. spiped-1.2.2 * Build fixes for some strictly POSIX-conforming platforms. * Detect and work around compilers which are POSIX-noncompliant in their handling of -rt and -lxnet options. * Minor documentation and typo fixes. spiped-1.2.1 * Fix build by adding missing #include. spiped-1.2.0 * New utility "spipe": A client for the spiped protocol, handling a single connection with standard input/output as one end. * Code rearrangement with no functional consequences. * Minor bug and documentation fixes. spiped-1.1.0 * New option -D: Wait until DNS lookups succeed. * New option -F: Don't daemonize. * Use SO_REUSEADDR to avoid 'socket address already in use' error (most importantly, if spiped is killed and restarted). * Minor bug and style fixes. spiped-1.0.0 * Initial release spiped-1.6.3/tests/000755 001751 001751 00000000000 14743020337 015606 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/liball/000755 001751 001751 00000000000 14743020337 015703 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/COPYRIGHT000644 001751 001751 00000003407 14745205620 015745 0ustar00cpercivacperciva000000 000000 The code in the "libcperciva/external" directory is distributed under the terms specified in each file. The included code and documentation ("spiped") is distributed under the following terms: Copyright 2005-2025 Colin Percival. All rights reserved. Copyright 2011-2025 Tarsnap Backup Inc. All rights reserved. Copyright 2014 Sean Kelly. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. In addition to the above, some files are: Copyright 2012 Andreas Olsson Copyright 2016 Tim Duesterhus and distributed under the same terms. Such files contain individual copyright statements and licenses. spiped-1.6.3/STYLE000644 001751 001751 00000015575 14650270210 015276 0ustar00cpercivacperciva000000 000000 Code style ========== In general, FreeBSD style(9) should be followed unless it is irrelevant (e.g., $FreeBSD$ tags). Functions with external linkage are declared like this: /** * module_func(arg1, arg2): * Description of what the function does, referring to arguments as * ${arg1} or suchlike. */ int module_func(void *, int); The identical comment appears in the C file where the function is defined. Static functions may have the above form of comment, or simply a /* Brief description of what the function does. */ line before the function. "Unrewrappable" comments starting in the first column should be /** * Written like this. * * Because (some of) the line-breaks are important. */ whereas when such comments are indented, they should be /*- * Written like this. * * Because (some of) the line-breaks are important. */ Line lengths should generally be 78 characters, and not more than 80 characters. In general, functions should return (int)(-1) or NULL to indicate error. Errors should be printed via warnp (if errno is relevant) or warn0 (if errno is not relevant) when they are first detected and also at higher levels where useful. As an exception to this, malloc failures (i.e., errno = ENOMEM) can result in failure being passed back up the call chain without being printed immediately. (Naturally, other errors can be passed back where a function definition so specifies; e.g., ENOENT in cases where a file not existing is not erroneous.) The first statement in main(), after variable declarations, should be "WARNP_INIT;" in order to set the program name used for printing warnings. We use %d rather than %i in printf and warn0/warnp strings. In general, functions should be structured with one return statement per status, e.g., one return() for success and one return() for failure. Errors should be handled by using goto to enter the error return path, e.g., int foo(int bar) { if (something fails) goto err0; /* ... */ if (something else fails) goto err1; /* ... */ if (yet another operation fails) goto err2; /* Success! */ return (0); err2: /* Clean up something. */ err1: /* Clean up something else. */ err0: /* Failure! */ return (-1); } As an exception to the above, if there is only one way for the function to fail, the idioms return (baz(bar)); and int rc; rc = baz(bar); /* ... cleanup code here ... */ return (rc); are allowed; furthermore, in cases such as foo_free(), the idiom if (we shouldn't do anything) return; is preferred over if (we shouldn't do anything) goto done; at the start of a function. Headers should be included in the following groups, with a blank line after each (non-empty) group: 1. , with first followed by others alphabetically. 2. , in alphabetical order. 3. <*.h>, in alphabetical order. 4. header files from /lib/, in alphabetical order. 5. header files from the program being built, in alphabetical order. 6. header files (usually just one) defining the interface for this C file. If ssize_t is needed, should be included to provide it. If size_t is needed, should be included to provide it unless , , , or is already required. If the C99 integer types (uint8_t, int64_t, etc.) are required, should be included to provide them unless is already required. The type 'char' should only be used to represent human-readable characters (input from users, output to users, pathnames, et cetera). The type 'char *' should normally be a NUL-terminated string. The types 'signed char' and 'unsigned char' should never be used; C99 integer types should be used instead. When a variable is declared to have a pointer type, there should be a space between the '*' and the variable name, e.g., int main(int argc, char * argv[]) { char * opt_p = NULL; Note that this is inconsistent with FreeBSD style(9). When used as a unary operator, '*' is not separated from its argument, e.g., while (*p != '\0') p++; When a struct is referenced, the idiom /* Opaque types. */ struct foo; struct bar * bar_from_foo(struct foo *); is preferable to #include "foo.h" /* needed for struct foo */ struct bar * bar_from_foo(struct foo *); unless there is some reason why the internal layout of struct foo is needed (e.g., if struct bar contains a struct foo rather than a struct foo *). Such struct declarations should be sorted alphabetically. The file foo.c should only export symbols of the following forms: foo_* -- most symbols should be of this form. FOO_* / BAR_FOO_* -- allowed in cases where FOO or BAR_FOO is idiomatic (e.g., MD5, HMAC_SHA256). foo() / defoo() / unfoo() -- where "foo" is a verb and this improves code clarity. Functions named foo_free should return void, and foo_free(NULL) should have no effect. The right way to spell a comment about this is /* Behave consistently with free(NULL). */ If static variables need to be initialized to 0 (or NULL) then they should be explicitly declared that way; implicit initialization should not be used. In non-trivial code, comments should be included which describe in English what is being done by the surrounding code with sufficient detail that if the code were removed, it could be replaced based on reading the comments without requiring any significant creativity. Comments and documentation should be written in en-GB-oed; i.e., with the 'u' included in words such as "honour", "colour", and "neighbour", and the ending '-ize' in words such as "organize" and "realize". The Oxford (aka. serial) comma should be used in lists. Quotation marks should be placed logically, i.e., not including punctuation marks which do not form a logical part of the quoted text. Two spaces should be used after a period which ends a sentence. The first local variable declaration in cookie-using functions should be struct foo * bar = cookie; When versions of functions are written to exploit special CPU features (using the cpusupport framework), that code should be placed into a separate file (e.g., crypto_aes_aesni.c) so that it can be compiled with different compiler flags. Such a file should start with #include "cpusupport.h" #ifdef CPUSUPPORT_FOO_BAR /** * CPUSUPPORT CFLAGS: FOO_BAR FOO_BAZ */ and end with #endif /* CPUSUPPORT_FOO_BAR */ For example, we could have #if defined(CPUSUPPORT_X86_SHANI) && defined(CPUSUPPORT_X86_SSSE3) /** * CPUSUPPORT CFLAGS: X86_SHANI X86_SSSE3 */ Functions for which special CPU-feature-exploiting variants exist should take the form { /* Variable declarations here. */ /* Asserts here, if any. */ #ifdef CPUSUPPORT_FOO_BAR if (/* We've decided we can use the variant code */) { /* Call variant code and return. */ } #endif /* Normal implementation of the function. */ } If there are multiple CPU-feature-exploiting variants, the `if` could instead be a `switch` which invokes the appropriate variant function. spiped-1.6.3/DESIGN.md000644 001751 001751 00000011520 13042745752 015744 0ustar00cpercivacperciva000000 000000 spiped design ============= Encrypted protocol ------------------ The client and server share a key file with 256 or more bits of entropy. On launch, they read the key file and compute K = SHA256(key file). When a connection is established: - C1. The client generates a 256-bit random value nonce_C and sends it. S1. The server generates a 256-bit random value nonce_S and sends it. - C2. The client receives a 256-bit value nonce_S. S2. The server receives a 256-bit value nonce_C. - C3/S3. Both parties now compute the 512-bit value dk_1 = PBKDF2-SHA256(K, nonce_C || nonce_S, 1) and parse it as a pair of 256-bit values dhmac_C || dhmac_S = dk_1. - C4. The client picks* a value x_C and computes** y_C = 2^x_C mod p, where p is the Diffie-Hellman "group #14" modulus, and h_C = HMAC-SHA256(dhmac_C, y_C). The client sends y_C || h_C to the server. S4. The server receives a 2304-bit value which it parses as y_C || h_C, where y_C is 2048 bits and h_C is 256 bits; and drops the connection if h_C is not equal to HMAC-SHA256(dhmac_C, y_C) or y_C >= p. - S5. The server picks\* a value x_S and computes\*\* y_S = 2^x_S mod p and h_S = HMAC-SHA256(dhmac_S, y_S). The server sends y_S || h_S to the client. C5. The client receives a 2304-bit value which it parses as y_S || h_S, where y_S is 2048 bits and h_S is 256 bits; and drops the connection if h_S is not equal to HMAC-SHA256(dhmac_S, y_S) or y_S >= p. - C6. The client computes\*\* y_SC = y_S^x_C mod p. S6. The server computes\*\* y_SC = y_C^x_S mod p. (Note that these two compute values are identical.) - C7/S7. Both parties now compute the 1024-bit value dk_2 = PBKDF2-SHA256(K, nonce_C || nonce_S || y_SC, 1) and parse it as a 4-tuple of 256-bit values E_C || H_C || E_S || H_S. Thereafter, the client and server exchange 1060-byte packets P generated from plaintext messages M of 1--1024 bytes msg_padded = M || ( 0x00 x (1024 - length(M))) || bigendian32(length(M)) msg_encrypted = AES256-CTR(E, msg_padded, packet#) P = msg_encrypted || HMAC-SHA256(H, msg_encrypted || bigendian64(packet#)) where E and H are E_C and H_C or E_S and H_S depending on whether the packet is being sent by the client or the server, and AES256-CTR is computed with nonce equal to the packet #, which starts at zero and increments for each packet sent in the same direction. \* The values x_C, x_S picked must either be 0 (if perfect forward secrecy is not desired) or have 256 bits of entropy (if perfect forward secrecy is desired). \*\* The values y_C, y_S, and y_SC are 2048 bits and big-endian. Security proof -------------- 1. Under the random oracle model, K has at least 255 bits of entropy (it's a 256-bit hash computed from a value with at least 256 bits of entropy). 2. Provided that at least one party is following the protocol and the key file has been used for fewer than 2^64 connections, the probability that the tuple (K, nonce_C, nonce_S) has occurred before is less than 2^(-192). 3. Under the random oracle model, the probability of an attacker without access to K guessing either of dhmac_C and dhmac_S is less than P(attacker guesses K) + P(the tuple has been input to the oracle before) + P(the attacker directly guesses), which is less than 2^(-255) + 2^(-192) + 2^(-255) = 2^(-192) + 2^(-254). 4. Consequently, in order for an attacker to convince a protocol-obeying party that a tuple (y, h) is legitimate, the attacker must do at least 2^190 expected work (which we consider to be computationally infeasible and do not consider any further). 5. If one of the parties opts to not have perfect forward secrecy, then the value y_SC will be equal to 1 and dk_2 will have the same security properties as dk_1, i.e., it will be computationally infeasible for an attacker without access to K to compute dk_2. 6. If both parties opt for perfect forward secrecy, an attacker who can compute y_SC has solved a Diffie-Hellman problem over the 2048-bit group #14, which is (under the CDH assumption) computationally infeasible. 7. Consequently, if both parties opt for perfect forward secrecy, an attacker who obtains access to K after the handshake has completed will continue to be unable to compute dk_2 from information exchanged during the handshake. 8. Under the random oracle model, the packets P are indistinguishable from random 1060-byte packets; thus no information about the keys used or the plaintext being transmitted is revealed by post-key-exchange communications. 9. Because the values (msg_encrypted || bigendian(packet#)) are distinct for each packet, under the random oracle model it is infeasible for an attacker without access to the value H to generate a packet which will be accepted as valid. spiped-1.6.3/libcperciva/000755 001751 001751 00000000000 14650270210 016721 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/lib/000755 001751 001751 00000000000 14070374447 015221 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/BUILDING000644 001751 001751 00000006447 13723620112 015571 0ustar00cpercivacperciva000000 000000 Installing ---------- To build and install spiped, run: # make BINDIR=/path/to/target/directory install To install man pages, add MAN1DIR=/path/to/man.1/directory to the command line (e.g., MAN1DIR=/usr/local/man/man1 on FreeBSD). Spiped should build and run on any IEEE Std 1003.1 (POSIX) compliant system which 1. Includes the Software Development Utilities option, 2. Has OpenSSL available via -lcrypto and #include , and 3. Provides /dev/urandom. Platform-specific notes ----------------------- - On OS X, the version of OpenSSL included with the operating system is outdated (0.9.8) and deprecated, and it is recommended that spiped be built with an updated version of OpenSSL. On OS X 10.11 "El Capitan", OpenSSL was removed entirely. After installing a newer version of OpenSSL, use CFLAGS="-I /path/to/openssl/headers" LDADD_EXTRA="-L /path/to/openssl/lib" to build spiped. Note that spiped will still build (on pre-10.11) if you set these options wrong: If you see warning: 'AES_set_encrypt_key' is deprecated during the build then spiped is still using the outdated version of OpenSSL from OS X. - On Cygwin the following command must be run before building spiped in order order to work around a bug in Cygwin's C library: sed -i.orig s/-D_POSIX_C_SOURCE=200809L// */Makefile Without this command, spiped will still build but it will crash. - On some platforms (Solaris, maybe others), additional compiler and/or linker options are required to find OpenSSL or system libraries; these can be provided by adding e.g., CFLAGS="-I/path/to/openssl/headers" (compiler option) or LDADD_EXTRA="-L/usr/sfw/lib -lsocket -lnsl" (linker option) to the make command line. - On Solaris, the command-line utilities in /usr/bin are not necessarily POSIX-compatible. According to standards(7), in order to use POSIX.1-2008 standard-conforming utilities, you must set your PATH so that certain directories (such as /usr/xpg4/bin/) take precedence over /usr/bin. Please check the documentation in your version of Solaris by: $ man standards and carefully read the "Utilities" section. - On some platforms (OpenBSD prior to 5.4, and possibly others) you will need to add #include at the start of lib/dnsthread/dnsthread.c libcperciva/util/sock_util.c proto/proto_conn.c spipe/main.c spipe/pushbits.c due to a POSIX-compliance bug on those platforms. - On some platforms (mostly Linuxes) it is possible to install OpenSSL libraries without the associated header files; the header files are usually in packages named "openssl-devel", "libssl-dev", or similar. - If your OS provides random bytes via some mechanism other than /dev/urandom, please make local changes to lib/util/entropy.c and notify the author. If spiped fails to build or run for other reasons, please notify the author. Updating build code and releasing --------------------------------- The POSIX-compatible Makefiles are generated via `make Makefiles` from the included (far more readable) BSD Makefiles. To run this target, you will need to have a BSD `make(1)` utility; NetBSD's `make(1)` is available for many operating systems as `bmake`. Release tarballs are generated via `make VERSION=x.y.z publish`, subject to the same caveat of needing a BSD-compatible make. spiped-1.6.3/spiped/000755 001751 001751 00000000000 14745266145 015743 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/spipe/000755 001751 001751 00000000000 14745266145 015577 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/Makefile000644 001751 001751 00000007062 14650270210 016103 0ustar00cpercivacperciva000000 000000 .POSIX: PROGS= spipe \ spiped LIBS= liball \ liball/optional_mutex_normal \ liball/optional_mutex_pthread TESTS= perftests/recv-zeros \ perftests/send-zeros \ perftests/standalone-enc \ tests/dnsthread-resolve \ tests/msleep \ tests/nc-client \ tests/nc-server \ tests/pthread_create_blocking_np \ tests/pushbits \ tests/valgrind BINDIR_DEFAULT= /usr/local/bin CFLAGS_DEFAULT= -O2 LIBCPERCIVA_DIR= libcperciva TEST_CMD= tests/test_spiped.sh ### Shared code between Tarsnap projects. .PHONY: all all: toplevel export CFLAGS="$${CFLAGS:-${CFLAGS_DEFAULT}}"; \ . ./posix-flags.sh; \ . ./cpusupport-config.h; \ . ./cflags-filter.sh; \ . ./apisupport-config.h; \ export HAVE_BUILD_FLAGS=1; \ for D in ${PROGS} ${TESTS}; do \ ( cd $${D} && ${MAKE} all ) || exit 2; \ done .PHONY: toplevel toplevel: apisupport-config.h cflags-filter.sh \ cpusupport-config.h libs \ posix-flags.sh # For "loop-back" building of a subdirectory .PHONY: buildsubdir buildsubdir: toplevel export CFLAGS="$${CFLAGS:-${CFLAGS_DEFAULT}}"; \ . ./posix-flags.sh; \ . ./cpusupport-config.h; \ . ./cflags-filter.sh; \ . ./apisupport-config.h; \ export HAVE_BUILD_FLAGS=1; \ cd ${BUILD_SUBDIR} && ${MAKE} ${BUILD_TARGET} # For "loop-back" building of libraries .PHONY: libs libs: apisupport-config.h cflags-filter.sh cpusupport-config.h posix-flags.sh export CFLAGS="$${CFLAGS:-${CFLAGS_DEFAULT}}"; \ . ./posix-flags.sh; \ . ./cpusupport-config.h; \ . ./cflags-filter.sh; \ . ./apisupport-config.h; \ export HAVE_BUILD_FLAGS=1; \ for D in ${LIBS}; do \ ( cd $${D} && make all ) || exit 2; \ done posix-flags.sh: if [ -d ${LIBCPERCIVA_DIR}/POSIX/ ]; then \ export CC="${CC}"; \ cd ${LIBCPERCIVA_DIR}/POSIX; \ printf "export \"LDADD_POSIX="; \ command -p sh posix-l.sh "$$PATH"; \ printf "\"\n"; \ printf "export \"CFLAGS_POSIX="; \ command -p sh posix-cflags.sh "$$PATH"; \ printf "\"\n"; \ fi > $@ if [ ! -s $@ ]; then \ printf "#define POSIX_COMPATIBILITY_NOT_CHECKED 1\n"; \ fi >> $@ cflags-filter.sh: if [ -d ${LIBCPERCIVA_DIR}/POSIX/ ]; then \ export CC="${CC}"; \ cd ${LIBCPERCIVA_DIR}/POSIX; \ command -p sh posix-cflags-filter.sh "$$PATH"; \ fi > $@ if [ ! -s $@ ]; then \ printf "# Compiler understands normal flags; "; \ printf "nothing to filter out\n"; \ fi >> $@ apisupport-config.h: if [ -d ${LIBCPERCIVA_DIR}/apisupport/ ]; then \ export CC="${CC}"; \ command -p sh \ ${LIBCPERCIVA_DIR}/apisupport/Build/apisupport.sh \ "$$PATH"; \ else \ :; \ fi > $@ cpusupport-config.h: if [ -d ${LIBCPERCIVA_DIR}/cpusupport/ ]; then \ export CC="${CC}"; \ command -p sh \ ${LIBCPERCIVA_DIR}/cpusupport/Build/cpusupport.sh \ "$$PATH"; \ fi > $@ if [ ! -s $@ ]; then \ printf "#define CPUSUPPORT_NONE 1\n"; \ fi >> $@ .PHONY: install install: all export BINDIR=$${BINDIR:-${BINDIR_DEFAULT}}; \ for D in ${PROGS}; do \ ( cd $${D} && ${MAKE} install ) || exit 2; \ done .PHONY: clean clean: test-clean rm -f apisupport-config.h cflags-filter.sh cpusupport-config.h posix-flags.sh for D in ${LIBS} ${PROGS} ${TESTS}; do \ ( cd $${D} && ${MAKE} clean ) || exit 2; \ done .PHONY: test test: all ${TEST_CMD} .PHONY: test-clean test-clean: rm -rf tests-output/ tests-valgrind/ # Developer targets: These only work with BSD make .PHONY: Makefiles Makefiles: ${MAKE} -f Makefile.BSD Makefiles .PHONY: publish publish: ${MAKE} -f Makefile.BSD publish spiped-1.6.3/perftests/000755 001751 001751 00000000000 13762775424 016501 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/perftests/recv-zeros/000755 001751 001751 00000000000 14745266144 020574 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/perftests/standalone-enc/000755 001751 001751 00000000000 14745266144 021370 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/perftests/send-zeros/000755 001751 001751 00000000000 14745266144 020566 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/perftests/send-zeros/main.c000644 001751 001751 00000005240 14650270210 021637 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include #include "monoclock.h" #include "parsenum.h" #include "sock.h" #include "warnp.h" int main(int argc, char ** argv) { /* Command-line parameters. */ const char * addr; size_t buflen; size_t count; /* Working variables. */ struct sock_addr ** sas_t; struct timeval begin, end; double duration_s; char * buffer; int socket; size_t to_send; WARNP_INIT; /* Parse command-line arguments. */ if (argc != 4) { warn0("usage: %s ADDRESS BUFLEN COUNT", argv[0]); goto err0; } addr = argv[1]; if (PARSENUM(&buflen, argv[2], 1, SSIZE_MAX)) { warnp("parsenum"); goto err0; } if (PARSENUM(&count, argv[3], 1, SIZE_MAX)) { warnp("parsenum"); goto err0; } /* Allocate and fill buffer to send. */ if ((buffer = malloc(buflen)) == NULL) { warnp("Out of memory"); goto err0; } memset(buffer, 0, buflen); /* Initialize count. */ to_send = count; /* Resolve target address. */ if ((sas_t = sock_resolve(addr)) == NULL) { warnp("Error resolving socket address: %s", addr); goto err1; } if (sas_t[0] == NULL) { warn0("No addresses found for %s", addr); goto err2; } /* Connect to target. */ if ((socket = sock_connect(sas_t)) == -1) { warnp("sock_connect"); goto err2; } /* Make it blocking. */ if (fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) & (~O_NONBLOCK)) == -1) { warnp("Cannot make connection blocking"); goto err3; } /* Get beginning time. */ if (monoclock_get(&begin)) { warn0("monoclock_get"); goto err3; } /* Send data. */ while (to_send > 0) { if (write(socket, buffer, buflen) != (ssize_t)buflen) { warnp("write failed"); goto err3; } to_send--; } /* We're not going to send anything else. */ if (shutdown(socket, SHUT_WR)) { warnp("shutdown"); goto err3; } /* * The server should not send any data back, but attempting to read * will detect when the other end of the socket is closed. */ if (read(socket, buffer, 1) != 0) { warnp("read"); goto err3; } /* Get ending time. */ if (monoclock_get(&end)) { warn0("monoclock_get"); goto err3; } /* Print duration and speed. */ duration_s = timeval_diff(begin, end); printf("%zu\t%zu\t%.4f\t%.2f\n", buflen, count, duration_s, (double)(buflen * count) / duration_s / 1e6); /* Clean up. */ if (close(socket)) { warnp("close"); goto err2; } sock_addr_freelist(sas_t); free(buffer); /* Success! */ exit(0); err3: if (close(socket)) warnp("close"); err2: sock_addr_freelist(sas_t); err1: free(buffer); err0: /* Failure! */ exit(1); } spiped-1.6.3/perftests/send-zeros/Makefile000644 001751 001751 00000001717 14745266144 022234 0ustar00cpercivacperciva000000 000000 .POSIX: # AUTOGENERATED FILE, DO NOT EDIT PROG=send-zeros SRCS=main.c IDIRS=-I../../libcperciva/util SUBDIR_DEPTH=../.. RELATIVE_DIR=perftests/send-zeros LIBALL=../../liball/liball.a ../../liball/optional_mutex_normal/liball_optional_mutex_normal.a all: if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \ cd ${SUBDIR_DEPTH}; \ ${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \ BUILD_TARGET=${PROG} buildsubdir; \ else \ ${MAKE} ${PROG}; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${LIBALL} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ../../libcperciva/util/monoclock.h ../../libcperciva/util/parsenum.h ../../libcperciva/util/sock.h ../../libcperciva/util/warnp.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o spiped-1.6.3/perftests/standalone-enc/fd_drain.c000644 001751 001751 00000002460 14743020337 023272 0ustar00cpercivacperciva000000 000000 #include #include #include "fork_func.h" #include "warnp.h" #include "fd_drain.h" #define FD_DRAIN_MAX_SIZE 16384 /** * fd_drain_internal(fd_p): * Drain bytes from the file descriptor ${*fd_p} -- passed as an (int *) -- as * quickly as possible. */ static int fd_drain_internal(void * cookie) { int fd = *((int *)cookie); uint8_t mybuf[FD_DRAIN_MAX_SIZE]; ssize_t readlen; /* Loop until we hit EOF or an error. */ do { readlen = read(fd, mybuf, FD_DRAIN_MAX_SIZE); } while (readlen > 0); /* Check for an error. */ if (readlen == -1) { warnp("read"); goto err0; } /* Success! */ return (0); err0: /* Failure! This value will be the pid's exit code. */ return (1); } /** * fd_drain(fd): * Drain bytes from the file descriptor ${fd} as quickly as possible. */ int fd_drain(int fd) { /* Call internal function. */ return (fd_drain_internal(&fd)); } /** * fd_drain_fork(fd): * Create a new process to drain bytes from the file descriptor ${fd} until it * receives an EOF. Return the process ID of the new process, or -1 upon * error. */ pid_t fd_drain_fork(int fd) { pid_t pid; /* Fork a new process to run the function. */ if ((pid = fork_func(fd_drain_internal, &fd)) == -1) goto err0; /* Success! */ return (pid); err0: /* Failure! */ return (-1); } spiped-1.6.3/perftests/standalone-enc/main.c000644 001751 001751 00000005723 14650270210 022447 0ustar00cpercivacperciva000000 000000 #include #include #include "cpusupport.h" #include "parsenum.h" #include "warnp.h" #include "standalone.h" /* Smaller buffers are padded, so no point testing smaller values. */ static const size_t perfsizes[] = {1024}; static const size_t num_perf = sizeof(perfsizes) / sizeof(perfsizes[0]); static size_t nbytes_perftest = 100000000; /* 100 MB */ static const size_t nbytes_warmup = 10000000; /* 10 MB */ /* Print a string, then whether or not we're using hardware instructions. */ static void print_hardware(const char * str) { /* Inform the user of the general topic... */ printf("%s", str); /* ... and whether we're using hardware acceleration or not. */ #if defined(CPUSUPPORT_CONFIG_FILE) #if defined(CPUSUPPORT_X86_SHANI) && defined(CPUSUPPORT_X86_SSSE3) if (cpusupport_x86_shani() && cpusupport_x86_ssse3()) printf(" using hardware SHANI"); else #endif #if defined(CPUSUPPORT_X86_SSE2) if (cpusupport_x86_sse2()) printf(" using hardware SSE2"); else #endif #if defined(CPUSUPPORT_ARM_SHA256) if (cpusupport_arm_sha256()) printf(" using hardware SHA256"); else #endif printf(" using software SHA"); #if defined(CPUSUPPORT_X86_AESNI) if (cpusupport_x86_aesni()) printf(" and hardware AESNI.\n"); else #endif printf(" and software AES.\n"); #else printf(" with unknown hardware acceleration status.\n"); #endif /* CPUSUPPORT_CONFIG_FILE */ } int main(int argc, char * argv[]) { int desired_test; size_t multiplier; WARNP_INIT; /* Parse command line. */ if ((argc < 2) || (argc > 3)) { fprintf(stderr, "usage: test_standalone_enc NUM [MULT]\n"); exit(1); } if (PARSENUM(&desired_test, argv[1], 1, 7)) { warnp("parsenum"); goto err0; } if (argc == 3) { /* Multiply number of bytes by the user-supplied value. */ if (PARSENUM(&multiplier, argv[2], 1, 1000)) { warnp("parsenum"); goto err0; } nbytes_perftest *= multiplier; } /* Report what we're doing. */ print_hardware("Testing spiped speed limits"); /* Run the desired test. */ switch (desired_test) { case 1: if (standalone_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup)) goto err0; break; case 2: if (standalone_aesctr(perfsizes, num_perf, nbytes_perftest, nbytes_warmup)) goto err0; break; case 3: if (standalone_aesctr_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup)) goto err0; break; case 4: if (standalone_pce(perfsizes, num_perf, nbytes_perftest, nbytes_warmup)) goto err0; break; case 5: if (standalone_transfer_noencrypt(perfsizes, num_perf, nbytes_perftest, nbytes_warmup, 0)) goto err0; break; case 6: if (standalone_transfer_noencrypt(perfsizes, num_perf, nbytes_perftest, nbytes_warmup, 1)) goto err0; break; case 7: if (standalone_pipe_socketpair_one(perfsizes, num_perf, nbytes_perftest, nbytes_warmup)) goto err0; break; default: warn0("invalid test number"); goto err0; } /* Success! */ exit(0); err0: /* Failure! */ exit(1); } spiped-1.6.3/perftests/standalone-enc/standalone_pipe_socketpair_one.c000644 001751 001751 00000010234 14743020337 027754 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "events.h" #include "fork_func.h" #include "noeintr.h" #include "perftest.h" #include "proto_crypt.h" #include "proto_pipe.h" #include "warnp.h" #include "fd_drain.h" #include "standalone.h" /* Ends of socketpairs (convention, not a firm requirement). */ #define R 0 #define W 1 /* Cookie for proto_pipe */ struct pipeinfo { struct proto_keys * k; pid_t out_pid; pid_t enc_pid; int in[2]; int out[2]; int status; int done; }; static int pipe_callback_status(void * cookie) { struct pipeinfo * pipeinfo = cookie; /* Was there an error? */ if (pipeinfo->status) { warn0("proto_pipe callback status: %d", pipeinfo->status); return (-1); } /* We've finished. */ pipeinfo->done = 1; /* Success! */ return (0); } /* Encrypt bytes sent to a socket, and send them to another socket. */ static int pipe_enc(void * cookie) { struct pipeinfo * pipeinfo = cookie; void * cancel_cookie; /* Create the pipe. */ if ((cancel_cookie = proto_pipe(pipeinfo->in[R], pipeinfo->out[W], 0, pipeinfo->k, &pipeinfo->status, pipe_callback_status, pipeinfo)) == NULL) { warn0("proto_pipe"); goto err0; } /* Let events happen. */ if (events_spin(&pipeinfo->done)) warnp("events_spin"); /* Clean up the pipe. */ proto_pipe_cancel(cancel_cookie); /* Success! */ return (0); err0: /* Failure! This value will be the pid's exit code. */ return (1); } static int pipe_init(void * cookie, uint8_t * buf, size_t buflen) { struct pipeinfo * pipeinfo = cookie; uint8_t kbuf[64]; size_t i; /* Set up encryption key. */ memset(kbuf, 0, 64); if ((pipeinfo->k = mkkeypair(kbuf)) == NULL) goto err0; /* Create socket pairs for the input and output. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipeinfo->in)) { warnp("socketpair"); goto err0; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipeinfo->out)) { warnp("socketpair"); goto err0; } /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* We haven't finished the event loop. */ pipeinfo->done = 0; /* Create the pipe processes. */ if ((pipeinfo->out_pid = fd_drain_fork(pipeinfo->out[R])) == -1) goto err0; if ((pipeinfo->enc_pid = fork_func(pipe_enc, pipeinfo)) == -1) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } static int pipe_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { struct pipeinfo * pipeinfo = cookie; size_t i; /* Send bytes. */ for (i = 0; i < nreps; i++) { if (noeintr_write(pipeinfo->in[W], buf, buflen) != (ssize_t)buflen) { warnp("network_write"); goto err0; } } /* We've finished writing stuff. */ if (shutdown(pipeinfo->in[W], SHUT_WR)) { warnp("shutdown"); goto err0; } /* Wait for the processes to finish. */ if (fork_func_wait(pipeinfo->enc_pid)) goto err0; if (fork_func_wait(pipeinfo->out_pid)) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } static int pipe_cleanup(void * cookie) { struct pipeinfo * pipeinfo = cookie; /* Clean up encryption key. */ proto_crypt_free(pipeinfo->k); /* Clean up sockets. */ if (close(pipeinfo->in[W])) { warnp("close"); goto err0; } if (close(pipeinfo->in[R])) { warnp("close"); goto err0; } if (close(pipeinfo->out[W])) { warnp("close"); goto err0; } if (close(pipeinfo->out[R])) { warnp("close"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * standalone_pipe_socketpair_one(perfsizes, num_perf, nbytes_perftest, * nbytes_warmup): * Performance test for one proto_pipe() over a socketpair. */ int standalone_pipe_socketpair_one(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup) { struct pipeinfo pipeinfo_actual; /* Report what we're doing. */ printf("Testing one proto_pipe() over a socketpair\n"); /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, pipe_init, pipe_func, pipe_cleanup, &pipeinfo_actual)) { warn0("perftest_buffers"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/standalone_hmac.c000644 001751 001751 00000003022 14650270210 024631 0ustar00cpercivacperciva000000 000000 #include #include #include #include "perftest.h" #include "sha256.h" #include "sysendian.h" #include "warnp.h" #include "standalone.h" static int hmac_init(void * cookie, uint8_t * buf, size_t buflen) { HMAC_SHA256_CTX * ctx = cookie; uint8_t kbuf[32]; size_t i; /* (Re-)Initialize the context. */ memset(kbuf, 0, 32); HMAC_SHA256_Init(ctx, kbuf, 32); /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* Success! */ return (0); } static int hmac_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { HMAC_SHA256_CTX * ctx = cookie; uint8_t hbuf[32]; uint8_t pnum_exp[8]; size_t i; /* Do the hashing. */ for (i = 0; i < nreps; i++) { HMAC_SHA256_Update(ctx, buf, buflen); /* Hash the iteration number as well. */ be64enc(pnum_exp, i); HMAC_SHA256_Update(ctx, pnum_exp, 8); } HMAC_SHA256_Final(hbuf, ctx); /* Success! */ return (0); } /** * standalone_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for HMAC-SHA256. */ int standalone_hmac(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup) { HMAC_SHA256_CTX ctx; /* Report what we're doing. */ printf("Testing HMAC_SHA256 with iteration numbers\n"); /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, hmac_init, hmac_func, NULL, &ctx)) { warn0("perftest_buffers"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/standalone_pce.c000644 001751 001751 00000003226 14650270210 024476 0ustar00cpercivacperciva000000 000000 #include #include #include #include "perftest.h" #include "proto_crypt.h" #include "warnp.h" #include "standalone.h" /* Cookie for proto_crypt_enc(). */ struct pce { struct proto_keys * k; }; static int pce_init(void * cookie, uint8_t * buf, size_t buflen) { struct pce * pce = cookie; uint8_t kbuf[64]; size_t i; /* Set up encryption key. */ memset(kbuf, 0, 64); if ((pce->k = mkkeypair(kbuf)) == NULL) goto err0; /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* Success! */ return (0); err0: /* Failure! */ return (-1); } static int pce_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { struct pce * pce = cookie; uint8_t encbuf[PCRYPT_ESZ]; size_t i; /* Encrypt a bunch of times. */ for (i = 0; i < nreps; i++) proto_crypt_enc(buf, buflen, encbuf, pce->k); /* Success! */ return (0); } static int pce_cleanup(void * cookie) { struct pce * pce = cookie; /* Clean up. */ proto_crypt_free(pce->k); /* Success! */ return (0); } /** * standalone_pce(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for proto_crypt_enc(). */ int standalone_pce(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup) { struct pce pce_actual; struct pce * pce = &pce_actual; /* Report what we're doing. */ printf("Testing proto_crypt_enc()\n"); /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, pce_init, pce_func, pce_cleanup, pce)) { warn0("perftest_buffers"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/standalone.h000644 001751 001751 00000002661 14650270210 023656 0ustar00cpercivacperciva000000 000000 #ifndef STANDALONE_H_ #define STANDALONE_H_ #include /** * standalone_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for HMAC-SHA256. */ int standalone_hmac(const size_t *, size_t, size_t, size_t); /** * standalone_aesctr(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for AES-CTR. */ int standalone_aesctr(const size_t *, size_t, size_t, size_t); /** * standalone_aesctr_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for AES-CTR followed by HMAC-SHA256. */ int standalone_aesctr_hmac(const size_t *, size_t, size_t, size_t); /** * standalone_pce(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for proto_crypt_enc(). */ int standalone_pce(const size_t *, size_t, size_t, size_t); /** * standalone_transfer_noencrypt(perfsizes, num_perf, nbytes_perftest, * nbytes_warmup, method): * Performance test for sending data through two communication endpoints with * no encryption. If ${method} is 0, use two pipes; if ${method} is 1, use * two socketpairs. */ int standalone_transfer_noencrypt(const size_t *, size_t, size_t, size_t, int); /** * standalone_pipe_socketpair_one(perfsizes, num_perf, nbytes_perftest, * nbytes_warmup): * Performance test for one proto_pipe() over a socketpair. */ int standalone_pipe_socketpair_one(const size_t *, size_t, size_t, size_t); #endif /* !STANDALONE_H_ */ spiped-1.6.3/perftests/standalone-enc/standalone_aesctr.c000644 001751 001751 00000003146 14650270210 025211 0ustar00cpercivacperciva000000 000000 #include #include #include #include "crypto_aes.h" #include "crypto_aesctr.h" #include "perftest.h" #include "warnp.h" #include "standalone.h" static int aesctr_init(void * cookie, uint8_t * buf, size_t buflen) { size_t i; (void)cookie; /* UNUSED */ /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* Success! */ return (0); } static int aesctr_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { struct crypto_aes_key * k_aes = cookie; size_t i; /* Do the hashing. */ for (i = 0; i < nreps; i++) { /* * In proto_crypt_enc(), we would append the length to buf, * then encrypt the buffer + 4 bytes of length. For * simplicity, this test does not imitate that details. */ crypto_aesctr_buf(k_aes, i, buf, buf, buflen); } /* Success! */ return (0); } /** * standalone_aesctr(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for AES-CTR. */ int standalone_aesctr(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup) { struct crypto_aes_key * k_aes; uint8_t kbuf[32]; /* Report what we're doing. */ printf("Testing AES-CTR\n"); /* Initialize. */ memset(kbuf, 0, 32); if ((k_aes = crypto_aes_key_expand(kbuf, 32)) == NULL) goto err0; /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, aesctr_init, aesctr_func, NULL, k_aes)) { warn0("perftest_buffers"); goto err0; } /* Clean up. */ crypto_aes_key_free(k_aes); /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/standalone_transfer_noencrypt.c000644 001751 001751 00000013567 14743020337 027673 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include "noeintr.h" #include "perftest.h" #include "pthread_create_blocking_np.h" #include "warnp.h" #include "fd_drain.h" #include "standalone.h" /* The smallest this can be is PCRYPT_ESZ (which is 1060). */ #define MAXOUTSIZE 16384 /* Ends of pipes or sockets. */ #define W 1 #define R 0 /* Cookie for proto_pipe */ struct shared { pthread_t data_thr; pthread_t output_thr; int in[2]; int out[2]; int finished[2]; int method; }; /* Read and discard one byte from ${fd}, looping upon EINTR. */ static int readbyte(int fd) { char dummy; char done = 0; do { switch (read(fd, &dummy, 1)) { case -1: /* Anything other than EINTR is bad. */ if (errno != EINTR) { warnp("read"); goto err0; } /* Otherwise, loop and read again. */ break; case 0: warn0("Unexpected EOF in pipe"); goto err0; case 1: /* Expected value; quit the loop. */ done = 1; } } while (!done); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Transfer bytes from ->in to ->out. */ static void * transfer_data(void * cookie) { struct shared * shared = cookie; uint8_t mybuf[MAXOUTSIZE]; ssize_t readlen; /* Loop until we hit EOF. */ do { /* Get data from ->in, and break on EOF. */ if ((readlen = read(shared->in[R], mybuf, MAXOUTSIZE)) == -1) { warnp("read"); goto err0; } if (readlen == 0) break; /* Send data to ->out. */ if (noeintr_write(shared->out[W], mybuf, (size_t)readlen) != readlen) { warnp("network_write"); goto err0; } } while (1); /* When ->in received an EOF, close ->out. */ if (close(shared->out[W])) { warnp("close"); goto err0; } err0: /* Finished! */ return (NULL); } /* Drain bytes from ->out as quickly as possible. */ static void * drain_output(void * cookie) { struct shared * shared = cookie; char dummy = 0; /* Read until we get an EOF. */ if (fd_drain(shared->out[R])) goto err0; /* Notify that we've finished. */ if (noeintr_write(shared->finished[W], &dummy, 1) != 1) { warnp("network_write"); goto err0; } err0: /* Finished! */ return (NULL); } static int perftest_init(void * cookie, uint8_t * buf, size_t buflen) { struct shared * shared = cookie; size_t i; int rc; /* Sanity checks. */ assert(buflen <= MAXOUTSIZE); /* Create communication endpoints. */ if (shared->method == 0) { /* Use pipes. */ if (pipe(shared->in)) { warnp("pipe"); goto err0; } if (pipe(shared->out)) { warnp("pipe"); goto err0; } if (pipe(shared->finished)) { warnp("pipe"); goto err0; } } else if (shared->method == 1) { /* Use socketpairs. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, shared->in)) { warnp("socketpair"); goto err0; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, shared->out)) { warnp("socketpair"); goto err0; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, shared->finished)) { warnp("socketpair"); goto err0; } } else goto err0; /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* Create the threads. */ if ((rc = pthread_create_blocking_np(&shared->output_thr, NULL, drain_output, shared))) { warn0("pthread_create: %s", strerror(rc)); goto err0; } if ((rc = pthread_create_blocking_np(&shared->data_thr, NULL, transfer_data, shared))) { warn0("pthread_create: %s", strerror(rc)); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } static int perftest_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { struct shared * shared = cookie; size_t i; /* Send bytes. */ for (i = 0; i < nreps; i++) { if (noeintr_write(shared->in[W], buf, buflen) != (ssize_t)buflen) { warnp("network_write"); goto err0; } } /* We've finished sending data. */ if (close(shared->in[W])) { warnp("close"); goto err0; } /* Wait until transfer_data has finished. */ if (readbyte(shared->finished[R])) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } static int perftest_cleanup(void * cookie) { struct shared * shared = cookie; int rc; /* Wait for threads to finish. */ if ((rc = pthread_join(shared->data_thr, NULL))) { warn0("pthread_join: %s", strerror(rc)); goto err0; } if ((rc = pthread_join(shared->output_thr, NULL))) { warn0("pthread_join: %s", strerror(rc)); goto err0; } /* Clean up communication. */ if (close(shared->out[R])) { warnp("close"); goto err0; } if (close(shared->in[R])) { warnp("close"); goto err0; } if (close(shared->finished[W])) { warnp("close"); goto err0; } if (close(shared->finished[R])) { warnp("close"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * standalone_transfer_noencrypt(perfsizes, num_perf, nbytes_perftest, * nbytes_warmup, method): * Performance test for sending data through two communication endpoints with * no encryption. If ${method} is 0, use two pipes; if ${method} is 1, use * two socketpairs. */ int standalone_transfer_noencrypt(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup, int method) { struct shared shared_actual; const char * method_str; /* Report what we're doing. */ if (method == 0) method_str = "two pipes"; else if (method == 1) method_str = "two socketpairs"; else { warn0("method not recognized"); goto err0; } printf("Testing sending data over %s, no encryption\n", method_str); /* Record the communication method. */ shared_actual.method = method; /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, perftest_init, perftest_func, perftest_cleanup, &shared_actual)) { warn0("perftest_buffers"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/Makefile000644 001751 001751 00000013030 14745266144 023025 0ustar00cpercivacperciva000000 000000 .POSIX: # AUTOGENERATED FILE, DO NOT EDIT PROG=test_standalone_enc SRCS=main.c fd_drain.c standalone_aesctr.c standalone_aesctr_hmac.c standalone_hmac.c standalone_pce.c standalone_transfer_noencrypt.c standalone_pipe_socketpair_one.c proto_crypt.c IDIRS=-I../../lib/proto -I../../libcperciva/alg -I../../libcperciva/cpusupport -I../../libcperciva/crypto -I../../libcperciva/events -I../../libcperciva/util -I../../lib/util LDADD_REQ=-lcrypto -lpthread SUBDIR_DEPTH=../.. RELATIVE_DIR=perftests/standalone-enc LIBALL=../../liball/liball.a ../../liball/optional_mutex_pthread/liball_optional_mutex_pthread.a all: if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \ cd ${SUBDIR_DEPTH}; \ ${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \ BUILD_TARGET=${PROG} buildsubdir; \ else \ ${MAKE} ${PROG}; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${LIBALL} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ../../libcperciva/cpusupport/cpusupport.h ../../cpusupport-config.h ../../libcperciva/util/parsenum.h ../../libcperciva/util/warnp.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o fd_drain.o: fd_drain.c ../../libcperciva/util/fork_func.h ../../libcperciva/util/warnp.h fd_drain.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c fd_drain.c -o fd_drain.o standalone_aesctr.o: standalone_aesctr.c ../../libcperciva/crypto/crypto_aes.h ../../libcperciva/crypto/crypto_aesctr.h ../../libcperciva/util/perftest.h ../../libcperciva/util/warnp.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c standalone_aesctr.c -o standalone_aesctr.o standalone_aesctr_hmac.o: standalone_aesctr_hmac.c ../../libcperciva/crypto/crypto_aes.h ../../libcperciva/crypto/crypto_aesctr.h ../../libcperciva/util/perftest.h ../../libcperciva/alg/sha256.h ../../libcperciva/util/sysendian.h ../../libcperciva/util/warnp.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c standalone_aesctr_hmac.c -o standalone_aesctr_hmac.o standalone_hmac.o: standalone_hmac.c ../../libcperciva/util/perftest.h ../../libcperciva/alg/sha256.h ../../libcperciva/util/sysendian.h ../../libcperciva/util/warnp.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c standalone_hmac.c -o standalone_hmac.o standalone_pce.o: standalone_pce.c ../../libcperciva/util/perftest.h ../../lib/proto/proto_crypt.h ../../libcperciva/crypto/crypto_dh.h ../../libcperciva/util/warnp.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -DSTANDALONE_ENC_TESTING -c standalone_pce.c -o standalone_pce.o standalone_transfer_noencrypt.o: standalone_transfer_noencrypt.c ../../libcperciva/util/noeintr.h ../../libcperciva/util/perftest.h ../../lib/util/pthread_create_blocking_np.h ../../libcperciva/util/warnp.h fd_drain.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c standalone_transfer_noencrypt.c -o standalone_transfer_noencrypt.o standalone_pipe_socketpair_one.o: standalone_pipe_socketpair_one.c ../../libcperciva/events/events.h ../../libcperciva/util/fork_func.h ../../libcperciva/util/noeintr.h ../../libcperciva/util/perftest.h ../../lib/proto/proto_crypt.h ../../libcperciva/crypto/crypto_dh.h ../../lib/proto/proto_pipe.h ../../libcperciva/util/warnp.h fd_drain.h standalone.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -DSTANDALONE_ENC_TESTING -c standalone_pipe_socketpair_one.c -o standalone_pipe_socketpair_one.o proto_crypt.o: ../../lib/proto/proto_crypt.c ../../libcperciva/crypto/crypto_aes.h ../../libcperciva/crypto/crypto_aesctr.h ../../libcperciva/crypto/crypto_verify_bytes.h ../../libcperciva/util/insecure_memzero.h ../../libcperciva/alg/sha256.h ../../libcperciva/util/sysendian.h ../../libcperciva/util/warnp.h ../../lib/proto/proto_crypt.h ../../libcperciva/crypto/crypto_dh.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -DSTANDALONE_ENC_TESTING -c ../../lib/proto/proto_crypt.c -o proto_crypt.o perftest: @${MAKE} all > /dev/null @printf "# nblks\tbsize\ttime\tspeed\talg\n" @for N in 1 2 3 4 5 6 7; do \ ./test_standalone_enc $$N | \ grep "blocks" | \ awk -v N="$$N" \ '{printf "%d\t%d\t%.6f\t%.6f\t%d\n", \ $$1, $$5, $$6, $$8, N}'; \ done spiped-1.6.3/perftests/standalone-enc/fd_drain.h000644 001751 001751 00000000652 14743020337 023300 0ustar00cpercivacperciva000000 000000 #ifndef FD_DRAIN_H_ #define FD_DRAIN_H_ #include /** * fd_drain(fd): * Drain bytes from the file descriptor ${fd} as quickly as possible. */ int fd_drain(int); /** * fd_drain_fork(fd): * Create a new process to drain bytes from the file descriptor ${fd} until it * receives an EOF. Return the process ID of the new process, or -1 upon * error. */ pid_t fd_drain_fork(int); #endif /* !FD_DRAIN_H_ */ spiped-1.6.3/perftests/standalone-enc/standalone_aesctr_hmac.c000644 001751 001751 00000004535 14650270210 026204 0ustar00cpercivacperciva000000 000000 #include #include #include #include "crypto_aes.h" #include "crypto_aesctr.h" #include "perftest.h" #include "sha256.h" #include "sysendian.h" #include "warnp.h" #include "standalone.h" /* Cookie for HMAC_SHA256 with crypto_aesctr. */ struct aesctr_hmac_cookie { HMAC_SHA256_CTX * ctx; struct crypto_aes_key * k_aes; }; static int aesctr_hmac_init(void * cookie, uint8_t * buf, size_t buflen) { struct aesctr_hmac_cookie * ahc = cookie; uint8_t kbuf[32]; size_t i; /* (Re-)Initialize the context. */ memset(kbuf, 0, 32); HMAC_SHA256_Init(ahc->ctx, kbuf, 32); /* Set the input. */ for (i = 0; i < buflen; i++) buf[i] = (uint8_t)(i & 0xff); /* Success! */ return (0); } static int aesctr_hmac_func(void * cookie, uint8_t * buf, size_t buflen, size_t nreps) { struct aesctr_hmac_cookie * ahc = cookie; uint8_t hbuf[32]; uint8_t pnum_exp[8]; size_t i; /* Do the hashing. */ for (i = 0; i < nreps; i++) { /* * In proto_crypt_enc(), we would append the length to buf, * then encrypt the buffer + 4 bytes of length. After that, * we'd hash the resulting (larger) buffer. For simplicity, * this test does not imitate those details. */ crypto_aesctr_buf(ahc->k_aes, i, buf, buf, buflen); HMAC_SHA256_Update(ahc->ctx, buf, buflen); be64enc(pnum_exp, i); HMAC_SHA256_Update(ahc->ctx, pnum_exp, 8); } HMAC_SHA256_Final(hbuf, ahc->ctx); /* Success! */ return (0); } /** * standalone_aesctr_hmac(perfsizes, num_perf, nbytes_perftest, nbytes_warmup): * Performance test for AES-CTR followed by HMAC-SHA256. */ int standalone_aesctr_hmac(const size_t * perfsizes, size_t num_perf, size_t nbytes_perftest, size_t nbytes_warmup) { struct aesctr_hmac_cookie aesctr_hmac_cookie; struct aesctr_hmac_cookie * ahc = &aesctr_hmac_cookie; HMAC_SHA256_CTX ctx; uint8_t kbuf[32]; /* Report what we're doing. */ printf("Testing HMAC_SHA256 with AES-CTR\n"); /* Initialize. */ ahc->ctx = &ctx; memset(kbuf, 0, 32); if ((ahc->k_aes = crypto_aes_key_expand(kbuf, 32)) == NULL) goto err0; /* Time the function. */ if (perftest_buffers(nbytes_perftest, perfsizes, num_perf, nbytes_warmup, 0, aesctr_hmac_init, aesctr_hmac_func, NULL, ahc)) { warn0("perftest_buffers"); goto err0; } /* Clean up. */ crypto_aes_key_free(ahc->k_aes); /* Success! */ return (0); err0: /* Failure! */ return (1); } spiped-1.6.3/perftests/standalone-enc/freebsd_flamegraph.sh000755 001751 001751 00000003673 14650270210 025520 0ustar00cpercivacperciva000000 000000 #!/bin/sh # To see only profile data from pipe_enc_thread: # ./freebsd_flamegraph.sh # # To see all profile data: # ./freebsd_flamegraph.sh --all set -e -o noclobber -o nounset # This command must be in the same directory; it will be invoked as "./${cmd}". cmd="test_standalone_enc" args="5 10" outfilename="bench" # Sanity check: dtrace silently truncates the execname to 19 characters, which # this script does not handle. numchars="$(printf "%s" "${cmd}" | wc -c)" if [ "${numchars}" -gt "19" ]; then printf "%s is %d chars; that's too long for dtrace!\n" \ "${cmd}" "${numchars}" exit 1 fi # Should we keep all the profile data? if [ "${1:-}" = "--all" ]; then KEEP_ALL=1 else KEEP_ALL=0 fi # Set dtrace command; if we're not root, we must have doas(1) configured. uid=$(id -u) if [ "${uid}" -eq "0" ]; then DTRACE_CMD="dtrace" else DTRACE_CMD="doas /usr/sbin/dtrace" fi # Clear previous data rm -f "${outfilename}.stacks" "${outfilename}.folded" "${outfilename}.svg" rm -f "${outfilename}.tmp" # Get profile data and consolidate it. ${DTRACE_CMD} \ -x ustackframes=100 \ -n "profile-997 \ /execname == \"${cmd}\" && arg1/ \ { @[ustack()] = count(); }" \ -o "${outfilename}.stacks" \ -c "./${cmd} ${args}" stackcollapse.pl "${outfilename}.stacks" > "${outfilename}.folded" # Unless otherwise specified, only keep the pipe_enc_thread part. # If there's no pipe_enc_thread, don't do any filtering. if grep -q pipe_enc_thread "${outfilename}.folded" ; then has_pipe_enc=1 else has_pipe_enc=0 fi if [ "${KEEP_ALL}" -eq "0" ] && [ "${has_pipe_enc}" -gt "0" ]; then grep pipe_enc_thread "${outfilename}.folded" > "${outfilename}.tmp" mv "${outfilename}.tmp" "${outfilename}.folded" fi # Generate flamegraph image. flamegraph.pl \ --width 1000 \ --title "1 proto_pipe() doing encryption" \ --subtitle "(total of 3 threads in 1 process)" \ --hash \ "${outfilename}.folded" > "${outfilename}.svg" spiped-1.6.3/perftests/recv-zeros/Makefile000644 001751 001751 00000001654 14745266144 022242 0ustar00cpercivacperciva000000 000000 .POSIX: # AUTOGENERATED FILE, DO NOT EDIT PROG=recv-zeros SRCS=main.c IDIRS=-I../../libcperciva/util SUBDIR_DEPTH=../.. RELATIVE_DIR=perftests/recv-zeros LIBALL=../../liball/liball.a ../../liball/optional_mutex_normal/liball_optional_mutex_normal.a all: if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \ cd ${SUBDIR_DEPTH}; \ ${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \ BUILD_TARGET=${PROG} buildsubdir; \ else \ ${MAKE} ${PROG}; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${LIBALL} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ../../libcperciva/util/parsenum.h ../../libcperciva/util/sock.h ../../libcperciva/util/warnp.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I../.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o spiped-1.6.3/perftests/recv-zeros/main.c000644 001751 001751 00000003515 14743020337 021656 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "parsenum.h" #include "sock.h" #include "warnp.h" int main(int argc, char ** argv) { /* Command-line parameters. */ const char * addr = NULL; size_t buflen; /* Working variables. */ struct sock_addr * sa; int socket; int socket_recv; char * buffer; ssize_t r; WARNP_INIT; /* Parse command-line arguments. */ if (argc < 3) { warn0("usage: %s ADDRESS BUFLEN", argv[0]); goto err0; } addr = argv[1]; if (PARSENUM(&buflen, argv[2], 1, SSIZE_MAX)) { warnp("parsenum"); goto err0; } /* Allocate buffer. */ if ((buffer = malloc(buflen)) == NULL) { warnp("malloc"); goto err0; } /* Resolve the address. */ if ((sa = sock_resolve_one(addr, 0)) == NULL) { warn0("sock_resolve_one"); goto err1; } /* Create a socket, bind it, mark it as listening. */ if ((socket = sock_listener(sa)) == -1) { warn0("sock_listener"); goto err2; } /* Make it blocking. */ if (fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) & (~O_NONBLOCK)) == -1) { warnp("Cannot make connection blocking"); goto err3; } /* Accept a connection. */ if ((socket_recv = accept(socket, NULL, NULL)) == -1) { warnp("accept"); goto err3; } /* Receive data, but do nothing with it. */ do { r = recv(socket_recv, buffer, buflen, MSG_WAITALL); } while (r == (ssize_t)buflen); if (r == -1) { warnp("recv"); goto err4; } /* Close the connection. */ if (close(socket_recv)) { warnp("close"); goto err3; } /* Clean up. */ if (close(socket)) { warnp("close"); goto err2; } sock_addr_free(sa); free(buffer); /* Success! */ exit(0); err4: if (close(socket_recv)) warnp("close"); err3: if (close(socket)) warnp("close"); err2: sock_addr_free(sa); err1: free(buffer); err0: /* Failure! */ exit(1); } spiped-1.6.3/spipe/pushbits.h000644 001751 001751 00000000557 14650270210 017577 0ustar00cpercivacperciva000000 000000 #ifndef PUSHBITS_H_ #define PUSHBITS_H_ #include /** * pushbits(in, out, thr): * Create a thread which copies data from ${in} to ${out} and * store the thread ID in ${thr}. Wait until ${thr} has started. * If ${out} is a socket, disable writing to it after the thread * exits. */ int pushbits(int, int, pthread_t *); #endif /* !PUSHBITS_H_ */ spiped-1.6.3/spipe/Makefile000644 001751 001751 00000004142 14745266143 017236 0ustar00cpercivacperciva000000 000000 .POSIX: # AUTOGENERATED FILE, DO NOT EDIT PROG=spipe MAN1=spipe.1 SRCS=main.c pushbits.c IDIRS=-I../libcperciva/crypto -I../libcperciva/events -I../libcperciva/util -I../lib/proto -I../lib/util LDADD_REQ=-lcrypto -lpthread SUBDIR_DEPTH=.. RELATIVE_DIR=spipe LIBALL=../liball/liball.a ../liball/optional_mutex_pthread/liball_optional_mutex_pthread.a all: if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \ cd ${SUBDIR_DEPTH}; \ ${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \ BUILD_TARGET=${PROG} buildsubdir; \ else \ ${MAKE} ${PROG}; \ fi install:${PROG} mkdir -p ${BINDIR} cp ${PROG} ${BINDIR}/_inst.${PROG}.$$$$_ && \ strip ${BINDIR}/_inst.${PROG}.$$$$_ && \ chmod 0555 ${BINDIR}/_inst.${PROG}.$$$$_ && \ mv -f ${BINDIR}/_inst.${PROG}.$$$$_ ${BINDIR}/${PROG} if ! [ -z "${MAN1DIR}" ]; then \ mkdir -p ${MAN1DIR}; \ for MPAGE in ${MAN1}; do \ cp $$MPAGE ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ chmod 0444 ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ mv -f ${MAN1DIR}/_inst.$$MPAGE.$$$$_ ${MAN1DIR}/$$MPAGE; \ done; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${LIBALL} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ../libcperciva/events/events.h ../libcperciva/util/getopt.h ../lib/util/graceful_shutdown.h ../libcperciva/util/parsenum.h ../libcperciva/util/sock.h ../libcperciva/util/sock_util.h ../libcperciva/util/warnp.h ../lib/proto/proto_conn.h ../lib/proto/proto_crypt.h ../libcperciva/crypto/crypto_dh.h pushbits.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o pushbits.o: pushbits.c ../libcperciva/util/noeintr.h ../lib/util/pthread_create_blocking_np.h ../libcperciva/util/warnp.h pushbits.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c pushbits.c -o pushbits.o spiped-1.6.3/spipe/spipe.1000644 001751 001751 00000006145 14745266145 017007 0ustar00cpercivacperciva000000 000000 .\"- .\" Copyright (c) 2012 Andreas Olsson .\" Copyright (c) 2016 Tim Duesterhus .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .TH SPIPE 1 "January 25, 2025" "spiped 1.6.3" "spipe README" .SH NAME spipe - spiped client utility .SH SYNOPSIS .B spipe \-t \-k [\-b ] [\-f | \-g] [\-j] [\-o ] .br .B spiped \-v .SH OPTIONS .TP .B \-t Address to which .B spipe should connect. Must be in one of the following formats: .IP \(bu /absolute/path/to/unix/socket .IP \(bu host.name:port .IP \(bu [ip.v4.ad.dr]:port .IP \(bu [ipv6::addr]:port .TP .B \-k Use the provided key file to authenticate and encrypt. Pass "\-" to read from standard input. Note that reading the key via standard input will make it impossible to read anything else via standard input, thereby limiting .B spipe to receiving data but not sending any. .TP .B \-b Bind the outgoing address. If this is a network address, the port number may either be specified or left to the operating system. If you specify the port number, the operating system will not permit you to open a second connection until the first one has completely expired (i.e. the TCP state is no longer in the TIME-WAIT state). .TP .B \-f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup by disabling the Diffie-Hellman handshake, at the expense of losing perfect forward secrecy. .TP .B \-g Require perfect forward secrecy by dropping connections if the other host is using the \-f option. .TP .B \-j Disable transport layer keep-alives. (By default they are enabled.) .TP .B \-o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. .TP .B \-v Print version number. .SH SEE ALSO .BR spiped (1). spiped-1.6.3/spipe/main.c000644 001751 001751 00000016675 14745266145 016706 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include "events.h" #include "getopt.h" #include "graceful_shutdown.h" #include "parsenum.h" #include "sock.h" #include "sock_util.h" #include "warnp.h" #include "proto_conn.h" #include "proto_crypt.h" #include "pushbits.h" /* Cookie with variables about the event loop and threads. */ struct events_threads { pthread_t threads[2]; int conndone; int connection_error; int stopped; }; static int callback_conndied(void * cookie, int reason) { struct events_threads * ET = cookie; /* Check reason. */ switch (reason) { case PROTO_CONN_CLOSED: case PROTO_CONN_CANCELLED: break; case PROTO_CONN_CONNECT_FAILED: warn0("Could not connect"); ET->connection_error = 1; break; case PROTO_CONN_HANDSHAKE_FAILED: warn0("Handshake failed"); ET->connection_error = 1; break; default: warn0("Connection error"); ET->connection_error = 1; } /* Shut it down if there's an error. */ if (ET->connection_error) graceful_shutdown_manual(); /* Quit event loop. */ ET->conndone = 1; /* Success! */ return (0); } static int callback_graceful_shutdown(void * cookie) { struct events_threads * ET = cookie; int rc; int i; /* Cancel the threads. */ for (i = 0; i < 2; i++) { if ((rc = pthread_cancel(ET->threads[i])) != 0) { /* * According to the POSIX standard, a Thread ID should * still be valid after pthread_exit has been invoked * by the thread if pthread_join() has not yet been * called. However, many platforms return ESRCH in * this situation. */ if (rc != ESRCH) { warn0("pthread_cancel: %s", strerror(rc)); goto err0; } } } /* Wait for the threads to finish. */ for (i = 0; i < 2; i++) { if ((rc = pthread_join(ET->threads[i], NULL)) != 0) { warn0("pthread_join: %s", strerror(rc)); goto err0; } } /* We've stopped the threads. */ ET->stopped = 1; /* Shut down the main event loop. */ ET->conndone = 1; /* Success! */ return (0); err0: /* Failure! */ return (-1); } static void usage(void) { fprintf(stderr, "usage: spipe -t -k " " [-b ] [-f | -g]\n" " [-j] [-o ]\n" " spipe -v\n"); exit(1); } /* Simplify error-handling in command-line parse loop. */ #define OPT_EPARSE(opt, arg) do { \ warnp("Error parsing argument: %s %s", opt, arg); \ exit(1); \ } while (0) int main(int argc, char * argv[]) { /* Command-line parameters. */ const char * opt_b = NULL; int opt_f = 0; int opt_g = 0; int opt_j = 0; const char * opt_k = NULL; int opt_o_set = 0; double opt_o = 0.0; const char * opt_t = NULL; /* Working variables. */ struct events_threads ET; struct sock_addr * sa_b = NULL; struct sock_addr ** sas_t; struct proto_secret * K; const char * ch; int s[2]; void * conn_cookie; int rc; WARNP_INIT; /* Parse the command line. */ while ((ch = GETOPT(argc, argv)) != NULL) { GETOPT_SWITCH(ch) { GETOPT_OPTARG("-b"): if (opt_b) usage(); opt_b = optarg; break; GETOPT_OPT("-f"): if (opt_f) usage(); opt_f = 1; break; GETOPT_OPT("-g"): if (opt_g) usage(); opt_g = 1; break; GETOPT_OPT("-j"): if (opt_j) usage(); opt_j = 1; break; GETOPT_OPTARG("-k"): if (opt_k) usage(); opt_k = optarg; break; GETOPT_OPTARG("-o"): if (opt_o_set) usage(); opt_o_set = 1; if (PARSENUM(&opt_o, optarg, 0, INFINITY)) OPT_EPARSE(ch, optarg); break; GETOPT_OPTARG("-t"): if (opt_t) usage(); opt_t = optarg; break; GETOPT_OPT("-v"): fprintf(stderr, "spipe 1.6.3\n"); exit(0); GETOPT_MISSING_ARG: warn0("Missing argument to %s", ch); usage(); GETOPT_DEFAULT: warn0("illegal option -- %s", ch); usage(); } } argc -= optind; argv += optind; /* We should have processed all the arguments. */ if (argc != 0) usage(); (void)argv; /* argv is not used beyond this point. */ /* Set defaults. */ if (opt_o == 0.0) opt_o = 5.0; /* Sanity-check options. */ if (opt_f && opt_g) usage(); if (opt_k == NULL) usage(); if (!(opt_o > 0.0)) usage(); if ((opt_t == NULL) || sock_addr_validate(opt_t)) usage(); if (opt_b && sock_addr_validate(opt_b)) usage(); /* Initialize the "events & threads" cookie. */ ET.conndone = 0; ET.connection_error = 0; ET.stopped = 0; /* Resolve target address. */ if ((sas_t = sock_resolve(opt_t)) == NULL) { warnp("Error resolving socket address: %s", opt_t); goto err0; } if (sas_t[0] == NULL) { warn0("No addresses found for %s", opt_t); goto err1; } /* Resolve bind address (if applicable). */ if (opt_b && ((sa_b = sock_resolve_one(opt_b, 1)) == NULL)) { warnp("Failed to get bind address"); goto err1; } /* Load the keying data. */ if ((K = proto_crypt_secret(opt_k)) == NULL) { warnp("Error reading shared secret"); goto err2; } /* * Create a socket pair to push bits through. The spiped protocol * code expects to be handed a socket to read/write bits to, and our * stdin/stdout might not be sockets (in fact, almost certainly aren't * sockets); so we'll hand one end of the socket pair to the spiped * protocol code and shuttle bits between stdin/stdout and the other * end of the socket pair ourselves. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s)) { warnp("socketpair"); goto err3; } /* Set up a connection. */ if ((conn_cookie = proto_conn_create(s[1], sas_t, sa_b, 0, opt_f, opt_g, opt_j, K, opt_o, callback_conndied, &ET)) == NULL) { warnp("Could not set up connection"); goto err4; } /* sas_t and s[1] are now owned by proto_conn. */ sas_t = NULL; s[1] = -1; /* Push bits from the socket to stdout. */ if (pushbits(s[0], STDOUT_FILENO, &ET.threads[1])) { warnp("Could not push bits"); goto err5; } /* Push bits from stdin into the socket. */ if (pushbits(STDIN_FILENO, s[0], &ET.threads[0])) { warnp("Could not push bits"); goto err6; } /* Register a handler for SIGTERM. */ if (graceful_shutdown_initialize(&callback_graceful_shutdown, &ET)) { warn0("Failed to start graceful_shutdown timer"); goto err7; } /* Loop until we're done with the connection. */ if (events_spin(&ET.conndone)) { warnp("Error running event loop"); goto err5; } /* Wait for threads to finish (if necessary) */ if (ET.stopped == 0) { if ((rc = pthread_join(ET.threads[0], NULL)) != 0) { warn0("pthread_join: %s", strerror(rc)); goto err3; } if ((rc = pthread_join(ET.threads[1], NULL)) != 0) { warn0("pthread_join: %s", strerror(rc)); goto err3; } } /* Clean up. */ if (close(s[0])) warnp("close"); proto_crypt_secret_free(K); sock_addr_free(sa_b); /* Handle a connection error. */ if (ET.connection_error) goto err0; /* Success! */ exit(0); err7: if ((rc = pthread_cancel(ET.threads[0])) != 0) warn0("pthread_cancel: %s", strerror(rc)); if ((rc = pthread_join(ET.threads[0], NULL)) != 0) warn0("pthread_join: %s", strerror(rc)); err6: if ((rc = pthread_cancel(ET.threads[1])) != 0) warn0("pthread_cancel: %s", strerror(rc)); if ((rc = pthread_join(ET.threads[1], NULL)) != 0) warn0("pthread_join: %s", strerror(rc)); err5: proto_conn_drop(conn_cookie, PROTO_CONN_CANCELLED); err4: if ((s[1] != -1) && close(s[1])) warnp("close"); if (close(s[0])) warnp("close"); err3: proto_crypt_secret_free(K); err2: sock_addr_free(sa_b); err1: sock_addr_freelist(sas_t); err0: /* Failure! */ exit(1); } spiped-1.6.3/spipe/pushbits.c000644 001751 001751 00000004103 14154500003 017554 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include "noeintr.h" #include "pthread_create_blocking_np.h" #include "warnp.h" #include "pushbits.h" struct push { uint8_t buf[BUFSIZ]; int in; int out; }; static void workthread_cleanup(void * cookie) { struct push * P = cookie; /* * Try to shut down the descriptor we're writing to. Ignore ENOTSOCK, * since it might, indeed, not be a socket. */ if (shutdown(P->out, SHUT_WR)) { if (errno != ENOTSOCK) { warnp("Error shutting down socket"); exit(1); } } /* Free our parameters. */ free(P); } /* Bit-pushing thread. */ static void * workthread(void * cookie) { struct push * P = cookie; ssize_t readlen; /* Set up cleanup function. */ pthread_cleanup_push(workthread_cleanup, P); /* Infinite loop unless we hit EOF or an error. */ do { /* Read data and die on error. */ if ((readlen = read(P->in, P->buf, BUFSIZ)) == -1) { if (errno == EINTR) continue; warnp("Error reading"); exit(1); } /* If we hit EOF, exit the loop. */ if (readlen == 0) break; /* Write the data back out. */ if (noeintr_write(P->out, &P->buf, (size_t)readlen) != readlen) { warnp("Error writing"); exit(1); } } while (1); /* Clean up. */ pthread_cleanup_pop(1); /* We're done. */ return (NULL); } /** * pushbits(in, out, thr): * Create a thread which copies data from ${in} to ${out} and * store the thread ID in ${thr}. Wait until ${thr} has started. * If ${out} is a socket, disable writing to it after the thread * exits. */ int pushbits(int in, int out, pthread_t * thr) { struct push * P; int rc; /* Allocate structure. */ if ((P = malloc(sizeof(struct push))) == NULL) goto err0; P->in = in; P->out = out; /* Create thread. */ if ((rc = pthread_create_blocking_np(thr, NULL, workthread, P)) != 0) { warn0("pthread_create_blocking_np: %s", strerror(rc)); goto err1; } /* Success! */ return (0); err1: free(P); err0: /* Failure! */ return (-1); } spiped-1.6.3/spiped/main.c000644 001751 001751 00000020341 14745266145 017033 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "asprintf.h" #include "daemonize.h" #include "events.h" #include "getopt.h" #include "graceful_shutdown.h" #include "parsenum.h" #include "setuidgid.h" #include "sock.h" #include "sock_util.h" #include "warnp.h" #include "dispatch.h" #include "proto_crypt.h" static void usage(void) { fprintf(stderr, "usage: spiped {-e | -d} -s " "-t -k \n" " [-b [-DFj] [-f | -g] " "[-n ]\n" " [-o ] [-p ] [-r | -R] " "[--syslog]\n" " [-u { | <:groupname> | }]\n" " spiped -v\n"); exit(1); } static int callback_graceful_shutdown(void * dispatch_cookie) { dispatch_request_shutdown(dispatch_cookie); /* Success! */ return (0); } /* * Signal handler for SIGINT to perform a hard shutdown. */ static void diediedie_handler(int signo) { (void)signo; /* UNUSED */ _exit(0); } /* Simplify error-handling in command-line parse loop. */ #define OPT_EPARSE(opt, arg) do { \ warnp("Error parsing argument: %s %s", opt, arg); \ exit(1); \ } while (0) int main(int argc, char * argv[]) { /* Command-line parameters. */ const char * opt_b = NULL; int opt_d = 0; int opt_D = 0; int opt_e = 0; int opt_f = 0; int opt_g = 0; int opt_F = 0; int opt_j = 0; const char * opt_k = NULL; int opt_n_set = 0; size_t opt_n = 0; int opt_o_set = 0; double opt_o = 0.0; const char * opt_p = NULL; int opt_r_set = 0; double opt_r = 0.0; int opt_R = 0; int opt_syslog = 0; const char * opt_s = NULL; const char * opt_t = NULL; const char * opt_u = NULL; /* Working variables. */ struct sock_addr * sa_s; struct sock_addr * sa_b = NULL; struct sock_addr ** sas_t; struct proto_secret * K; const char * ch; char * pidfilename = NULL; int s; void * dispatch_cookie = NULL; int conndone = 0; WARNP_INIT; /* Parse the command line. */ while ((ch = GETOPT(argc, argv)) != NULL) { GETOPT_SWITCH(ch) { GETOPT_OPTARG("-b"): if (opt_b) usage(); opt_b = optarg; break; GETOPT_OPT("-d"): if (opt_d || opt_e) usage(); opt_d = 1; break; GETOPT_OPT("-D"): if (opt_D) usage(); opt_D = 1; break; GETOPT_OPT("-e"): if (opt_d || opt_e) usage(); opt_e = 1; break; GETOPT_OPT("-f"): if (opt_f) usage(); opt_f = 1; break; GETOPT_OPT("-F"): if (opt_F) usage(); opt_F = 1; break; GETOPT_OPT("-g"): if (opt_g) usage(); opt_g = 1; break; GETOPT_OPT("-j"): if (opt_j) usage(); opt_j = 1; break; GETOPT_OPTARG("-k"): if (opt_k) usage(); opt_k = optarg; break; GETOPT_OPTARG("-n"): if (opt_n_set) usage(); opt_n_set = 1; if (PARSENUM(&opt_n, optarg)) OPT_EPARSE(ch, optarg); if (opt_n == 0) opt_n = SIZE_MAX; break; GETOPT_OPTARG("-o"): if (opt_o_set) usage(); opt_o_set = 1; if (PARSENUM(&opt_o, optarg, 0, INFINITY)) OPT_EPARSE(ch, optarg); break; GETOPT_OPTARG("-p"): if (opt_p) usage(); opt_p = optarg; break; GETOPT_OPTARG("-r"): if (opt_r_set) usage(); opt_r_set = 1; if (PARSENUM(&opt_r, optarg, 0, INFINITY)) OPT_EPARSE(ch, optarg); break; GETOPT_OPT("-R"): if (opt_R) usage(); opt_R = 1; break; GETOPT_OPTARG("-s"): if (opt_s) usage(); opt_s = optarg; break; GETOPT_OPT("--syslog"): if (opt_syslog) usage(); opt_syslog = 1; break; GETOPT_OPTARG("-t"): if (opt_t) usage(); opt_t = optarg; break; GETOPT_OPTARG("-u"): if (opt_u != NULL) usage(); opt_u = optarg; break; GETOPT_OPT("-v"): fprintf(stderr, "spiped 1.6.3\n"); exit(0); GETOPT_MISSING_ARG: warn0("Missing argument to %s", ch); usage(); GETOPT_DEFAULT: warn0("illegal option -- %s", ch); usage(); } } argc -= optind; argv += optind; /* We should have processed all the arguments. */ if (argc != 0) usage(); (void)argv; /* argv is not used beyond this point. */ /* Set defaults. */ if (!opt_n_set) opt_n = 100; if (opt_o == 0.0) opt_o = 5.0; if (opt_r == 0.0) opt_r = 60.0; /* Sanity-check options. */ if (!opt_d && !opt_e) usage(); if (opt_f && opt_g) usage(); if (opt_k == NULL) usage(); if (!(opt_o > 0.0)) usage(); if ((opt_r != 60.0) && opt_R) usage(); if ((opt_s == NULL) || sock_addr_validate(opt_s)) usage(); if ((opt_t == NULL) || sock_addr_validate(opt_t)) usage(); if (opt_b && sock_addr_validate(opt_b)) usage(); /* * A limit of SIZE_MAX connections is equivalent to any larger limit; * we'll be unable to allocate memory for socket bookkeeping before we * reach either. */ if (opt_n > SIZE_MAX) opt_n = SIZE_MAX; /* Figure out where our pid should be written. */ if (asprintf(&pidfilename, (opt_p != NULL) ? "%s" : "%s.pid", (opt_p != NULL) ? opt_p : opt_s) == -1) { warnp("asprintf"); goto err0; } /* Check whether we are running as init (e.g., inside a container). */ if (getpid() == 1) { /* https://github.com/docker/docker/issues/7086 */ warn0("WARNING: Applying workaround for Docker signal-handling bug"); /* Bind an explicit signal handler for SIGINT. */ if (signal(SIGINT, diediedie_handler) == SIG_ERR) { warnp("Failed to bind SIGINT signal handler"); } } /* Daemonize early if we're going to wait for DNS to be ready. */ if (opt_D && !opt_F) { if (daemonize(pidfilename)) { warnp("Failed to daemonize"); goto err1; } /* Send to syslog (if applicable). */ if (opt_syslog) warnp_syslog(1); } /* Resolve source address. */ while ((sa_s = sock_resolve_one(opt_s, 0)) == NULL) { if (!opt_D) { warnp("Error resolving socket address: %s", opt_s); goto err1; } sleep(1); } /* Resolve target address. */ while ((sas_t = sock_resolve(opt_t)) == NULL) { if (!opt_D) { warnp("Error resolving socket address: %s", opt_t); goto err2; } sleep(1); } if (sas_t[0] == NULL) { warn0("No addresses found for %s", opt_t); goto err3; } /* Resolve bind address (if applicable). */ if (opt_b) { while ((sa_b = sock_resolve_one(opt_b, 1)) == NULL) { if (!opt_D) { warnp("Error resolving socket address: %s", opt_b); goto err3; } sleep(1); } } /* Load the keying data. */ if ((K = proto_crypt_secret(opt_k)) == NULL) { warnp("Error reading shared secret"); goto err4; } /* Create and bind a socket, and mark it as listening. */ if ((s = sock_listener(sa_s)) == -1) goto err5; /* Daemonize and write pid. */ if (!opt_D && !opt_F) { if (daemonize(pidfilename)) { warnp("Failed to daemonize"); goto err6; } /* Send to syslog (if applicable). */ if (opt_syslog) warnp_syslog(1); } /* Drop privileges (if applicable). */ if (opt_u && setuidgid(opt_u, SETUIDGID_SGROUP_LEAVE_WARN)) { warnp("Failed to drop privileges"); goto err7; } /* Start accepting connections. */ if ((dispatch_cookie = dispatch_accept(s, opt_t, opt_R ? 0.0 : opt_r, sas_t, sa_b, opt_d, opt_f, opt_g, opt_j, K, opt_n, opt_o, &conndone)) == NULL) { warnp("Failed to initialize connection acceptor"); goto err7; } /* dispatch is now maintaining sas_t and s. */ sas_t = NULL; s = -1; /* Register a handler for SIGTERM. */ if (graceful_shutdown_initialize(&callback_graceful_shutdown, dispatch_cookie)) { warn0("Failed to start graceful_shutdown timer"); goto err7; } /* * Loop until an error occurs, or a connection closes if the * command-line argument -1 was given. */ if (events_spin(&conndone)) { warnp("Error running event loop"); goto err7; } /* Stop accepting connections and shut down the dispatcher. */ dispatch_shutdown(dispatch_cookie); /* Free the protocol secret structure. */ proto_crypt_secret_free(K); /* Free arrays of resolved addresses. */ sock_addr_free(sa_s); sock_addr_free(sa_b); /* Free pid filename. */ free(pidfilename); /* Success! */ exit(0); err7: dispatch_shutdown(dispatch_cookie); err6: if ((s != -1) && close(s)) warnp("close"); err5: proto_crypt_secret_free(K); err4: sock_addr_free(sa_b); err3: sock_addr_freelist(sas_t); err2: sock_addr_free(sa_s); err1: free(pidfilename); err0: /* Failure! */ exit(1); } spiped-1.6.3/spiped/dispatch.h000644 001751 001751 00000003506 14650270210 017676 0ustar00cpercivacperciva000000 000000 #ifndef DISPATCH_H_ #define DISPATCH_H_ #include /* Opaque structures. */ struct proto_secret; struct sock_addr; /** * dispatch_accept(s, tgt, rtime, sas, sa_b, decr, nopfs, requirepfs, * nokeepalive, K, nconn_max, timeo, conndone): * Start accepting connections on the socket ${s}. Bind outgoing address to * ${sa_b} if it is not NULL. Connect to the target ${tgt}, re-resolving * it every ${rtime} seconds if ${rtime} > 0; on address resolution * failure use the most recent successfully obtained addresses, or the * addresses ${sas}. If ${decr} is 0, encrypt the outgoing connections; if * ${decr} is non-zero, decrypt the incoming connections. Don't accept more * than ${nconn_max} connections. If ${nopfs} is non-zero, don't use perfect * forward secrecy. If ${requirepfs} is non-zero, require that both ends use * perfect forward secrecy. Enable transport layer keep-alives (if applicable) * if and only if ${nokeepalive} is zero. Drop connections if the handshake or * connecting to the target takes more than ${timeo} seconds. If * dispatch_request_shutdown() is called then ${conndone} is set to a non-zero * value as soon as there are no active connections. Return a cookie which can * be passed to dispatch_shutdown() and dispatch_request_shutdown(). */ void * dispatch_accept(int, const char *, double, struct sock_addr **, const struct sock_addr *, int, int, int, int, const struct proto_secret *, size_t, double, int *); /** * dispatch_shutdown(dispatch_cookie): * Stop the server, free memory, and close the listening socket. */ void dispatch_shutdown(void *); /** * dispatch_request_shutdown(dispatch_cookie): * Request a shutdown: Stop accepting new connections and notify once * every existing connection ended. */ void dispatch_request_shutdown(void *); #endif /* !DISPATCH_H_ */ spiped-1.6.3/spiped/dispatch.c000644 001751 001751 00000020466 14650270210 017675 0ustar00cpercivacperciva000000 000000 #include #include #include #include "dnsthread.h" #include "events.h" #include "network.h" #include "queue.h" #include "sock.h" #include "sock_util.h" #include "warnp.h" #include "proto_conn.h" #include "dispatch.h" struct accept_state { int s; const char * tgt; struct sock_addr ** sas; const struct sock_addr * sa_b; double rtime; int decr; int nopfs; int requirepfs; int nokeepalive; int * conndone; int shutdown_requested; const struct proto_secret * K; size_t nconn; size_t nconn_max; double timeo; void * accept_cookie; void * dnstimer_cookie; LIST_HEAD(conn_head, conn_list_node) conn_cookies; DNSTHREAD T; }; /* Doubly linked list. */ struct conn_list_node { void * conn_cookie; LIST_ENTRY(conn_list_node) entries; struct accept_state * A; }; static int callback_gotconn(void *, int); static int callback_resolveagain(void *); /* Callback from address resolution. */ static int callback_resolve(void * cookie, struct sock_addr ** sas) { struct accept_state * A = cookie; /* If the address resolution succeeded... */ if (sas != NULL) { /* Free the old addresses. */ sock_addr_freelist(A->sas); /* Use the new addresses. */ A->sas = sas; } /* Wait a while before resolving again. */ if ((A->dnstimer_cookie = events_timer_register_double( callback_resolveagain, A, A->rtime)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Timer callback to trigger another address resolution. */ static int callback_resolveagain(void * cookie) { struct accept_state * A = cookie; /* This timer is expired. */ A->dnstimer_cookie = NULL; /* Re-resolve the target address. */ return (dnsthread_resolveone(A->T, A->tgt, callback_resolve, A)); } /* Non-blocking accept, if we can have more connections. */ static int doaccept(struct accept_state * A) { int rc = 0; /* Warn about reaching nconn_max. */ if (A->nconn >= A->nconn_max) { warn0("Maximum number of connections (%zu) reached", A->nconn_max); } /* If we can, accept a new connection. */ if ((A->nconn < A->nconn_max) && (A->accept_cookie == NULL) && !A->shutdown_requested) { if ((A->accept_cookie = network_accept(A->s, callback_gotconn, A)) == NULL) rc = -1; } /* Return success/fail status. */ return (rc); } /* A connection has closed. Accept more if necessary. */ static int callback_conndied(void * cookie, int reason) { struct conn_list_node * node_ptr = cookie; struct accept_state * A = node_ptr->A; (void)reason; /* UNUSED */ /* We should always have a non-empty list of conn_cookies. */ assert(!LIST_EMPTY(&A->conn_cookies)); /* We've lost a connection. */ A->nconn -= 1; /* Remove the closed connection from the list of conn_cookies. */ LIST_REMOVE(node_ptr, entries); /* Clean up the now-unused node. */ free(node_ptr); /* If requested to do so, indicate that all connections are closed. */ if (A->shutdown_requested && (A->nconn == 0)) *A->conndone = 1; /* Maybe accept more connections. */ return (doaccept(A)); } /* Handle an incoming connection. */ static int callback_gotconn(void * cookie, int s) { struct accept_state * A = cookie; struct sock_addr ** sas; struct conn_list_node * node_new; /* This accept is no longer in progress. */ A->accept_cookie = NULL; /* If we got a -1 descriptor, something went seriously wrong. */ if (s == -1) { warnp("network_accept failed"); goto err0; } /* We have gained a connection. */ A->nconn += 1; /* Duplicate the target address list. */ if ((sas = sock_addr_duplist(A->sas)) == NULL) goto err1; /* Create new conn_list_node. */ if ((node_new = malloc(sizeof(struct conn_list_node))) == NULL) goto err2; node_new->A = A; /* Create a new connection. */ if ((node_new->conn_cookie = proto_conn_create(s, sas, A->sa_b, A->decr, A->nopfs, A->requirepfs, A->nokeepalive, A->K, A->timeo, callback_conndied, node_new)) == NULL) { warnp("Failure setting up new connection"); goto err3; } /* Insert node_new to the beginning of the conn_cookies list. */ LIST_INSERT_HEAD(&A->conn_cookies, node_new, entries); /* Accept another connection if we can. */ if (doaccept(A)) goto err0; /* Success! */ return (0); err3: free(node_new); err2: sock_addr_freelist(sas); err1: A->nconn -= 1; if (close(s)) warnp("close"); err0: /* Failure! */ return (-1); } /** * dispatch_accept(s, tgt, rtime, sas, sa_b, decr, nopfs, requirepfs, * nokeepalive, K, nconn_max, timeo, conndone): * Start accepting connections on the socket ${s}. Bind outgoing address to * ${sa_b} if it is not NULL. Connect to the target ${tgt}, re-resolving * it every ${rtime} seconds if ${rtime} > 0; on address resolution * failure use the most recent successfully obtained addresses, or the * addresses ${sas}. If ${decr} is 0, encrypt the outgoing connections; if * ${decr} is non-zero, decrypt the incoming connections. Don't accept more * than ${nconn_max} connections. If ${nopfs} is non-zero, don't use perfect * forward secrecy. If ${requirepfs} is non-zero, require that both ends use * perfect forward secrecy. Enable transport layer keep-alives (if applicable) * if and only if ${nokeepalive} is zero. Drop connections if the handshake or * connecting to the target takes more than ${timeo} seconds. If * dispatch_request_shutdown() is called then ${conndone} is set to a non-zero * value as soon as there are no active connections. Return a cookie which can * be passed to dispatch_shutdown() and dispatch_request_shutdown(). */ void * dispatch_accept(int s, const char * tgt, double rtime, struct sock_addr ** sas, const struct sock_addr * sa_b, int decr, int nopfs, int requirepfs, int nokeepalive, const struct proto_secret * K, size_t nconn_max, double timeo, int * conndone) { struct accept_state * A; /* Bake a cookie. */ if ((A = malloc(sizeof(struct accept_state))) == NULL) goto err0; A->s = s; A->tgt = tgt; A->sas = sas; A->sa_b = sa_b; A->rtime = rtime; A->decr = decr; A->nopfs = nopfs; A->requirepfs = requirepfs; A->nokeepalive = nokeepalive; A->conndone = conndone; A->shutdown_requested = 0; A->K = K; A->nconn = 0; A->nconn_max = nconn_max; A->timeo = timeo; A->T = NULL; A->accept_cookie = NULL; A->dnstimer_cookie = NULL; LIST_INIT(&A->conn_cookies); /* If address re-resolution is enabled... */ if (rtime > 0.0) { /* Launch an address resolution thread. */ if ((A->T = dnsthread_spawn()) == NULL) goto err1; /* Re-resolve the target address after a while. */ if ((A->dnstimer_cookie = events_timer_register_double( callback_resolveagain, A, A->rtime)) == NULL) goto err2; } /* Accept a connection. */ if (doaccept(A)) goto err3; /* Success! */ return (A); err3: if (A->dnstimer_cookie != NULL) events_timer_cancel(A->dnstimer_cookie); err2: if (A->T != NULL) dnsthread_kill(A->T); err1: free(A); err0: /* Failure! */ return (NULL); } /** * dispatch_shutdown(dispatch_cookie): * Stop the server, free memory, and close the listening socket. */ void dispatch_shutdown(void * dispatch_cookie) { struct accept_state * A = dispatch_cookie; struct conn_list_node * C; /* * Shutdown any open connections. proto_conn_drop() will call * callback_conndied(), which removes the relevant conn_list_node from * the list of conn_cookies. */ while ((C = LIST_FIRST(&A->conn_cookies)) != NULL) { proto_conn_drop(C->conn_cookie, PROTO_CONN_CANCELLED); /* * Convince static analyzers that C->conn_cookie is no longer * in the list. */ assert(C != LIST_FIRST(&A->conn_cookies)); } if (A->accept_cookie != NULL) network_accept_cancel(A->accept_cookie); if (A->dnstimer_cookie != NULL) events_timer_cancel(A->dnstimer_cookie); if (A->T != NULL) dnsthread_kill(A->T); sock_addr_freelist(A->sas); if (close(A->s)) warnp("close"); free(A); } /** * dispatch_request_shutdown(dispatch_cookie): * Request a shutdown: Stop accepting new connections and notify once * every existing connection ended. */ void dispatch_request_shutdown(void * dispatch_cookie) { struct accept_state * A = dispatch_cookie; A->shutdown_requested = 1; /* Cancel any further accepts. */ if (A->accept_cookie != NULL) { network_accept_cancel(A->accept_cookie); A->accept_cookie = NULL; } /* If no connections are open... */ if (A->nconn == 0) { /* Indicate that all connections are closed. */ *A->conndone = 1; } } spiped-1.6.3/spiped/spiped.1000644 001751 001751 00000012763 14745266145 017322 0ustar00cpercivacperciva000000 000000 .\"- .\" Copyright (c) 2012 Andreas Olsson .\" Copyright (c) 2016 Tim Duesterhus .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .TH SPIPED 1 "January 25, 2025" "spiped 1.6.3" "spiped README" .SH NAME spiped - secure pipe daemon .SH SYNOPSIS .B spiped {\-e | \-d} \-s \-t \-k .br [\-DFj] [\-b ] [\-f | \-g] [\-n ] .br [\-o ] [\-p ] [\-r | \-R] [\-\-syslog] .br [\-u | <:groupname> | ] .br .B spiped \-v .SH OPTIONS .TP .B \-e Take unencrypted connections from the .I source socket and send encrypted connections to the .IR "target socket" . .TP .B \-d Take encrypted connections from the .I source socket and send unencrypted connections to the .IR "target socket" . .TP .B \-s Address on which spiped should listen for incoming connections. The accepted formats are the same as the ones accepted by .IR "target socket" . Note that contrary to .I target socket hostnames are resolved when .B spiped is launched and are not re-resolved later; thus if DNS entries change .B spiped will continue to accept connections at the expired address. .TP .B \-t Address to which .B spiped should connect. Must be in one of the following formats: .IP \(bu /absolute/path/to/unix/socket .IP \(bu host.name:port .IP \(bu [ip.v4.ad.dr]:port .IP \(bu [ipv6::addr]:port .IP Hostnames are re-resolved every .I rtime seconds. .TP .B \-k Use the provided key file to authenticate and encrypt. Pass "\-" to read from standard input. .TP .B \-b Bind the outgoing address. If this is a network address, the port number may either be specified or left to the operating system. If you specify the port number, the operating system will not permit you to open a second connection until the first one has completely expired (i.e. the TCP state is no longer in the TIME-WAIT state). .TP .B \-D Wait for DNS. Normally when .B spiped is launched it resolves addresses and binds to its .I source socket before the parent process returns; with this option it will daemonize first and retry failed DNS lookups until they succeed. This allows .B spiped to launch even if DNS isn't set up yet, but at the expense of losing the guarantee that once .B spiped has finished launching it will be ready to create pipes. .TP .B \-f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup by disabling the Diffie-Hellman handshake, at the expense of losing perfect forward secrecy. .TP .B \-g Require perfect forward secrecy by dropping connections if the other host is using the \-f option. .TP .B \-F Run in foreground. This can be useful with systems like daemontools. .TP .B \-j Disable transport layer keep-alives. (By default they are enabled.) .TP .B \-n Limit on the number of simultaneous connections allowed. A value of 0 indicates that no limit should be imposed; this may be inadvisable in some circumstances, since .B spiped will terminate if it fails to allocate memory for handling a new connection. Defaults to 100 connections. .TP .B \-o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. .TP .B \-p File to which .BR spiped 's process ID should be written. Defaults to .IR "source socket" .pid (in the current directory if .I source socket is not an absolute path). No file will be written if -F (run in foreground) is used. .TP .B \-r Re-resolve the address of .I target socket every .I rtime seconds. Defaults to re-resolution every 60 seconds. .TP .B \-R Disable target address re-resolution. .TP .B \-\-syslog After daemonizing, send warnings to syslog instead of stderr. Has no effect if -F (run in foreground) is used. .TP .B \-u | <:groupname> | After binding a socket, change the user to .I username and/or the group to .IR groupname . .TP .B \-v Print version number. .SH SIGNALS spiped provides special treatment of the following signals: .TP .B SIGTERM On receipt of the .I SIGTERM signal .B spiped will stop accepting new connections and exit once there are no active connections left. .SH SEE ALSO .BR spipe (1). spiped-1.6.3/spiped/Makefile000644 001751 001751 00000004607 14745266143 017410 0ustar00cpercivacperciva000000 000000 .POSIX: # AUTOGENERATED FILE, DO NOT EDIT PROG=spiped MAN1=spiped.1 SRCS=main.c dispatch.c IDIRS=-I../libcperciva/crypto -I../libcperciva/events -I../libcperciva/external/queue -I../libcperciva/network -I../libcperciva/util -I../lib/dnsthread -I../lib/proto -I../lib/util LDADD_REQ=-lcrypto -lpthread SUBDIR_DEPTH=.. RELATIVE_DIR=spiped LIBALL=../liball/liball.a ../liball/optional_mutex_pthread/liball_optional_mutex_pthread.a all: if [ -z "$${HAVE_BUILD_FLAGS}" ]; then \ cd ${SUBDIR_DEPTH}; \ ${MAKE} BUILD_SUBDIR=${RELATIVE_DIR} \ BUILD_TARGET=${PROG} buildsubdir; \ else \ ${MAKE} ${PROG}; \ fi install:${PROG} mkdir -p ${BINDIR} cp ${PROG} ${BINDIR}/_inst.${PROG}.$$$$_ && \ strip ${BINDIR}/_inst.${PROG}.$$$$_ && \ chmod 0555 ${BINDIR}/_inst.${PROG}.$$$$_ && \ mv -f ${BINDIR}/_inst.${PROG}.$$$$_ ${BINDIR}/${PROG} if ! [ -z "${MAN1DIR}" ]; then \ mkdir -p ${MAN1DIR}; \ for MPAGE in ${MAN1}; do \ cp $$MPAGE ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ chmod 0444 ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ mv -f ${MAN1DIR}/_inst.$$MPAGE.$$$$_ ${MAN1DIR}/$$MPAGE; \ done; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${LIBALL} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LIBALL} ${LDFLAGS} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ../libcperciva/util/asprintf.h ../libcperciva/util/daemonize.h ../libcperciva/events/events.h ../libcperciva/util/getopt.h ../lib/util/graceful_shutdown.h ../libcperciva/util/parsenum.h ../libcperciva/util/setuidgid.h ../libcperciva/util/sock.h ../libcperciva/util/sock_util.h ../libcperciva/util/warnp.h dispatch.h ../lib/proto/proto_crypt.h ../libcperciva/crypto/crypto_dh.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c main.c -o main.o dispatch.o: dispatch.c ../lib/dnsthread/dnsthread.h ../libcperciva/events/events.h ../libcperciva/network/network.h ../libcperciva/external/queue/queue.h ../libcperciva/util/sock.h ../libcperciva/util/sock_util.h ../libcperciva/util/warnp.h ../lib/proto/proto_conn.h dispatch.h ${CC} ${CFLAGS_POSIX} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DCPUSUPPORT_CONFIG_FILE=\"cpusupport-config.h\" -DAPISUPPORT_CONFIG_FILE=\"apisupport-config.h\" -I.. ${IDIRS} ${CPPFLAGS} ${CFLAGS} -c dispatch.c -o dispatch.o spiped-1.6.3/lib/proto/000755 001751 001751 00000000000 14743020337 016355 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/lib/dnsthread/000755 001751 001751 00000000000 14650270210 017160 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/lib/util/000755 001751 001751 00000000000 14650270210 016161 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/lib/util/pthread_create_blocking_np.c000644 001751 001751 00000007743 14154500003 023652 0ustar00cpercivacperciva000000 000000 #include #include #include #include "pthread_create_blocking_np.h" struct wrapped_cookie { /* User-supplied. */ void * (*start_routine)(void *); void * arg; /* Synchronization. */ pthread_mutex_t mutex; pthread_cond_t cond; int running; /* 1 if the thread has started. */ /* In case the synchronization fails. */ int rc_sync; /* non-zero if synchronization failed. */ }; /* Routine which is executed by pthread_create(). */ static void * wrapped_thread(void * cookie) { struct wrapped_cookie * U = cookie; void * (*start_routine)(void *); void * arg; int rc; /* * Copy the user-supplied parameters, because U will not be valid * after we signal the parent thread that we have started running. */ start_routine = U->start_routine; arg = U->arg; /* Lock mutex. */ if ((rc = pthread_mutex_lock(&U->mutex))) goto err1; /* Set the "running" flag and signal the condition variable. */ U->running = 1; if ((rc = pthread_cond_signal(&U->cond))) goto err2; /* Unlock mutex. This allows the parent thread to free U. */ if ((rc = pthread_mutex_unlock(&U->mutex))) goto err1; /* Run the desired routine. */ return (start_routine(arg)); err2: /* * Don't record any errors in this clean-up; the existing value of rc * is more important. */ pthread_mutex_unlock(&U->mutex); err1: /* If there was an error, then we can still write to U. */ U->rc_sync = rc; /* Failure! */ return (NULL); } /** * pthread_create_blocking_np(thread, attr, start_routine, arg): * Run pthread_create() and block until the the ${thread} has started. The * thread will execute ${start_routine} with ${arg} as its sole argument. * When ${start_routine} finishes, make its returned value available via * pthread_join(). If successful, return 0; otherwise return the error number. */ int pthread_create_blocking_np(pthread_t * restrict thread, const pthread_attr_t * restrict attr, void * (*start_routine)(void *), void * restrict arg) { struct wrapped_cookie * U; int rc; /* * Allocate our cookie and store parameters. The C standard does not * require that variables with automatic storage duration are * accessible by other threads; POSIX (and thus pthreads) does provide * that guarantee, but out of an abundance of caution we take the * option of using malloc in case this code ends up running on a * non-POSIX system. */ if ((U = malloc(sizeof(struct wrapped_cookie))) == NULL) { rc = errno; goto err0; } U->start_routine = start_routine; U->arg = arg; /* Initialize synchronization-related variables. */ if ((rc = pthread_mutex_init(&U->mutex, NULL)) != 0) goto err1; if ((rc = pthread_cond_init(&U->cond, NULL)) != 0) goto err2; U->running = 0; U->rc_sync = 0; /* Lock mutex. */ if ((rc = pthread_mutex_lock(&U->mutex)) != 0) goto err3; /* Create the thread. */ if ((rc = pthread_create(thread, attr, wrapped_thread, U)) != 0) { /* * Don't record any pthread_mutex_unlock() error here; the * error from pthread_create() is more important. */ pthread_mutex_unlock(&U->mutex); goto err3; } /* Wait for the thread to have started, then unlock the mutex. */ while (!U->running) { /* Wait until signalled. */ if ((rc = pthread_cond_wait(&U->cond, &U->mutex)) != 0) goto err5; /* Quit if there was an error in the synchronization. */ if ((rc = U->rc_sync) != 0) goto err5; } if ((rc = pthread_mutex_unlock(&U->mutex)) != 0) goto err4; /* Clean up synchronization-related variables. */ if ((rc = pthread_cond_destroy(&U->cond)) != 0) goto err2; if ((rc = pthread_mutex_destroy(&U->mutex)) != 0) goto err1; /* Clean up. */ free(U); /* Success! */ return (0); err5: /* * Don't record any errors in this clean-up; the existing value of rc * is more important. */ pthread_mutex_unlock(&U->mutex); err4: pthread_cancel(*thread); pthread_join(*thread, NULL); err3: pthread_cond_destroy(&U->cond); err2: pthread_mutex_destroy(&U->mutex); err1: free(U); err0: /* Failure! */ return (rc); } spiped-1.6.3/lib/util/graceful_shutdown.h000644 001751 001751 00000001034 14650270210 022053 0ustar00cpercivacperciva000000 000000 #ifndef GRACEFUL_SHUTDOWN_H_ #define GRACEFUL_SHUTDOWN_H_ /** * graceful_shutdown_initialize(callback, caller_cookie): * Initialize a signal handler for SIGTERM, and start a continuous 1-second * timer which checks if SIGTERM was given; if detected, call ${callback} and * give it the ${caller_cookie}. */ int graceful_shutdown_initialize(int (*)(void *), void *); /** * graceful_shutdown_manual(void): * Shutdown immediately, without needing a SIGTERM. */ void graceful_shutdown_manual(void); #endif /* !GRACEFUL_SHUTDOWN_H_ */ spiped-1.6.3/lib/util/graceful_shutdown.c000644 001751 001751 00000005734 13762775424 022105 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "events.h" #include "warnp.h" #include "graceful_shutdown.h" /* Data from parent code. */ static int (* begin_shutdown)(void *); static void (* sighandler_sigterm_orig)(int); static void * caller_cookie; static void * timer_cookie = NULL; /* Flag to show that SIGTERM was received. */ static volatile sig_atomic_t should_shutdown = 0; /* Signal handler for SIGTERM to perform a graceful shutdown. */ static void graceful_shutdown_handler(int signo) { (void)signo; /* UNUSED */ should_shutdown = 1; } static void graceful_shutdown_atexit(void) { if (timer_cookie != NULL) { events_timer_cancel(timer_cookie); timer_cookie = NULL; } } /* Requests a graceful shutdown of the caller via the cookie info. */ static int graceful_shutdown(void * cookie) { (void)cookie; /* UNUSED */ /* This timer has expired. */ timer_cookie = NULL; /* Use the callback function, or schedule another check in 1 second. */ if (should_shutdown) { if (begin_shutdown(caller_cookie) != 0) { warn0("Failed to begin shutdown"); goto err0; } /* Restore original SIGTERM handler. */ if (signal(SIGTERM, sighandler_sigterm_orig) == SIG_ERR) warnp("Failed to restore original SIGTERM handler"); } else { if ((timer_cookie = events_timer_register_double( graceful_shutdown, NULL, 1.0)) == NULL) { warnp("Failed to register the graceful shutdown timer"); goto err0; } } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * graceful_shutdown_initialize(callback, caller_cookie): * Initialize a signal handler for SIGTERM, and start a continuous 1-second * timer which checks if SIGTERM was given; if detected, call ${callback} and * give it the ${caller_cookie}. */ int graceful_shutdown_initialize(int (* begin_shutdown_parent)(void *), void * caller_cookie_parent) { /* Record callback data. */ begin_shutdown = begin_shutdown_parent; caller_cookie = caller_cookie_parent; /* Start signal handler and save the original one. */ if ((sighandler_sigterm_orig = signal(SIGTERM, graceful_shutdown_handler)) == SIG_ERR) { warnp("signal"); goto err0; } /* Clean up the timer cookie at exit. */ if (atexit(graceful_shutdown_atexit)) goto err0; /* Periodically check whether a signal was received. */ if ((timer_cookie = events_timer_register_double( graceful_shutdown, NULL, 1.0)) == NULL) { warnp("Failed to register the graceful shutdown timer"); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * graceful_shutdown_manual(void): * Shutdown immediately, without needing a SIGTERM. */ void graceful_shutdown_manual(void) { /* Sanity check: we must be initialized. */ assert(begin_shutdown != NULL); assert(caller_cookie != NULL); /* Stop the timer. */ if (timer_cookie != NULL) { events_timer_cancel(timer_cookie); timer_cookie = NULL; } /* Shut down. */ should_shutdown = 1; graceful_shutdown(NULL); } spiped-1.6.3/lib/util/pthread_create_blocking_np.h000644 001751 001751 00000001176 14650270210 023656 0ustar00cpercivacperciva000000 000000 #ifndef PTHREAD_CREATE_BLOCKING_NP_H_ #define PTHREAD_CREATE_BLOCKING_NP_H_ #include /** * pthread_create_blocking_np(thread, attr, start_routine, arg): * Run pthread_create() and block until the the ${thread} has started. The * thread will execute ${start_routine} with ${arg} as its sole argument. * When ${start_routine} finishes, make its returned value available via * pthread_join(). If successful, return 0; otherwise return the error number. */ int pthread_create_blocking_np(pthread_t * restrict, const pthread_attr_t * restrict, void *(*)(void *), void *); #endif /* !PTHREAD_CREATE_BLOCKING_NP_H_ */ spiped-1.6.3/lib/dnsthread/dnsthread.c000644 001751 001751 00000025007 14650270210 021304 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include "events.h" #include "noeintr.h" #include "sock.h" #include "warnp.h" #include "dnsthread.h" /* Thread management structure. */ struct dnsthread_internal { /* Threading glue. */ pthread_t thr; /* Thread ID. */ pthread_mutex_t mtx; /* Controls access to this structure. */ pthread_cond_t cv; /* Thread sleeps on this. */ /* State management. */ int state; /* THREAD_* as below. */ int wakeupsock[2]; /* Writes to [0], reads from [1]. */ /* Address resolution variables. */ char * addr; /* Address to be resolved. */ struct sock_addr ** sas; /* Results. */ int res_errno; /* Errno to be passed back on failure. */ /* Callback to occur when resolution is complete. */ int (* callback)(void *, struct sock_addr **); /* Callback. */ void * cookie; /* Cookie. */ }; /* Cookie used by dnsthread_resolve. */ struct resolve_cookie { int (* callback)(void *, struct sock_addr **); void * cookie; DNSTHREAD T; }; /* * Thread states. _resolveone moves the thread from SLEEPING to HASWORK; * workthread moves the thread from HASWORK to SLEEPING; and _kill moves the * thread from either state to SUICIDE. */ #define THREAD_SLEEPING 0 #define THREAD_HASWORK 1 #define THREAD_SUICIDE 2 /* Callback functions used below. */ static int callback_resolveone(void * cookie); static int callback_resolve(void *, struct sock_addr **); /* Address resolution thread. */ static void * workthread(void * cookie) { struct dnsthread_internal * T = cookie; char * addr; struct sock_addr ** sas; int res_errno = 0; int rc; uint8_t zero = 0; /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); exit(1); } /* Infinite loop doing work until told to suicide. */ do { /* * Sleep on the condition variable as long as we're in the * SLEEPING state. */ while (T->state == THREAD_SLEEPING) { /* Sleep until we're woken up. */ if ((rc = pthread_cond_wait(&T->cv, &T->mtx)) != 0) { warn0("pthread_cond_wait: %s", strerror(rc)); exit(1); } } /* If we need to kill ourself, stop looping. */ if (T->state == THREAD_SUICIDE) break; /* Grab the work. */ addr = T->addr; /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); exit(1); } /* Perform the address resolution. */ if ((sas = sock_resolve(addr)) == NULL) res_errno = errno; /* Grab the mutex again. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); exit(1); } /* Write the answer back. */ T->sas = sas; T->res_errno = res_errno; /* Send a completion message. */ if (noeintr_write(T->wakeupsock[0], &zero, 1) != 1) { warnp("Error writing to wakeup socket"); exit(1); } /* Return to sleeping, unless we were instructed to die. */ if (T->state != THREAD_SUICIDE) T->state = THREAD_SLEEPING; } while (1); /* Close the socket pair. */ if (close(T->wakeupsock[1])) warnp("close"); if (close(T->wakeupsock[0])) warnp("close"); /* Destroy the condition variable. */ if ((rc = pthread_cond_destroy(&T->cv)) != 0) { warn0("pthread_cond_destroy: %s", strerror(rc)); exit(1); } /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); exit(1); } /* Destroy the mutex. */ if ((rc = pthread_mutex_destroy(&T->mtx)) != 0) { warn0("pthread_mutex_destroy: %s", strerror(rc)); exit(1); } /* Free the control structure. */ free(T); /* Successful thread termination. */ return (NULL); } /** * dnsthread_spawn(void): * Spawn a thread for performing address resolution. Return a token which can * be passed to dnsthread_resolveone() and dnsthread_kill(). */ DNSTHREAD dnsthread_spawn(void) { struct dnsthread_internal * T; int rc; /* Allocate a thread management structure. */ if ((T = malloc(sizeof(struct dnsthread_internal))) == NULL) goto err0; /* Create and lock a mutex. */ if ((rc = pthread_mutex_init(&T->mtx, NULL)) != 0) { warn0("pthread_mutex_init: %s", strerror(rc)); goto err1; } if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err2; } /* Create state-changed condition variable. */ if ((rc = pthread_cond_init(&T->cv, NULL)) != 0) { warn0("pthread_cond_init: %s", strerror(rc)); goto err3; } /* Create wakeup socketpair. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, T->wakeupsock)) { warnp("socketpair"); goto err4; } /* The thread starts out sleeping. */ T->state = THREAD_SLEEPING; /* Create the thread. */ if ((rc = pthread_create(&T->thr, NULL, workthread, T)) != 0) { warn0("pthread_create: %s", strerror(rc)); goto err5; } /* Unlock the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* Success! */ return (T); err5: if (close(T->wakeupsock[1])) warnp("close"); if (close(T->wakeupsock[0])) warnp("close"); err4: pthread_cond_destroy(&T->cv); err3: pthread_mutex_unlock(&T->mtx); err2: pthread_mutex_destroy(&T->mtx); err1: free(T); err0: /* Failure! */ return (NULL); } /** * dnsthread_resolveone(T, addr, callback, cookie): * Using the thread for which ${T} was returned by dnsthread_spawn(), resolve * the address ${addr}, which must be in one of the forms accepted by * sock_resolve(). If ${T} is already resolving an address, do not * resolve this address and instead return with errno == EALREADY. Upon * completion, invoke ${callback}(${cookie}, sas), where ${sas} is a * NULL-terminated array of pointers to sock_addr structures or NULL on * resolution failure. */ int dnsthread_resolveone(DNSTHREAD T, const char * addr, int (* callback)(void *, struct sock_addr **), void * cookie) { int err = 0; int rc; /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* If the resolver is already busy, fail. */ if (T->state == THREAD_HASWORK) { err = EALREADY; goto ealready; } /* Duplicate the address to be resolved. */ if ((T->addr = strdup(addr)) == NULL) goto err1; /* Remember what callback we'll need to do eventually. */ T->callback = callback; T->cookie = cookie; /* There is now work for the thread to do. */ T->state = THREAD_HASWORK; /* Wake up the worker thread. */ if ((rc = pthread_cond_signal(&T->cv)) != 0) { warn0("pthread_cond_signal: %s", strerror(rc)); goto err1; } /* We want a callback when the worker thread pokes us. */ if (events_network_register(callback_resolveone, T, T->wakeupsock[1], EVENTS_NETWORK_OP_READ)) { warnp("Error registering wakeup listener"); goto err1; } ealready: /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* If err was set earlier, store the value in errno. */ if (err) errno = err; /* Success! */ return (0); err1: pthread_mutex_unlock(&T->mtx); err0: /* Failure! */ return (-1); } /* Callback for dnsthread_resolveone, from wakeup socket. */ static int callback_resolveone(void * cookie) { struct dnsthread_internal * T = cookie; struct sock_addr ** sas; uint8_t zero; int res_errno = 0; int (* callback)(void *, struct sock_addr **); void * cb_cookie; int rc; /* Drain the byte from the socketpair. */ if (read(T->wakeupsock[1], &zero, 1) != 1) { warn0("Error reading from wakeup socket"); goto err0; } /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* Free the (strduped) address which was to be resolved. */ free(T->addr); /* Grab the result. */ sas = T->sas; res_errno = T->res_errno; /* Grab the callback. */ callback = T->callback; cb_cookie = T->cookie; /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* Perform the callback. */ if (sas == NULL) errno = res_errno; return ((callback)(cb_cookie, sas)); err0: /* Failure! */ return (-1); } /** * dnsthread_kill(T): * Instruct an address resolution thread to die. If the thread does not have * an address resolution operation currently pending, wait for the thread to * die before returning. */ int dnsthread_kill(DNSTHREAD T) { int rc; int ostate; pthread_t thr; /* Lock the control structure. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* Remember what state the thread is currently in. */ ostate = T->state; /* Grab the thread ID. */ thr = T->thr; /* Tell the thread to die, and wake it up. */ T->state = THREAD_SUICIDE; if ((rc = pthread_cond_signal(&T->cv)) != 0) { warn0("pthread_cond_signal: %s", strerror(rc)); goto err1; } /* Unlock the control structure. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* If the thread was sleeping, wait for it to wake up and die. */ if (ostate == THREAD_SLEEPING) { if ((rc = pthread_join(thr, NULL)) != 0) { warn0("pthread_join: %s", strerror(rc)); goto err0; } } /* Success! */ return (0); err1: pthread_mutex_unlock(&T->mtx); err0: /* Failure! */ return (-1); } /** * dnsthread_resolve(addr, callback, cookie): * Perform a non-blocking address resolution of ${addr}. This function may * spawn a thread internally. */ int dnsthread_resolve(const char * addr, int (* callback)(void *, struct sock_addr **), void * cookie) { struct resolve_cookie * R; /* Bake a cookie. */ if ((R = malloc(sizeof(struct resolve_cookie))) == NULL) goto err0; R->callback = callback; R->cookie = cookie; /* Spawn a thread. */ if ((R->T = dnsthread_spawn()) == NULL) goto err1; /* Launch the request. */ if (dnsthread_resolveone(R->T, addr, callback_resolve, R)) goto err2; /* Success! */ return (0); err2: dnsthread_kill(R->T); err1: free(R); err0: /* Failure! */ return (-1); } /* Callback for dnsthread_resolve, from dnsthread_resolveone. */ static int callback_resolve(void * cookie, struct sock_addr ** sas) { struct resolve_cookie * R = cookie; int rc; /* Invoke the upstream callback. */ rc = (R->callback)(R->cookie, sas); /* Kill the resolver thread. */ if (dnsthread_kill(R->T)) rc = -1; /* Free our cookie. */ free(R); /* Return upstream return code or failure. */ return (rc); } spiped-1.6.3/lib/dnsthread/dnsthread.h000644 001751 001751 00000002745 14650270210 021315 0ustar00cpercivacperciva000000 000000 #ifndef DNSTHREAD_H_ #define DNSTHREAD_H_ /* Opaque address structure. */ struct sock_addr; /* Opaque thread token. */ typedef struct dnsthread_internal * DNSTHREAD; /** * dnsthread_spawn(void): * Spawn a thread for performing address resolution. Return a token which can * be passed to dnsthread_resolveone() and dnsthread_kill(). */ DNSTHREAD dnsthread_spawn(void); /** * dnsthread_resolveone(T, addr, callback, cookie): * Using the thread for which ${T} was returned by dnsthread_spawn(), resolve * the address ${addr}, which must be in one of the forms accepted by * sock_resolve(). If ${T} is already resolving an address, do not * resolve this address and instead return with errno == EALREADY. Upon * completion, invoke ${callback}(${cookie}, sas), where ${sas} is a * NULL-terminated array of pointers to sock_addr structures or NULL on * resolution failure. */ int dnsthread_resolveone(DNSTHREAD, const char *, int (*)(void *, struct sock_addr **), void *); /** * dnsthread_kill(T): * Instruct an address resolution thread to die. If the thread does not have * an address resolution operation currently pending, wait for the thread to * die before returning. */ int dnsthread_kill(DNSTHREAD); /** * dnsthread_resolve(addr, callback, cookie): * Perform a non-blocking address resolution of ${addr}. This function may * spawn a thread internally. */ int dnsthread_resolve(const char *, int (*)(void *, struct sock_addr **), void *); #endif /* !DNSTHREAD_H_ */ spiped-1.6.3/lib/proto/proto_handshake.c000644 001751 001751 00000017324 14070374447 021710 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "crypto_entropy.h" #include "network.h" #include "proto_crypt.h" #include "proto_handshake.h" struct handshake_cookie { int (* callback)(void *, struct proto_keys *, struct proto_keys *); void * cookie; int s; int decr; int nopfs; int requirepfs; const struct proto_secret * K; uint8_t nonce_local[PCRYPT_NONCE_LEN]; uint8_t nonce_remote[PCRYPT_NONCE_LEN]; uint8_t dhmac_local[PCRYPT_DHMAC_LEN]; uint8_t dhmac_remote[PCRYPT_DHMAC_LEN]; uint8_t x[PCRYPT_X_LEN]; uint8_t yh_local[PCRYPT_YH_LEN]; uint8_t yh_remote[PCRYPT_YH_LEN]; void * read_cookie; void * write_cookie; }; static int callback_nonce_write(void *, ssize_t); static int callback_nonce_read(void *, ssize_t); static int gotnonces(struct handshake_cookie *); static int dhread(struct handshake_cookie *); static int callback_dh_read(void *, ssize_t); static int dhwrite(struct handshake_cookie *); static int callback_dh_write(void *, ssize_t); static int handshakedone(struct handshake_cookie *); /* The handshake failed. Call back and clean up. */ static int handshakefail(struct handshake_cookie * H) { int rc; /* Cancel any pending network read or write. */ if (H->read_cookie != NULL) network_read_cancel(H->read_cookie); if (H->write_cookie != NULL) network_write_cancel(H->write_cookie); /* Perform the callback. */ rc = (H->callback)(H->cookie, NULL, NULL); /* Free the cookie. */ free(H); /* Return status from callback. */ return (rc); } /** * proto_handshake(s, decr, nopfs, requirepfs, K, callback, cookie): * Perform a protocol handshake on socket ${s}. If ${decr} is non-zero we are * at the receiving end of the connection; otherwise at the sending end. If * ${nopfs} is non-zero, perform a "weak" handshake without perfect forward * secrecy. If ${requirepfs} is non-zero, drop the connection if the other * end attempts to perform a "weak" handshake. The shared protocol secret is * ${K}. Upon completion, invoke ${callback}(${cookie}, f, r), where f * contains the keys needed for the forward direction and r contains the keys * needed for the reverse direction; or f = r = NULL if the handshake failed. * Return a cookie which can be passed to proto_handshake_cancel() to cancel the * handshake. */ void * proto_handshake(int s, int decr, int nopfs, int requirepfs, const struct proto_secret * K, int (* callback)(void *, struct proto_keys *, struct proto_keys *), void * cookie) { struct handshake_cookie * H; /* Bake a cookie. */ if ((H = malloc(sizeof(struct handshake_cookie))) == NULL) goto err0; H->callback = callback; H->cookie = cookie; H->s = s; H->decr = decr; H->nopfs = nopfs; H->requirepfs = requirepfs; H->K = K; /* Generate a 32-byte connection nonce. */ if (crypto_entropy_read(H->nonce_local, 32)) goto err1; /* Send our nonce. */ if ((H->write_cookie = network_write(s, H->nonce_local, 32, 32, callback_nonce_write, H)) == NULL) goto err1; /* Read the other party's nonce. */ if ((H->read_cookie = network_read(s, H->nonce_remote, 32, 32, callback_nonce_read, H)) == NULL) goto err2; /* Success! */ return (H); err2: network_write_cancel(H->write_cookie); err1: free(H); err0: /* Failure! */ return (NULL); } /* We've written our nonce. */ static int callback_nonce_write(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This write is no longer pending. */ H->write_cookie = NULL; /* Did we successfully write? */ if (len < 32) return (handshakefail(H)); /* If the nonce read is also done, move on to the next step. */ if (H->read_cookie == NULL) return (gotnonces(H)); /* Nothing to do. */ return (0); } /* We've read a nonce. */ static int callback_nonce_read(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This read is no longer pending. */ H->read_cookie = NULL; /* Did we successfully read? */ if (len < 32) return (handshakefail(H)); /* If the nonce write is also done, move on to the next step. */ if (H->write_cookie == NULL) return (gotnonces(H)); /* Nothing to do. */ return (0); } /* We have two nonces. Start the DH exchange. */ static int gotnonces(struct handshake_cookie * H) { /* Compute the diffie-hellman parameter MAC keys. */ proto_crypt_dhmac(H->K, H->nonce_local, H->nonce_remote, H->dhmac_local, H->dhmac_remote, H->decr); /* * If we're the server, we need to read the client's diffie-hellman * parameter. If we're the client, we need to generate and send our * diffie-hellman parameter. */ if (H->decr) return (dhread(H)); else return (dhwrite(H)); /* NOTREACHED */ } /* Read a diffie-hellman parameter. */ static int dhread(struct handshake_cookie * H) { /* Read the remote signed diffie-hellman parameter. */ if ((H->read_cookie = network_read(H->s, H->yh_remote, PCRYPT_YH_LEN, PCRYPT_YH_LEN, callback_dh_read, H)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* We have read a diffie-hellman parameter. */ static int callback_dh_read(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This read is no longer pending. */ H->read_cookie = NULL; /* Did we successfully read? */ if (len < PCRYPT_YH_LEN) return (handshakefail(H)); /* Is the value we read valid? */ if (proto_crypt_dh_validate(H->yh_remote, H->dhmac_remote, H->requirepfs)) return (handshakefail(H)); /* * If we're the server, we need to send our diffie-hellman parameter * next. If we're the client, move on to the final computation. */ if (H->decr) return (dhwrite(H)); else return (handshakedone(H)); /* NOTREACHED */ } /* Generate and write a diffie-hellman parameter. */ static int dhwrite(struct handshake_cookie * H) { /* Generate a signed diffie-hellman parameter. */ if (proto_crypt_dh_generate(H->yh_local, H->x, H->dhmac_local, H->nopfs)) goto err0; /* Write our signed diffie-hellman parameter. */ if ((H->write_cookie = network_write(H->s, H->yh_local, PCRYPT_YH_LEN, PCRYPT_YH_LEN, callback_dh_write, H)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* We have written our diffie-hellman parameter. */ static int callback_dh_write(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This write is no longer pending. */ H->write_cookie = NULL; /* Did we successfully write? */ if (len < PCRYPT_YH_LEN) return (handshakefail(H)); /* * If we're the server, move on to the final computation. If we're * the client, we need to read the server's parameter next. */ if (H->decr) return (handshakedone(H)); else return (dhread(H)); /* NOTREACHED */ } /* We've got all the bits; do the final computation and callback. */ static int handshakedone(struct handshake_cookie * H) { struct proto_keys * c; struct proto_keys * s; int rc; /* Sanity-check: There should be no callbacks in progress. */ assert(H->read_cookie == NULL); assert(H->write_cookie == NULL); /* Perform the final computation. */ if (proto_crypt_mkkeys(H->K, H->nonce_local, H->nonce_remote, H->yh_remote, H->x, H->nopfs, H->decr, &c, &s)) goto err0; /* Perform the callback. */ rc = (H->callback)(H->cookie, c, s); /* Free the cookie. */ free(H); /* Return status code from callback. */ return (rc); err0: /* Failure! */ return (-1); } /** * proto_handshake_cancel(cookie): * Cancel the handshake for which proto_handshake() returned ${cookie}. */ void proto_handshake_cancel(void * cookie) { struct handshake_cookie * H = cookie; /* Cancel any in-progress network operations. */ if (H->read_cookie != NULL) network_read_cancel(H->read_cookie); if (H->write_cookie != NULL) network_write_cancel(H->write_cookie); /* Free the cookie. */ free(H); } spiped-1.6.3/lib/proto/proto_pipe.h000644 001751 001751 00000001426 14650270210 020703 0ustar00cpercivacperciva000000 000000 #ifndef PROTO_PIPE_H_ #define PROTO_PIPE_H_ /* Opaque structure. */ struct proto_keys; /** * proto_pipe(s_in, s_out, decr, k, status, callback, cookie): * Read bytes from ${s_in} and write them to ${s_out}. If ${decr} is non-zero * then use ${k} to decrypt the bytes; otherwise use ${k} to encrypt them. * If EOF is read, set ${status} to 0, and if an error is encountered set * ${status} to -1; in either case, invoke ${callback}(${cookie}). Return a * cookie which can be passed to proto_pipe_cancel(). */ void * proto_pipe(int, int, int, struct proto_keys *, int *, int (*)(void *), void *); /** * proto_pipe_cancel(cookie): * Shut down the pipe created by proto_pipe() for which ${cookie} was returned. */ void proto_pipe_cancel(void *); #endif /* !PROTO_PIPE_H_ */ spiped-1.6.3/lib/proto/proto_crypt.c000644 001751 001751 00000025440 14650270210 021104 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "crypto_aes.h" #include "crypto_aesctr.h" #include "crypto_verify_bytes.h" #include "insecure_memzero.h" #include "sha256.h" #include "sysendian.h" #include "warnp.h" #include "proto_crypt.h" struct proto_secret { uint8_t K[32]; }; struct proto_keys { struct crypto_aes_key * k_aes; HMAC_SHA256_CTX ctx_init; uint64_t pnum; }; /** * mkkeypair(kbuf): * Convert the 64 bytes of ${kbuf} into a protocol key structure. */ #ifdef STANDALONE_ENC_TESTING struct proto_keys * mkkeypair(uint8_t kbuf[64]) #else static struct proto_keys * mkkeypair(uint8_t kbuf[64]) #endif { struct proto_keys * k; /* Allocate a structure. */ if ((k = malloc(sizeof(struct proto_keys))) == NULL) goto err0; /* Expand the AES key. */ if ((k->k_aes = crypto_aes_key_expand(&kbuf[0], 32)) == NULL) goto err1; /* Initialize the HMAC_SHA256 context. */ HMAC_SHA256_Init(&k->ctx_init, &kbuf[32], 32); /* The first packet will be packet number zero. */ k->pnum = 0; /* Success! */ return (k); err1: free(k); err0: /* Failure! */ return (NULL); } /** * proto_crypt_secret(filename): * Read the key file ${filename} and return a protocol secret structure. */ struct proto_secret * proto_crypt_secret(const char * filename) { SHA256_CTX ctx; FILE * f; struct proto_secret * K; uint8_t buf[BUFSIZ]; size_t lenread; /* Allocate a protocol secret structure. */ if ((K = malloc(sizeof(struct proto_secret))) == NULL) goto err0; /* Open the file, or use stdin if requested. */ if (strcmp(filename, STDIN_FILENAME) == 0) { f = stdin; } else if ((f = fopen(filename, "r")) == NULL) { warnp("Cannot open file: %s", filename); goto err1; } /* Initialize the SHA256 hash context. */ SHA256_Init(&ctx); /* Read the file until we hit EOF. */ while ((lenread = fread(buf, 1, BUFSIZ, f)) > 0) SHA256_Update(&ctx, buf, lenread); /* Did we hit EOF? */ if (!feof(f)) { if (f == stdin) { warnp("Error reading from stdin"); } else { warnp("Error reading file: %s", filename); } goto err2; } /* Close the file if it isn't stdin. */ if ((f != stdin) && fclose(f)) warnp("fclose"); /* Compute the final hash and wipe context state. */ SHA256_Final(K->K, &ctx); /* Success! */ return (K); err2: /* Close the file if it isn't stdin. */ if ((f != stdin) && fclose(f)) warnp("fclose"); /* Wipe context state. */ SHA256_Final(K->K, &ctx); err1: proto_crypt_secret_free(K); err0: /* Failure! */ return (NULL); } /** * proto_crypt_dhmac(K, nonce_l, nonce_r, dhmac_l, dhmac_r, decr): * Using the protocol secret ${K}, and the local and remote nonces ${nonce_l} * and ${nonce_r}, compute the local and remote diffie-hellman parameter MAC * keys ${dhmac_l} and ${dhmac_r}. If ${decr} is non-zero, "local" == "S" * and "remote" == "C"; otherwise the assignments are opposite. */ void proto_crypt_dhmac(const struct proto_secret * K, const uint8_t nonce_l[PCRYPT_NONCE_LEN], const uint8_t nonce_r[PCRYPT_NONCE_LEN], uint8_t dhmac_l[PCRYPT_DHMAC_LEN], uint8_t dhmac_r[PCRYPT_DHMAC_LEN], int decr) { uint8_t nonce_CS[PCRYPT_NONCE_LEN * 2]; uint8_t dk_1[PCRYPT_DHMAC_LEN * 2]; const uint8_t * nonce_c, * nonce_s; uint8_t * dhmac_c, * dhmac_s; /* Figure out how {c, s} maps to {l, r}. */ nonce_c = decr ? nonce_r : nonce_l; dhmac_c = decr ? dhmac_r : dhmac_l; nonce_s = decr ? nonce_l : nonce_r; dhmac_s = decr ? dhmac_l : dhmac_r; /* Copy in nonces (in the right order). */ memcpy(&nonce_CS[0], nonce_c, PCRYPT_NONCE_LEN); memcpy(&nonce_CS[PCRYPT_NONCE_LEN], nonce_s, PCRYPT_NONCE_LEN); /* Compute dk_1. */ PBKDF2_SHA256(K->K, 32, nonce_CS, PCRYPT_NONCE_LEN * 2, 1, dk_1, PCRYPT_DHMAC_LEN * 2); /* Copy out diffie-hellman parameter MAC keys (in the right order). */ memcpy(dhmac_c, &dk_1[0], PCRYPT_DHMAC_LEN); memcpy(dhmac_s, &dk_1[PCRYPT_DHMAC_LEN], PCRYPT_DHMAC_LEN); } /** * is_not_one(x, len): * Return non-zero if the big-endian value stored at (${x}, ${len}) is not * equal to 1. */ static int is_not_one(const uint8_t * x, size_t len) { size_t i; char y; for (i = 0, y = 0; i < len - 1; i++) { y |= x[i]; } return (y | (x[len - 1] - 1)); } /** * proto_crypt_dh_validate(yh_r, dhmac_r, requirepfs): * Return non-zero if the value ${yh_r} received from the remote party is not * correctly MACed using the diffie-hellman parameter MAC key ${dhmac_r}, or * if the included y value is >= the diffie-hellman group modulus, or if * ${requirepfs} is non-zero and the included y value is 1. */ int proto_crypt_dh_validate(const uint8_t yh_r[PCRYPT_YH_LEN], const uint8_t dhmac_r[PCRYPT_DHMAC_LEN], int requirepfs) { uint8_t hbuf[32]; /* Compute HMAC. */ HMAC_SHA256_Buf(dhmac_r, PCRYPT_DHMAC_LEN, yh_r, CRYPTO_DH_PUBLEN, hbuf); /* Check that the MAC matches. */ if (crypto_verify_bytes(&yh_r[CRYPTO_DH_PUBLEN], hbuf, 32)) return (1); /* Sanity-check the diffie-hellman value. */ if (crypto_dh_sanitycheck(&yh_r[0])) return (1); /* If necessary, enforce that the diffie-hellman value is != 1. */ if (requirepfs) { if (! is_not_one(&yh_r[0], CRYPTO_DH_PUBLEN)) return (1); } /* Everything is good. */ return (0); } /** * proto_crypt_dh_generate(yh_l, x, dhmac_l, nopfs): * Using the MAC key ${dhmac_l}, generate the MACed diffie-hellman handshake * parameter ${yh_l}. Store the diffie-hellman private value in ${x}. If * ${nopfs} is non-zero, skip diffie-hellman generation and use y = 1. */ int proto_crypt_dh_generate(uint8_t yh_l[PCRYPT_YH_LEN], uint8_t x[PCRYPT_X_LEN], const uint8_t dhmac_l[PCRYPT_DHMAC_LEN], int nopfs) { /* Are we skipping the diffie-hellman generation? */ if (nopfs) { /* Set y_l to a big-endian 1. */ memset(yh_l, 0, CRYPTO_DH_PUBLEN - 1); yh_l[CRYPTO_DH_PUBLEN - 1] = 1; } else { /* Generate diffie-hellman parameters x and y. */ if (crypto_dh_generate(yh_l, x)) goto err0; } /* Append an HMAC. */ HMAC_SHA256_Buf(dhmac_l, PCRYPT_DHMAC_LEN, yh_l, CRYPTO_DH_PUBLEN, &yh_l[CRYPTO_DH_PUBLEN]); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * proto_crypt_mkkeys(K, nonce_l, nonce_r, yh_r, x, nopfs, decr, eh_c, eh_s): * Using the protocol secret ${K}, the local and remote nonces ${nonce_l} and * ${nonce_r}, the remote MACed diffie-hellman handshake parameter ${yh_r}, * and the local diffie-hellman secret ${x}, generate the keys ${eh_c} and * ${eh_s}. If ${nopfs} is non-zero, we are performing weak handshaking and * y_SC is set to 1 rather than being computed. If ${decr} is non-zero, * "local" == "S" and "remote" == "C"; otherwise the assignments are opposite. */ int proto_crypt_mkkeys(const struct proto_secret * K, const uint8_t nonce_l[PCRYPT_NONCE_LEN], const uint8_t nonce_r[PCRYPT_NONCE_LEN], const uint8_t yh_r[PCRYPT_YH_LEN], const uint8_t x[PCRYPT_X_LEN], int nopfs, int decr, struct proto_keys ** eh_c, struct proto_keys ** eh_s) { uint8_t nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN]; uint8_t dk_2[128]; const uint8_t * nonce_c, * nonce_s; /* Copy in nonces (in the right order). */ nonce_c = decr ? nonce_r : nonce_l; nonce_s = decr ? nonce_l : nonce_r; memcpy(&nonce_y[0], nonce_c, PCRYPT_NONCE_LEN); memcpy(&nonce_y[PCRYPT_NONCE_LEN], nonce_s, PCRYPT_NONCE_LEN); /* Are we bypassing the diffie-hellman computation? */ if (nopfs) { /* We sent y_l = 1, so y_SC is also 1. */ memset(&nonce_y[PCRYPT_NONCE_LEN * 2], 0, CRYPTO_DH_KEYLEN - 1); nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN - 1] = 1; } else { /* Perform the diffie-hellman computation. */ if (crypto_dh_compute(yh_r, x, &nonce_y[PCRYPT_NONCE_LEN * 2])) goto err0; } /* Compute dk_2. */ PBKDF2_SHA256(K->K, 32, nonce_y, PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN, 1, dk_2, 128); /* Create key structures. */ if ((*eh_c = mkkeypair(&dk_2[0])) == NULL) goto err0; if ((*eh_s = mkkeypair(&dk_2[64])) == NULL) goto err1; /* Success! */ return (0); err1: proto_crypt_free(*eh_c); err0: /* Failure! */ return (-1); } /** * proto_crypt_enc(ibuf, len, obuf, k): * Encrypt ${len} bytes from ${ibuf} into PCRYPT_ESZ bytes using the keys in * ${k}, and write the result into ${obuf}. */ void proto_crypt_enc(uint8_t * ibuf, size_t len, uint8_t obuf[PCRYPT_ESZ], struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t pnum_exp[8]; /* Sanity-check the length. */ assert(len <= PCRYPT_MAXDSZ); /* Copy the decrypted data into the encrypted buffer. */ memcpy(obuf, ibuf, len); /* Pad up to PCRYPT_MAXDSZ with zeroes. */ memset(&obuf[len], 0, PCRYPT_MAXDSZ - len); /* Add the length. */ be32enc(&obuf[PCRYPT_MAXDSZ], (uint32_t)len); /* Encrypt the buffer in-place. */ crypto_aesctr_buf(k->k_aes, k->pnum, obuf, obuf, PCRYPT_MAXDSZ + 4); /* Copy the original (initialized) context. */ memcpy(&ctx, &k->ctx_init, sizeof(HMAC_SHA256_CTX)); /* Append an HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Update(&ctx, obuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(&obuf[PCRYPT_MAXDSZ + 4], &ctx); /* Increment packet number. */ k->pnum += 1; } /** * proto_crypt_dec(ibuf, obuf, k): * Decrypt PCRYPT_ESZ bytes from ${ibuf} using the keys in ${k}. If the data * is valid, write it into ${obuf} and return the length; otherwise, return * -1. */ ssize_t proto_crypt_dec(uint8_t ibuf[PCRYPT_ESZ], uint8_t * obuf, struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t hbuf[32]; uint8_t pnum_exp[8]; size_t len; /* Copy the original (initialized) context. */ memcpy(&ctx, &k->ctx_init, sizeof(HMAC_SHA256_CTX)); /* Verify HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Update(&ctx, ibuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(hbuf, &ctx); if (crypto_verify_bytes(hbuf, &ibuf[PCRYPT_MAXDSZ + 4], 32)) return (-1); /* Decrypt the buffer in-place. */ crypto_aesctr_buf(k->k_aes, k->pnum, ibuf, ibuf, PCRYPT_MAXDSZ + 4); /* Increment packet number. */ k->pnum += 1; /* Parse length. */ len = be32dec(&ibuf[PCRYPT_MAXDSZ]); /* Make sure nobody is being evil here... */ if ((len == 0) || (len > PCRYPT_MAXDSZ)) return (-1); /* Copy the bytes into the output buffer. */ memcpy(obuf, ibuf, len); /* Return the decrypted length. */ return ((ssize_t)len); } /** * proto_crypt_secret_free(K): * Free the protocol secret structure ${K}. */ void proto_crypt_secret_free(struct proto_secret * K) { /* Be compatible with free(NULL). */ if (K == NULL) return; /* Clear secret from the memory. */ insecure_memzero(K, sizeof(struct proto_secret)); /* Free the key structure. */ free(K); } /** * proto_crypt_free(k): * Free the protocol key structure ${k}. */ void proto_crypt_free(struct proto_keys * k) { /* Be compatible with free(NULL). */ if (k == NULL) return; /* Free the AES key. */ crypto_aes_key_free(k->k_aes); /* Free the key structure. */ free(k); } spiped-1.6.3/lib/proto/proto_conn.h000644 001751 001751 00000003474 14650270210 020710 0ustar00cpercivacperciva000000 000000 #ifndef PROTO_CONN_H_ #define PROTO_CONN_H_ /* Opaque structures. */ struct proto_secret; struct sock_addr; /* Reason why the connection was dropped. */ enum { PROTO_CONN_CLOSED = 0, /* Normal exit */ PROTO_CONN_CANCELLED, /* Exit triggered by client code */ PROTO_CONN_CONNECT_FAILED, /* Could not connect */ PROTO_CONN_HANDSHAKE_FAILED, /* Handshake failed */ PROTO_CONN_ERROR, /* Unspecified reason */ }; /** * proto_conn_create(s, sas, sa_b, decr, nopfs, requirepfs, nokeepalive, K, * timeo, callback_dead, cookie): * Create a connection with one end at ${s} and the other end connecting to * the target addresses ${sas}. Bind outgoing address to ${sa_b} if it * is not NULL. If ${decr} is 0, encrypt the outgoing data; if ${decr} is * nonzero, decrypt the incoming data. If ${nopfs} is non-zero, * don't use perfect forward secrecy. If ${requirepfs} is non-zero, drop * the connection if the other end tries to disable perfect forward secrecy. * Enable transport layer keep-alives (if applicable) on both sockets if and * only if ${nokeepalive} is zero. Drop the connection if the handshake or * connecting to the target takes more than ${timeo} seconds. When the * connection is dropped, invoke ${callback_dead}(${cookie}). Free ${sas} * once it is no longer needed. Return a cookie which can be passed to * proto_conn_drop(). If there is a connection error after this * function returns, close ${s}. */ void * proto_conn_create(int, struct sock_addr **, const struct sock_addr *, int, int, int, int, const struct proto_secret *, double, int (*)(void *, int), void *); /** * proto_conn_drop(conn_cookie, reason): * Drop connection and free memory associated with ${conn_cookie}, due to * ${reason}. Return success or failure. */ int proto_conn_drop(void *, int); #endif /* !PROTO_CONN_H_ */ spiped-1.6.3/lib/proto/proto_handshake.h000644 001751 001751 00000002326 14650270210 021674 0ustar00cpercivacperciva000000 000000 #ifndef PROTO_HANDSHAKE_H_ #define PROTO_HANDSHAKE_H_ /* Opaque structures. */ struct proto_keys; struct proto_secret; /** * proto_handshake(s, decr, nopfs, requirepfs, K, callback, cookie): * Perform a protocol handshake on socket ${s}. If ${decr} is non-zero we are * at the receiving end of the connection; otherwise at the sending end. If * ${nopfs} is non-zero, perform a "weak" handshake without perfect forward * secrecy. If ${requirepfs} is non-zero, drop the connection if the other * end attempts to perform a "weak" handshake. The shared protocol secret is * ${K}. Upon completion, invoke ${callback}(${cookie}, f, r), where f * contains the keys needed for the forward direction and r contains the keys * needed for the reverse direction; or f = r = NULL if the handshake failed. * Return a cookie which can be passed to proto_handshake_cancel() to cancel the * handshake. */ void * proto_handshake(int, int, int, int, const struct proto_secret *, int (*)(void *, struct proto_keys *, struct proto_keys *), void *); /** * proto_handshake_cancel(cookie): * Cancel the handshake for which proto_handshake() returned ${cookie}. */ void proto_handshake_cancel(void *); #endif /* !PROTO_HANDSHAKE_H_ */ spiped-1.6.3/lib/proto/proto_pipe.c000644 001751 001751 00000012335 14743020337 020705 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "netbuf.h" #include "network.h" #include "warnp.h" #include "proto_crypt.h" #include "proto_pipe.h" /* Maximum size of data to output in a single callback_pipe_read() call. */ #define OUTBUFSIZE (8 * PCRYPT_ESZ) struct pipe_cookie { int (* callback)(void *); void * cookie; int * status; int s_in; int s_out; int decr; struct proto_keys * k; uint8_t outbuf[OUTBUFSIZE]; struct netbuf_read * R; void * write_cookie; ssize_t wlen; size_t minread; size_t full_buflen; }; static int callback_pipe_read(void *, int); static int callback_pipe_write(void *, ssize_t); /** * proto_pipe(s_in, s_out, decr, k, status, callback, cookie): * Read bytes from ${s_in} and write them to ${s_out}. If ${decr} is non-zero * then use ${k} to decrypt the bytes; otherwise use ${k} to encrypt them. * If EOF is read, set ${status} to 0, and if an error is encountered set * ${status} to -1; in either case, invoke ${callback}(${cookie}). Return a * cookie which can be passed to proto_pipe_cancel(). */ void * proto_pipe(int s_in, int s_out, int decr, struct proto_keys * k, int * status, int (* callback)(void *), void * cookie) { struct pipe_cookie * P; /* Bake a cookie. */ if ((P = malloc(sizeof(struct pipe_cookie))) == NULL) goto err0; P->callback = callback; P->cookie = cookie; P->status = status; P->s_in = s_in; P->s_out = s_out; P->decr = decr; P->k = k; P->write_cookie = NULL; /* Initialize reader. */ if ((P->R = netbuf_read_init(P->s_in)) == NULL) goto err1; /* Set the minimum number of bytes to read. */ P->minread = P->decr ? PCRYPT_ESZ : 1; /* Set the number of bytes in a full buffer. */ P->full_buflen = P->decr ? PCRYPT_ESZ : PCRYPT_MAXDSZ; /* Start reading. */ if (netbuf_read_wait(P->R, P->minread, callback_pipe_read, P)) goto err2; /* Success! */ return (P); err2: netbuf_read_free(P->R); err1: free(P); err0: /* Failure! */ return (NULL); } /* Some data has been read. */ static int callback_pipe_read(void * cookie, int status) { struct pipe_cookie * P = cookie; uint8_t * inbuf; size_t inlen; size_t inpos = 0; size_t outpos = 0; size_t loop_inlen; ssize_t loop_outlen; /* Did we read EOF? */ if (status == 1) goto eof; /* Did the read fail? */ if (status == -1) goto fail; /* Get data. */ netbuf_read_peek(P->R, &inbuf, &inlen); /* Process as many packets as possible. */ while (inlen > 0) { /* Stop processing if we don't have space for more output. */ if (outpos + P->full_buflen > OUTBUFSIZE) break; /* How many bytes should we process this time? */ loop_inlen = (inlen > P->full_buflen) ? P->full_buflen : inlen; /* * If we don't have enough data to decrypt, leave it until the * next time callback_pipe_read() is called. */ if ((P->decr) && (loop_inlen < PCRYPT_ESZ)) break; /* Encrypt or decrypt the data. */ if (P->decr) { if ((loop_outlen = proto_crypt_dec(&inbuf[inpos], &P->outbuf[outpos], P->k)) == -1) goto fail; } else { proto_crypt_enc(&inbuf[inpos], loop_inlen, &P->outbuf[outpos], P->k); loop_outlen = PCRYPT_ESZ; } /* We've processed this data. */ inlen -= loop_inlen; inpos += loop_inlen; outpos += (size_t)loop_outlen; } /* Let netbuf layer know what we've used. */ netbuf_read_consume(P->R, inpos); /* Write the encrypted or decrypted data. */ P->wlen = (ssize_t)outpos; if ((P->write_cookie = network_write(P->s_out, P->outbuf, (size_t)P->wlen, (size_t)P->wlen, callback_pipe_write, P)) == NULL) goto err0; /* Success! */ return (0); fail: /* Record that this connection is broken. */ *(P->status) = -1; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); eof: /* We aren't going to write any more. */ if (shutdown(P->s_out, SHUT_WR)) { /* * We've already received an EOF, so it's no cause for concern * if the other side has already closed the connection. */ if (errno != ENOTCONN) { warnp("shutdown"); goto err0; } } /* Record that we have reached EOF. */ *(P->status) = 0; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); err0: /* Failure! */ return (-1); } static int callback_pipe_write(void * cookie, ssize_t len) { struct pipe_cookie * P = cookie; /* This write is no longer in progress. */ P->write_cookie = NULL; /* Did we fail to write everything? */ if (len < P->wlen) goto fail; /* Launch another read. */ if (netbuf_read_wait(P->R, P->minread, callback_pipe_read, P)) goto err0; /* Success! */ return (0); fail: /* Record that this connection is broken. */ *(P->status) = -1; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); err0: /* Failure! */ return (-1); } /** * proto_pipe_cancel(cookie): * Shut down the pipe created by proto_pipe() for which ${cookie} was returned. */ void proto_pipe_cancel(void * cookie) { struct pipe_cookie * P = cookie; /* If a read or write is in progress, cancel it. */ netbuf_read_wait_cancel(P->R); if (P->write_cookie) network_write_cancel(P->write_cookie); /* Clean up the buffered reader. */ netbuf_read_free(P->R); /* Free the cookie. */ free(P); } spiped-1.6.3/lib/proto/proto_conn.c000644 001751 001751 00000025753 14653532061 020717 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "events.h" #include "network.h" #include "sock.h" #include "warnp.h" #include "proto_crypt.h" #include "proto_handshake.h" #include "proto_pipe.h" #include "proto_conn.h" struct conn_state { int (* callback_dead)(void *, int); void * cookie; struct sock_addr ** sas; int decr; int nopfs; int requirepfs; int nokeepalive; const struct proto_secret * K; double timeo; int s; int t; void * connect_cookie; void * connect_timeout_cookie; void * handshake_cookie; void * handshake_timeout_cookie; struct proto_keys * k_f; struct proto_keys * k_r; void * pipe_f; void * pipe_r; int stat_f; int stat_r; }; static int callback_connect_done(void *, int); static int callback_connect_timeout(void *); static int callback_handshake_done(void *, struct proto_keys *, struct proto_keys *); static int callback_handshake_timeout(void *); static int callback_pipestatus(void *); /* Start a handshake. */ static int starthandshake(struct conn_state * C, int s, int decr) { /* Start the handshake timer. */ if ((C->handshake_timeout_cookie = events_timer_register_double( callback_handshake_timeout, C, C->timeo)) == NULL) goto err0; /* Start the handshake. */ if ((C->handshake_cookie = proto_handshake(s, decr, C->nopfs, C->requirepfs, C->K, callback_handshake_done, C)) == NULL) goto err1; /* Success! */ return (0); err1: events_timer_cancel(C->handshake_timeout_cookie); C->handshake_timeout_cookie = NULL; err0: /* Failure! */ return (-1); } /* Launch the two pipes. */ static int launchpipes(struct conn_state * C) { int on = C->nokeepalive ? 0 : 1; int one = 1; /* * Attempt to turn keepalives on or off as requested. We ignore * failures here since the sockets might not be of a type for which * SO_KEEPALIVE is valid -- it is a socket level option, but protocol * specific. In particular, it has no sensible meaning for UNIX * sockets. */ (void)setsockopt(C->s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); (void)setsockopt(C->t, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); /*- * Attempt to turn off nagling on both sockets. If the TCP stack has * enough window space that it is always able to send packets, then on * the encrypted end this will result in every 1060-byte spiped packet * getting its own TCP segment, including 40 bytes of TCP/IP headers; * this is fine. On the unencrypted end, we might send a single byte * of data with 40 bytes of TCP/IP headers; this is not so good. * * However, a write over the unencrypted connection will only happen * after an spiped packet has been read from the encrypted connection, * so the worst case is 80 bytes of TCP/IP headers per 1061 bytes of * TCP/IP payload (this may still be only a single byte of spiped * payload, but that is not relevant to the question of overhead from * small TCP/IP segments); and while the two sockets might not be on * the same network, if they are on different networks it is almost * guaranteed that the network over which the encrypted connection is * passing would be a wider-area network which is both less secure and * more expensive. Consequently, the maximum TCP/IP overhead ratio of * 80/1061 is almost certain to hold even with weighted byte costs. * * We ignore errors since (as with keep-alives) we may be dealing with * a non-TCP socket; and also because while POSIX requires TCP_NODELAY * to be defined, it is not required to be implemented as a socket * option. */ (void)setsockopt(C->s, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); (void)setsockopt(C->t, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); /* Create two pipes. */ if ((C->pipe_f = proto_pipe(C->s, C->t, C->decr, C->k_f, &C->stat_f, callback_pipestatus, C)) == NULL) goto err0; if ((C->pipe_r = proto_pipe(C->t, C->s, !C->decr, C->k_r, &C->stat_r, callback_pipestatus, C)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * proto_conn_drop(conn_cookie, reason): * Drop connection and free memory associated with ${conn_cookie}, due to * ${reason}. Return success or failure. */ int proto_conn_drop(void * conn_cookie, int reason) { struct conn_state * C = conn_cookie; int rc; /* Close the incoming connection. */ if (close(C->s)) warnp("close"); /* Close the outgoing connection if it is open. */ if ((C->t != -1) && close(C->t)) warnp("close"); /* Stop connecting if a connection is in progress. */ if (C->connect_cookie != NULL) network_connect_cancel(C->connect_cookie); /* Free the target addresses if we haven't already done so. */ sock_addr_freelist(C->sas); /* Stop handshaking if a handshake is in progress. */ if (C->handshake_cookie != NULL) proto_handshake_cancel(C->handshake_cookie); /* Kill timeouts if they are pending. */ if (C->connect_timeout_cookie != NULL) events_timer_cancel(C->connect_timeout_cookie); if (C->handshake_timeout_cookie != NULL) events_timer_cancel(C->handshake_timeout_cookie); /* Free protocol keys. */ proto_crypt_free(C->k_f); proto_crypt_free(C->k_r); /* Shut down pipes. */ if (C->pipe_f != NULL) proto_pipe_cancel(C->pipe_f); if (C->pipe_r != NULL) proto_pipe_cancel(C->pipe_r); /* Notify the upstream that we've dropped a connection. */ rc = (C->callback_dead)(C->cookie, reason); /* Free the connection cookie. */ free(C); /* Return success/fail status. */ return (rc); } /** * proto_conn_create(s, sas, sa_b, decr, nopfs, requirepfs, nokeepalive, K, * timeo, callback_dead, cookie): * Create a connection with one end at ${s} and the other end connecting to * the target addresses ${sas}. Bind outgoing address to ${sa_b} if it * is not NULL. If ${decr} is 0, encrypt the outgoing data; if ${decr} is * nonzero, decrypt the incoming data. If ${nopfs} is non-zero, * don't use perfect forward secrecy. If ${requirepfs} is non-zero, drop * the connection if the other end tries to disable perfect forward secrecy. * Enable transport layer keep-alives (if applicable) on both sockets if and * only if ${nokeepalive} is zero. Drop the connection if the handshake or * connecting to the target takes more than ${timeo} seconds. When the * connection is dropped, invoke ${callback_dead}(${cookie}). Free ${sas} * once it is no longer needed. Return a cookie which can be passed to * proto_conn_drop(). If there is a connection error after this * function returns, close ${s}. */ void * proto_conn_create(int s, struct sock_addr ** sas, const struct sock_addr * sa_b, int decr, int nopfs, int requirepfs, int nokeepalive, const struct proto_secret * K, double timeo, int (* callback_dead)(void *, int), void * cookie) { struct conn_state * C; /* Bake a cookie for this connection. */ if ((C = malloc(sizeof(struct conn_state))) == NULL) goto err0; C->callback_dead = callback_dead; C->cookie = cookie; C->sas = sas; C->decr = decr; C->nopfs = nopfs; C->requirepfs = requirepfs; C->nokeepalive = nokeepalive; C->K = K; C->timeo = timeo; C->s = s; C->t = -1; C->connect_cookie = NULL; C->connect_timeout_cookie = NULL; C->handshake_cookie = NULL; C->handshake_timeout_cookie = NULL; C->k_f = C->k_r = NULL; C->pipe_f = C->pipe_r = NULL; C->stat_f = C->stat_r = 1; /* Start the connect timer. */ if ((C->connect_timeout_cookie = events_timer_register_double( callback_connect_timeout, C, C->timeo)) == NULL) goto err1; /* Connect to target. */ if ((C->connect_cookie = network_connect_bind(C->sas, sa_b, callback_connect_done, C)) == NULL) goto err2; /* If we're decrypting, start the handshake. */ if (C->decr) { if (starthandshake(C, C->s, C->decr)) goto err3; } /* Success! */ return (C); err3: network_connect_cancel(C->connect_cookie); err2: events_timer_cancel(C->connect_timeout_cookie); err1: free(C); err0: /* Failure! */ return (NULL); } /* We have connected to the target. */ static int callback_connect_done(void * cookie, int t) { struct conn_state * C = cookie; /* This connection attempt is no longer pending. */ C->connect_cookie = NULL; /* Don't need the target address any more. */ sock_addr_freelist(C->sas); C->sas = NULL; /* We beat the clock. */ events_timer_cancel(C->connect_timeout_cookie); C->connect_timeout_cookie = NULL; /* Did we manage to connect? */ if ((C->t = t) == -1) return (proto_conn_drop(C, PROTO_CONN_CONNECT_FAILED)); /* If we're encrypting, start the handshake. */ if (!C->decr) { if (starthandshake(C, C->t, C->decr)) goto err1; } /* If the handshake already finished, start shuttling data. */ if ((C->t != -1) && (C->k_f != NULL) && (C->k_r != NULL)) { if (launchpipes(C)) goto err1; } /* Success! */ return (0); err1: proto_conn_drop(C, PROTO_CONN_ERROR); /* Failure! */ return (-1); } /* Connecting to the target took too long. */ static int callback_connect_timeout(void * cookie) { struct conn_state * C = cookie; /* This timeout is no longer pending. */ C->connect_timeout_cookie = NULL; /* * We could free C->sas here, but from a semantic point of view it * could still be in use by the not-yet-cancelled connect operation. * Instead, we free it in proto_conn_drop, after cancelling the * connect. */ /* Drop the connection. */ return (proto_conn_drop(C, PROTO_CONN_ERROR)); } /* We have performed the protocol handshake. */ static int callback_handshake_done(void * cookie, struct proto_keys * f, struct proto_keys * r) { struct conn_state * C = cookie; /* The handshake is no longer in progress. */ C->handshake_cookie = NULL; /* We beat the clock. */ events_timer_cancel(C->handshake_timeout_cookie); C->handshake_timeout_cookie = NULL; /* If the protocol handshake failed, drop the connection. */ if ((f == NULL) && (r == NULL)) return (proto_conn_drop(C, PROTO_CONN_HANDSHAKE_FAILED)); /* We should have two keys. */ assert(f != NULL); assert(r != NULL); /* Record the keys so we can free them later. */ C->k_f = f; C->k_r = r; /* If we already connected to the target, start shuttling data. */ if ((C->t != -1) && (C->k_f != NULL) && (C->k_r != NULL)) { if (launchpipes(C)) goto err1; } /* Success! */ return (0); err1: proto_conn_drop(C, PROTO_CONN_ERROR); /* Failure! */ return (-1); } /* The protocol handshake took too long. */ static int callback_handshake_timeout(void * cookie) { struct conn_state * C = cookie; /* This timeout is no longer pending. */ C->handshake_timeout_cookie = NULL; /* Drop the connection. */ return (proto_conn_drop(C, PROTO_CONN_ERROR)); } /* The status of one of the directions has changed. */ static int callback_pipestatus(void * cookie) { struct conn_state * C = cookie; /* If we have an error in either direction, kill the connection. */ if ((C->stat_f == -1) || (C->stat_r == -1)) return (proto_conn_drop(C, PROTO_CONN_ERROR)); /* If both directions have been shut down, kill the connection. */ if ((C->stat_f == 0) && (C->stat_r == 0)) return (proto_conn_drop(C, PROTO_CONN_CLOSED)); /* Nothing to do. */ return (0); } spiped-1.6.3/lib/proto/proto_crypt.h000644 001751 001751 00000010014 14650270210 021100 0ustar00cpercivacperciva000000 000000 #ifndef PROTO_CRYPT_H_ #define PROTO_CRYPT_H_ #include #include #include "crypto_dh.h" /* Opaque structures. */ struct proto_keys; struct proto_secret; /* Size of nonce. */ #define PCRYPT_NONCE_LEN 32 /* Size of temporary MAC keys used for Diffie-Hellman parameters. */ #define PCRYPT_DHMAC_LEN 32 /* Size of private Diffie-Hellman value. */ #define PCRYPT_X_LEN CRYPTO_DH_PRIVLEN /* Size of MACed Diffie-Hellman parameter. */ #define PCRYPT_YH_LEN (CRYPTO_DH_PUBLEN + 32) /* Filename for stdin. */ #define STDIN_FILENAME "-" /** * proto_crypt_secret(filename): * Read the key file ${filename} and return a protocol secret structure. */ struct proto_secret * proto_crypt_secret(const char *); /** * proto_crypt_dhmac(K, nonce_l, nonce_r, dhmac_l, dhmac_r, decr): * Using the protocol secret ${K}, and the local and remote nonces ${nonce_l} * and ${nonce_r}, compute the local and remote diffie-hellman parameter MAC * keys ${dhmac_l} and ${dhmac_r}. If ${decr} is non-zero, "local" == "S" * and "remote" == "C"; otherwise the assignments are opposite. */ void proto_crypt_dhmac(const struct proto_secret *, const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_NONCE_LEN], uint8_t[PCRYPT_DHMAC_LEN], uint8_t[PCRYPT_DHMAC_LEN], int); /** * proto_crypt_dh_validate(yh_r, dhmac_r, requirepfs): * Return non-zero if the value ${yh_r} received from the remote party is not * correctly MACed using the diffie-hellman parameter MAC key ${dhmac_r}, or * if the included y value is >= the diffie-hellman group modulus, or if * ${requirepfs} is non-zero and the included y value is 1. */ int proto_crypt_dh_validate(const uint8_t[PCRYPT_YH_LEN], const uint8_t[PCRYPT_DHMAC_LEN], int); /** * proto_crypt_dh_generate(yh_l, x, dhmac_l, nopfs): * Using the MAC key ${dhmac_l}, generate the MACed diffie-hellman handshake * parameter ${yh_l}. Store the diffie-hellman private value in ${x}. If * ${nopfs} is non-zero, skip diffie-hellman generation and use y = 1. */ int proto_crypt_dh_generate(uint8_t[PCRYPT_YH_LEN], uint8_t[PCRYPT_X_LEN], const uint8_t[PCRYPT_DHMAC_LEN], int); /** * proto_crypt_mkkeys(K, nonce_l, nonce_r, yh_r, x, nopfs, decr, eh_c, eh_s): * Using the protocol secret ${K}, the local and remote nonces ${nonce_l} and * ${nonce_r}, the remote MACed diffie-hellman handshake parameter ${yh_r}, * and the local diffie-hellman secret ${x}, generate the keys ${eh_c} and * ${eh_s}. If ${nopfs} is non-zero, we are performing weak handshaking and * y_SC is set to 1 rather than being computed. If ${decr} is non-zero, * "local" == "S" and "remote" == "C"; otherwise the assignments are opposite. */ int proto_crypt_mkkeys(const struct proto_secret *, const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_YH_LEN], const uint8_t[PCRYPT_X_LEN], int, int, struct proto_keys **, struct proto_keys **); /* Maximum size of an unencrypted packet. */ #define PCRYPT_MAXDSZ 1024 /* Size of an encrypted packet. */ #define PCRYPT_ESZ (PCRYPT_MAXDSZ + 4 /* len */ + 32 /* hmac */) /** * proto_crypt_enc(ibuf, len, obuf, k): * Encrypt ${len} bytes from ${ibuf} into PCRYPT_ESZ bytes using the keys in * ${k}, and write the result into ${obuf}. */ void proto_crypt_enc(uint8_t *, size_t, uint8_t[PCRYPT_ESZ], struct proto_keys *); /** * proto_crypt_dec(ibuf, obuf, k): * Decrypt PCRYPT_ESZ bytes from ${ibuf} using the keys in ${k}. If the data * is valid, write it into ${obuf} and return the length; otherwise, return * -1. */ ssize_t proto_crypt_dec(uint8_t[PCRYPT_ESZ], uint8_t *, struct proto_keys *); /** * proto_crypt_secret_free(K): * Free the protocol secret structure ${K}. */ void proto_crypt_secret_free(struct proto_secret *); /** * proto_crypt_free(k): * Free the protocol key structure ${k}. */ void proto_crypt_free(struct proto_keys *); #ifdef STANDALONE_ENC_TESTING /** * mkkeypair(kbuf): * Convert the 64 bytes of ${kbuf} into a protocol key structure. */ struct proto_keys * mkkeypair(uint8_t kbuf[64]); #endif #endif /* !PROTO_CRYPT_H_ */ spiped-1.6.3/libcperciva/crypto/000755 001751 001751 00000000000 14650270210 020241 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/network/000755 001751 001751 00000000000 14650270210 020412 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/alg/000755 001751 001751 00000000000 14743020337 017472 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/datastruct/000755 001751 001751 00000000000 14743020337 021105 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/util/000755 001751 001751 00000000000 14743020337 017704 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/events/000755 001751 001751 00000000000 14650270210 020225 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/POSIX/000755 001751 001751 00000000000 14653533105 017633 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/apisupport/000755 001751 001751 00000000000 14650270210 021127 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/netbuf/000755 001751 001751 00000000000 14743020337 020212 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/cpusupport/000755 001751 001751 00000000000 14743020337 021153 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/external/000755 001751 001751 00000000000 14650270210 020543 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/external/queue/000755 001751 001751 00000000000 14650270210 021667 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/external/queue/queue.h000644 001751 001751 00000054776 14650270210 023207 0ustar00cpercivacperciva000000 000000 /* $NetBSD: queue.h,v 1.75.2.1 2021/04/03 22:29:03 thorpej Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef SYS_QUEUE_H_ #define SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * A singly-linked list is headed by a single forward pointer. The * elements are singly linked for minimum space and pointer manipulation * overhead at the expense of O(n) removal for arbitrary elements. New * elements can be added to the list after an existing element or at the * head of the list. Elements being removed from the head of the list * should use the explicit macro for this purpose for optimum * efficiency. A singly-linked list may only be traversed in the forward * direction. Singly-linked lists are ideal for applications with large * datasets and few or no removals or for implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * For details on the use of these macros, see the queue(3) manual page. */ /* * Include the definition of NULL only on NetBSD because sys/null.h * is not available elsewhere. This conditional makes the header * portable and it can simply be dropped verbatim into any system. * The caveat is that on other systems some other header * must provide NULL before the macros can be used. */ #ifdef __NetBSD__ #include #endif #if defined(_KERNEL) && defined(DIAGNOSTIC) #define QUEUEDEBUG 1 #endif #if defined(QUEUEDEBUG) # if defined(_KERNEL) # define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__) # else # include # define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__) # endif #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = (head)->slh_first; \ (var) != SLIST_END(head); \ (var) = (var)->field.sle_next) #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = SLIST_FIRST((head)); \ (var) != SLIST_END(head) && \ ((tvar) = SLIST_NEXT((var), field), 1); \ (var) = (tvar)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) do { \ (head)->slh_first = SLIST_END(head); \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE_AFTER(slistelm, field) do { \ (slistelm)->field.sle_next = \ SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (/*CONSTCOND*/0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = (head)->slh_first; \ while(curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ } while (/*CONSTCOND*/0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods. */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for ((var) = ((head)->lh_first); \ (var) != LIST_END(head); \ (var) = ((var)->field.le_next)) #define LIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = LIST_FIRST((head)); \ (var) != LIST_END(head) && \ ((tvar) = LIST_NEXT((var), field), 1); \ (var) = (tvar)) #define LIST_MOVE(head1, head2, field) do { \ LIST_INIT((head2)); \ if (!LIST_EMPTY((head1))) { \ (head2)->lh_first = (head1)->lh_first; \ (head2)->lh_first->field.le_prev = &(head2)->lh_first; \ LIST_INIT((head1)); \ } \ } while (/*CONSTCOND*/0) /* * List functions. */ #if defined(QUEUEDEBUG) #define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ if ((head)->lh_first && \ (head)->lh_first->field.le_prev != &(head)->lh_first) \ QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ __FILE__, __LINE__); #define QUEUEDEBUG_LIST_OP(elm, field) \ if ((elm)->field.le_next && \ (elm)->field.le_next->field.le_prev != \ &(elm)->field.le_next) \ QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ __FILE__, __LINE__); \ if (*(elm)->field.le_prev != (elm)) \ QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ __FILE__, __LINE__); #define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ (elm)->field.le_next = (void *)1L; \ (elm)->field.le_prev = (void *)1L; #else #define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) #define QUEUEDEBUG_LIST_OP(elm, field) #define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) #endif #define LIST_INIT(head) do { \ (head)->lh_first = LIST_END(head); \ } while (/*CONSTCOND*/0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ QUEUEDEBUG_LIST_OP((listelm), field) \ if (((elm)->field.le_next = (listelm)->field.le_next) != \ LIST_END(head)) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ QUEUEDEBUG_LIST_OP((listelm), field) \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (/*CONSTCOND*/0) #define LIST_INSERT_HEAD(head, elm, field) do { \ QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (/*CONSTCOND*/0) #define LIST_REMOVE(elm, field) do { \ QUEUEDEBUG_LIST_OP((elm), field) \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ } while (/*CONSTCOND*/0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ } while (/*CONSTCOND*/0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for ((var) = ((head)->sqh_first); \ (var) != SIMPLEQ_END(head); \ (var) = ((var)->field.sqe_next)) #define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \ for ((var) = ((head)->sqh_first); \ (var) != SIMPLEQ_END(head) && \ ((next = ((var)->field.sqe_next)), 1); \ (var) = (next)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (/*CONSTCOND*/0) #define SIMPLEQ_REMOVE(head, elm, type, field) do { \ if ((head)->sqh_first == (elm)) { \ SIMPLEQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->sqh_first; \ while (curelm->field.sqe_next != (elm)) \ curelm = curelm->field.sqe_next; \ if ((curelm->field.sqe_next = \ curelm->field.sqe_next->field.sqe_next) == NULL) \ (head)->sqh_last = &(curelm)->field.sqe_next; \ } \ } while (/*CONSTCOND*/0) #define SIMPLEQ_CONCAT(head1, head2) do { \ if (!SIMPLEQ_EMPTY((head2))) { \ *(head1)->sqh_last = (head2)->sqh_first; \ (head1)->sqh_last = (head2)->sqh_last; \ SIMPLEQ_INIT((head2)); \ } \ } while (/*CONSTCOND*/0) #define SIMPLEQ_LAST(head, type, field) \ (SIMPLEQ_EMPTY((head)) ? \ NULL : \ ((struct type *)(void *) \ ((char *)((head)->sqh_last) - offsetof(struct type, field)))) /* * Tail queue definitions. */ #define TAILQ_HEAD_(name, type, qual) \ struct name { \ qual type *tqh_first; /* first element */ \ qual type *qual *tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD(name, type) TAILQ_HEAD_(name, struct type,) #define TAILQ_HEAD_INITIALIZER(head) \ { TAILQ_END(head), &(head).tqh_first } #define TAILQ_ENTRY_(type, qual) \ struct { \ qual type *tqe_next; /* next element */ \ qual type *qual *tqe_prev; /* address of previous next element */\ } #define TAILQ_ENTRY(type) TAILQ_ENTRY_(struct type,) /* * Tail queue access methods. */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) (NULL) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)(void *)((head)->tqh_last))->tqh_last)) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)(void *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->tqh_first); \ (var) != TAILQ_END(head); \ (var) = ((var)->field.tqe_next)) #define TAILQ_FOREACH_SAFE(var, head, field, next) \ for ((var) = ((head)->tqh_first); \ (var) != TAILQ_END(head) && \ ((next) = TAILQ_NEXT(var, field), 1); (var) = (next)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = TAILQ_LAST((head), headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV((var), headname, field)) #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ for ((var) = TAILQ_LAST((head), headname); \ (var) != TAILQ_END(head) && \ ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev)) /* * Tail queue functions. */ #if defined(QUEUEDEBUG) #define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ if ((head)->tqh_first && \ (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \ __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ if (*(head)->tqh_last != NULL) \ QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \ __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_OP(elm, field) \ if ((elm)->field.tqe_next && \ (elm)->field.tqe_next->field.tqe_prev != \ &(elm)->field.tqe_next) \ QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \ __FILE__, __LINE__); \ if (*(elm)->field.tqe_prev != (elm)) \ QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \ __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ if ((elm)->field.tqe_next == NULL && \ (head)->tqh_last != &(elm)->field.tqe_next) \ QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\ (head), (elm), __FILE__, __LINE__); #define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ (elm)->field.tqe_next = (void *)1L; \ (elm)->field.tqe_prev = (void *)1L; #else #define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) #define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) #define QUEUEDEBUG_TAILQ_OP(elm, field) #define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) #define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) #endif #define TAILQ_INIT(head) do { \ (head)->tqh_first = TAILQ_END(head); \ (head)->tqh_last = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ (elm)->field.tqe_next = TAILQ_END(head); \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ QUEUEDEBUG_TAILQ_OP((listelm), field) \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \ TAILQ_END(head)) \ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ QUEUEDEBUG_TAILQ_OP((listelm), field) \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (/*CONSTCOND*/0) #define TAILQ_REMOVE(head, elm, field) do { \ QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ QUEUEDEBUG_TAILQ_OP((elm), field) \ if (((elm)->field.tqe_next) != TAILQ_END(head)) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ } while (/*CONSTCOND*/0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \ TAILQ_END(head)) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ } while (/*CONSTCOND*/0) #define TAILQ_CONCAT(head1, head2, field) do { \ if (!TAILQ_EMPTY(head2)) { \ *(head1)->tqh_last = (head2)->tqh_first; \ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ (head1)->tqh_last = (head2)->tqh_last; \ TAILQ_INIT((head2)); \ } \ } while (/*CONSTCOND*/0) /* * Singly-linked Tail queue declarations. */ #define STAILQ_HEAD(name, type) \ struct name { \ struct type *stqh_first; /* first element */ \ struct type **stqh_last; /* addr of last next element */ \ } #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } #define STAILQ_ENTRY(type) \ struct { \ struct type *stqe_next; /* next element */ \ } /* * Singly-linked Tail queue access methods. */ #define STAILQ_FIRST(head) ((head)->stqh_first) #define STAILQ_END(head) NULL #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) /* * Singly-linked Tail queue functions. */ #define STAILQ_INIT(head) do { \ (head)->stqh_first = NULL; \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ (head)->stqh_last = &(elm)->field.stqe_next; \ (head)->stqh_first = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.stqe_next = NULL; \ *(head)->stqh_last = (elm); \ (head)->stqh_last = &(elm)->field.stqe_next; \ } while (/*CONSTCOND*/0) #define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ (head)->stqh_last = &(elm)->field.stqe_next; \ (listelm)->field.stqe_next = (elm); \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE_HEAD(head, field) do { \ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ (head)->stqh_last = &(head)->stqh_first; \ } while (/*CONSTCOND*/0) #define STAILQ_REMOVE(head, elm, type, field) do { \ if ((head)->stqh_first == (elm)) { \ STAILQ_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->stqh_first; \ while (curelm->field.stqe_next != (elm)) \ curelm = curelm->field.stqe_next; \ if ((curelm->field.stqe_next = \ curelm->field.stqe_next->field.stqe_next) == NULL) \ (head)->stqh_last = &(curelm)->field.stqe_next; \ } \ } while (/*CONSTCOND*/0) #define STAILQ_FOREACH(var, head, field) \ for ((var) = ((head)->stqh_first); \ (var); \ (var) = ((var)->field.stqe_next)) #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = STAILQ_FIRST((head)); \ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ (var) = (tvar)) #define STAILQ_CONCAT(head1, head2) do { \ if (!STAILQ_EMPTY((head2))) { \ *(head1)->stqh_last = (head2)->stqh_first; \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_INIT((head2)); \ } \ } while (/*CONSTCOND*/0) #define STAILQ_LAST(head, type, field) \ (STAILQ_EMPTY((head)) ? \ NULL : \ ((struct type *)(void *) \ ((char *)((head)->stqh_last) - offsetof(struct type, field)))) #endif /* !SYS_QUEUE_H_ */ spiped-1.6.3/libcperciva/cpusupport/cpusupport_x86_rdrand.c000644 001751 001751 00000001142 14743020337 025600 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_X86_CPUID #include #define CPUID_RDRAND_BIT (1 << 30) #endif CPUSUPPORT_FEATURE_DECL(x86, rdrand) { #ifdef CPUSUPPORT_X86_CPUID unsigned int eax, ebx, ecx, edx; /* Check if CPUID supports the level we need. */ if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) goto unsupported; if (eax < 1) goto unsupported; /* Ask about CPU features. */ if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) goto unsupported; /* Return the relevant feature bit. */ return ((ecx & CPUID_RDRAND_BIT) ? 1 : 0); unsupported: #endif /* Not supported. */ return (0); } spiped-1.6.3/libcperciva/cpusupport/cpusupport_x86_shani.c000644 001751 001751 00000001533 14743020337 025434 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_X86_CPUID_COUNT #include #define CPUID_SHANI_BIT (1 << 29) #endif CPUSUPPORT_FEATURE_DECL(x86, shani) { #ifdef CPUSUPPORT_X86_CPUID_COUNT unsigned int eax, ebx, ecx, edx; /* Check if CPUID supports the level we need. */ if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) goto unsupported; if (eax < 7) goto unsupported; /* * Ask about extended CPU features. Note that this macro violates * the principle of being "function-like" by taking the variables * used for holding output registers as named parameters rather than * as pointers (which would be necessary if __cpuid_count were a * function). */ __cpuid_count(7, 0, eax, ebx, ecx, edx); /* Return the relevant feature bit. */ return ((ebx & CPUID_SHANI_BIT) ? 1 : 0); unsupported: #endif /* Not supported. */ return (0); } spiped-1.6.3/libcperciva/cpusupport/cpusupport.h000644 001751 001751 00000015336 14650270210 023552 0ustar00cpercivacperciva000000 000000 #ifndef CPUSUPPORT_H_ #define CPUSUPPORT_H_ /* * To enable support for non-portable CPU features at compile time, one or * more CPUSUPPORT_ARCH_FEATURE macros should be defined. This can be done * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h * (or similar) can be provided to include that file here. */ #ifdef CPUSUPPORT_CONFIG_FILE #include CPUSUPPORT_CONFIG_FILE #endif /** * The CPUSUPPORT_FEATURE macro declares the necessary variables and * functions for detecting CPU feature support at run time. The function * defined in the macro acts to cache the result of the ..._detect function * using the ..._present and ..._init variables. The _detect function and the * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in * appropriate cpusupport_foo_bar.c file. * * In order to allow CPUSUPPORT_FEATURE to be used for features which do not * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file, * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then * we access _present_1, _init_1, and _detect_1; but if it is not defined, we * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus * preventing the compiler from emitting a reference to an external symbol. * * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations * for nonexistent features without running afoul of the requirement that * "If an identifier declared with external linkage is used... in the entire * program there shall be exactly one external definition" (C99 standard, 6.9 * paragraph 5). In practice, this means that users of the cpusupport code * can omit build and runtime detection files without changing the framework * code. */ #define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) \ static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); } \ extern int cpusupport_ ## arch_feature ## _present_ ## enabled; \ extern int cpusupport_ ## arch_feature ## _init_ ## enabled; \ int cpusupport_ ## arch_feature ## _detect_ ## enabled(void); \ \ static inline int \ cpusupport_ ## arch_feature(void) \ { \ \ if (cpusupport_ ## arch_feature ## _present_ ## enabled) \ return (1); \ else if (cpusupport_ ## arch_feature ## _init_ ## enabled) \ return (0); \ cpusupport_ ## arch_feature ## _present_ ## enabled = \ cpusupport_ ## arch_feature ## _detect_ ## enabled(); \ cpusupport_ ## arch_feature ## _init_ ## enabled = 1; \ return (cpusupport_ ## arch_feature ## _present_ ## enabled); \ } \ static void (* cpusupport_ ## arch_feature ## _dummyptr)(void); \ static inline void \ cpusupport_ ## arch_feature ## _dummyfunc(void) \ { \ \ (void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler; \ (void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler; \ (void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler; \ (void)cpusupport_ ## arch_feature ## _present_ ## enabled; \ (void)cpusupport_ ## arch_feature ## _init_ ## enabled; \ (void)cpusupport_ ## arch_feature ## _detect_ ## enabled; \ (void)cpusupport_ ## arch_feature ## _dummyptr; \ } \ static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc; \ struct cpusupport_ ## arch_feature ## _dummy #define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled) \ CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled) #define CPUSUPPORT_FEATURE(arch, feature, enabler) \ CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler) /** * CPUSUPPORT_FEATURE_DECL(arch, feature): * Macro which defines variables and provides a function declaration for * detecting the presence of "feature" on the "arch" architecture. The * function body following this macro expansion must return nonzero if the * feature is present, or zero if the feature is not present or the detection * fails for any reason. */ #define CPUSUPPORT_FEATURE_DECL(arch, feature) \ extern int cpusupport_ ## arch ## _ ## feature ## _present_1; \ extern int cpusupport_ ## arch ## _ ## feature ## _init_1; \ int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0; \ int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0; \ int cpusupport_ ## arch ## _ ## feature ## _detect_1(void); \ int \ cpusupport_ ## arch ## _ ## feature ## _detect_1(void) /** * CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, check): * Check if we can enable ${success_value}, given the ${cpusupport_checks} and * ${check}; if so, write to ${hwvar}. If the ${cpusupport_checks} pass but * the ${check} is non-zero, produce a warning which includes a stringified * ${success_value}, then fallthrough. */ #define CPUSUPPORT_VALIDATE(hwvar, success_value, cpusupport_checks, \ check) do { \ if ((cpusupport_checks)) { \ if ((check) == 0) { \ (hwvar) = (success_value); \ return; \ } else { \ warn0("Disabling " #success_value \ " due to failed self-test"); \ } \ } \ } while (0) /** * List of features. If a feature here is not enabled by the appropriate * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the * corresponding run-time detection code (cpusupport_arch_feature.c) must be * compiled and linked in. * * There are a few features for which we do not have run-time checks: * - X86_CPUID: compile-time is enough; if __get_cpuid() fails, then all the * x86 detection features will fail, but there's nothing we can * do about that. * - X86_CPUID_COUNT: ditto. * - X86_SSE42_64: the cpuid check tells us if the CPU supports SSE4.2, but * that says nothing about whether it's in 64-bit mode. */ CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI); CPUSUPPORT_FEATURE(x86, rdrand, X86_RDRAND); CPUSUPPORT_FEATURE(x86, shani, X86_SHANI); CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2); CPUSUPPORT_FEATURE(x86, sse42, X86_SSE42); CPUSUPPORT_FEATURE(x86, ssse3, X86_SSSE3); CPUSUPPORT_FEATURE(arm, aes, ARM_AES); CPUSUPPORT_FEATURE(arm, crc32_64, ARM_CRC32_64); CPUSUPPORT_FEATURE(arm, sha256, ARM_SHA256); #endif /* !CPUSUPPORT_H_ */ spiped-1.6.3/libcperciva/cpusupport/Build/000755 001751 001751 00000000000 14743020337 022212 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/cpusupport/cpusupport_x86_ssse3.c000644 001751 001751 00000001136 14743020337 025371 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_X86_CPUID #include #define CPUID_SSSE3_BIT (1 << 9) #endif CPUSUPPORT_FEATURE_DECL(x86, ssse3) { #ifdef CPUSUPPORT_X86_CPUID unsigned int eax, ebx, ecx, edx; /* Check if CPUID supports the level we need. */ if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) goto unsupported; if (eax < 1) goto unsupported; /* Ask about CPU features. */ if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) goto unsupported; /* Return the relevant feature bit. */ return ((ecx & CPUID_SSSE3_BIT) ? 1 : 0); unsupported: #endif /* Not supported. */ return (0); } spiped-1.6.3/libcperciva/cpusupport/cpusupport_arm_aes.c000644 001751 001751 00000002711 14101630450 025222 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_HWCAP_GETAUXVAL #include #if defined(__arm__) /** * Workaround for a glibc bug: contains a comment saying: * The following must match the kernel's . * However, it does not contain any of the HWCAP2_* entries from . */ #ifndef HWCAP2_AES #include #endif #endif /* __arm__ */ #endif /* CPUSUPPORT_HWCAP_GETAUXVAL */ #if defined(CPUSUPPORT_HWCAP_ELF_AUX_INFO) #include #endif /* CPUSUPPORT_HWCAP_ELF_AUX_INFO */ CPUSUPPORT_FEATURE_DECL(arm, aes) { int supported = 0; #if defined(CPUSUPPORT_ARM_AES) #if defined(CPUSUPPORT_HWCAP_GETAUXVAL) unsigned long capabilities; #if defined(__aarch64__) capabilities = getauxval(AT_HWCAP); supported = (capabilities & HWCAP_AES) ? 1 : 0; #elif defined(__arm__) capabilities = getauxval(AT_HWCAP2); supported = (capabilities & HWCAP2_AES) ? 1 : 0; #endif #endif /* CPUSUPPORT_HWCAP_GETAUXVAL */ #if defined(CPUSUPPORT_HWCAP_ELF_AUX_INFO) unsigned long capabilities; #if defined(__aarch64__) if (elf_aux_info(AT_HWCAP, &capabilities, sizeof(unsigned long))) return (0); supported = (capabilities & HWCAP_AES) ? 1 : 0; #else if (elf_aux_info(AT_HWCAP2, &capabilities, sizeof(unsigned long))) return (0); supported = (capabilities & HWCAP2_AES) ? 1 : 0; #endif #endif /* CPUSUPPORT_HWCAP_ELF_AUX_INFO */ #endif /* CPUSUPPORT_ARM_AES */ /* Return the supported status. */ return (supported); } spiped-1.6.3/libcperciva/cpusupport/cpusupport_x86_aesni.c000644 001751 001751 00000001137 14743020337 025431 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_X86_CPUID #include #define CPUID_AESNI_BIT (1 << 25) #endif CPUSUPPORT_FEATURE_DECL(x86, aesni) { #ifdef CPUSUPPORT_X86_CPUID unsigned int eax, ebx, ecx, edx; /* Check if CPUID supports the level we need. */ if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) goto unsupported; if (eax < 1) goto unsupported; /* Ask about CPU features. */ if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) goto unsupported; /* Return the relevant feature bit. */ return ((ecx & CPUID_AESNI_BIT) ? 1 : 0); unsupported: #endif /* Not supported. */ return (0); } spiped-1.6.3/libcperciva/cpusupport/cpusupport_x86_sse2.c000644 001751 001751 00000001134 14743020337 025203 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_X86_CPUID #include #define CPUID_SSE2_BIT (1 << 26) #endif CPUSUPPORT_FEATURE_DECL(x86, sse2) { #ifdef CPUSUPPORT_X86_CPUID unsigned int eax, ebx, ecx, edx; /* Check if CPUID supports the level we need. */ if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) goto unsupported; if (eax < 1) goto unsupported; /* Ask about CPU features. */ if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) goto unsupported; /* Return the relevant feature bit. */ return ((edx & CPUID_SSE2_BIT) ? 1 : 0); unsupported: #endif /* Not supported. */ return (0); } spiped-1.6.3/libcperciva/cpusupport/cpusupport_arm_sha256.c000644 001751 001751 00000002730 14101630450 025463 0ustar00cpercivacperciva000000 000000 #include "cpusupport.h" #ifdef CPUSUPPORT_HWCAP_GETAUXVAL #include #if defined(__arm__) /** * Workaround for a glibc bug: contains a comment saying: * The following must match the kernel's . * However, it does not contain any of the HWCAP2_* entries from . */ #ifndef HWCAP2_CRC32 #include #endif #endif /* __arm__ */ #endif /* CPUSUPPORT_HWCAP_GETAUXVAL */ #if defined(CPUSUPPORT_HWCAP_ELF_AUX_INFO) #include #endif /* CPUSUPPORT_HWCAP_ELF_AUX_INFO */ CPUSUPPORT_FEATURE_DECL(arm, sha256) { int supported = 0; #if defined(CPUSUPPORT_ARM_SHA256) #if defined(CPUSUPPORT_HWCAP_GETAUXVAL) unsigned long capabilities; #if defined(__aarch64__) capabilities = getauxval(AT_HWCAP); supported = (capabilities & HWCAP_SHA2) ? 1 : 0; #elif defined(__arm__) capabilities = getauxval(AT_HWCAP2); supported = (capabilities & HWCAP2_SHA2) ? 1 : 0; #endif #endif /* CPUSUPPORT_HWCAP_GETAUXVAL */ #if defined(CPUSUPPORT_HWCAP_ELF_AUX_INFO) unsigned long capabilities; #if defined(__aarch64__) if (elf_aux_info(AT_HWCAP, &capabilities, sizeof(unsigned long))) return (0); supported = (capabilities & HWCAP_SHA2) ? 1 : 0; #else if (elf_aux_info(AT_HWCAP2, &capabilities, sizeof(unsigned long))) return (0); supported = (capabilities & HWCAP2_SHA2) ? 1 : 0; #endif #endif /* CPUSUPPORT_HWCAP_ELF_AUX_INFO */ #endif /* CPUSUPPORT_ARM_SHA256 */ /* Return the supported status. */ return (supported); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-SSE2.c000644 001751 001751 00000000670 14014627713 025704 0ustar00cpercivacperciva000000 000000 #include static char a[16]; /* * Use a separate function for this, because that means that the alignment of * the _mm_loadu_si128() will move to function level, which may require * -Wno-cast-align. */ static __m128i load_128(const char * src) { __m128i x; x = _mm_loadu_si128((const __m128i *)src); return (x); } int main(void) { __m128i x; x = load_128(a); _mm_storeu_si128((__m128i *)a, x); return (a[0]); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-RDRAND.c000644 001751 001751 00000000134 14154500003 026120 0ustar00cpercivacperciva000000 000000 #include int main(void) { unsigned int x; return (!_rdrand32_step(&x)); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-SHANI.c000644 001751 001751 00000000762 14650270210 026024 0ustar00cpercivacperciva000000 000000 #include #include /* * Use a separate function for this, because that means that the alignment of * the _mm_loadu_si128() will move to function level, which may require * -Wno-cast-align. */ static __m128i load_128(const uint8_t * src) { __m128i x; x = _mm_loadu_si128((const __m128i *)src); return (x); } int main(void) { __m128i x; uint8_t a[16] = {0}; x = load_128(a); x = _mm_sha256msg1_epu32(x, x); _mm_storeu_si128((__m128i *)a, x); return (a[0]); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-HWCAP-GETAUXVAL.c000644 001751 001751 00000000160 14014627713 026777 0ustar00cpercivacperciva000000 000000 #include int main(void) { unsigned long val; val = getauxval(AT_HWCAP); return (val != 0); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-HWCAP-ELF_AUX_INFO.c000644 001751 001751 00000000246 14101630450 027367 0ustar00cpercivacperciva000000 000000 #include int main(void) { int res; unsigned long val; res = elf_aux_info(AT_HWCAP, &val, sizeof(unsigned long)); (void)res; return (val != 0); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport.sh000755 001751 001751 00000006406 14650270210 024775 0ustar00cpercivacperciva000000 000000 # Should be sourced by `command -p sh path/to/cpusupport.sh "$PATH"` from # within a Makefile. if ! [ "${PATH}" = "$1" ]; then echo "WARNING: POSIX violation: ${SHELL}'s command -p resets \$PATH" 1>&2 PATH=$1 fi # Standard output should be written to cpusupport-config.h, which is both a # C header file defining CPUSUPPORT_ARCH_FEATURE macros and sourceable sh # code which sets CFLAGS_ARCH_FEATURE environment variables. SRCDIR=$(command -p dirname "$0") CFLAGS_HARDCODED="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700" # Do we want to record stderr to a file? if [ "${DEBUG:-0}" -eq "0" ]; then outcc="/dev/null" else outcc="cpusupport-stderr.log" rm -f "${outcc}" fi feature() { ARCH=$1 FEATURE=$2 shift 2; # Bail if we didn't include this feature in this source tree. feature_filename="${SRCDIR}/cpusupport-${ARCH}-${FEATURE}.c" if ! [ -f "${feature_filename}" ]; then return fi # Check if we can compile this feature (and any required arguments). printf "Checking if compiler supports %s %s feature..." \ "${ARCH}" "${FEATURE}" 1>&2 for CPU_CFLAGS in "$@"; do if ${CC} ${CPPFLAGS} ${CFLAGS} ${CFLAGS_HARDCODED} \ ${CPU_CFLAGS} "${feature_filename}" 2>>"${outcc}"; then rm -f a.out break; fi CPU_CFLAGS=NOTSUPPORTED; done case ${CPU_CFLAGS} in NOTSUPPORTED) echo " no" 1>&2 ;; "") echo " yes" 1>&2 echo "#define CPUSUPPORT_${ARCH}_${FEATURE} 1" ;; *) echo " yes, via ${CPU_CFLAGS}" 1>&2 echo "#define CPUSUPPORT_${ARCH}_${FEATURE} 1" echo "#ifdef cpusupport_dummy" echo "export CFLAGS_${ARCH}_${FEATURE}=\"${CPU_CFLAGS}\"" echo "#endif" ;; esac } if [ "$2" = "--all" ]; then feature() { ARCH=$1 FEATURE=$2 echo "#define CPUSUPPORT_${ARCH}_${FEATURE} 1" } fi # Detect CPU-detection features feature HWCAP ELF_AUX_INFO "" feature HWCAP GETAUXVAL "" feature X86 CPUID "" feature X86 CPUID_COUNT "" # Detect specific features feature X86 AESNI "" "-maes" \ "-maes -Wno-cast-align" \ "-maes -Wno-missing-prototypes -Wno-cast-qual" \ "-maes -Wno-missing-prototypes -Wno-cast-qual -Wno-cast-align" \ "-maes -Wno-missing-prototypes -Wno-cast-qual -Wno-cast-align \ -DBROKEN_MM_LOADU_SI64" feature X86 RDRAND "" "-mrdrnd" feature X86 SHANI "" "-msse2 -msha" \ "-msse2 -msha -Wno-cast-align" feature X86 SSE2 "" \ "-Wno-cast-align" \ "-msse2" \ "-msse2 -Wno-cast-align" feature X86 SSE42 "" "-msse4.2" \ "-msse4.2 -Wno-cast-align" \ "-msse4.2 -Wno-cast-align -fno-strict-aliasing" \ "-msse4.2 -Wno-cast-align -fno-strict-aliasing -Wno-cast-qual" feature X86 SSE42_64 "" "-msse4.2" \ "-msse4.2 -Wno-cast-align" \ "-msse4.2 -Wno-cast-align -fno-strict-aliasing" \ "-msse4.2 -Wno-cast-align -fno-strict-aliasing -Wno-cast-qual" feature X86 SSSE3 "" "-mssse3" \ "-mssse3 -Wno-cast-align" # Detect specific ARM features feature ARM AES "-march=armv8.1-a+crypto" \ "-march=armv8.1-a+crypto -D__ARM_ACLE=200" feature ARM CRC32_64 "-march=armv8.1-a" \ "-march=armv8.1-a+crc" \ "-march=armv8.1-a+crc -Wno-cast-align" \ "-march=armv8.1-a -D__ARM_ACLE=200" feature ARM SHA256 "-march=armv8.1-a+crypto" \ "-march=armv8.1-a+crypto -Wno-cast-align" \ "-march=armv8.1-a+crypto -D__ARM_ACLE=200" spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-CPUID.c000644 001751 001751 00000000154 14650270210 026021 0ustar00cpercivacperciva000000 000000 #include int main(void) { unsigned int a, b, c, d; return (__get_cpuid(0, &a, &b, &c, &d)); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-ARM-SHA256.c000644 001751 001751 00000000341 14650270210 026055 0ustar00cpercivacperciva000000 000000 #ifdef __ARM_NEON #include #endif int main(void) { uint32x4_t w0 = {0}; uint32x4_t w4 = {0}; uint32x4_t output; output = vsha256su0q_u32(w0, w4); (void)output; /* UNUSED */ /* Success! */ return (0); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-SSSE3.c000644 001751 001751 00000000756 13777161017 026042 0ustar00cpercivacperciva000000 000000 #include #include static char a[16]; /* * Use a separate function for this, because that means that the alignment of * the _mm_loadu_si128() will move to function level, which may require * -Wno-cast-align. */ static __m128i load_128(const char * src) { __m128i x; x = _mm_loadu_si128((const __m128i *)src); return (x); } int main(void) { __m128i x; x = load_128(a); x = _mm_alignr_epi8(x, x, 8); _mm_storeu_si128((__m128i *)a, x); return (a[0]); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-AESNI.c000644 001751 001751 00000001141 14650270210 026011 0ustar00cpercivacperciva000000 000000 #include #include /* * Use a separate function for this, because that means that the alignment of * the _mm_loadu_si128() will move to function level, which may require * -Wno-cast-align. */ static __m128i load_128(const uint8_t * src) { __m128i x; x = _mm_loadu_si128((const __m128i *)src); return (x); } int main(void) { __m128i x, y; uint8_t a[16] = {0}; x = load_128(a); #ifdef BROKEN_MM_LOADU_SI64 y = _mm_loadu_si128((const __m128i *)a); #else y = _mm_loadu_si64(a); #endif y = _mm_aesenc_si128(x, y); _mm_storeu_si128((__m128i *)&a[0], y); return (a[0]); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-X86-CPUID_COUNT.c000644 001751 001751 00000000166 13762775424 027020 0ustar00cpercivacperciva000000 000000 #include int main(void) { unsigned int a, b, c, d; __cpuid_count(7, 0, a, b, c, d); return ((int)a); } spiped-1.6.3/libcperciva/cpusupport/Build/cpusupport-ARM-AES.c000644 001751 001751 00000000657 14743020337 025635 0ustar00cpercivacperciva000000 000000 #include #ifdef __ARM_NEON #include #endif int main(void) { uint8x16_t data; uint8x16_t key = {0}; uint8x16_t output; uint32x4_t lanes = {0}; uint8_t arr[16] = {0}; /* Check AES. */ data = vld1q_u8(arr); output = vaeseq_u8(data, key); (void)output; /* UNUSED */ /* Check _u32: some compilers only support the _u8 variant. */ lanes = vdupq_laneq_u32(lanes, 0); /* Success! */ return (0); } spiped-1.6.3/libcperciva/netbuf/netbuf.h000644 001751 001751 00000006560 14650270210 021647 0ustar00cpercivacperciva000000 000000 #ifndef NETBUF_H_ #define NETBUF_H_ #include #include /* Opaque types. */ struct network_ssl_ctx; struct netbuf_read; struct netbuf_write; /** * netbuf_read_init(s): * Create and return a buffered reader attached to socket ${s}. The caller * is responsible for ensuring that no attempts are made to read from said * socket except via the returned reader. */ struct netbuf_read * netbuf_read_init(int); /** * netbuf_read_peek(R, data, datalen): * Set ${data} to point to the currently buffered data in the reader ${R}; set * ${datalen} to the number of bytes buffered. */ void netbuf_read_peek(struct netbuf_read *, uint8_t **, size_t *); /** * netbuf_read_wait(R, len, callback, cookie): * Wait until ${R} has ${len} or more bytes of data buffered or an error * occurs; then invoke ${callback}(${cookie}, status) with status set to 0 * if the data is available, -1 on error, or 1 on EOF. */ int netbuf_read_wait(struct netbuf_read *, size_t, int (*)(void *, int), void *); /** * netbuf_read_wait_cancel(R): * Cancel any in-progress wait on the reader ${R}. Do not invoke the callback * associated with the wait. */ void netbuf_read_wait_cancel(struct netbuf_read *); /** * netbuf_read_consume(R, len): * Advance the reader pointer for the reader ${R} by ${len} bytes. */ void netbuf_read_consume(struct netbuf_read *, size_t); /** * netbuf_read_free(R): * Free the reader ${R}. Note that an indeterminate amount of data may have * been buffered and will be lost. */ void netbuf_read_free(struct netbuf_read *); /** * netbuf_write_init(s, fail_callback, fail_cookie): * Create and return a buffered writer attached to socket ${s}. The caller * is responsible for ensuring that no attempts are made to write to said * socket except via the returned writer until netbuf_write_free() is called. * If a write fails, ${fail_callback} will be invoked with the parameter * ${fail_cookie}. */ struct netbuf_write * netbuf_write_init(int, int (*)(void *), void *); /** * netbuf_write_reserve(W, len): * Reserve ${len} bytes of space in the buffered writer ${W} and return a * pointer to the buffer. This operation must be followed by a call to * netbuf_write_consume() before the next call to _reserve() or _write() and * before a callback could be made into netbuf_write() (i.e., before control * returns to the event loop). */ uint8_t * netbuf_write_reserve(struct netbuf_write *, size_t); /** * netbuf_write_consume(W, len): * Consume a reservation previously made by netbuf_write_reserve(); the value * ${len} must be <= the value passed to netbuf_write_reserve(). */ int netbuf_write_consume(struct netbuf_write *, size_t); /** * netbuf_write_write(W, buf, buflen): * Write ${buflen} bytes from the buffer ${buf} via the buffered writer ${W}. */ int netbuf_write_write(struct netbuf_write *, const uint8_t *, size_t); /** * netbuf_write_free(W): * Free the writer ${W}. */ void netbuf_write_free(struct netbuf_write *); /** * netbuf_ssl_read_init(ssl): * Behave as netbuf_read_init() but take an SSL context instead. */ struct netbuf_read * netbuf_ssl_read_init(struct network_ssl_ctx *); /** * netbuf_ssl_write_init(ssl, fail_callback, fail_cookie): * Behave as netbuf_write_init() but take an SSL context instead. */ struct netbuf_write * netbuf_ssl_write_init(struct network_ssl_ctx *, int (*)(void *), void *); #endif /* !NETBUF_H_ */ spiped-1.6.3/libcperciva/netbuf/netbuf_ssl_internal.h000644 001751 001751 00000002264 14650270210 024421 0ustar00cpercivacperciva000000 000000 #ifndef NETBUF_SSL_H_ #define NETBUF_SSL_H_ #include #include /* Opaque type. */ struct network_ssl_ctx; /* * Function pointers defined in netbuf_read and netbuf_write; we set them * from our _init functions in order to avoid unnecessary linkage. */ extern void * (* netbuf_read_ssl_func)(struct network_ssl_ctx *, uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *); extern void (* netbuf_read_ssl_cancel_func)(void *); extern void * (* netbuf_write_ssl_func)(struct network_ssl_ctx *, const uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *); extern void (* netbuf_write_ssl_cancel_func)(void *); /** * netbuf_read_init2(s, ssl): * Behave like netbuf_read_init() if ${ssl} is NULL. If the SSL context * ${ssl} is not NULL, use it and ignore ${s}. */ struct netbuf_read * netbuf_read_init2(int, struct network_ssl_ctx *); /** * netbuf_write_init2(s, ssl, fail_callback, fail_cookie): * Behave like netbuf_write_init() if ${ssl} is NULL. If the SSL context * ${ssl} is not NULL, use it and ignore ${s}. */ struct netbuf_write * netbuf_write_init2(int, struct network_ssl_ctx *, int (*)(void *), void *); #endif /* !NETBUF_SSL_H_ */ spiped-1.6.3/libcperciva/netbuf/netbuf_read.c000644 001751 001751 00000016277 14743020337 022651 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "events.h" #include "network.h" #include "netbuf.h" #include "netbuf_ssl_internal.h" /* * Set to NULL here; initialized by netbuf_ssl if SSL is being used. This * allows us to avoid needing to link libssl into binaries which aren't * going to be using SSL. */ void * (* netbuf_read_ssl_func)(struct network_ssl_ctx *, uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *) = NULL; void (* netbuf_read_ssl_cancel_func)(void *) = NULL; /* Buffered reader structure. */ struct netbuf_read { /* Reader state. */ int s; /* Source socket for reads... */ struct network_ssl_ctx * ssl; /* ... unless we're using this. */ int (* callback)(void *, int); /* Callback for _wait. */ void * cookie; /* Cookie for _wait. */ void * read_cookie; /* From network_read. */ void * immediate_cookie; /* From events_immediate_register. */ /* Buffer state. */ uint8_t * buf; /* Current read buffer. */ size_t buflen; /* Length of buf. */ size_t bufpos; /* Position of read pointer in buf. */ size_t datalen; /* Position of write pointer in buf. */ }; static int callback_success(void *); static int callback_read(void *, ssize_t); /** * netbuf_read_init(s): * Create and return a buffered reader attached to socket ${s}. The caller * is responsible for ensuring that no attempts are made to read from said * socket except via the returned reader. */ struct netbuf_read * netbuf_read_init(int s) { /* Call the real function (without SSL). */ return (netbuf_read_init2(s, NULL)); } /** * netbuf_read_init2(s, ssl): * Behave like netbuf_read_init() if ${ssl} is NULL. If the SSL context * ${ssl} is not NULL, use it and ignore ${s}. */ struct netbuf_read * netbuf_read_init2(int s, struct network_ssl_ctx * ssl) { struct netbuf_read * R; /* Bake a cookie. */ if ((R = malloc(sizeof(struct netbuf_read))) == NULL) goto err0; R->s = s; R->ssl = ssl; R->read_cookie = NULL; R->immediate_cookie = NULL; /* Allocate buffer. */ R->buflen = 4096; if ((R->buf = malloc(R->buflen)) == NULL) goto err1; R->bufpos = 0; R->datalen = 0; /* Success! */ return (R); err1: free(R); err0: /* Failure! */ return (NULL); } /** * netbuf_read_peek(R, data, datalen): * Set ${data} to point to the currently buffered data in the reader ${R}; set * ${datalen} to the number of bytes buffered. */ void netbuf_read_peek(struct netbuf_read * R, uint8_t ** data, size_t * datalen) { /* Point at current buffered data. */ *data = &R->buf[R->bufpos]; *datalen = R->datalen - R->bufpos; } /* Ensure that ${R} can store at least ${len} bytes. */ static int netbuf_read_resize_buffer(struct netbuf_read * R, size_t len) { uint8_t * nbuf; size_t nbuflen; /* Compute new buffer size. */ nbuflen = R->buflen * 2; if (nbuflen < len) nbuflen = len; /* Allocate new buffer. */ if ((nbuf = malloc(nbuflen)) == NULL) goto err0; /* Copy data into new buffer. */ memcpy(nbuf, &R->buf[R->bufpos], R->datalen - R->bufpos); /* Free old buffer and use new buffer. */ free(R->buf); R->buf = nbuf; R->buflen = nbuflen; R->datalen -= R->bufpos; R->bufpos = 0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * netbuf_read_wait(R, len, callback, cookie): * Wait until ${R} has ${len} or more bytes of data buffered or an error * occurs; then invoke ${callback}(${cookie}, status) with status set to 0 * if the data is available, -1 on error, or 1 on EOF. */ int netbuf_read_wait(struct netbuf_read * R, size_t len, int (* callback)(void *, int), void * cookie) { /* Sanity-check: We shouldn't be reading already. */ assert(R->read_cookie == NULL); assert(R->immediate_cookie == NULL); /* Record parameters for future reference. */ R->callback = callback; R->cookie = cookie; /* If we have enough data already, schedule a callback. */ if (R->datalen - R->bufpos >= len) { if ((R->immediate_cookie = events_immediate_register(callback_success, R, 0)) == NULL) goto err0; else goto done; } /* Resize the buffer if needed. */ if ((R->buflen < len) && netbuf_read_resize_buffer(R, len)) goto err0; /* Move data to start of buffer if needed. */ if (R->buflen - R->bufpos < len) { memmove(R->buf, &R->buf[R->bufpos], R->datalen - R->bufpos); R->datalen -= R->bufpos; R->bufpos = 0; } /* Read data into the buffer. */ if (R->ssl) { if ((R->read_cookie = (netbuf_read_ssl_func)(R->ssl, &R->buf[R->datalen], R->buflen - R->datalen, R->bufpos + len - R->datalen, callback_read, R)) == NULL) goto err0; } else { if ((R->read_cookie = network_read(R->s, &R->buf[R->datalen], R->buflen - R->datalen, R->bufpos + len - R->datalen, callback_read, R)) == NULL) goto err0; } done: /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Perform immediate callback for netbuf_read_wait. */ static int callback_success(void * cookie) { struct netbuf_read * R = cookie; /* Sanity-check: We should be expecting this callback. */ assert(R->immediate_cookie != NULL); /* This callback is no longer pending. */ R->immediate_cookie = NULL; /* Perform callback. */ return ((R->callback)(R->cookie, 0)); } /* Callback for a completed network read. */ static int callback_read(void * cookie, ssize_t lenread) { struct netbuf_read * R = cookie; /* Sanity-check: We should be reading. */ assert(R->read_cookie != NULL); /* This callback is no longer pending. */ R->read_cookie = NULL; /* Did the read fail? */ if (lenread < 0) goto failed; /* Did we hit EOF? */ if (lenread == 0) goto eof; /* We've got more data. */ R->datalen += (size_t)lenread; /* Perform callback. */ return ((R->callback)(R->cookie, 0)); eof: /* Perform EOF callback. */ return ((R->callback)(R->cookie, 1)); failed: /* Perform failure callback. */ return ((R->callback)(R->cookie, -1)); } /** * netbuf_read_wait_cancel(R): * Cancel any in-progress wait on the reader ${R}. Do not invoke the callback * associated with the wait. */ void netbuf_read_wait_cancel(struct netbuf_read * R) { /* If we have an in-progress read, cancel it. */ if (R->read_cookie != NULL) { if (R->ssl) (netbuf_read_ssl_cancel_func)(R->read_cookie); else network_read_cancel(R->read_cookie); R->read_cookie = NULL; } /* If we have an immediate callback pending, cancel it. */ if (R->immediate_cookie != NULL) { events_immediate_cancel(R->immediate_cookie); R->immediate_cookie = NULL; } } /** * netbuf_read_consume(R, len): * Advance the reader pointer for the reader ${R} by ${len} bytes. */ void netbuf_read_consume(struct netbuf_read * R, size_t len) { /* Sanity-check: We can't consume data we don't have. */ assert(R->datalen - R->bufpos >= len); /* Advance the buffer pointer. */ R->bufpos += len; } /** * netbuf_read_free(R): * Free the reader ${R}. Note that an indeterminate amount of data may have * been buffered and will be lost. */ void netbuf_read_free(struct netbuf_read * R) { /* Behave consistently with free(NULL). */ if (R == NULL) return; /* Can't free a reader which is busy. */ assert(R->read_cookie == NULL); assert(R->immediate_cookie == NULL); /* Free the buffer and the reader. */ free(R->buf); free(R); } spiped-1.6.3/libcperciva/apisupport/Build/000755 001751 001751 00000000000 14653532061 022176 5ustar00cpercivacperciva000000 000000 spiped-1.6.3/libcperciva/apisupport/Build/apisupport.sh000755 001751 001751 00000004234 14650270210 024736 0ustar00cpercivacperciva000000 000000 # Should be sourced by `command -p sh path/to/apisupport.sh "$PATH"` from # within a Makefile. if ! [ "${PATH}" = "$1" ]; then echo "WARNING: POSIX violation: ${SHELL}'s command -p resets \$PATH" 1>&2 PATH=$1 fi # Standard output should be written to apisupport-config.h, which is both a # C header file defining APISUPPORT_PLATFORM_FEATURE macros and sourceable sh # code which sets CFLAGS_PLATFORM_FEATURE environment variables. SRCDIR=$(command -p dirname "$0") CFLAGS_HARDCODED="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700" # Do we want to record stderr to a file? if [ "${DEBUG:-0}" -eq "0" ]; then outcc="/dev/null" else outcc="apisupport-stderr.log" rm -f "${outcc}" fi feature() { PLATFORM=$1 FEATURE=$2 EXTRALIB=$3 shift 3; # Bail if we didn't include this feature in this source tree. feature_filename="${SRCDIR}/apisupport-${PLATFORM}-${FEATURE}.c" if ! [ -f "${feature_filename}" ]; then return fi # Check if we can compile this feature (and any required arguments). printf "Checking if compiler supports %s %s feature..." \ "${PLATFORM}" "${FEATURE}" 1>&2 for API_CFLAGS in "$@"; do if ${CC} ${CPPFLAGS} ${CFLAGS} ${CFLAGS_HARDCODED} \ ${API_CFLAGS} "${feature_filename}" ${LDADD_EXTRA} \ ${EXTRALIB} 2>>"${outcc}"; then rm -f a.out break; fi API_CFLAGS=NOTSUPPORTED; done case ${API_CFLAGS} in NOTSUPPORTED) echo " no" 1>&2 ;; "") echo " yes" 1>&2 echo "#define APISUPPORT_${PLATFORM}_${FEATURE} 1" ;; *) echo " yes, via ${API_CFLAGS}" 1>&2 echo "#define APISUPPORT_${PLATFORM}_${FEATURE} 1" echo "#ifdef apisupport_dummy" echo "export CFLAGS_${PLATFORM}_${FEATURE}=\"${API_CFLAGS}\"" echo "#endif" ;; esac } if [ "$2" = "--all" ]; then feature() { PLATFORM=$1 FEATURE=$2 echo "#define APISUPPORT_${PLATFORM}_${FEATURE} 1" } fi # Detect how to compile non-POSIX code. feature NONPOSIX SETGROUPS "" "" \ "-U_POSIX_C_SOURCE -U_XOPEN_SOURCE" \ "-U_POSIX_C_SOURCE -U_XOPEN_SOURCE -Wno-reserved-id-macro" # Detect how to compile libssl and libcrypto code. feature LIBSSL HOST_NAME "-lssl" "" \ "-Wno-cast-qual" feature LIBCRYPTO LOW_LEVEL_AES "-lcrypto" "" \ "-Wno-deprecated-declarations" spiped-1.6.3/libcperciva/apisupport/Build/apisupport-NONPOSIX-SETGROUPS.c000644 001751 001751 00000000452 14653532061 027415 0ustar00cpercivacperciva000000 000000 #include /* * Including a .c file is unusual, but setgroups_none.c contains a number of * system-specific header includes, which we do not want to duplicate here. */ #include "../../util/setgroups_none.c" int main(void) { (void)setgroups(0, NULL); /* Success! */ return (0); } spiped-1.6.3/libcperciva/apisupport/Build/apisupport-LIBCRYPTO-LOW_LEVEL_AES.c000644 001751 001751 00000000333 14650270210 030162 0ustar00cpercivacperciva000000 000000 #include #include int main(void) { AES_KEY kexp_actual; const uint8_t key_unexpanded[16] = { 0 }; AES_set_encrypt_key(key_unexpanded, 128, &kexp_actual); /* Success! */ return (0); } spiped-1.6.3/libcperciva/POSIX/posix-clock_gettime.c000644 001751 001751 00000000152 13360750213 023741 0ustar00cpercivacperciva000000 000000 #include int main(void) { struct timespec ts; return (clock_gettime(CLOCK_REALTIME, &ts)); } spiped-1.6.3/libcperciva/POSIX/posix-cflags-filter.sh000644 001751 001751 00000001607 14650270210 024045 0ustar00cpercivacperciva000000 000000 # Should be sourced by # command -p sh posix-cflags-filter.sh "$PATH" # from within a Makefile. # Produces a file to be sourced which edits CFLAGS. # Sanity check environment variables if [ -z "${CC}" ]; then echo "\$CC is not defined! Cannot run any compiler tests." 1>&2 exit 1 fi if ! [ "${PATH}" = "$1" ]; then echo "WARNING: POSIX violation: ${SHELL}'s command -p resets \$PATH" 1>&2 PATH=$1 fi # Find directory of this script and the source files D=$(dirname "$0") if ! ${CC} -O2 "${D}/posix-trivial.c" 2>/dev/null; then if ${CC} "${D}/posix-trivial.c" 2>/dev/null; then echo 'CFLAGS_FILTERED=""' echo 'for OPT in $CFLAGS; do' echo ' if [ "$OPT" = "-O2" ]; then' echo ' continue' echo ' fi' echo ' CFLAGS_FILTERED="$CFLAGS $OPT"' echo 'done' echo 'CFLAGS="$CFLAGS_FILTERED"' echo "WARNING: POSIX violation: make's CC doesn't understand -O2" 1>&2 fi fi rm -f a.out spiped-1.6.3/libcperciva/POSIX/posix-trivial.c000644 001751 001751 00000000061 14650270210 022576 0ustar00cpercivacperciva000000 000000 int main(void) { /* Success! */ return (0); } spiped-1.6.3/libcperciva/POSIX/posix-restrict.c000644 001751 001751 00000000234 14650270210 022765 0ustar00cpercivacperciva000000 000000 static int foo(const char * restrict x, const char * restrict y) { return (x == y); } int main(void) { char x[10]; char y[10]; return (foo(x, y)); } spiped-1.6.3/libcperciva/POSIX/README000644 001751 001751 00000003742 14154500003 020504 0ustar00cpercivacperciva000000 000000 POSIX compatibility code ------------------------ This code exists to work around some common POSIX compatibility issues. POSIX specifies that if the first line of a Makefile is ".POSIX:" then the Makefile should be processed according to POSIX rules, including with CC=c99; thus we should see behaviour consistent with a standard-compliant C99 compiler. One POSIX compatibility check requires a runtime test. This will be automatically disabled if the build system detects that you are cross-compiling for another platform, or it can be manually disabled by setting DISABLE_POSIX_RUNTIME_CHECKS to a non-zero value. - posix-cflags.sh: Detects if ${CC} supports certain POSIX features, and outputs a POSIXFAIL_ define if it is not supported so that we can work around the problem. The potential command-line flags are: - DPOSIXFAIL_MSG_NOSIGNAL: not defining MSG_NOSIGNAL. - DPOSIXFAIL_CLOCK_REALTIME: not defining CLOCK_REALTIME. - DPOSIXFAIL_CLOCK_GETTIME: not declaring clock_gettime(), or clock_gettime() is not linkable. The latter test requires a runtime check. - DPOSIXFAIL_INET_ADDRSTRLEN: not defining INET_ADDRSTRLEN. - DPOSIXFAIL_INET6_ADDRSTRLEN: not defining INET6_ADDRSTRLEN. - DPOSIXFAIL_ABSTRACT_DECLARATOR: ${CC} does not accept qualifiers in an abstract declarator. - DPOSIXFAIL_STAT_ST_MTIM: struct stat does not contain st_mtim. - std=c99: ${CC} does not accept the `restrict` keyword by default, but accepts it when given this flag. - posix-cflags-filter.sh: Detects if ${CC} supports expected ${CFLAG} value(s). The potential ${CFLAGS} flags it checks are: - O2: some compilers only accept -O. - posix-l.sh: Detects whether the linker supports certain POSIX features. The potential command-line flags are: - lrt lxnet: c99 is required to understand these options, and ignore them if the routines for which they specify linkage are already in the standard C library spiped-1.6.3/libcperciva/POSIX/posix-msg_nosignal.c000644 001751 001751 00000000105 13360750213 023606 0ustar00cpercivacperciva000000 000000 #include int main(void) { return (MSG_NOSIGNAL); } spiped-1.6.3/libcperciva/POSIX/posix-stat-st_mtim.c000644 001751 001751 00000000225 14650270210 023553 0ustar00cpercivacperciva000000 000000 #include int main(void) { struct stat sb; /* Can we reference st_mtim? */ (void)sb.st_mtim.tv_sec; /* Success! */ return (0); } spiped-1.6.3/libcperciva/POSIX/posix-l.sh000755 001751 001751 00000001316 14650270210 021556 0ustar00cpercivacperciva000000 000000 # Should be sourced by # command -p sh posix-l.sh "$PATH" # from within a Makefile. # Sanity check environment variables if [ -z "${CC}" ]; then echo "\$CC is not defined! Cannot run any compiler tests." 1>&2 exit 1 fi if ! [ "${PATH}" = "$1" ]; then echo "WARNING: POSIX violation: ${SHELL}'s command -p resets \$PATH" 1>&2 PATH=$1 fi # Find directory of this script and the source files D=$(dirname "$0") FIRST=YES for LIB in rt xnet; do if ${CC} ${CFLAGS} -l"${LIB}" "${D}/posix-trivial.c" 2>/dev/null; then if [ "${FIRST}" = "NO" ]; then printf " "; fi printf "%s" "-l${LIB}"; FIRST=NO; else echo "WARNING: POSIX violation: ${CC} does not understand -l${LIB}" 1>&2 fi rm -f a.out done spiped-1.6.3/libcperciva/POSIX/posix-inet6-addrstrlen.c000644 001751 001751 00000000111 13723620112 024305 0ustar00cpercivacperciva000000 000000 #include int main(void) { return (INET6_ADDRSTRLEN); } spiped-1.6.3/libcperciva/POSIX/posix-inet-addrstrlen.c000644 001751 001751 00000000110 13723620112 024216 0ustar00cpercivacperciva000000 000000 #include int main(void) { return (INET_ADDRSTRLEN); } spiped-1.6.3/libcperciva/POSIX/posix-cflags.sh000755 001751 001751 00000010334 14650270210 022562 0ustar00cpercivacperciva000000 000000 # Should be sourced by # command -p sh posix-cflags.sh "$PATH" # from within a Makefile. # Sanity check environment variables if [ -z "${CC}" ]; then echo "\$CC is not defined! Cannot run any compiler tests." 1>&2 exit 1 fi if ! [ "${PATH}" = "$1" ]; then echo "WARNING: POSIX violation: ${SHELL}'s command -p resets \$PATH" 1>&2 PATH=$1 fi # Find directory of this script and the source files D=$(dirname "$0") # Check if we can compile & run a binary. if ! ${CC} ${CFLAGS} "${D}/posix-trivial.c" 2>/dev/null; then echo "WARNING: failed to compile posix-trivial.c" 1>&2 else # If the user hasn't disabled runtime checks... if [ "${DISABLE_POSIX_RUNTIME_CHECKS:-0}" -eq "0" ]; then # ... test if we can run the trivial binary. if ! ./a.out ; then echo "WARNING: failed to run a trivial binary; " 1>&2 echo "disabling runtime POSIX compatibility checks" 1>&2 DISABLE_POSIX_RUNTIME_CHECKS=1 fi fi fi FIRST=YES if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L "${D}/posix-msg_nosignal.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_MSG_NOSIGNAL" echo "WARNING: POSIX violation: not defining MSG_NOSIGNAL" 1>&2 fi if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L "${D}/posix-clock_realtime.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_CLOCK_REALTIME" echo "WARNING: POSIX violation: not defining CLOCK_REALTIME" 1>&2 fi if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 "${D}/posix-inet-addrstrlen.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_INET_ADDRSTRLEN" echo "WARNING: POSIX violation: not defining INET_ADDRSTRLEN" 1>&2 fi if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 "${D}/posix-inet6-addrstrlen.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_INET6_ADDRSTRLEN" echo "WARNING: POSIX violation: not defining INET6_ADDRSTRLEN" 1>&2 fi if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L "${D}/posix-clock_gettime.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_CLOCK_GETTIME" echo "WARNING: POSIX violation: not declaring clock_gettime()" 1>&2 elif [ "${DISABLE_POSIX_RUNTIME_CHECKS:-0}" -ne "0" ]; then # Do nothing true else # Even if the compilation succeeds, we still need to run the binary # because OS X 10.11 with XCode 8 _will_ contain clock_gettime() in the # header (because it was added in 10.12 and they only use one SDK per # XCode version), but it will link to the 10.11 library (which doesn't # include it). Annoyingly, there's two levels of error output on OS X: # one from the binary itself, and one from the signal it sends to the # calling process. The "( ./x 2>y ) 2>y" captures both types of error # message. if ! ( ./a.out 2>/dev/null ) 2>/dev/null ; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_CLOCK_GETTIME" echo "WARNING: POSIX violation: clock_gettime() is not linkable" 1>&2 fi fi if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 "${D}/posix-stat-st_mtim.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_STAT_ST_MTIM" echo "WARNING: POSIX violation: struct stat does not contain st_mtim" 1>&2 fi CFLAGS_C99="" if ! ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L "${D}/posix-restrict.c" 2>/dev/null; then echo "WARNING: POSIX violation: ${CC} does not accept the 'restrict' keyword" 1>&2 if ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L -std=c99 "${D}/posix-restrict.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-std=c99" CFLAGS_C99="-std=c99" fi fi if ! ${CC} ${CFLAGS} ${CFLAGS_C99} -D_POSIX_C_SOURCE=200809L -DARGNAME="" "${D}/posix-abstract-declarator.c" 2>/dev/null; then echo "WARNING: POSIX violation: ${CC} does not accept qualifiers in an abstract declarator" 1>&2 # Test compile with -DPOSIXFAIL_ABSTRACT_DECLARATOR if ${CC} ${CFLAGS} ${CFLAGS_C99} -D_POSIX_C_SOURCE=200809L -DPOSIXFAIL_ABSTRACT_DECLARATOR "${D}/posix-abstract-declarator.c" 2>/dev/null; then [ "${FIRST}" = "NO" ] && printf " "; FIRST=NO printf %s "-DPOSIXFAIL_ABSTRACT_DECLARATOR" fi fi rm -f a.out spiped-1.6.3/libcperciva/POSIX/posix-clock_realtime.c000644 001751 001751 00000000101 13360750213 024077 0ustar00cpercivacperciva000000 000000 #include int main(void) { return (CLOCK_REALTIME); } spiped-1.6.3/libcperciva/POSIX/posix-abstract-declarator.c000644 001751 001751 00000000474 14650270210 025055 0ustar00cpercivacperciva000000 000000 #ifdef POSIXFAIL_ABSTRACT_DECLARATOR static int func(int ARGNAME[static restrict 1]); #else static int func(int [static restrict 1]); #endif int func(int arr[static restrict 1]) { (void)arr; /* UNUSED */ /* Success! */ return (0); } int main(void) { (void)func; /* UNUSED */ /* Success! */ return (0); } spiped-1.6.3/libcperciva/events/events.h000644 001751 001751 00000007633 14650270210 021713 0ustar00cpercivacperciva000000 000000 #ifndef EVENTS_H_ #define EVENTS_H_ #include /** * events_immediate_register(func, cookie, prio): * Register ${func}(${cookie}) to be run the next time events_run() is * invoked, after immediate events with smaller ${prio} values and before * events with larger ${prio} values. The value ${prio} must be in the range * [0, 31]. Return a cookie which can be passed to events_immediate_cancel(). */ void * events_immediate_register(int (*)(void *), void *, int); /** * events_immediate_cancel(cookie): * Cancel the immediate event for which the cookie ${cookie} was returned by * events_immediate_register(). */ void events_immediate_cancel(void *); /* "op" parameter to events_network_register(). */ #define EVENTS_NETWORK_OP_READ 0 #define EVENTS_NETWORK_OP_WRITE 1 /** * events_network_register(func, cookie, s, op): * Register ${func}(${cookie}) to be run when socket ${s} is ready for * reading or writing depending on whether ${op} is EVENTS_NETWORK_OP_READ or * EVENTS_NETWORK_OP_WRITE. If there is already an event registration for * this ${s}/${op} pair, errno will be set to EEXIST and the function will * fail. */ int events_network_register(int (*)(void *), void *, int, int); /** * events_network_cancel(s, op): * Cancel the event registered for the socket/operation pair ${s}/${op}. If * there is no such registration, errno will be set to ENOENT and the * function will fail. */ int events_network_cancel(int, int); /** * events_network_selectstats(N, mu, va, max): * Return statistics on the inter-select durations since the last time this * function was called. */ void events_network_selectstats(double *, double *, double *, double *); /** * events_timer_register(func, cookie, timeo): * Register ${func}(${cookie}) to be run ${timeo} in the future. Return a * cookie which can be passed to events_timer_cancel() or events_timer_reset(). */ void * events_timer_register(int (*)(void *), void *, const struct timeval *); /** * events_timer_register_double(func, cookie, timeo): * As events_timer_register(), but ${timeo} is a double-precision * floating-point value specifying a number of seconds. */ void * events_timer_register_double(int (*)(void *), void *, double); /** * events_timer_cancel(cookie): * Cancel the timer for which the cookie ${cookie} was returned by * events_timer_register(). */ void events_timer_cancel(void *); /** * events_timer_reset(cookie): * Reset the timer for which the cookie ${cookie} was returned by * events_timer_register() to its initial value. */ int events_timer_reset(void *); /** * events_run(void): * Run events. Events registered via events_immediate_register() will be run * first, in order of increasing ${prio} values; then events associated with * ready sockets registered via events_network_register(); finally, events * associated with expired timers registered via events_timer_register() will * be run. If any event function returns a non-zero result, no further events * will be run and said non-zero result will be returned; on error, * -1 will be returned. May be interrupted by events_interrupt(), in which * case 0 will be returned. If there are runnable events, events_run() is * guaranteed to run at least one; but it may return while there are still * more runnable events. */ int events_run(void); /** * events_spin(done): * Call events_run() until ${done} is non-zero (and return 0), an error occurs * (and return -1), or a callback returns a non-zero status (and return the * status code from the callback). May be interrupted by events_interrupt() * (and return 0). */ int events_spin(const int *); /** * events_interrupt(void): * Halt the event loop after finishing the current event. This function can * be safely called from within a signal handler. */ void events_interrupt(void); /** * events_shutdown(void): * Deprecated function; does nothing. */ void events_shutdown(void); #endif /* !EVENTS_H_ */ spiped-1.6.3/libcperciva/events/events_timer.c000644 001751 001751 00000013327 14650270210 023103 0ustar00cpercivacperciva000000 000000 #include #include #include #include "monoclock.h" #include "timerqueue.h" #include "events.h" #include "events_internal.h" struct timerrec { struct eventrec * r; void * cookie; struct timeval tv_orig; }; /* This also tracks whether we've initialized the atexit function. */ static struct timerqueue * Q = NULL; static void events_timer_shutdown(void); /* Set tv := + tdelta. */ static int gettimeout(struct timeval * tv, const struct timeval * tdelta) { if (monoclock_get(tv)) goto err0; tv->tv_sec += tdelta->tv_sec; if ((tv->tv_usec += tdelta->tv_usec) >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec += 1; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_timer_register(func, cookie, timeo): * Register ${func}(${cookie}) to be run ${timeo} in the future. Return a * cookie which can be passed to events_timer_cancel() or events_timer_reset(). */ void * events_timer_register(int (* func)(void *), void * cookie, const struct timeval * timeo) { struct eventrec * r; struct timerrec * t; struct timeval tv; /* Create the timer queue if it doesn't exist yet. */ if (Q == NULL) { if ((Q = timerqueue_init()) == NULL) goto err0; /* Clean up the timer queue at exit. */ if (atexit(events_timer_shutdown)) goto err0; } /* Bundle into an eventrec record. */ if ((r = events_mkrec(func, cookie)) == NULL) goto err0; /* Create a timer record. */ if ((t = malloc(sizeof(struct timerrec))) == NULL) goto err1; t->r = r; memcpy(&t->tv_orig, timeo, sizeof(struct timeval)); /* Compute the absolute timeout. */ if (gettimeout(&tv, &t->tv_orig)) goto err2; /* Add this to the timer queue. */ if ((t->cookie = timerqueue_add(Q, &tv, t)) == NULL) goto err2; /* Success! */ return (t); err2: free(t); err1: events_freerec(r); err0: /* Failure! */ return (NULL); } /** * events_timer_register_double(func, cookie, timeo): * As events_timer_register(), but ${timeo} is a double-precision * floating-point value specifying a number of seconds. */ void * events_timer_register_double(int (* func)(void *), void * cookie, double timeo) { struct timeval tv; /* Convert timeo to a struct timeval. */ tv.tv_sec = (time_t)timeo; tv.tv_usec = (suseconds_t)((timeo - (double)tv.tv_sec) * 1000000.0); /* Schedule the timeout. */ return (events_timer_register(func, cookie, &tv)); } /** * events_timer_cancel(cookie): * Cancel the timer for which the cookie ${cookie} was returned by * events_timer_register(). */ void events_timer_cancel(void * cookie) { struct timerrec * t = cookie; /* Remove from the timer queue. */ timerqueue_delete(Q, t->cookie); /* Free the eventrec and timer records. */ events_freerec(t->r); free(t); } /** * events_timer_reset(cookie): * Reset the timer for which the cookie ${cookie} was returned by * events_timer_register() to its initial value. */ int events_timer_reset(void * cookie) { struct timerrec * t = cookie; struct timeval tv; /* Compute the new timeout. */ if (gettimeout(&tv, &t->tv_orig)) goto err0; /* Adjust the timer. */ timerqueue_increase(Q, t->cookie, &tv); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_timer_min(timeo): * Return via ${timeo} a pointer to the minimum time which must be waited * before a timer will expire; or to NULL if there are no timers. The caller * is responsible for freeing the returned pointer. */ int events_timer_min(struct timeval ** timeo) { struct timeval tnow; const struct timeval * tv; /* If we have no queue, we have no timers; return NULL. */ if (Q == NULL) { *timeo = NULL; goto done; } /* Get the minimum timer from the queue. */ tv = timerqueue_getmin(Q); /* If there are no timers, return NULL. */ if (tv == NULL) { *timeo = NULL; goto done; } /* Allocate space for holding the returned timeval. */ if ((*timeo = malloc(sizeof(struct timeval))) == NULL) goto err0; /* Get the current time... */ if (monoclock_get(&tnow)) goto err1; /* ... and compare it to the minimum timer. */ if ((tnow.tv_sec > tv->tv_sec) || ((tnow.tv_sec == tv->tv_sec) && (tnow.tv_usec > tv->tv_usec))) { /* The timer has already expired, so return zero. */ (*timeo)->tv_sec = 0; (*timeo)->tv_usec = 0; } else { /* Compute the difference. */ (*timeo)->tv_sec = tv->tv_sec - tnow.tv_sec; (*timeo)->tv_usec = tv->tv_usec - tnow.tv_usec; if (tv->tv_usec < tnow.tv_usec) { (*timeo)->tv_usec += 1000000; (*timeo)->tv_sec -= 1; } } done: /* Success! */ return (0); err1: free(*timeo); err0: /* Failure! */ return (-1); } /** * events_timer_get(r): * Return via ${r} a pointer to an eventrec structure corresponding to an * expired timer, and delete said timer; or to NULL if there are no expired * timers. The caller is responsible for freeing the returned pointer. */ int events_timer_get(struct eventrec ** r) { struct timeval tnow; struct timerrec * t; /* If we have no queue, we have no timers; return NULL. */ if (Q == NULL) { *r = NULL; goto done; } /* Get current time. */ if (monoclock_get(&tnow)) goto err0; /* Get an expired timer, if there is one. */ t = timerqueue_getptr(Q, &tnow); /* If there is an expired timer... */ if (t != NULL) { /* ... pass back the eventrec and free the timer. */ *r = t->r; free(t); } else { /* Otherwise, return NULL. */ *r = NULL; } done: /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_timer_shutdown(void): * Clean up and free memory. This should run automatically via atexit. */ static void events_timer_shutdown(void) { /* If we have a queue and it is empty, free it. */ if ((Q != NULL) && (timerqueue_getmin(Q) == NULL)) { timerqueue_free(Q); Q = NULL; } } spiped-1.6.3/libcperciva/events/events.c000644 001751 001751 00000012303 14650270210 021674 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "mpool.h" #include "events.h" #include "events_internal.h" /* Event structure. */ struct eventrec { int (* func)(void *); void * cookie; }; MPOOL(eventrec, struct eventrec, 4096); /* Zero timeval, for use with non-blocking event runs. */ static const struct timeval tv_zero = {0, 0}; /* We want to interrupt a running event loop. */ static volatile sig_atomic_t interrupt_requested = 0; /** * events_mkrec(func, cookie): * Package ${func}, ${cookie} into a struct eventrec. */ struct eventrec * events_mkrec(int (* func)(void *), void * cookie) { struct eventrec * r; /* Allocate structure. */ if ((r = mpool_eventrec_malloc()) == NULL) goto err0; /* Initialize. */ r->func = func; r->cookie = cookie; /* Success! */ return (r); err0: /* Failure! */ return (NULL); } /** * events_freerec(r): * Free the eventrec ${r}. */ void events_freerec(struct eventrec * r) { mpool_eventrec_free(r); } /* Do an event. This makes events_run cleaner. */ static inline int doevent(struct eventrec * r) { int rc; /* Invoke the callback. */ rc = (r->func)(r->cookie); /* Free the event record. */ mpool_eventrec_free(r); /* Return the status code from the callback. */ return (rc); } /** * events_run(void): * Run events. Events registered via events_immediate_register() will be run * first, in order of increasing ${prio} values; then events associated with * ready sockets registered via events_network_register(); finally, events * associated with expired timers registered via events_timer_register() will * be run. If any event function returns a non-zero result, no further events * will be run and said non-zero result will be returned; on error, * -1 will be returned. May be interrupted by events_interrupt(), in which * case 0 will be returned. If there are runnable events, events_run() is * guaranteed to run at least one; but it may return while there are still * more runnable events. */ static int events_run_internal(void) { struct eventrec * r; struct timeval * tv; struct timeval tv2; int rc = 0; /* If we have any immediate events, process them and return. */ if ((r = events_immediate_get()) != NULL) { while (r != NULL) { /* Process the event. */ if ((rc = doevent(r)) != 0) goto done; /* Interrupt loop if requested. */ if (interrupt_requested) goto done; /* Get the next event. */ r = events_immediate_get(); } /* We've processed at least one event; time to return. */ goto done; } /* * Figure out the maximum duration to block, and wait up to that * duration for network events to become available. */ if (events_timer_min(&tv)) goto err0; if (events_network_select(tv, &interrupt_requested)) goto err1; free(tv); /* * Check for available immediate events, network events, and timer * events, in that order of priority; exit only when no more events * are available or when interrupted. */ do { /* Interrupt loop if requested. */ if (interrupt_requested) goto done; /* Run an immediate event, if one is available. */ if ((r = events_immediate_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Run a network event, if one is available. */ if ((r = events_network_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Check if any new network events are available. */ memcpy(&tv2, &tv_zero, sizeof(struct timeval)); if (events_network_select(&tv2, &interrupt_requested)) goto err0; if ((r = events_network_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Run a timer event, if one is available. */ if (events_timer_get(&r)) goto err0; if (r != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* No events available. */ break; } while (1); done: /* Success! */ return (rc); err1: free(tv); err0: /* Failure! */ return (-1); } /* Wrapper function for events_run to reset interrupt_requested. */ int events_run(void) { int rc; /* Call the real function. */ rc = events_run_internal(); /* Reset interrupt_requested after quitting the loop. */ interrupt_requested = 0; /* Return status. */ return (rc); } /** * events_spin(done): * Call events_run() until ${done} is non-zero (and return 0), an error occurs * (and return -1), or a callback returns a non-zero status (and return the * status code from the callback). May be interrupted by events_interrupt() * (and return 0). */ int events_spin(const int * done) { int rc = 0; /* Loop until we're done or have a non-zero status. */ while ((done[0] == 0) && (rc == 0) && (interrupt_requested == 0)) { /* Run events. */ rc = events_run_internal(); } /* Reset interrupt_requested after quitting the loop. */ interrupt_requested = 0; /* Return status code. */ return (rc); } /** * events_interrupt(void): * Halt the event loop after finishing the current event. This function can * be safely called from within a signal handler. */ void events_interrupt(void) { /* Interrupt the event loop. */ interrupt_requested = 1; } /** * events_shutdown(void): * Deprecated function; does nothing. */ void events_shutdown(void) { } spiped-1.6.3/libcperciva/events/events_internal.h000644 001751 001751 00000005022 14650270210 023575 0ustar00cpercivacperciva000000 000000 #ifndef EVENTS_INTERNAL_H_ #define EVENTS_INTERNAL_H_ #include #include /* Opaque event structure. */ struct eventrec; /** * events_mkrec(func, cookie): * Package ${func}, ${cookie} into a struct eventrec. */ struct eventrec * events_mkrec(int (*)(void *), void *); /** * events_freerec(r): * Free the eventrec ${r}. */ void events_freerec(struct eventrec *); /** * events_immediate_get(void): * Remove and return an eventrec structure from the immediate event queue, * or return NULL if there are no such events. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_immediate_get(void); /** * events_network_select(tv, interrupt_requested): * Check for socket readiness events, waiting up to ${tv} time if there are * no sockets immediately ready, or indefinitely if ${tv} is NULL. The value * stored in ${tv} may be modified. If ${*interrupt_requested} is non-zero * and a signal is received, exit. */ int events_network_select(const struct timeval *, const volatile sig_atomic_t *); /** * events_network_selectstats_startclock(void): * Start the inter-select duration clock: There is a selectable event. */ void events_network_selectstats_startclock(void); /** * events_network_selectstats_stopclock(void): * Stop the inter-select duration clock: There are no selectable events. */ void events_network_selectstats_stopclock(void); /** * events_network_selectstats_select(void): * Update inter-select duration statistics in relation to an upcoming * select(2) call. */ void events_network_selectstats_select(void); /** * events_network_get(void): * Find a socket readiness event which was identified by a previous call to * events_network_select, and return it as an eventrec structure; or return * NULL if there are no such events available. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_network_get(void); /** * events_timer_min(timeo): * Return via ${timeo} a pointer to the minimum time which must be waited * before a timer will expire; or to NULL if there are no timers. The caller * is responsible for freeing the returned pointer. */ int events_timer_min(struct timeval **); /** * events_timer_get(r): * Return via ${r} a pointer to an eventrec structure corresponding to an * expired timer, and delete said timer; or to NULL if there are no expired * timers. The caller is responsible for freeing the returned pointer. */ int events_timer_get(struct eventrec **); #endif /* !EVENTS_INTERNAL_H_ */ spiped-1.6.3/libcperciva/events/events_network.c000644 001751 001751 00000027722 14650270210 023460 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include #include "ctassert.h" #include "elasticarray.h" #include "warnp.h" #include "events.h" #include "events_internal.h" /* * Sanity checks on the nfds_t type: POSIX simply says "an unsigned integer * type used for the number of file descriptors", but it doesn't make sense * for it to be larger than size_t unless there's an undocumented limit on * the number of descriptors which can be polled (since poll takes an array, * the size of which must fit into a size_t); and nfds_t should be able to * store the value INT_MAX + 1 (in case every possible file descriptor is in * use and being polled for). */ CTASSERT((nfds_t)(-1) <= (size_t)(-1)); CTASSERT((nfds_t)((size_t)(INT_MAX) + 1) == (size_t)(INT_MAX) + 1); /* Structure for holding readability and writability events for a socket. */ struct socketrec { struct eventrec * reader; struct eventrec * writer; size_t pollpos; }; /* List of sockets. */ ELASTICARRAY_DECL(SOCKETLIST, socketlist, struct socketrec); static SOCKETLIST S = NULL; /* Poll structures. */ static struct pollfd * fds; /* Number of poll structures allocated in array. */ static size_t fds_alloc; /* Number of poll structures initialized. */ static size_t nfds; /* Position to which events_network_get has scanned in *fds. */ static size_t fdscanpos; /** * Invariants: * 1. Initialized entries in S and fds point to each other: * S[i].pollpos < nfds ==> fds[S[i].pollpos].fd == i * j < nfds ==> S[fds[j].fd].pollpos == j * 2. Descriptors with events registered are in the right place: * S[i].reader != NULL ==> S[i].pollpos < nfds * S[i].writer != NULL ==> S[i].pollpos < nfds * 3. Descriptors without events registered aren't in the way: * (S[i].reader == NULL && S[i].writer == NULL) ==> S[i].pollpos == -1 * 4. Descriptors with events registered have the right masks: * S[i].reader != NULL <==> (fds[S[i].pollpos].events & POLLIN) != 0 * S[i].writer != NULL <==> (fds[S[i].pollpos].events & POLLOUT) != 0 * 5. We don't have events ready which we don't want: * (fds[j].revents & (POLLIN | POLLOUT) & (~fds[j].events)) == 0 * 6. Returned events are in position to be scanned later: * fds[j].revents != 0 ==> f < fdscanpos. */ static void events_network_shutdown(void); /* Initialize data structures if we haven't already done so. */ static int init(void) { /* If we're already initialized, do nothing. */ if (S != NULL) goto done; /* Initialize the socket list. */ if ((S = socketlist_init(0)) == NULL) goto err0; /* We have no poll structures allocated or initialized. */ fds = NULL; fds_alloc = nfds = fdscanpos = 0; /* Clean up the socket list at exit. */ if (atexit(events_network_shutdown)) goto err0; done: /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Grow the socket list and initialize new records. */ static int growsocketlist(size_t nrec) { size_t i; /* Get the old size. */ i = socketlist_getsize(S); /* Grow the list. */ if (socketlist_resize(S, nrec)) goto err0; /* Initialize new members. */ for (; i < nrec; i++) { socketlist_get(S, i)->reader = NULL; socketlist_get(S, i)->writer = NULL; socketlist_get(S, i)->pollpos = (size_t)(-1); } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Add a new descriptor to the pollfd array. */ static int growpollfd(size_t fd) { size_t new_fds_alloc; struct pollfd * new_fds; /* We should not be called if the descriptor is already listed. */ assert(socketlist_get(S, fd)->pollpos == (size_t)(-1)); /* Expand the pollfd allocation if needed. */ if (fds_alloc == nfds) { new_fds_alloc = fds_alloc == 0 ? 16 : fds_alloc * 2; if (new_fds_alloc > SIZE_MAX / sizeof(struct pollfd)) { errno = ENOMEM; goto err0; } if ((new_fds = realloc(fds, new_fds_alloc * sizeof(struct pollfd))) == NULL) goto err0; fds = new_fds; fds_alloc = new_fds_alloc; } /* Sanity-check. */ assert(nfds < fds_alloc); assert(fd < INT_MAX); /* Initialize pollfd structure. */ fds[nfds].fd = (int)fd; fds[nfds].events = 0; fds[nfds].revents = 0; /* Point at pollfd structure. */ socketlist_get(S, fd)->pollpos = nfds; /* We now have one more pollfd structure. */ nfds++; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Clear a bit from a pollfd and maintain invariants. */ static void clearbit(size_t pollpos, short bit) { /* Clear the bit. */ fds[pollpos].events &= (short)(~bit); fds[pollpos].revents &= (short)(~bit); /* Is this pollfd in the way? */ if (fds[pollpos].events == 0) { /* Clear the descriptor's pollpos pointer. */ socketlist_get(S, (size_t)fds[pollpos].fd)->pollpos = (size_t)(-1); /* If this wasn't the last pollfd, move another one up. */ if (pollpos != nfds - 1) { memcpy(&fds[pollpos], &fds[nfds-1], sizeof(struct pollfd)); socketlist_get(S, (size_t)fds[pollpos].fd)->pollpos = pollpos; } /* Shrink the pollfd array. */ nfds--; } } /** * events_network_register(func, cookie, s, op): * Register ${func}(${cookie}) to be run when socket ${s} is ready for * reading or writing depending on whether ${op} is EVENTS_NETWORK_OP_READ or * EVENTS_NETWORK_OP_WRITE. If there is already an event registration for * this ${s}/${op} pair, errno will be set to EEXIST and the function will * fail. */ int events_network_register(int (* func)(void *), void * cookie, int s, int op) { struct eventrec ** r; /* Initialize if necessary. */ if (init()) goto err0; /* Sanity-check socket number. */ if (s < 0) { warn0("Invalid file descriptor for network event: %d", s); goto err0; } /* Sanity-check operation. */ if ((op != EVENTS_NETWORK_OP_READ) && (op != EVENTS_NETWORK_OP_WRITE)) { warn0("Invalid operation for network event: %d", op); goto err0; } /* Grow the array if necessary. */ if (((size_t)(s) >= socketlist_getsize(S)) && (growsocketlist((size_t)s + 1) != 0)) goto err0; /* Look up the relevant event pointer. */ if (op == EVENTS_NETWORK_OP_READ) r = &socketlist_get(S, (size_t)s)->reader; else r = &socketlist_get(S, (size_t)s)->writer; /* Error out if we already have an event registered. */ if (*r != NULL) { errno = EEXIST; goto err0; } /* Register the new event. */ if ((*r = events_mkrec(func, cookie)) == NULL) goto err0; /* If we had no events registered, start a clock. */ if (nfds == 0) events_network_selectstats_startclock(); /* If this descriptor isn't in the pollfd array, add it. */ if (socketlist_get(S, (size_t)s)->pollpos == (size_t)(-1)) { if (growpollfd((size_t)s)) goto err1; } /* Set the appropriate event flag. */ if (op == EVENTS_NETWORK_OP_READ) fds[socketlist_get(S, (size_t)s)->pollpos].events |= POLLIN; else fds[socketlist_get(S, (size_t)s)->pollpos].events |= POLLOUT; /* Success! */ return (0); err1: events_freerec(*r); *r = NULL; err0: /* Failure! */ return (-1); } /** * events_network_cancel(s, op): * Cancel the event registered for the socket/operation pair ${s}/${op}. If * there is no such registration, errno will be set to ENOENT and the * function will fail. */ int events_network_cancel(int s, int op) { struct eventrec ** r; /* Initialize if necessary. */ if (init()) goto err0; /* Sanity-check socket number. */ if (s < 0) { warn0("Invalid file descriptor for network event: %d", s); goto err0; } /* Sanity-check operation. */ if ((op != EVENTS_NETWORK_OP_READ) && (op != EVENTS_NETWORK_OP_WRITE)) { warn0("Invalid operation for network event: %d", op); goto err0; } /* We have no events registered beyond the end of the array. */ if ((size_t)(s) >= socketlist_getsize(S)) { errno = ENOENT; goto err0; } /* Look up the relevant event pointer. */ if (op == EVENTS_NETWORK_OP_READ) r = &socketlist_get(S, (size_t)s)->reader; else r = &socketlist_get(S, (size_t)s)->writer; /* Check if we have an event. */ if (*r == NULL) { errno = ENOENT; goto err0; } /* Free the event. */ events_freerec(*r); *r = NULL; /* Clear the appropriate pollfd bit(s). */ if (op == EVENTS_NETWORK_OP_READ) clearbit(socketlist_get(S, (size_t)s)->pollpos, POLLIN); else clearbit(socketlist_get(S, (size_t)s)->pollpos, POLLOUT); /* If that was the last remaining event, stop the clock. */ if (nfds == 0) events_network_selectstats_stopclock(); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_select(tv, interrupt_requested): * Check for socket readiness events, waiting up to ${tv} time if there are * no sockets immediately ready, or indefinitely if ${tv} is NULL. The value * stored in ${tv} may be modified. If ${*interrupt_requested} is non-zero * and a signal is received, exit. */ int events_network_select(const struct timeval * tv, const volatile sig_atomic_t * interrupt_requested) { int timeout; /* Initialize if necessary. */ if (init()) goto err0; /* * Convert timeout to an integer number of ms. We round up in order * to avoid creating busy loops when 0 < ${tv} < 1 ms. */ if (tv == NULL) timeout = -1; else if (tv->tv_sec >= INT_MAX / 1000) timeout = INT_MAX; else timeout = (int)(tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000); /* We're about to call poll! */ events_network_selectstats_select(); /* Poll. */ while (poll(fds, (nfds_t)nfds, timeout) == -1) { /* EINTR is harmless, unless we've requested an interrupt. */ if (errno == EINTR) { if (*interrupt_requested) break; continue; } /* Anything else is an error. */ warnp("poll()"); goto err0; } /* If we have any events registered, start the clock again. */ if (nfds > 0) events_network_selectstats_startclock(); /* Start scanning at the last registered descriptor and work down. */ fdscanpos = nfds - 1; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_get(void): * Find a socket readiness event which was identified by a previous call to * events_network_select, and return it as an eventrec structure; or return * NULL if there are no such events available. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_network_get(void) { struct eventrec * r; /* We haven't found any events yet. */ r = NULL; /* Scan through the pollfds looking for ready descriptors. */ for (; fdscanpos < nfds; fdscanpos--) { /* Did we poll on an invalid descriptor? */ assert((fds[fdscanpos].revents & POLLNVAL) == 0); /* * If either POLLERR ("an exceptional condition") or POLLHUP * ("has been disconnected") is set, then we should invoke * whatever callbacks we have available. */ if (fds[fdscanpos].revents & (POLLERR | POLLHUP)) { fds[fdscanpos].revents &= ~(POLLERR | POLLHUP); fds[fdscanpos].revents |= fds[fdscanpos].events; } /* Are we ready for reading? */ if (fds[fdscanpos].revents & POLLIN) { r = socketlist_get(S, (size_t)fds[fdscanpos].fd)->reader; socketlist_get(S, (size_t)fds[fdscanpos].fd)->reader = NULL; clearbit(fdscanpos, POLLIN); break; } /* Are we ready for writing? */ if (fds[fdscanpos].revents & POLLOUT) { r = socketlist_get(S, (size_t)fds[fdscanpos].fd)->writer; socketlist_get(S, (size_t)fds[fdscanpos].fd)->writer = NULL; clearbit(fdscanpos, POLLOUT); break; } } /* If we're returning the last registered event, stop the clock. */ if ((r != NULL) && (nfds == 0)) events_network_selectstats_stopclock(); /* Return the event we found, or NULL if we didn't find any. */ return (r); } /** * events_network_shutdown(void): * Clean up and free memory. This should run automatically via atexit. */ static void events_network_shutdown(void) { /* If we're not initialized, do nothing. */ if (S == NULL) return; /* If we have any registered events, do nothing. */ if (nfds > 0) return; /* Free the pollfd array. */ free(fds); fds = NULL; fds_alloc = 0; /* Free the socket list. */ socketlist_free(S); S = NULL; } spiped-1.6.3/libcperciva/events/events_network_selectstats.c000644 001751 001751 00000004071 14650270210 026066 0ustar00cpercivacperciva000000 000000 #include #include "monoclock.h" #include "events.h" #include "events_internal.h" /* Time when inter-select duration clock started. */ static struct timeval st; static int running = 0; /* Statistics on inter-select durations. */ static double N = 0.0; static double mu = 0.0; static double M2 = 0.0; static double max = 0.0; /** * events_network_selectstats_startclock(void): * Start the inter-select duration clock: There is a selectable event. */ void events_network_selectstats_startclock(void) { /* If the clock is already running, return silently. */ if (running) return; /* Get the current time; return silently on error. */ if (monoclock_get(&st)) return; /* The clock is now running. */ running = 1; } /** * events_network_selectstats_stopclock(void): * Stop the inter-select duration clock: There are no selectable events. */ void events_network_selectstats_stopclock(void) { /* The clock is no longer running. */ running = 0; } /** * events_network_selectstats_select(void): * Update inter-select duration statistics in relation to an upcoming * select(2) call. */ void events_network_selectstats_select(void) { struct timeval tnow; double t, d; /* If the clock is not running, return silently. */ if (!running) return; /* If we can't get the current time, fail silently. */ if (monoclock_get(&tnow)) goto done; /* Compute inter-select duration in seconds. */ t = timeval_diff(st, tnow); /* Adjust statistics. We track running mean, variance * N, and max. */ N += 1.0; d = t - mu; mu += d / N; M2 += d * (t - mu); if (max < t) max = t; done: /* The clock is no longer running. */ running = 0; } /** * events_network_selectstats(N, mu, va, max): * Return statistics on the inter-select durations since the last time this * function was called. */ void events_network_selectstats(double * _n, double * _mu, double * _va, double * _max) { /* Copy statistics out. */ *_n = N; *_mu = mu; if (N > 1.0) *_va = M2 / (N - 1.0); else *_va = 0.0; *_max = max; /* Zero statistics. */ N = mu = M2 = max = 0.0; } spiped-1.6.3/libcperciva/events/events_immediate.c000644 001751 001751 00000007321 14650270210 023716 0ustar00cpercivacperciva000000 000000 #include #include #include "mpool.h" #include "queue.h" #include "events.h" #include "events_internal.h" struct eventq { struct eventrec * r; TAILQ_ENTRY(eventq) entries; int prio; }; MPOOL(eventq, struct eventq, 4096); /* First nodes in the linked lists. */ static TAILQ_HEAD(tailhead, eventq) heads[32] = { TAILQ_HEAD_INITIALIZER(heads[0]), TAILQ_HEAD_INITIALIZER(heads[1]), TAILQ_HEAD_INITIALIZER(heads[2]), TAILQ_HEAD_INITIALIZER(heads[3]), TAILQ_HEAD_INITIALIZER(heads[4]), TAILQ_HEAD_INITIALIZER(heads[5]), TAILQ_HEAD_INITIALIZER(heads[6]), TAILQ_HEAD_INITIALIZER(heads[7]), TAILQ_HEAD_INITIALIZER(heads[8]), TAILQ_HEAD_INITIALIZER(heads[9]), TAILQ_HEAD_INITIALIZER(heads[10]), TAILQ_HEAD_INITIALIZER(heads[11]), TAILQ_HEAD_INITIALIZER(heads[12]), TAILQ_HEAD_INITIALIZER(heads[13]), TAILQ_HEAD_INITIALIZER(heads[14]), TAILQ_HEAD_INITIALIZER(heads[15]), TAILQ_HEAD_INITIALIZER(heads[16]), TAILQ_HEAD_INITIALIZER(heads[17]), TAILQ_HEAD_INITIALIZER(heads[18]), TAILQ_HEAD_INITIALIZER(heads[19]), TAILQ_HEAD_INITIALIZER(heads[20]), TAILQ_HEAD_INITIALIZER(heads[21]), TAILQ_HEAD_INITIALIZER(heads[22]), TAILQ_HEAD_INITIALIZER(heads[23]), TAILQ_HEAD_INITIALIZER(heads[24]), TAILQ_HEAD_INITIALIZER(heads[25]), TAILQ_HEAD_INITIALIZER(heads[26]), TAILQ_HEAD_INITIALIZER(heads[27]), TAILQ_HEAD_INITIALIZER(heads[28]), TAILQ_HEAD_INITIALIZER(heads[29]), TAILQ_HEAD_INITIALIZER(heads[30]), TAILQ_HEAD_INITIALIZER(heads[31]) }; /* For i < minq, heads[i] == NULL. */ static int minq = 32; /** * events_immediate_register(func, cookie, prio): * Register ${func}(${cookie}) to be run the next time events_run() is * invoked, after immediate events with smaller ${prio} values and before * events with larger ${prio} values. The value ${prio} must be in the range * [0, 31]. Return a cookie which can be passed to events_immediate_cancel(). */ void * events_immediate_register(int (* func)(void *), void * cookie, int prio) { struct eventrec * r; struct eventq * q; /* Sanity check. */ assert((prio >= 0) && (prio < 32)); /* Bundle into an eventrec record. */ if ((r = events_mkrec(func, cookie)) == NULL) goto err0; /* Create a linked list node. */ if ((q = mpool_eventq_malloc()) == NULL) goto err1; q->r = r; q->prio = prio; /* Add to the queue. */ TAILQ_INSERT_TAIL(&heads[prio], q, entries); /* Update minq if necessary. */ if (prio < minq) minq = prio; /* Success! */ return (q); err1: events_freerec(r); err0: /* Failure! */ return (NULL); } /** * events_immediate_cancel(cookie): * Cancel the immediate event for which the cookie ${cookie} was returned by * events_immediate_register(). */ void events_immediate_cancel(void * cookie) { struct eventq * q = cookie; int prio = q->prio; /* Remove it from the list. */ TAILQ_REMOVE(&heads[prio], q, entries); /* Free the eventrec. */ events_freerec(q->r); /* Return the node to the malloc pool. */ mpool_eventq_free(q); } /** * events_immediate_get(void): * Remove and return an eventrec structure from the immediate event queue, * or return NULL if there are no such events. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_immediate_get(void) { struct eventq * q; struct eventrec * r; /* Advance past priorities which have no events. */ while ((minq < 32) && (TAILQ_EMPTY(&heads[minq]))) minq++; /* Are there any events? */ if (minq == 32) return (NULL); /* * Remove the first node from the highest priority non-empty linked * list. */ q = TAILQ_FIRST(&heads[minq]); TAILQ_REMOVE(&heads[minq], q, entries); /* Extract the eventrec. */ r = q->r; /* Return the node to the malloc pool. */ mpool_eventq_free(q); /* Return the eventrec. */ return (r); } spiped-1.6.3/libcperciva/util/noeintr.h000644 001751 001751 00000000605 14650270210 021526 0ustar00cpercivacperciva000000 000000 #ifndef NOEINTR_H_ #define NOEINTR_H_ #include /** * noeintr_write(d, buf, nbytes): * Write ${nbytes} bytes of data from ${buf} to the file descriptor ${d} per * the write(2) system call, but looping until completion if interrupted by * a signal. Return ${nbytes} on success or -1 on error. */ ssize_t noeintr_write(int, const void *, size_t); #endif /* !NOEINTR_H_ */ spiped-1.6.3/libcperciva/util/insecure_memzero.h000644 001751 001751 00000002721 14650270210 023424 0ustar00cpercivacperciva000000 000000 #ifndef INSECURE_MEMZERO_H_ #define INSECURE_MEMZERO_H_ #include /* Pointer to memory-zeroing function. */ extern void (* volatile insecure_memzero_ptr)(volatile void *, size_t); /** * insecure_memzero(buf, len): * Attempt to zero ${len} bytes at ${buf} in spite of optimizing compilers' * best (standards-compliant) attempts to remove the buffer-zeroing. In * particular, to avoid performing the zeroing, a compiler would need to * use optimistic devirtualization; recognize that non-volatile objects do not * need to be treated as volatile, even if they are accessed via volatile * qualified pointers; and perform link-time optimization; in addition to the * dead-code elimination which often causes buffer-zeroing to be elided. * * Note however that zeroing a buffer does not guarantee that the data held * in the buffer is not stored elsewhere; in particular, there may be copies * held in CPU registers or in anonymous allocations on the stack, even if * every named variable is successfully sanitized. Solving the "wipe data * from the system" problem will require a C language extension which does not * yet exist. * * For more information, see: * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html * http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html */ static inline void insecure_memzero(volatile void * buf, size_t len) { (insecure_memzero_ptr)(buf, len); } #endif /* !INSECURE_MEMZERO_H_ */ spiped-1.6.3/libcperciva/util/optional_mutex.c000644 001751 001751 00000003254 14743020337 023123 0ustar00cpercivacperciva000000 000000 #ifdef OPTIONAL_MUTEX_PTHREAD_YES #include #endif #include "optional_mutex.h" /* Sanity check OPTIONAL_MUTEX_PTHREAD_* defines. */ #if defined(OPTIONAL_MUTEX_PTHREAD_YES) && defined(OPTIONAL_MUTEX_PTHREAD_NO) #error "You must not define both OPTIONAL_MUTEX_PTHREAD_YES " \ "and OPTIONAL_MUTEX_PTHREAD_NO" #elif !(defined(OPTIONAL_MUTEX_PTHREAD_YES) || \ defined(OPTIONAL_MUTEX_PTHREAD_NO)) #error "You must define either OPTIONAL_MUTEX_PTHREAD_YES " \ "or OPTIONAL_MUTEX_PTHREAD_NO" #endif #ifdef OPTIONAL_MUTEX_PTHREAD_YES /* Clang normally warns if you have a mutex held at the end of a function. */ #ifdef __clang__ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wthread-safety-analysis\"") #endif #endif /** * optional_mutex_lock(mutex): * If OPTIONAL_MUTEX_PTHREAD_YES is defined, call pthread_mutex_lock(); * if OPTIONAL_MUTEX_PTHREAD_NO is defined, do nothing. */ int optional_mutex_lock(pthread_mutex_t * mutex) { #ifdef OPTIONAL_MUTEX_PTHREAD_YES /* Mutexes are enabled; call the pthread function. */ return (pthread_mutex_lock(mutex)); #else (void)mutex; /* UNUSED */ /* Do nothing. */ return (0); #endif } /** * optional_mutex_unlock(mutex): * If OPTIONAL_MUTEX_PTHREAD_YES is defined, call pthread_mutex_unlock(); * if OPTIONAL_MUTEX_PTHREAD_NO is defined, do nothing. */ int optional_mutex_unlock(pthread_mutex_t * mutex) { #ifdef OPTIONAL_MUTEX_PTHREAD_YES /* Mutexes are enabled; call the pthread function. */ return (pthread_mutex_unlock(mutex)); #else (void)mutex; /* UNUSED */ /* Do nothing. */ return (0); #endif } #ifdef OPTIONAL_MUTEX_PTHREAD_YES #ifdef __clang__ _Pragma("clang diagnostic pop") #endif #endif spiped-1.6.3/libcperciva/util/setuidgid.h000644 001751 001751 00000002057 14650270210 022034 0ustar00cpercivacperciva000000 000000 #ifndef SETUIDGID_H_ #define SETUIDGID_H_ /* How should we treat supplementary groups? */ enum { SETUIDGID_SGROUP_IGNORE = 0, SETUIDGID_SGROUP_LEAVE_WARN, SETUIDGID_SGROUP_LEAVE_ERROR }; /** * setuidgid(user_group_string, leave_suppgrp): * Set the UID and/or GID to the names given in ${user_group_string}. If no * UID or GID can be found matching those strings, treat the values as numeric * IDs. Depending on the existence and position of a colon ":", the behaviour * is * - no ":" means that the string is a username. * - ":" in the first position means that the string is a groupname. * - otherwise, the string is parsed into "username:groupname". * * The behaviour with supplementary groups depends on ${leave_suppgrp}: * - SETUIDGID_SGROUP_IGNORE: do not attempt to leave supplementary groups. * - SETUIDGID_SGROUP_LEAVE_WARN: attempt to leave; if it fails, give a * warning but continue. * - SETUIDGID_SGROUP_LEAVE_ERROR: attempt to leave; if it fails, return * an error. */ int setuidgid(const char *, int); #endif /* !SETUIDGID_H_ */ spiped-1.6.3/libcperciva/util/entropy.h000644 001751 001751 00000001527 14650270210 021554 0ustar00cpercivacperciva000000 000000 #ifndef ENTROPY_H_ #define ENTROPY_H_ #include #include /* Opaque type. */ struct entropy_read_cookie; /** * entropy_read_init(void): * Initialize the ability to produce random bytes from the operating system, * and return a cookie. */ struct entropy_read_cookie * entropy_read_init(void); /** * entropy_read_fill(er, buf, buflen): * Fill the given buffer with random bytes provided by the operating system * using the resources in ${er}. */ int entropy_read_fill(struct entropy_read_cookie *, uint8_t *, size_t); /** * entropy_read_done(er): * Release any resources used by ${er}. */ int entropy_read_done(struct entropy_read_cookie *); /** * entropy_read(buf, buflen): * Fill the given buffer with random bytes provided by the operating system. */ int entropy_read(uint8_t *, size_t); #endif /* !ENTROPY_H_ */ spiped-1.6.3/libcperciva/util/monoclock.h000644 001751 001751 00000002127 14650270210 022035 0ustar00cpercivacperciva000000 000000 #ifndef MONOCLOCK_H_ #define MONOCLOCK_H_ #include /* Macro to simplify benchmarks. */ #define timeval_diff(x, y) ((double)((y).tv_sec - (x).tv_sec) + \ (double)((y).tv_usec - (x).tv_usec) * 0.000001) /** * monoclock_get(tv): * Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use * that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if * available) or gettimeofday(2). */ int monoclock_get(struct timeval *); /** * monoclock_get_cputime(tv): * Store in ${tv} the duration the process has been running if * CLOCK_PROCESS_CPUTIME_ID is available; fall back to monoclock_get() * otherwise. */ int monoclock_get_cputime(struct timeval *); /** * monoclock_getres(resd): * Store an upper limit on timer granularity in ${resd}. If CLOCK_MONOTONIC * is available, use that clock; if CLOCK_MONOTONIC is unavailable, use * CLOCK_REALTIME (if available) or gettimeofday(2). For this value to be * meaningful, we assume that clock_getres(x) succeeds iff clock_gettime(x) * succeeds. */ int monoclock_getres(double *); #endif /* !MONOCLOCK_H_ */ spiped-1.6.3/libcperciva/util/perftest.c000644 001751 001751 00000007224 14650270210 021703 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "monoclock.h" #include "warnp.h" #include "perftest.h" /** * perftest_buffers(nbytes, sizes, nsizes, nbytes_warmup, cputime, * init_func, func, clean_func, cookie): * Time using ${func} to process ${nbytes} bytes in blocks of ${sizes}. * Before timing any block sizes, process ${nbytes_warmup} bytes with the * maximum size in ${sizes}. If ${cputime} is non-zero, attempt to use * cpu time rather than wall-clock time. Invoke callback functions as: * init_func(cookie, buffer, buflen) * func(cookie, buffer, buflen, nbuffers) * clean_func(cookie) * where ${buffer} is large enough to hold the maximum buffer size. Print * the time and speed of processing each buffer size. ${init_func} and * ${clean_func} may be NULL. If ${init_func} has completed successfully, * then ${clean_func} will be called if there is a subsequent error. If * ${nbytes_warmup} is 0, then don't perform an initial ${init_func} && * ${func} && ${clean_func}. */ int perftest_buffers(size_t nbytes, const size_t * sizes, size_t nsizes, size_t nbytes_warmup, int cputime, int init_func(void *, uint8_t *, size_t), int func(void *, uint8_t *, size_t, size_t), int clean_func(void *), void * cookie) { uint8_t * buf; struct timeval begin, end; double * delta_s; double speed; size_t i; size_t buflen; size_t num_buffers; size_t nbuffers_warmup; size_t nbytes_in_buffer; size_t max_buflen = 0; /* Find the maximum buffer size. */ for (i = 0; i < nsizes; i++) { if (max_buflen < sizes[i]) max_buflen = sizes[i]; } assert(max_buflen > 0); /* Allocate buffers. */ if ((buf = malloc(max_buflen)) == NULL) { warnp("malloc"); goto err0; } if ((delta_s = malloc(nsizes * sizeof(double))) == NULL) { warnp("malloc"); goto err1; } /* Warm up. */ if (nbytes_warmup > 0) { nbuffers_warmup = nbytes_warmup / max_buflen; if (init_func && init_func(cookie, buf, max_buflen)) goto err2; if (func(cookie, buf, max_buflen, nbuffers_warmup)) goto err3; if (clean_func && clean_func(cookie)) goto err2; } /* Run operations. */ for (i = 0; i < nsizes; i++) { /* Configure and sanity checks. */ buflen = sizes[i]; assert(buflen > 0); num_buffers = nbytes / buflen; /* Set up. */ if (init_func && init_func(cookie, buf, buflen)) goto err2; /* Get beginning time. */ if (cputime) { if (monoclock_get_cputime(&begin)) { warnp("monoclock_get_cputime()"); goto err3; } } else { if (monoclock_get(&begin)) { warnp("monoclock_get()"); goto err3; } } /* Time actual code. */ if (func(cookie, buf, buflen, num_buffers)) goto err3; /* Get ending time. */ if (cputime) { if (monoclock_get_cputime(&end)) { warnp("monoclock_get_cputime()"); goto err3; } } else { if (monoclock_get(&end)) { warnp("monoclock_get()"); goto err3; } } /* Store time. */ delta_s[i] = timeval_diff(begin, end); /* Clean up. */ if (clean_func && clean_func(cookie)) goto err2; } /* Print output. */ for (i = 0; i < nsizes; i++) { buflen = sizes[i]; num_buffers = nbytes / buflen; /* We might not be processing an integer number of buffers. */ nbytes_in_buffer = buflen * num_buffers; speed = (double)nbytes_in_buffer / 1e6 / delta_s[i]; /* Print output. */ printf("%zu blocks of size %zu\t%.06f s\t%.06f MB/s\n", num_buffers, buflen, delta_s[i], speed); } /* Clean up. */ free(delta_s); free(buf); /* Success! */ return (0); err3: if (clean_func) clean_func(cookie); err2: free(delta_s); err1: free(buf); err0: /* Failure! */ return (-1); } spiped-1.6.3/libcperciva/util/asprintf.h000644 001751 001751 00000000502 14650270210 021672 0ustar00cpercivacperciva000000 000000 #ifndef ASPRINTF_H_ #define ASPRINTF_H_ /* Avoid namespace collisions with BSD/GNU asprintf. */ #ifdef asprintf #undef asprintf #endif #define asprintf libcperciva_asprintf /** * asprintf(ret, format, ...): * Do asprintf(3) like GNU and BSD do. */ int asprintf(char **, const char *, ...); #endif /* !ASPRINTF_H_ */ spiped-1.6.3/libcperciva/util/sock_util.c000644 001751 001751 00000020261 14743020337 022045 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include "asprintf.h" #include "sock.h" #include "warnp.h" #include "sock_internal.h" #include "sock_util.h" #ifdef POSIXFAIL_INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif #ifdef POSIXFAIL_INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif /** * sock_addr_cmp(sa1, sa2): * Return non-zero iff the socket addresses ${sa1} and ${sa2} are different. */ int sock_addr_cmp(const struct sock_addr * sa1, const struct sock_addr * sa2) { /* Family, socket type, and name length must match. */ if ((sa1->ai_family != sa2->ai_family) || (sa1->ai_socktype != sa2->ai_socktype) || (sa1->namelen != sa2->namelen)) return (1); /* The required length of the sockaddr must match. */ if (memcmp(sa1->name, sa2->name, sa1->namelen) != 0) return (1); /* Everything matched. */ return (0); } /** * sock_addr_dup(sa): * Duplicate the provided socket address. */ struct sock_addr * sock_addr_dup(const struct sock_addr * sa) { struct sock_addr * sa2; /* Allocate a struct sock_addr and copy fields. */ if ((sa2 = malloc(sizeof(struct sock_addr))) == NULL) goto err0; sa2->ai_family = sa->ai_family; sa2->ai_socktype = sa->ai_socktype; sa2->namelen = sa->namelen; /* Allocate and copy the sockaddr. */ if ((sa2->name = malloc(sa2->namelen)) == NULL) goto err1; memcpy(sa2->name, sa->name, sa2->namelen); /* Success! */ return (sa2); err1: free(sa2); err0: /* Failure! */ return (NULL); } /** * sock_addr_duplist(sas): * Duplicate the provided list of socket addresses. */ struct sock_addr ** sock_addr_duplist(struct sock_addr * const * sas) { struct sock_addr ** sas2; size_t i; /* Count socket addresses. */ for (i = 0; sas[i] != NULL; i++) continue; /* Allocate the list to hold addresses plus a NULL terminator. */ if ((sas2 = malloc((i + 1) * sizeof(struct sock_addr *))) == NULL) goto err0; /* Duplicate addresses and NULL-terminate. */ for (i = 0; sas[i] != NULL; i++) { if ((sas2[i] = sock_addr_dup(sas[i])) == NULL) goto err1; } sas2[i] = NULL; /* Success! */ return (sas2); err1: /* * Regardless of how many addresses we managed to duplicate before * failing and being sent here, we have a valid socket address list, * since the erroring sock_addr_dup call NULL-terminated it for us; * so we can free it and its constituent addresses easily. */ sock_addr_freelist(sas2); err0: /* Failure! */ return (NULL); } /** * sock_addr_serialize(sa, buf, buflen): * Allocate a buffer and serialize the socket address ${sa} into it. Return * the buffer via ${buf} and its length via ${buflen}. The serialization is * machine and operating system dependent. */ int sock_addr_serialize(const struct sock_addr * sa, uint8_t ** buf, size_t * buflen) { uint8_t * p; /* Compute buffer length and allocate buffer. */ *buflen = 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen; if ((p = *buf = malloc(*buflen)) == NULL) goto err0; /* Copy in data. */ memcpy(p, &sa->ai_family, sizeof(int)); p += sizeof(int); memcpy(p, &sa->ai_socktype, sizeof(int)); p += sizeof(int); memcpy(p, &sa->namelen, sizeof(socklen_t)); p += sizeof(socklen_t); memcpy(p, sa->name, sa->namelen); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * sock_addr_deserialize(buf, buflen): * Deserialize the ${buflen}-byte serialized socket address from ${buf}. */ struct sock_addr * sock_addr_deserialize(const uint8_t * buf, size_t buflen) { struct sock_addr * sa; /* Sanity check. */ if (buflen < 2 * sizeof(int) + sizeof(socklen_t)) goto err0; /* Allocate a structure and copy in fields. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err0; memcpy(&sa->ai_family, buf, sizeof(int)); buf += sizeof(int); memcpy(&sa->ai_socktype, buf, sizeof(int)); buf += sizeof(int); memcpy(&sa->namelen, buf, sizeof(socklen_t)); buf += sizeof(socklen_t); /* Allocate and copy the sockaddr. */ if (buflen != 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen) goto err1; if ((sa->name = malloc(sa->namelen)) == NULL) goto err1; memcpy(sa->name, buf, sa->namelen); /* Success! */ return (sa); err1: free(sa); err0: /* Failure! */ return (NULL); } /* Prettyprint an IPv4 address. */ static char * prettyprint_ipv4(struct sockaddr * name, size_t namelen) { struct sockaddr_in sa_in; char addr[INET_ADDRSTRLEN]; char * s; /* Check name length. */ if (namelen != sizeof(struct sockaddr_in)) return (NULL); /* Copy into buffer for alignment. */ memcpy(&sa_in, name, namelen); /* Convert IP address to string. */ if (inet_ntop(AF_INET, &sa_in.sin_addr, addr, sizeof(addr)) == NULL) return (NULL); /* Construct address string. */ if (asprintf(&s, "[%s]:%d", addr, ntohs(sa_in.sin_port)) == -1) return (NULL); /* Success! */ return (s); } /* Prettyprint an IPv6 address. */ static char * prettyprint_ipv6(struct sockaddr * name, size_t namelen) { struct sockaddr_in6 sa_in6; char addr[INET6_ADDRSTRLEN]; char * s; /* Check name length. */ if (namelen != sizeof(struct sockaddr_in6)) return (NULL); /* Copy into buffer for alignment. */ memcpy(&sa_in6, name, namelen); /* Convert IPv6 address to string. */ if (inet_ntop(AF_INET6, &sa_in6.sin6_addr, addr, sizeof(addr)) == NULL) return (NULL); /* Construct address string. */ if (asprintf(&s, "[%s]:%d", addr, ntohs(sa_in6.sin6_port)) == -1) return (NULL); /* Success! */ return (s); } /* Prettyprint a UNIX address. */ static char * prettyprint_unix(struct sockaddr_un * name) { /* Just strdup the path. */ return (strdup(name->sun_path)); } /** * sock_addr_prettyprint(sa): * Allocate and return a string in one of the forms * /path/to/unix/socket * [ip.v4.ad.dr]:port * [ipv6:add::ress]:port * representing the provided socket address. */ char * sock_addr_prettyprint(const struct sock_addr * sa) { /* Handle different types of addresses differently. */ switch (sa->ai_family) { case AF_INET: return (prettyprint_ipv4(sa->name, sa->namelen)); case AF_INET6: return (prettyprint_ipv6(sa->name, sa->namelen)); case AF_UNIX: return (prettyprint_unix((struct sockaddr_un *)(sa->name))); default: return (strdup("Unknown address")); } } /** * sock_addr_ensure_port(addr): * Allocate a new string to serve as the address for sock_resolve(). * If ${addr} contains a port number or is the address of a Unix domain * socket, duplicate that string; if not, add a port number of ":0". */ char * sock_addr_ensure_port(const char * addr) { char * bind_addr; char * cr; /* Sanity check. */ assert(addr != NULL); /* Where is the right-most colon in $addr? */ cr = strrchr(addr, ':'); /* Figure out what type of address $addr is. */ if (cr == addr) { /* * If the right-most colon is the first char, it's not a valid * address, but we'll strdup it anyway. */ bind_addr = strdup(addr); } else if (addr[0] == '/') { /* It's a Unix domain socket and doesn't need a port number. */ bind_addr = strdup(addr); } else if (addr[0] != '[') { /* It's a hostname... */ if (cr == NULL) { /* ... without any port number, so we add ":0". */ if (asprintf(&bind_addr, "%s:0", addr) == -1) goto err0; } else { /* ... which already has a port number. */ bind_addr = strdup(addr); } } else { /* addr[0] == '[', so it's an address... */ if ((cr == NULL) || (cr[-1] != ']')) { /* ... without a port number, so we add ":0". */ if (asprintf(&bind_addr, "%s:0", addr) == -1) goto err0; } else { /* ... which already has a port number. */ bind_addr = strdup(addr); } } /* Success! */ return (bind_addr); err0: /* Failure! */ return (NULL); } /** * sock_addr_validate(addr): * Check that ${addr} is syntactically valid, but do not perform any address * resolution. */ int sock_addr_validate(const char * addr) { /* Sanity check. */ assert(addr != NULL); /* Check for an empty address. */ if (strlen(addr) == 0) { warn0("Empty socket address."); goto err0; } /* If this isn't a UNIX socket address, check for a missing hostname. */ if ((addr[0] != '/') && (addr[0] == ':')) { warn0("No host in \"%s\"", addr); goto err0; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } spiped-1.6.3/libcperciva/util/getopt.h000644 001751 001751 00000015541 14650270210 021357 0ustar00cpercivacperciva000000 000000 #ifndef GETOPT_H_ #define GETOPT_H_ #include #include #include /** * This getopt implementation parses options of the following forms: * -a -b -c foo (single-character options) * -abc foo (packed single-character options) * -abcfoo (packed single-character options and an argument) * --foo bar (long option) * --foo=bar (long option and argument separated by '=') * * It does not support abbreviated options (e.g., interpreting --foo as * --foobar when there are no other --foo* options) since that misfeature * results in breakage when new options are added. It also does not support * options appearing after non-options (e.g., "cp foo bar -R") since that is * a horrible GNU perversion. * * Upon encountering '--', it consumes that argument (by incrementing optind) * and returns NULL to signal the end of option processing. Upon encountering * a bare '-' argument or any argument not starting with '-' it returns NULL * to signal the end of option processing (without consuming the argument). * Note that these behaviours do not apply when such strings are encountered * as arguments to options; e.g., if "--foo" takes an argument, then the * command line arguments "--foo -- --bar" is interpreted as having two * options ("--foo --" and "--bar") and no left-over arguments. */ /* Work around LLVM bug. */ #ifdef __clang__ #warning Working around bug in LLVM optimizer #warning For more details see https://bugs.llvm.org/show_bug.cgi?id=27190 #define GETOPT_USE_COMPUTED_GOTO #endif /* Work around broken header on Solaris. */ #if defined(__GNUC__) && (defined(sun) || defined(__sun)) #warning Working around broken header on Solaris #define GETOPT_USE_COMPUTED_GOTO #endif /* Select the method of performing local jumps. */ #ifdef GETOPT_USE_COMPUTED_GOTO /* Workaround with computed goto. */ #define DO_SETJMP DO_SETJMP_(__LINE__) #define DO_SETJMP_(x) DO_SETJMP__(x) #define DO_SETJMP__(x) \ void * getopt_initloop = && getopt_initloop_ ## x; \ getopt_initloop_ ## x: #define DO_LONGJMP \ goto *getopt_initloop #else /* Intended code, for fully C99-compliant systems. */ #define DO_SETJMP \ sigjmp_buf getopt_initloop; \ if (!getopt_initialized) \ sigsetjmp(getopt_initloop, 0) #define DO_LONGJMP \ siglongjmp(getopt_initloop, 1) #endif /* Avoid namespace collisions with libc getopt. */ #define getopt libcperciva_getopt #define optarg libcperciva_optarg #define optind libcperciva_optind #define opterr libcperciva_opterr #define optreset libcperciva_optreset /* Standard getopt global variables. */ extern const char * optarg; extern int optind, opterr, optreset; /* Dummy option string, equal to "(dummy)". */ #define GETOPT_DUMMY getopt_dummy /** * GETOPT(argc, argv): * When called for the first time (or the first time after optreset is set to * a nonzero value), return GETOPT_DUMMY, aka. "(dummy)". Thereafter, return * the next option string and set optarg / optind appropriately; abort if not * properly initialized when not being called for the first time. */ #define GETOPT(argc, argv) getopt(argc, argv) /** * GETOPT_SWITCH(ch): * Jump to the appropriate GETOPT_OPT, GETOPT_OPTARG, GETOPT_MISSING_ARG, or * GETOPT_DEFAULT based on the option string ${ch}. When called for the first * time, perform magic to index the options. * * GETOPT_SWITCH(ch) is equivalent to "switch (ch)" in a standard getopt loop. */ #define GETOPT_SWITCH(ch) \ volatile size_t getopt_ln_min = __LINE__; \ volatile size_t getopt_ln = getopt_ln_min - 1; \ volatile int getopt_default_missing = 0; \ DO_SETJMP; \ switch (getopt_initialized ? getopt_lookup(ch) + getopt_ln_min : getopt_ln++) /** * GETOPT_OPT(os): * Jump to this point when the option string ${os} is passed to GETOPT_SWITCH. * * GETOPT_OPT("-x") is equivalent to "case 'x'" in a standard getopt loop * which has an optstring containing "x". */ #define GETOPT_OPT(os) GETOPT_OPT_(os, __LINE__) #define GETOPT_OPT_(os, ln) GETOPT_OPT__(os, ln) #define GETOPT_OPT__(os, ln) \ case ln: \ if (getopt_initialized) \ goto getopt_skip_ ## ln; \ getopt_register_opt(os, ln - getopt_ln_min, 0); \ DO_LONGJMP; \ getopt_skip_ ## ln /** * GETOPT_OPTARG(os): * Jump to this point when the option string ${os} is passed to GETOPT_SWITCH, * unless no argument is available, in which case jump to GETOPT_MISSING_ARG * (if present) or GETOPT_DEFAULT (if not). * * GETOPT_OPTARG("-x") is equivalent to "case 'x'" in a standard getopt loop * which has an optstring containing "x:". */ #define GETOPT_OPTARG(os) GETOPT_OPTARG_(os, __LINE__) #define GETOPT_OPTARG_(os, ln) GETOPT_OPTARG__(os, ln) #define GETOPT_OPTARG__(os, ln) \ case ln: \ if (getopt_initialized) { \ assert(optarg != NULL); \ goto getopt_skip_ ## ln; \ } \ getopt_register_opt(os, ln - getopt_ln_min, 1); \ DO_LONGJMP; \ getopt_skip_ ## ln /** * GETOPT_MISSING_ARG: * Jump to this point if an option string specified in GETOPT_OPTARG is seen * but no argument is available. * * GETOPT_MISSING_ARG is equivalent to "case ':'" in a standard getopt loop * which has an optstring starting with ":". As such, it also has the effect * of disabling warnings about invalid options, as if opterr had been zeroed. */ #define GETOPT_MISSING_ARG GETOPT_MISSING_ARG_(__LINE__) #define GETOPT_MISSING_ARG_(ln) GETOPT_MISSING_ARG__(ln) #define GETOPT_MISSING_ARG__(ln) \ case ln: \ if (getopt_initialized) \ goto getopt_skip_ ## ln; \ getopt_register_missing(ln - getopt_ln_min); \ DO_LONGJMP; \ getopt_skip_ ## ln /** * GETOPT_DEFAULT: * Jump to this point if an unrecognized option is seen or if an option * specified in GETOPT_OPTARG is seen, no argument is available, and there is * no GETOPT_MISSING_ARG label. * * GETOPT_DEFAULT is equivalent to "case '?'" in a standard getopt loop. * * NOTE: This MUST be present in the GETOPT_SWITCH statement, and MUST occur * after all other GETOPT_* labels. */ #define GETOPT_DEFAULT GETOPT_DEFAULT_(__LINE__) #define GETOPT_DEFAULT_(ln) GETOPT_DEFAULT__(ln) #define GETOPT_DEFAULT__(ln) \ goto getopt_skip_ ## ln; \ case ln: \ getopt_initialized = 1; \ break; \ default: \ if (getopt_initialized) \ goto getopt_skip_ ## ln; \ if (!getopt_default_missing) { \ getopt_setrange(ln - getopt_ln_min); \ getopt_default_missing = 1; \ } \ DO_LONGJMP; \ getopt_skip_ ## ln /* * The back-end implementation. These should be considered internal * interfaces and not used directly. */ const char * getopt(int, char * const []); size_t getopt_lookup(const char *); void getopt_register_opt(const char *, size_t, int); void getopt_register_missing(size_t); void getopt_setrange(size_t); extern const char * getopt_dummy; extern int getopt_initialized; #endif /* !GETOPT_H_ */ spiped-1.6.3/libcperciva/util/warnp.h000644 001751 001751 00000003563 14650270210 021205 0ustar00cpercivacperciva000000 000000 #ifndef WARNP_H_ #define WARNP_H_ #include #include /* Avoid namespace collisions with BSD . */ #define warn libcperciva_warn #define warnx libcperciva_warnx /* * Maximum length of messages sent to syslog; longer warnings will * be truncated. */ #define WARNP_SYSLOG_MAX_LINE 4095 /** * warnp_setprogname(progname): * Set the program name to be used by warn() and warnx() to ${progname}. */ void warnp_setprogname(const char *); #define WARNP_INIT do { \ if (argv[0] != NULL) \ warnp_setprogname(argv[0]); \ } while (0) /** * warnp_syslog(enable): * Send future messages to syslog if ${enable} is non-zero. Messages to * syslog will be truncated at WARNP_SYSLOG_MAX_LINE characters. */ void warnp_syslog(int); /** * warnp_syslog_priority(priority): * Tag future syslog messages with priority ${priority}. Do not enable * syslog messages; for that, use warnp_syslog(). */ void warnp_syslog_priority(int); /* As in BSD . */ void warn(const char *, ...); void warnx(const char *, ...); /* * If compiled with DEBUG defined, print __FILE__ and __LINE__. */ #ifdef DEBUG #define warnline do { \ warnx("%s, %d", __FILE__, __LINE__); \ } while (0) #else #define warnline #endif /* * Call warn(3) or warnx(3) depending upon whether errno == 0; and clear * errno (so that the standard error message isn't repeated later). */ #define warnp(...) do { \ warnline; \ if (errno != 0) { \ warn(__VA_ARGS__); \ errno = 0; \ } else \ warnx(__VA_ARGS__); \ } while (0) /* * Call warnx(3) and set errno == 0. Unlike warnp(), this should be used * in cases where we're reporting a problem which we discover ourselves * rather than one which is reported to us from a library or the kernel. */ #define warn0(...) do { \ warnline; \ warnx(__VA_ARGS__); \ errno = 0; \ } while (0) #endif /* !WARNP_H_ */ spiped-1.6.3/libcperciva/util/ipc_sync.h000644 001751 001751 00000002617 14653532061 021674 0ustar00cpercivacperciva000000 000000 #ifndef IPC_SYNC_H_ #define IPC_SYNC_H_ /** * Normal usage: * 1) ipc_sync_init() * 2) fork a new process * 3) process x: ipc_sync_wait() * process y: ipc_sync_signal() * 4) both processes: ipc_sync_done() * * If there's a need to make _wait() or _signal() as fast as possible * (e.g. for a benchmark or a performance bottleneck), call the * relevant _prep() function before the critical section. */ /* Opaque structure. */ struct ipc_sync; /** * ipc_sync_init(void): * Initialize an inter-process synchronization barrier. This must be called * before forking. */ struct ipc_sync * ipc_sync_init(void); /** * ipc_sync_wait(IS): * Block until ipc_sync_signal() has been called with ${IS}. */ int ipc_sync_wait(struct ipc_sync *); /** * ipc_sync_signal(IS): * Indicate that ${IS} should no longer block. */ int ipc_sync_signal(struct ipc_sync *); /** * ipc_sync_wait_prep(IS): * Perform any operation(s) that would speed up an upcoming call to * ipc_sync_wait(). Calling this function is optional. */ int ipc_sync_wait_prep(struct ipc_sync *); /** * ipc_sync_signal_prep(IS): * Perform any operation(s) that would speed up an upcoming call to * ipc_sync_signal(). Calling this function is optional. */ int ipc_sync_signal_prep(struct ipc_sync *); /** * ipc_sync_done(IS): * Free resources associated with ${IS}. */ int ipc_sync_done(struct ipc_sync *); #endif /* !IPC_SYNC_H_ */ spiped-1.6.3/libcperciva/util/setgroups_none.h000644 001751 001751 00000000406 14650270210 023121 0ustar00cpercivacperciva000000 000000 #ifndef SETGROUPS_NONE_H_ #define SETGROUPS_NONE_H_ /** * setgroups_none(void): * Attempt to leave all supplementary groups. If we do not know how to do this * on the platform, return 0 anyway. */ int setgroups_none(void); #endif /* !SETGROUPS_NONE_H_ */ spiped-1.6.3/libcperciva/util/sock.c000644 001751 001751 00000031125 14743020337 021011 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include #include #include #include #include "imalloc.h" #include "parsenum.h" #include "warnp.h" #include "sock.h" #include "sock_internal.h" #include "sock_util.h" /* Convert a path into a socket address. */ static struct sock_addr ** sock_resolve_unix(const char * addr) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_un * sa_un; /* Allocate and populate a sockaddr_un structure. */ if ((sa_un = calloc(1, sizeof(struct sockaddr_un))) == NULL) goto err0; sa_un->sun_family = AF_UNIX; /* Safely copy addr into the structure. */ if (strlen(addr) >= sizeof(sa_un->sun_path)) { warn0("socket path too long: %s", addr); goto err1; } strcpy(sa_un->sun_path, addr); /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_UNIX; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sa_un; sa->namelen = sizeof(struct sockaddr_un); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sa_un); err0: /* Failure! */ return (NULL); } /* Resolve a host into a list of socket addresses. */ static struct sock_addr ** sock_resolve_host(const char * addr, const char * ports) { struct addrinfo hints; struct addrinfo * res; struct addrinfo * r; struct sock_addr ** sas; size_t n; int error; /* Create hints structure. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; /* Perform DNS lookup. */ if ((error = getaddrinfo(addr, ports, &hints, &res)) != 0) { warn0("Error looking up %s: %s", addr, gai_strerror(error)); goto err0; } /* Count addresses returned. */ for (n = 0, r = res; r != NULL; r = r->ai_next) n++; /* Sanity check. */ assert(n < SIZE_MAX); /* Allocate our response array. */ if (IMALLOC(sas, n + 1, struct sock_addr *)) goto err1; /* Create address structures. */ for (n = 0, r = res; r != NULL; n++, r = r->ai_next) { /* Allocate a structure. */ if ((sas[n] = malloc(sizeof(struct sock_addr))) == NULL) goto err2; /* Copy in the address metadata. */ sas[n]->ai_family = r->ai_family; sas[n]->ai_socktype = r->ai_socktype; sas[n]->namelen = r->ai_addrlen; /* Duplicate the address. */ if ((sas[n]->name = malloc(sas[n]->namelen)) == NULL) goto err3; memcpy(sas[n]->name, r->ai_addr, sas[n]->namelen); } /* Terminate array with a NULL. */ sas[n] = NULL; /* Free the linked list of addresses returned by getaddrinfo. */ freeaddrinfo(res); /* Success! */ return (sas); err3: free(sas[n]); err2: for (; n > 0; n--) sock_addr_free(sas[n - 1]); free(sas); err1: freeaddrinfo(res); err0: /* Failure! */ return (NULL); } /* Parse an IPv6 address into a socket address. */ static struct sock_addr ** sock_resolve_ipv6(const char * addr, in_port_t p) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_in6 * sin6; /* Allocate and populate a sockaddr_in6 structure. */ if ((sin6 = calloc(1, sizeof(struct sockaddr_in6))) == NULL) goto err0; sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(p); if (inet_pton(AF_INET6, addr, &sin6->sin6_addr) != 1) { warn0("Error parsing IP address: %s", addr); goto err1; } /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_INET6; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sin6; sa->namelen = sizeof(struct sockaddr_in6); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sin6); err0: /* Failure! */ return (NULL); } /* Parse an IPv4 address into a socket address. */ static struct sock_addr ** sock_resolve_ipv4(const char * addr, in_port_t p) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_in * sin; /* Allocate and populate a sockaddr_in structure. */ if ((sin = calloc(1, sizeof(struct sockaddr_in))) == NULL) goto err0; sin->sin_family = AF_INET; sin->sin_port = htons(p); if (inet_pton(AF_INET, addr, &sin->sin_addr) != 1) { warn0("Error parsing IP address: %s", addr); goto err1; } /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_INET; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sin; sa->namelen = sizeof(struct sockaddr_in); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sin); err0: /* Failure! */ return (NULL); } /** * sock_resolve(addr): * Return a NULL-terminated array of pointers to sock_addr structures. */ struct sock_addr ** sock_resolve(const char * addr) { struct sock_addr ** res; char * s; char * ports; char * ips; long p; /* Check syntax. */ if (sock_addr_validate(addr)) goto err0; /* If the address starts with '/', it's a Unix domain socket. */ if (addr[0] == '/') { res = sock_resolve_unix(addr); goto done0; } /* Copy the address so that we can mangle it. */ if ((s = strdup(addr)) == NULL) goto err0; /* The address should end with :port. Look for the last ':'. */ if ((ports = strrchr(s, ':')) == NULL) { warn0("Address must contain port number: %s", s); goto err1; } *ports++ = '\0'; /* If the address doesn't start with '[', it's a host name. */ if (s[0] != '[') { res = sock_resolve_host(s, ports); goto done1; } /* The address (sans :port) should end with ']'. */ if (s[strlen(s) - 1] != ']') { warn0("Invalid [IP address]: %s", s); goto err1; } /* Extract the IP address string. */ ips = &s[1]; ips[strlen(ips) - 1] = '\0'; /* Parse the port number in base 10, no trailing characters. */ if (PARSENUM_EX(&p, ports, 1, 65535, 10, 0)) { warn0("Invalid port number: %s", ports); goto err1; } /* If the IP address contains ':', it's IPv6; otherwise, IPv4. */ if (strchr(ips, ':') != NULL) res = sock_resolve_ipv6(ips, (in_port_t)p); else res = sock_resolve_ipv4(ips, (in_port_t)p); done1: /* Free string allocated by strdup. */ free(s); done0: /* Return result from sock_resolve_foo. */ return (res); err1: free(s); err0: /* Failure! */ return (NULL); } /** * sock_resolve_one(addr, addport): * Return a single sock_addr structure, or NULL if there are no addresses. * Warn if there is more than one address, and return the first one. * If ${addport} is non-zero, use sock_addr_ensure_port() to add a port number * of ":0" if appropriate. */ struct sock_addr * sock_resolve_one(const char * addr, int addport) { struct sock_addr ** sas; struct sock_addr * sa; struct sock_addr ** sa_tmp; char * addr_alloc = NULL; /* Prepare the address to resolve. */ if (addport && ((addr = addr_alloc = sock_addr_ensure_port(addr)) == NULL)) { warnp("sock_addr_ensure_port"); goto err0; } /* Resolve target address. */ if ((sas = sock_resolve(addr)) == NULL) { warnp("Error resolving socket address: %s", addr); goto err1; } /* Check that the array is not empty. */ if (sas[0] == NULL) { warn0("No addresses found for %s", addr); goto err2; } /* If there's more than one address, give a warning. */ if (sas[1] != NULL) warn0("Using the first of multiple addresses found for %s", addr); /* Keep the address we want. */ sa = sas[0]; /* Free the other addresses and list. */ for (sa_tmp = &sas[1]; *sa_tmp != NULL; sa_tmp++) sock_addr_free(*sa_tmp); free(sas); /* Clean up. */ free(addr_alloc); /* Success! */ return (sa); err2: sock_addr_freelist(sas); err1: free(addr_alloc); err0: /* Failure! */ return (NULL); } /** * sock_listener(sa): * Create a socket, attempt to set SO_REUSEADDR, bind it to the socket address * ${sa}, mark it for listening, and mark it as non-blocking. */ int sock_listener(const struct sock_addr * sa) { int s; int val = 1; /* Create a socket. */ if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) { warnp("socket(%d, %d)", sa->ai_family, sa->ai_socktype); goto err0; } /* Attempt to set SO_REUSEADDR. */ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { /* ENOPROTOOPT is ok. */ if (errno != ENOPROTOOPT) { warnp("setsockopt(SO_REUSEADDR)"); goto err1; } } /* Bind the socket. */ if (bind(s, sa->name, sa->namelen)) { warnp("Error binding socket"); goto err1; } /* Mark the socket as listening. */ if (listen(s, 10)) { warnp("Error marking socket as listening"); goto err1; } /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Error marking socket as non-blocking"); goto err1; } /* Success! */ return (s); err1: if (close(s)) warnp("close"); err0: /* Failure! */ return (-1); } /** * sock_connect(sas): * Iterate through the addresses in ${sas}, attempting to create a socket and * connect (blockingly). Once connected, stop iterating, mark the socket as * non-blocking, and return it. */ int sock_connect(struct sock_addr * const * sas) { int s = -1; /* Iterate through the addresses provided. */ for (; sas[0] != NULL; sas++) { /* Create a socket. */ if ((s = socket(sas[0]->ai_family, sas[0]->ai_socktype, 0)) == -1) continue; /* Attempt to connect. */ if (connect(s, sas[0]->name, sas[0]->namelen) == 0) break; /* Close the socket; this address didn't work. */ if (close(s)) warnp("close"); } /* Did we manage to connect? */ if (sas[0] == NULL) { warn0("Could not connect"); goto err0; } /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Cannot make connection non-blocking"); goto err1; } /* Success! */ return (s); err1: if (close(s)) warnp("close"); err0: /* Failure! */ return (-1); } /** * sock_connect_nb(sa): * Create a socket, mark it as non-blocking, and attempt to connect to the * address ${sa}. Return the socket (connected or in the process of * connecting) or -1 on error. */ int sock_connect_nb(const struct sock_addr * sa) { /* Let sock_connect_bind_nb handle this. */ return (sock_connect_bind_nb(sa, NULL)); } /** * sock_connect_bind_nb(sa, sa_b): * Create a socket, mark it as non-blocking, and attempt to connect to the * address ${sa}. If ${sa_b} is not NULL, attempt to set SO_REUSEADDR on the * socket and bind it to ${sa_b} immediately after creating it. Return the * socket (connected or in the process of connecting) or -1 on error. */ int sock_connect_bind_nb(const struct sock_addr * sa, const struct sock_addr * sa_b) { int s; int val = 1; /* Create a socket. */ if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) { warnp("socket(%d, %d)", sa->ai_family, sa->ai_socktype); goto err0; } /* Bind the socket to sa_b (if applicable). */ if (sa_b) { /* Attempt to set SO_REUSEADDR. */ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { /* ENOPROTOOPT is ok. */ if (errno != ENOPROTOOPT) { warnp("setsockopt(SO_REUSEADDR)"); goto err1; } } /* Bind socket. */ if ((bind(s, sa_b->name, sa_b->namelen)) == -1) { warnp("Error binding socket"); goto err1; } } /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Cannot make socket non-blocking"); goto err1; } /* Attempt to connect. */ if ((connect(s, sa->name, sa->namelen) == -1) && (errno != EINPROGRESS) && (errno != EINTR)) { warnp("connect"); goto err1; } /* We have a connect(ed|ing) socket. */ return (s); err1: if (close(s)) warnp("close"); err0: /* We failed to connect to this address. */ return (-1); } /** * sock_addr_free(sa): * Free the provided sock_addr structure. */ void sock_addr_free(struct sock_addr * sa) { /* Behave consistently with free(NULL). */ if (sa == NULL) return; /* Free the protocol-specific address structure and our struct. */ free(sa->name); free(sa); } /** * sock_addr_freelist(sas): * Free the provided NULL-terminated array of sock_addr structures. */ void sock_addr_freelist(struct sock_addr ** sas) { struct sock_addr ** p; /* Behave consistently with free(NULL). */ if (sas == NULL) return; /* Free structures until we hit NULL. */ for (p = sas; *p != NULL; p++) sock_addr_free(*p); /* Free the list. */ free(sas); } spiped-1.6.3/libcperciva/util/daemonize.h000644 001751 001751 00000000546 14650270210 022027 0ustar00cpercivacperciva000000 000000 #ifndef DAEMONIZE_H_ #define DAEMONIZE_H_ /** * daemonize(spid): * Daemonize and write the process ID in decimal to a file named ${spid}. * The parent process will exit only after the child has written its pid. * On success, the child will return 0; on failure, the parent will return * -1. */ int daemonize(const char *); #endif /* !DAEMONIZE_H_ */ spiped-1.6.3/libcperciva/util/sock_internal.h000644 001751 001751 00000000361 14650270210 022702 0ustar00cpercivacperciva000000 000000 #ifndef SOCK_INTERNAL_H_ #define SOCK_INTERNAL_H_ #include /* Socket address structure. */ struct sock_addr { int ai_family; int ai_socktype; struct sockaddr * name; socklen_t namelen; }; #endif /* !SOCK_INTERNAL_H_ */ spiped-1.6.3/libcperciva/util/fork_func.h000644 001751 001751 00000000721 14650270210 022023 0ustar00cpercivacperciva000000 000000 #ifndef FORK_FUNC_H_ #define FORK_FUNC_H_ #include /** * fork_func(func, cookie): * Fork and run ${func} in a new process, with ${cookie} as the sole argument. */ pid_t fork_func(int (*)(void *), void *); /** * fork_func_wait(pid): * Wait for the process ${pid} to finish. Print any error arising from ${pid}. * If ${pid} exited cleanly, return its exit code; otherwise, return -1. */ int fork_func_wait(pid_t); #endif /* !FORK_FUNC_H_ */ spiped-1.6.3/libcperciva/util/sock_util.h000644 001751 001751 00000003515 14743020337 022055 0ustar00cpercivacperciva000000 000000 #ifndef SOCK_UTIL_H_ #define SOCK_UTIL_H_ #include #include /* Opaque address structure. */ struct sock_addr; /** * sock_addr_cmp(sa1, sa2): * Return non-zero iff the socket addresses ${sa1} and ${sa2} are different. */ int sock_addr_cmp(const struct sock_addr *, const struct sock_addr *); /** * sock_addr_dup(sa): * Duplicate the provided socket address. */ struct sock_addr * sock_addr_dup(const struct sock_addr *); /** * sock_addr_duplist(sas): * Duplicate the provided list of socket addresses. */ struct sock_addr ** sock_addr_duplist(struct sock_addr * const *); /** * sock_addr_serialize(sa, buf, buflen): * Allocate a buffer and serialize the socket address ${sa} into it. Return * the buffer via ${buf} and its length via ${buflen}. The serialization is * machine and operating system dependent. */ int sock_addr_serialize(const struct sock_addr *, uint8_t **, size_t *); /** * sock_addr_deserialize(buf, buflen): * Deserialize the ${buflen}-byte serialized socket address from ${buf}. */ struct sock_addr * sock_addr_deserialize(const uint8_t *, size_t); /** * sock_addr_prettyprint(sa): * Allocate and return a string in one of the forms * /path/to/unix/socket * [ip.v4.ad.dr]:port * [ipv6:add::ress]:port * representing the provided socket address. */ char * sock_addr_prettyprint(const struct sock_addr *); /** * sock_addr_ensure_port(addr): * Allocate a new string to serve as the address for sock_resolve(). * If ${addr} contains a port number or is the address of a Unix domain * socket, duplicate that string; if not, add a port number of ":0". */ char * sock_addr_ensure_port(const char *); /** * sock_addr_validate(addr): * Check that ${addr} is syntactically valid, but do not perform any address * resolution. */ int sock_addr_validate(const char *); #endif /* !SOCK_UTIL_H_ */ spiped-1.6.3/libcperciva/util/getopt.c000644 001751 001751 00000020640 14650270210 021346 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "getopt.h" /* * Standard getopt global variables. optreset starts as non-zero in order to * trigger initialization behaviour. */ const char * optarg = NULL; int optind = 1; int opterr = 1; int optreset = 1; /* * Quasi-internal global variables -- these are used via GETOPT macros. */ const char * getopt_dummy = "(dummy)"; int getopt_initialized = 0; /* * Internal variables. */ static const char * cmdname = NULL; static struct opt { const char * os; size_t olen; int hasarg; } * opts = NULL; /* Probably a sparse array: some values, some NULLs. */ static size_t nopts; /* Maximum number of options. */ static size_t opt_missing; static size_t opt_default; static size_t opt_found; static const char * packedopts; static char popt[3]; static int atexit_registered = 0; /* Print a message. */ #define PRINTMSG(...) do { \ if (cmdname != NULL) \ fprintf(stderr, "%s: ", cmdname); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ } while (0) /* Print an error message and die. */ #define DIE(...) do { \ PRINTMSG(__VA_ARGS__); \ abort(); \ } while (0) /* Print a warning, if warnings are enabled. */ #define WARN(...) do { \ if (opterr == 0) \ break; \ if (opt_missing != opt_default) \ break; \ PRINTMSG(__VA_ARGS__); \ } while (0) /* Free allocated options array. */ static void getopt_atexit(void) { free(opts); opts = NULL; } /* Reset internal state. */ static void reset(int argc, char * const argv[]) { const char * p; /* If we have arguments, stash argv[0] for error messages. */ if (argc > 0) { /* Find the basename, without leading directories. */ for (p = cmdname = argv[0]; *p != '\0'; p++) { if (*p == '/') cmdname = p + 1; } } /* Discard any registered command-line options. */ free(opts); opts = NULL; /* Register atexit handler if we haven't done so already. */ if (!atexit_registered) { atexit(getopt_atexit); atexit_registered = 1; } /* We will start scanning from the first option. */ optind = 1; /* We're not in the middle of any packed options. */ packedopts = NULL; /* We haven't found any option yet. */ opt_found = (size_t)(-1); /* We're not initialized yet. */ getopt_initialized = 0; /* Finished resetting state. */ optreset = 0; } /* Search for an option string. */ static size_t searchopt(const char * os) { size_t i; /* Scan the array of options. */ for (i = 0; i < nopts; i++) { /* Is there an option in this slot? */ if (opts[i].os == NULL) continue; /* Does this match up to the length of the option string? */ if (strncmp(opts[i].os, os, opts[i].olen)) continue; /* Do we have