authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-30 19:36:43-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-30 19:36:43-05:00
log86ba8c06bff84ac4865cef18080fa64fe946cb11
tree0460754507f6112ee4dcb59d7dfd2d98c7a42d66
parent73e535e1125d76bcd4e85123defea8b76412ab09
parent99f6f8ead90d36eab9b50fc1f2792a2bdfab8867
signature Commit is signed but in an unrecognized format.

Merge branch 'lun-4-net-reuseaddr-opt'

Closes #3820

3 files changed, 47 insertions(+), 1 deletions(-)

lib/std/c.zig+2-1
...@@ -120,7 +120,8 @@ pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;...@@ -120,7 +120,8 @@ pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
120pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;120pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
121pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;121pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
122pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;122pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;
123pub extern "c" fn getsockopt(sockfd: fd_t, level: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int;123pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: *c_void, optlen: *socklen_t) c_int;
124pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: *c_void, optlen: socklen_t) c_int;
124pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;125pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;
125pub extern "c" fn sendto(126pub extern "c" fn sendto(
126 sockfd: fd_t,127 sockfd: fd_t,
lib/std/net.zig+14
...@@ -1279,6 +1279,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)...@@ -1279,6 +1279,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
1279pub const StreamServer = struct {1279pub const StreamServer = struct {
1280 /// Copied from `Options` on `init`.1280 /// Copied from `Options` on `init`.
1281 kernel_backlog: u32,1281 kernel_backlog: u32,
1282 reuse_address: bool,
12821283
1283 /// `undefined` until `listen` returns successfully.1284 /// `undefined` until `listen` returns successfully.
1284 listen_address: Address,1285 listen_address: Address,
...@@ -1290,6 +1291,9 @@ pub const StreamServer = struct {...@@ -1290,6 +1291,9 @@ pub const StreamServer = struct {
1290 /// If more than this many connections pool in the kernel, clients will start1291 /// If more than this many connections pool in the kernel, clients will start
1291 /// seeing "Connection refused".1292 /// seeing "Connection refused".
1292 kernel_backlog: u32 = 128,1293 kernel_backlog: u32 = 128,
1294
1295 /// Enable SO_REUSEADDR on the socket.
1296 reuse_address: bool = false,
1293 };1297 };
12941298
1295 /// After this call succeeds, resources have been acquired and must1299 /// After this call succeeds, resources have been acquired and must
...@@ -1298,6 +1302,7 @@ pub const StreamServer = struct {...@@ -1298,6 +1302,7 @@ pub const StreamServer = struct {
1298 return StreamServer{1302 return StreamServer{
1299 .sockfd = null,1303 .sockfd = null,
1300 .kernel_backlog = options.kernel_backlog,1304 .kernel_backlog = options.kernel_backlog,
1305 .reuse_address = options.reuse_address,
1301 .listen_address = undefined,1306 .listen_address = undefined,
1302 };1307 };
1303 }1308 }
...@@ -1320,6 +1325,15 @@ pub const StreamServer = struct {...@@ -1320,6 +1325,15 @@ pub const StreamServer = struct {
1320 self.sockfd = null;1325 self.sockfd = null;
1321 }1326 }
13221327
1328 if (self.reuse_address) {
1329 try os.setsockopt(
1330 self.sockfd.?,
1331 os.SOL_SOCKET,
1332 os.SO_REUSEADDR,
1333 &mem.toBytes(@as(c_int, 1)),
1334 );
1335 }
1336
1323 var socklen = address.getOsSockLen();1337 var socklen = address.getOsSockLen();
1324 try os.bind(sockfd, &address.any, socklen);1338 try os.bind(sockfd, &address.any, socklen);
1325 try os.listen(sockfd, self.kernel_backlog);1339 try os.listen(sockfd, self.kernel_backlog);
lib/std/os.zig+31
...@@ -3250,3 +3250,34 @@ pub fn sched_yield() SchedYieldError!void {...@@ -3250,3 +3250,34 @@ pub fn sched_yield() SchedYieldError!void {
3250 else => return error.SystemCannotYield,3250 else => return error.SystemCannotYield,
3251 }3251 }
3252}3252}
3253
3254pub const SetSockOptError = error{
3255 /// The socket is already connected, and a specified option cannot be set while the socket is connected.
3256 AlreadyConnected,
3257
3258 /// The option is not supported by the protocol.
3259 InvalidProtocolOption,
3260
3261 /// The send and receive timeout values are too big to fit into the timeout fields in the socket structure.
3262 TimeoutTooBig,
3263
3264 /// Insufficient resources are available in the system to complete the call.
3265 SystemResources,
3266} || UnexpectedError;
3267
3268/// Set a socket's options.
3269pub fn setsockopt(fd: fd_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
3270 switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {
3271 0 => {},
3272 EBADF => unreachable, // always a race condition
3273 ENOTSOCK => unreachable, // always a race condition
3274 EINVAL => unreachable,
3275 EFAULT => unreachable,
3276 EDOM => return error.TimeoutTooBig,
3277 EISCONN => return error.AlreadyConnected,
3278 ENOPROTOOPT => return error.InvalidProtocolOption,
3279 ENOMEM => return error.SystemResources,
3280 ENOBUFS => return error.SystemResources,
3281 else => |err| return unexpectedErrno(err),
3282 }
3283}