Cleanup socket code

This commit is contained in:
Justine Tunney 2021-02-05 23:45:34 -08:00
parent a91ba89d85
commit e06c90fafc
13 changed files with 108 additions and 94 deletions

View file

@ -22,20 +22,19 @@
#include "libc/nt/runtime.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_close_nt(int fd) {
textwindows int sys_close_nt(struct Fd *fd) {
bool32 ok;
if (g_fds.p[fd].kind == kFdFile &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeDisk) {
if (fd->kind == kFdFile && GetFileType(fd->handle) == kNtFileTypeDisk) {
/*
* Like Linux, closing a file on Windows doesn't guarantee it's
* immediately synced to disk. But unlike Linux, this could cause
* subsequent operations, e.g. unlink() to break w/ access error.
*/
FlushFileBuffers(g_fds.p[fd].handle);
FlushFileBuffers(fd->handle);
}
ok = CloseHandle(g_fds.p[fd].handle);
if (g_fds.p[fd].kind == kFdConsole) {
ok &= CloseHandle(g_fds.p[fd].extra);
ok = CloseHandle(fd->handle);
if (fd->kind == kFdConsole) {
ok &= CloseHandle(fd->extra);
}
return ok ? 0 : __winerr();
}

View file

@ -44,11 +44,11 @@ int close(int fd) {
} else if (!IsWindows()) {
rc = sys_close(fd);
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdSocket) {
rc = weaken(sys_closesocket_nt)(fd);
rc = weaken(sys_closesocket_nt)(g_fds.p + fd);
} else if (fd < g_fds.n &&
(g_fds.p[fd].kind == kFdFile || g_fds.p[fd].kind == kFdConsole ||
g_fds.p[fd].kind == kFdProcess)) {
rc = sys_close_nt(fd);
rc = sys_close_nt(g_fds.p + fd);
} else {
rc = ebadf();
}

View file

@ -1,17 +1,21 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/dce.h"
#include "libc/limits.h"
#include "libc/macros.h"
#include "libc/nt/struct/context.h"
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/nt/struct/systeminfo.h"
#include "libc/nt/struct/win32fileattributedata.h"
#include "libc/runtime/runtime.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/struct/utimbuf.h"
@ -23,12 +27,6 @@ COSMOPOLITAN_C_START_
#define kIoMotion ((const int8_t[3]){1, 0, 0})
struct NtContext;
struct NtWin32FileAttributeData;
struct ZiposHandle;
struct __darwin_siginfo;
struct __darwin_ucontext;
struct IoctlPtmGet {
int theduxfd;
int workerfd;
@ -56,8 +54,8 @@ struct Fd {
};
struct Fds {
size_t f; // lowest free slot
size_t n; // monotonic capacity
size_t f; /* lowest free slot */
size_t n; /* monotonic capacity */
struct Fd *p;
struct Fd __init_p[OPEN_MAX];
};
@ -75,7 +73,6 @@ hidden extern const struct NtSecurityAttributes kNtIsInheritable;
int __reservefd(void) hidden;
void __releasefd(int) hidden;
int __ensurefds(int) hidden;
void __removefd(int) hidden;
forceinline bool __isfdopen(int fd) {
return 0 <= fd && fd < g_fds.n && g_fds.p[fd].kind != kFdEmpty;
@ -231,7 +228,7 @@ bool32 sys_isatty_nt(int) hidden;
char *sys_getcwd_nt(char *, size_t) hidden;
i64 sys_lseek_nt(int, i64, int) hidden;
int sys_chdir_nt(const char *) hidden;
int sys_close_nt(int) hidden;
int sys_close_nt(struct Fd *) hidden;
int sys_dup_nt(int, int, int) hidden;
int sys_execve_nt(const char *, char *const[], char *const[]) hidden;
int sys_faccessat_nt(int, const char *, int, uint32_t) hidden;

View file

@ -1,27 +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/calls/internal.h"
#include "libc/macros.h"
void __removefd(int fd) {
if (__isfdopen(fd)) {
g_fds.p[fd].kind = kFdEmpty;
g_fds.f = MIN(g_fds.f, fd);
}
}

View file

@ -19,12 +19,6 @@
#include "libc/macros.h"
.source __FILE__
/ @fileoverview Address Sanitizer Thunks
/
/ This has tiny code size and reduces API surface area
/ since ASAN has the same stylistic hugeness as UBSAN.
/ We also guard all the functions, against reentrancy.
.rodata.cst4
__asan_option_detect_stack_use_after_return:
.long 0

View file

@ -336,7 +336,7 @@ int __sys_listen_nt(uint64_t, int);
int __sys_setsockopt_nt(uint64_t, int, int, const void *, int);
int __sys_shutdown_nt(uint64_t, int);
int __sys_select_nt(int, struct NtFdSet *, struct NtFdSet *, struct NtFdSet *,
struct NtTimeval *);
struct NtTimeval *);
uint64_t WSASocket(int af, int type, int protocol,
const struct NtWsaProtocolInfo *opt_lpProtocolInfo,
@ -393,8 +393,8 @@ int WSASendTo(uint64_t s, const struct NtIovec *lpBuffers,
const NtWsaOverlappedCompletionRoutine opt_lpCompletionRoutine)
paramsnonnull((2));
int WSAPoll(struct sys_pollfd_nt *inout_fdArray, uint32_t nfds, signed timeout_ms)
paramsnonnull();
int WSAPoll(struct sys_pollfd_nt *inout_fdArray, uint32_t nfds,
signed timeout_ms) paramsnonnull();
int WSARecv(uint64_t s, const struct NtIovec *out_lpBuffers,
uint32_t dwBufferCount, uint32_t *opt_out_lpNumberOfBytesRecvd,
@ -529,7 +529,7 @@ bool32 AcceptEx(int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength, uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength, uint32_t *out_lpdwBytesReceived,
struct NtOverlapped inout_lpOverlapped);
struct NtOverlapped *inout_lpOverlapped);
void GetAcceptExSockaddrs(
const void *lpOutputBuffer /*[recvsize+addrsize+addrlen]*/,

View file

@ -17,36 +17,50 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
#include "libc/nt/struct/pollfd.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_accept_nt(struct Fd *fd, void *addr, uint32_t *addrsize,
int flags) {
int flags) {
int64_t h;
int client;
uint32_t yes;
int client, oflags;
struct SockFd *sockfd, *sockfd2;
sockfd = (struct SockFd *)fd->extra;
for (;;) {
if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1, 1000)) continue;
if (!WSAPoll(&(struct sys_pollfd_nt){fd->handle, POLLIN}, 1, 1000))
continue;
if ((client = __reservefd()) == -1) return -1;
if ((h = WSAAccept(fd->handle, addr, (int32_t *)addrsize, 0, 0)) != -1) {
oflags = 0;
if (flags & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (flags & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
if (flags & SOCK_NONBLOCK) {
yes = 1;
if (__sys_ioctlsocket_nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) {
if (__sys_ioctlsocket_nt(g_fds.p[client].handle, FIONBIO,
(uint32_t[]){1}) == -1) {
__winsockerr();
__sys_closesocket_nt(g_fds.p[client].handle);
__releasefd(client);
return __winsockerr();
return -1;
}
}
sockfd2 = calloc(1, sizeof(struct SockFd));
sockfd2->family = sockfd->family;
sockfd2->type = sockfd->type;
sockfd2->protocol = sockfd->protocol;
sockfd2->event = WSACreateEvent();
g_fds.p[client].kind = kFdSocket;
g_fds.p[client].flags = flags;
g_fds.p[client].flags = oflags;
g_fds.p[client].handle = h;
g_fds.p[client].extra = (uintptr_t)sockfd2;
return client;
} else {
__releasefd(client);

View file

@ -16,21 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/mem/mem.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int sys_closesocket_nt(int fd) {
int rc;
if (!__isfdkind(fd, kFdSocket)) return ebadf();
if (__sys_closesocket_nt(g_fds.p[fd].handle) != -1) {
rc = 0;
/**
* Closes socket on Windows.
*
* This function should only be called by close().
*/
textwindows int sys_closesocket_nt(struct Fd *fd) {
struct SockFd *sockfd;
sockfd = (struct SockFd *)fd->extra;
WSACloseEvent(sockfd->event);
free(sockfd);
if (__sys_closesocket_nt(fd->handle) != -1) {
return 0;
} else {
rc = __winsockerr();
return __winsockerr();
}
__removefd(fd);
return rc;
}

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_SOCK_INTERNAL_H_
#include "libc/bits/bits.h"
#include "libc/calls/internal.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/select.h"
#include "libc/sock/sock.h"
@ -45,6 +46,22 @@ struct msghdr_bsd {
uint32_t msg_flags; /* « different type */
};
struct SockFd {
int family;
int type;
int protocol;
int64_t event;
bool32 (*AcceptEx)(int64_t sListenSocket, int64_t sAcceptSocket,
void *out_lpOutputBuffer /*[recvlen+local+remoteaddrlen]*/,
uint32_t dwReceiveDataLength,
uint32_t dwLocalAddressLength,
uint32_t dwRemoteAddressLength,
uint32_t *out_lpdwBytesReceived,
struct NtOverlapped *inout_lpOverlapped) __msabi;
};
hidden extern int64_t __iocp;
errno_t __dos2errno(uint32_t);
int32_t __sys_accept(int32_t, void *, uint32_t *, int) nodiscard hidden;
@ -85,7 +102,7 @@ int sys_listen_nt(struct Fd *, int) hidden;
int sys_connect_nt(struct Fd *, const void *, uint32_t) hidden;
int sys_bind_nt(struct Fd *, const void *, uint32_t);
int sys_accept_nt(struct Fd *, void *, uint32_t *, int) hidden;
int sys_closesocket_nt(int) hidden;
int sys_closesocket_nt(struct Fd *) hidden;
int sys_socket_nt(int, int, int) hidden;
int sys_select_nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
int sys_shutdown_nt(struct Fd *, int) hidden;

View file

@ -45,14 +45,14 @@ ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
ssize_t got;
if (!IsWindows()) {
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize);
opt_inout_srcaddrsize);
if (opt_out_srcaddr && IsBsd() && got != -1) {
sockaddr2linux(opt_out_srcaddr);
}
return got;
} else if (__isfdkind(fd, kFdSocket)) {
return sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags,
opt_out_srcaddr, opt_inout_srcaddrsize);
return sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
flags, opt_out_srcaddr, opt_inout_srcaddrsize);
} else {
return ebadf();
}

View file

@ -59,7 +59,7 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
}
} else if (__isfdkind(fd, kFdSocket)) {
return sys_sendto_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags,
opt_addr, addrsize);
opt_addr, addrsize);
} else {
return ebadf();
}

View file

@ -40,6 +40,14 @@ struct sockaddr_in { /* Linux+NT ABI */
uint8_t sin_zero[8];
};
struct sockaddr_storage {
union {
uint16_t ss_family;
intptr_t __ss_align;
char __ss_storage[128];
};
};
struct pollfd {
int32_t fd;
int16_t events;

View file

@ -17,32 +17,43 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
#define CLOEXEC 0x00080000
#define NONBLOCK 0x00000800
textwindows int sys_socket_nt(int family, int type, int protocol) {
int fd;
uint32_t yes;
int64_t h;
struct SockFd *sockfd;
int fd, oflags, truetype;
if ((fd = __reservefd()) == -1) return -1;
if ((g_fds.p[fd].handle = WSASocket(family, type & ~(CLOEXEC | NONBLOCK),
protocol, NULL, 0, 0)) != -1) {
if (type & NONBLOCK) {
yes = 1;
if (__sys_ioctlsocket_nt(g_fds.p[fd].handle, FIONBIO, &yes) == -1) {
__sys_closesocket_nt(g_fds.p[fd].handle);
truetype = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
if ((h = WSASocket(family, truetype, protocol, NULL, 0, 0)) != -1) {
oflags = 0;
if (type & SOCK_CLOEXEC) oflags |= O_CLOEXEC;
if (type & SOCK_NONBLOCK) oflags |= O_NONBLOCK;
if (type & SOCK_NONBLOCK) {
if (__sys_ioctlsocket_nt(h, FIONBIO, (uint32_t[1]){1}) == -1) {
__sys_closesocket_nt(h);
__releasefd(fd);
return __winsockerr();
}
}
sockfd = calloc(1, sizeof(struct SockFd));
sockfd->family = family;
sockfd->type = truetype;
sockfd->protocol = protocol;
sockfd->event = WSACreateEvent();
g_fds.p[fd].kind = kFdSocket;
g_fds.p[fd].flags = type & (CLOEXEC | NONBLOCK);
g_fds.p[fd].flags = oflags;
g_fds.p[fd].handle = h;
g_fds.p[fd].extra = (uintptr_t)sockfd;
return fd;
} else {
__releasefd(fd);
return __winsockerr();
}
}