import socket proc console_write(p: pointer, len: csize_t) {.importc, cdecl.} # Basic SockAddr struct match (IPv4) type SockAddrIn = object sin_family: uint16 sin_port: uint16 sin_addr: uint32 sin_zero: array[8, char] proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} = # Domain=2 (AF_INET), Type=1 (SOCK_STREAM) # We ignore them for now and just give a Nexus Socket return new_socket() proc connect*(fd: int, sock_addr: pointer, len: int): int {.exportc, cdecl.} = if sock_addr == nil: return -1 # Cast raw pointer to SockAddrIn let sin = cast[ptr SockAddrIn](sock_addr) # Call the Shim # Note: Linux sockaddr_in is Big Endian for Port/IP usually # NPK is likely running the same endianness as Kernel (Little Endian on RISC-V/x86) # But `connect` expects Network Byte Order (Big Endian). # We pass it raw to connect_flow, which will store it. return connect_flow(fd, sin.sin_addr, sin.sin_port) proc write*(fd: cint, buf: pointer, count: csize_t): int {.exportc, cdecl.} = if fd == 1 or fd == 2: when defined(is_kernel): # 1. Allocate a Console Slab var pkt = ion_alloc() if pkt.data == nil: return -1 # 2. Copy the string (Cap at SLAB_SIZE) let safe_count = min(int(count), SLAB_SIZE) copyMem(pkt.data, buf, safe_count) pkt.len = uint16(safe_count) # 3. Push to KERNEL CONSOLE (Port 0) ion_egress_to_port(0, pkt) return int(safe_count) else: # Membrane side: Direct to UART for Phase 7 console_write(buf, count) return int(count) # Handle Sockets (fd > 2) return send_flow(int(fd), buf, int(count)) proc read*(fd: int, buf: pointer, count: int): int {.exportc, cdecl.} = # TODO: Lookup socket, check RX ring return -1 # EBADF