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:
Justine Tunney 2023-07-23 16:31:10 -07:00
parent ac92f25296
commit 0ba3199915
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
49 changed files with 347 additions and 352 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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)) {

View file

@ -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)) {

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,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;
}

View file

@ -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).
*/

View file

@ -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).
*/

View file

@ -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,

View file

@ -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;

View file

@ -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();