| 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 | 131 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; |
| 132 | 132 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; |
| 133 | 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 | 135 | pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; |
| 135 | 136 | pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int; |
| 136 | 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 | 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 | 391 | pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 362 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | |
| 363 | const sockfd = try os.socket( | |
| 364 | os.AF_UNIX, | |
| 365 | os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block, | |
| 366 | 0, | |
| 367 | ); | |
| 392 | const flags = os.SOCK_STREAM | getUnixSocketInitFlags(); | |
| 393 | const sockfd = try os.socket(os.AF_UNIX, flags, 0); | |
| 394 | ||
| 395 | if (comptime builtin.os.tag.isDarwin()) { | |
| 396 | try setUnixSocketFlags(sockfd); | |
| 397 | } | |
| 398 | ||
| 368 | 399 | errdefer os.close(sockfd); |
| 369 | 400 | |
| 370 | 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 | 437 | } |
| 407 | 438 | |
| 408 | 439 | pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 409 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | |
| 410 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | |
| 440 | const sock_flags = os.SOCK_STREAM | getUnixSocketInitFlags(); | |
| 411 | 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 | 447 | errdefer os.close(sockfd); |
| 413 | 448 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| 414 | 449 | |
| ... | ... | @@ -1312,11 +1347,14 @@ pub const StreamServer = struct { |
| 1312 | 1347 | } |
| 1313 | 1348 | |
| 1314 | 1349 | pub fn listen(self: *StreamServer, address: Address) !void { |
| 1315 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | |
| 1316 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | |
| 1350 | const flags = os.SOCK_STREAM | getUnixSocketInitFlags(); | |
| 1317 | 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 | 1358 | self.sockfd = sockfd; |
| 1321 | 1359 | errdefer { |
| 1322 | 1360 | os.close(sockfd); |
| ... | ... | @@ -1374,12 +1412,20 @@ pub const StreamServer = struct { |
| 1374 | 1412 | }; |
| 1375 | 1413 | |
| 1376 | 1414 | /// If this function succeeds, the returned `Connection` is a caller-managed resource. |
| 1377 | pub fn accept(self: *StreamServer) AcceptError!Connection { | |
| 1378 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | |
| 1379 | const accept_flags = nonblock | os.SOCK_CLOEXEC; | |
| 1415 | pub fn accept(self: *StreamServer) !Connection { | |
| 1380 | 1416 | var accepted_addr: Address = undefined; |
| 1381 | 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 | 1429 | return Connection{ |
| 1384 | 1430 | .file = fs.File{ .handle = fd }, |
| 1385 | 1431 | .address = accepted_addr, |
lib/std/os.zig+43-3| ... | ... | @@ -2309,12 +2309,53 @@ pub fn accept4( |
| 2309 | 2309 | /// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful. |
| 2310 | 2310 | flags: u32, |
| 2311 | 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 | 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 | 2356 | switch (errno(rc)) { |
| 2315 | 2357 | 0 => return @intCast(fd_t, rc), |
| 2316 | 2358 | EINTR => continue, |
| 2317 | ||
| 2318 | 2359 | EAGAIN => if (std.event.Loop.instance) |loop| { |
| 2319 | 2360 | loop.waitUntilFdReadable(sockfd); |
| 2320 | 2361 | continue; |
| ... | ... | @@ -2333,7 +2374,6 @@ pub fn accept4( |
| 2333 | 2374 | EOPNOTSUPP => unreachable, |
| 2334 | 2375 | EPROTO => return error.ProtocolFailure, |
| 2335 | 2376 | EPERM => return error.BlockedByFirewall, |
| 2336 | ||
| 2337 | 2377 | else => |err| return unexpectedErrno(err), |
| 2338 | 2378 | } |
| 2339 | 2379 | } |