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
This commit is contained in:
Justine Tunney 2021-03-16 22:44:54 -07:00
parent 4e93750afd
commit 4177489762
11 changed files with 172 additions and 133 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
// }}}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall __sys_socketpair,0x0870870872087035,globl,hidden

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_socketpair,0x0870870872087035,globl,hidden

View file

@ -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

View file

@ -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]));
}