// posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets. #include #include #include #include #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 = SysSvFromCstr(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); }