Make more Windows socket fixes and improvements

This change makes send() / sendto() always block on Windows. It's needed
because poll(POLLOUT) doesn't guarantee a socket is immediately writable
on Windows, and it caused rsync to fail because it made that assumption.
The only exception is when a SO_SNDTIMEO is specified which will EAGAIN.

Tests are added confirming MSG_WAITALL and MSG_NOSIGNAL work as expected
on all our supported OSes. Most of the platform-specific MSG_FOO magnums
have been deleted, with the exception of MSG_FASTOPEN. Your --strace log
will now show MSG_FOO flags as symbols rather than numbers.

I've also removed cv_wait_example_test because it's 0.3% flaky with Qemu
under system load since it depends on a process being readily scheduled.
This commit is contained in:
Justine Tunney 2024-09-18 19:54:56 -07:00
parent ce2fbf9325
commit 87a6669900
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
41 changed files with 584 additions and 184 deletions

View file

@ -8,8 +8,8 @@ struct thatispacked DescribeFlags {
const char *name; const char *name;
}; };
const char *_DescribeFlags(char *, size_t, const struct DescribeFlags *, const char *_DescribeFlags(char *, size_t, const struct DescribeFlags *, size_t,
size_t, const char *, unsigned) libcesque; const char *, unsigned) libcesque;
const char *_DescribeArchPrctlCode(char[12], int) libcesque; const char *_DescribeArchPrctlCode(char[12], int) libcesque;
const char *_DescribeCancelState(char[12], int, int *) libcesque; const char *_DescribeCancelState(char[12], int, int *) libcesque;
@ -27,6 +27,7 @@ const char *_DescribeItimer(char[12], int) libcesque;
const char *_DescribeMapFlags(char[64], int) libcesque; const char *_DescribeMapFlags(char[64], int) libcesque;
const char *_DescribeMapping(char[8], int, int) libcesque; const char *_DescribeMapping(char[8], int, int) libcesque;
const char *_DescribeMremapFlags(char[30], int) libcesque; const char *_DescribeMremapFlags(char[30], int) libcesque;
const char *_DescribeMsg(char[16], int) libcesque;
const char *_DescribeMsyncFlags(char[48], int) libcesque; const char *_DescribeMsyncFlags(char[48], int) libcesque;
const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque; const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque;
const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque; const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque;
@ -84,6 +85,7 @@ const char *_DescribeWhichPrio(char[12], int) libcesque;
#define DescribeMapFlags(x) _DescribeMapFlags(alloca(64), x) #define DescribeMapFlags(x) _DescribeMapFlags(alloca(64), x)
#define DescribeMapping(x, y) _DescribeMapping(alloca(8), x, y) #define DescribeMapping(x, y) _DescribeMapping(alloca(8), x, y)
#define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x) #define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x)
#define DescribeMsg(x) _DescribeMsg(alloca(16), x)
#define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x) #define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x)
#define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x) #define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x)
#define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x) #define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x)

36
libc/intrin/describemsg.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2024 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/intrin/describeflags.h"
#include "libc/macros.h"
#include "libc/sysv/consts/msg.h"
const char *_DescribeMsg(char buf[16], int x) {
const struct DescribeFlags kMsgFlags[] = {
{MSG_FASTOPEN, "FASTOPEN"}, // order matters
{MSG_OOB, "OOB"}, //
{MSG_PEEK, "PEEK"}, //
{MSG_DONTROUTE, "DONTROUTE"}, //
{MSG_DONTWAIT, "DONTWAIT"}, //
{MSG_WAITALL, "WAITALL"}, //
{MSG_NOSIGNAL, "NOSIGNAL"}, //
{MSG_TRUNC, "TRUNC"}, //
{MSG_CTRUNC, "CTRUNC"}, //
};
return _DescribeFlags(buf, 16, kMsgFlags, ARRAYLEN(kMsgFlags), "MSG_", x);
}

View file

@ -65,7 +65,7 @@ int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *,
size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *, size_t); size_t __iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *, size_t);
ssize_t __winsock_block(int64_t, uint32_t, int, uint32_t, uint64_t, ssize_t __winsock_block(int64_t, uint32_t, bool, uint32_t, uint64_t,
int (*)(int64_t, struct NtOverlapped *, uint32_t *, int (*)(int64_t, struct NtOverlapped *, uint32_t *,
void *), void *),
void *); void *);

View file

