TcpUdpListener
TcpUdpListener is a chain-head adapter wrapper around TcpListener and UdpListener. It creates one internal TCP
listener and one internal UDP listener with the same listener settings, so a single WaterWall entry node can accept both
TCP and UDP traffic on the same address and port set.
This node does not translate TCP into UDP, and it does not translate UDP into TCP. It only lets both transport adapters feed one shared next node.
Typical Placement
Use TcpUdpListener when the same service entry should accept both TCP and UDP:
TcpUdpListener -> SpeedTestServer
TcpUdpListener -> SniffRouter -> TcpUdpConnector
TcpUdpListener -> Router -> ...
The next node must be valid for the traffic you expect. If both TCP and UDP will arrive in production, the next node must understand both normal TCP lines and UDP peer lines, or it must route them by protocol.
Basic Example
[
{
"name": "mixed-in",
"type": "TcpUdpListener",
"settings": {
"address": "0.0.0.0",
"port": 443,
"nodelay": true,
"large-send-buffer": true,
"large-recv-buffer": true
},
"next": "mixed-out"
},
{
"name": "mixed-out",
"type": "TcpUdpConnector",
"settings": {
"address": "127.0.0.1",
"port": 8443,
"reuseaddr": true,
"nodelay": true
}
}
]
In this example, inbound TCP on port 443 is forwarded through the internal TcpListener, and inbound UDP on port 443
is forwarded through the internal UdpListener. The shared TcpUdpConnector at the end chooses its own TCP or UDP child
connector from the line protocol metadata.
Multiport Example
{
"name": "mixed-public-entry",
"type": "TcpUdpListener",
"settings": {
"address": "0.0.0.0",
"port": [
443,
8443
],
"nodelay": true,
"large-send-buffer": true,
"large-recv-buffer": true,
"interface": "eth0",
"fwmark": 10,
"balance-group": "public-mixed",
"balance-interval": 30000,
"multiport-backend": "socket",
"whitelist": [
"192.0.2.0/24",
"2001:db8::/64"
],
"blacklist": [
"192.0.2.99/32"
]
},
"next": "next-node"
}
The same port list is used for both TCP and UDP. TCP port 443 and UDP port 443 are different socket protocols, so
they can be bound at the same time.
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 "TcpUdpListener". |
settings | object | Shared listener settings passed to both internal child listeners. Must be a non-empty object. |
next | string | The node that receives both TCP lines and UDP peer lines. |
Required settings fields:
| Field | Type | Description |
|---|---|---|
address | string | Local bind address for both child listeners. |
port or port-range | number, array, or range array | Port definition used by both TCP and UDP listeners. Exactly one of these fields is required. |
Port Configuration
TcpUdpListener inherits the listener port syntax from TcpListener and UdpListener.
Single Port
{
"settings": {
"address": "0.0.0.0",
"port": 443
}
}
Explicit Port List
{
"settings": {
"address": "0.0.0.0",
"port": [
443,
8443,
2083
]
}
}
This listens only on the listed ports for both TCP and UDP.
Contiguous Port Range
{
"settings": {
"address": "0.0.0.0",
"port-range": [
40000,
40100
]
}
}
port-range must be a two-item array: [min, max].
Optional Settings
Because the same settings object is passed to both child listeners, most options are the same options documented on
TcpListener and UdpListener.
| Setting | Applies to | Description |
|---|---|---|
nodelay | TCP child | Enables TCP_NODELAY on accepted TCP sockets. |
large-send-buffer | TCP and UDP children | Sets SO_SNDBUF where supported. |
large-recv-buffer | TCP and UDP children | Sets SO_RCVBUF where supported. |
interface | TCP and UDP children | Restricts sockets to a local network interface where supported. |
fwmark | TCP and UDP children | Applies a Linux-style socket mark where supported. |
balance-group | TCP and UDP children | Groups compatible same-port listeners for sticky distribution. |
balance-interval | TCP and UDP children | Sticky interval for repeated clients or peers in a balance group. |
initial-idle-timeout-ms | TCP child | Initial idle timeout before listener-side TCP payload activity. |
active-idle-timeout-ms | TCP child | Idle timeout after TCP payload activity has started. |
multiport-backend | TCP and UDP children | Backend used for contiguous port ranges: "iptables" or "socket". |
whitelist | TCP and UDP children | Allowed client or peer IPs and CIDR ranges. |
blacklist | TCP and UDP children | Blocked client or peer IPs and CIDR ranges. |
For exact socket behavior, timeout defaults, and multiport implementation details, see the TcpListener and
UdpListener pages.
Runtime Flow
At startup, TcpUdpListener creates two internal child tunnels:
TcpListener, named like<node-name>.tcp-listenerUdpListener, named like<node-name>.udp-listener
Both children are inserted into the chain. They own the real sockets and line lifecycle:
- the internal
TcpListeneraccepts TCP sockets and creates TCP lines - the internal
UdpListenercreates UDP peer lines - upstream callbacks from either child enter
TcpUdpListener TcpUdpListenerforwards upstreamInit,Payload,Pause,Resume,Est, andFinishtonext
On the downstream path, the next node calls back into TcpUdpListener. The wrapper checks the line source protocol:
| Source protocol metadata | Downstream child |
|---|---|
| TCP | internal TcpListener |
| UDP | internal UdpListener |
| missing or ambiguous TCP/UDP flags | fatal configuration or routing error |
This is why nodes after TcpUdpListener should preserve the line source protocol metadata.
Line Ownership
TcpUdpListener itself has no per-line state. It never creates lines and never calls lineDestroy().
Line ownership stays with the child adapter that created the line:
- TCP lines are owned by the internal
TcpListener - UDP peer lines are owned by the internal
UdpListener
Node Metadata
| Property | Value |
|---|---|
| Node flag | kNodeFlagChainHead |
| Previous node | Not allowed |
| Next node | Required |
| Layer group | kNodeLayer4 |
required_padding_left | 0 |
| Line state size | 0 |
Common Mistakes
- Do not use
TcpUdpListeneras a protocol converter. It accepts both protocols, but it does not convert between them. - Do not point it at a next node that only works for TCP if UDP traffic can arrive.
- Do not configure different TCP and UDP port sets on this wrapper; both child listeners receive the same settings.
- Do not remove or corrupt source protocol metadata before callbacks return downstream to this node.