Support non-blocking i/o across platforms

This change introduces new tests for `O_NONBLOCK` and `SOCK_NONBLOCK` to
confirm that non-blocking i/o is now working on all supported platforms,
including Windows. For example, you can now say on Windows, MacOS, etc.:

    socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

To create a non-blocking IPv4 TCP socket. Or you can enable non-blocking
i/o on an existing socket / pipe / etc. file descriptor by calling fcntl

    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);

This functionality is polyfilled on older Linux kernels too, e.g. RHEL5.
Now that fcntl() support is much better the FIOCLEX / FIONCLEX polyfills
for ioctl() have been removed since they're ugly non-POSIX diameond APIs

This change fixes a weakness in kprintf() that was causing Windows trace
tools to frequently crash.
This commit is contained in:
Justine Tunney 2023-07-23 02:56:47 -07:00
parent 5c9e03e3e0
commit 1d4eb08fa1
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
102 changed files with 678 additions and 331 deletions

View file

@ -36,10 +36,13 @@
#include "libc/nt/runtime.h"
#include "libc/nt/struct/byhandlefileinformation.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/thread.h"
@ -307,21 +310,49 @@ static textwindows int sys_fcntl_nt_dupfd(int fd, int cmd, int start) {
return sys_dup_nt(fd, -1, (cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0), start);
}
static textwindows int sys_fcntl_nt_setfl(int fd, unsigned *flags, unsigned arg,
unsigned supported) {
unsigned old, neu, changed, other, allowed;
old = *flags & supported;
other = *flags & ~supported;
neu = arg & supported;
changed = old ^ neu;
// you may change the following access mode flags:
//
// - O_NONBLOCK make read() raise EAGAIN
// - O_NDELAY same thing as O_NONBLOCK
//
allowed = O_NONBLOCK;
if (changed & ~allowed) {
// the following access mode flags are supported, but it's currently
// not possible to change them on windows.
//
// - O_APPEND tried to support but failed
// - O_RANDOM use posix_fadvise() instead
// - O_SEQUENTIAL use posix_fadvise() instead
// - O_DIRECT possibly in future?
// - O_DSYNC possibly in future?
// - O_RSYNC possibly in future?
// - O_SYNC possibly in future?
//
return enotsup();
}
// 1. ignore flags that aren't access mode flags
// 2. return zero if nothing's changed
*flags = other | neu;
return 0;
}
textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
int rc;
uint32_t flags;
int access_mode_flags = O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT |
O_NOATIME | O_NONBLOCK | O_RANDOM | O_SEQUENTIAL;
if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdSocket)) {
if (cmd == F_GETFL) {
rc = g_fds.p[fd].flags &
(O_ACCMODE | O_APPEND | O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK |
O_RANDOM | O_SEQUENTIAL);
rc = g_fds.p[fd].flags & access_mode_flags;
} else if (cmd == F_SETFL) {
// O_APPEND doesn't appear to be tunable at cursory glance
// O_NONBLOCK might require we start doing all i/o in threads
// O_DSYNC / O_RSYNC / O_SYNC maybe if we fsync() everything
// O_DIRECT | O_RANDOM | O_SEQUENTIAL | O_NDELAY possible but
// not worth it.
rc = enosys();
rc = sys_fcntl_nt_setfl(fd, &g_fds.p[fd].flags, arg, access_mode_flags);
} else if (cmd == F_GETFD) {
if (g_fds.p[fd].flags & O_CLOEXEC) {
rc = FD_CLOEXEC;

View file

@ -26,9 +26,15 @@
// Applies file descriptor fixups on XNU or old Linux.
// See __fixupnewsockfd() for socket file descriptors.
int __fixupnewfd(int fd, int flags) {
int file_mode;
if (fd != -1) {
if (flags & O_CLOEXEC) {
_npassert(!__sys_fcntl(fd, F_SETFD, FD_CLOEXEC));
_unassert((file_mode = __sys_fcntl(fd, F_GETFD)) != -1);
_unassert(!__sys_fcntl(fd, F_SETFD, file_mode | FD_CLOEXEC));
}
if (flags & O_NONBLOCK) {
_unassert((file_mode = __sys_fcntl(fd, F_GETFL)) != -1);
_unassert(!__sys_fcntl(fd, F_SETFL, file_mode | O_NONBLOCK));
}
}
return fd;

View file

@ -76,6 +76,6 @@ int getdomainname(char *name, size_t len) {
if (!rc && len && !strcmp(name, "(none)")) {
name[0] = 0;
}
STRACE("getdomainname([%#.*s], %'zu) → %d% m", len, name, len, rc);
STRACE("getdomainname([%#.*s], %'zu) → %d% m", (int)len, name, len, rc);
return rc;
}

View file

@ -71,6 +71,6 @@ int gethostname(char *name, size_t len) {
} else {
rc = enosys();
}
STRACE("gethostname([%#.*s], %'zu) → %d% m", len, name, len, rc);
STRACE("gethostname([%#.*s], %'zu) → %d% m", (int)len, name, len, rc);
return rc;
}

View file

@ -558,34 +558,6 @@ static int ioctl_siocgifflags(int fd, void *arg) {
}
}
/**
* Sets "close on exec" on file descriptor the fast way.
*
* @see ioctl(fd, FIOCLEX, 0) dispatches here
*/
static int ioctl_fioclex(int fd, int req) {
int rc;
if (fd >= 0) {
if (IsWindows() || (fd < g_fds.n && g_fds.p[fd].kind == kFdZip)) {
if (__isfdopen(fd)) {
if (req == FIOCLEX) {
g_fds.p[fd].flags |= O_CLOEXEC;
} else {
g_fds.p[fd].flags &= ~O_CLOEXEC;
}
rc = 0;
} else {
rc = ebadf();
}
} else {
rc = sys_ioctl(fd, req);
}
} else {
rc = einval();
}
return rc;
}
/**
* Performs special i/o operation on file descriptor.
*
@ -618,17 +590,6 @@ static int ioctl_fioclex(int fd, int req) {
* - `TIOCNXCL` to give up exclusive mode on terminal. Only
* available on UNIX.
*
* - `FIOCLEX` sets the `O_CLOEXEC` state (no arg) noting that this
* polyfill may be removed in the future, and code should migrate
* to the equivalent fcntl() api.
*
* - `FIONBIO` sets the `O_NONBLOCK` state (arg is `int *enabled`)
* which is supported on Windows for sockets.
*
* - `FIONCLEX` clears the `O_CLOEXEC` state (no arg) noting that
* this polyfill may be removed in the future, and code should
* migrate to the equivalent fcntl() api.
*
* - `SIOCGIFCONF` takes an struct ifconf object of a given size,
* whose arg is `struct ifconf *`. It implements the Linux style
* and modifies the following:
@ -647,6 +608,9 @@ static int ioctl_fioclex(int fd, int req) {
* network broadcast addr. This data structure should be obtained
* by calling `SIOCGIFCONF`.
*
* - `FIONBIO` isn't polyfilled; use `fcntl(F_SETFL, O_NONBLOCK)`
* - `FIOCLEX` isn't polyfilled; use `fcntl(F_SETFD, FD_CLOEXEC)`
* - `FIONCLEX` isn't polyfilled; use `fcntl(F_SETFD, 0)`
* - `TCGETS` isn't polyfilled; use tcgetattr()
* - `TCSETS` isn't polyfilled; use tcsetattr()
* - `TCSETSW` isn't polyfilled; use tcsetattr()
@ -673,10 +637,6 @@ int ioctl(int fd, unsigned long request, ...) {
va_end(va);
if (request == FIONBIO) {
rc = ioctl_default(fd, request, arg);
} else if (request == FIOCLEX) {
rc = ioctl_fioclex(fd, request);
} else if (request == FIONCLEX) {
rc = ioctl_fioclex(fd, request);
} else if (request == TIOCGWINSZ) {
rc = tcgetwinsize(fd, arg);
} else if (request == TIOCSWINSZ) {

View file

@ -33,6 +33,7 @@
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
@ -51,6 +52,9 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data,
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
POLLTRACE("IOCP EINTR");
}
if (fd->flags & O_NONBLOCK) {
return eagain();
}
if (_check_interrupts(true, g_fds.p)) {
POLLTRACE("sys_read_nt interrupted");
return -1;

View file

@ -56,6 +56,6 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);
}
STRACE("readlinkat(%s, %#s, [%#.*s]) → %d% m", DescribeDirfd(dirfd), path,
MAX(0, bytes), buf, bytes);
(int)MAX(0, bytes), buf, bytes);
return bytes;
}

View file

@ -42,6 +42,7 @@ unsigned __wincrash(struct NtExceptionPointers *ep) {
ucontext_t ctx;
struct CosmoTib *tib;
static bool noreentry;
noreentry = true;
if ((tib = __tls_enabled ? __get_tls_privileged() : 0)) {
if (~tib->tib_flags & TIB_FLAG_WINCRASHING) {

View file

@ -1,7 +1,7 @@
/*-*- 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
Copyright 2023 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
@ -16,21 +16,23 @@
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/struct/sockaddr.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h"
int sys_accept(int server, void *addr, uint32_t *addrsize) {
int client;
uint32_t size;
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
client = __sys_accept(server, addr, addrsize, 0);
} else {
size = sizeof(bsd);
if ((client = __sys_accept(server, &bsd, &size, 0)) != -1) {
sockaddr2linux(&bsd, size, addr, addrsize);
}
}
return client;
__msabi extern typeof(CancelIoEx) *const __imp_CancelIoEx;
/**
* Cancels Windows i/o operation.
*/
bool32 CancelIoEx(int64_t hFile, struct NtOverlapped *opt_lpOverlapped) {
bool32 ok;
ok = __imp_CancelIoEx(hFile, opt_lpOverlapped);
if (!ok) __winerr();
NTTRACE("CancelIoEx(%ld, %s) → %hhhd% m", hFile,
DescribeNtOverlapped(opt_lpOverlapped), ok);
return ok;
}

View file

@ -146,6 +146,7 @@ o/$(MODE)/libc/intrin/exit1.greg.o \
o/$(MODE)/libc/intrin/wsarecv.o \
o/$(MODE)/libc/intrin/wsarecvfrom.o \
o/$(MODE)/libc/intrin/createfile.o \
o/$(MODE)/libc/intrin/cancelioex.o \
o/$(MODE)/libc/intrin/reopenfile.o \
o/$(MODE)/libc/intrin/deletefile.o \
o/$(MODE)/libc/intrin/createpipe.o \
@ -175,6 +176,7 @@ o/$(MODE)/libc/intrin/mapviewoffileexnuma.o \
o/$(MODE)/libc/intrin/createfilemapping.o \
o/$(MODE)/libc/intrin/createfilemappingnuma.o \
o/$(MODE)/libc/intrin/waitformultipleobjects.o \
o/$(MODE)/libc/intrin/wsagetoverlappedresult.o \
o/$(MODE)/libc/intrin/generateconsolectrlevent.o \
o/$(MODE)/libc/intrin/wsawaitformultipleevents.o: private\
CFLAGS += \

View file

@ -26,12 +26,14 @@
#include "libc/errno.h"
#include "libc/fmt/divmod10.internal.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/asancodes.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/cmpxchg.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/likely.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/safemacros.internal.h"
@ -259,6 +261,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
va_list va) {
int si, y;
wint_t t, u;
char errnum[12];
const char *abet;
signed char type;
const char *s, *f;
@ -539,6 +542,10 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
} else {
type = 0;
s = _strerrno(e);
if (!s) {
FormatInt32(errnum, e);
s = errnum;
}
goto FormatString;
}
}
@ -612,7 +619,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt,
if (cols) --cols; // end quote
p = kemitquote(p, e, type, hash);
}
if (sign == ' ' && (!pdot || prec) && *s) {
if (sign == ' ' && (!pdot || prec) && s && *s) {
if (p < e) *p = ' ';
++p;
}

View file

@ -0,0 +1,59 @@
/*-*- 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 2023 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/errno.h"
#include "libc/intrin/describentoverlapped.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
__msabi extern typeof(WSAGetOverlappedResult)
*const __imp_WSAGetOverlappedResult;
static char *DescribeTransfer(char buf[16], bool32 ok, uint32_t *transfer) {
if (ok) {
ksnprintf(buf, 16, "%'u", *transfer);
return buf;
} else {
return "n/a";
}
}
/**
* Gets overlap i/o result.
*
* @return true on success, or false on failure
* @note this wrapper takes care of ABI, STRACE(), and __winsockerr()
*/
bool32 WSAGetOverlappedResult(uint64_t s,
const struct NtOverlapped *lpOverlapped,
uint32_t *out_lpcbTransfer, bool32 fWait,
uint32_t *out_lpdwFlags) {
bool32 ok;
ok = __imp_WSAGetOverlappedResult(s, lpOverlapped, out_lpcbTransfer, fWait,
out_lpdwFlags);
if (!ok) __winsockerr();
NTTRACE("WSAGetOverlappedResult(%ld, %s, [%s], %hhhd, [%#x]) → %hhhd% lm", s,
DescribeNtOverlapped(lpOverlapped),
DescribeTransfer(alloca(16), ok, out_lpcbTransfer), fWait,
*out_lpdwFlags, ok);
return ok;
}

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/describentoverlapped.internal.h"
@ -23,6 +24,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
__msabi extern typeof(WSARecv) *const __imp_WSARecv;
@ -38,6 +40,12 @@ textwindows int WSARecv(
struct NtOverlapped *opt_inout_lpOverlapped,
const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine) {
int rc;
if (opt_inout_lpOverlapped) {
// Use NULL for this parameter if the lpOverlapped parameter is not
// NULL to avoid potentially erroneous results. This parameter can
// be NULL only if the lpOverlapped parameter is not NULL.
_unassert(!opt_out_lpNumberOfBytesRecvd);
}
#if defined(SYSDEBUG) && _NTTRACE
uint32_t NumberOfBytesRecvd;
if (opt_out_lpNumberOfBytesRecvd) {
@ -50,7 +58,7 @@ textwindows int WSARecv(
*opt_out_lpNumberOfBytesRecvd = NumberOfBytesRecvd;
}
if (rc == -1) {
__winerr();
__winsockerr();
}
if (UNLIKELY(__strace > 0) && strace_enabled(0) > 0) {
kprintf(STRACE_PROLOGUE "WSARecv(%lu, [", s);
@ -66,7 +74,7 @@ textwindows int WSARecv(
opt_out_lpNumberOfBytesRecvd, inout_lpFlags,
opt_inout_lpOverlapped, opt_lpCompletionRoutine);
if (rc == -1) {
__winerr();
__winsockerr();
}
#endif
return rc;

View file

@ -3,7 +3,7 @@
.text.windows
.ftrace1
CancelIoEx:
__CancelIoEx:
.ftrace2
#ifdef __x86_64__
push %rbp
@ -14,5 +14,5 @@ CancelIoEx:
mov x0,#0
ret
#endif
.endfn CancelIoEx,globl
.endfn __CancelIoEx,globl
.previous

View file

@ -98,7 +98,6 @@ imp 'CallNamedPipeA' CallNamedPipeA kernel32 110 7
imp 'CallbackMayRunLong' CallbackMayRunLong kernel32 0
imp 'CancelDeviceWakeupRequest' CancelDeviceWakeupRequest kernel32 113
imp 'CancelIo' CancelIo kernel32 0 1
imp 'CancelIoEx' CancelIoEx kernel32 0 2
imp 'CancelSynchronousIo' CancelSynchronousIo kernel32 0 1
imp 'CancelTimerQueueTimer' CancelTimerQueueTimer kernel32 118
imp 'CancelWaitableTimer' CancelWaitableTimer kernel32 0
@ -1097,6 +1096,7 @@ imp 'WriteProfileString' WriteProfileStringW kernel32 1575
imp 'WriteTapemark' WriteTapemark kernel32 1576
imp 'ZombifyActCtx' ZombifyActCtx kernel32 0
imp 'ZombifyActCtxWorker' ZombifyActCtxWorker kernel32 1578
imp '__CancelIoEx' CancelIoEx kernel32 0 2
imp '__CloseHandle' CloseHandle kernel32 0 1
imp '__CreateDirectory' CreateDirectoryW kernel32 0 2
imp '__CreateFile' CreateFileW kernel32 0 7
@ -3228,7 +3228,6 @@ imp 'WSAEnumNetworkEvents' WSAEnumNetworkEvents ws2_32 64 3
imp 'WSAEnumProtocols' WSAEnumProtocolsW ws2_32 66 3
imp 'WSAEventSelect' WSAEventSelect ws2_32 67 3
imp 'WSAGetLastError' WSAGetLastError ws2_32 111 0
imp 'WSAGetOverlappedResult' WSAGetOverlappedResult ws2_32 68 5
imp 'WSAGetQOSByName' WSAGetQOSByName ws2_32 69 3
imp 'WSAGetServiceClassInfo' WSAGetServiceClassInfoW ws2_32 71 4
imp 'WSAGetServiceClassNameByClassId' WSAGetServiceClassNameByClassIdW ws2_32 73 3
@ -3329,6 +3328,7 @@ imp '__WSARecvFrom' WSARecvFrom ws2_32 93 9
imp '__WSAWaitForMultipleEvents' WSAWaitForMultipleEvents ws2_32 124 5
imp '__sys_recv_nt' recv ws2_32 16 4 # we're using WSARecvFrom()
imp '__sys_send_nt' send ws2_32 19 4 # we're using WSASendTo()
imp '__WSAGetOverlappedResult' WSAGetOverlappedResult ws2_32 68 5
# IPHLPAPI.DLL
#

View file

@ -294,7 +294,7 @@ int32_t WSAStartup(uint16_t wVersionRequested, struct NtWsaData *lpWSAData)
paramsnonnull() dontdiscard;
int WSACleanup(void);
int WSAGetLastError(void);
int WSAGetLastError(void) nosideeffect;
void WSASetLastError(int);
int __sys_bind_nt(uint64_t, const void *, int);
@ -343,6 +343,12 @@ int64_t WSAAccept(uint64_t s, struct sockaddr *out_addr,
const uint32_t *opt_dwCallbackData)
paramsnonnull((2)) dontdiscard;
bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength, uint32_t *out_lpdwBytesReceived,
struct NtOverlapped *inout_lpOverlapped);
int WSASend(uint64_t s, const struct NtIovec *lpBuffers, uint32_t dwBufferCount,
uint32_t *opt_out_lpNumberOfBytesSent, uint32_t dwFlags,
struct NtOverlapped *opt_inout_lpOverlapped,

View file

@ -3,7 +3,7 @@
.text.windows
.ftrace1
WSAGetOverlappedResult:
__WSAGetOverlappedResult:
.ftrace2
#ifdef __x86_64__
push %rbp
@ -14,5 +14,5 @@ WSAGetOverlappedResult:
mov x0,#0
ret
#endif
.endfn WSAGetOverlappedResult,globl
.endfn __WSAGetOverlappedResult,globl
.previous

View file

@ -58,8 +58,8 @@ int __inflate(void *out, size_t outsize, const void *in, size_t insize) {
} else {
rc = _puff(out, &outsize, in, &insize);
}
STRACE("inflate([%#.*hhs%s], %'zu, %#.*hhs%s, %'zu) → %d", MIN(40, outsize),
out, outsize > 40 ? "..." : "", outsize, MIN(40, insize), in,
insize > 40 ? "..." : "", insize, rc);
STRACE("inflate([%#.*hhs%s], %'zu, %#.*hhs%s, %'zu) → %d",
(int)MIN(40, outsize), out, outsize > 40 ? "..." : "", outsize,
(int)MIN(40, insize), in, insize > 40 ? "..." : "", insize, rc);
return rc;
}

View file

@ -17,58 +17,109 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/sock/struct/sockaddr.internal.h"
#include "libc/sock/struct/sockaddr6.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/fio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize,
int flags) {
int64_t h;
union AcceptExAddr {
union sockaddr_storage_linux addr;
char buf[sizeof(struct sockaddr_storage) + 16];
};
struct AcceptExBuffer {
union AcceptExAddr local;
union AcceptExAddr remote;
};
static void CopyLinuxSockAddr(const union sockaddr_storage_linux *addr,
void *out_addr, uint32_t *inout_addrsize) {
uint32_t insize, outsize;
if (out_addr && inout_addrsize) {
if (addr->sa.sa_family == AF_INET) {
outsize = sizeof(struct sockaddr_in);
} else if (addr->sa.sa_family == AF_INET6) {
outsize = sizeof(struct sockaddr_in6);
} else if (addr->sa.sa_family == AF_UNIX) {
outsize = sizeof(addr->sun.sun_family) +
strnlen(addr->sun.sun_path, sizeof(addr->sun.sun_path)) + 1;
} else {
outsize = sizeof(union sockaddr_storage_linux);
}
insize = *inout_addrsize;
if (insize) bzero(out_addr, insize);
outsize = MIN(insize, outsize);
if (outsize) memcpy(out_addr, addr, outsize);
*inout_addrsize = outsize;
}
}
textwindows int sys_accept_nt(struct Fd *fd, void *out_addr,
uint32_t *inout_addrsize, int accept4_flags) {
int64_t handle;
int rc, client, oflags;
uint32_t bytes_received;
uint32_t completion_flags;
struct AcceptExBuffer buffer;
struct SockFd *sockfd, *sockfd2;
sockfd = (struct SockFd *)fd->extra;
if (_check_interrupts(true, g_fds.p)) return -1;
for (;;) {
if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1,
__SIG_POLLING_INTERVAL_MS)) {
// deliver interrupt instead if any are pending
if (_check_interrupts(true, g_fds.p)) {
return eintr();
return -1;
}
continue;
// creates resources for child socket
// inherit the listener configuration
sockfd = (struct SockFd *)fd->extra;
if (!(sockfd2 = malloc(sizeof(struct SockFd)))) {
return -1;
}
if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) {
memcpy(sockfd2, sockfd, sizeof(*sockfd));
if ((handle = WSASocket(sockfd2->family, sockfd2->type, sockfd2->protocol,
NULL, 0, kNtWsaFlagOverlapped)) == -1) {
free(sockfd2);
return __winsockerr();
}
// accept network connection
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (!AcceptEx(fd->handle, handle, &buffer, 0, sizeof(buffer.local),
sizeof(buffer.remote), &bytes_received, &overlapped)) {
sockfd = (struct SockFd *)fd->extra;
if (__wsablock(fd, &overlapped, &completion_flags, true,
sockfd->rcvtimeo) == -1) {
WSACloseEvent(overlapped.hEvent);
__sys_closesocket_nt(handle);
free(sockfd2);
return -1;
}
}
WSACloseEvent(overlapped.hEvent);
// create file descriptor for new socket
// don't inherit the file open mode bits
oflags = 0;
if (flags & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (flags & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
if ((!(flags & SOCK_NONBLOCK) ||
__sys_ioctlsocket_nt(h, FIONBIO, (uint32_t[]){1}) != -1) &&
(sockfd2 = calloc(1, sizeof(struct SockFd)))) {
if (accept4_flags & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (accept4_flags & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
__fds_lock();
if ((client = __reservefd_unlocked(-1)) != -1) {
sockfd2->family = sockfd->family;
sockfd2->type = sockfd->type;
sockfd2->protocol = sockfd->protocol;
client = __reservefd_unlocked(-1);
g_fds.p[client].kind = kFdSocket;
g_fds.p[client].flags = oflags;
g_fds.p[client].mode = 0140666;
g_fds.p[client].handle = h;
g_fds.p[client].handle = handle;
g_fds.p[client].extra = (uintptr_t)sockfd2;
__fds_unlock();
// handoff information to caller;
CopyLinuxSockAddr(&buffer.remote.addr, out_addr, inout_addrsize);
return client;
}
__fds_unlock();
free(sockfd2);
}
__sys_closesocket_nt(h);
}
return __winsockerr();
}
}

View file

@ -16,15 +16,20 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.internal.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
if (!flags) return sys_accept(server, addr, addrsize);
int olderr, client;
int olderr, client, file_mode;
union sockaddr_storage_bsd bsd;
uint32_t size = sizeof(bsd);
void *out_addr = !IsBsd() ? addr : &bsd;
@ -37,8 +42,17 @@ int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
errno = olderr;
demodernize = true;
TriedAndTrue:
client = __fixupnewsockfd(__sys_accept(server, out_addr, out_addrsize, 0),
flags);
if ((client = __sys_accept(server, out_addr, out_addrsize, 0)) != -1) {
// __sys_accept() has inconsistent flag inheritence across platforms
_unassert((file_mode = __sys_fcntl(client, F_GETFD)) != -1);
_unassert(!__sys_fcntl(client, F_SETFD,
((file_mode & ~FD_CLOEXEC) |
(flags & SOCK_CLOEXEC ? FD_CLOEXEC : 0))));
_unassert((file_mode = __sys_fcntl(client, F_GETFL)) != -1);
_unassert(!__sys_fcntl(client, F_SETFL,
((file_mode & ~O_NONBLOCK) |
(flags & SOCK_NONBLOCK ? O_NONBLOCK : 0))));
}
}
if (client != -1 && IsBsd()) {
sockaddr2linux(&bsd, size, addr, addrsize);

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/intrin/bsr.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
@ -29,7 +30,7 @@ textwindows int sys_connect_nt(struct Fd *fd, const void *addr,
sockfd = (struct SockFd *)fd->extra;
_npassert(fd->kind == kFdSocket);
return __winsockblock(
fd->handle, FD_CONNECT_BIT,
fd->handle, _bsr(kNtFdConnect),
WSAConnect(fd->handle, addr, addrsize, NULL, NULL, NULL, NULL),
sockfd->rcvtimeo);
}

View file

@ -21,11 +21,6 @@
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
/**
* Applies non-atomic file descriptor fixups on XNU or ancient Linux.
*
* @param fd of -1 means no-op
*/
int __fixupnewsockfd(int fd, int flags) {
return __fixupnewfd(fd, (((flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0) |
((flags & SOCK_NONBLOCK) ? O_NONBLOCK : 0)));

View file

@ -11,18 +11,16 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define FD_READ (1 << FD_READ_BIT)
#define FD_READ_BIT 0
#define FD_WRITE (1 << FD_WRITE_BIT)
#define FD_WRITE_BIT 1
#define FD_OOB (1 << FD_OOB_BIT)
#define FD_OOB_BIT 2
#define FD_ACCEPT (1 << FD_ACCEPT_BIT)
#define FD_ACCEPT_BIT 3
#define FD_CONNECT (1 << FD_CONNECT_BIT)
#define FD_CONNECT_BIT 4
#define FD_CLOSE (1 << FD_CLOSE_BIT)
#define FD_CLOSE_BIT 5
#define kNtFdRead 1
#define kNtFdWrite 2
#define kNtFdOob 4
#define kNtFdAccept 8
#define kNtFdConnect 16
#define kNtFdClose 32
#define kNtFdQos 64
#define kNtFdGroupQos 128
#define kNtFdRoutingInterfaceChange 256
#define kNtFdAddressListChange 512
/* ------------------------------------------------------------------------------------*/
@ -34,17 +32,6 @@ struct SockFd {
int protocol;
uint32_t rcvtimeo;
uint32_t sndtimeo;
bool32 (*__msabi ConnectEx)(int64_t s, const struct sockaddr *name,
int namelen, const void *opt_lpSendBuffer,
uint32_t dwSendDataLength,
uint32_t *out_lpdwBytesSent,
struct NtOverlapped *inout_lpOverlapped);
bool32 (*__msabi AcceptEx)(
int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength, uint32_t *out_lpdwBytesReceived,
struct NtOverlapped *inout_lpOverlapped);
};
errno_t __dos2errno(uint32_t) _Hide;
@ -59,7 +46,6 @@ int32_t __sys_socket(int32_t, int32_t, int32_t) _Hide;
int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) _Hide;
int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard _Hide;
int32_t sys_accept(int32_t, void *, uint32_t *) _Hide;
int32_t sys_bind(int32_t, const void *, uint32_t) _Hide;
int32_t sys_connect(int32_t, const void *, uint32_t) _Hide;
int32_t sys_getsockopt(int32_t, int32_t, int32_t, void *, uint32_t *) _Hide;
@ -99,8 +85,6 @@ size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
void WinSockInit(void) _Hide;
int64_t __winsockerr(void) nocallback _Hide;
int __fixupnewsockfd(int, int) _Hide;
int __wsablock(int64_t, struct NtOverlapped *, uint32_t *, bool,
uint32_t) _Hide;
int64_t __winsockblock(int64_t, unsigned, int64_t, uint32_t) _Hide;
struct SockFd *_dupsockfd(struct SockFd *) _Hide;
int64_t GetNtBaseSocket(int64_t) _Hide;

View file

@ -16,9 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
@ -30,20 +32,24 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
size_t iovlen, uint32_t flags) {
int err;
ssize_t rc;
uint32_t got = 0;
uint32_t got = -666;
struct SockFd *sockfd;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return -1;
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
err = errno;
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
&overlapped, NULL)) {
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
&overlapped, 0)) {
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
rc = got;
} else {
rc = -1;
}
} else {
errno = err;
sockfd = (struct SockFd *)fd->extra;
rc = __wsablock(fd->handle, &overlapped, &flags, true, sockfd->rcvtimeo);
rc = __wsablock(fd, &overlapped, &flags, true, sockfd->rcvtimeo);
}
WSACloseEvent(overlapped.hEvent);
_unassert(WSACloseEvent(overlapped.hEvent));
return rc;
}

View file

@ -31,20 +31,23 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
uint32_t *opt_inout_srcaddrsize) {
int err;
ssize_t rc;
uint32_t got = 0;
uint32_t got = -666;
struct SockFd *sockfd;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return -1;
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
err = errno;
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
NULL)) {
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) {
if (WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) {
rc = got;
} else {
rc = -1;
}
} else {
errno = err;
sockfd = (struct SockFd *)fd->extra;
rc = __wsablock(fd->handle, &overlapped, &flags, true, sockfd->rcvtimeo);
rc = __wsablock(fd, &overlapped, &flags, true, sockfd->rcvtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -21,23 +21,28 @@
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h"
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
uint32_t flags) {
ssize_t rc;
uint32_t sent = 0;
uint32_t sent = -666;
struct SockFd *sockfd;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return -1;
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
flags, &overlapped, NULL)) {
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false,
&flags)) {
rc = sent;
} else {
rc = -1;
}
} else {
sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true,
sockfd->sndtimeo);
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, true, sockfd->sndtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -65,11 +65,11 @@ static textwindows int SendfileBlock(int64_t handle,
break;
}
}
if (!WSAGetOverlappedResult(handle, overlapped, &got, false, &flags)) {
NTTRACE("WSAGetOverlappedResult failed %lm");
return __winsockerr();
}
if (WSAGetOverlappedResult(handle, overlapped, &got, false, &flags)) {
return got;
} else {
return -1;
}
}
static dontinline textwindows ssize_t sys_sendfile_nt(

View file

@ -21,6 +21,7 @@
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h"
textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
@ -30,15 +31,19 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
uint32_t sent = 0;
struct SockFd *sockfd;
struct NtIovec iovnt[16];
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (_check_interrupts(true, g_fds.p)) return -1;
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
if (WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false,
&flags)) {
rc = sent;
} else {
rc = -1;
}
} else {
sockfd = (struct SockFd *)g_fds.p[fd].extra;
rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true,
sockfd->sndtimeo);
rc = __wsablock(g_fds.p + fd, &overlapped, &flags, true, sockfd->sndtimeo);
}
WSACloseEvent(overlapped.hEvent);
return rc;