@ -17,15 +17,17 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/fds.h"
#include "libc/nt/struct/iovec.h" #include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
#ifdef __x86_64__ #ifdef __x86_64__
#define _MSG_OOB 1 #define _MSG_OOB 1
@ -33,6 +35,8 @@
#define _MSG_WAITALL 8 #define _MSG_WAITALL 8
#define _MSG_DONTWAIT 64 #define _MSG_DONTWAIT 64
__msabi extern typeof(__sys_ioctlsocket_nt) *const __imp_ioctlsocket;
struct RecvArgs { struct RecvArgs {
const struct iovec *iov; const struct iovec *iov;
size_t iovlen; size_t iovlen;
@ -54,13 +58,24 @@ textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
return einval(); return einval();
ssize_t rc; ssize_t rc;
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block(); sigset_t waitmask = __sig_block();
bool nonblock = !(flags & _MSG_WAITALL) &&
((f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT)); // "Be aware that if the underlying transport provider does not
flags &= ~_MSG_DONTWAIT; // support MSG_WAITALL, or if the socket is in a non-blocking mode,
rc = __winsock_block(f->handle, flags, nonblock, f->rcvtimeo, m, // then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL
sys_recv_nt_start, &(struct RecvArgs){iov, iovlen}); // is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then
__sig_unblock(m); // this call will fail with WSAEOPNOTSUPP."
// —Quoth MSDN § WSARecv
if (flags & _MSG_WAITALL)
__imp_ioctlsocket(f->handle, FIONBIO, (uint32_t[]){0});
rc = __winsock_block(f->handle, flags & ~_MSG_DONTWAIT,
(f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT),
f->rcvtimeo, waitmask, sys_recv_nt_start,
&(struct RecvArgs){iov, iovlen});
__sig_unblock(waitmask);
return rc; return rc;
} }

View file

@ -20,20 +20,40 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/msg.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**
* Receives data from network socket. * Receives data from network socket.
* *
* Calling `recv(fd, p, n, 0)` is equivalent to `read(fd, p, n)`.
*
* Unlike files where the OS tries very hard to fulfill the entire
* requested `size` before returning, read operations on sockets aim to
* return as quickly as possible. For example, if 10 bytes are requested
* and a packet comes in with only 5 bytes, then recv() will most likely
* return those 5 bytes before waiting longer. The `MSG_WAITALL` flag
* may be passed when waiting longer is desired. In that case, short
* reads should only be possible when the connection status changes or
* the receive operation is interrupted by a signal.
*
* @param fd is the file descriptor returned by socket() * @param fd is the file descriptor returned by socket()
* @param buf is where received network data gets copied * @param buf is where received network data gets copied
* @param size is the byte capacity of buf * @param size is the byte capacity of buf
* @param flags can have `MSG_OOB`, `MSG_PEEK`, `MSG_DONTWAIT`, `MSG_WAITALL` * @param flags can have `MSG_OOB`, `MSG_PEEK`, `MSG_DONTWAIT`, `MSG_WAITALL`
* @return number of bytes received, 0 on remote close, or -1 w/ errno * @return number of bytes received, 0 on remote close, or -1 w/ errno
* @raise EINTR if signal handler was called instead
* @raise EINVAL if unknown bits were passed in `flags`
* @raise EINVAL if flag isn't supported by host operating system
* @raise EINVAL if `MSG_WAITALL` and `MSG_PEEK` were both passed
* @raise EBADF if `fd` is an invalid file descriptor
* @raise EAGAIN if `MSG_DONTWAIT` was passed and no data was available
* @raise EAGAIN if `O_NONBLOCK` is in play and no data was available
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable), * @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc. * EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
* @cancelationpoint * @cancelationpoint
@ -44,7 +64,11 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
ssize_t rc; ssize_t rc;
BEGIN_CANCELATION_POINT; BEGIN_CANCELATION_POINT;
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { if ((flags & (MSG_WAITALL | MSG_PEEK)) == (MSG_WAITALL | MSG_PEEK)) {
// this is possible on some OSes like Linux but it breaks FreeBSD
// and Windows will raise EOPNOTSUPP when it gets passed together
return einval();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = enotsock(); rc = enotsock();
} else if (!IsWindows()) { } else if (!IsWindows()) {
rc = sys_recvfrom(fd, buf, size, flags, 0, 0); rc = sys_recvfrom(fd, buf, size, flags, 0, 0);
@ -65,7 +89,8 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
} }
END_CANCELATION_POINT; END_CANCELATION_POINT;
DATATRACE("recv(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd, DATATRACE("recv(%d, [%#.*hhs%s], %'zu, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc); MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size,
DescribeMsg(flags), rc);
return rc; return rc;
} }

View file

