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

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