diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-05-02 17:36:28 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-05-02 17:36:28 -0400 |
| commit | 8a8beefa36da8257a328a86340d0d60e1bd569a6 (patch) | |
| tree | 5bd6f42f9338830975c02fe102bdcf1213944450 /lib/std/os.zig | |
| parent | 07bee9da42977420916ca0f1044b47fab4a694dc (diff) | |
| download | zig-8a8beefa36da8257a328a86340d0d60e1bd569a6.tar.gz zig-8a8beefa36da8257a328a86340d0d60e1bd569a6.zip | |
solve the problem with Darwin shims in std.os instead
* implement SOCK_NONBLOCK and SOCK_CLOEXEC Darwin shims in std.os
* revert changes to std.net
* remove os.accept and rename os.accept4 to os.accept
Diffstat (limited to 'lib/std/os.zig')
| -rw-r--r-- | lib/std/os.zig | 102 |
1 files changed, 56 insertions, 46 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig index 99dee13dd0..ff7089ceb0 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2159,9 +2159,20 @@ pub const SocketError = error{ } || UnexpectedError; pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t { + const have_sock_flags = comptime !std.Target.current.isDarwin(); + const filtered_sock_type = if (!have_sock_flags) + socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) + else + socket_type; const rc = system.socket(domain, socket_type, protocol); switch (errno(rc)) { - 0 => return @intCast(fd_t, rc), + 0 => { + const fd = @intCast(fd_t, rc); + if (!have_sock_flags and filtered_sock_type != socket_type) { + try setSockFlags(fd, socket_type); + } + return fd; + }, EACCES => return error.PermissionDenied, EAFNOSUPPORT => return error.AddressFamilyNotSupported, EINVAL => return error.ProtocolFamilyNotAvailable, @@ -2284,7 +2295,7 @@ pub const AcceptError = error{ /// Accept a connection on a socket. /// If the application has a global event loop enabled, EAGAIN is handled /// via the event loop. Otherwise EAGAIN results in error.WouldBlock. -pub fn accept4( +pub fn accept( /// This argument is a socket that has been created with `socket`, bound to a local address /// with `bind`, and is listening for connections after a `listen`. sockfd: fd_t, @@ -2300,8 +2311,7 @@ pub fn accept4( /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` /// will return a value greater than was supplied to the call. addr_size: *socklen_t, - /// If flags is 0, then `accept4` is the same as `accept`. The following values can be bitwise - /// ORed in flags to obtain different behavior: + /// The following values can be bitwise ORed in flags to obtain different behavior: /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`) /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve /// the same result. @@ -2309,52 +2319,23 @@ pub fn accept4( /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. flags: u32, ) AcceptError!fd_t { - if (comptime builtin.os.tag.isDarwin()) { - @compileError("accept4 not available for target Darwin, use accept"); - } + const have_accept4 = comptime !std.Target.current.isDarwin(); + assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s) - return try _accept(sockfd, addr, addr_size, flags); -} - -/// Accept a connection on a socket. -/// If the application has a global event loop enabled, EAGAIN is handled -/// via the event loop. Otherwise EAGAIN results in error.WouldBlock. -pub fn accept( - /// This argument is a socket that has been created with `socket`, bound to a local address - /// with `bind`, and is listening for connections after a `listen`. - sockfd: fd_t, - /// This argument is a pointer to a sockaddr structure. This structure is filled in with the - /// address of the peer socket, as known to the communications layer. The exact format of the - /// address returned addr is determined by the socket's address family (see `socket` and the - /// respective protocol man pages). - addr: *sockaddr, - /// This argument is a value-result argument: the caller must initialize it to contain the - /// size (in bytes) of the structure pointed to by addr; on return it will contain the actual size - /// of the peer address. - /// - /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` - /// will return a value greater than was supplied to the call. - addr_size: *socklen_t, -) AcceptError!fd_t { - return try _accept(sockfd, addr, addr_size, 0); -} - -fn _accept(sockfd: fd_t, addr: *sockaddr, addr_size: *socklen_t, flags: u32) AcceptError!fd_t { while (true) { - const rc = func: { - switch (comptime builtin.os.tag) { - .linux, .freebsd, .netbsd, .dragonfly => - break :func system.accept4(sockfd, addr, addr_size, flags), - .ios, .macosx, .watchos, .tvos => { - assert(flags == 0); - break :func system.accept(sockfd, addr, addr_size); - }, - else => @compileError("accept not available for target"), - } - }; + const rc = if (have_accept4) + system.accept4(sockfd, addr, addr_size, flags) + else + system.accept(sockfd, addr, addr_size); switch (errno(rc)) { - 0 => return @intCast(fd_t, rc), + 0 => { + const fd = @intCast(fd_t, rc); + if (!have_accept4 and flags != 0) { + try setSockFlags(fd, flags); + } + return fd; + }, EINTR => continue, EAGAIN => if (std.event.Loop.instance) |loop| { loop.waitUntilFdReadable(sockfd); @@ -3285,6 +3266,35 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { } } +fn setSockFlags(fd: fd_t, flags: u32) !void { + { + var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + if ((flags & SOCK_NONBLOCK) != 0) fd_flags |= FD_CLOEXEC; + _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + } + { + var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + if ((flags & SOCK_CLOEXEC) != 0) fl_flags |= O_NONBLOCK; + _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) { + error.FileBusy => unreachable, + error.Locked => unreachable, + else => |e| return e, + }; + } +} + pub const FlockError = error{ WouldBlock, |
