mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-03 09:48:29 +00:00
Fix some more socket bugs
- The functions that return a sockaddr now do so the same way the Linux Kernel does across platforms, e.g. getpeername(), accept4() - Socket system calls on Windows will now only check for interrupts when a blocking operation needs to be performed. - Write tests for recvfrom() system call
This commit is contained in:
parent
ac92f25296
commit
0ba3199915
49 changed files with 347 additions and 352 deletions
|
@ -18,13 +18,12 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/state.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/sock/struct/sockaddr.internal.h"
|
||||
#include "libc/sock/struct/sockaddr6.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
@ -32,7 +31,7 @@
|
|||
#include "libc/sysv/consts/sock.h"
|
||||
|
||||
union AcceptExAddr {
|
||||
union sockaddr_storage_linux addr;
|
||||
struct sockaddr_storage addr;
|
||||
char buf[sizeof(struct sockaddr_storage) + 16];
|
||||
};
|
||||
|
||||
|
@ -41,30 +40,8 @@ struct AcceptExBuffer {
|
|||
union AcceptExAddr remote;
|
||||
};
|
||||
|
||||
static void CopyLinuxSockAddr(const union sockaddr_storage_linux *addr,
|
||||
void *out_addr, uint32_t *inout_addrsize) {
|
||||
uint32_t insize, outsize;
|
||||
if (out_addr && inout_addrsize) {
|
||||
if (addr->sa.sa_family == AF_INET) {
|
||||
outsize = sizeof(struct sockaddr_in);
|
||||
} else if (addr->sa.sa_family == AF_INET6) {
|
||||
outsize = sizeof(struct sockaddr_in6);
|
||||
} else if (addr->sa.sa_family == AF_UNIX) {
|
||||
outsize = sizeof(addr->sun.sun_family) +
|
||||
strnlen(addr->sun.sun_path, sizeof(addr->sun.sun_path)) + 1;
|
||||
} else {
|
||||
outsize = sizeof(union sockaddr_storage_linux);
|
||||
}
|
||||
insize = *inout_addrsize;
|
||||
if (insize) bzero(out_addr, insize);
|
||||
outsize = MIN(insize, outsize);
|
||||
if (outsize) memcpy(out_addr, addr, outsize);
|
||||
*inout_addrsize = outsize;
|
||||
}
|
||||
}
|
||||
|
||||
textwindows int sys_accept_nt(struct Fd *fd, void *out_addr,
|
||||
uint32_t *inout_addrsize, int accept4_flags) {
|
||||
textwindows int sys_accept_nt(struct Fd *fd, struct sockaddr_storage *addr,
|
||||
int accept4_flags) {
|
||||
int64_t handle;
|
||||
int rc, client, oflags;
|
||||
uint32_t bytes_received;
|
||||
|
@ -72,11 +49,6 @@ textwindows int sys_accept_nt(struct Fd *fd, void *out_addr,
|
|||
struct AcceptExBuffer buffer;
|
||||
struct SockFd *sockfd, *sockfd2;
|
||||
|
||||
// deliver interrupt instead if any are pending
|
||||
if (_check_interrupts(true, g_fds.p)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// creates resources for child socket
|
||||
// inherit the listener configuration
|
||||
sockfd = (struct SockFd *)fd->extra;
|
||||
|
@ -120,6 +92,6 @@ textwindows int sys_accept_nt(struct Fd *fd, void *out_addr,
|
|||
__fds_unlock();
|
||||
|
||||
// handoff information to caller;
|
||||
CopyLinuxSockAddr(&buffer.remote.addr, out_addr, inout_addrsize);
|
||||
memcpy(addr, &buffer.remote.addr, sizeof(*addr));
|
||||
return client;
|
||||
}
|
||||
|
|
|
@ -27,23 +27,20 @@
|
|||
#include "libc/sysv/consts/fd.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/sock.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
|
||||
int sys_accept4(int server, struct sockaddr_storage *addr, int flags) {
|
||||
uint32_t size = sizeof(*addr);
|
||||
int olderr, client, file_mode;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
uint32_t size = sizeof(bsd);
|
||||
void *out_addr = !IsBsd() ? addr : &bsd;
|
||||
uint32_t *out_addrsize = !IsBsd() ? addrsize : &size;
|
||||
static bool demodernize;
|
||||
if (demodernize) goto TriedAndTrue;
|
||||
olderr = errno;
|
||||
client = __sys_accept4(server, out_addr, out_addrsize, flags);
|
||||
client = __sys_accept4(server, addr, &size, flags);
|
||||
if (client == -1 && errno == ENOSYS) {
|
||||
// XNU/RHEL5/etc. don't support accept4(), but it's easilly polyfilled
|
||||
errno = olderr;
|
||||
demodernize = true;
|
||||
TriedAndTrue:
|
||||
if ((client = __sys_accept(server, out_addr, out_addrsize, 0)) != -1) {
|
||||
if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return einval();
|
||||
if ((client = __sys_accept(server, addr, &size, 0)) != -1) {
|
||||
// __sys_accept() has inconsistent flag inheritence across platforms
|
||||
// this is one of the issues that accept4() was invented for solving
|
||||
_unassert((file_mode = __sys_fcntl(client, F_GETFD)) != -1);
|
||||
_unassert(!__sys_fcntl(client, F_SETFD,
|
||||
((file_mode & ~FD_CLOEXEC) |
|
||||
|
@ -54,8 +51,5 @@ int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
|
|||
(flags & SOCK_NONBLOCK ? O_NONBLOCK : 0))));
|
||||
}
|
||||
}
|
||||
if (client != -1 && IsBsd()) {
|
||||
sockaddr2linux(&bsd, size, addr, addrsize);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
|
|
@ -44,18 +44,24 @@
|
|||
int accept4(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize,
|
||||
int flags) {
|
||||
int rc;
|
||||
char addrbuf[72];
|
||||
struct sockaddr_storage ss = {0};
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (!out_addr || !inout_addrsize ||
|
||||
(IsAsan() && !__asan_is_valid(out_addr, *inout_addrsize))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_accept4(fd, out_addr, inout_addrsize, flags);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_accept_nt(&g_fds.p[fd], out_addr, inout_addrsize, flags);
|
||||
if (IsWindows()) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_accept_nt(g_fds.p + fd, &ss, flags);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
rc = sys_accept4(fd, &ss, flags);
|
||||
}
|
||||
|
||||
if (rc != -1) {
|
||||
if (IsBsd()) {
|
||||
__convert_bsd_to_sockaddr(&ss);
|
||||
}
|
||||
__write_sockaddr(&ss, out_addr, inout_addrsize);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sock/yoink.inc"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int sys_getpeername_nt(struct Fd *fd, void *out_addr,
|
||||
uint32_t *out_addrsize) {
|
||||
_npassert(fd->kind == kFdSocket);
|
||||
if (__sys_getpeername_nt(fd->handle, out_addr, out_addrsize) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winsockerr();
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/sockaddr.internal.h"
|
||||
|
||||
int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
|
||||
int rc;
|
||||
uint32_t size;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
if (!IsBsd()) {
|
||||
rc = __sys_getpeername(fd, out_addr, out_addrsize);
|
||||
} else {
|
||||
size = sizeof(bsd);
|
||||
if ((rc = __sys_getpeername(fd, &bsd, &size)) != -1) {
|
||||
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
|
||||
textwindows int sys_getsockname_nt(struct Fd *fd, void *out_addr,
|
||||
uint32_t *out_addrsize) {
|
||||
_npassert(fd->kind == kFdSocket);
|
||||
if (__sys_getsockname_nt(fd->handle, out_addr, out_addrsize) != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winsockerr();
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/sockaddr.internal.h"
|
||||
|
||||
int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
|
||||
int rc;
|
||||
uint32_t size;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
if (!IsBsd()) {
|
||||
rc = __sys_getsockname(fd, out_addr, out_addrsize);
|
||||
} else {
|
||||
size = sizeof(bsd);
|
||||
if ((rc = __sys_getsockname(fd, &bsd, &size)) != -1) {
|
||||
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
|
@ -17,9 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
|
@ -27,25 +30,63 @@
|
|||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static int __getsockpeername(int fd, struct sockaddr *out_addr,
|
||||
uint32_t *inout_addrsize, const char *name,
|
||||
int impl_sysv(int, void *, uint32_t *),
|
||||
int impl_win32(uint64_t, void *, uint32_t *)) {
|
||||
int rc;
|
||||
struct sockaddr_storage ss = {0};
|
||||
uint32_t size = sizeof(ss);
|
||||
|
||||
if (IsWindows()) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
if ((rc = impl_win32(g_fds.p[fd].handle, &ss, &size))) {
|
||||
if (impl_win32 == __sys_getsockname_nt &&
|
||||
WSAGetLastError() == WSAEINVAL) {
|
||||
// The socket has not been bound to an address with bind, or
|
||||
// ADDR_ANY is specified in bind but connection has not yet
|
||||
// occurred. -MSDN
|
||||
ss.ss_family = ((struct SockFd *)g_fds.p[fd].extra)->family;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = __winsockerr();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
} else {
|
||||
rc = impl_sysv(fd, &ss, &size);
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
if (IsBsd()) {
|
||||
__convert_bsd_to_sockaddr(&ss);
|
||||
}
|
||||
__write_sockaddr(&ss, out_addr, inout_addrsize);
|
||||
}
|
||||
|
||||
STRACE("%s(%d, [%s]) -> %d% lm", name, fd,
|
||||
DescribeSockaddr(out_addr, inout_addrsize ? *inout_addrsize : 0), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns details about network interface kernel granted socket.
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see getpeername()
|
||||
*/
|
||||
int getsockname(int fd, struct sockaddr *out_addr, uint32_t *out_addrsize) {
|
||||
int rc;
|
||||
if (!out_addrsize || !out_addrsize ||
|
||||
(IsAsan() && (!__asan_is_valid(out_addrsize, 4) ||
|
||||
!__asan_is_valid(out_addr, *out_addrsize)))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_getsockname(fd, out_addr, out_addrsize);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_getsockname_nt(&g_fds.p[fd], out_addr, out_addrsize);
|
||||
} else {
|
||||
rc = ebadf();
|
||||
}
|
||||
STRACE("getsockname(%d, [%s]) -> %d% lm", fd,
|
||||
DescribeSockaddr(out_addr, out_addrsize ? *out_addrsize : 0), rc);
|
||||
return rc;
|
||||
int getsockname(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize) {
|
||||
return __getsockpeername(fd, out_addr, inout_addrsize, "getsockname",
|
||||
__sys_getsockname, __sys_getsockname_nt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns details about remote end of connected socket.
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see getsockname()
|
||||
*/
|
||||
int getpeername(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize) {
|
||||
return __getsockpeername(fd, out_addr, inout_addrsize, "getpeername",
|
||||
__sys_getpeername, __sys_getpeername_nt);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ int32_t __sys_getsockname(int32_t, void *, uint32_t *) _Hide;
|
|||
int32_t __sys_socket(int32_t, int32_t, int32_t) _Hide;
|
||||
int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) _Hide;
|
||||
|
||||
int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard _Hide;
|
||||
int32_t sys_accept4(int32_t, struct sockaddr_storage *, int) dontdiscard _Hide;
|
||||
int32_t sys_bind(int32_t, const void *, uint32_t) _Hide;
|
||||
int32_t sys_connect(int32_t, const void *, uint32_t) _Hide;
|
||||
int32_t sys_getsockopt(int32_t, int32_t, int32_t, void *, uint32_t *) _Hide;
|
||||
|
|
|
@ -32,10 +32,9 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
|||
size_t iovlen, uint32_t flags) {
|
||||
int err;
|
||||
ssize_t rc;
|
||||
uint32_t got = -666;
|
||||
uint32_t got;
|
||||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
err = errno;
|
||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
||||
|
|
|
@ -31,10 +31,9 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov,
|
|||
uint32_t *opt_inout_srcaddrsize) {
|
||||
int err;
|
||||
ssize_t rc;
|
||||
uint32_t got = -666;
|
||||
uint32_t got;
|
||||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
err = errno;
|
||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0, &flags,
|
||||
|
|
|
@ -53,37 +53,23 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
|||
struct sockaddr *opt_out_srcaddr,
|
||||
uint32_t *opt_inout_srcaddrsize) {
|
||||
ssize_t rc;
|
||||
uint32_t sz;
|
||||
union sockaddr_storage_bsd bsd;
|
||||
struct sockaddr_storage addr = {0};
|
||||
uint32_t addrsize = sizeof(addr);
|
||||
BEGIN_CANCELLATION_POINT;
|
||||
|
||||
if (IsAsan() &&
|
||||
(!__asan_is_valid(buf, size) ||
|
||||
(opt_out_srcaddr &&
|
||||
(!__asan_is_valid(opt_inout_srcaddrsize,
|
||||
sizeof(*opt_inout_srcaddrsize)) ||
|
||||
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize))))) {
|
||||
if (IsAsan() && !__asan_is_valid(buf, size)) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
if (!IsBsd() || !opt_out_srcaddr) {
|
||||
rc = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
|
||||
opt_inout_srcaddrsize);
|
||||
} else {
|
||||
sz = sizeof(bsd);
|
||||
if ((rc = sys_recvfrom(fd, buf, size, flags, &bsd, &sz)) != -1) {
|
||||
sockaddr2linux(&bsd, sz, (void *)opt_out_srcaddr,
|
||||
opt_inout_srcaddrsize);
|
||||
}
|
||||
}
|
||||
rc = sys_recvfrom(fd, buf, size, flags, &addr, &addrsize);
|
||||
} else if (__isfdopen(fd)) {
|
||||
if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
|
||||
flags, opt_out_srcaddr, opt_inout_srcaddrsize);
|
||||
flags, &addr, &addrsize);
|
||||
} else if (__isfdkind(fd, kFdFile) && !opt_out_srcaddr) { /* socketpair */
|
||||
if (flags) {
|
||||
rc = einval();
|
||||
} else {
|
||||
if (!flags) {
|
||||
rc = sys_read_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, -1);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
} else {
|
||||
rc = enotsock();
|
||||
|
@ -92,6 +78,13 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
|||
rc = ebadf();
|
||||
}
|
||||
|
||||
if (rc != -1) {
|
||||
if (IsBsd()) {
|
||||
__convert_bsd_to_sockaddr(&addr);
|
||||
}
|
||||
__write_sockaddr(&addr, opt_out_srcaddr, opt_inout_srcaddrsize);
|
||||
}
|
||||
|
||||
END_CANCELLATION_POINT;
|
||||
DATATRACE("recvfrom(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd,
|
||||
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc);
|
||||
|
|
|
@ -27,10 +27,9 @@
|
|||
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||
uint32_t flags) {
|
||||
ssize_t rc;
|
||||
uint32_t sent = -666;
|
||||
uint32_t sent;
|
||||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||
flags, &overlapped, NULL)) {
|
||||
|
|
|
@ -31,7 +31,6 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
|
|||
uint32_t sent = 0;
|
||||
struct SockFd *sockfd;
|
||||
struct NtIovec iovnt[16];
|
||||
if (_check_interrupts(true, g_fds.p)) return -1;
|
||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), 0,
|
||||
flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2023 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,36 +16,60 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/strace.internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#include "libc/sock/struct/sockaddr.internal.h"
|
||||
#include "libc/sock/syscall_fd.internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/sock/struct/sockaddr6.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/af.h"
|
||||
|
||||
/**
|
||||
* Returns details about remote end of connected socket.
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @see getsockname()
|
||||
*/
|
||||
int getpeername(int fd, struct sockaddr *out_addr, uint32_t *out_addrsize) {
|
||||
int rc;
|
||||
if (!out_addr || !out_addrsize ||
|
||||
(IsAsan() && (!__asan_is_valid(out_addrsize, 4) ||
|
||||
!__asan_is_valid(out_addr, *out_addrsize)))) {
|
||||
rc = efault();
|
||||
} else if (!IsWindows()) {
|
||||
rc = sys_getpeername(fd, out_addr, out_addrsize);
|
||||
} else if (__isfdkind(fd, kFdSocket)) {
|
||||
rc = sys_getpeername_nt(&g_fds.p[fd], out_addr, out_addrsize);
|
||||
// computes byte length of socket address
|
||||
uint8_t __get_sockaddr_len(const struct sockaddr_storage *addr) {
|
||||
if (addr->ss_family == AF_INET) {
|
||||
return sizeof(struct sockaddr_in);
|
||||
} else if (addr->ss_family == AF_INET6) {
|
||||
return sizeof(struct sockaddr_in6);
|
||||
} else if (addr->ss_family == AF_UNIX) {
|
||||
struct sockaddr_un *sun = (struct sockaddr_un *)addr;
|
||||
return sizeof(sun->sun_family) +
|
||||
strnlen(sun->sun_path, sizeof(sun->sun_path)) + 1;
|
||||
} else {
|
||||
rc = ebadf();
|
||||
return sizeof(struct sockaddr_storage);
|
||||
}
|
||||
STRACE("getpeername(%d, [%s]) -> %d% lm", fd,
|
||||
DescribeSockaddr(out_addr, out_addrsize ? *out_addrsize : 0), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// converts bsd sockaddr to cosmo abi
|
||||
void __convert_bsd_to_sockaddr(struct sockaddr_storage *addr) {
|
||||
union {
|
||||
struct sockaddr cosmo;
|
||||
struct sockaddr_bsd bsd;
|
||||
} *pun = (void *)addr;
|
||||
pun->cosmo.sa_family = pun->bsd.sa_family;
|
||||
}
|
||||
|
||||
// converts cosmo sockaddr abi to bsd
|
||||
void __convert_sockaddr_to_bsd(struct sockaddr_storage *addr) {
|
||||
uint8_t len;
|
||||
union {
|
||||
struct sockaddr cosmo;
|
||||
struct sockaddr_bsd bsd;
|
||||
} *pun = (void *)addr;
|
||||
len = __get_sockaddr_len(addr);
|
||||
pun->bsd.sa_family = pun->cosmo.sa_family;
|
||||
pun->bsd.sa_len = len;
|
||||
}
|
||||
|
||||
// copies sockaddr from internal memory to user's buffer
|
||||
void __write_sockaddr(const struct sockaddr_storage *addr, void *out_addr,
|
||||
uint32_t *inout_addrsize) {
|
||||
if (!out_addr) return;
|
||||
if (!inout_addrsize) return;
|
||||
uint32_t insize = *inout_addrsize;
|
||||
if (insize) bzero(out_addr, insize);
|
||||
uint32_t outsize = __get_sockaddr_len(addr);
|
||||
uint32_t copysize = MIN(insize, outsize);
|
||||
if (copysize) memcpy(out_addr, addr, copysize);
|
||||
*inout_addrsize = outsize;
|
||||
}
|
|
@ -23,6 +23,8 @@
|
|||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// TODO(jart): DELETE
|
||||
|
||||
/**
|
||||
* Converts sockaddr (Linux/Windows) → sockaddr_bsd (XNU/BSD).
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "libc/sysv/consts/af.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
// TODO(jart): DELETE
|
||||
|
||||
/**
|
||||
* Converts sockaddr_bsd (XNU/BSD) → sockaddr (Linux/Windows).
|
||||
*/
|
||||
|
|
|
@ -44,6 +44,11 @@ union sockaddr_storage_linux {
|
|||
const char *DescribeSockaddr(char[128], const struct sockaddr *, size_t);
|
||||
#define DescribeSockaddr(sa, sz) DescribeSockaddr(alloca(128), sa, sz)
|
||||
|
||||
void __convert_bsd_to_sockaddr(struct sockaddr_storage *);
|
||||
void __convert_sockaddr_to_bsd(struct sockaddr_storage *);
|
||||
uint8_t __get_sockaddr_len(const struct sockaddr_storage *);
|
||||
void __write_sockaddr(const struct sockaddr_storage *, void *, uint32_t *);
|
||||
|
||||
int sockaddr2bsd(const void *, uint32_t, union sockaddr_storage_bsd *,
|
||||
uint32_t *);
|
||||
void sockaddr2linux(const union sockaddr_storage_bsd *, uint32_t,
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
#include "libc/calls/struct/fd.internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/nt/struct/overlapped.h"
|
||||
#include "libc/sock/struct/sockaddr.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int sys_accept_nt(struct Fd *, void *, uint32_t *, int) _Hide;
|
||||
int sys_accept_nt(struct Fd *, struct sockaddr_storage *, int) _Hide;
|
||||
int sys_bind_nt(struct Fd *, const void *, uint32_t);
|
||||
int sys_closesocket_nt(struct Fd *) _Hide;
|
||||
int sys_connect_nt(struct Fd *, const void *, uint32_t) _Hide;
|
||||
|
|
|
@ -40,7 +40,7 @@ textwindows int __wsablock(struct Fd *fd, struct NtOverlapped *overlapped,
|
|||
uint32_t *flags, bool restartable,
|
||||
uint32_t timeout) {
|
||||
int e, rc;
|
||||
uint32_t i, got = -666;
|
||||
uint32_t i, got;
|
||||
if (WSAGetLastError() != kNtErrorIoPending) {
|
||||
NTTRACE("sock i/o failed %s", strerror(errno));
|
||||
return __winsockerr();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue