add lwIP TCP/IP stack as a runtime driver, native socket syscalls, SysGetMemoryStatus replacing CatchAllDebugBucket, fix timeGetTime to return milliseconds, fix SysSleep to interpret argument as milliseconds, SysGetTick now returns microseconds, harden all syscalls against bad user pointers with CopyFromUser/CopyToUser/MmProbeUser throughout, add networking test apps, port-forward 8080 in runa.bat, split LWIP_DRIVER_CFLAGS, add settings.ini to deploy, remove ethernet.c stub

This commit is contained in:
maksw committed 2026-05-22 18:54:53 +02:00
1 parent 18b4dd0f61
commit df13b8056c
365 files changed
+143263 -1362

No files matched your search

+131
View File
@@ -18,6 +18,21 @@
#ifdef ENOSYS
#undef ENOSYS
#endif
#ifdef EWOULDBLOCK
#undef EWOULDBLOCK
#endif
#ifdef EINPROGRESS
#undef EINPROGRESS
#endif
#ifdef ETIMEDOUT
#undef ETIMEDOUT
#endif
#ifdef ECONNRESET
#undef ECONNRESET
#endif
#ifdef ENOTSOCK
#undef ENOTSOCK
#endif
extern int errno; // defined in posix_fd.c; single global in v1
#define EPERM 1
@@ -37,7 +52,12 @@ extern int errno; // defined in posix_fd.c; single global in v1
#define ENOSPC 28
#define ERANGE 34
#define EAGAIN 35
#define EWOULDBLOCK EAGAIN
#define ENOSYS 38
#define ENOTSOCK 88
#define EINPROGRESS 115
#define ETIMEDOUT 116
#define ECONNRESET 104
// ---------------------------------------------------------------------------
// open() flags
@@ -64,6 +84,117 @@ typedef int32_t off_t;
typedef uint32_t mode_t;
typedef int64_t ssize_t;
// ---------------------------------------------------------------------------
// Sockets
// ---------------------------------------------------------------------------
typedef uint16_t sa_family_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
typedef uint32_t socklen_t;
#define AF_INET 2
#define PF_INET AF_INET
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#define SOL_SOCKET 1
#define SO_RCVTIMEO 1
#define SO_SNDTIMEO 2
#define SO_NONBLOCK 3
#define INADDR_ANY ((in_addr_t)0x00000000u)
#define INADDR_NONE ((in_addr_t)0xFFFFFFFFu)
struct in_addr {
in_addr_t s_addr;
};
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct hostent {
char* h_name;
char** h_aliases;
int h_addrtype;
int h_length;
char** h_addr_list;
};
#define h_addr h_addr_list[0]
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr* ai_addr;
char* ai_canonname;
struct addrinfo* ai_next;
};
#define AI_PASSIVE 0x0001
struct pollfd {
int fd;
short events;
short revents;
};
#define POLLIN 0x0001
#define POLLOUT 0x0002
#define POLLERR 0x0004
#define POLLHUP 0x0008
#define POLLNVAL 0x0010
typedef unsigned long nfds_t;
typedef struct timeval {
long tv_sec;
long tv_usec;
} timeval;
__declspec(dllexport) uint16_t htons(uint16_t x);
__declspec(dllexport) uint16_t ntohs(uint16_t x);
__declspec(dllexport) uint32_t htonl(uint32_t x);
__declspec(dllexport) uint32_t ntohl(uint32_t x);
__declspec(dllexport) in_addr_t inet_addr(const char* text);
__declspec(dllexport) char* inet_ntoa(struct in_addr in);
__declspec(dllexport) int socket(int domain, int type, int protocol);
__declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t addrlen);
__declspec(dllexport) int listen(int fd, int backlog);
__declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrlen);
__declspec(dllexport) int connect(int fd, const struct sockaddr* addr, socklen_t addrlen);
__declspec(dllexport) ssize_t send(int fd, const void* buf, size_t len, int flags);
__declspec(dllexport) ssize_t recv(int fd, void* buf, size_t len, int flags);
__declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int flags, const struct sockaddr* dest, socklen_t destlen);
__declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags, struct sockaddr* src, socklen_t* srclen);
__declspec(dllexport) int shutdown(int fd, int how);
__declspec(dllexport) int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen);
__declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optval, socklen_t* optlen);
__declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout);
__declspec(dllexport) struct hostent* gethostbyname(const char* name);
__declspec(dllexport) int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res);
__declspec(dllexport) void freeaddrinfo(struct addrinfo* res);
// ---------------------------------------------------------------------------
// pthread types
// ---------------------------------------------------------------------------
+19
View File
@@ -5,6 +5,25 @@
int errno = 0;
int PosixStatusToErrno(uint32_t s) {
switch (s) {
case 0x0000: return 0; // STATUS_SUCCESS
case 0x0002: return ENOSYS; // STATUS_NOT_SUPPORTED
case 0x0003: return EAGAIN; // STATUS_TIMEOUT / would block
case 0x0010: return EINVAL; // STATUS_INVALID_PARAMETER
case 0x0011: return EBADF; // STATUS_INVALID_HANDLE
case 0x0012: return ERANGE; // STATUS_BUFFER_TOO_SMALL
case 0x0020: return ENOMEM; // STATUS_NO_MEMORY
case 0x0021: return EACCES; // STATUS_ACCESS_DENIED
case 0x0022: return ENOENT; // STATUS_NOT_FOUND
case 0x0023: return EEXIST; // STATUS_ALREADY_EXISTS
case 0x0030: return ECONNRESET; // STATUS_OBJECT_DEAD
case 0x0031: return EAGAIN; // STATUS_QUEUE_FULL
case 0x0032: return EAGAIN; // STATUS_QUEUE_EMPTY
default: return EIO;
}
}
static FD_ENTRY gFdTable[FD_TABLE_PIDS][FD_MAX];
__declspec(dllexport) void PosixFdInit(void) {
+3
View File
@@ -10,6 +10,7 @@ typedef enum {
FD_CONSOLE_W, // fd 1, 2 - writes via SysWriteConsole
FD_DEVNULL, // /dev/null
FD_DEVZERO, // /dev/zero
FD_SOCKET, // kernel socket handle
} FD_TYPE;
typedef struct {
@@ -32,3 +33,5 @@ __declspec(dllexport) FD_ENTRY* FdGet(uint32_t pid, int fd);
// Release an fd slot (does NOT close the kernel handle).
__declspec(dllexport) void FdFree(uint32_t pid, int fd);
int PosixStatusToErrno(uint32_t s);
+18 -22
View File
@@ -6,22 +6,6 @@
#include "posix_fd.h"
#include "posix_path.h"
// KSTATUS -> errno
static int KsToErrno(uint32_t s) {
switch (s) {
case 0x0000: return 0; // STATUS_SUCCESS
case 0x0022: return ENOENT; // STATUS_NOT_FOUND
case 0x0021: return EACCES; // STATUS_ACCESS_DENIED
case 0x0020: return ENOMEM; // STATUS_NO_MEMORY
case 0x0023: return EEXIST; // STATUS_ALREADY_EXISTS
case 0x0010: return EINVAL; // STATUS_INVALID_PARAMETER
case 0x0012: return ERANGE; // STATUS_BUFFER_TOO_SMALL
case 0x0002: return ENOSYS; // STATUS_NOT_SUPPORTED
case 0x0031: return EAGAIN; // STATUS_QUEUE_FULL
default: return EIO;
}
}
__declspec(dllexport) void clearscreen(void) {
SysScreenClear(0x00000000);
}
@@ -55,7 +39,7 @@ __declspec(dllexport) int open(const char* path, int flags, ...) {
} else {
s = SysOpenFile(p, &kh);
}
if (s != 0) { errno = KsToErrno(s); return -1; }
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
if ((flags & O_TRUNC) && (flags & O_WRONLY))
SysTruncateFile(kh, 0);
@@ -92,7 +76,13 @@ __declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
case FD_FILE: {
size_t got = 0;
uint32_t s = SysReadFile(e->KHandle, buf, count, &got);
if (s != 0 && got == 0) { errno = KsToErrno(s); return -1; }
if (s != 0 && got == 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
case FD_SOCKET: {
size_t got = 0;
uint32_t s = SysRecv(e->KHandle, buf, count, 0, &got);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
default:
@@ -117,9 +107,15 @@ __declspec(dllexport) ssize_t write(int fd, const void* buf, size_t count) {
case FD_FILE: {
size_t written = 0;
uint32_t s = SysWriteFile(e->KHandle, buf, count, &written);
if (s != 0 && written == 0) { errno = KsToErrno(s); return -1; }
if (s != 0 && written == 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)written;
}
case FD_SOCKET: {
size_t sent = 0;
uint32_t s = SysSend(e->KHandle, buf, count, 0, &sent);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
default:
errno = EBADF;
return -1;
@@ -130,7 +126,7 @@ __declspec(dllexport) int close(int fd) {
uint32_t pid = SysGetCurrentPid();
FD_ENTRY* e = FdGet(pid, fd);
if (!e) return -1;
if (e->Type == FD_FILE)
if (e->Type == FD_FILE || e->Type == FD_SOCKET)
SysCloseHandle(e->KHandle);
FdFree(pid, fd);
return 0;
@@ -148,7 +144,7 @@ __declspec(dllexport) int unlink(const char* path) {
}
uint32_t s = SysDeleteFile(p);
if (s != 0) { errno = KsToErrno(s); return -1; }
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
@@ -182,6 +178,6 @@ __declspec(dllexport) off_t lseek(int fd, off_t offset, int whence) {
if (target < 0 || target > 0x7FFFFFFFLL) { errno = EINVAL; return -1; }
uint32_t s = SysSeekFile(e->KHandle, (uint64_t)target);
if (s != 0) { errno = KsToErrno(s); return -1; }
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (off_t)target;
}
+472
View File
@@ -0,0 +1,472 @@
// posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets.
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <syscall.h>
#include "posix.h"
#include "posix_fd.h"
static uint16_t bswap16(uint16_t x) {
return (uint16_t)((x << 8) | (x >> 8));
}
static uint32_t bswap32(uint32_t x) {
return ((x & 0x000000FFu) << 24) |
((x & 0x0000FF00u) << 8) |
((x & 0x00FF0000u) >> 8) |
((x & 0xFF000000u) >> 24);
}
__declspec(dllexport) uint16_t htons(uint16_t x) { return bswap16(x); }
__declspec(dllexport) uint16_t ntohs(uint16_t x) { return bswap16(x); }
__declspec(dllexport) uint32_t htonl(uint32_t x) { return bswap32(x); }
__declspec(dllexport) uint32_t ntohl(uint32_t x) { return bswap32(x); }
static int ParseByte(const char** p, uint8_t* out) {
const char* s = *p;
if (*s < '0' || *s > '9') return 0;
unsigned v = 0;
while (*s >= '0' && *s <= '9') {
v = v * 10 + (unsigned)(*s - '0');
if (v > 255) return 0;
s++;
}
*out = (uint8_t)v;
*p = s;
return 1;
}
static int ParseIpv4Bytes(const char* text, uint8_t out[4]) {
const char* p = text;
for (int i = 0; i < 4; i++) {
if (!ParseByte(&p, &out[i])) return 0;
if (i != 3) {
if (*p != '.') return 0;
p++;
}
}
return *p == '\0';
}
__declspec(dllexport) in_addr_t inet_addr(const char* text) {
uint8_t b[4];
if (!text || !ParseIpv4Bytes(text, b)) return INADDR_NONE;
in_addr_t out = 0;
uint8_t* p = (uint8_t*)&out;
p[0] = b[0]; p[1] = b[1]; p[2] = b[2]; p[3] = b[3];
return out;
}
__declspec(dllexport) char* inet_ntoa(struct in_addr in) {
static char buf[16];
const uint8_t* p = (const uint8_t*)&in.s_addr;
// Tiny decimal formatter, avoiding stdio dependency.
char* w = buf;
for (int i = 0; i < 4; i++) {
unsigned v = p[i];
if (v >= 100) { *w++ = (char)('0' + v / 100); v %= 100; *w++ = (char)('0' + v / 10); *w++ = (char)('0' + v % 10); }
else if (v >= 10) { *w++ = (char)('0' + v / 10); *w++ = (char)('0' + v % 10); }
else { *w++ = (char)('0' + v); }
if (i != 3) *w++ = '.';
}
*w = '\0';
return buf;
}
static int SockAddrToSys(const struct sockaddr* addr, socklen_t addrlen, SYS_SOCKET_ADDRESS_IPV4* out) {
if (!addr || !out || addrlen < sizeof(struct sockaddr_in)) { errno = EINVAL; return -1; }
const struct sockaddr_in* in = (const struct sockaddr_in*)addr;
if (in->sin_family != AF_INET) { errno = EINVAL; return -1; }
memset(out, 0, sizeof(*out));
out->Family = SYS_AF_INET;
out->Port = ntohs(in->sin_port);
const uint8_t* p = (const uint8_t*)&in->sin_addr.s_addr;
out->Address[0] = p[0];
out->Address[1] = p[1];
out->Address[2] = p[2];
out->Address[3] = p[3];
return 0;
}
static void SysToSockAddr(const SYS_SOCKET_ADDRESS_IPV4* in, struct sockaddr* addr, socklen_t* addrlen) {
if (!addr || !addrlen) return;
if (*addrlen < sizeof(struct sockaddr_in)) {
*addrlen = sizeof(struct sockaddr_in);
return;
}
struct sockaddr_in* out = (struct sockaddr_in*)addr;
memset(out, 0, sizeof(*out));
out->sin_family = AF_INET;
out->sin_port = htons(in->Port);
uint8_t* p = (uint8_t*)&out->sin_addr.s_addr;
p[0] = in->Address[0];
p[1] = in->Address[1];
p[2] = in->Address[2];
p[3] = in->Address[3];
*addrlen = sizeof(struct sockaddr_in);
}
static FD_ENTRY* SocketFdGet(int fd) {
FD_ENTRY* e = FdGet(SysGetCurrentPid(), fd);
if (!e) return (FD_ENTRY*)0;
if (e->Type != FD_SOCKET) { errno = ENOTSOCK; return (FD_ENTRY*)0; }
return e;
}
__declspec(dllexport) int socket(int domain, int type, int protocol) {
uint32_t kh = 0;
uint32_t s = SysSocket((uint32_t)domain, (uint32_t)type, (uint32_t)protocol, &kh);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
int fd = FdAlloc(SysGetCurrentPid(), FD_SOCKET, kh);
if (fd < 0) {
SysCloseHandle(kh);
return -1;
}
return fd;
}
__declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t addrlen) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 a;
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
uint32_t s = SysBind(e->KHandle, &a, sizeof(a));
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
__declspec(dllexport) int listen(int fd, int backlog) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t s = SysListen(e->KHandle, backlog < 0 ? 0u : (uint32_t)backlog);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
__declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrlen) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 remote;
size_t remoteSize = sizeof(remote);
uint32_t kh = 0;
uint32_t s = SysAccept(e->KHandle, addr ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)0,
addr ? &remoteSize : (size_t*)0, &kh);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
int outfd = FdAlloc(SysGetCurrentPid(), FD_SOCKET, kh);
if (outfd < 0) {
SysCloseHandle(kh);
return -1;
}
if (addr) SysToSockAddr(&remote, addr, addrlen);
return outfd;
}
__declspec(dllexport) int connect(int fd, const struct sockaddr* addr, socklen_t addrlen) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 a;
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
uint32_t s = SysConnect(e->KHandle, &a, sizeof(a));
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
__declspec(dllexport) ssize_t send(int fd, const void* buf, size_t len, int flags) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
size_t sent = 0;
uint32_t s = SysSend(e->KHandle, buf, len, (uint32_t)flags, &sent);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
__declspec(dllexport) ssize_t recv(int fd, void* buf, size_t len, int flags) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
size_t got = 0;
uint32_t s = SysRecv(e->KHandle, buf, len, (uint32_t)flags, &got);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
__declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int flags,
const struct sockaddr* dest, socklen_t destlen) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 remote;
if (SockAddrToSys(dest, destlen, &remote) != 0) return -1;
size_t sent = 0;
SYS_SOCKET_SEND_TO_REQUEST req;
memset(&req, 0, sizeof(req));
req.Buffer = buf;
req.Length = len;
req.Flags = (uint32_t)flags;
req.RemoteAddress = &remote;
req.RemoteAddressSize = sizeof(remote);
req.SentOut = &sent;
uint32_t s = SysSendTo(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
__declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
struct sockaddr* src, socklen_t* srclen) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
SYS_SOCKET_ADDRESS_IPV4 remote;
size_t remoteSize = sizeof(remote);
size_t got = 0;
SYS_SOCKET_RECV_FROM_REQUEST req;
memset(&req, 0, sizeof(req));
req.Buffer = buf;
req.Length = len;
req.Flags = (uint32_t)flags;
req.RemoteAddressOut = src ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)0;
req.RemoteAddressSizeInOut = src ? &remoteSize : (size_t*)0;
req.ReceivedOut = &got;
uint32_t s = SysRecvFrom(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
if (src) SysToSockAddr(&remote, src, srclen);
return (ssize_t)got;
}
__declspec(dllexport) int shutdown(int fd, int how) {
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t s = SysShutdown(e->KHandle, (uint32_t)how);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
static uint32_t TimevalToMs(const struct timeval* tv) {
if (!tv) return 0;
uint64_t ms = (uint64_t)tv->tv_sec * 1000u + (uint64_t)(tv->tv_usec / 1000);
return ms > 0xFFFFFFFFu ? 0xFFFFFFFFu : (uint32_t)ms;
}
__declspec(dllexport) int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
if (level != SOL_SOCKET || !optval) { errno = EINVAL; return -1; }
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t option = 0;
uint32_t value = 0;
if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
option = (optname == SO_RCVTIMEO) ? SYS_SOCKET_OPT_RECV_TIMEOUT_MS : SYS_SOCKET_OPT_SEND_TIMEOUT_MS;
if (optlen == sizeof(struct timeval)) value = TimevalToMs((const struct timeval*)optval);
else if (optlen == sizeof(uint32_t)) memcpy(&value, optval, sizeof(value));
else { errno = EINVAL; return -1; }
} else if (optname == SO_NONBLOCK) {
option = SYS_SOCKET_OPT_NONBLOCKING;
if (optlen < sizeof(int)) { errno = EINVAL; return -1; }
value = (*(const int*)optval) ? 1u : 0u;
} else {
errno = ENOSYS;
return -1;
}
SYS_SOCKET_OPTION_REQUEST req;
memset(&req, 0, sizeof(req));
req.Option = option;
req.Value = &value;
req.ValueSize = sizeof(value);
uint32_t s = SysSetSocketOption(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
__declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optval, socklen_t* optlen) {
if (level != SOL_SOCKET || !optval || !optlen) { errno = EINVAL; return -1; }
FD_ENTRY* e = SocketFdGet(fd);
if (!e) return -1;
uint32_t option = 0;
if (optname == SO_RCVTIMEO) option = SYS_SOCKET_OPT_RECV_TIMEOUT_MS;
else if (optname == SO_SNDTIMEO) option = SYS_SOCKET_OPT_SEND_TIMEOUT_MS;
else if (optname == SO_NONBLOCK) option = SYS_SOCKET_OPT_NONBLOCKING;
else { errno = ENOSYS; return -1; }
uint32_t value = 0;
size_t actual = sizeof(value);
SYS_SOCKET_OPTION_REQUEST req;
memset(&req, 0, sizeof(req));
req.Option = option;
req.Value = &value;
req.ValueSize = sizeof(value);
req.ActualSizeOut = &actual;
uint32_t s = SysGetSocketOption(e->KHandle, &req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
if ((optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) && *optlen >= sizeof(struct timeval)) {
struct timeval* tv = (struct timeval*)optval;
tv->tv_sec = (long)(value / 1000u);
tv->tv_usec = (long)((value % 1000u) * 1000u);
*optlen = sizeof(struct timeval);
} else if (*optlen >= sizeof(uint32_t)) {
memcpy(optval, &value, sizeof(value));
*optlen = sizeof(value);
} else {
errno = ERANGE;
return -1;
}
return 0;
}
__declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
if (!fds || nfds == 0 || nfds > 64) { errno = EINVAL; return -1; }
SYS_POLLFD* kfds = (SYS_POLLFD*)SysAlloc(sizeof(SYS_POLLFD) * nfds);
if (!kfds) { errno = ENOMEM; return -1; }
for (nfds_t i = 0; i < nfds; i++) {
kfds[i].Handle = 0;
kfds[i].Events = 0;
kfds[i].ReturnedEvents = 0;
fds[i].revents = 0;
FD_ENTRY* e = FdGet(SysGetCurrentPid(), fds[i].fd);
if (!e || e->Type != FD_SOCKET) {
continue;
}
kfds[i].Handle = e->KHandle;
if (fds[i].events & POLLIN) kfds[i].Events |= SYS_POLL_READ;
if (fds[i].events & POLLOUT) kfds[i].Events |= SYS_POLL_WRITE;
if (fds[i].events & POLLERR) kfds[i].Events |= SYS_POLL_ERROR;
if (fds[i].events & POLLHUP) kfds[i].Events |= SYS_POLL_HANGUP;
}
size_t ready = 0;
uint32_t timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout;
uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready);
if (s != 0) {
SysFree(kfds);
errno = PosixStatusToErrno(s);
return -1;
}
int out = 0;
for (nfds_t i = 0; i < nfds; i++) {
short re = 0;
if (kfds[i].ReturnedEvents & SYS_POLL_READ) re |= POLLIN;
if (kfds[i].ReturnedEvents & SYS_POLL_WRITE) re |= POLLOUT;
if (kfds[i].ReturnedEvents & SYS_POLL_ERROR) re |= POLLERR;
if (kfds[i].ReturnedEvents & SYS_POLL_HANGUP) re |= POLLHUP;
if (kfds[i].ReturnedEvents & SYS_POLL_INVALID) re |= POLLNVAL;
fds[i].revents = re;
if (re) out++;
}
SysFree(kfds);
return out;
}
static unsigned ParsePort(const char* s) {
unsigned v = 0;
if (!s) return 0;
while (*s >= '0' && *s <= '9') {
v = v * 10 + (unsigned)(*s - '0');
if (v > 65535u) return 0;
s++;
}
return *s == '\0' ? v : 0;
}
static int ResolveNameIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4* out) {
uint8_t b[4];
if (ParseIpv4Bytes(name, b)) {
memset(out, 0, sizeof(*out));
out->Family = SYS_AF_INET;
out->Address[0] = b[0]; out->Address[1] = b[1]; out->Address[2] = b[2]; out->Address[3] = b[3];
return 0;
}
size_t size = sizeof(*out);
SYS_RESOLVE_HOST_REQUEST req;
memset(&req, 0, sizeof(req));
req.Name = name;
req.NameLength = strlen(name);
req.Family = SYS_AF_INET;
req.AddressOut = out;
req.AddressSizeInOut = &size;
uint32_t s = SysResolveHost(&req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
__declspec(dllexport) struct hostent* gethostbyname(const char* name) {
static struct hostent h;
static char hname[256];
static char* aliases[1];
static char* addr_list[2];
static uint8_t addr[4];
if (!name || strlen(name) >= sizeof(hname)) { errno = EINVAL; return (struct hostent*)0; }
SYS_SOCKET_ADDRESS_IPV4 a;
if (ResolveNameIpv4(name, &a) != 0) return (struct hostent*)0;
strcpy(hname, name);
memcpy(addr, a.Address, 4);
aliases[0] = (char*)0;
addr_list[0] = (char*)addr;
addr_list[1] = (char*)0;
h.h_name = hname;
h.h_aliases = aliases;
h.h_addrtype = AF_INET;
h.h_length = 4;
h.h_addr_list = addr_list;
return &h;
}
__declspec(dllexport) int getaddrinfo(const char* node, const char* service,
const struct addrinfo* hints, struct addrinfo** res) {
if (!res) return EINVAL;
*res = (struct addrinfo*)0;
int family = hints ? hints->ai_family : AF_INET;
if (family != AF_INET && family != 0) return EINVAL;
SYS_SOCKET_ADDRESS_IPV4 a;
memset(&a, 0, sizeof(a));
a.Family = SYS_AF_INET;
if (!node) {
a.Address[0] = 0; a.Address[1] = 0; a.Address[2] = 0; a.Address[3] = 0;
} else if (ResolveNameIpv4(node, &a) != 0) {
return errno;
}
a.Port = service ? ParsePort(service) : 0;
size_t total = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
struct addrinfo* ai = (struct addrinfo*)SysAlloc(total);
if (!ai) return ENOMEM;
memset(ai, 0, total);
struct sockaddr_in* sin = (struct sockaddr_in*)((uint8_t*)ai + sizeof(struct addrinfo));
sin->sin_family = AF_INET;
sin->sin_port = htons(a.Port);
uint8_t* p = (uint8_t*)&sin->sin_addr.s_addr;
p[0] = a.Address[0]; p[1] = a.Address[1]; p[2] = a.Address[2]; p[3] = a.Address[3];
ai->ai_family = AF_INET;
ai->ai_socktype = hints ? hints->ai_socktype : 0;
ai->ai_protocol = hints ? hints->ai_protocol : 0;
ai->ai_addrlen = sizeof(struct sockaddr_in);
ai->ai_addr = (struct sockaddr*)sin;
ai->ai_next = (struct addrinfo*)0;
*res = ai;
return 0;
}
__declspec(dllexport) void freeaddrinfo(struct addrinfo* res) {
if (res) SysFree(res);
}