Add epoll and do more release readiness changes

This change also pays off some of the remaining technical debt with
stdio, file descriptors, and memory managemnt polyfills.
This commit is contained in:
Justine Tunney 2020-11-28 12:01:51 -08:00
parent a9ea949df8
commit 3e4fd4b0ad
271 changed files with 5706 additions and 1365 deletions

View file

@ -22,6 +22,7 @@
#include "libc/nt/files.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/sock.h"
#include "libc/sysv/errfuns.h"
@ -31,20 +32,20 @@ textwindows int accept$nt(struct Fd *fd, void *addr, uint32_t *addrsize,
int client;
uint32_t yes;
assert(fd->kind == kFdSocket);
if ((client = createfd()) == -1) return -1;
if ((client = __getemptyfd()) == -1) return -1;
if ((g_fds.p[client].handle = WSAAccept(fd->handle, addr, (int32_t *)addrsize,
NULL, NULL)) != -1) {
if (flags & SOCK_NONBLOCK) {
yes = 1;
if (__ioctlsocket$nt(g_fds.p[client].handle, FIONBIO, &yes) == -1) {
__closesocket$nt(g_fds.p[client].handle);
return winsockerr();
return __winsockerr();
}
}
g_fds.p[client].kind = kFdSocket;
g_fds.p[client].flags = flags;
return client;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -17,11 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sysv/errfuns.h"
/**
* Creates client socket file descriptor for incoming connection.
@ -33,11 +29,5 @@
* @asyncsignalsafe
*/
int accept(int fd, void *out_addr, uint32_t *inout_addrsize) {
if (!IsWindows()) {
return accept$sysv(fd, out_addr, inout_addrsize);
} else if (isfdkind(fd, kFdSocket)) {
return accept$nt(&g_fds.p[fd], out_addr, inout_addrsize, 0);
} else {
return ebadf();
}
return accept4(fd, out_addr, inout_addrsize, 0);
}

View file

@ -32,13 +32,14 @@
* @param flags can have SOCK_{CLOEXEC,NONBLOCK}, which may apply to
* both the newly created socket and the server one
* @return client fd which needs close(), or -1 w/ errno
* @asyncsignalsafe
*/
int accept4(int fd, void *out_addr, uint32_t *inout_addrsize, int flags) {
if (!out_addr) return efault();
if (!inout_addrsize) return efault();
if (!IsWindows()) {
return accept4$sysv(fd, out_addr, inout_addrsize, flags);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return accept$nt(&g_fds.p[fd], out_addr, inout_addrsize, flags);
} else {
return ebadf();

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
/**
@ -38,6 +39,6 @@ textwindows int bind$nt(struct Fd *fd, const void *addr, uint32_t addrsize) {
if (__bind$nt(fd->handle, addr, addrsize) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -48,7 +48,7 @@ int bind(int fd, const void *addr, uint32_t addrsize) {
sockaddr2bsd(&addr2);
return bind$sysv(fd, &addr2, addrsize);
}
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return bind$nt(&g_fds.p[fd], addr, addrsize);
} else {
return ebadf();

View file

@ -21,16 +21,17 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int closesocket$nt(int fd) {
int rc;
if (!isfdkind(fd, kFdSocket)) return ebadf();
if (!__isfdkind(fd, kFdSocket)) return ebadf();
if (__closesocket$nt(g_fds.p[fd].handle) != -1) {
rc = 0;
} else {
rc = winsockerr();
rc = __winsockerr();
}
removefd(fd);
__removefd(fd);
return rc;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int connect$nt(struct Fd *fd, const void *addr, uint32_t addrsize) {

View file

@ -37,7 +37,7 @@ int connect(int fd, const void *addr, uint32_t addrsize) {
if (!addr) return efault();
if (!IsWindows()) {
return connect$sysv(fd, addr, addrsize);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return connect$nt(&g_fds.p[fd], addr, addrsize);
} else {
return ebadf();

1506
libc/sock/epoll.c Normal file

File diff suppressed because it is too large Load diff

25
libc/sock/epoll.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_WEPOLL_H_
#define COSMOPOLITAN_LIBC_SOCK_WEPOLL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct thatispacked epoll_event {
uint32_t events;
epoll_data_t data;
};
int epoll_create(int);
int epoll_create1(int);
int epoll_ctl(int, int, int, struct epoll_event *);
int epoll_wait(int, struct epoll_event *, int, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SOCK_WEPOLL_H_ */

View file

@ -17,10 +17,8 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/calls/internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"

View file

@ -22,6 +22,7 @@
#include "libc/dce.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int getpeername$nt(struct Fd *fd, void *out_addr,
@ -30,6 +31,6 @@ textwindows int getpeername$nt(struct Fd *fd, void *out_addr,
if (__getpeername$nt(fd->handle, out_addr, out_addrsize) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -31,7 +31,7 @@
int getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
if (!IsWindows()) {
return getpeername$sysv(fd, out_addr, out_addrsize);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return getpeername$nt(&g_fds.p[fd], out_addr, out_addrsize);
} else {
return ebadf();

View file

@ -22,6 +22,7 @@
#include "libc/dce.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int getsockname$nt(struct Fd *fd, void *out_addr,
@ -30,6 +31,6 @@ textwindows int getsockname$nt(struct Fd *fd, void *out_addr,
if (__getsockname$nt(fd->handle, out_addr, out_addrsize) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -31,7 +31,7 @@
int getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
if (!IsWindows()) {
return getsockname$sysv(fd, out_addr, out_addrsize);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return getsockname$nt(&g_fds.p[fd], out_addr, out_addrsize);
} else {
return ebadf();

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int getsockopt$nt(struct Fd *fd, int level, int optname,
@ -31,6 +32,6 @@ textwindows int getsockopt$nt(struct Fd *fd, int level, int optname,
-1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -39,7 +39,7 @@ int getsockopt(int fd, int level, int optname, void *out_opt_optval,
if (optname == -1) return 0; /* our sysvconsts definition */
if (!IsWindows()) {
return getsockopt$sysv(fd, level, optname, out_opt_optval, out_optlen);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return getsockopt$nt(&g_fds.p[fd], level, optname, out_opt_optval,
out_optlen);
} else {

View file

@ -3,6 +3,7 @@
#ifndef __STRICT_ANSI__
#include "libc/bits/bits.h"
#include "libc/nt/winsock.h"
#include "libc/sock/select.h"
#include "libc/sock/sock.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -48,6 +49,8 @@ struct msghdr$bsd {
uint32_t msg_flags; /* « different type */
};
errno_t MapDosErrorToErrno(uint32_t);
int32_t __accept$sysv(int32_t, void *, uint32_t *) nodiscard hidden;
int32_t __accept4$sysv(int32_t, void *, uint32_t *, int) nodiscard hidden;
int32_t __connect$sysv(int32_t, const void *, uint32_t) hidden;
@ -73,6 +76,11 @@ int64_t writev$sysv(int32_t, const struct iovec *, int32_t) hidden;
ssize_t recvfrom$sysv(int, void *, size_t, int, void *, uint32_t *) hidden;
ssize_t sendto$sysv(int, const void *, size_t, int, const void *,
uint32_t) hidden;
int32_t select$sysv(int32_t, fd_set *, fd_set *, fd_set *,
struct timeval *) hidden;
int32_t epoll_create$sysv(int32_t) hidden;
int32_t epoll_ctl$sysv(int32_t, int32_t, int32_t, void *) hidden;
int32_t epoll_wait$sysv(int32_t, void *, int32_t, int32_t) hidden;
int poll$nt(struct pollfd *, uint64_t, int32_t) hidden;
int getsockopt$nt(struct Fd *, int, int, void *, uint32_t *) hidden;
@ -84,8 +92,9 @@ int bind$nt(struct Fd *, const void *, uint32_t);
int accept$nt(struct Fd *, void *, uint32_t *, int) hidden;
int closesocket$nt(int) hidden;
int socket$nt(int, int, int) hidden;
int select$nt(int, fd_set *, fd_set *, fd_set *, struct timeval *) hidden;
size_t iovec2nt(struct iovec$nt[hasatleast 16], const struct iovec *,
size_t iovec2nt(struct NtIovec[hasatleast 16], const struct iovec *,
size_t) hidden;
ssize_t sendto$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *,
uint32_t) hidden;
@ -93,12 +102,14 @@ ssize_t recvfrom$nt(struct Fd *, const struct iovec *, size_t, uint32_t, void *,
uint32_t *) hidden;
void winsockinit(void) hidden;
int64_t winsockerr(void) nocallback hidden;
int64_t __winsockerr(void) nocallback hidden;
int fixupnewsockfd$sysv(int, int) hidden;
ssize_t WinSendRecv(int64_t, void *, size_t, uint32_t, struct sockaddr *,
uint32_t *, bool) hidden;
int64_t winsockblock(int64_t, unsigned, int64_t) hidden;
int close$epoll(int) hidden;
/**
* Converts sockaddr (Linux/Windows) sockaddr$bsd (XNU/BSD).
*/

View file

@ -29,7 +29,7 @@
* @return effective iovlen
* @see IOV_MAX
*/
textwindows size_t iovec2nt(struct iovec$nt iovnt[hasatleast 16],
textwindows size_t iovec2nt(struct NtIovec iovnt[hasatleast 16],
const struct iovec *iov, size_t iovlen) {
size_t i, limit;
for (limit = 0x7ffff000, i = 0; i < MIN(16, iovlen); ++i) {

View file

@ -21,6 +21,7 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/errfuns.h"
textwindows int listen$nt(struct Fd *fd, int backlog) {
@ -28,6 +29,6 @@ textwindows int listen$nt(struct Fd *fd, int backlog) {
if (__listen$nt(fd->handle, backlog) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -37,7 +37,7 @@
int listen(int fd, int backlog) {
if (!IsWindows()) {
return listen$sysv(fd, backlog);
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return listen$nt(&g_fds.p[fd], backlog);
} else {
return ebadf();

View file

@ -0,0 +1,176 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/errno.h"
#include "libc/nt/errors.h"
#include "libc/sock/sock.h"
/**
* Translates Windows error using superset of consts.sh.
*/
textwindows errno_t MapDosErrorToErrno(uint32_t error) {
switch (error) {
case kNtErrorModNotFound:
return ENOSYS;
case kNtErrorBadCommand:
return EACCES;
case kNtErrorBadLength:
return EACCES;
case kNtErrorBadNetpath:
return ENOENT;
case kNtErrorBadNetName:
return ENOENT;
case kNtErrorBadNetResp:
return ENETDOWN;
case kNtErrorBadPathname:
return ENOENT;
case kNtErrorCannotMake:
return EACCES;
case kNtErrorCommitmentLimit:
return ENOMEM;
case kNtErrorConnectionAborted:
return ECONNABORTED;
case kNtErrorConnectionActive:
return EISCONN;
case kNtErrorConnectionRefused:
return ECONNREFUSED;
case kNtErrorCrc:
return EACCES;
case kNtErrorDirNotEmpty:
return ENOTEMPTY;
case kNtErrorDupName:
return EADDRINUSE;
case kNtErrorFilenameExcedRange:
return ENOENT;
case kNtErrorFileNotFound:
return ENOENT;
case kNtErrorGenFailure:
return EACCES;
case kNtErrorGracefulDisconnect:
return EPIPE;
case kNtErrorHostDown:
return EHOSTUNREACH;
case kNtErrorHostUnreachable:
return EHOSTUNREACH;
case kNtErrorInsufficientBuffer:
return EFAULT;
case kNtErrorInvalidAddress:
return EADDRNOTAVAIL;
case kNtErrorInvalidFunction:
return EINVAL;
case kNtErrorInvalidNetname:
return EADDRNOTAVAIL;
case kNtErrorInvalidUserBuffer:
return EMSGSIZE;
case kNtErrorIoPending:
return EINPROGRESS;
case kNtErrorLockViolation:
return EACCES;
case kNtErrorMoreData:
return EMSGSIZE;
case kNtErrorNetnameDeleted:
return ECONNABORTED;
case kNtErrorNetworkAccessDenied:
return EACCES;
case kNtErrorNetworkBusy:
return ENETDOWN;
case kNtErrorNetworkUnreachable:
return ENETUNREACH;
case kNtErrorNoaccess:
return EFAULT;
case kNtErrorNonpagedSystemResources:
return ENOMEM;
case kNtErrorNotEnoughMemory:
return ENOMEM;
case kNtErrorNotEnoughQuota:
return ENOMEM;
case kNtErrorNotFound:
return ENOENT;
case kNtErrorNotLocked:
return EACCES;
case kNtErrorNotReady:
return EACCES;
case kNtErrorNotSupported:
return ENOTSUP;
case kNtErrorNoMoreFiles:
return ENOENT;
case kNtErrorNoSystemResources:
return ENOMEM;
case kNtErrorOperationAborted:
return EINTR;
case kNtErrorOutOfPaper:
return EACCES;
case kNtErrorPagedSystemResources:
return ENOMEM;
case kNtErrorPagefileQuota:
return ENOMEM;
case kNtErrorPathNotFound:
return ENOENT;
case kNtErrorPipeNotConnected:
return EPIPE;
case kNtErrorPortUnreachable:
return ECONNRESET;
case kNtErrorProtocolUnreachable:
return ENETUNREACH;
case kNtErrorRemNotList:
return ECONNREFUSED;
case kNtErrorRequestAborted:
return EINTR;
case kNtErrorReqNotAccep:
return EWOULDBLOCK;
case kNtErrorSectorNotFound:
return EACCES;
case kNtErrorSemTimeout:
return ETIMEDOUT;
case kNtErrorSharingViolation:
return EACCES;
case kNtErrorTooManyNames:
return ENOMEM;
case kNtErrorUnexpNetErr:
return ECONNABORTED;
case kNtErrorWorkingSetQuota:
return ENOMEM;
case kNtErrorWriteProtect:
return EACCES;
case kNtErrorWrongDisk:
return EACCES;
case WSAEACCES:
return EACCES;
case WSAEDISCON:
return EPIPE;
case WSAEFAULT:
return EFAULT;
case WSAEINPROGRESS:
return EBUSY;
case WSAEINVAL:
return EINVAL;
case WSAEPROCLIM:
return ENOMEM;
case WSAESHUTDOWN:
return EPIPE;
case WSANOTINITIALISED:
return ENETDOWN;
case WSASYSNOTREADY:
return ENETDOWN;
case WSAVERNOTSUPPORTED:
return ENOSYS;
default:
return error;
}
}

View file

@ -21,6 +21,7 @@
#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/poll.h"
#include "libc/sysv/errfuns.h"
@ -30,7 +31,7 @@ textwindows int poll$nt(struct pollfd *fds, uint64_t nfds, int32_t timeout_ms) {
struct pollfd$nt ntfds[64];
if (nfds > 64) return einval();
for (i = 0; i < nfds; ++i) {
if (!isfdkind(fds[i].fd, kFdSocket)) return ebadf();
if (!__isfdkind(fds[i].fd, kFdSocket)) return ebadf();
ntfds[i].handle = g_fds.p[fds[i].fd].handle;
ntfds[i].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
}
@ -40,6 +41,6 @@ textwindows int poll$nt(struct pollfd *fds, uint64_t nfds, int32_t timeout_ms) {
}
return got;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -20,6 +20,7 @@
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
/**
* Performs recv(), recvfrom(), or readv() on Windows NT.
@ -32,12 +33,12 @@ textwindows ssize_t recvfrom$nt(struct Fd *fd, const struct iovec *iov,
void *opt_out_srcaddr,
uint32_t *opt_inout_srcaddrsize) {
uint32_t got;
struct iovec$nt iovnt[16];
struct NtIovec iovnt[16];
got = 0;
if (WSARecvFrom(fd->handle, iovnt, iovec2nt(iovnt, iov, iovlen), &got, &flags,
opt_out_srcaddr, opt_inout_srcaddrsize, NULL, NULL) != -1) {
return got;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -51,7 +51,7 @@ ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
sockaddr2linux(opt_out_srcaddr);
}
return got;
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return recvfrom$nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags,
opt_out_srcaddr, opt_inout_srcaddrsize);
} else {

114
libc/sock/select-nt.c Normal file
View file

@ -0,0 +1,114 @@
/*-*- 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
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/popcnt.h"
#include "libc/calls/internal.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
static int GetFdsPopcnt(int nfds, fd_set *fds) {
int i, n = 0;
if (fds) {
for (i = 0; i < nfds; ++i) {
n += popcnt(fds->fds_bits[i]);
}
}
return n;
}
static int FindFdByHandle(int nfds, int64_t h) {
int i, n;
n = MIN(nfds << 3, g_fds.n);
for (i = 0; i < n; ++i) {
if (h == g_fds.p[i].handle && g_fds.p[i].kind != kFdEmpty) {
return i;
}
}
return -1;
}
static struct NtFdSet *FdSetToNtFdSet(int nfds, fd_set *fds) {
int i, j, k, n, m, fd;
struct NtFdSet *ntfds;
if (fds && (n = GetFdsPopcnt(nfds, fds))) {
m = MIN(n, ARRAYLEN(ntfds->fd_array));
ntfds = malloc(sizeof(struct NtFdSet));
for (k = i = 0; i < nfds; ++i) {
if (fds->fds_bits[i]) {
for (j = 0; j < 64 && k < m; ++j) {
if ((fds->fds_bits[i] & (1ul << j)) && i * 8 + j < g_fds.n) {
ntfds->fd_array[k++] = g_fds.p[i * 8 + j].handle;
}
}
}
}
ntfds->fd_count = m;
return ntfds;
} else {
return NULL;
}
}
static void NtFdSetToFdSet(int nfds, fd_set *fds, struct NtFdSet *ntfds) {
int i, fd;
if (ntfds) {
for (i = 0; i < nfds; ++i) {
fds->fds_bits[i] = 0;
}
for (i = 0; i < ntfds->fd_count; ++i) {
if ((fd = FindFdByHandle(nfds, ntfds->fd_array[i])) != -1) {
fds->fds_bits[fd >> 3] |= 1ul << (fd & 7);
}
}
}
}
static struct NtTimeval *TimevalToNtTimeval(struct timeval *tv,
struct NtTimeval *nttv) {
if (tv) {
nttv->tv_sec = tv->tv_sec;
nttv->tv_usec = tv->tv_usec;
return nttv;
} else {
return NULL;
}
}
int select$nt(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout) {
int n, rc;
struct NtTimeval nttimeout, *nttimeoutp;
struct NtFdSet *ntreadfds, *ntwritefds, *ntexceptfds;
nfds = MIN(ARRAYLEN(readfds->fds_bits), ROUNDUP(nfds, 8)) >> 3;
ntreadfds = FdSetToNtFdSet(nfds, readfds);
ntwritefds = FdSetToNtFdSet(nfds, writefds);
ntexceptfds = FdSetToNtFdSet(nfds, exceptfds);
nttimeoutp = TimevalToNtTimeval(timeout, &nttimeout);
rc = __select$nt(0, ntreadfds, ntwritefds, ntexceptfds, nttimeoutp);
NtFdSetToFdSet(nfds, readfds, ntreadfds);
NtFdSetToFdSet(nfds, writefds, ntwritefds);
NtFdSetToFdSet(nfds, exceptfds, ntexceptfds);
free(ntreadfds);
free(ntwritefds);
free(ntexceptfds);
return rc;
}

View file

@ -18,14 +18,19 @@
02110-1301 USA
*/
#include "libc/calls/struct/timeval.h"
#include "libc/sock/select.internal.h"
#include "libc/dce.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
/**
* Does what poll() does except with a complicated bitset API.
* @note windows nt is limited to first 64 socket descriptors
*/
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout) {
/* TODO(jart): Windows */
return select$sysv(nfds, readfds, writefds, exceptfds, timeout);
if (!IsWindows()) {
return select$sysv(nfds, readfds, writefds, exceptfds, timeout);
} else {
return select$nt(nfds, readfds, writefds, exceptfds, timeout);
}
}

View file

@ -1,11 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_
#define COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_
#include "libc/sock/select.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int32_t select$sysv(int32_t, fd_set *, fd_set *, fd_set *, struct timeval *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SOCK_SELECT_INTERNAL_H_ */

View file

@ -31,7 +31,8 @@ static textwindows ssize_t sendfile$linux2nt(int outfd, int infd,
size_t uptobytes) {
struct NtOverlapped Overlapped;
struct NtOverlapped *lpOverlapped;
if (!isfdkind(outfd, kFdSocket) || !isfdkind(outfd, kFdFile)) return ebadf();
if (!__isfdkind(outfd, kFdSocket) || !__isfdkind(outfd, kFdFile))
return ebadf();
if (inout_opt_inoffset) {
memset(&Overlapped, 0, sizeof(Overlapped));
Overlapped.Pointer = (void *)(intptr_t)(*inout_opt_inoffset);
@ -44,7 +45,7 @@ static textwindows ssize_t sendfile$linux2nt(int outfd, int infd,
lpOverlapped, NULL, 0)) {
return uptobytes;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/yoink.inc"
#include "libc/sysv/consts/fileno.h"
/**
@ -34,11 +35,11 @@ textwindows ssize_t sendto$nt(struct Fd *fd, const struct iovec *iov,
size_t iovlen, uint32_t flags, void *opt_in_addr,
uint32_t in_addrsize) {
uint32_t sent;
struct iovec$nt iovnt[16];
struct NtIovec iovnt[16];
if (WSASendTo(fd->handle, iovnt, iovec2nt(iovnt, iov, iovlen), &sent, flags,
opt_in_addr, in_addrsize, NULL, NULL) != -1) {
return sent;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -58,7 +58,7 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
sockaddr2bsd(&addr2);
return sendto$sysv(fd, buf, size, flags, &addr2, addrsize);
}
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return sendto$nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1, flags,
opt_addr, addrsize);
} else {

View file

@ -39,7 +39,7 @@ static textwindows int setsockopt$nt(struct Fd *fd, int level, int optname,
if (__setsockopt$nt(fd->handle, level, optname, optval, optlen) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}
@ -70,7 +70,7 @@ int setsockopt(int fd, int level, int optname, const void *optval,
}
} while (setsockopt_polyfill(&optname));
return -1;
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return setsockopt$nt(&g_fds.p[fd], level, optname, optval, optlen);
} else {
return ebadf();

View file

@ -28,7 +28,7 @@ static int shutdown$nt(struct Fd *fd, int how) {
if (__shutdown$nt(fd->handle, how) != -1) {
return 0;
} else {
return winsockerr();
return __winsockerr();
}
}
@ -48,7 +48,7 @@ int shutdown(int fd, int how) {
/* TODO(jart): What's wrong with XNU shutdown()? */
return 0;
}
} else if (isfdkind(fd, kFdSocket)) {
} else if (__isfdkind(fd, kFdSocket)) {
return shutdown$nt(&g_fds.p[fd], how);
} else {
return ebadf();

View file

@ -19,6 +19,7 @@ LIBC_SOCK_A_CHECKS = \
$(LIBC_SOCK_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_SOCK_A_DIRECTDEPS = \
LIBC_BITS \
LIBC_CALLS \
LIBC_CONV \
LIBC_FMT \
@ -27,6 +28,8 @@ LIBC_SOCK_A_DIRECTDEPS = \
LIBC_STDIO \
LIBC_STUBS \
LIBC_NT_KERNELBASE \
LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_NT_WS2_32 \
LIBC_NT_MSWSOCK \
LIBC_NEXGEN32E \

View file

@ -20,31 +20,31 @@
#include "libc/calls/internal.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/sock.h"
STATIC_YOINK("closesocket$nt");
STATIC_YOINK("kNtWsaData");
STATIC_YOINK("recvfrom$nt");
STATIC_YOINK("sendto$nt");
#define CLOEXEC 0x00080000
#define NONBLOCK 0x00000800
textwindows int socket$nt(int family, int type, int protocol) {
int fd;
if ((fd = createfd()) == -1) return -1;
if ((g_fds.p[fd].handle =
WSASocket(family, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), protocol,
NULL, 0, (type & SOCK_CLOEXEC))) != -1) {
if (type & SOCK_NONBLOCK) {
uint32_t yes = 1;
uint32_t yes;
if ((fd = __getemptyfd()) == -1) return -1;
if ((g_fds.p[fd].handle = WSASocket(family, type & ~(CLOEXEC | NONBLOCK),
protocol, NULL, 0, (type & CLOEXEC))) !=
-1) {
if (type & NONBLOCK) {
yes = 1;
if (__ioctlsocket$nt(g_fds.p[fd].handle, FIONBIO, &yes) == -1) {
__closesocket$nt(g_fds.p[fd].handle);
return winsockerr();
return __winsockerr();
}
}
g_fds.p[fd].kind = kFdSocket;
g_fds.p[fd].flags = type;
g_fds.p[fd].flags = type & (CLOEXEC | NONBLOCK);
return fd;
} else {
return winsockerr();
return __winsockerr();
}
}

View file

@ -28,7 +28,7 @@ textwindows int64_t winsockblock(int64_t fh, unsigned eventbit, int64_t rc) {
int64_t eh;
struct NtWsaNetworkEvents ev;
if (rc != -1) return rc;
if (WSAGetLastError() != EWOULDBLOCK) return winsockerr();
if (WSAGetLastError() != EWOULDBLOCK) return __winsockerr();
eh = WSACreateEvent();
memset(&ev, 0, sizeof(ev));
if (WSAEventSelect(fh, eh, 1u << eventbit) != -1 &&
@ -39,7 +39,7 @@ textwindows int64_t winsockblock(int64_t fh, unsigned eventbit, int64_t rc) {
errno = ev.iErrorCode[eventbit];
}
} else {
winsockerr();
__winsockerr();
}
WSACloseEvent(eh);
return rc;

View file

@ -24,7 +24,7 @@
/**
* Error return path for winsock wrappers.
*/
textwindows int64_t winsockerr(void) {
errno = WSAGetLastError();
textwindows int64_t __winsockerr(void) {
errno = MapDosErrorToErrno(WSAGetLastError());
return -1;
}

4
libc/sock/yoink.inc Normal file
View file

@ -0,0 +1,4 @@
STATIC_YOINK("kNtWsaData"); // for winmain
STATIC_YOINK("closesocket$nt"); // for close
STATIC_YOINK("recvfrom$nt"); // for readv
STATIC_YOINK("sendto$nt"); // for writev