| author | |
| committer | |
| log | 529064856a2e5466c890869f786b73442bc5c84b |
| tree | bc9cdd56a16c6c94d75721c84657a2d5a42c661d |
| parent | 2be347a2c88e435079333773fc30b8e967cc7068 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
2 files changed, 34 insertions(+), 0 deletions(-)
lib/std/net.zig+13| ... | ... | @@ -1867,6 +1867,7 @@ pub const StreamServer = struct { |
| 1867 | 1867 | /// Copied from `Options` on `init`. |
| 1868 | 1868 | kernel_backlog: u31, |
| 1869 | 1869 | reuse_address: bool, |
| 1870 | reuse_port: bool, | |
| 1870 | 1871 | |
| 1871 | 1872 | /// `undefined` until `listen` returns successfully. |
| 1872 | 1873 | listen_address: Address, |
| ... | ... | @@ -1881,6 +1882,9 @@ pub const StreamServer = struct { |
| 1881 | 1882 | |
| 1882 | 1883 | /// Enable SO.REUSEADDR on the socket. |
| 1883 | 1884 | reuse_address: bool = false, |
| 1885 | ||
| 1886 | /// Enable SO.REUSEPORT on the socket. | |
| 1887 | reuse_port: bool = false, | |
| 1884 | 1888 | }; |
| 1885 | 1889 | |
| 1886 | 1890 | /// After this call succeeds, resources have been acquired and must |
| ... | ... | @@ -1890,6 +1894,7 @@ pub const StreamServer = struct { |
| 1890 | 1894 | .sockfd = null, |
| 1891 | 1895 | .kernel_backlog = options.kernel_backlog, |
| 1892 | 1896 | .reuse_address = options.reuse_address, |
| 1897 | .reuse_port = options.reuse_port, | |
| 1893 | 1898 | .listen_address = undefined, |
| 1894 | 1899 | }; |
| 1895 | 1900 | } |
| ... | ... | @@ -1920,6 +1925,14 @@ pub const StreamServer = struct { |
| 1920 | 1925 | &mem.toBytes(@as(c_int, 1)), |
| 1921 | 1926 | ); |
| 1922 | 1927 | } |
| 1928 | if (@hasDecl(os.SO, "REUSEPORT") and self.reuse_port) { | |
| 1929 | try os.setsockopt( | |
| 1930 | sockfd, | |
| 1931 | os.SOL.SOCKET, | |
| 1932 | os.SO.REUSEPORT, | |
| 1933 | &mem.toBytes(@as(c_int, 1)), | |
| 1934 | ); | |
| 1935 | } | |
| 1923 | 1936 | |
| 1924 | 1937 | var socklen = address.getOsSockLen(); |
| 1925 | 1938 | try os.bind(sockfd, &address.any, socklen); |
lib/std/net/test.zig+21| ... | ... | @@ -230,6 +230,27 @@ test "listen on ipv4 try connect on ipv6 then ipv4" { |
| 230 | 230 | try await client_frame; |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | test "listen on an in use port" { | |
| 234 | if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) { | |
| 235 | // TODO build abstractions for other operating systems | |
| 236 | return error.SkipZigTest; | |
| 237 | } | |
| 238 | ||
| 239 | const localhost = try net.Address.parseIp("127.0.0.1", 0); | |
| 240 | ||
| 241 | var server1 = net.StreamServer.init(net.StreamServer.Options{ | |
| 242 | .reuse_port = true, | |
| 243 | }); | |
| 244 | defer server1.deinit(); | |
| 245 | try server1.listen(localhost); | |
| 246 | ||
| 247 | var server2 = net.StreamServer.init(net.StreamServer.Options{ | |
| 248 | .reuse_port = true, | |
| 249 | }); | |
| 250 | defer server2.deinit(); | |
| 251 | try server2.listen(server1.listen_address); | |
| 252 | } | |
| 253 | ||
| 233 | 254 | fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void { |
| 234 | 255 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 235 | 256 |