mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-11 21:49:12 +00:00
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:
parent
a9ea949df8
commit
3e4fd4b0ad
271 changed files with 5706 additions and 1365 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
1506
libc/sock/epoll.c
Normal file
File diff suppressed because it is too large
Load diff
25
libc/sock/epoll.h
Normal file
25
libc/sock/epoll.h
Normal 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_ */
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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).
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
176
libc/sock/mapdoserrortoerrno.c
Normal file
176
libc/sock/mapdoserrortoerrno.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
114
libc/sock/select-nt.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
4
libc/sock/yoink.inc
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue