ConnectionFisherServer
ConnectionFisherServer is the server-side peer for
ConnectionFisherClient. It waits for the fixed client probe, replies with the
fixed server marker, and only then allows the line to become a normal forwarding
stream.
Use it only on paths that are expected to receive traffic from
ConnectionFisherClient.
Typical Placement
Simple TCP layout:
TcpListener -> ConnectionFisherServer -> TcpConnector
Paired with the client:
TcpListener -> ConnectionFisherClient -> TcpConnector
TcpListener -> ConnectionFisherServer -> TcpConnector
With other stream tunnels in between:
ConnectionFisherClient -> EncryptionClient -> TcpConnector
TcpListener -> EncryptionServer -> ConnectionFisherServer -> TcpConnector
The server must see the same FISH? bytes that the client sends after any
intermediate client/server tunnel pair has decoded them.
What It Does
- Initializes local line state on upstream
Init. - Delays upstream
Inittowardnext. - Buffers upstream bytes until the first 5 bytes are available.
- Requires the first 5 bytes to be
FISH?. - Sends the fixed reply
FISH!downstream to the client. - Initializes
nextonly when post-probe payload is available. - Forwards payload normally after the probe phase is complete.
- Closes the line on invalid probe data or exhausted startup storage.
ConnectionFisherServer is a middle stream tunnel. It does not create sockets
directly and it does not create packet lines.
Configuration Example
{
"name": "fisher-server",
"type": "ConnectionFisherServer",
"next": "service"
}
settings is not used by the current implementation.
Required Fields
Top-level fields:
| Field | Type | Description |
|---|---|---|
name | string | User-chosen node name. Must be unique inside the config file. |
type | string | Must be exactly "ConnectionFisherServer". |
next | string | Required. The next stream node receives payload after the probe phase. |
ConnectionFisherServer must also have a previous node in the chain. It is not
a chain head or chain end.
Settings
No settings fields are currently parsed.
Probe Exchange
| Direction | Bytes | Meaning |
|---|---|---|
| client to server | FISH? | Required first 5 upstream bytes. |
| server to client | FISH! | Reply sent after a valid probe. |
The markers are fixed ASCII bytes. They are not a security mechanism.
Server Phases
The implementation uses three phases:
| Phase | Behavior |
|---|---|
| wait ping | Upstream bytes are buffered until at least 5 bytes are available. |
| wait payload | The probe was valid and FISH! was sent, but next is not initialized yet unless extra payload is already buffered. |
| established | next Init has started; retained input drains before the server retires itself. |
Handshake Flow
On upstream Init, the server only initializes its own line state. It does not
call tunnelNextUpStreamInit() yet.
On upstream payload before establishment:
- The server buffers incoming bytes.
- A partial probe retains at most four bytes; data following a complete probe has a separate 2 MiB limit.
- Once at least 5 bytes are available, the first 5 bytes are read.
- If they are not exactly
FISH?, the line is closed. - If they match,
FISH!is sent downstream to the previous side. - If payload remains after the first 5 bytes, the server initializes
nextand forwards the remaining payload upstream. - If no extra payload remains, the server waits until the next upstream payload
arrives, then initializes
nextand forwards that payload.
The continuing path is published before calling next Init. Transport Est is forwarded promptly, including repeated notifications emitted synchronously from Init. Later payload forwards normally without waiting for Est.
The body coalesced with FISH? and the first post-probe payload retain their FIFO position across the FISH! reply, onward Init and nested Est callbacks. Temporary input ordering is bounded to 2 MiB and 1,024 buffers, including the body held across Init. It drains within the admitted dispatch and does not queue ready data merely for Pause or Est. The incomplete probe is at most four bytes; a complete probe can include an application body within the separate 2 MiB limit. Close during Init or Est releases older local input before returning.
Lifecycle Behavior
Before establishment:
- upstream
Initis local only - upstream payload is treated as probe or first post-probe payload
- the latest upstream
Pauseis retained for replay after next Init;Resumecancels it, including during Init reentry - downstream
Est,Pause, andResumeare not forwarded - downstream payload is unexpected, recycled, and causes the line to close
After establishment:
- upstream payload is forwarded to
next - downstream payload is forwarded to the previous node
- upstream Pause/Resume are forwarded to
next, including repeats - downstream Est/Pause/Resume are forwarded to the previous node, including repeats
After next Init, any pending Pause replay and all admitted input settle, the server destroys and zeros its line state and permanently bypasses itself on that line. This does not wait for Est or Resume. A newer Pause/Resume during Init cancels stale pending replay. Later callbacks go directly between its neighbors.
Before bypass, upstream Finish destroys local state and only forwards upstream
Finish if next had already been initialized. On protocol error before next
exists, it closes only the previous side because there is no next-side line yet.
Limits
| Limit | Value | Behavior |
|---|---|---|
| Probe length | 5 bytes | The first bytes must be FISH?. |
| Incomplete probe | 4 bytes | A complete five-byte probe is validated immediately. |
| Pending application data | 2 MiB / 1,024 buffers | Includes the body held across next Init; excludes the probe marker. |
| Required left padding | 0 | The server does not prepend to existing payload buffers. |
The FISH! reply is allocated as a separate small buffer.
Notes and Caveats
- Use it with a matching
ConnectionFisherClient. - Place it after any server-side tunnel that decodes the transport used between the client and server.
- It is intended for stream-style chains, not packet-line chains.
- The probe is fixed and public; use other WaterWall nodes for real security.
- Upstream
Estand downstreamInitare disabled callbacks for this node.
Splice Support and Setup Retirement
Both nodes accept ordinary buffers and private-pipe payloads. Complete deliveries entering handshake
or selection parsing are materialized with sbufEnsureOrdinary(); application FIFOs retain buffers
opaquely. A complete five-byte marker can carry up to 2 MiB of following application data. An incomplete
marker retains at most four bytes, and the marker does not consume the application-data allowance.
After setup and FIFO drain, the client releases its handshake streams and empty queue storage but keeps the main-to-selected-child mapping and endpoint flow control needed for payload, pressure and Finish. The server destroys and zeros its entire line state, then permanently bypasses itself after backend Init and replay settle. Ready payloads preserve their buffers without inspection, materialization or the startup backlog limit. Server backend initialization still waits for the first application payload, so losing candidates create no backend connection. Neither node requests ordinary reads for the established TCP stream.
Node Metadata
Source-backed metadata:
| Property | Value |
|---|---|
| node flags | kNodeFlagSupportsSplice |
can_have_prev | true |
can_have_next | true |
layer_group | kNodeLayer4 |
layer_group_prev_node | kNodeLayer4 |
layer_group_next_node | kNodeLayer4 |
required_padding_left | 0 bytes |