zig icon indicating copy to clipboard operation
zig copied to clipboard

std.net.StreamServer does not support port reuse

Open yyds-page opened this issue 3 years ago • 2 comments

Zig Version

0.9.1

Steps to Reproduce

  1. 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.", .{});
}
  1. build
zig build
  1. 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);
    ^

yyds-page avatar Mar 31 '22 07:03 yyds-page

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 avatar Mar 31 '22 13:03 komuw

@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

amirrezaask avatar Mar 31 '22 17:03 amirrezaask