Skip to content

Sockets Implementation

opencode-agent[bot] edited this page May 10, 2026 · 3 revisions

Sockets-Implementation

How JNode bridges the standard java.net API to its native TCP/IP stack.

Overview

JNode implements a complete network stack in pure Java because it runs directly on bare hardware without a host OS. The socket implementation layer bridges standard Java networking classes (java.net.Socket, ServerSocket) to JNode's internal TransportLayer state machines. When a Java application calls Socket.connect(), the call flows through a custom SocketImplFactory into TCPControlBlock and eventually sends raw IP packets via the network device driver.

Key Components

Class / File Role
net/src/net/org/jnode/net/ipv4/tcp/TCPProtocol.java Transport layer entry point; registers SocketImplFactory with the JVM
net/src/net/org/jnode/net/ipv4/tcp/TCPSocketImplFactory.java Factory creating TCPSocketImpl instances for Socket/ServerSocket
net/src/net/org/jnode/net/ipv4/tcp/TCPSocketImpl.java Core bridge: implements java.net.SocketImpl, delegates to TCPControlBlock
net/src/net/org/jnode/net/ipv4/tcp/TCPControlBlock.java Per-connection state machine; manages TCP state transitions and data flow
net/src/net/org/jnode/net/ipv4/tcp/TCPInChannel.java Manages incoming data buffering, sequence numbers, out-of-order segments
net/src/net/org/jnode/net/ipv4/tcp/TCPOutChannel.java Manages outgoing data buffering, retransmission, ACK processing
net/src/net/org/jnode/net/ipv4/tcp/TCPInputStream.java Wraps TCPControlBlock.appRead() as java.io.InputStream
net/src/net/org/jnode/net/ipv4/tcp/TCPOutputStream.java Wraps TCPControlBlock.appSendData() as java.io.OutputStream
net/src/net/org/jnode/net/ipv4/tcp/TCPConstants.java TCP flags, connection states (LISTEN, SYN_SENT, ESTABLISHED, etc.)

How It Works

1. Factory Registration

At initialization, TCPProtocol creates a TCPSocketImplFactory and registers it with the JVM via Socket.setSocketImplFactory() and ServerSocket.setSocketFactory(). From this point on, any new Socket() or new ServerSocket() will produce a TCPSocketImpl instead of the platform default.

TCPProtocol.<init>
  → new TCPSocketImplFactory(this)
  → Socket.setSocketImplFactory(factory)   // privileged
  → ServerSocket.setSocketFactory(factory)

2. Connection Establishment

Client side (connect()):

Socket.connect(host, port)
  → TCPSocketImpl.connect(InetAddress, port)
    → controlBlock.appConnect(IPv4Address, port)
      → sendSYN() → state = SYN_SENT
      → waitUntilState(ESTABLISHED, timeout)

Server side (accept()):

ServerSocket.accept()
  → TCPSocketImpl.accept(SocketImpl)
    → controlBlock.appAccept()
      → wait for readyToAcceptList notification
      → return accepted TCPSocketImpl

3. State Machine

TCPControlBlock implements the full TCP state machine (defined in TCPConstants):

CLOSED → LISTEN (appListen) → SYN_RECV (SYN received) → ESTABLISHED (ACK received)
CLOSED → SYN_SENT (SYN sent) → ESTABLISHED (ACK+SYN received)
ESTABLISHED → FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED

Each receive() call dispatches based on curState to the appropriate handler method (e.g., receiveEstablished(), receiveFinWait1()).

4. Data Flow

Sending (OutputStream.write()):

TCPOutputStream.write(buf, off, len)
  → controlBlock.appSendData(buf, off, len)
    → chunks data into MSS-sized segments
    → TCPOutChannel.send() → TCPOutSegment → TCPProtocol.send() → IPv4Service.transmit()

Receiving (InputStream.read()):

TCPInputStream.read(buf, off, len)
  → controlBlock.appRead(buf, off, len)
    → TCPInChannel.read() blocks until data available
      → dataBuffer.getData() copied to user buffer

5. Stream/Channel Architecture

TCPInputStream and TCPOutputStream wrap the control block's appRead()/appSendData() methods. Closing either stream triggers impl.close(), which calls controlBlock.appClose() initiating the FIN handshake.

Gotchas

  • SYN retransmission: On connection failure, appConnect() retries up to TCP_MAXCONNECT (3) times with the default 10-second TCP_DEFAULT_TIMEOUT per attempt.
  • Out-of-order segments: TCPInChannel buffers out-of-order segments in futureSegments (a LinkedList<TCPInSegment>) and processes them only when the expected sequence number arrives.
  • FIN_WAIT_2 timeout: In FIN_WAIT_2 state, the implementation blocks for a hardcoded 400ms before transitioning to TIME_WAIT, rather than using the full 2MSL timeout.
  • Port unreachable: When a segment arrives for an unbound port, TCPProtocol.processPortUnreachable() sends a RST+ACK rather than just dropping the packet.
  • Privileged registration: The SocketImplFactory registration must run inside AccessController.doPrivileged() because Socket.setSocketImplFactory() requires security permission.

Related Pages

Clone this wiki locally