| author | |
| committer | |
| log | 07bee9da42977420916ca0f1044b47fab4a694dc |
| tree | 88cab3ee6234abf5a7022da6f12bca6a497cf007 |
| parent | 03a7124543a52f7904090516e572b71b893c7ba2 |
3 files changed, 105 insertions(+), 18 deletions(-)
lib/std/c.zig+1| ... | @@ -131,6 +131,7 @@ pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint | ... | @@ -131,6 +131,7 @@ pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint |
| 131 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; | 131 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; |
| 132 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; | 132 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; |
| 133 | pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; | 133 | pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; |
| 134 | pub extern "c" fn accept(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) c_int; | ||
| 134 | pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; | 135 | pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; |
| 135 | pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int; | 136 | pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int; |
| 136 | pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int; | 137 | pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int; |
lib/std/net.zig+61-15| ... | @@ -358,13 +358,44 @@ pub const Address = extern union { | ... | @@ -358,13 +358,44 @@ pub const Address = extern union { |
| 358 | } | 358 | } |
| 359 | }; | 359 | }; |
| 360 | 360 | ||
| 361 | fn getUnixSocketInitFlags() u16 { | ||
| 362 | comptime { | ||
| 363 | var flags = 0; | ||
| 364 | switch (builtin.os.tag) { | ||
| 365 | .linux, .freebsd, .netbsd, .dragonfly => { | ||
| 366 | flags |= os.SOCK_CLOEXEC; | ||
| 367 | flags |= if (std.io.is_async) os.SOCK_NONBLOCK else 0; | ||
| 368 | }, | ||
| 369 | else => {}, | ||
| 370 | } | ||
| 371 | |||
| 372 | return flags; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | // These are primarily needed for UNIX-based platforms without | ||
| 377 | // SOCK_CLOEXEC and SOCK_NONBLOCK flags when creating sockets | ||
| 378 | // or accepting connections | ||
| 379 | fn setUnixSocketFlags(sock: os.fd_t) os.FcntlError!void { | ||
| 380 | var fdflags = try os.fcntl(sock, os.F_GETFD, 0); | ||
| 381 | fdflags |= os.FD_CLOEXEC; | ||
| 382 | _ = try os.fcntl(sock, os.F_SETFD, fdflags); | ||
| 383 | |||
| 384 | if (std.io.is_async) { | ||
| 385 | var flflags = try os.fcntl(sock, os.F_GETFL, 0); | ||
| 386 | flflags |= os.O_NONBLOCK; | ||
| 387 | _ = try os.fcntl(sock, os.F_SETFL, fdflags); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 361 | pub fn connectUnixSocket(path: []const u8) !fs.File { | 391 | pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 362 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 392 | const flags = os.SOCK_STREAM | getUnixSocketInitFlags(); |
| 363 | const sockfd = try os.socket( | 393 | const sockfd = try os.socket(os.AF_UNIX, flags, 0); |
| 364 | os.AF_UNIX, | 394 | |
| 365 | os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block, | 395 | if (comptime builtin.os.tag.isDarwin()) { |
| 366 | 0, | 396 | try setUnixSocketFlags(sockfd); |
| 367 | ); | 397 | } |
| 398 | |||
| 368 | errdefer os.close(sockfd); | 399 | errdefer os.close(sockfd); |
| 369 | 400 | ||
| 370 | var addr = try std.net.Address.initUnix(path); | 401 | var addr = try std.net.Address.initUnix(path); |
| ... | @@ -406,9 +437,13 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) | ... | @@ -406,9 +437,13 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 406 | } | 437 | } |
| 407 | 438 | ||
| 408 | pub fn tcpConnectToAddress(address: Address) !fs.File { | 439 | pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 409 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 440 | const sock_flags = os.SOCK_STREAM | getUnixSocketInitFlags(); |
| 410 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | ||
| 411 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); | 441 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); |
| 442 | |||
| 443 | if (comptime builtin.os.tag.isDarwin()) { | ||
| 444 | try setUnixSocketFlags(sockfd); | ||
| 445 | } | ||
| 446 | |||
| 412 | errdefer os.close(sockfd); | 447 | errdefer os.close(sockfd); |
| 413 | try os.connect(sockfd, &address.any, address.getOsSockLen()); | 448 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| 414 | 449 | ||
| ... | @@ -1312,11 +1347,14 @@ pub const StreamServer = struct { | ... | @@ -1312,11 +1347,14 @@ pub const StreamServer = struct { |
| 1312 | } | 1347 | } |
| 1313 | 1348 | ||
| 1314 | pub fn listen(self: *StreamServer, address: Address) !void { | 1349 | pub fn listen(self: *StreamServer, address: Address) !void { |
| 1315 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 1350 | const flags = os.SOCK_STREAM | getUnixSocketInitFlags(); |
| 1316 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | ||
| 1317 | const proto = if (address.any.family == os.AF_UNIX) @as(u32, 0) else os.IPPROTO_TCP; | 1351 | const proto = if (address.any.family == os.AF_UNIX) @as(u32, 0) else os.IPPROTO_TCP; |
| 1352 | const sockfd = try os.socket(address.any.family, flags, proto); | ||
| 1353 | |||
| 1354 | if (comptime builtin.os.tag.isDarwin()) { | ||
| 1355 | try setUnixSocketFlags(sockfd); | ||
| 1356 | } | ||
| 1318 | 1357 | ||
| 1319 | const sockfd = try os.socket(address.any.family, sock_flags, proto); | ||
| 1320 | self.sockfd = sockfd; | 1358 | self.sockfd = sockfd; |
| 1321 | errdefer { | 1359 | errdefer { |
| 1322 | os.close(sockfd); | 1360 | os.close(sockfd); |
| ... | @@ -1374,12 +1412,20 @@ pub const StreamServer = struct { | ... | @@ -1374,12 +1412,20 @@ pub const StreamServer = struct { |
| 1374 | }; | 1412 | }; |
| 1375 | 1413 | ||
| 1376 | /// If this function succeeds, the returned `Connection` is a caller-managed resource. | 1414 | /// If this function succeeds, the returned `Connection` is a caller-managed resource. |
| 1377 | pub fn accept(self: *StreamServer) AcceptError!Connection { | 1415 | pub fn accept(self: *StreamServer) !Connection { |
| 1378 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | ||
| 1379 | const accept_flags = nonblock | os.SOCK_CLOEXEC; | ||
| 1380 | var accepted_addr: Address = undefined; | 1416 | var accepted_addr: Address = undefined; |
| 1381 | var adr_len: os.socklen_t = @sizeOf(Address); | 1417 | var adr_len: os.socklen_t = @sizeOf(Address); |
| 1382 | if (os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| { | 1418 | var _accept: os.AcceptError!os.fd_t = undefined; |
| 1419 | |||
| 1420 | if (comptime builtin.os.tag.isDarwin()) { | ||
| 1421 | try setUnixSocketFlags(self.sockfd.?); | ||
| 1422 | _accept = os.accept(self.sockfd.?, &accepted_addr.any, &adr_len); | ||
| 1423 | } else { | ||
| 1424 | const flags = getUnixSocketInitFlags(); | ||
| 1425 | _accept = os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, flags); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | if (_accept) |fd| { | ||
| 1383 | return Connection{ | 1429 | return Connection{ |
| 1384 | .file = fs.File{ .handle = fd }, | 1430 | .file = fs.File{ .handle = fd }, |
| 1385 | .address = accepted_addr, | 1431 | .address = accepted_addr, |
lib/std/os.zig+43-3| ... | @@ -2309,12 +2309,53 @@ pub fn accept4( | ... | @@ -2309,12 +2309,53 @@ pub fn accept4( |
| 2309 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. | 2309 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. |
| 2310 | flags: u32, | 2310 | flags: u32, |
| 2311 | ) AcceptError!fd_t { | 2311 | ) AcceptError!fd_t { |
| 2312 | if (comptime builtin.os.tag.isDarwin()) { | ||
| 2313 | @compileError("accept4 not available for target Darwin, use accept"); | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | return try _accept(sockfd, addr, addr_size, flags); | ||
| 2317 | } | ||
| 2318 | |||
| 2319 | /// Accept a connection on a socket. | ||
| 2320 | /// If the application has a global event loop enabled, EAGAIN is handled | ||
| 2321 | /// via the event loop. Otherwise EAGAIN results in error.WouldBlock. | ||
| 2322 | pub fn accept( | ||
| 2323 | /// This argument is a socket that has been created with `socket`, bound to a local address | ||
| 2324 | /// with `bind`, and is listening for connections after a `listen`. | ||
| 2325 | sockfd: fd_t, | ||
| 2326 | /// This argument is a pointer to a sockaddr structure. This structure is filled in with the | ||
| 2327 | /// address of the peer socket, as known to the communications layer. The exact format of the | ||
| 2328 | /// address returned addr is determined by the socket's address family (see `socket` and the | ||
| 2329 | /// respective protocol man pages). | ||
| 2330 | addr: *sockaddr, | ||
| 2331 | /// This argument is a value-result argument: the caller must initialize it to contain the | ||
| 2332 | /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size | ||
| 2333 | /// of the peer address. | ||
| 2334 | /// | ||
| 2335 | /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` | ||
| 2336 | /// will return a value greater than was supplied to the call. | ||
| 2337 | addr_size: *socklen_t, | ||
| 2338 | ) AcceptError!fd_t { | ||
| 2339 | return try _accept(sockfd, addr, addr_size, 0); | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | fn _accept(sockfd: fd_t, addr: *sockaddr, addr_size: *socklen_t, flags: u32) AcceptError!fd_t { | ||
| 2312 | while (true) { | 2343 | while (true) { |
| 2313 | const rc = system.accept4(sockfd, addr, addr_size, flags); | 2344 | const rc = func: { |
| 2345 | switch (comptime builtin.os.tag) { | ||
| 2346 | .linux, .freebsd, .netbsd, .dragonfly => | ||
| 2347 | break :func system.accept4(sockfd, addr, addr_size, flags), | ||
| 2348 | .ios, .macosx, .watchos, .tvos => { | ||
| 2349 | assert(flags == 0); | ||
| 2350 | break :func system.accept(sockfd, addr, addr_size); | ||
| 2351 | }, | ||
| 2352 | else => @compileError("accept not available for target"), | ||
| 2353 | } | ||
| 2354 | }; | ||
| 2355 | |||
| 2314 | switch (errno(rc)) { | 2356 | switch (errno(rc)) { |
| 2315 | 0 => return @intCast(fd_t, rc), | 2357 | 0 => return @intCast(fd_t, rc), |
| 2316 | EINTR => continue, | 2358 | EINTR => continue, |
| 2317 | |||
| 2318 | EAGAIN => if (std.event.Loop.instance) |loop| { | 2359 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 2319 | loop.waitUntilFdReadable(sockfd); | 2360 | loop.waitUntilFdReadable(sockfd); |
| 2320 | continue; | 2361 | continue; |
| ... | @@ -2333,7 +2374,6 @@ pub fn accept4( | ... | @@ -2333,7 +2374,6 @@ pub fn accept4( |
| 2333 | EOPNOTSUPP => unreachable, | 2374 | EOPNOTSUPP => unreachable, |
| 2334 | EPROTO => return error.ProtocolFailure, | 2375 | EPROTO => return error.ProtocolFailure, |
| 2335 | EPERM => return error.BlockedByFirewall, | 2376 | EPERM => return error.BlockedByFirewall, |
| 2336 | |||
| 2337 | else => |err| return unexpectedErrno(err), | 2377 | else => |err| return unexpectedErrno(err), |
| 2338 | } | 2378 | } |
| 2339 | } | 2379 | } |