From 417748976208afc2d64a6071358ca4d2d2a19bca Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 16 Mar 2021 22:44:54 -0700 Subject: [PATCH] Perform fine-tuning of socketpair and pipe - removed unneeded share parameter from pipe on nt - socktpair(type | SOCK_CLOEXEC) is now polyfilled - use textwindows for linker micro-optimization - apologies for auto clang-format diff noise :( - improve socketpair docstring See #122 --- libc/calls/createpipename.c | 47 ++++++++++ libc/calls/internal.h | 2 - libc/calls/pipe-nt.c | 34 +------- libc/sock/internal.h | 1 + libc/sock/socketpair-nt.c | 135 +++++++++++++---------------- libc/sock/socketpair-sysv.c | 38 ++++++++ libc/sock/socketpair.c | 26 ++---- libc/sysv/calls/__sys_socketpair.s | 2 + libc/sysv/calls/sys_socketpair.s | 2 - libc/sysv/syscalls.sh | 2 +- test/libc/sock/socketpair_test.c | 16 ++++ 11 files changed, 172 insertions(+), 133 deletions(-) create mode 100644 libc/calls/createpipename.c create mode 100644 libc/sock/socketpair-sysv.c create mode 100644 libc/sysv/calls/__sys_socketpair.s delete mode 100644 libc/sysv/calls/sys_socketpair.s diff --git a/libc/calls/createpipename.c b/libc/calls/createpipename.c new file mode 100644 index 000000000..8b81f5e25 --- /dev/null +++ b/libc/calls/createpipename.c @@ -0,0 +1,47 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/alg/reverse.internal.h" +#include "libc/calls/calls.h" +#include "libc/nt/process.h" + +static const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\"; + +static textwindows size_t UintToChar16Array(char16_t *a, uint64_t i) { + size_t j = 0; + do { + a[j++] = i % 10 + '0'; + i /= 10; + } while (i > 0); + a[j] = 0; + reverse(a, j); + return j; +} + +textwindows char16_t *CreatePipeName(char16_t *a) { + static long x; + unsigned i; + for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i]; + i += UintToChar16Array(a + i, GetCurrentProcessId()); + a[i++] = u'-'; + i += UintToChar16Array(a + i, GetCurrentProcessId()); + a[i++] = u'-'; + i += UintToChar16Array(a + i, x++); + a[i] = u'\0'; + return a; +} diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 71ad7b97a..32e057289 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -67,7 +67,6 @@ hidden extern int __vforked; hidden extern unsigned __sighandrvas[NSIG]; hidden extern struct Fds g_fds; hidden extern const struct NtSecurityAttributes kNtIsInheritable; -hidden extern const char kPipeNamePrefix[]; int __reservefd(void) hidden; void __releasefd(int) hidden; @@ -292,7 +291,6 @@ unsigned __wincrash_nt(struct NtExceptionPointers *); ssize_t sys_readv_nt(struct Fd *, const struct iovec *, int) hidden; ssize_t sys_writev_nt(struct Fd *, const struct iovec *, int) hidden; char16_t *CreatePipeName(char16_t *) hidden; -size_t UintToChar16Array(char16_t *, uint64_t) hidden; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § syscalls » metal ─╬─│┼ diff --git a/libc/calls/pipe-nt.c b/libc/calls/pipe-nt.c index 493d5f03a..9a23cd87d 100644 --- a/libc/calls/pipe-nt.c +++ b/libc/calls/pipe-nt.c @@ -16,42 +16,12 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/alg/reverse.internal.h" #include "libc/calls/internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" -#include "libc/nt/enum/filesharemode.h" #include "libc/nt/ipc.h" -#include "libc/nt/process.h" #include "libc/nt/runtime.h" -#include "libc/sysv/consts/o.h" - -const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\"; - -size_t UintToChar16Array(char16_t *a, uint64_t i) { - size_t j = 0; - do { - a[j++] = i % 10 + '0'; - i /= 10; - } while (i > 0); - a[j] = 0; - reverse(a, j); - return j; -} - -char16_t *CreatePipeName(char16_t *a) { - static long x; - unsigned i; - for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i]; - i += UintToChar16Array(a + i, GetCurrentProcessId()); - a[i++] = u'-'; - i += UintToChar16Array(a + i, GetCurrentProcessId()); - a[i++] = u'-'; - i += UintToChar16Array(a + i, x++); - a[i] = u'\0'; - return a; -} textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) { int64_t hin, hout; @@ -66,8 +36,8 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) { if ((hin = CreateNamedPipe(pipename, kNtPipeAccessInbound, kNtPipeWait | kNtPipeReadmodeByte, 1, 65536, 65536, 0, &kNtIsInheritable)) != -1) { - if ((hout = CreateFile(pipename, kNtGenericWrite, kNtFileShareWrite, - &kNtIsInheritable, kNtOpenExisting, 0, 0)) != -1) { + if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable, + kNtOpenExisting, 0, 0)) != -1) { g_fds.p[reader].kind = kFdFile; g_fds.p[reader].flags = flags; g_fds.p[reader].handle = hin; diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 50b646c98..1a9c38838 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -70,6 +70,7 @@ int32_t __sys_connect(int32_t, const void *, uint32_t) hidden; int32_t __sys_socket(int32_t, int32_t, int32_t) hidden; int32_t __sys_getsockname(int32_t, void *, uint32_t *) hidden; int32_t __sys_getpeername(int32_t, void *, uint32_t *) hidden; +int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden; int32_t sys_accept4(int32_t, void *, uint32_t *, int) nodiscard hidden; int32_t sys_accept(int32_t, void *, uint32_t *) hidden; diff --git a/libc/sock/socketpair-nt.c b/libc/sock/socketpair-nt.c index c92aa85b4..8855f49cb 100644 --- a/libc/sock/socketpair-nt.c +++ b/libc/sock/socketpair-nt.c @@ -16,96 +16,77 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/errno.h" -#include "libc/mem/mem.h" -#include "libc/sock/internal.h" -#include "libc/sock/yoink.inc" -#include "libc/sysv/consts/fio.h" -#include "libc/sysv/consts/o.h" -#include "libc/sysv/consts/sock.h" -#include "libc/sysv/consts/af.h" - -#include "libc/alg/reverse.internal.h" #include "libc/nt/createfile.h" #include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/creationdisposition.h" -#include "libc/nt/enum/filesharemode.h" #include "libc/nt/ipc.h" -#include "libc/nt/process.h" #include "libc/nt/runtime.h" - +#include "libc/sock/internal.h" +#include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/o.h" +#include "libc/sysv/consts/sock.h" +#include "libc/sysv/errfuns.h" // {{{ sys_socketpair_nt -int sys_socketpair_nt(int family, int type, int proto, int sv[2]) { - int64_t hpipe, h1, h2; - int reader, writer; - char16_t pipename[64]; - uint32_t mode; +textwindows int sys_socketpair_nt(int family, int type, int proto, int sv[2]) { + int64_t hpipe, h1, h2; + int reader, writer, oflags; + char16_t pipename[64]; + uint32_t mode; - // Supports only AF_UNIX - if (family != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } + // Supports only AF_UNIX + if (family != AF_UNIX) { + return eafnosupport(); + } - mode = kNtPipeWait; - if (type == SOCK_STREAM) { - mode |= kNtPipeReadmodeByte | kNtPipeTypeByte; - } else if ((type == SOCK_DGRAM) || (type == SOCK_SEQPACKET)) { - mode |= kNtPipeReadmodeMessage | kNtPipeTypeMessage; - } else { - errno = EOPNOTSUPP; - return -1; - } + oflags = 0; + if (type & SOCK_CLOEXEC) oflags |= O_CLOEXEC; + type &= ~SOCK_CLOEXEC; - CreatePipeName(pipename); - if ((reader = __reservefd()) == -1) return -1; - if ((writer = __reservefd()) == -1) { - __releasefd(reader); - return -1; - } - if ((hpipe = CreateNamedPipe(pipename, - kNtPipeAccessDuplex, - mode, - 1, - 65536, - 65536, - 0, - &kNtIsInheritable)) == -1) { - __winerr(); - __releasefd(writer); - __releasefd(reader); - return -1; - } + mode = kNtPipeWait; + if (type == SOCK_STREAM) { + mode |= kNtPipeReadmodeByte | kNtPipeTypeByte; + } else if ((type == SOCK_DGRAM) || (type == SOCK_SEQPACKET)) { + mode |= kNtPipeReadmodeMessage | kNtPipeTypeMessage; + } else { + return eopnotsupp(); + } - h1 = CreateFile(pipename, - kNtGenericWrite | kNtGenericRead, - 0, // Not shared - &kNtIsInheritable, - kNtOpenExisting, 0, 0); - if (h1 == -1) { - CloseHandle(hpipe); - __winerr(); - __releasefd(writer); - __releasefd(reader); - return -1; - } + CreatePipeName(pipename); + if ((reader = __reservefd()) == -1) return -1; + if ((writer = __reservefd()) == -1) { + __releasefd(reader); + return -1; + } + if ((hpipe = CreateNamedPipe(pipename, kNtPipeAccessDuplex, mode, 1, 65536, + 65536, 0, &kNtIsInheritable)) == -1) { + __winerr(); + __releasefd(writer); + __releasefd(reader); + return -1; + } - g_fds.p[reader].kind = kFdFile; - g_fds.p[reader].flags = 0; // TODO - g_fds.p[reader].handle = hpipe; + h1 = CreateFile(pipename, kNtGenericWrite | kNtGenericRead, + 0, // Not shared + &kNtIsInheritable, kNtOpenExisting, 0, 0); + if (h1 == -1) { + CloseHandle(hpipe); + __winerr(); + __releasefd(writer); + __releasefd(reader); + return -1; + } - g_fds.p[writer].kind = kFdFile; - g_fds.p[writer].flags = 0; // TODO - g_fds.p[writer].handle = h1; + g_fds.p[reader].kind = kFdFile; + g_fds.p[reader].flags = oflags; + g_fds.p[reader].handle = hpipe; - sv[0] = reader; - sv[1] = writer; - return 0; + g_fds.p[writer].kind = kFdFile; + g_fds.p[writer].flags = oflags; + g_fds.p[writer].handle = h1; + + sv[0] = reader; + sv[1] = writer; + return 0; } // }}} - - - - diff --git a/libc/sock/socketpair-sysv.c b/libc/sock/socketpair-sysv.c new file mode 100644 index 000000000..45d6a1179 --- /dev/null +++ b/libc/sock/socketpair-sysv.c @@ -0,0 +1,38 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/dce.h" +#include "libc/errno.h" +#include "libc/sock/internal.h" +#include "libc/sysv/consts/sock.h" + +int sys_socketpair(int family, int type, int protocol, int sv[2]) { + int e = errno; + if (__sys_socketpair(family, type, protocol, sv) != -1) return 0; + if ((type & (SOCK_CLOEXEC | SOCK_NONBLOCK)) && + (errno == EINVAL || errno == EPROTOTYPE || errno == EPROTONOSUPPORT)) { + errno = e; + if (__sys_socketpair(family, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), + protocol, sv) != -1) { + __fixupnewsockfd(sv[0], type); + __fixupnewsockfd(sv[1], type); + return 0; + } + } + return -1; +} diff --git a/libc/sock/socketpair.c b/libc/sock/socketpair.c index ae37f7671..c0b928bc8 100644 --- a/libc/sock/socketpair.c +++ b/libc/sock/socketpair.c @@ -20,35 +20,23 @@ #include "libc/sock/internal.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" -#include "libc/sysv/consts/sock.h" -#include "libc/sysv/errfuns.h" /** - * Creates a pair of connected sockets + * Creates bidirectional pipe. * - * @param family can be AF_UNIX, AF_INET, etc. - * @param type can be SOCK_STREAM (for TCP), SOCK_DGRAM (e.g. UDP), or - * SOCK_RAW (IP) so long as IP_HDRINCL was passed to setsockopt(); - * and additionally, may be or'd with SOCK_NONBLOCK, SOCK_CLOEXEC - * @param protocol can be IPPROTO_TCP, IPPROTO_UDP, or IPPROTO_ICMP - * @param sv a vector of 2 integers to store the created sockets. + * @param family should be AF_UNIX or synonymously AF_LOCAL + * @param type may be or'd with SOCK_CLOEXEC + * @param sv a vector of 2 integers to store the created sockets * @return 0 if success, -1 in case of error * @error EFAULT, EPFNOSUPPORT, etc. * @see libc/sysv/consts.sh * @asyncsignalsafe */ int socketpair(int family, int type, int protocol, int sv[2]) { - if (family == AF_UNSPEC) { - family = AF_UNIX; - } else if (family == AF_INET6) { - /* Recommend IPv6 on frontend serving infrastructure only. That's - what Google Cloud does. It's more secure. It also means poll() - will work on Windows, which doesn't allow mixing third layers. */ - errno = EAFNOSUPPORT; - return epfnosupport(); - } + if (family == AF_UNSPEC) family = AF_UNIX; if (!IsWindows()) { return sys_socketpair(family, type, protocol, sv); + } else { + return sys_socketpair_nt(family, type, protocol, sv); } - return sys_socketpair_nt(family, type, protocol, sv); } diff --git a/libc/sysv/calls/__sys_socketpair.s b/libc/sysv/calls/__sys_socketpair.s new file mode 100644 index 000000000..8bd0753c7 --- /dev/null +++ b/libc/sysv/calls/__sys_socketpair.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall __sys_socketpair,0x0870870872087035,globl,hidden diff --git a/libc/sysv/calls/sys_socketpair.s b/libc/sysv/calls/sys_socketpair.s deleted file mode 100644 index 1a094acb3..000000000 --- a/libc/sysv/calls/sys_socketpair.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall sys_socketpair,0x0870870872087035,globl,hidden diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 2c0853616..e2be2da08 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -88,7 +88,7 @@ scall sys_bind 0x0680680682068031 globl hidden scall sys_listen 0x06a06a06a206a032 globl hidden scall __sys_getsockname 0x0200200202020033 globl hidden scall __sys_getpeername 0x01f01f08d201f034 globl hidden -scall sys_socketpair 0x0870870872087035 globl hidden +scall __sys_socketpair 0x0870870872087035 globl hidden scall sys_setsockopt 0x0690690692069036 globl hidden scall sys_getsockopt 0x0760760762076037 globl hidden scall sys_fork 0x0020020022002039 globl hidden # xnu needs eax&=~-edx bc eax always holds pid and edx is 0 for parent and 1 for child diff --git a/test/libc/sock/socketpair_test.c b/test/libc/sock/socketpair_test.c index fb84d153d..7b84c2294 100644 --- a/test/libc/sock/socketpair_test.c +++ b/test/libc/sock/socketpair_test.c @@ -20,6 +20,7 @@ #include "libc/dce.h" #include "libc/sock/sock.h" #include "libc/sysv/consts/af.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sock.h" #include "libc/testlib/testlib.h" @@ -57,4 +58,19 @@ TEST(socketpair, testAfUnixDgram) { ASSERT_NE(-1, close(fd[1])); } +TEST(socketpair, testCloexec) { + int fd[2]; + const char ping[] = "ping"; + const char pong[] = "pong"; + char buf[32]; + ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fd)); + ASSERT_EQ(sizeof(ping), write(fd[0], ping, sizeof(ping))); + ASSERT_EQ(sizeof(ping), read(fd[1], buf, sizeof(ping))); + EXPECT_STREQ(ping, buf); + ASSERT_EQ(sizeof(pong), write(fd[1], pong, sizeof(pong))); + ASSERT_EQ(sizeof(pong), read(fd[0], buf, sizeof(pong))); + EXPECT_STREQ(pong, buf); + ASSERT_NE(-1, close(fd[0])); + ASSERT_NE(-1, close(fd[1])); +}