m³OS docs GitHub

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.

Complete

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

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 SocketHandle type 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, and write must all work on it via the existing fd dispatch path.
  • Add a sys_socket dispatch path in the syscall gate: validate the domain (AF_INET only), type (SOCK_STREAM or SOCK_DGRAM), and protocol; allocate a SocketHandle; send a NET_SOCKET_CREATE IPC message to net_server; and return the new fd number.
  • Implement sys_bind and sys_connect as thin syscall stubs that copy the sockaddr_in from userspace, forward it to net_server via IPC, and block the calling task until the operation completes or returns an error code.
  • Implement sys_listen and sys_accept. accept blocks the calling task in the kernel; net_server unblocks it and returns the peer address and a new socket fd when the TCP handshake completes.
  • Implement sys_send / sys_sendto and sys_recv / sys_recvfrom. For TCP, net_server may 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, and sys_getsockopt. Support at minimum SOL_SOCKET options SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF, and IPPROTO_TCP option TCP_NODELAY.
  • Extend sys_poll to handle socket fds. Teach net_server to track per-socket readiness state and send a notification to the kernel when a socket becomes readable or writable so a blocked poll call can be woken.
  • Add SOCK_DGRAM / IPPROTO_ICMP support to net_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, use poll to wait for replies with a timeout, and print each round-trip time to stdout.
  • Remove the ping builtin from kernel/src/main.rs and delete the associated dead-code paths.
  • Remove the #[allow(dead_code)] annotations from the network stack modules in kernel/src/net/ now that they are reachable from userspace through net_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
  • epoll and epoll_wait
  • sendfile and zero-copy I/O
  • Multicast group membership (IP_ADD_MEMBERSHIP)
  • SO_REUSEPORT for multi-process listeners
  • Non-blocking sockets (O_NONBLOCK) and EAGAIN handling
  • DNS resolution (getaddrinfo / /etc/resolv.conf)
  • TLS / DTLS
  • TCP retransmission and congestion control improvements
  • recvmsg / sendmsg with ancillary data (cmsg)

Source materials

Important code

Code spotlight cards

Code spotlight

Ping

userspace/ping/ See file

Write userspace/ping/ as a standalone ELF binary. Open an ICMP DGRAM socket,

Code spotlight

Kernel entry

kernel/src/main.rs See file

Remove the ping builtin from kernel/src/main.rs and delete the associated

Code spotlight

Net

kernel/src/net/ See file

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