Add socketpair (#122)

This commit is contained in:
fabriziobertocci 2021-03-17 01:05:59 -04:00 committed by GitHub
parent 6388ef21f8
commit ca88ce5026
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 238 additions and 4 deletions

View file

@ -67,6 +67,7 @@ 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;
@ -290,6 +291,8 @@ int __mkntpathat(int, const char *, int, char16_t[PATH_MAX]) hidden;
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

@ -27,9 +27,9 @@
#include "libc/nt/runtime.h"
#include "libc/sysv/consts/o.h"
static const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\";
const char kPipeNamePrefix[] = "\\\\?\\pipe\\cosmo\\";
static size_t UintToChar16Array(char16_t *a, uint64_t i) {
size_t UintToChar16Array(char16_t *a, uint64_t i) {
size_t j = 0;
do {
a[j++] = i % 10 + '0';
@ -40,7 +40,7 @@ static size_t UintToChar16Array(char16_t *a, uint64_t i) {
return j;
}
static char16_t *CreatePipeName(char16_t *a) {
char16_t *CreatePipeName(char16_t *a) {
static long x;
unsigned i;
for (i = 0; kPipeNamePrefix[i]; ++i) a[i] = kPipeNamePrefix[i];

View file

@ -82,6 +82,7 @@ int32_t sys_getpeername(int32_t, void *, uint32_t *) hidden;
int32_t sys_poll(struct pollfd *, uint64_t, signed) hidden;
int32_t sys_shutdown(int32_t, int32_t) hidden;
int32_t sys_socket(int32_t, int32_t, int32_t) hidden;
int32_t sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden;
int64_t sys_readv(int32_t, const struct iovec *, int32_t) hidden;
int64_t sys_writev(int32_t, const struct iovec *, int32_t) hidden;
ssize_t sys_recvfrom(int, void *, size_t, int, void *, uint32_t *) hidden;
@ -104,6 +105,11 @@ int sys_bind_nt(struct Fd *, const void *, uint32_t);
int sys_accept_nt(struct Fd *, void *, uint32_t *, int) hidden;
int sys_closesocket_nt(struct Fd *) hidden;
int sys_socket_nt(int, int, int) hidden;
/*
int sys_socketpair_nt_stream(int, int, int, int[2]) hidden;
int sys_socketpair_nt_dgram(int, int, int, int[2]) hidden;
*/
int sys_socketpair_nt(int, int, int, int[2]) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
int sys_shutdown_nt(struct Fd *, int) hidden;

View file

@ -91,7 +91,7 @@ ssize_t writev(int, const struct iovec *, int);
ssize_t sendfile(int, int, int64_t *, size_t);
int getsockopt(int, int, int, void *, uint32_t *) paramsnonnull((5));
int setsockopt(int, int, int, const void *, uint32_t);
int socketpair(int, int, int, int64_t[2]) paramsnonnull();
int socketpair(int, int, int, int[2]) paramsnonnull();
int poll(struct pollfd *, uint64_t, int32_t) paramsnonnull();
int ppoll(struct pollfd *, uint64_t, const struct timespec *,
const struct sigset *) paramsnonnull((1, 4));

111
libc/sock/socketpair-nt.c Normal file
View file

@ -0,0 +1,111 @@
/*-*- 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/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"
// {{{ 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;
// Supports only AF_UNIX
if (family != AF_UNIX) {
errno = EAFNOSUPPORT;
return -1;
}
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;
}
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;
}
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[reader].kind = kFdFile;
g_fds.p[reader].flags = 0; // TODO
g_fds.p[reader].handle = hpipe;
g_fds.p[writer].kind = kFdFile;
g_fds.p[writer].flags = 0; // TODO
g_fds.p[writer].handle = h1;
sv[0] = reader;
sv[1] = writer;
return 0;
}
// }}}

54
libc/sock/socketpair.c Normal file
View file

@ -0,0 +1,54 @@
/*-*- 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/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
*
* @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.
* @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 (!IsWindows()) {
return sys_socketpair(family, type, protocol, sv);
}
return sys_socketpair_nt(family, type, protocol, sv);
}

View file

@ -0,0 +1,60 @@
/*-*- 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 Alison Winters
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/assert.h"
#include "libc/dce.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/testlib.h"
TEST(socketpair, testAfUnixStream) {
int fd[2];
const char ping[] = "ping";
const char pong[] = "pong";
char buf[32];
ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 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]));
}
TEST(socketpair, testAfUnixDgram) {
int fd[2];
const char ping[] = "ping";
const char pong[] = "pong";
char buf[32];
ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_DGRAM, 0, fd));
ASSERT_EQ(sizeof(ping), write(fd[0], ping, sizeof(ping)));
ASSERT_EQ(sizeof(ping), read(fd[1], buf, sizeof(buf)));
EXPECT_STREQ(ping, buf);
ASSERT_EQ(sizeof(pong), write(fd[1], pong, sizeof(pong)));
ASSERT_EQ(sizeof(pong), read(fd[0], buf, sizeof(buf)));
EXPECT_STREQ(pong, buf);
ASSERT_NE(-1, close(fd[0]));
ASSERT_NE(-1, close(fd[1]));
}