@ -59,14 +59,13 @@ textwindows ssize_t sys_recvfrom_nt(int fd, const struct iovec *iov,
return einval(); return einval();
ssize_t rc; ssize_t rc;
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block(); sigset_t waitmask = __sig_block();
bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT); rc = __winsock_block(f->handle, flags & ~_MSG_DONTWAIT,
flags &= ~_MSG_DONTWAIT; (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT),
rc = __winsock_block(f->handle, flags, nonblock, f->rcvtimeo, m, f->rcvtimeo, waitmask, sys_recvfrom_nt_start,
sys_recvfrom_nt_start,
&(struct RecvFromArgs){iov, iovlen, opt_out_srcaddr, &(struct RecvFromArgs){iov, iovlen, opt_out_srcaddr,
opt_inout_srcaddrsize}); opt_inout_srcaddrsize});
__sig_unblock(m); __sig_unblock(waitmask);
return rc; return rc;
} }

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
@ -95,7 +96,11 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
} }
END_CANCELATION_POINT; END_CANCELATION_POINT;
DATATRACE("recvfrom(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd, DATATRACE(
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc); "recvfrom(%d, [%#.*hhs%s], %'zu, %s, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, DescribeMsg(flags),
DescribeSockaddr(opt_out_srcaddr,
opt_inout_srcaddrsize ? *opt_inout_srcaddrsize : 0),
rc);
return rc; return rc;
} }

View file

@ -17,20 +17,25 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/fds.h" #include "libc/errno.h"
#include "libc/nt/errors.h"
#include "libc/nt/struct/iovec.h" #include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
#ifdef __x86_64__ #ifdef __x86_64__
#define _MSG_OOB 1 #define _MSG_OOB 1
#define _MSG_DONTROUTE 4 #define _MSG_DONTROUTE 4
#define _MSG_DONTWAIT 64 #define _MSG_DONTWAIT 64
#define _MSG_NOSIGNAL 0x10000000
struct SendArgs { struct SendArgs {
const struct iovec *iov; const struct iovec *iov;
@ -49,23 +54,24 @@ textwindows static int sys_send_nt_start(int64_t handle,
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen, textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
uint32_t flags) { uint32_t flags) {
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE)) if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE | _MSG_NOSIGNAL))
return einval(); return einval();
ssize_t rc; ssize_t rc;
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block(); sigset_t waitmask = __sig_block();
// we don't check O_NONBLOCK because we want to avoid needing to call rc = __winsock_block(f->handle, flags & ~(_MSG_DONTWAIT | _MSG_NOSIGNAL),
// WSAPoll() every time we write() to a non-blocking socket. WIN32 is false, f->sndtimeo, waitmask, sys_send_nt_start,
// unsafe at canceling socket sends. lots of code doesn't check write &(struct SendArgs){iov, iovlen});
// return status. good programs that sincerely want to avoid blocking
// on send() operations should have already called poll() beforehand. __sig_unblock(waitmask);
bool nonblock = flags & _MSG_DONTWAIT;
if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN
errno = kNtErrorBrokenPipe; // EPIPE
if (!(flags & _MSG_NOSIGNAL))
__sig_raise(SIGPIPE, SI_KERNEL);
}
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(f->handle, flags, -nonblock, f->sndtimeo, m,
sys_send_nt_start, &(struct SendArgs){iov, iovlen});
__sig_unblock(m);
return rc; return rc;
} }

View file

@ -21,6 +21,7 @@
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
@ -78,7 +79,7 @@ ssize_t send(int fd, const void *buf, size_t size, int flags) {
} }
END_CANCELATION_POINT; END_CANCELATION_POINT;
DATATRACE("send(%d, %#.*hhs%s, %'zu, %#x) → %'ld% lm", fd, DATATRACE("send(%d, %#.*hhs%s, %'zu, %s) → %'ld% lm", fd, MAX(0, MIN(40, rc)),
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc); buf, rc > 40 ? "..." : "", size, DescribeMsg(flags), rc);
return rc; return rc;
} }

View file

@ -17,20 +17,26 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.internal.h" #include "libc/calls/struct/sigset.internal.h"
#include "libc/errno.h"
#include "libc/intrin/fds.h" #include "libc/intrin/fds.h"
#include "libc/nt/errors.h"
#include "libc/nt/struct/iovec.h" #include "libc/nt/struct/iovec.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h" #include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__
#define _MSG_OOB 1 #define _MSG_OOB 1
#define _MSG_DONTROUTE 4 #define _MSG_DONTROUTE 4
#define _MSG_DONTWAIT 64 #define _MSG_DONTWAIT 64
#define _MSG_NOSIGNAL 0x10000000
struct SendToArgs { struct SendToArgs {
const struct iovec *iov; const struct iovec *iov;
@ -52,17 +58,25 @@ static textwindows int sys_sendto_nt_start(int64_t handle,
textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov, textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
size_t iovlen, uint32_t flags, size_t iovlen, uint32_t flags,
void *opt_in_addr, uint32_t in_addrsize) { void *opt_in_addr, uint32_t in_addrsize) {
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE)) if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE | _MSG_NOSIGNAL))
return einval(); return einval();
ssize_t rc; ssize_t rc;
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block(); sigset_t waitmask = __sig_block();
bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT);
flags &= ~_MSG_DONTWAIT; rc = __winsock_block(f->handle, flags & ~(_MSG_DONTWAIT | _MSG_NOSIGNAL),
rc = __winsock_block( false, f->sndtimeo, waitmask, sys_sendto_nt_start,
f->handle, flags, -nonblock, f->sndtimeo, m, sys_sendto_nt_start, &(struct SendToArgs){iov, iovlen, //
&(struct SendToArgs){iov, iovlen, opt_in_addr, in_addrsize}); opt_in_addr, in_addrsize});
__sig_unblock(m);
__sig_unblock(waitmask);
if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN
errno = kNtErrorBrokenPipe; // EPIPE
if (!(flags & _MSG_NOSIGNAL))
__sig_raise(SIGPIPE, SI_KERNEL);
}
return rc; return rc;
} }

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h" #include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
@ -88,8 +89,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, int flags,
} }
END_CANCELATION_POINT; END_CANCELATION_POINT;
DATATRACE("sendto(%d, %#.*hhs%s, %'zu, %#x, %p, %u) → %'ld% lm", fd, DATATRACE("sendto(%d, %#.*hhs%s, %'zu, %s, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size,
opt_addr, addrsize, rc); DescribeMsg(flags), DescribeSockaddr(opt_addr, addrsize), rc);
return rc; return rc;
} }

