mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
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:
parent
ce2fbf9325
commit
87a6669900
41 changed files with 584 additions and 184 deletions
|
@ -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
36
libc/intrin/describemsg.c
Normal 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);
|
||||||
|
}
|
|
@ -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 *);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_BATCH,0x040000,0x040000,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_BCAST,0,0,0,0,0,0x100,0x100,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_CMSG_CLOEXEC,0x40000000,0x40000000,0,0,0x040000,0x0800,0x0800,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_CONFIRM,0x0800,0x0800,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_EOF,0x0200,0x0200,0x0100,0x0100,0x0100,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_EOR,0x80,0x80,8,8,8,8,8,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_ERRQUEUE,0x2000,0x2000,0,0,0,0,0,0x1000
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_EXCEPT,0x2000,0x2000,0,0,0,0,0,0
|
|
|
@ -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
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_FIN,0x0200,0x0200,0x0100,0x0100,0x0100,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_INFO,12,12,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_MCAST,0,0,0,0,0,0x200,0x200,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_MORE,0x8000,0x8000,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_NOERROR,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0
|
|
|
@ -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
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_NOTIFICATION,0x8000,0x8000,0,0,0x2000,0,0x4000,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_PARITY_ERROR,9,9,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_PROXY,0x10,0x10,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_RST,0x1000,0x1000,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_STAT,11,11,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_SYN,0x0400,0x0400,0,0,0,0,0,0
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon msg,MSG_WAITFORONE,0x010000,0x010000,0,0,0x080000,0,0x2000,0
|
|
|
@ -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
|
||||||
|
|
196
test/posix/msg_nosignal_test.c
Normal file
196
test/posix/msg_nosignal_test.c
Normal 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;
|
||||||
|
}
|
207
test/posix/msg_waitall_test.c
Normal file
207
test/posix/msg_waitall_test.c
Normal 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;
|
||||||
|
}
|
10
third_party/lua/lunix.c
vendored
10
third_party/lua/lunix.c
vendored
|
@ -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);
|
||||||
|
|
|
@ -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
|
21
third_party/python/Modules/socketmodule.c
vendored
21
third_party/python/Modules/socketmodule.c
vendored
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue