Project: BDS (Bedrock Dedicated Server)
Summary: NetherNet listener is bound without SO_REUSEADDR; a restart within about a minute silently starts with no listener
Environment: BDS 1.26.63.1 and 1.26.62.1, Linux x86_64 (Ubuntu 22.04; also Debian in a Docker container with host networking), transport=nethernet, server-port 19132
Steps to reproduce:
Start bedrock_server with transport=nethernet. The log shows "Accepting clients on [::]:19132".
On the same host, send one GET /v1/join to port 19132 (for example
curl <http://127.0.0.1:19132/v1/join),> or open a TCP connection to the port and leave it open.Type
stop. The server quits normally.ss -tan '( sport = :19132 )'now shows the server side of that connection in TIME-WAIT or FIN-WAIT-2.Start bedrock_server again within 60 seconds.
Observed:
The log has no "Accepting clients" line and no error, then "Server started". Port 19132 is closed: GET /v1/join is refused, no client can join, the server stays like this until the next restart. strace of the second start:
setsockopt(21, SOL_SOCKET, SO_TIMESTAMP_OLD, [1], 4) = 0
setsockopt(21, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
bind(21, {sa_family=AF_INET6, sin6_port=htons(19132), "::"}, 28) = -1 EADDRINUSE
bind(21, {sa_family=AF_INET, sin_port=htons(19132), "0.0.0.0"}, 16) = -1 EADDRINUSESO_REUSEADDR is never set on any socket of the process.
Expected:
The listener is bound with SO_REUSEADDR, so that a restart binds next to the TIME-WAIT and FIN-WAIT-2 leftovers of the previous instance's own connections, as every TCP server does.
When the listener cannot be bound, the server logs an error and exits instead of printing "Server started" and running without connectivity.
Notes:
Any quick restart on Linux hits this: an update script, systemd Restart=, Docker with host networking. A plain GET such as a health probe is enough to leave the leftover, because the server closes the connection first.
Docker bridge networking hides the bug, since each start gets a fresh network namespace.
A test preload that sets SO_REUSEADDR on the TCP socket before bind, running on both the stopping and the starting instance, makes the immediate restart work. A wait for the leftovers to expire works as well.
BDS-23108 and BDS-23120 describe different NetherNet failures.
Environment
Docker
Comments 0
No comments.