View file

@ -42,7 +42,7 @@
#ifdef __x86_64__ #ifdef __x86_64__
textwindows ssize_t textwindows ssize_t
__winsock_block(int64_t handle, uint32_t flags, int nonblock, __winsock_block(int64_t handle, uint32_t flags, bool nonblock,
uint32_t srwtimeout, sigset_t waitmask, uint32_t srwtimeout, sigset_t waitmask,
int StartSocketOp(int64_t handle, struct NtOverlapped *overlap, int StartSocketOp(int64_t handle, struct NtOverlapped *overlap,
uint32_t *flags, void *arg), uint32_t *flags, void *arg),
@ -63,21 +63,6 @@ __winsock_block(int64_t handle, uint32_t flags, int nonblock,
bool got_eagain = false; bool got_eagain = false;
uint32_t other_error = 0; uint32_t other_error = 0;
// send() and sendto() provide O_NONBLOCK as a negative number
// because winsock has a bug that causes CancelIoEx() to cause
// WSAGetOverlappedResult() to report errors when it succeeded
if (nonblock < 0) {
struct sys_pollfd_nt fds[1] = {{handle, POLLOUT}};
switch (WSAPoll(fds, 1, 0)) {
case -1:
return __winsockerr();
case 0:
return eagain();
default:
break;
}
}
// create event handle for overlapped i/o // create event handle for overlapped i/o
intptr_t event; intptr_t event;
if (!(event = WSACreateEvent())) if (!(event = WSACreateEvent()))
@ -86,7 +71,10 @@ __winsock_block(int64_t handle, uint32_t flags, int nonblock,
struct NtOverlapped overlap = {.hEvent = event}; struct NtOverlapped overlap = {.hEvent = event};
bool32 ok = !StartSocketOp(handle, &overlap, &flags, arg); bool32 ok = !StartSocketOp(handle, &overlap, &flags, arg);
if (!ok && WSAGetLastError() == kNtErrorIoPending) { if (!ok && WSAGetLastError() == kNtErrorIoPending) {
if (nonblock > 0) { if (nonblock) {
// send() and sendto() shall not pass O_NONBLOCK along to here
// because winsock has a bug that causes CancelIoEx() to cause
// WSAGetOverlappedResult() to report errors when it succeeded
CancelIoEx(handle, &overlap); CancelIoEx(handle, &overlap);
got_eagain = true; got_eagain = true;
} else { } else {

View file

@ -1138,32 +1138,12 @@ syscon reboot RB_NOSYNC 0x20000000 0x20000000 4 4 4 4 4 0x2000000
syscon msg MSG_OOB 1 1 1 1 1 1 1 1 # consensus syscon msg MSG_OOB 1 1 1 1 1 1 1 1 # consensus
syscon msg MSG_PEEK 2 2 2 2 2 2 2 2 # consensus syscon msg MSG_PEEK 2 2 2 2 2 2 2 2 # consensus
syscon msg MSG_DONTROUTE 4 4 4 4 4 4 4 4 # consensus syscon msg MSG_DONTROUTE 4 4 4 4 4 4 4 4 # consensus
syscon msg MSG_FASTOPEN 0x20000000 0x20000000 0 0 0 0 0 0 # TODO
syscon msg MSG_WAITALL 0x0100 0x0100 0x40 0x40 0x40 0x40 0x40 8 # bsd consensus
syscon msg MSG_MORE 0x8000 0x8000 0 0 0 0 0 0 # send/sendto: manual TCP_CORK hbasically
syscon msg MSG_NOSIGNAL 0x4000 0x4000 0x80000 0x80000 0x020000 0x0400 0x0400 0 # send/sendto: don't SIGPIPE on EOF
syscon msg MSG_DONTWAIT 0x40 0x40 0x80 0x80 0x80 0x80 0x80 0x40 # send/sendto: manual non-blocking syscon msg MSG_DONTWAIT 0x40 0x40 0x80 0x80 0x80 0x80 0x80 0x40 # send/sendto: manual non-blocking
syscon msg MSG_WAITALL 0x0100 0x0100 0x40 0x40 0x40 0x40 0x40 8 # bsd consensus
syscon msg MSG_NOSIGNAL 0x4000 0x4000 0x80000 0x80000 0x020000 0x0400 0x0400 0x10000000 # send/sendto: don't raise sigpipe on local shutdown
syscon msg MSG_TRUNC 0x20 0x20 0x10 0x10 0x10 0x10 0x10 0x0100 # bsd consensus syscon msg MSG_TRUNC 0x20 0x20 0x10 0x10 0x10 0x10 0x10 0x0100 # bsd consensus
syscon msg MSG_CTRUNC 8 8 0x20 0x20 0x20 0x20 0x20 0x0200 # bsd consensus syscon msg MSG_CTRUNC 8 8 0x20 0x20 0x20 0x20 0x20 0x0200 # bsd consensus
syscon msg MSG_ERRQUEUE 0x2000 0x2000 0 0 0 0 0 0x1000 # bsd consensus syscon msg MSG_FASTOPEN 0x20000000 0x20000000 -1 -1 -1 -1 -1 -1 #
syscon msg MSG_NOERROR 0x1000 0x1000 0x1000 0x1000 0x1000 0x1000 0x1000 0 # unix consensus
syscon msg MSG_EOR 0x80 0x80 8 8 8 8 8 0 # bsd consensus
syscon msg MSG_CMSG_CLOEXEC 0x40000000 0x40000000 0 0 0x040000 0x0800 0x0800 0
syscon msg MSG_WAITFORONE 0x010000 0x010000 0 0 0x080000 0 0x2000 0
syscon msg MSG_BATCH 0x040000 0x040000 0 0 0 0 0 0
syscon msg MSG_CONFIRM 0x0800 0x0800 0 0 0 0 0 0
syscon msg MSG_EXCEPT 0x2000 0x2000 0 0 0 0 0 0
syscon msg MSG_FIN 0x0200 0x0200 0x0100 0x0100 0x0100 0 0 0
syscon msg MSG_EOF 0x0200 0x0200 0x0100 0x0100 0x0100 0 0 0
syscon msg MSG_INFO 12 12 0 0 0 0 0 0
syscon msg MSG_PARITY_ERROR 9 9 0 0 0 0 0 0
syscon msg MSG_PROXY 0x10 0x10 0 0 0 0 0 0
syscon msg MSG_RST 0x1000 0x1000 0 0 0 0 0 0
syscon msg MSG_STAT 11 11 0 0 0 0 0 0
syscon msg MSG_SYN 0x0400 0x0400 0 0 0 0 0 0
syscon msg MSG_BCAST 0 0 0 0 0 0x100 0x100 0
syscon msg MSG_MCAST 0 0 0 0 0 0x200 0x200 0
syscon msg MSG_NOTIFICATION 0x8000 0x8000 0 0 0x2000 0 0x4000 0
# getpriority() / setpriority() magnums (a.k.a. nice) # getpriority() / setpriority() magnums (a.k.a. nice)
# #

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_BATCH,0x040000,0x040000,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_BCAST,0,0,0,0,0,0x100,0x100,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_CMSG_CLOEXEC,0x40000000,0x40000000,0,0,0x040000,0x0800,0x0800,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_CONFIRM,0x0800,0x0800,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_EOF,0x0200,0x0200,0x0100,0x0100,0x0100,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_EOR,0x80,0x80,8,8,8,8,8,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_ERRQUEUE,0x2000,0x2000,0,0,0,0,0,0x1000

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_EXCEPT,0x2000,0x2000,0,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_FASTOPEN,0x20000000,0x20000000,0,0,0,0,0,0 .syscon msg,MSG_FASTOPEN,0x20000000,0x20000000,-1,-1,-1,-1,-1,-1

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_FIN,0x0200,0x0200,0x0100,0x0100,0x0100,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_INFO,12,12,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_MCAST,0,0,0,0,0,0x200,0x200,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_MORE,0x8000,0x8000,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_NOERROR,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_NOSIGNAL,0x4000,0x4000,0x80000,0x80000,0x020000,0x0400,0x0400,0 .syscon msg,MSG_NOSIGNAL,0x4000,0x4000,0x80000,0x80000,0x020000,0x0400,0x0400,0x10000000

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_NOTIFICATION,0x8000,0x8000,0,0,0x2000,0,0x4000,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_PARITY_ERROR,9,9,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_PROXY,0x10,0x10,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_RST,0x1000,0x1000,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_STAT,11,11,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_SYN,0x0400,0x0400,0,0,0,0,0,0

View file

@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon msg,MSG_WAITFORONE,0x010000,0x010000,0,0,0x080000,0,0x2000,0

View file

@ -2,41 +2,18 @@
#define COSMOPOLITAN_LIBC_SYSV_CONSTS_MSG_H_ #define COSMOPOLITAN_LIBC_SYSV_CONSTS_MSG_H_
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern const int MSG_BATCH;
extern const int MSG_BCAST;
extern const int MSG_CMSG_CLOEXEC;
extern const int MSG_CONFIRM;
extern const int MSG_CTRUNC;
extern const int MSG_DONTROUTE;
extern const int MSG_DONTWAIT; extern const int MSG_DONTWAIT;
extern const int MSG_EOF;
extern const int MSG_EOR;
extern const int MSG_ERRQUEUE;
extern const int MSG_EXCEPT;
extern const int MSG_FASTOPEN;
extern const int MSG_FIN;
extern const int MSG_INFO;
extern const int MSG_MCAST;
extern const int MSG_MORE;
extern const int MSG_NOERROR;
extern const int MSG_NOSIGNAL;
extern const int MSG_NOTIFICATION;
extern const int MSG_OOB;
extern const int MSG_PARITY_ERROR;
extern const int MSG_PEEK;
extern const int MSG_PROXY;
extern const int MSG_RST;
extern const int MSG_STAT;
extern const int MSG_SYN;
extern const int MSG_TRUNC;
extern const int MSG_WAITALL; extern const int MSG_WAITALL;
extern const int MSG_WAITFORONE; extern const int MSG_NOSIGNAL;
extern const int MSG_TRUNC;
extern const int MSG_CTRUNC;
extern const int MSG_FASTOPEN; /* linux only */
#define MSG_OOB 1 #define MSG_OOB 1
#define MSG_PEEK 2 #define MSG_PEEK 2
#define MSG_DONTROUTE 4 #define MSG_DONTROUTE 4
#define MSG_DONTWAIT MSG_DONTWAIT #define MSG_DONTWAIT MSG_DONTWAIT
#define MSG_FASTOPEN MSG_FASTOPEN #define MSG_NOSIGNAL MSG_NOSIGNAL
#define MSG_WAITALL MSG_WAITALL #define MSG_WAITALL MSG_WAITALL
#define MSG_TRUNC MSG_TRUNC #define MSG_TRUNC MSG_TRUNC
#define MSG_CTRUNC MSG_CTRUNC #define MSG_CTRUNC MSG_CTRUNC

View file

@ -0,0 +1,196 @@
// Copyright 2024 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 <arpa/inet.h>
#include <cosmo.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/**
* @fileoverview send(MSG_NOSIGNAL) test
*
* It's possible when writing to a socket for SIGPIPE to be raised. It
* can happen for a variety of reasons. The one reason that has broad
* consensus across OSes and is officially documented, is if shutdown()
* is used on the local end.
*/
struct sockaddr_in serv_addr;
atomic_bool g_ready_for_conn;
atomic_bool g_ready_for_data;
atomic_bool g_ready_for_more;
atomic_bool g_ready_for_exit;
volatile sig_atomic_t g_got_signal;
void onsig(int sig) {
g_got_signal = sig;
}
void *server_thread(void *arg) {
socklen_t len;
int server, client;
struct sockaddr_in cli_addr;
// create listening socket
server = socket(AF_INET, SOCK_STREAM, 0);
if (server == -1) {
perror("socket");
exit(10);
}
// initialize server address
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serv_addr.sin_port = htons(0);
// bind socket
if (bind(server, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
perror("bind");
exit(11);
}
// get assigned port
len = sizeof(serv_addr);
if (getsockname(server, (struct sockaddr *)&serv_addr, &len)) {
perror("getsockname");
exit(12);
}
// listen on the socket
if (listen(server, SOMAXCONN)) {
perror("listen");
exit(13);
}
// wake main thread
g_ready_for_conn = true;
// accept connection
len = sizeof(cli_addr);
client = accept(server, (struct sockaddr *)&cli_addr, &len);
if (client == -1) {
perror("accept");
exit(14);
}
// wake main thread
g_ready_for_data = true;
// wait for thread
for (;;)
if (g_ready_for_exit)
break;
// close sockets
if (close(client))
exit(29);
if (close(server))
exit(28);
return 0;
}
int main() {
// create server thread
pthread_t th;
if (pthread_create(&th, 0, server_thread, 0))
return 1;
// wait for thread
for (;;)
if (g_ready_for_conn)
break;
// create socket
int client = socket(AF_INET, SOCK_STREAM, 0);
if (client == -1) {
perror("socket");
return 2;
}
// connect to server
if (connect(client, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
perror("connect");
return 3;
}
// wait for thread
for (;;)
if (g_ready_for_data)
break;
// handle signals
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = onsig;
sigemptyset(&sa.sa_mask);
sigaction(SIGPIPE, &sa, 0);
// half close socket
if (shutdown(client, SHUT_WR))
return 15;
// send first transmission
int rc;
for (;;) {
rc = write(client, "x", 1);
if (rc == 1)
continue;
if (rc != -1)
return 4;
if (errno != EPIPE) {
perror("write");
return 5;
}
// NetBSD is oddly lazy about sending SIGPIPE
if (IsNetbsd())
for (;;)
if (g_got_signal)
break;
if (g_got_signal != SIGPIPE) {
fprintf(stderr, "expected SIGPIPE but got %s\n", strsignal(g_got_signal));
return 6;
}
g_got_signal = 0;
break;
}
// send first transmission
rc = send(client, "x", 1, MSG_NOSIGNAL);
if (rc != -1)
return 7;
if (errno != EPIPE)
return 8;
if (g_got_signal)
return 9;
g_ready_for_exit = true;
if (pthread_join(th, 0))
return 6;
}

View file

@ -0,0 +1,207 @@
// Copyright 2024 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 <arpa/inet.h>
#include <cosmo.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/**
* @fileoverview recv(MSG_WAITALL) test
*/
struct sockaddr_in serv_addr;
atomic_bool g_ready_for_conn;
atomic_bool g_ready_for_data;
atomic_bool g_ready_for_more;
atomic_bool g_ready_for_exit;
void *server_thread(void *arg) {
socklen_t len;
int server, client;
struct sockaddr_in cli_addr;
// create listening socket
server = socket(AF_INET, SOCK_STREAM, 0);
if (server == -1) {
perror("socket");
exit(10);
}
// initialize server address
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serv_addr.sin_port = htons(0);
// bind socket
if (bind(server, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
perror("bind");
exit(11);
}
// get assigned port
len = sizeof(serv_addr);
if (getsockname(server, (struct sockaddr *)&serv_addr, &len)) {
perror("getsockname");
exit(12);
}
// listen on the socket
if (listen(server, SOMAXCONN)) {
perror("listen");
exit(13);
}
// wake main thread
g_ready_for_conn = true;
// accept connection
len = sizeof(cli_addr);
client = accept(server, (struct sockaddr *)&cli_addr, &len);
if (client == -1) {
perror("accept");
exit(14);
}
// check waitall + dontwait
char buf[2];
int rc = recv(client, buf, 2, MSG_WAITALL | MSG_DONTWAIT);
if (rc != -1)
exit(15);
if (errno != EAGAIN)
exit(16);
// wake main thread
g_ready_for_data = true;
// check peek
rc = recv(client, buf, 2, MSG_PEEK);
if (rc == -1) {
perror("recv1");
exit(17);
}
if (rc != 1)
exit(18);
if (buf[0] != 'x')
exit(19);
// check read() has @restartable behavior
rc = recv(client, buf, 2, MSG_WAITALL);
if (rc == -1) {
perror("recv2");
exit(21);
}
if (rc != 2)
exit(22);
if (buf[0] != 'x')
exit(23);
if (buf[1] != 'y')
exit(24);
// wake main thread
g_ready_for_more = true;
// check normal recv won't wait
rc = read(client, buf, 2);
if (rc == -1) {
perror("recv3");
exit(25);
}
if (rc != 1)
exit(26);
if (buf[0] != 'x')
exit(27);
// wait for main thread
for (;;)
if (g_ready_for_exit)
break;
// close listening socket
if (close(server))
exit(28);
if (close(client))
exit(29);
return 0;
}
int main() {
// create server thread
pthread_t th;
if (pthread_create(&th, 0, server_thread, 0))
return 1;
// wait for thread
for (;;)
if (g_ready_for_conn)
break;
// create socket
int client = socket(AF_INET, SOCK_STREAM, 0);
if (client == -1) {
perror("socket");
return 2;
}
// connect to server
if (connect(client, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
perror("connect");
return 3;
}
// wait for thread
for (;;)
if (g_ready_for_data)
break;
// send first transmission
usleep(100e3);
if (write(client, "x", 1) != 1)
return 4;
usleep(100e3);
if (write(client, "y", 1) != 1)
return 5;
// wait for thread
for (;;)
if (g_ready_for_more)
break;
// send second transmission
usleep(100e3);
if (write(client, "x", 1) != 1)
return 4;
usleep(100e3);
if (write(client, "y", 1) != 1)
return 5;
g_ready_for_exit = true;
if (pthread_join(th, 0))
return 6;
}

View file

@ -3439,12 +3439,14 @@ int LuaUnix(lua_State *L) {
LuaSetIntField(L, "SHUT_RDWR", SHUT_RDWR); LuaSetIntField(L, "SHUT_RDWR", SHUT_RDWR);
// recvfrom() / sendto() flags // recvfrom() / sendto() flags
LuaSetIntField(L, "MSG_WAITALL", MSG_WAITALL);
LuaSetIntField(L, "MSG_DONTROUTE", MSG_DONTROUTE);
LuaSetIntField(L, "MSG_PEEK", MSG_PEEK);
LuaSetIntField(L, "MSG_OOB", MSG_OOB); LuaSetIntField(L, "MSG_OOB", MSG_OOB);
LuaSetIntField(L, "MSG_PEEK", MSG_PEEK);
LuaSetIntField(L, "MSG_DONTROUTE", MSG_DONTROUTE);
LuaSetIntField(L, "MSG_DONTWAIT", MSG_DONTWAIT);
LuaSetIntField(L, "MSG_NOSIGNAL", MSG_NOSIGNAL); LuaSetIntField(L, "MSG_NOSIGNAL", MSG_NOSIGNAL);
LuaSetIntField(L, "MSG_MORE", MSG_MORE); LuaSetIntField(L, "MSG_WAITALL", MSG_WAITALL);
LuaSetIntField(L, "MSG_TRUNC", MSG_TRUNC);
LuaSetIntField(L, "MSG_CTRUNC", MSG_CTRUNC);
// readdir() type // readdir() type
LuaSetIntField(L, "DT_UNKNOWN", DT_UNKNOWN); LuaSetIntField(L, "DT_UNKNOWN", DT_UNKNOWN);

View file

@ -25,6 +25,7 @@
#include "third_party/nsync/testing/closure.h" #include "third_party/nsync/testing/closure.h"
#include "third_party/nsync/testing/smprintf.h" #include "third_party/nsync/testing/smprintf.h"
#include "third_party/nsync/testing/testing.h" #include "third_party/nsync/testing/testing.h"
#include "libc/dce.h"
#include "third_party/nsync/testing/time_extra.h" #include "third_party/nsync/testing/time_extra.h"
/* Example use of CV.wait(): A priority queue of strings whose /* Example use of CV.wait(): A priority queue of strings whose

View file

@ -6790,24 +6790,9 @@ PyInit__socket(void)
PyModule_AddIntMacro(m, MSG_TRUNC); PyModule_AddIntMacro(m, MSG_TRUNC);
PyModule_AddIntMacro(m, MSG_CTRUNC); PyModule_AddIntMacro(m, MSG_CTRUNC);
PyModule_AddIntMacro(m, MSG_WAITALL); PyModule_AddIntMacro(m, MSG_WAITALL);
if (MSG_DONTWAIT) PyModule_AddIntMacro(m, MSG_DONTWAIT); PyModule_AddIntMacro(m, MSG_DONTWAIT);
if (MSG_EOR) PyModule_AddIntMacro(m, MSG_EOR); PyModule_AddIntMacro(m, MSG_NOSIGNAL);
if (MSG_NOSIGNAL) PyModule_AddIntMacro(m, MSG_NOSIGNAL); if (MSG_FASTOPEN != -1) PyModule_AddIntMacro(m, MSG_FASTOPEN);
if (MSG_BCAST) PyModule_AddIntMacro(m, MSG_BCAST);
if (MSG_MCAST) PyModule_AddIntMacro(m, MSG_MCAST);
if (MSG_CMSG_CLOEXEC) PyModule_AddIntMacro(m, MSG_CMSG_CLOEXEC);
if (MSG_ERRQUEUE) PyModule_AddIntMacro(m, MSG_ERRQUEUE);
if (MSG_CONFIRM) PyModule_AddIntMacro(m, MSG_CONFIRM);
if (MSG_MORE) PyModule_AddIntMacro(m, MSG_MORE);
if (MSG_NOTIFICATION) PyModule_AddIntMacro(m, MSG_NOTIFICATION);
if (MSG_EOF) PyModule_AddIntMacro(m, MSG_EOF);
if (MSG_FASTOPEN) PyModule_AddIntMacro(m, MSG_FASTOPEN);
#ifdef MSG_BTAG
if (MSG_BTAG) PyModule_AddIntMacro(m, MSG_BTAG);
#endif
#ifdef MSG_ETAG
if (MSG_ETAG) PyModule_AddIntMacro(m, MSG_ETAG);
#endif
/* Protocol level and numbers, usable for [gs]etsockopt */ /* Protocol level and numbers, usable for [gs]etsockopt */
PyModule_AddIntMacro(m, SOL_SOCKET); PyModule_AddIntMacro(m, SOL_SOCKET);