From e3a49b40dc0c1e16e0302d9121bee662c2148d47 Mon Sep 17 00:00:00 2001 From: oboard Date: Fri, 21 Aug 2026 15:16:49 +0800 Subject: [PATCH] fix: enable SO_REUSEADDR in native listener for rapid restarts Pass `reuse_addr=true` when constructing the native HTTP server so a new process can immediately rebind a port that a previous process left in TIME_WAIT. Without it, repeated development restarts on the same address can fail with "Address already in use" even though no process is listening. Document the BSD/macOS side effect noted by moonbitlang/async: with reuse_addr enabled, a specific-address bind may steal an interface from a wildcard bind and vice versa. Co-Authored-By: Claude --- mocket.native.mbt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mocket.native.mbt b/mocket.native.mbt index a863180..ef07897 100644 --- a/mocket.native.mbt +++ b/mocket.native.mbt @@ -478,6 +478,14 @@ async fn handle_websocket_request( } ///| +/// Listen and serve on `address`. +/// +/// The native listener enables `SO_REUSEADDR` (`reuse_addr=true`) so that a +/// process can immediately rebind a port that a previous process left in +/// `TIME_WAIT`. On macOS/BSD this has the side effect that a bind to a specific +/// address may "steal" the specific interface from an existing wildcard bind +/// (`0.0.0.0`), and a wildcard bind can bind to the remaining interfaces if a +/// specific-interface bind already exists. pub async fn listen_ffi(mocket : Mocket, address : String) -> Unit noraise { let address = normalize_listen_address(address) let addr = @socket.Addr::parse(address) catch { @@ -488,7 +496,7 @@ pub async fn listen_ffi(mocket : Mocket, address : String) -> Unit noraise { } let port = addr.port() register_ws_handler(mocket, port) - let server = @http.Server(addr) catch { + let server = @http.Server(addr, reuse_addr=true) catch { err => { println("mocket: failed to listen on \{address}: \{err}") return