Phase 23
Socket API
Expose the kernel's existing TCP/IP stack to userspace via standard Linux socket syscalls. At the end of this phase a userspace program can open a TCP connection, send an HTTP/1.0 request, and receive the response — entirely from ring-3 code, with no kernel modifications needed for each new network program. The `ping` shell builtin moves out of the kernel and into a standalone userspace ELF.
Learning goal
Understand how socket syscalls map to internal kernel objects and how fds unify files and sockets behind the same descriptor table.
Category
infrastructure
Components touched
Builds on
Unlocked by this phase
Why this phase matters
Expose the kernel’s existing TCP/IP stack to userspace via standard Linux socket syscalls. At the end of this phase a userspace program can open a TCP connection, send an HTTP/1.0 request, and receive the response — entirely from ring-3 code, with no kernel modifications needed for each new network program. The ping shell builtin moves out of the kernel and into a standalone userspace ELF.
How it works in m3OS
The roadmap entry defines the learning scope for this phase; a deeper implementation doc has not been matched yet.
How it builds on earlier phases
This phase builds on ANSI Escape and turns that foundation into Socket API.
Implementation outline
- Define a
SocketHandletype in the kernel and add a socket slot to the per-process fd table alongside file and pipe slots. A socket fd must be indistinguishable from a file fd from userspace;close,read, andwritemust all work on it via the existing fd dispatch path. - Add a
sys_socketdispatch path in the syscall gate: validate the domain (AF_INETonly), type (SOCK_STREAMorSOCK_DGRAM), and protocol; allocate aSocketHandle; send aNET_SOCKET_CREATEIPC message tonet_server; and return the new fd number. - Implement
sys_bindandsys_connectas thin syscall stubs that copy thesockaddr_infrom userspace, forward it tonet_servervia IPC, and block the calling task until the operation completes or returns an error code. - Implement
sys_listenandsys_accept.acceptblocks the calling task in the kernel;net_serverunblocks it and returns the peer address and a new socket fd when the TCP handshake completes. - Implement
sys_send/sys_sendtoandsys_recv/sys_recvfrom. For TCP,net_servermay need to buffer partial sends across multiple IPC messages; for UDP, each call maps to one datagram. Copy data through a shared page capability to avoid copying through the IPC message payload. - Implement
sys_shutdown,sys_getsockname,sys_getpeername,sys_setsockopt, andsys_getsockopt. Support at minimumSOL_SOCKEToptionsSO_REUSEADDR,SO_KEEPALIVE,SO_RCVBUF,SO_SNDBUF, andIPPROTO_TCPoptionTCP_NODELAY. - Extend
sys_pollto handle socket fds. Teachnet_serverto track per-socket readiness state and send a notification to the kernel when a socket becomes readable or writable so a blockedpollcall can be woken. - Add
SOCK_DGRAM/IPPROTO_ICMPsupport tonet_server’s socket dispatch. Sending on such a socket constructs an ICMP echo request; receiving delivers the first matching ICMP echo reply. No raw socket privilege check is required for ICMP DGRAM in this phase. - Write
userspace/ping/as a standalone ELF binary. Open an ICMP DGRAM socket, send echo requests in a loop, usepollto wait for replies with a timeout, and print each round-trip time to stdout. - Remove the
pingbuiltin fromkernel/src/main.rsand delete the associated dead-code paths. - Remove the
#[allow(dead_code)]annotations from the network stack modules inkernel/src/net/now that they are reachable from userspace throughnet_server.
Task progress snapshot
No checklist tasks were discovered for this phase yet.
Documentation targets
- Documentation deliverables have not been listed yet.
Deferred follow-on work
- AF_UNIX (Unix domain sockets)
- AF_INET6 (IPv6)
- Raw sockets (
SOCK_RAW) for userspace epollandepoll_waitsendfileand zero-copy I/O- Multicast group membership (
IP_ADD_MEMBERSHIP) SO_REUSEPORTfor multi-process listeners- Non-blocking sockets (
O_NONBLOCK) andEAGAINhandling - DNS resolution (
getaddrinfo//etc/resolv.conf) - TLS / DTLS
- TCP retransmission and congestion control improvements
recvmsg/sendmsgwith ancillary data (cmsg)
Source materials
Important code
Code spotlight cards
Code spotlight
Ping
Write userspace/ping/ as a standalone ELF binary. Open an ICMP DGRAM socket,
Code spotlight
Kernel entry
Remove the ping builtin from kernel/src/main.rs and delete the associated
Code spotlight
Net
kernel/src/net/ now that they are reachable from userspace through net_server.
Key files
- userspace/ping/ — Write userspace/ping/ as a standalone ELF binary. Open an ICMP DGRAM socket,
- kernel/src/main.rs — Remove the ping builtin from kernel/src/main.rs and delete the associated
- kernel/src/net/ — kernel/src/net/ now that they are reachable from userspace through net_server.
- kernel/src/net/mod.rs — SocketHandle, SocketEntry, SOCKET_TABLE, alloc/free/with helpers
- kernel/src/arch/x86_64/syscall.rs — All sys_socket/bind/connect/listen/accept/send/recv/shutdown/poll dispatch
- kernel/src/process/mod.rs — FdBackend::Socket variant, ref counting on fork/close
- userspace/syscall-lib/src/lib.rs — SockaddrIn, socket constants, syscall wrappers
- userspace/ping/src/main.rs — Userspace ping ELF binary
- kernel-core/src/net/mod.rs — SockaddrIn layout tests (host-testable)
How real OSes differ
- Linux's socket layer (`net/socket.c`) handles dozens of address families (AF_INET6, AF_UNIX, AF_NETLINK, AF_PACKET, AF_VSOCK, and more), non-blocking I/O through `epoll`, zero-copy sends via `sendfile` and `splice`, multicast group membership, `SO_REUSEPORT` for multi-process listeners, `io_uring` for async socket I/O, and a full `netfilter` hook chain for firewalling and NAT.
- The socket buffer (`sk_buff`) is a carefully optimized structure that avoids copies across protocol layers.
- This phase implements a single address family with blocking I/O and a simple `poll` extension — enough to run real network programs but with none of the performance or scalability mechanisms of a production stack.
Success criteria
- `socket(AF_INET, SOCK_STREAM, 0)` returns a valid fd; `close` on it sends a TCP RST or FIN as appropriate.
- A userspace TCP client can connect to `10.0.2.2:80`, send an HTTP/1.0 `GET /` request, and print the response body to stdout.
- A userspace TCP server can `bind`, `listen`, and `accept` a connection from the QEMU host and echo data back.
- A userspace UDP client can send a datagram to a host echo server and receive the reply.
- `poll([{fd: sock, events: POLLIN}], 1, timeout_ms)` returns when data arrives and 0 when it times out with no data.
- `ping 10.0.2.2` runs as a userspace ELF (not a shell builtin) and receives ICMP echo replies.
- The `ping` kernel builtin no longer exists in `kernel/src/main.rs`.
- `setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ...)` has observable effect (disables Nagle; small sends are not coalesced).
Related phases
Keep exploring the roadmap
Phase 22
CompleteANSI Escape
Learn how ANSI Escape fits into m3OS.
Phase 24
CompletePersistent Storage
Give m3OS a persistent block device so that files written during one boot session survive into the next. A virtio-blk driver (the simplest PCI virtio device in QEMU) handles raw sector I/O; a partition parser finds the FAT32 data partition; the existing `fat_server` gains a write path that flushes directly to disk. After this phase, writing a file to `/data` and rebooting leaves the file visible on the next boot (and on the host via `losetup` or similar).