aboutsummaryrefslogtreecommitdiff
path: root/src/io/io_darwin.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-01-23 23:00:15 -0800
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-01-23 23:00:15 -0800
commitde0cf421115ed3814ccc4d46e4d6202aac792ba0 (patch)
tree8c3f609e9497c30ae2f7512a5b5d7b8e0d37595f /src/io/io_darwin.zig
parentec9e4eb97e0633e508606af9d18e76a3c63647da (diff)
downloadbun-de0cf421115ed3814ccc4d46e4d6202aac792ba0.tar.gz
bun-de0cf421115ed3814ccc4d46e4d6202aac792ba0.tar.zst
bun-de0cf421115ed3814ccc4d46e4d6202aac792ba0.zip
Use non-cancellable syscalls for HTTP & use errno for errors
Diffstat (limited to 'src/io/io_darwin.zig')
-rw-r--r--src/io/io_darwin.zig532
1 files changed, 503 insertions, 29 deletions
diff --git a/src/io/io_darwin.zig b/src/io/io_darwin.zig
index c072cd4bd..97ccd6d23 100644
--- a/src/io/io_darwin.zig
+++ b/src/io/io_darwin.zig
@@ -15,9 +15,383 @@ const os = struct {
pub const EOVERFLOW = 84;
pub const ESPIPE = 29;
};
+
+const SystemErrno = @import("../darwin_c.zig").SystemErrno;
+pub const Errno = error{
+ EPERM,
+ ENOENT,
+ ESRCH,
+ EINTR,
+ EIO,
+ ENXIO,
+ E2BIG,
+ ENOEXEC,
+ EBADF,
+ ECHILD,
+ EDEADLK,
+ ENOMEM,
+ EACCES,
+ EFAULT,
+ ENOTBLK,
+ EBUSY,
+ EEXIST,
+ EXDEV,
+ ENODEV,
+ ENOTDIR,
+ EISDIR,
+ EINVAL,
+ ENFILE,
+ EMFILE,
+ ENOTTY,
+ ETXTBSY,
+ EFBIG,
+ ENOSPC,
+ ESPIPE,
+ EROFS,
+ EMLINK,
+ EPIPE,
+ EDOM,
+ ERANGE,
+ EAGAIN,
+ EINPROGRESS,
+ EALREADY,
+ ENOTSOCK,
+ EDESTADDRREQ,
+ EMSGSIZE,
+ EPROTOTYPE,
+ ENOPROTOOPT,
+ EPROTONOSUPPORT,
+ ESOCKTNOSUPPORT,
+ ENOTSUP,
+ EPFNOSUPPORT,
+ EAFNOSUPPORT,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ ENETDOWN,
+ ENETUNREACH,
+ ENETRESET,
+ ECONNABORTED,
+ ECONNRESET,
+ ENOBUFS,
+ EISCONN,
+ ENOTCONN,
+ ESHUTDOWN,
+ ETOOMANYREFS,
+ ETIMEDOUT,
+ ECONNREFUSED,
+ ELOOP,
+ ENAMETOOLONG,
+ EHOSTDOWN,
+ EHOSTUNREACH,
+ ENOTEMPTY,
+ EPROCLIM,
+ EUSERS,
+ EDQUOT,
+ ESTALE,
+ EREMOTE,
+ EBADRPC,
+ ERPCMISMATCH,
+ EPROGUNAVAIL,
+ EPROGMISMATCH,
+ EPROCUNAVAIL,
+ ENOLCK,
+ ENOSYS,
+ EFTYPE,
+ EAUTH,
+ ENEEDAUTH,
+ EPWROFF,
+ EDEVERR,
+ EOVERFLOW,
+ EBADEXEC,
+ EBADARCH,
+ ESHLIBVERS,
+ EBADMACHO,
+ ECANCELED,
+ EIDRM,
+ ENOMSG,
+ EILSEQ,
+ ENOATTR,
+ EBADMSG,
+ EMULTIHOP,
+ ENODATA,
+ ENOLINK,
+ ENOSR,
+ ENOSTR,
+ EPROTO,
+ ETIME,
+ EOPNOTSUPP,
+ ENOPOLICY,
+ ENOTRECOVERABLE,
+ EOWNERDEAD,
+ EQFULL,
+ Unexpected,
+};
+
+const errno_map: [108]Errno = brk: {
+ var errors: [108]Errno = undefined;
+ errors[1] = error.EPERM;
+ errors[2] = error.ENOENT;
+ errors[3] = error.ESRCH;
+ errors[4] = error.EINTR;
+ errors[5] = error.EIO;
+ errors[6] = error.ENXIO;
+ errors[7] = error.E2BIG;
+ errors[8] = error.ENOEXEC;
+ errors[9] = error.EBADF;
+ errors[10] = error.ECHILD;
+ errors[11] = error.EDEADLK;
+ errors[12] = error.ENOMEM;
+ errors[13] = error.EACCES;
+ errors[14] = error.EFAULT;
+ errors[15] = error.ENOTBLK;
+ errors[16] = error.EBUSY;
+ errors[17] = error.EEXIST;
+ errors[18] = error.EXDEV;
+ errors[19] = error.ENODEV;
+ errors[20] = error.ENOTDIR;
+ errors[21] = error.EISDIR;
+ errors[22] = error.EINVAL;
+ errors[23] = error.ENFILE;
+ errors[24] = error.EMFILE;
+ errors[25] = error.ENOTTY;
+ errors[26] = error.ETXTBSY;
+ errors[27] = error.EFBIG;
+ errors[28] = error.ENOSPC;
+ errors[29] = error.ESPIPE;
+ errors[30] = error.EROFS;
+ errors[31] = error.EMLINK;
+ errors[32] = error.EPIPE;
+ errors[33] = error.EDOM;
+ errors[34] = error.ERANGE;
+ errors[35] = error.EAGAIN;
+ errors[36] = error.EINPROGRESS;
+ errors[37] = error.EALREADY;
+ errors[38] = error.ENOTSOCK;
+ errors[39] = error.EDESTADDRREQ;
+ errors[40] = error.EMSGSIZE;
+ errors[41] = error.EPROTOTYPE;
+ errors[42] = error.ENOPROTOOPT;
+ errors[43] = error.EPROTONOSUPPORT;
+ errors[44] = error.ESOCKTNOSUPPORT;
+ errors[45] = error.ENOTSUP;
+ errors[46] = error.EPFNOSUPPORT;
+ errors[47] = error.EAFNOSUPPORT;
+ errors[48] = error.EADDRINUSE;
+ errors[49] = error.EADDRNOTAVAIL;
+ errors[50] = error.ENETDOWN;
+ errors[51] = error.ENETUNREACH;
+ errors[52] = error.ENETRESET;
+ errors[53] = error.ECONNABORTED;
+ errors[54] = error.ECONNRESET;
+ errors[55] = error.ENOBUFS;
+ errors[56] = error.EISCONN;
+ errors[57] = error.ENOTCONN;
+ errors[58] = error.ESHUTDOWN;
+ errors[59] = error.ETOOMANYREFS;
+ errors[60] = error.ETIMEDOUT;
+ errors[61] = error.ECONNREFUSED;
+ errors[62] = error.ELOOP;
+ errors[63] = error.ENAMETOOLONG;
+ errors[64] = error.EHOSTDOWN;
+ errors[65] = error.EHOSTUNREACH;
+ errors[66] = error.ENOTEMPTY;
+ errors[67] = error.EPROCLIM;
+ errors[68] = error.EUSERS;
+ errors[69] = error.EDQUOT;
+ errors[70] = error.ESTALE;
+ errors[71] = error.EREMOTE;
+ errors[72] = error.EBADRPC;
+ errors[73] = error.ERPCMISMATCH;
+ errors[74] = error.EPROGUNAVAIL;
+ errors[75] = error.EPROGMISMATCH;
+ errors[76] = error.EPROCUNAVAIL;
+ errors[77] = error.ENOLCK;
+ errors[78] = error.ENOSYS;
+ errors[79] = error.EFTYPE;
+ errors[80] = error.EAUTH;
+ errors[81] = error.ENEEDAUTH;
+ errors[82] = error.EPWROFF;
+ errors[83] = error.EDEVERR;
+ errors[84] = error.EOVERFLOW;
+ errors[85] = error.EBADEXEC;
+ errors[86] = error.EBADARCH;
+ errors[87] = error.ESHLIBVERS;
+ errors[88] = error.EBADMACHO;
+ errors[89] = error.ECANCELED;
+ errors[90] = error.EIDRM;
+ errors[91] = error.ENOMSG;
+ errors[92] = error.EILSEQ;
+ errors[93] = error.ENOATTR;
+ errors[94] = error.EBADMSG;
+ errors[95] = error.EMULTIHOP;
+ errors[96] = error.ENODATA;
+ errors[97] = error.ENOLINK;
+ errors[98] = error.ENOSR;
+ errors[99] = error.ENOSTR;
+ errors[100] = error.EPROTO;
+ errors[101] = error.ETIME;
+ errors[102] = error.EOPNOTSUPP;
+ errors[103] = error.ENOPOLICY;
+ errors[104] = error.ENOTRECOVERABLE;
+ errors[105] = error.EOWNERDEAD;
+ errors[106] = error.EQFULL;
+ break :brk errors;
+};
+
+const socket_t = os.socket_t;
+const sockaddr = darwin.sockaddr;
+const socklen_t = darwin.socklen_t;
+const system = darwin;
+
+pub fn asError(err: anytype) Errno {
+ return switch (@enumToInt(err)) {
+ 1...errno_map.len => |val| errno_map[@intCast(u8, val)],
+ else => error.Unexpected,
+ };
+}
+const fd_t = os.fd_t;
+
const mem = std.mem;
const assert = std.debug.assert;
const c = std.c;
+const darwin = struct {
+ pub usingnamespace os.darwin;
+ pub extern "c" fn @"recvfrom$NOCANCEL"(sockfd: c.fd_t, noalias buf: *anyopaque, len: usize, flags: u32, noalias src_addr: ?*c.sockaddr, noalias addrlen: ?*c.socklen_t) isize;
+ pub extern "c" fn @"sendto$NOCANCEL"(
+ sockfd: c.fd_t,
+ buf: *const anyopaque,
+ len: usize,
+ flags: u32,
+ dest_addr: ?*const c.sockaddr,
+ addrlen: c.socklen_t,
+ ) isize;
+ pub extern "c" fn @"fcntl$NOCANCEL"(fd: c.fd_t, cmd: c_int, ...) c_int;
+ pub extern "c" fn @"sendmsg$NOCANCEL"(sockfd: c.fd_t, msg: *const std.x.os.Socket.Message, flags: c_int) isize;
+ pub extern "c" fn @"recvmsg$NOCANCEL"(sockfd: c.fd_t, msg: *std.x.os.Socket.Message, flags: c_int) isize;
+ pub extern "c" fn @"connect$NOCANCEL"(sockfd: c.fd_t, sock_addr: *const c.sockaddr, addrlen: c.socklen_t) c_int;
+ pub extern "c" fn @"accept$NOCANCEL"(sockfd: c.fd_t, noalias addr: ?*c.sockaddr, noalias addrlen: ?*c.socklen_t) c_int;
+ pub extern "c" fn @"accept4$NOCANCEL"(sockfd: c.fd_t, noalias addr: ?*c.sockaddr, noalias addrlen: ?*c.socklen_t, flags: c_uint) c_int;
+};
+
+pub const Syscall = struct {
+ pub fn close(fd: std.os.fd_t) CloseError!void {
+ return switch (darwin.getErrno(darwin.@"close$NOCANCEL"(fd))) {
+ .SUCCESS => void{},
+ .BADF => error.FileDescriptorInvalid,
+ .IO => error.InputOutput,
+ else => |err| asError(err),
+ };
+ }
+
+ pub const SocketError = error{
+ /// Permission to create a socket of the specified type and/or
+ /// pro‐tocol is denied.
+ PermissionDenied,
+
+ /// The implementation does not support the specified address family.
+ AddressFamilyNotSupported,
+
+ /// Unknown protocol, or protocol family not available.
+ ProtocolFamilyNotAvailable,
+
+ /// The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
+
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
+
+ /// Insufficient memory is available. The socket cannot be created until sufficient
+ /// resources are freed.
+ SystemResources,
+
+ /// The protocol type or the specified protocol is not supported within this domain.
+ ProtocolNotSupported,
+
+ /// The socket type is not supported by the protocol.
+ SocketTypeNotSupported,
+ } || Errno;
+ const SOCK = os.SOCK;
+ const FD_CLOEXEC = os.FD_CLOEXEC;
+ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) Errno!usize {
+ const rc = darwin.@"fcntl$NOCANCEL"(fd, cmd, arg);
+ return switch (darwin.getErrno(rc)) {
+ .SUCCESS => @intCast(usize, rc),
+ else => |err| asError(err),
+ };
+ }
+
+ const F = std.os.F;
+ const O = std.os.O;
+ pub fn setSockFlags(sock: socket_t, flags: u32) !void {
+ if ((flags & SOCK.CLOEXEC) != 0) {
+ var fd_flags = try fcntl(sock, F.GETFD, 0);
+ fd_flags |= FD_CLOEXEC;
+ _ = try fcntl(sock, F.SETFD, fd_flags);
+ }
+
+ if ((flags & SOCK.NONBLOCK) != 0) {
+ var fl_flags = try fcntl(sock, F.GETFL, 0);
+ fl_flags |= O.NONBLOCK;
+ _ = try fcntl(sock, F.SETFL, fl_flags);
+ }
+ }
+
+ pub const SetSockOptError = error{
+ /// The socket is already connected, and a specified option cannot be set while the socket is connected.
+ AlreadyConnected,
+
+ /// The option is not supported by the protocol.
+ InvalidProtocolOption,
+
+ /// The send and receive timeout values are too big to fit into the timeout fields in the socket structure.
+ TimeoutTooBig,
+
+ /// Insufficient resources are available in the system to complete the call.
+ SystemResources,
+
+ // Setting the socket option requires more elevated permissions.
+ PermissionDenied,
+
+ NetworkSubsystemFailed,
+ FileDescriptorNotASocket,
+ SocketNotBound,
+ } || Errno;
+
+ pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
+ switch (darwin.getErrno(darwin.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {
+ .SUCCESS => {},
+ .DOM => return error.TimeoutTooBig,
+ .ISCONN => return error.AlreadyConnected,
+ .NOPROTOOPT => return error.InvalidProtocolOption,
+ .NOMEM => return error.SystemResources,
+ .NOBUFS => return error.SystemResources,
+ .PERM => return error.PermissionDenied,
+ else => |err| return asError(err),
+ }
+ }
+
+ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {
+ const filtered_sock_type = socket_type & ~@as(u32, os.SOCK.NONBLOCK | os.SOCK.CLOEXEC);
+ const rc = darwin.socket(domain, filtered_sock_type, protocol);
+ switch (darwin.getErrno(rc)) {
+ .SUCCESS => {
+ const fd = @intCast(fd_t, rc);
+ try setSockFlags(fd, socket_type);
+ return fd;
+ },
+ .ACCES => return error.PermissionDenied,
+ .AFNOSUPPORT => return error.AddressFamilyNotSupported,
+ .INVAL => return error.ProtocolFamilyNotAvailable,
+ .MFILE => return error.ProcessFdQuotaExceeded,
+ .NFILE => return error.SystemFdQuotaExceeded,
+ .NOBUFS => return error.SystemResources,
+ .NOMEM => return error.SystemResources,
+ .PROTONOSUPPORT => return error.ProtocolNotSupported,
+ .PROTOTYPE => return error.SocketTypeNotSupported,
+ else => |err| return asError(err),
+ }
+ }
+};
const FIFO = @import("./fifo.zig").FIFO;
const Time = @import("./time.zig").Time;
@@ -217,7 +591,7 @@ fn flush_timeouts(self: *IO) ?u64 {
const timeout_ns = expires - now;
if (min_timeout) |min_ns| {
- min_timeout = std.math.min(min_ns, timeout_ns);
+ min_timeout = @minimum(min_ns, timeout_ns);
} else {
min_timeout = timeout_ns;
}
@@ -296,7 +670,7 @@ fn submit(
const result = OperationImpl.doOperation(op_data);
// Requeue onto io_pending if error.WouldBlock
- switch (operation_tag) {
+ switch (comptime operation_tag) {
.accept, .connect, .read, .write, .send, .recv => {
_ = result catch |err| switch (err) {
error.WouldBlock => {
@@ -423,11 +797,13 @@ pub fn accept(
null,
os.SOCK.NONBLOCK | os.SOCK.CLOEXEC,
);
- errdefer os.close(fd);
+ errdefer {
+ Syscall.close(fd) catch {};
+ }
// darwin doesn't support os.MSG.NOSIGNAL,
// but instead a socket option to avoid SIGPIPE.
- os.setsockopt(fd, os.SOL_SOCKET, os.SO_NOSIGPIPE, &mem.toBytes(@as(c_int, 1))) catch |err| return switch (err) {
+ Syscall.setsockopt(fd, os.SOL_SOCKET, os.SO_NOSIGPIPE, &mem.toBytes(@as(c_int, 1))) catch |err| return switch (err) {
error.TimeoutTooBig => unreachable,
error.PermissionDenied => error.NetworkSubsystemFailed,
error.AlreadyConnected => error.NetworkSubsystemFailed,
@@ -446,7 +822,7 @@ pub const CloseError = error{
DiskQuota,
InputOutput,
NoSpaceLeft,
-} || os.UnexpectedError;
+} || Errno;
pub fn close(
self: *IO,
@@ -470,19 +846,25 @@ pub fn close(
},
struct {
fn doOperation(op: anytype) CloseError!void {
- return switch (os.system.close(op.fd)) {
- 0 => {},
- os.EBADF => error.FileDescriptorInvalid,
- os.EINTR => {}, // A success, see https://github.com/ziglang/zig/issues/2425
- os.EIO => error.InputOutput,
- else => |errno| os.unexpectedErrno(os.errno(errno)),
- };
+ return Syscall.close(op.fd);
}
},
);
}
-pub const ConnectError = os.ConnectError;
+pub const ConnectError = error{
+ AddressFamilyNotSupported,
+ AddressInUse,
+ AddressNotAvailable,
+ ConnectionPending,
+ ConnectionRefused,
+ ConnectionResetByPeer,
+ ConnectionTimedOut,
+ NetworkUnreachable,
+ PermissionDenied,
+ SystemResources,
+ WouldBlock,
+} || Errno;
pub fn connect(
self: *IO,
@@ -491,7 +873,7 @@ pub fn connect(
comptime callback: fn (
context: Context,
completion: *Completion,
- result: ConnectError!void,
+ result: IO.ConnectError!void,
) void,
completion: *Completion,
socket: os.socket_t,
@@ -508,12 +890,53 @@ pub fn connect(
.initiated = false,
},
struct {
- fn doOperation(op: anytype) ConnectError!void {
+ fn doOperation(op: anytype) IO.ConnectError!void {
// Don't call connect after being rescheduled by io_pending as it gives EISCONN.
// Instead, check the socket error to see if has been connected successfully.
const result = switch (op.initiated) {
- true => os.getsockoptError(op.socket),
- else => os.connect(op.socket, &op.address.any, op.address.getOsSockLen()),
+ true => brk: {
+ var err_code: i32 = undefined;
+ var size: u32 = @sizeOf(u32);
+ const rc = system.getsockopt(op.socket, os.SOL.SOCKET, os.SO.ERROR, @ptrCast([*]u8, &err_code), &size);
+ assert(size == 4);
+ break :brk switch (darwin.getErrno(rc)) {
+ .SUCCESS => switch (@intToEnum(os.E, err_code)) {
+ .SUCCESS => void{},
+ .ACCES => error.PermissionDenied,
+ .PERM => error.PermissionDenied,
+ .ADDRINUSE => error.AddressInUse,
+ .ADDRNOTAVAIL => error.AddressNotAvailable,
+ .AFNOSUPPORT => error.AddressFamilyNotSupported,
+ .AGAIN => error.SystemResources,
+ .ALREADY => error.ConnectionPending,
+ .CONNREFUSED => error.ConnectionRefused,
+ // .FAULT => unreachable, // The socket structure address is outside the user's address space.
+ // .ISCONN => unreachable, // The socket is already connected.
+ .NETUNREACH => error.NetworkUnreachable,
+ // .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ // .PROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ .TIMEDOUT => error.ConnectionTimedOut,
+ .CONNRESET => error.ConnectionResetByPeer,
+ else => |err| asError(err),
+ },
+ else => |err| asError(err),
+ };
+ },
+ else => switch (darwin.getErrno(darwin.@"connect$NOCANCEL"(op.socket, &op.address.any, op.address.getOsSockLen()))) {
+ .SUCCESS => void{},
+ .ACCES => error.PermissionDenied,
+ .PERM => error.PermissionDenied,
+ .ADDRINUSE => error.AddressInUse,
+ .ADDRNOTAVAIL => error.AddressNotAvailable,
+ .AFNOSUPPORT => error.AddressFamilyNotSupported,
+ .AGAIN, .INPROGRESS => error.WouldBlock,
+ .ALREADY => error.ConnectionPending,
+ .CONNREFUSED => error.ConnectionRefused,
+ .CONNRESET => error.ConnectionResetByPeer,
+ .NETUNREACH => error.NetworkUnreachable,
+ .TIMEDOUT => error.ConnectionTimedOut,
+ else => |err| asError(err),
+ },
};
op.initiated = true;
@@ -562,7 +985,7 @@ pub const ReadError = error{
IsDir,
SystemResources,
Unseekable,
-} || os.UnexpectedError;
+} || Errno;
pub fn read(
self: *IO,
@@ -604,7 +1027,6 @@ pub fn read(
os.EAGAIN => error.WouldBlock,
os.EBADF => error.NotOpenForReading,
os.ECONNRESET => error.ConnectionResetByPeer,
- os.EFAULT => unreachable,
os.EINVAL => error.Alignment,
os.EIO => error.InputOutput,
os.EISDIR => error.IsDir,
@@ -613,7 +1035,7 @@ pub fn read(
os.ENXIO => error.Unseekable,
os.EOVERFLOW => error.Unseekable,
os.ESPIPE => error.Unseekable,
- else => error.Unexpected,
+ else => |err| asError(err),
};
}
}
@@ -621,7 +1043,12 @@ pub fn read(
);
}
-pub const RecvError = os.RecvFromError;
+pub const RecvError = error{
+ SystemResources,
+ ConnectionRefused,
+ ConnectionResetByPeer,
+ WouldBlock,
+} || Errno;
pub fn recv(
self: *IO,
@@ -648,13 +1075,37 @@ pub fn recv(
},
struct {
fn doOperation(op: anytype) RecvError!usize {
- return os.recv(op.socket, op.buf[0..op.len], 0);
+ const rc = system.@"recvfrom$NOCANCEL"(op.socket, op.buf, op.len, 0, null, null);
+ return switch (system.getErrno(rc)) {
+ .SUCCESS => @intCast(usize, rc),
+ .AGAIN => error.WouldBlock,
+ .NOMEM => error.SystemResources,
+ .CONNREFUSED => error.ConnectionRefused,
+ .CONNRESET => error.ConnectionResetByPeer,
+ else => |err| asError(err),
+ };
}
},
);
}
-pub const SendError = os.SendToError;
+pub const SendError = error{
+ AccessDenied,
+ AddressFamilyNotSupported,
+ BrokenPipe,
+ ConnectionResetByPeer,
+ FastOpenAlreadyInProgress,
+ FileNotFound,
+ MessageTooBig,
+ NameTooLong,
+ NetworkSubsystemFailed,
+ NetworkUnreachable,
+ NotDir,
+ SocketNotConnected,
+ SymLinkLoop,
+ SystemResources,
+ WouldBlock,
+} || Errno;
pub fn send(
self: *IO,
@@ -683,13 +1134,34 @@ pub fn send(
},
struct {
fn doOperation(op: anytype) SendError!usize {
- return os.sendto(op.socket, op.buf[0..op.len], op.flags, null, 0);
+ const rc = system.@"sendto$NOCANCEL"(op.socket, op.buf, op.len, op.flags, null, 0);
+ return switch (system.getErrno(rc)) {
+ .SUCCESS => @intCast(usize, rc),
+ .ACCES => error.AccessDenied,
+ .AGAIN => error.WouldBlock,
+ .ALREADY => error.FastOpenAlreadyInProgress,
+ .CONNRESET => error.ConnectionResetByPeer,
+ .MSGSIZE => error.MessageTooBig,
+ .NOBUFS => error.SystemResources,
+ .NOMEM => error.SystemResources,
+ .PIPE => error.BrokenPipe,
+ .AFNOSUPPORT => error.AddressFamilyNotSupported,
+ .LOOP => error.SymLinkLoop,
+ .NAMETOOLONG => error.NameTooLong,
+ .NOENT => error.FileNotFound,
+ .NOTDIR => error.NotDir,
+ .HOSTUNREACH => error.NetworkUnreachable,
+ .NETUNREACH => error.NetworkUnreachable,
+ .NOTCONN => error.SocketNotConnected,
+ .NETDOWN => error.NetworkSubsystemFailed,
+ else => |err| asError(err),
+ };
}
},
);
}
-pub const TimeoutError = error{Canceled} || os.UnexpectedError;
+pub const TimeoutError = error{Canceled} || Errno;
pub fn timeout(
self: *IO,
@@ -755,11 +1227,13 @@ pub fn write(
}
pub fn openSocket(family: u32, sock_type: u32, protocol: u32) !os.socket_t {
- const fd = try os.socket(family, sock_type | os.SOCK.NONBLOCK, protocol);
- errdefer os.close(fd);
+ const fd = try Syscall.socket(family, sock_type | os.SOCK.NONBLOCK, protocol);
+ errdefer {
+ Syscall.close(fd) catch {};
+ }
// darwin doesn't support os.MSG.NOSIGNAL, but instead a socket option to avoid SIGPIPE.
- try os.setsockopt(fd, os.SOL.SOCKET, os.SO.NOSIGPIPE, &mem.toBytes(@as(c_int, 1)));
+ try Syscall.setsockopt(fd, os.SOL.SOCKET, os.SO.NOSIGPIPE, &mem.toBytes(@as(c_int, 1)));
return fd;
}
@@ -775,7 +1249,7 @@ fn buffer_limit(buffer_len: usize) usize {
.macos, .ios, .watchos, .tvos => std.math.maxInt(i32),
else => std.math.maxInt(isize),
};
- return std.math.min(limit, buffer_len);
+ return @minimum(limit, buffer_len);
}
pub var global: IO = undefined;