| ... | @@ -2159,9 +2159,20 @@ pub const SocketError = error{ | ... | @@ -2159,9 +2159,20 @@ pub const SocketError = error{ |
| 2159 | } || UnexpectedError; | 2159 | } || UnexpectedError; |
| 2160 | | 2160 | |
| 2161 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t { | 2161 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t { |
| | 2162 | const have_sock_flags = comptime !std.Target.current.isDarwin(); |
| | 2163 | const filtered_sock_type = if (!have_sock_flags) |
| | 2164 | socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) |
| | 2165 | else |
| | 2166 | socket_type; |
| 2162 | const rc = system.socket(domain, socket_type, protocol); | 2167 | const rc = system.socket(domain, socket_type, protocol); |
| 2163 | switch (errno(rc)) { | 2168 | switch (errno(rc)) { |
| 2164 | 0 => return @intCast(fd_t, rc), | 2169 | 0 => { |
| | 2170 | const fd = @intCast(fd_t, rc); |
| | 2171 | if (!have_sock_flags and filtered_sock_type != socket_type) { |
| | 2172 | try setSockFlags(fd, socket_type); |
| | 2173 | } |
| | 2174 | return fd; |
| | 2175 | }, |
| 2165 | EACCES => return error.PermissionDenied, | 2176 | EACCES => return error.PermissionDenied, |
| 2166 | EAFNOSUPPORT => return error.AddressFamilyNotSupported, | 2177 | EAFNOSUPPORT => return error.AddressFamilyNotSupported, |
| 2167 | EINVAL => return error.ProtocolFamilyNotAvailable, | 2178 | EINVAL => return error.ProtocolFamilyNotAvailable, |
| ... | @@ -2284,7 +2295,7 @@ pub const AcceptError = error{ | ... | @@ -2284,7 +2295,7 @@ pub const AcceptError = error{ |
| 2284 | /// Accept a connection on a socket. | 2295 | /// Accept a connection on a socket. |
| 2285 | /// If the application has a global event loop enabled, EAGAIN is handled | 2296 | /// If the application has a global event loop enabled, EAGAIN is handled |
| 2286 | /// via the event loop. Otherwise EAGAIN results in error.WouldBlock. | 2297 | /// via the event loop. Otherwise EAGAIN results in error.WouldBlock. |
| 2287 | pub fn accept4( | 2298 | pub fn accept( |
| 2288 | /// This argument is a socket that has been created with `socket`, bound to a local address | 2299 | /// This argument is a socket that has been created with `socket`, bound to a local address |
| 2289 | /// with `bind`, and is listening for connections after a `listen`. | 2300 | /// with `bind`, and is listening for connections after a `listen`. |
| 2290 | sockfd: fd_t, | 2301 | sockfd: fd_t, |
| ... | @@ -2300,8 +2311,7 @@ pub fn accept4( | ... | @@ -2300,8 +2311,7 @@ pub fn accept4( |
| 2300 | /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` | 2311 | /// The returned address is truncated if the buffer provided is too small; in this case, `addr_size` |
| 2301 | /// will return a value greater than was supplied to the call. | 2312 | /// will return a value greater than was supplied to the call. |
| 2302 | addr_size: *socklen_t, | 2313 | addr_size: *socklen_t, |
| 2303 | /// If flags is 0, then `accept4` is the same as `accept`. The following values can be bitwise | 2314 | /// The following values can be bitwise ORed in flags to obtain different behavior: |
| 2304 | /// ORed in flags to obtain different behavior: | | |
| 2305 | /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`) | 2315 | /// * `SOCK_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the open file description (see `open`) |
| 2306 | /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve | 2316 | /// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve |
| 2307 | /// the same result. | 2317 | /// the same result. |
| ... | @@ -2309,12 +2319,24 @@ pub fn accept4( | ... | @@ -2309,12 +2319,24 @@ pub fn accept4( |
| 2309 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. | 2319 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. |
| 2310 | flags: u32, | 2320 | flags: u32, |
| 2311 | ) AcceptError!fd_t { | 2321 | ) AcceptError!fd_t { |
| | 2322 | const have_accept4 = comptime !std.Target.current.isDarwin(); |
| | 2323 | assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s) |
| | 2324 | |
| 2312 | while (true) { | 2325 | while (true) { |
| 2313 | const rc = system.accept4(sockfd, addr, addr_size, flags); | 2326 | const rc = if (have_accept4) |
| | 2327 | system.accept4(sockfd, addr, addr_size, flags) |
| | 2328 | else |
| | 2329 | system.accept(sockfd, addr, addr_size); |
| | 2330 | |
| 2314 | switch (errno(rc)) { | 2331 | switch (errno(rc)) { |
| 2315 | 0 => return @intCast(fd_t, rc), | 2332 | 0 => { |
| | 2333 | const fd = @intCast(fd_t, rc); |
| | 2334 | if (!have_accept4 and flags != 0) { |
| | 2335 | try setSockFlags(fd, flags); |
| | 2336 | } |
| | 2337 | return fd; |
| | 2338 | }, |
| 2316 | EINTR => continue, | 2339 | EINTR => continue, |
| 2317 | | | |
| 2318 | EAGAIN => if (std.event.Loop.instance) |loop| { | 2340 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 2319 | loop.waitUntilFdReadable(sockfd); | 2341 | loop.waitUntilFdReadable(sockfd); |
| 2320 | continue; | 2342 | continue; |
| ... | @@ -2333,7 +2355,6 @@ pub fn accept4( | ... | @@ -2333,7 +2355,6 @@ pub fn accept4( |
| 2333 | EOPNOTSUPP => unreachable, | 2355 | EOPNOTSUPP => unreachable, |
| 2334 | EPROTO => return error.ProtocolFailure, | 2356 | EPROTO => return error.ProtocolFailure, |
| 2335 | EPERM => return error.BlockedByFirewall, | 2357 | EPERM => return error.BlockedByFirewall, |
| 2336 | | | |
| 2337 | else => |err| return unexpectedErrno(err), | 2358 | else => |err| return unexpectedErrno(err), |
| 2338 | } | 2359 | } |
| 2339 | } | 2360 | } |
| ... | @@ -3245,6 +3266,35 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { | ... | @@ -3245,6 +3266,35 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { |
| 3245 | } | 3266 | } |
| 3246 | } | 3267 | } |
| 3247 | | 3268 | |
| | 3269 | fn setSockFlags(fd: fd_t, flags: u32) !void { |
| | 3270 | { |
| | 3271 | var fd_flags = fcntl(fd, F_GETFD, 0) catch |err| switch (err) { |
| | 3272 | error.FileBusy => unreachable, |
| | 3273 | error.Locked => unreachable, |
| | 3274 | else => |e| return e, |
| | 3275 | }; |
| | 3276 | if ((flags & SOCK_NONBLOCK) != 0) fd_flags |= FD_CLOEXEC; |
| | 3277 | _ = fcntl(fd, F_SETFD, fd_flags) catch |err| switch (err) { |
| | 3278 | error.FileBusy => unreachable, |
| | 3279 | error.Locked => unreachable, |
| | 3280 | else => |e| return e, |
| | 3281 | }; |
| | 3282 | } |
| | 3283 | { |
| | 3284 | var fl_flags = fcntl(fd, F_GETFL, 0) catch |err| switch (err) { |
| | 3285 | error.FileBusy => unreachable, |
| | 3286 | error.Locked => unreachable, |
| | 3287 | else => |e| return e, |
| | 3288 | }; |
| | 3289 | if ((flags & SOCK_CLOEXEC) != 0) fl_flags |= O_NONBLOCK; |
| | 3290 | _ = fcntl(fd, F_SETFL, fl_flags) catch |err| switch (err) { |
| | 3291 | error.FileBusy => unreachable, |
| | 3292 | error.Locked => unreachable, |
| | 3293 | else => |e| return e, |
| | 3294 | }; |
| | 3295 | } |
| | 3296 | } |
| | 3297 | |
| 3248 | pub const FlockError = error{ | 3298 | pub const FlockError = error{ |
| 3249 | WouldBlock, | 3299 | WouldBlock, |
| 3250 | | 3300 | |