Commit 529064856a
lib/std/net/test.zig
@@ -230,6 +230,27 @@ test "listen on ipv4 try connect on ipv6 then ipv4" {
try await client_frame;
}
+test "listen on an in use port" {
+ if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) {
+ // TODO build abstractions for other operating systems
+ return error.SkipZigTest;
+ }
+
+ const localhost = try net.Address.parseIp("127.0.0.1", 0);
+
+ var server1 = net.StreamServer.init(net.StreamServer.Options{
+ .reuse_port = true,
+ });
+ defer server1.deinit();
+ try server1.listen(localhost);
+
+ var server2 = net.StreamServer.init(net.StreamServer.Options{
+ .reuse_port = true,
+ });
+ defer server2.deinit();
+ try server2.listen(server1.listen_address);
+}
+
fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
lib/std/net.zig
@@ -1867,6 +1867,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,
@@ -1881,6 +1882,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
@@ -1890,6 +1894,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,
};
}
@@ -1920,6 +1925,14 @@ pub const StreamServer = struct {
&mem.toBytes(@as(c_int, 1)),
);
}
+ if (@hasDecl(os.SO, "REUSEPORT") and 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);