KeepAliveServer
KeepAliveServer is the server-side peer for KeepAliveClient. It decodes
upstream keepalive frames from the client side, forwards normal payloads to
next, answers ping frames with pong frames, and wraps downstream payloads in
the same frame format on the way back.
Use it only as the matching peer for KeepAliveClient. By itself, it expects
framed upstream input and will not understand ordinary unframed payload bytes.
KeepAliveServer is a normal composable tunnel. It does not create sockets,
does not create or destroy line_t objects, and does not own any periodic
timer.
Typical Placement
Direct in-process test:
TesterClient -> KeepAliveClient -> KeepAliveServer -> TesterServer
Two-server TCP layout:
client side: TcpListener -> KeepAliveClient -> TcpConnector
server side: TcpListener -> KeepAliveServer -> TcpConnector
Any tunnels between the client and server must preserve the keepalive frame bytes exactly.
What It Does
- Initializes local line state on upstream
Init. - Buffers upstream framed bytes until complete frames are available.
- Decodes upstream normal frames and forwards their payload to
next. - Answers upstream ping frames by sending downstream pong frames.
- Ignores upstream pong frames.
- Drops empty normal frames and unknown frame kinds.
- Encodes downstream payloads as normal keepalive frames and sends them to the previous node.
- Splits downstream payloads larger than
65534bytes into multiple normal frames. - Destroys local line state and forwards the received directional
Finish.
The server does not have its own keepalive timer. Periodic ping generation is
owned by KeepAliveClient.
Configuration Example
{
"name": "ka-server",
"type": "KeepAliveServer",
"settings": {},
"next": "service"
}
Matching client side:
{
"name": "ka-client",
"type": "KeepAliveClient",
"settings": {
"ping-interval": 60000
},
"next": "transport"
}
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 "KeepAliveServer". |
settings | object | Optional. The current implementation has no server-specific settings. |
next | string | Required in normal use. The next node receives decoded upstream payloads. |
KeepAliveServer must have a previous node and must be reached by a matching
KeepAliveClient.
Settings
KeepAliveServer currently has no meaningful settings. Keepalive timing is
configured on KeepAliveClient with settings.ping-interval.
Frame Format
The server uses the same 3-byte prefix as the client:
| Bytes | Field | Description |
|---|---|---|
0..1 | body length | Unsigned 16-bit big-endian integer. This length includes the 1-byte frame kind plus any payload bytes. |
2 | frame kind | 1 normal payload, 2 ping, or 3 pong. |
Frame kinds:
| Kind | Meaning | Body payload |
|---|---|---|
1 | normal payload | Original WaterWall payload bytes. |
2 | ping | Empty in normal keepalive traffic. |
3 | pong | Empty response to a ping frame. |
Because the body length is 16-bit and includes the kind byte, the maximum
payload carried by one normal frame is 65534 bytes. Larger downstream payloads
are split into multiple frames.
Direction Behavior
| Incoming callback | Behavior |
|---|---|
upstream Init | Initializes the read buffer, then forwards Init to next. |
upstream Payload | Treats bytes as framed input from KeepAliveClient; forwards decoded normal payloads to next. |
upstream Est / Pause / Resume | Forwards to next. |
upstream Finish | Destroys local state, then forwards Finish to next. |
downstream Payload | Encodes the payload into one or more normal frames and forwards them to the previous node. Empty payloads are recycled. |
downstream Est / Pause / Resume | Forwards to the previous node. |
downstream Finish | Destroys local state, then forwards Finish to the previous node. |
downstream Init | Disabled; reaching this callback is treated as a fatal invalid chain flow. |
Framed Input Handling
Upstream bytes are accumulated in a buffer_stream_t. This means a frame can
arrive split across multiple payload callbacks, or multiple frames can arrive in
one callback.
The decoder behavior is conservative:
- waits for more bytes when the prefix or full body has not arrived yet
- clears the read stream when a frame body length smaller than
1is seen - drops empty normal frames
- drops unknown frame kinds
- clears the read stream if buffered upstream input grows beyond
131074bytes
Buffer And Padding Notes
KeepAliveServer prepends the 3-byte frame prefix while encoding downstream
payloads, so its node metadata advertises:
required_padding_left = 3
layer_group = kNodeLayerAnything
If a frame buffer does not have enough left padding for the prefix, the frame is dropped and the buffer is recycled. In a correctly composed chain, WaterWall's chain padding calculation should reserve this space.
When the current line is a worker packet line, the server checks that the framed
output does not exceed kMaxAllowedPacketLength. If payload + 3 would exceed
that limit, the frame is dropped.
Practical Notes
- Pair this node with
KeepAliveClient; it is not useful by itself. - Ping and pong frames are internal to the KeepAlive pair and are not delivered as payload to surrounding nodes.
- The server answers pings, but it does not measure client health or enforce a pong timeout.
- This node does not encrypt, authenticate, compress, or rewrite payload bytes.
- It is safest around transports that preserve the framed bytes between the client and server.