zig
zig copied to clipboard
std.net.StreamServer does not support port reuse
Zig Version
0.9.1
Steps to Reproduce
- code
main.zig:
const std = @import("std");
const StreamServer = std.net.StreamServer;
const Address = std.net.Address;
pub fn main() anyerror!void {
var server = StreamServer.init(.{
.reuse_address = true,
});
defer server.deinit();
var addr = try Address.parseIp("127.0.0.1", 8080);
try server.listen(addr);
while (true) {
//do sth.
std.time.sleep(1*std.time.ns_per_s);
}
std.log.info("ok.", .{});
}
- build
zig build
- run
./zig-out/bin/streamServerPortReuse &
./zig-out/bin/streamServerPortReuse
Expected Behavior
Multiple instances can run without error.
StreamServer can accept reuse_port parameter.
const std = @import("std");
const StreamServer = std.net.StreamServer;
const Address = std.net.Address;
pub fn main() anyerror!void {
var server = StreamServer.init(.{
.reuse_address = true,
.reuse_port = true, // FIXME:
});
defer server.deinit();
var addr = try Address.parseIp("127.0.0.1", 8080);
try server.listen(addr);
while (true) {
//do sth.
std.time.sleep(1*std.time.ns_per_s);
}
std.log.info("ok.", .{});
}
After patching /opt/homebrew/Cellar/zig/0.9.1/lib/zig/std/net.zig, it accepts reuse_port parameter and works as expected.
diff --git a/net.zig b/net.zig
index f564a9d..942a79b 100644
--- a/net.zig
+++ b/net.zig
@@ -1706,6 +1706,7 @@ pub const StreamServer = struct {
/// Copied from `Options` on `init`.
kernel_backlog: u31,
reuse_address: bool,
+ reuse_port: bool,
/// `undefined` until `listen` returns successfully.
listen_address: Address,
@@ -1720,6 +1721,9 @@ pub const StreamServer = struct {
/// Enable SO.REUSEADDR on the socket.
reuse_address: bool = false,
+
+ /// Enable SO.REUSEPORT on the socket.
+ reuse_port: bool = false,
};
/// After this call succeeds, resources have been acquired and must
@@ -1729,6 +1733,7 @@ pub const StreamServer = struct {
.sockfd = null,
.kernel_backlog = options.kernel_backlog,
.reuse_address = options.reuse_address,
+ .reuse_port = options.reuse_port,
.listen_address = undefined,
};
}
@@ -1759,6 +1764,14 @@ pub const StreamServer = struct {
&mem.toBytes(@as(c_int, 1)),
);
}
+ if (self.reuse_port) {
+ try os.setsockopt(
+ sockfd,
+ os.SOL.SOCKET,
+ os.SO.REUSEPORT,
+ &mem.toBytes(@as(c_int, 1)),
+ );
+ }
var socklen = address.getOsSockLen();
try os.bind(sockfd, &address.any, socklen);
Actual Behavior
The first instance works, but the second instance fails.
aka@akadeMacBook-Pro streamServerPortReuse% ./zig-out/bin/streamServerPortReuse &
[1] 15826
aka@akadeMacBook-Pro streamServerPortReuse %
aka@akadeMacBook-Pro streamServerPortReuse % ./zig-out/bin/streamServerPortReuse
error: AddressInUse
/opt/homebrew/Cellar/zig/0.9.1/lib/zig/std/os.zig:3135:27: 0x10291c51b in std.os.bind (streamServerPortReuse)
.ADDRINUSE => return error.AddressInUse,
^
/opt/homebrew/Cellar/zig/0.9.1/lib/zig/std/net.zig:1764:9: 0x10291958b in std.net.StreamServer.listen (streamServerPortReuse)
try os.bind(sockfd, &address.any, socklen);
^
/Users/aka/github/streamServerPortReuse/src/main.zig:13:5: 0x1029190a3 in main (streamServerPortReuse)
try server.listen(addr);
^
cc @amirrezaask I think this is one of the issues you were facing in your Live Coding A Web Server in Zig video series.
And while you are here, kudos for doing that series. It is interesting seeing someone new to Zig just intuiting their way around.
@komuw I am not sure if this is the problem that I have, I am suspecting that in case of crashes my program does not stop listening but maybe this issue is also related. 😅 i wanted to write stuff in zig and since there wasn't much content online I said let's give it a try, thanks for your kindness, really appreciate it, I hope I can continue it with other projects as well