View file

@ -16,36 +16,50 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/sio.h"
#include "libc/sysv/errfuns.h"
static textwindows int sockatmark_nt(int64_t fd) {
static textwindows int sockatmark_nt(int fd, unsigned long magnum) {
bool32 res;
int64_t hand;
uint32_t bytes;
if (WSAIoctl(fd, SIOCATMARK, 0, 0, &res, sizeof(res), &bytes, 0, 0) != -1) {
return !res;
} else {
return -1;
if (fd >= g_fds.n) return ebadf();
if (g_fds.p[fd].kind != kFdSocket) return einval();
hand = g_fds.p[fd].handle;
if (WSAIoctl(hand, magnum, 0, 0, &res, sizeof(res), &bytes, 0, 0) == -1) {
return __winsockerr();
}
return !res;
}
/**
* Returns true if out of band data is available on socket for reading.
*
* @return 1 if OOB'd, 0 if not, or -1 w/ errno
* @raise EBADF if `fd` isn't an open file descriptor
* @raise EINVAL if `fd` isn't an appropriate file descriptor
*/
int sockatmark(int fd) {
int rc;
unsigned long magnum;
if (IsLinux()) {
magnum = 0x8905; // SIOCATMARK (Linux only)
} else { //
magnum = 0x40047307; // SIOCATMARK (BSD, Windows)
}
if (!IsWindows()) {
if (sys_ioctl(fd, SIOCATMARK, &rc) == -1) {
if (sys_ioctl(fd, magnum, &rc) == -1) {
rc = -1;
}
} else {
rc = sockatmark_nt(fd);
rc = sockatmark_nt(fd, magnum);
}
STRACE("sockatmark(%d) → %d% m", fd, rc);
return rc;

View file

@ -24,7 +24,6 @@
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/so.h"
@ -52,13 +51,6 @@ textwindows int sys_socket_nt(int family, int type, int protocol) {
oflags = 0;
if (type & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (type & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
if (type & SOCK_NONBLOCK) {
if (__sys_ioctlsocket_nt(h, FIONBIO, (uint32_t[1]){1}) == -1) {
__sys_closesocket_nt(h);
__releasefd(fd);
return __winsockerr();
}
}
sockfd = calloc(1, sizeof(struct SockFd));
sockfd->family = family;
sockfd->type = truetype;

View file

@ -22,29 +22,12 @@
#include "libc/sysv/consts/sock.h"
int sys_socket(int family, int type, int protocol) {
static bool once, demodernize;
int sock, olderr;
if (!once && (type & (SOCK_CLOEXEC | SOCK_NONBLOCK))) {
if (IsXnu()) {
demodernize = true;
once = true;
} else {
olderr = errno;
if ((sock = __sys_socket(family, type, protocol)) != -1) {
once = true;
int sock, tf, e = errno;
tf = SOCK_CLOEXEC | SOCK_NONBLOCK;
sock = __sys_socket(family, type, protocol);
if (sock == -1 && (type & tf) && (errno == EINVAL || errno == EPROTOTYPE)) {
errno = e; // XNU/RHEL5/etc. don't support flags; see if removing helps
sock = __fixupnewsockfd(__sys_socket(family, type & ~tf, protocol), type);
}
return sock;
} else {
errno = olderr;
demodernize = true;
once = true;
}
}
}
if (!demodernize) {
return __sys_socket(family, type, protocol);
} else {
return __fixupnewsockfd(
__sys_socket(family, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), protocol),
type);
}
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_SOCK_SYSCALL_INTERNAL_H_
#include "libc/calls/struct/fd.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -18,6 +19,8 @@ int sys_shutdown_nt(struct Fd *, int) _Hide;
ssize_t sys_recv_nt(struct Fd *, const struct iovec *, size_t, uint32_t) _Hide;
ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
void *, uint32_t *) _Hide;
int __wsablock(struct Fd *, struct NtOverlapped *, uint32_t *, bool,
uint32_t) _Hide;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,24 +16,41 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/enum/wsa.h"
#include "libc/nt/errors.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thread.h"
#include "libc/nt/winsock.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
uint32_t *flags, bool restartable,
uint32_t timeout) {
int rc;
uint32_t i, got;
int e, rc;
uint32_t i, got = -666;
if (WSAGetLastError() != kNtErrorIoPending) {
NTTRACE("sock i/o failed %lm");
NTTRACE("sock i/o failed %s", strerror(errno));
return __winsockerr();
}
if (fd->flags & O_NONBLOCK) {
e = errno;
_unassert(CancelIoEx(fd->handle, overlapped) ||
WSAGetLastError() == kNtErrorNotFound);
errno = e;
}
for (;;) {
i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true,
__SIG_POLLING_INTERVAL_MS, true);
@ -46,6 +63,7 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
}
if (timeout) {
if (timeout <= __SIG_POLLING_INTERVAL_MS) {
NTTRACE("__wsablock timeout elapsed");
return eagain();
}
timeout -= __SIG_POLLING_INTERVAL_MS;
@ -54,9 +72,12 @@ textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped,
break;
}
}
if (!WSAGetOverlappedResult(handle, overlapped, &got, false, flags)) {
NTTRACE("WSAGetOverlappedResult failed %lm");
return __winsockerr();
}
if (WSAGetOverlappedResult(fd->handle, overlapped, &got, false, flags)) {
return got;
} else if ((fd->flags & O_NONBLOCK) &&
WSAGetLastError() == kNtErrorOperationAborted) {
return eagain();
} else {
return -1;
}
}

View file

@ -947,7 +947,6 @@ syscon ioctl FIONCLEX 0x5450 0x5450 0x20006602 0x20006602 0x20006602 0
#syscon ioctl FIONWRITE 0x0 0x0 0x0 0x0 0x40046677 0x0 0x0 -1 # [FreeBSD Generalization] bytes queued in FD's output buffer (same as TIOCOUTQ for TTY FDs; see also SO_SNDBUF)
#syscon ioctl FIONSPACE 0x0 0x0 0x0 0x0 0x40046676 0x0 0x0 -1 # [FreeBSD Generalization] capacity of FD's output buffer, e.g. equivalent to TIOCGSERIAL w/ UART
syscon ioctl SIOCGIFCONF 0x8912 0x8912 0xc00c6924 0xc00c6924 0xc0106924 0xc0106924 0xc0106924 0
syscon ioctl SIOCATMARK 0x8905 0x8905 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 0x40047307 # use sockatmark(); determines if oob is available; bsd consensus
syscon ioctl SIOCADDMULTI 0x8931 0x8931 0x80206931 0x80206931 0x80206931 0x80206931 0x80206931 0 # bsd consensus
syscon ioctl SIOCDELMULTI 0x8932 0x8932 0x80206932 0x80206932 0x80206932 0x80206932 0x80206932 0 # bsd consensus
syscon ioctl SIOCDIFADDR 0x8936 0x8936 0x80206919 0x80206919 0x80206919 0x80206919 0x80206919 0 # bsd consensus

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCADDDLCI,0x8980,0x8980,0,0,0,0,0,0
.syscon ioctl,SIOCADDDLCI,0x8980,0x8980,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCADDMULTI,0x8931,0x8931,0x80206931,0x80206931,0x80206931,0x80206931,0x80206931,0
.syscon ioctl,SIOCADDMULTI,0x8931,0x8931,0x80206931,0x80206931,0x80206931,0x80206931,0x80206931,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCADDRT,0x890b,0x890b,0,0,0,0,0,0
.syscon ioctl,SIOCADDRT,0x890b,0x890b,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCATMARK,0x8905,0x8905,0x40047307,0x40047307,0x40047307,0x40047307,0x40047307,0x40047307

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDARP,0x8953,0x8953,0,0,0,0,0,0
.syscon ioctl,SIOCDARP,0x8953,0x8953,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDELDLCI,0x8981,0x8981,0,0,0,0,0,0
.syscon ioctl,SIOCDELDLCI,0x8981,0x8981,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDELMULTI,0x8932,0x8932,0x80206932,0x80206932,0x80206932,0x80206932,0x80206932,0
.syscon ioctl,SIOCDELMULTI,0x8932,0x8932,0x80206932,0x80206932,0x80206932,0x80206932,0x80206932,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDELRT,0x890c,0x890c,0,0,0,0,0,0
.syscon ioctl,SIOCDELRT,0x890c,0x890c,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDEVPRIVATE,0x89f0,0x89f0,0,0,0,0,0,0
.syscon ioctl,SIOCDEVPRIVATE,0x89f0,0x89f0,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDIFADDR,0x8936,0x8936,0x80206919,0x80206919,0x80206919,0x80206919,0x80206919,0
.syscon ioctl,SIOCDIFADDR,0x8936,0x8936,0x80206919,0x80206919,0x80206919,0x80206919,0x80206919,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCDRARP,0x8960,0x8960,0,0,0,0,0,0
.syscon ioctl,SIOCDRARP,0x8960,0x8960,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGARP,0x8954,0x8954,0,0,0,0,0,0
.syscon ioctl,SIOCGARP,0x8954,0x8954,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFADDR,0x8915,0x8915,0xc0206921,0xc0206921,0xc0206921,0xc0206921,0xc0206921,0
.syscon ioctl,SIOCGIFADDR,0x8915,0x8915,0xc0206921,0xc0206921,0xc0206921,0xc0206921,0xc0206921,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFBR,0x8940,0x8940,0,0,0,0,0,0
.syscon ioctl,SIOCGIFBR,0x8940,0x8940,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFBRDADDR,0x8919,0x8919,0xc0206923,0xc0206923,0xc0206923,0xc0206923,0xc0206923,0
.syscon ioctl,SIOCGIFBRDADDR,0x8919,0x8919,0xc0206923,0xc0206923,0xc0206923,0xc0206923,0xc0206923,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFCONF,0x8912,0x8912,0xc00c6924,0xc00c6924,0xc0106924,0xc0106924,0xc0106924,0
.syscon ioctl,SIOCGIFCONF,0x8912,0x8912,0xc00c6924,0xc00c6924,0xc0106924,0xc0106924,0xc0106924,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFCOUNT,0x8938,0x8938,0,0,0,0,0,0
.syscon ioctl,SIOCGIFCOUNT,0x8938,0x8938,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFDSTADDR,0x8917,0x8917,0xc0206922,0xc0206922,0xc0206922,0xc0206922,0xc0206922,0
.syscon ioctl,SIOCGIFDSTADDR,0x8917,0x8917,0xc0206922,0xc0206922,0xc0206922,0xc0206922,0xc0206922,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFENCAP,0x8925,0x8925,0,0,0,0,0,0
.syscon ioctl,SIOCGIFENCAP,0x8925,0x8925,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFFLAGS,0x8913,0x8913,0xc0206911,0xc0206911,0xc0206911,0xc0206911,0xc0206911,0
.syscon ioctl,SIOCGIFFLAGS,0x8913,0x8913,0xc0206911,0xc0206911,0xc0206911,0xc0206911,0xc0206911,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFHWADDR,0x8927,0x8927,0,0,0,0,0,0
.syscon ioctl,SIOCGIFHWADDR,0x8927,0x8927,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFINDEX,0x8933,0x8933,0,0,0xc0206920,0,0,0
.syscon ioctl,SIOCGIFINDEX,0x8933,0x8933,0,0,0xc0206920,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFMAP,0x8970,0x8970,0,0,0,0,0,0
.syscon ioctl,SIOCGIFMAP,0x8970,0x8970,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFMEM,0x891f,0x891f,0,0,0,0,0,0
.syscon ioctl,SIOCGIFMEM,0x891f,0x891f,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFMETRIC,0x891d,0x891d,0xc0206917,0xc0206917,0xc0206917,0xc0206917,0xc0206917,0
.syscon ioctl,SIOCGIFMETRIC,0x891d,0x891d,0xc0206917,0xc0206917,0xc0206917,0xc0206917,0xc0206917,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFMTU,0x8921,0x8921,0xc0206933,0xc0206933,0xc0206933,0xc020697e,0xc020697e,0
.syscon ioctl,SIOCGIFMTU,0x8921,0x8921,0xc0206933,0xc0206933,0xc0206933,0xc020697e,0xc020697e,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFNAME,0x8910,0x8910,0,0,0,0,0,0
.syscon ioctl,SIOCGIFNAME,0x8910,0x8910,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFNETMASK,0x891b,0x891b,0xc0206925,0xc0206925,0xc0206925,0xc0206925,0xc0206925,0
.syscon ioctl,SIOCGIFNETMASK,0x891b,0x891b,0xc0206925,0xc0206925,0xc0206925,0xc0206925,0xc0206925,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFPFLAGS,0x8935,0x8935,0,0,0,0,0,0
.syscon ioctl,SIOCGIFPFLAGS,0x8935,0x8935,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFSLAVE,0x8929,0x8929,0,0,0,0,0,0
.syscon ioctl,SIOCGIFSLAVE,0x8929,0x8929,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGIFTXQLEN,0x8942,0x8942,0,0,0,0,0,0
.syscon ioctl,SIOCGIFTXQLEN,0x8942,0x8942,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGPGRP,0x8904,0x8904,0x40047309,0x40047309,0x40047309,0x40047309,0x40047309,0
.syscon ioctl,SIOCGPGRP,0x8904,0x8904,0x40047309,0x40047309,0x40047309,0x40047309,0x40047309,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGRARP,0x8961,0x8961,0,0,0,0,0,0
.syscon ioctl,SIOCGRARP,0x8961,0x8961,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGSTAMP,0x8906,0x8906,0,0,0,0,0,0
.syscon ioctl,SIOCGSTAMP,0x8906,0x8906,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCGSTAMPNS,0x8907,0x8907,0,0,0,0,0,0
.syscon ioctl,SIOCGSTAMPNS,0x8907,0x8907,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCPROTOPRIVATE,0x89e0,0x89e0,0,0,0,0,0,0
.syscon ioctl,SIOCPROTOPRIVATE,0x89e0,0x89e0,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCRTMSG,0x890d,0x890d,0,0,0,0,0,0
.syscon ioctl,SIOCRTMSG,0x890d,0x890d,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSARP,0x8955,0x8955,0,0,0,0,0,0
.syscon ioctl,SIOCSARP,0x8955,0x8955,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFADDR,0x8916,0x8916,0x8020690c,0x8020690c,0x8020690c,0x8020690c,0x8020690c,0
.syscon ioctl,SIOCSIFADDR,0x8916,0x8916,0x8020690c,0x8020690c,0x8020690c,0x8020690c,0x8020690c,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFBR,0x8941,0x8941,0,0,0,0,0,0
.syscon ioctl,SIOCSIFBR,0x8941,0x8941,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFBRDADDR,0x891a,0x891a,0x80206913,0x80206913,0x80206913,0x80206913,0x80206913,0
.syscon ioctl,SIOCSIFBRDADDR,0x891a,0x891a,0x80206913,0x80206913,0x80206913,0x80206913,0x80206913,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFDSTADDR,0x8918,0x8918,0x8020690e,0x8020690e,0x8020690e,0x8020690e,0x8020690e,0
.syscon ioctl,SIOCSIFDSTADDR,0x8918,0x8918,0x8020690e,0x8020690e,0x8020690e,0x8020690e,0x8020690e,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFENCAP,0x8926,0x8926,0,0,0,0,0,0
.syscon ioctl,SIOCSIFENCAP,0x8926,0x8926,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFFLAGS,0x8914,0x8914,0x80206910,0x80206910,0x80206910,0x80206910,0x80206910,0
.syscon ioctl,SIOCSIFFLAGS,0x8914,0x8914,0x80206910,0x80206910,0x80206910,0x80206910,0x80206910,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFHWADDR,0x8924,0x8924,0,0,0,0,0,0
.syscon ioctl,SIOCSIFHWADDR,0x8924,0x8924,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFHWBROADCAST,0x8937,0x8937,0,0,0,0,0,0
.syscon ioctl,SIOCSIFHWBROADCAST,0x8937,0x8937,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFLINK,0x8911,0x8911,0,0,0,0,0,0
.syscon ioctl,SIOCSIFLINK,0x8911,0x8911,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFMAP,0x8971,0x8971,0,0,0,0,0,0
.syscon ioctl,SIOCSIFMAP,0x8971,0x8971,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFMEM,0x8920,0x8920,0,0,0,0,0,0
.syscon ioctl,SIOCSIFMEM,0x8920,0x8920,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFMETRIC,0x891e,0x891e,0x80206918,0x80206918,0x80206918,0x80206918,0x80206918,0
.syscon ioctl,SIOCSIFMETRIC,0x891e,0x891e,0x80206918,0x80206918,0x80206918,0x80206918,0x80206918,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFMTU,0x8922,0x8922,0x80206934,0x80206934,0x80206934,0x8020697f,0x8020697f,0
.syscon ioctl,SIOCSIFMTU,0x8922,0x8922,0x80206934,0x80206934,0x80206934,0x8020697f,0x8020697f,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFNAME,0x8923,0x8923,0,0,0x80206928,0,0,0
.syscon ioctl,SIOCSIFNAME,0x8923,0x8923,0,0,0x80206928,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFNETMASK,0x891c,0x891c,0x80206916,0x80206916,0x80206916,0x80206916,0x80206916,0
.syscon ioctl,SIOCSIFNETMASK,0x891c,0x891c,0x80206916,0x80206916,0x80206916,0x80206916,0x80206916,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFPFLAGS,0x8934,0x8934,0,0,0,0,0,0
.syscon ioctl,SIOCSIFPFLAGS,0x8934,0x8934,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFSLAVE,0x8930,0x8930,0,0,0,0,0,0
.syscon ioctl,SIOCSIFSLAVE,0x8930,0x8930,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSIFTXQLEN,0x8943,0x8943,0,0,0,0,0,0
.syscon ioctl,SIOCSIFTXQLEN,0x8943,0x8943,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSPGRP,0x8902,0x8902,0x80047308,0x80047308,0x80047308,0x80047308,0x80047308,0
.syscon ioctl,SIOCSPGRP,0x8902,0x8902,0x80047308,0x80047308,0x80047308,0x80047308,0x80047308,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOCSRARP,0x8962,0x8962,0,0,0,0,0,0
.syscon ioctl,SIOCSRARP,0x8962,0x8962,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sio,SIOGIFINDEX,0x8933,0x8933,0,0,0,0,0,0
.syscon ioctl,SIOGIFINDEX,0x8933,0x8933,0,0,0,0,0,0

View file

@ -3,16 +3,12 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern const uint32_t FIOASYNC;
extern const uint32_t FIOCLEX;
extern const uint32_t FIONBIO;
extern const uint32_t FIONCLEX;
extern const uint32_t FIONREAD;
extern const uint32_t FIONREAD; /* one of the few encouraged ioctls */
extern const uint32_t FIONBIO; /* use fcntl(fd, F_SETFL, O_NONBLOCK) */
extern const uint32_t FIOCLEX; /* use fcntl(fd, F_SETFD, FD_CLOEXEC) */
extern const uint32_t FIONCLEX; /* use fcntl(fd, F_SETFD, 0) */
extern const uint32_t FIOASYNC; /* todo: fcntl(fd, F_SETOWN, pid) */
#define FIOASYNC FIOASYNC
#define FIOCLEX FIOCLEX
#define FIONBIO FIONBIO
#define FIONCLEX FIONCLEX
#define FIONREAD FIONREAD
COSMOPOLITAN_C_END_

View file

@ -6,7 +6,6 @@ COSMOPOLITAN_C_START_
extern const unsigned long SIOCADDDLCI;
extern const unsigned long SIOCADDMULTI;
extern const unsigned long SIOCADDRT;
extern const unsigned long SIOCATMARK; /* use sockatmark() */
extern const unsigned long SIOCDARP;
extern const unsigned long SIOCDELDLCI;
extern const unsigned long SIOCDELMULTI;

View file

@ -23,6 +23,15 @@
* Initializes pthread attributes.
*
* @return 0 on success, or errno on error
* @see pthread_attr_setdetachstate()
* @see pthread_attr_setsigmask_np()
* @see pthread_attr_setstack()
* @see pthread_attr_setstacksize()
* @see pthread_attr_setguardsize()
* @see pthread_attr_setschedparam()
* @see pthread_attr_setschedpolicy()
* @see pthread_attr_setinheritsched()
* @see pthread_attr_setscope()
*/
errno_t pthread_attr_init(pthread_attr_t *attr) {
*attr = (pthread_attr_t){

View file

@ -0,0 +1,127 @@
/*-*- 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 2023 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/calls.h"
#include "libc/errno.h"
#include "libc/intrin/strace.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
TEST(O_NONBLOCK, canBeSetBySocket_toMakeListenNonBlocking) {
int ws, pid;
char buf[16] = {0};
int64_t inoffset;
uint32_t addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(0x7f000001),
};
pthread_spinlock_t *phaser = _mapshared(4096);
EXPECT_EQ(0, pthread_spin_lock(phaser + 0));
EXPECT_EQ(0, pthread_spin_lock(phaser + 1));
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP));
ASSERT_SYS(0, 0, bind(3, (struct sockaddr *)&addr, sizeof(addr)));
ASSERT_SYS(0, 0, getsockname(3, (struct sockaddr *)&addr, &addrsize));
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
SPAWN(fork);
ASSERT_SYS(EAGAIN, -1, accept(3, (struct sockaddr *)&addr, &addrsize));
EXPECT_EQ(0, pthread_spin_unlock(phaser + 0));
for (;;) {
int e = errno;
int fd = accept(3, (struct sockaddr *)&addr, &addrsize);
if (fd == -1 && errno == EAGAIN) {
errno = e;
usleep(1000);
continue;
}
ASSERT_SYS(0, 4, fd);
break;
}
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
EXPECT_EQ(0, pthread_spin_unlock(phaser + 1));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
PARENT();
EXPECT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
EXPECT_EQ(0, pthread_spin_lock(phaser + 0));
ASSERT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
EXPECT_EQ(0, pthread_spin_lock(phaser + 1));
EXPECT_SYS(0, 5, read(3, buf, 16));
EXPECT_STREQ("hello", buf);
EXPECT_SYS(0, 0, close(3));
WAIT(exit, 0);
munmap(phaser, 4096);
}
TEST(O_NONBLOCK, canBeTunedWithFcntl_toMakeReadNonBlocking) {
int ws, pid;
char buf[16] = {0};
int64_t inoffset;
uint32_t addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(0x7f000001),
};
pthread_spinlock_t *phaser = _mapshared(4096);
EXPECT_EQ(0, pthread_spin_lock(phaser + 0));
EXPECT_EQ(0, pthread_spin_lock(phaser + 1));
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(0, 0, bind(3, (struct sockaddr *)&addr, sizeof(addr)));
ASSERT_SYS(0, 0, getsockname(3, (struct sockaddr *)&addr, &addrsize));
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
SPAWN(fork);
ASSERT_SYS(0, 4, accept(3, (struct sockaddr *)&addr, &addrsize));
EXPECT_EQ(0, pthread_spin_lock(phaser + 0));
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
EXPECT_EQ(0, pthread_spin_lock(phaser + 1));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
PARENT();
EXPECT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(0, 0, connect(3, (struct sockaddr *)&addr, sizeof(addr)));
ASSERT_SYS(0, 0, fcntl(3, F_SETFL, O_NONBLOCK));
ASSERT_SYS(EAGAIN, -1, read(3, buf, 16));
EXPECT_EQ(0, pthread_spin_unlock(phaser + 0));
TryAgain:
int e = errno;
ssize_t rc = read(3, buf, 16);
if (rc == -1 && errno == EAGAIN) {
errno = e;
usleep(1000);
goto TryAgain;
}
EXPECT_SYS(0, 5, rc);
EXPECT_STREQ("hello", buf);
EXPECT_EQ(0, pthread_spin_unlock(phaser + 1));
EXPECT_SYS(0, 0, close(3));
WAIT(exit, 0);
munmap(phaser, 4096);
}

View file

@ -33,6 +33,7 @@ TEST_LIBC_SOCK_DIRECTDEPS = \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_LOG \
LIBC_SYSV_CALLS \
LIBC_TESTLIB \
@ -58,6 +59,9 @@ o/$(MODE)/test/libc/sock/%.com.dbg: \
o/$(MODE)/test/libc/sock/unix_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc unix
o/$(MODE)/test/libc/sock/nonblock_test.com.runs \
o/$(MODE)/test/libc/sock/socket_test.com.runs \
o/$(MODE)/test/libc/sock/shutdown_test.com.runs \
o/$(MODE)/test/libc/sock/setsockopt_test.com.runs \
o/$(MODE)/test/libc/sock/sendfile_test.com.runs \
o/$(MODE)/test/libc/sock/poll_test.com.runs \
@ -70,17 +74,12 @@ o/$(MODE)/test/libc/sock/nointernet_test.com.runs: \
o/$(MODE)/test/libc/sock/socket_test.com.runs: \
private .INTERNET = 1 # todo: ipv6 filtering
o/$(MODE)/test/libc/sock/socket_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
o/$(MODE)/test/libc/sock/recvmsg_test.com.runs: \
private .INTERNET = 1 # need to bind to 0.0.0.0
o/$(MODE)/test/libc/sock/recvmsg_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet recvfd sendfd
o/$(MODE)/test/libc/sock/shutdown_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
.PHONY: o/$(MODE)/test/libc/sock

View file

@ -684,11 +684,21 @@ PyInit_termios(void)
PyModule_AddIntConstant(m, "CWERASE", CWERASE);
/* ioctl */
#ifdef FIOCLEX
PyModule_AddIntConstant(m, "FIOCLEX", FIOCLEX);
#endif
#ifdef FIONCLEX
PyModule_AddIntConstant(m, "FIONCLEX", FIONCLEX);
#endif
#ifdef FIONBIO
PyModule_AddIntConstant(m, "FIONBIO", FIONBIO);
#endif
#ifdef FIONREAD
PyModule_AddIntConstant(m, "FIONREAD", FIONREAD);
#endif
#ifdef FIOASYNC
PyModule_AddIntConstant(m, "FIOASYNC", FIOASYNC);
#endif
if (EXTA) PyModule_AddIntConstant(m, "EXTA", EXTA);
if (EXTB) PyModule_AddIntConstant(m, "EXTB", EXTB);
@ -744,17 +754,25 @@ PyInit_termios(void)
/* TODO(jart): NOSTOP */
/* TODO(jart): START */
/* TODO(jart): STOP */
#ifdef TIOCSCTTY
if (TIOCSCTTY) PyModule_AddIntConstant(m, "TIOCSCTTY", TIOCSCTTY);
#endif
/* TODO(jart): TIOCSERCONFIG */
/* TODO(jart): TIOCSERGSTRUCT */
/* TODO(jart): TIOCSERGWILD */
/* TODO(jart): TIOCSERSWILD */
#ifdef TIOCSETD
if (TIOCSETD) PyModule_AddIntConstant(m, "TIOCSETD", TIOCSETD);
#endif
/* TODO(jart): TIOCSLCKTRMIOS */
#ifdef TIOCSPGRP
if (TIOCSPGRP) PyModule_AddIntConstant(m, "TIOCSPGRP", TIOCSPGRP);
#endif
/* TODO(jart): TIOCSSERIAL */
/* TODO(jart): TIOCSSOFTCAR */
#ifdef TIOCSTI
if (TIOCSTI) PyModule_AddIntConstant(m, "TIOCSTI", TIOCSTI);
#endif
/* TODO(jart): TIOCTTYGSTRUCT */
return m;

Some files were not shown because too many files have changed in this diff Show more