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.acceptmaster
parent
07bee9da42
commit
8a8beefa36
|
@ -358,44 +358,13 @@ pub const Address = extern union {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn getUnixSocketInitFlags() u16 {
|
|
||||||
comptime {
|
|
||||||
var flags = 0;
|
|
||||||
switch (builtin.os.tag) {
|
|
||||||
.linux, .freebsd, .netbsd, .dragonfly => {
|
|
||||||
flags |= os.SOCK_CLOEXEC;
|
|
||||||
flags |= if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
|
||||||
},
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are primarily needed for UNIX-based platforms without
|
|
||||||
// SOCK_CLOEXEC and SOCK_NONBLOCK flags when creating sockets
|
|
||||||
// or accepting connections
|
|
||||||
fn setUnixSocketFlags(sock: os.fd_t) os.FcntlError!void {
|
|
||||||
var fdflags = try os.fcntl(sock, os.F_GETFD, 0);
|
|
||||||
fdflags |= os.FD_CLOEXEC;
|
|
||||||
_ = try os.fcntl(sock, os.F_SETFD, fdflags);
|
|
||||||
|
|
||||||
if (std.io.is_async) {
|
|
||||||
var flflags = try os.fcntl(sock, os.F_GETFL, 0);
|
|
||||||
flflags |= os.O_NONBLOCK;
|
|
||||||
_ = try os.fcntl(sock, os.F_SETFL, fdflags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn connectUnixSocket(path: []const u8) !fs.File {
|
pub fn connectUnixSocket(path: []const u8) !fs.File {
|
||||||
const flags = os.SOCK_STREAM | getUnixSocketInitFlags();
|
const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
||||||
const sockfd = try os.socket(os.AF_UNIX, flags, 0);
|
const sockfd = try os.socket(
|
||||||
|
os.AF_UNIX,
|
||||||
if (comptime builtin.os.tag.isDarwin()) {
|
os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block,
|
||||||
try setUnixSocketFlags(sockfd);
|
0,
|
||||||
}
|
);
|
||||||
|
|
||||||
errdefer os.close(sockfd);
|
errdefer os.close(sockfd);
|
||||||
|
|
||||||
var addr = try std.net.Address.initUnix(path);
|
var addr = try std.net.Address.initUnix(path);
|
||||||
|
@ -437,13 +406,9 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tcpConnectToAddress(address: Address) !fs.File {
|
pub fn tcpConnectToAddress(address: Address) !fs.File {
|
||||||
const sock_flags = os.SOCK_STREAM | getUnixSocketInitFlags();
|
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
||||||
|
const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
|
||||||
const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
|
const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
|
||||||
|
|
||||||
if (comptime builtin.os.tag.isDarwin()) {
|
|
||||||
try setUnixSocketFlags(sockfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
errdefer os.close(sockfd);
|
errdefer os.close(sockfd);
|
||||||
try os.connect(sockfd, &address.any, address.getOsSockLen());
|
try os.connect(sockfd, &address.any, address.getOsSockLen());
|
||||||
|
|
||||||
|
@ -1347,14 +1312,11 @@ pub const StreamServer = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen(self: *StreamServer, address: Address) !void {
|
pub fn listen(self: *StreamServer, address: Address) !void {
|
||||||
const flags = os.SOCK_STREAM | getUnixSocketInitFlags();
|
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
||||||
|
const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock;
|
||||||
const proto = if (address.any.family == os.AF_UNIX) @as(u32, 0) else os.IPPROTO_TCP;
|
const proto = if (address.any.family == os.AF_UNIX) @as(u32, 0) else os.IPPROTO_TCP;
|
||||||
const sockfd = try os.socket(address.any.family, flags, proto);
|
|
||||||
|
|
||||||
if (comptime builtin.os.tag.isDarwin()) {
|
|
||||||
try setUnixSocketFlags(sockfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const sockfd = try os.socket(address.any.family, sock_flags, proto);
|
||||||
self.sockfd = sockfd;
|
self.sockfd = sockfd;
|
||||||
errdefer {
|
errdefer {
|
||||||
os.close(sockfd);
|
os.close(sockfd);
|
||||||
|
@ -1412,20 +1374,12 @@ pub const StreamServer = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// If this function succeeds, the returned `Connection` is a caller-managed resource.
|
/// If this function succeeds, the returned `Connection` is a caller-managed resource.
|
||||||
pub fn accept(self: *StreamServer) !Connection {
|
pub fn accept(self: *StreamServer) AcceptError!Connection {
|
||||||
|
const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0;
|
||||||
|
const accept_flags = nonblock | os.SOCK_CLOEXEC;
|
||||||
var accepted_addr: Address = undefined;
|
var accepted_addr: Address = undefined;
|
||||||
var adr_len: os.socklen_t = @sizeOf(Address);
|
var adr_len: os.socklen_t = @sizeOf(Address);
|
||||||
var _accept: os.AcceptError!os.fd_t = undefined;
|
if (os.accept(self.sockfd.?, &accepted_addr.any, &adr_len, accept_flags)) |fd| {
|
||||||
|
|
||||||
if (comptime builtin.os.tag.isDarwin()) {
|
|
||||||
try setUnixSocketFlags(self.sockfd.?);
|
|
||||||
_accept = os.accept(self.sockfd.?, &accepted_addr.any, &adr_len);
|
|
||||||
} else {
|
|
||||||
const flags = getUnixSocketInitFlags();
|
|
||||||
_accept = os.accept4(self.sockfd.?, &accepted_addr.any, &adr_len, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_accept) |fd| {
|
|
||||||
return Connection{
|
return Connection{
|
||||||
.file = fs.File{ .handle = fd },
|
.file = fs.File{ .handle = fd },
|
||||||
.address = accepted_addr,
|
.address = accepted_addr,
|
||||||
|
|
112
lib/std/os.zig
112
lib/std/os.zig
|
@ -2159,9 +2159,20 @@ pub const SocketError = error{
|
||||||
} || UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
|
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);
|
const rc = system.socket(domain, socket_type, protocol);
|
||||||
switch (errno(rc)) {
|
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,
|
EACCES => return error.PermissionDenied,
|
||||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||||
EINVAL => return error.ProtocolFamilyNotAvailable,
|
EINVAL => return error.ProtocolFamilyNotAvailable,
|
||||||
|
@ -2281,41 +2292,6 @@ pub const AcceptError = error{
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
} || UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
/// 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(
|
|
||||||
/// 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,
|
|
||||||
/// If flags is 0, then `accept4` is the same as `accept`. 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.
|
|
||||||
/// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
|
|
||||||
/// 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
return try _accept(sockfd, addr, addr_size, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Accept a connection on a socket.
|
/// Accept a connection on a socket.
|
||||||
/// If the application has a global event loop enabled, EAGAIN is handled
|
/// If the application has a global event loop enabled, EAGAIN is handled
|
||||||
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
/// via the event loop. Otherwise EAGAIN results in error.WouldBlock.
|
||||||
|
@ -2335,26 +2311,31 @@ pub fn accept(
|
||||||
/// The returned address is truncated if the buffer provided is too small; in this case, `addr_size`
|
/// 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.
|
/// will return a value greater than was supplied to the call.
|
||||||
addr_size: *socklen_t,
|
addr_size: *socklen_t,
|
||||||
|
/// 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.
|
||||||
|
/// * `SOCK_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
|
||||||
|
/// description of the `O_CLOEXEC` flag in `open` for reasons why this may be useful.
|
||||||
|
flags: u32,
|
||||||
) AcceptError!fd_t {
|
) AcceptError!fd_t {
|
||||||
return try _accept(sockfd, addr, addr_size, 0);
|
const have_accept4 = comptime !std.Target.current.isDarwin();
|
||||||
}
|
assert(0 == (flags & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC))); // Unsupported flag(s)
|
||||||
|
|
||||||
fn _accept(sockfd: fd_t, addr: *sockaddr, addr_size: *socklen_t, flags: u32) AcceptError!fd_t {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const rc = func: {
|
const rc = if (have_accept4)
|
||||||
switch (comptime builtin.os.tag) {
|
system.accept4(sockfd, addr, addr_size, flags)
|
||||||
.linux, .freebsd, .netbsd, .dragonfly =>
|
else
|
||||||
break :func system.accept4(sockfd, addr, addr_size, flags),
|
system.accept(sockfd, addr, addr_size);
|
||||||
.ios, .macosx, .watchos, .tvos => {
|
|
||||||
assert(flags == 0);
|
|
||||||
break :func system.accept(sockfd, addr, addr_size);
|
|
||||||
},
|
|
||||||
else => @compileError("accept not available for target"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (errno(rc)) {
|
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,
|
EINTR => continue,
|
||||||
EAGAIN => if (std.event.Loop.instance) |loop| {
|
EAGAIN => if (std.event.Loop.instance) |loop| {
|
||||||
loop.waitUntilFdReadable(sockfd);
|
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{
|
pub const FlockError = error{
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
|
|
||||||
|
|
|
@ -764,6 +764,15 @@ pub const SOCK_RDM = 4;
|
||||||
pub const SOCK_SEQPACKET = 5;
|
pub const SOCK_SEQPACKET = 5;
|
||||||
pub const SOCK_MAXADDRLEN = 255;
|
pub const SOCK_MAXADDRLEN = 255;
|
||||||
|
|
||||||
|
/// Not actually supported by Darwin, but Zig supplies a shim.
|
||||||
|
/// This numerical value is not ABI-stable. It need only not conflict
|
||||||
|
/// with any other "SOCK_" bits.
|
||||||
|
pub const SOCK_CLOEXEC = 1 << 15;
|
||||||
|
/// Not actually supported by Darwin, but Zig supplies a shim.
|
||||||
|
/// This numerical value is not ABI-stable. It need only not conflict
|
||||||
|
/// with any other "SOCK_" bits.
|
||||||
|
pub const SOCK_NONBLOCK = 1 << 16;
|
||||||
|
|
||||||
pub const IPPROTO_ICMP = 1;
|
pub const IPPROTO_ICMP = 1;
|
||||||
pub const IPPROTO_ICMPV6 = 58;
|
pub const IPPROTO_ICMPV6 = 58;
|
||||||
pub const IPPROTO_TCP = 6;
|
pub const IPPROTO_TCP = 6;
|
||||||
|
|
Loading…
Reference in New Issue