Skip to main content

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 Init toward next.
  • 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 next only 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:

FieldTypeDescription
namestringUser-chosen node name. Must be unique inside the config file.
typestringMust be exactly "ConnectionFisherServer".
nextstringRequired. 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​

DirectionBytesMeaning
client to serverFISH?Required first 5 upstream bytes.
server to clientFISH!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:

PhaseBehavior
wait pingUpstream bytes are buffered until at least 5 bytes are available.
wait payloadThe probe was valid and FISH! was sent, but next is not initialized yet unless extra payload is already buffered.
establishednext 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:

  1. The server buffers incoming bytes.
  2. A partial probe retains at most four bytes; data following a complete probe has a separate 2 MiB limit.
  3. Once at least 5 bytes are available, the first 5 bytes are read.
  4. If they are not exactly FISH?, the line is closed.
  5. If they match, FISH! is sent downstream to the previous side.
  6. If payload remains after the first 5 bytes, the server initializes next and forwards the remaining payload upstream.
  7. If no extra payload remains, the server waits until the next upstream payload arrives, then initializes next and 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 Init is local only
  • upstream payload is treated as probe or first post-probe payload
  • the latest upstream Pause is retained for replay after next Init; Resume cancels it, including during Init reentry
  • downstream Est, Pause, and Resume are 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​

LimitValueBehavior
Probe length5 bytesThe first bytes must be FISH?.
Incomplete probe4 bytesA complete five-byte probe is validated immediately.
Pending application data2 MiB / 1,024 buffersIncludes the body held across next Init; excludes the probe marker.
Required left padding0The 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 Est and downstream Init are 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:

PropertyValue
node flagskNodeFlagSupportsSplice
can_have_prevtrue
can_have_nexttrue
layer_groupkNodeLayer4
layer_group_prev_nodekNodeLayer4
layer_group_next_nodekNodeLayer4
required_padding_left0 bytes