| author | |
| committer | |
| log | a6347a68a94b80c5b3e79a9bea3d7711a8f013a6 |
| tree | 8803c98eb34e38eaf56ca06a29be8b921b65450e |
| parent | 961961cf85618083702799ef60f9f77dec806774 |
10 files changed, 457 insertions(+), 145 deletions(-)
lib/std/Io.zig+109-22| ... | ... | @@ -665,14 +665,14 @@ pub const VTable = struct { |
| 665 | 665 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, |
| 666 | 666 | fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void, |
| 667 | 667 | |
| 668 | now: *const fn (?*anyopaque, clockid: std.posix.clockid_t) NowError!Timestamp, | |
| 669 | sleep: *const fn (?*anyopaque, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void, | |
| 668 | now: *const fn (?*anyopaque, Timestamp.Clock) Timestamp.Error!i96, | |
| 669 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, | |
| 670 | 670 | |
| 671 | 671 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, |
| 672 | 672 | accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Stream, |
| 673 | 673 | ipBind: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket, |
| 674 | netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) net.Socket.SendError!void, | |
| 675 | netReceive: *const fn (?*anyopaque, handle: net.Socket.Handle, buffer: []u8, timeout: Timeout) net.Socket.ReceiveTimeoutError!net.ReceivedMessage, | |
| 674 | netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) net.SendResult, | |
| 675 | netReceive: *const fn (?*anyopaque, net.Socket.Handle, message_buffer: []net.IncomingMessage, data_buffer: []u8, net.ReceiveFlags, Timeout) struct { ?net.Socket.ReceiveTimeoutError, usize }, | |
| 676 | 676 | netRead: *const fn (?*anyopaque, src: net.Stream, data: [][]u8) net.Stream.Reader.Error!usize, |
| 677 | 677 | netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, |
| 678 | 678 | netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void, |
| ... | ... | @@ -700,46 +700,135 @@ pub const UnexpectedError = error{ |
| 700 | 700 | pub const Dir = @import("Io/Dir.zig"); |
| 701 | 701 | pub const File = @import("Io/File.zig"); |
| 702 | 702 | |
| 703 | pub const Timestamp = enum(i96) { | |
| 704 | _, | |
| 703 | pub const Timestamp = struct { | |
| 704 | nanoseconds: i96, | |
| 705 | clock: Clock, | |
| 706 | ||
| 707 | pub const Clock = enum { | |
| 708 | /// A settable system-wide clock that measures real (i.e. wall-clock) | |
| 709 | /// time. This clock is affected by discontinuous jumps in the system | |
| 710 | /// time (e.g., if the system administrator manually changes the | |
| 711 | /// clock), and by frequency adjust‐ ments performed by NTP and similar | |
| 712 | /// applications. | |
| 713 | /// This clock normally counts the number of seconds since | |
| 714 | /// 1970-01-01 00:00:00 Coordinated Universal Time (UTC) except that it | |
| 715 | /// ignores leap seconds; near a leap second it is typically | |
| 716 | /// adjusted by NTP to stay roughly in sync with UTC. | |
| 717 | realtime, | |
| 718 | /// A nonsettable system-wide clock that represents time since some | |
| 719 | /// unspecified point in the past. | |
| 720 | /// | |
| 721 | /// On Linux, corresponds to how long the system has been running since | |
| 722 | /// it booted. | |
| 723 | /// | |
| 724 | /// Not affected by discontinuous jumps in the system time (e.g., if | |
| 725 | /// the system administrator manually changes the clock), but is | |
| 726 | /// affected by frequency adjustments. **This clock does not count time | |
| 727 | /// that the system is suspended.** | |
| 728 | /// | |
| 729 | /// Guarantees that the time returned by consecutive calls will not go | |
| 730 | /// backwards, but successive calls may return identical | |
| 731 | /// (not-increased) time values. | |
| 732 | monotonic, | |
| 733 | /// Identical to `monotonic` except it also includes any time that the | |
| 734 | /// system is suspended. | |
| 735 | boottime, | |
| 736 | }; | |
| 705 | 737 | |
| 706 | 738 | pub fn durationTo(from: Timestamp, to: Timestamp) Duration { |
| 707 | return .{ .nanoseconds = @intFromEnum(to) - @intFromEnum(from) }; | |
| 739 | assert(from.clock == to.clock); | |
| 740 | return .{ .nanoseconds = to.nanoseconds - from.nanoseconds }; | |
| 708 | 741 | } |
| 709 | 742 | |
| 710 | 743 | pub fn addDuration(from: Timestamp, duration: Duration) Timestamp { |
| 711 | return @enumFromInt(@intFromEnum(from) + duration.nanoseconds); | |
| 744 | return .{ | |
| 745 | .nanoseconds = from.nanoseconds + duration.nanoseconds, | |
| 746 | .clock = from.clock, | |
| 747 | }; | |
| 712 | 748 | } |
| 713 | 749 | |
| 714 | pub fn fromNow(io: Io, clockid: std.posix.clockid_t, duration: Duration) NowError!Timestamp { | |
| 715 | const now_ts = try now(io, clockid); | |
| 750 | pub const Error = error{UnsupportedClock} || UnexpectedError; | |
| 751 | ||
| 752 | /// This function is not cancelable because first of all it does not block, | |
| 753 | /// but more importantly, the cancelation logic itself may want to check | |
| 754 | /// the time. | |
| 755 | pub fn now(io: Io, clock: Clock) Error!Timestamp { | |
| 756 | return .{ | |
| 757 | .nanoseconds = try io.vtable.now(io.userdata, clock), | |
| 758 | .clock = clock, | |
| 759 | }; | |
| 760 | } | |
| 761 | ||
| 762 | pub fn fromNow(io: Io, clock: Clock, duration: Duration) Error!Timestamp { | |
| 763 | const now_ts = try now(io, clock); | |
| 716 | 764 | return addDuration(now_ts, duration); |
| 717 | 765 | } |
| 718 | 766 | |
| 767 | pub fn untilNow(timestamp: Timestamp, io: Io) Error!Duration { | |
| 768 | const now_ts = try Timestamp.now(io, timestamp.clock); | |
| 769 | return timestamp.durationTo(now_ts); | |
| 770 | } | |
| 771 | ||
| 772 | pub fn durationFromNow(timestamp: Timestamp, io: Io) Error!Duration { | |
| 773 | const now_ts = try now(io, timestamp.clock); | |
| 774 | return now_ts.durationTo(timestamp); | |
| 775 | } | |
| 776 | ||
| 777 | pub fn toClock(t: Timestamp, io: Io, clock: Clock) Error!Timestamp { | |
| 778 | if (t.clock == clock) return t; | |
| 779 | const now_old = try now(io, t.clock); | |
| 780 | const now_new = try now(io, clock); | |
| 781 | const duration = now_old.durationTo(t); | |
| 782 | return now_new.addDuration(duration); | |
| 783 | } | |
| 784 | ||
| 719 | 785 | pub fn compare(lhs: Timestamp, op: std.math.CompareOperator, rhs: Timestamp) bool { |
| 720 | return std.math.compare(@intFromEnum(lhs), op, @intFromEnum(rhs)); | |
| 786 | assert(lhs.clock == rhs.clock); | |
| 787 | return std.math.compare(lhs.nanoseconds, op, rhs.nanoseconds); | |
| 721 | 788 | } |
| 722 | 789 | }; |
| 790 | ||
| 723 | 791 | pub const Duration = struct { |
| 724 | 792 | nanoseconds: i96, |
| 725 | 793 | |
| 726 | pub fn ms(x: u64) Duration { | |
| 794 | pub fn fromMilliseconds(x: i64) Duration { | |
| 727 | 795 | return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_ms }; |
| 728 | 796 | } |
| 729 | 797 | |
| 730 | pub fn seconds(x: u64) Duration { | |
| 798 | pub fn fromSeconds(x: i64) Duration { | |
| 731 | 799 | return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_s }; |
| 732 | 800 | } |
| 801 | ||
| 802 | pub fn toMilliseconds(d: Duration) i64 { | |
| 803 | return @intCast(@divTrunc(d.nanoseconds, std.time.ns_per_ms)); | |
| 804 | } | |
| 805 | ||
| 806 | pub fn toSeconds(d: Duration) i64 { | |
| 807 | return @intCast(@divTrunc(d.nanoseconds, std.time.ns_per_s)); | |
| 808 | } | |
| 733 | 809 | }; |
| 810 | ||
| 811 | /// Declares under what conditions an operation should return `error.Timeout`. | |
| 734 | 812 | pub const Timeout = union(enum) { |
| 735 | 813 | none, |
| 736 | duration: Duration, | |
| 814 | duration: ClockAndDuration, | |
| 737 | 815 | deadline: Timestamp, |
| 738 | 816 | |
| 739 | pub const Error = error{Timeout}; | |
| 817 | pub const Error = error{ Timeout, UnsupportedClock }; | |
| 818 | ||
| 819 | pub const ClockAndDuration = struct { | |
| 820 | clock: Timestamp.Clock, | |
| 821 | duration: Duration, | |
| 822 | }; | |
| 823 | ||
| 824 | pub fn toDeadline(t: Timeout, io: Io) Timestamp.Error!?Timestamp { | |
| 825 | return switch (t) { | |
| 826 | .none => null, | |
| 827 | .duration => |d| try .fromNow(io, d.clock, d.duration), | |
| 828 | .deadline => |d| d, | |
| 829 | }; | |
| 830 | } | |
| 740 | 831 | }; |
| 741 | pub const NowError = std.posix.ClockGetTimeError || Cancelable; | |
| 742 | pub const SleepError = error{ UnsupportedClock, Unexpected, Canceled }; | |
| 743 | 832 | |
| 744 | 833 | pub const AnyFuture = opaque {}; |
| 745 | 834 | |
| ... | ... | @@ -1231,12 +1320,10 @@ pub fn cancelRequested(io: Io) bool { |
| 1231 | 1320 | return io.vtable.cancelRequested(io.userdata); |
| 1232 | 1321 | } |
| 1233 | 1322 | |
| 1234 | pub fn now(io: Io, clockid: std.posix.clockid_t) NowError!Timestamp { | |
| 1235 | return io.vtable.now(io.userdata, clockid); | |
| 1236 | } | |
| 1323 | pub const SleepError = error{UnsupportedClock} || UnexpectedError || Cancelable; | |
| 1237 | 1324 | |
| 1238 | pub fn sleep(io: Io, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void { | |
| 1239 | return io.vtable.sleep(io.userdata, clockid, timeout); | |
| 1325 | pub fn sleep(io: Io, timeout: Timeout) SleepError!void { | |
| 1326 | return io.vtable.sleep(io.userdata, timeout); | |
| 1240 | 1327 | } |
| 1241 | 1328 | |
| 1242 | 1329 | pub fn sleepDuration(io: Io, duration: Duration) SleepError!void { |
lib/std/Io/EventLoop.zig+1-1| ... | ... | @@ -1406,7 +1406,7 @@ fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: std.posix.o |
| 1406 | 1406 | .ISDIR => return error.IsDir, |
| 1407 | 1407 | .NOBUFS => return error.SystemResources, |
| 1408 | 1408 | .NOMEM => return error.SystemResources, |
| 1409 | .NOTCONN => return error.SocketNotConnected, | |
| 1409 | .NOTCONN => return error.SocketUnconnected, | |
| 1410 | 1410 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1411 | 1411 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1412 | 1412 | .NXIO => return error.Unseekable, |
lib/std/Io/File.zig+1-1| ... | ... | @@ -157,7 +157,7 @@ pub const ReadStreamingError = error{ |
| 157 | 157 | ConnectionResetByPeer, |
| 158 | 158 | ConnectionTimedOut, |
| 159 | 159 | NotOpenForReading, |
| 160 | SocketNotConnected, | |
| 160 | SocketUnconnected, | |
| 161 | 161 | /// This error occurs when no global event loop is configured, |
| 162 | 162 | /// and reading from the file descriptor would block. |
| 163 | 163 | WouldBlock, |
lib/std/Io/Threaded.zig+158-26| ... | ... | @@ -811,7 +811,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File |
| 811 | 811 | .ISDIR => return error.IsDir, |
| 812 | 812 | .NOBUFS => return error.SystemResources, |
| 813 | 813 | .NOMEM => return error.SystemResources, |
| 814 | .NOTCONN => return error.SocketNotConnected, | |
| 814 | .NOTCONN => return error.SocketUnconnected, | |
| 815 | 815 | .CONNRESET => return error.ConnectionResetByPeer, |
| 816 | 816 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 817 | 817 | .NOTCAPABLE => return error.AccessDenied, |
| ... | ... | @@ -834,7 +834,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File |
| 834 | 834 | .ISDIR => return error.IsDir, |
| 835 | 835 | .NOBUFS => return error.SystemResources, |
| 836 | 836 | .NOMEM => return error.SystemResources, |
| 837 | .NOTCONN => return error.SocketNotConnected, | |
| 837 | .NOTCONN => return error.SocketUnconnected, | |
| 838 | 838 | .CONNRESET => return error.ConnectionResetByPeer, |
| 839 | 839 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 840 | 840 | else => |err| return posix.unexpectedErrno(err), |
| ... | ... | @@ -933,7 +933,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset |
| 933 | 933 | .ISDIR => return error.IsDir, |
| 934 | 934 | .NOBUFS => return error.SystemResources, |
| 935 | 935 | .NOMEM => return error.SystemResources, |
| 936 | .NOTCONN => return error.SocketNotConnected, | |
| 936 | .NOTCONN => return error.SocketUnconnected, | |
| 937 | 937 | .CONNRESET => return error.ConnectionResetByPeer, |
| 938 | 938 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 939 | 939 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -960,7 +960,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset |
| 960 | 960 | .ISDIR => return error.IsDir, |
| 961 | 961 | .NOBUFS => return error.SystemResources, |
| 962 | 962 | .NOMEM => return error.SystemResources, |
| 963 | .NOTCONN => return error.SocketNotConnected, | |
| 963 | .NOTCONN => return error.SocketUnconnected, | |
| 964 | 964 | .CONNRESET => return error.ConnectionResetByPeer, |
| 965 | 965 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 966 | 966 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -999,19 +999,29 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi |
| 999 | 999 | }; |
| 1000 | 1000 | } |
| 1001 | 1001 | |
| 1002 | fn now(userdata: ?*anyopaque, clockid: posix.clockid_t) Io.NowError!Io.Timestamp { | |
| 1002 | fn now(userdata: ?*anyopaque, clock: Io.Timestamp.Clock) Io.Timestamp.Error!i96 { | |
| 1003 | 1003 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1004 | try pool.checkCancel(); | |
| 1005 | const timespec = try posix.clock_gettime(clockid); | |
| 1006 | return @enumFromInt(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec); | |
| 1004 | _ = pool; | |
| 1005 | const clock_id: posix.clockid_t = clockToPosix(clock); | |
| 1006 | var tp: posix.timespec = undefined; | |
| 1007 | switch (posix.errno(posix.system.clock_gettime(clock_id, &tp))) { | |
| 1008 | .SUCCESS => return @intCast(@as(i128, tp.sec) * std.time.ns_per_s + tp.nsec), | |
| 1009 | .INVAL => return error.UnsupportedClock, | |
| 1010 | else => |err| return posix.unexpectedErrno(err), | |
| 1011 | } | |
| 1007 | 1012 | } |
| 1008 | 1013 | |
| 1009 | fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, timeout: Io.Timeout) Io.SleepError!void { | |
| 1014 | fn sleep(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | |
| 1010 | 1015 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1016 | const clock_id: posix.clockid_t = clockToPosix(switch (timeout) { | |
| 1017 | .none => .monotonic, | |
| 1018 | .duration => |d| d.clock, | |
| 1019 | .deadline => |d| d.clock, | |
| 1020 | }); | |
| 1011 | 1021 | const deadline_nanoseconds: i96 = switch (timeout) { |
| 1012 | 1022 | .none => std.math.maxInt(i96), |
| 1013 | .duration => |duration| duration.nanoseconds, | |
| 1014 | .deadline => |deadline| @intFromEnum(deadline), | |
| 1023 | .duration => |d| d.duration.nanoseconds, | |
| 1024 | .deadline => |deadline| deadline.nanoseconds, | |
| 1015 | 1025 | }; |
| 1016 | 1026 | var timespec: posix.timespec = .{ |
| 1017 | 1027 | .sec = @intCast(@divFloor(deadline_nanoseconds, std.time.ns_per_s)), |
| ... | ... | @@ -1019,13 +1029,12 @@ fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, timeout: Io.Timeout) I |
| 1019 | 1029 | }; |
| 1020 | 1030 | while (true) { |
| 1021 | 1031 | try pool.checkCancel(); |
| 1022 | switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clockid, .{ .ABSTIME = switch (timeout) { | |
| 1032 | switch (std.os.linux.E.init(std.os.linux.clock_nanosleep(clock_id, .{ .ABSTIME = switch (timeout) { | |
| 1023 | 1033 | .none, .duration => false, |
| 1024 | 1034 | .deadline => true, |
| 1025 | 1035 | } }, &timespec, &timespec))) { |
| 1026 | 1036 | .SUCCESS => return, |
| 1027 | .FAULT => |err| return errnoBug(err), | |
| 1028 | .INTR => {}, | |
| 1037 | .INTR => continue, | |
| 1029 | 1038 | .INVAL => return error.UnsupportedClock, |
| 1030 | 1039 | else => |err| return posix.unexpectedErrno(err), |
| 1031 | 1040 | } |
| ... | ... | @@ -1313,15 +1322,18 @@ fn netSend( |
| 1313 | 1322 | handle: Io.net.Socket.Handle, |
| 1314 | 1323 | messages: []Io.net.OutgoingMessage, |
| 1315 | 1324 | flags: Io.net.SendFlags, |
| 1316 | ) Io.net.Socket.SendError!void { | |
| 1325 | ) Io.net.SendResult { | |
| 1317 | 1326 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1318 | 1327 | |
| 1319 | 1328 | if (have_sendmmsg) { |
| 1320 | 1329 | var i: usize = 0; |
| 1321 | 1330 | while (messages.len - i != 0) { |
| 1322 | i += try netSendMany(pool, handle, messages[i..], flags); | |
| 1331 | i += netSendMany(pool, handle, messages[i..], flags) catch |err| return .{ .fail = .{ | |
| 1332 | .err = err, | |
| 1333 | .sent = i, | |
| 1334 | } }; | |
| 1323 | 1335 | } |
| 1324 | return; | |
| 1336 | return .success; | |
| 1325 | 1337 | } |
| 1326 | 1338 | |
| 1327 | 1339 | try pool.checkCancel(); |
| ... | ... | @@ -1391,11 +1403,11 @@ fn netSendMany( |
| 1391 | 1403 | .NOMEM => return error.SystemResources, |
| 1392 | 1404 | .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket. |
| 1393 | 1405 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. |
| 1394 | .PIPE => return error.SocketNotConnected, | |
| 1406 | .PIPE => return error.SocketUnconnected, | |
| 1395 | 1407 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 1396 | 1408 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 1397 | 1409 | .NETUNREACH => return error.NetworkUnreachable, |
| 1398 | .NOTCONN => return error.SocketNotConnected, | |
| 1410 | .NOTCONN => return error.SocketUnconnected, | |
| 1399 | 1411 | .NETDOWN => return error.NetworkDown, |
| 1400 | 1412 | else => |err| return posix.unexpectedErrno(err), |
| 1401 | 1413 | } |
| ... | ... | @@ -1405,16 +1417,128 @@ fn netSendMany( |
| 1405 | 1417 | fn netReceive( |
| 1406 | 1418 | userdata: ?*anyopaque, |
| 1407 | 1419 | handle: Io.net.Socket.Handle, |
| 1408 | buffer: []u8, | |
| 1420 | message_buffer: []Io.net.IncomingMessage, | |
| 1421 | data_buffer: []u8, | |
| 1422 | flags: Io.net.ReceiveFlags, | |
| 1409 | 1423 | timeout: Io.Timeout, |
| 1410 | ) Io.net.Socket.ReceiveTimeoutError!Io.net.ReceivedMessage { | |
| 1424 | ) struct { ?Io.net.Socket.ReceiveTimeoutError, usize } { | |
| 1411 | 1425 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1412 | try pool.checkCancel(); | |
| 1413 | 1426 | |
| 1414 | _ = handle; | |
| 1415 | _ = buffer; | |
| 1416 | _ = timeout; | |
| 1417 | @panic("TODO"); | |
| 1427 | // recvmmsg is useless, here's why: | |
| 1428 | // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371) | |
| 1429 | // * it wants iovecs for each message but we have a better API: one data | |
| 1430 | // buffer to handle all the messages. The better API cannot be lowered to | |
| 1431 | // the split vectors though because reducing the buffer size might make | |
| 1432 | // some messages unreceivable. | |
| 1433 | ||
| 1434 | // So the strategy instead is to use poll with timeout and then non-blocking | |
| 1435 | // recvmsg calls. | |
| 1436 | const posix_flags: u32 = | |
| 1437 | @as(u32, if (flags.oob) posix.MSG.OOB else 0) | | |
| 1438 | @as(u32, if (flags.peek) posix.MSG.PEEK else 0) | | |
| 1439 | @as(u32, if (flags.trunc) posix.MSG.TRUNC else 0) | | |
| 1440 | posix.MSG.DONTWAIT | posix.MSG.NOSIGNAL; | |
| 1441 | ||
| 1442 | var poll_fds: [1]posix.pollfd = .{ | |
| 1443 | .{ | |
| 1444 | .fd = handle, | |
| 1445 | .events = posix.POLL.IN, | |
| 1446 | .revents = undefined, | |
| 1447 | }, | |
| 1448 | }; | |
| 1449 | var message_i: usize = 0; | |
| 1450 | var data_i: usize = 0; | |
| 1451 | ||
| 1452 | // TODO: recvmsg first, then poll if EAGAIN. saves syscall in case the messages are already queued. | |
| 1453 | ||
| 1454 | const deadline = timeout.toDeadline(pool.io()) catch |err| return .{ err, message_i }; | |
| 1455 | ||
| 1456 | poll: while (true) { | |
| 1457 | pool.checkCancel() catch |err| return .{ err, message_i }; | |
| 1458 | ||
| 1459 | if (message_i > 0 or message_buffer.len - message_i == 0) return .{ null, message_i }; | |
| 1460 | ||
| 1461 | const max_poll_ms = std.math.maxInt(u31); | |
| 1462 | const timeout_ms: u31 = if (deadline) |d| t: { | |
| 1463 | const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i }; | |
| 1464 | if (duration.nanoseconds <= 0) return .{ error.Timeout, message_i }; | |
| 1465 | break :t @intCast(@min(max_poll_ms, duration.toMilliseconds())); | |
| 1466 | } else max_poll_ms; | |
| 1467 | ||
| 1468 | const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms); | |
| 1469 | switch (posix.errno(poll_rc)) { | |
| 1470 | .SUCCESS => { | |
| 1471 | if (poll_rc == 0) { | |
| 1472 | // Possibly spurious timeout. | |
| 1473 | if (deadline == null) continue; | |
| 1474 | return .{ error.Timeout, message_i }; | |
| 1475 | } | |
| 1476 | ||
| 1477 | // Proceed to recvmsg. | |
| 1478 | while (true) { | |
| 1479 | pool.checkCancel() catch |err| return .{ err, message_i }; | |
| 1480 | ||
| 1481 | const message = &message_buffer[message_i]; | |
| 1482 | const remaining_data_buffer = data_buffer[data_i..]; | |
| 1483 | var storage: PosixAddress = undefined; | |
| 1484 | var iov: posix.iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len }; | |
| 1485 | var msg: posix.msghdr = .{ | |
| 1486 | .name = &storage.any, | |
| 1487 | .namelen = @sizeOf(PosixAddress), | |
| 1488 | .iov = (&iov)[0..1], | |
| 1489 | .iovlen = 1, | |
| 1490 | .control = message.control.ptr, | |
| 1491 | .controllen = message.control.len, | |
| 1492 | .flags = undefined, | |
| 1493 | }; | |
| 1494 | ||
| 1495 | const rc = posix.system.recvmsg(handle, &msg, posix_flags); | |
| 1496 | switch (posix.errno(rc)) { | |
| 1497 | .SUCCESS => { | |
| 1498 | const data = remaining_data_buffer[0..@intCast(rc)]; | |
| 1499 | data_i += data.len; | |
| 1500 | message.* = .{ | |
| 1501 | .from = addressFromPosix(&storage), | |
| 1502 | .data = data, | |
| 1503 | .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control, | |
| 1504 | .flags = .{ | |
| 1505 | .eor = (msg.flags & posix.MSG.EOR) != 0, | |
| 1506 | .trunc = (msg.flags & posix.MSG.TRUNC) != 0, | |
| 1507 | .ctrunc = (msg.flags & posix.MSG.CTRUNC) != 0, | |
| 1508 | .oob = (msg.flags & posix.MSG.OOB) != 0, | |
| 1509 | .errqueue = (msg.flags & posix.MSG.ERRQUEUE) != 0, | |
| 1510 | }, | |
| 1511 | }; | |
| 1512 | message_i += 1; | |
| 1513 | continue; | |
| 1514 | }, | |
| 1515 | .AGAIN => continue :poll, | |
| 1516 | .BADF => |err| return .{ errnoBug(err), message_i }, | |
| 1517 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, | |
| 1518 | .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i }, | |
| 1519 | .INTR => continue, | |
| 1520 | .FAULT => |err| return .{ errnoBug(err), message_i }, | |
| 1521 | .INVAL => |err| return .{ errnoBug(err), message_i }, | |
| 1522 | .NOBUFS => return .{ error.SystemResources, message_i }, | |
| 1523 | .NOMEM => return .{ error.SystemResources, message_i }, | |
| 1524 | .NOTCONN => return .{ error.SocketUnconnected, message_i }, | |
| 1525 | .NOTSOCK => |err| return .{ errnoBug(err), message_i }, | |
| 1526 | .MSGSIZE => return .{ error.MessageOversize, message_i }, | |
| 1527 | .PIPE => return .{ error.SocketUnconnected, message_i }, | |
| 1528 | .OPNOTSUPP => |err| return .{ errnoBug(err), message_i }, | |
| 1529 | .CONNRESET => return .{ error.ConnectionResetByPeer, message_i }, | |
| 1530 | .NETDOWN => return .{ error.NetworkDown, message_i }, | |
| 1531 | else => |err| return .{ posix.unexpectedErrno(err), message_i }, | |
| 1532 | } | |
| 1533 | } | |
| 1534 | }, | |
| 1535 | .INTR => continue, | |
| 1536 | .FAULT => |err| return .{ errnoBug(err), message_i }, | |
| 1537 | .INVAL => |err| return .{ errnoBug(err), message_i }, | |
| 1538 | .NOMEM => return .{ error.SystemResources, message_i }, | |
| 1539 | else => |err| return .{ posix.unexpectedErrno(err), message_i }, | |
| 1540 | } | |
| 1541 | } | |
| 1418 | 1542 | } |
| 1419 | 1543 | |
| 1420 | 1544 | fn netWritePosix( |
| ... | ... | @@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 { |
| 1653 | 1777 | fn recoverableOsBugDetected() void { |
| 1654 | 1778 | if (builtin.mode == .Debug) unreachable; |
| 1655 | 1779 | } |
| 1780 | ||
| 1781 | fn clockToPosix(clock: Io.Timestamp.Clock) posix.clockid_t { | |
| 1782 | return switch (clock) { | |
| 1783 | .realtime => posix.CLOCK.REALTIME, | |
| 1784 | .monotonic => posix.CLOCK.MONOTONIC, | |
| 1785 | .boottime => posix.CLOCK.BOOTTIME, | |
| 1786 | }; | |
| 1787 | } |
lib/std/Io/net.zig+91-8| ... | ... | @@ -695,9 +695,41 @@ pub const Ip6Address = struct { |
| 695 | 695 | }; |
| 696 | 696 | }; |
| 697 | 697 | |
| 698 | pub const ReceivedMessage = struct { | |
| 698 | pub const ReceiveFlags = packed struct(u8) { | |
| 699 | oob: bool = false, | |
| 700 | peek: bool = false, | |
| 701 | trunc: bool = false, | |
| 702 | _: u5 = 0, | |
| 703 | }; | |
| 704 | ||
| 705 | pub const IncomingMessage = struct { | |
| 706 | /// Populated by receive functions. | |
| 699 | 707 | from: IpAddress, |
| 700 | len: usize, | |
| 708 | /// Populated by receive functions, points into the caller-supplied buffer. | |
| 709 | data: []u8, | |
| 710 | /// Supplied by caller before calling receive functions; mutated by receive | |
| 711 | /// functions. | |
| 712 | control: []u8 = &.{}, | |
| 713 | /// Populated by receive functions. | |
| 714 | flags: Flags, | |
| 715 | ||
| 716 | pub const Flags = packed struct(u8) { | |
| 717 | /// indicates end-of-record; the data returned completed a record | |
| 718 | /// (generally used with sockets of type SOCK_SEQPACKET). | |
| 719 | eor: bool, | |
| 720 | /// indicates that the trailing portion of a datagram was discarded | |
| 721 | /// because the datagram was larger than the buffer supplied. | |
| 722 | trunc: bool, | |
| 723 | /// indicates that some control data was discarded due to lack of | |
| 724 | /// space in the buffer for ancil‐ lary data. | |
| 725 | ctrunc: bool, | |
| 726 | /// indicates expedited or out-of-band data was received. | |
| 727 | oob: bool, | |
| 728 | /// indicates that no data was received but an extended error from the | |
| 729 | /// socket error queue. | |
| 730 | errqueue: bool, | |
| 731 | _: u3 = 0, | |
| 732 | }; | |
| 701 | 733 | }; |
| 702 | 734 | |
| 703 | 735 | pub const OutgoingMessage = struct { |
| ... | ... | @@ -718,6 +750,14 @@ pub const SendFlags = packed struct(u8) { |
| 718 | 750 | _: u3 = 0, |
| 719 | 751 | }; |
| 720 | 752 | |
| 753 | pub const SendResult = union(enum) { | |
| 754 | success, | |
| 755 | fail: struct { | |
| 756 | err: Socket.SendError, | |
| 757 | sent: usize, | |
| 758 | }, | |
| 759 | }; | |
| 760 | ||
| 721 | 761 | pub const Interface = struct { |
| 722 | 762 | /// Value 0 indicates `none`. |
| 723 | 763 | index: u32, |
| ... | ... | @@ -839,7 +879,7 @@ pub const Socket = struct { |
| 839 | 879 | ConnectionResetByPeer, |
| 840 | 880 | /// Local end has been shut down on a connection-oriented socket, or |
| 841 | 881 | /// the socket was never connected. |
| 842 | SocketNotConnected, | |
| 882 | SocketUnconnected, | |
| 843 | 883 | } || Io.UnexpectedError || Io.Cancelable; |
| 844 | 884 | |
| 845 | 885 | /// Transfers `data` to `dest`, connectionless, in one packet. |
| ... | ... | @@ -853,14 +893,34 @@ pub const Socket = struct { |
| 853 | 893 | return io.vtable.netSend(io.userdata, s.handle, messages, flags); |
| 854 | 894 | } |
| 855 | 895 | |
| 856 | pub const ReceiveError = error{} || Io.UnexpectedError || Io.Cancelable; | |
| 896 | pub const ReceiveError = error{ | |
| 897 | /// Insufficient memory or other resource internal to the operating system. | |
| 898 | SystemResources, | |
| 899 | /// Per-process limit on the number of open file descriptors has been reached. | |
| 900 | ProcessFdQuotaExceeded, | |
| 901 | /// System-wide limit on the total number of open files has been reached. | |
| 902 | SystemFdQuotaExceeded, | |
| 903 | /// Local end has been shut down on a connection-oriented socket, or | |
| 904 | /// the socket was never connected. | |
| 905 | SocketUnconnected, | |
| 906 | /// The socket type requires that message be sent atomically, and the | |
| 907 | /// size of the message to be sent made this impossible. The message | |
| 908 | /// was not transmitted, or was partially transmitted. | |
| 909 | MessageOversize, | |
| 910 | /// Network connection was unexpectedly closed by sender. | |
| 911 | ConnectionResetByPeer, | |
| 912 | /// The local network interface used to reach the destination is offline. | |
| 913 | NetworkDown, | |
| 914 | } || Io.UnexpectedError || Io.Cancelable; | |
| 857 | 915 | |
| 858 | 916 | /// Waits for data. Connectionless. |
| 859 | 917 | /// |
| 860 | 918 | /// See also: |
| 861 | 919 | /// * `receiveTimeout` |
| 862 | pub fn receive(s: *const Socket, io: Io, source: *const IpAddress, buffer: []u8) ReceiveError!ReceivedMessage { | |
| 863 | return io.vtable.netReceive(io.userdata, s.handle, source, buffer, .none); | |
| 920 | pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage { | |
| 921 | var message: IncomingMessage = undefined; | |
| 922 | assert(1 == try io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, .none)); | |
| 923 | return message; | |
| 864 | 924 | } |
| 865 | 925 | |
| 866 | 926 | pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error; |
| ... | ... | @@ -871,13 +931,36 @@ pub const Socket = struct { |
| 871 | 931 | /// |
| 872 | 932 | /// See also: |
| 873 | 933 | /// * `receive` |
| 934 | /// * `receiveManyTimeout` | |
| 874 | 935 | pub fn receiveTimeout( |
| 875 | 936 | s: *const Socket, |
| 876 | 937 | io: Io, |
| 877 | 938 | buffer: []u8, |
| 878 | 939 | timeout: Io.Timeout, |
| 879 | ) ReceiveTimeoutError!ReceivedMessage { | |
| 880 | return io.vtable.netReceive(io.userdata, s.handle, buffer, timeout); | |
| 940 | ) ReceiveTimeoutError!IncomingMessage { | |
| 941 | var message: IncomingMessage = undefined; | |
| 942 | assert(1 == try io.vtable.netReceive(io.userdata, s.handle, (&message)[0..1], buffer, .{}, timeout)); | |
| 943 | return message; | |
| 944 | } | |
| 945 | ||
| 946 | /// Waits until at least one message is delivered, possibly returning more | |
| 947 | /// than one message. Connectionless. | |
| 948 | /// | |
| 949 | /// Returns number of messages received, or `error.Timeout` if no message | |
| 950 | /// arrives early enough. | |
| 951 | /// | |
| 952 | /// See also: | |
| 953 | /// * `receive` | |
| 954 | /// * `receiveTimeout` | |
| 955 | pub fn receiveManyTimeout( | |
| 956 | s: *const Socket, | |
| 957 | io: Io, | |
| 958 | message_buffer: []IncomingMessage, | |
| 959 | data_buffer: []u8, | |
| 960 | flags: ReceiveFlags, | |
| 961 | timeout: Io.Timeout, | |
| 962 | ) struct { ?ReceiveTimeoutError, usize } { | |
| 963 | return io.vtable.netReceive(io.userdata, s.handle, message_buffer, data_buffer, flags, timeout); | |
| 881 | 964 | } |
| 882 | 965 | }; |
| 883 | 966 |
lib/std/Io/net/HostName.zig+70-60| ... | ... | @@ -52,7 +52,7 @@ pub const LookupError = error{ |
| 52 | 52 | InvalidDnsARecord, |
| 53 | 53 | InvalidDnsAAAARecord, |
| 54 | 54 | NameServerFailure, |
| 55 | } || Io.NowError || IpAddress.BindError || Io.File.OpenError || Io.File.Reader.Error || Io.Cancelable; | |
| 55 | } || Io.Timestamp.Error || IpAddress.BindError || Io.File.OpenError || Io.File.Reader.Error || Io.Cancelable; | |
| 56 | 56 | |
| 57 | 57 | pub const LookupResult = struct { |
| 58 | 58 | /// How many `LookupOptions.addresses_buffer` elements are populated. |
| ... | ... | @@ -222,11 +222,11 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 222 | 222 | .{ .af = .ip4, .rr = std.posix.RR.AAAA }, |
| 223 | 223 | }; |
| 224 | 224 | var query_buffers: [2][280]u8 = undefined; |
| 225 | var answer_buffers: [2][512]u8 = undefined; | |
| 225 | var answer_buffer: [2 * 512]u8 = undefined; | |
| 226 | 226 | var queries_buffer: [2][]const u8 = undefined; |
| 227 | 227 | var answers_buffer: [2][]const u8 = undefined; |
| 228 | 228 | var nq: usize = 0; |
| 229 | var next_answer_buffer: usize = 0; | |
| 229 | var answer_buffer_i: usize = 0; | |
| 230 | 230 | |
| 231 | 231 | for (family_records) |fr| { |
| 232 | 232 | if (options.family != fr.af) { |
| ... | ... | @@ -262,79 +262,89 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 262 | 262 | const mapped_nameservers = if (any_ip6) ip4_mapped[0..rc.nameservers_len] else rc.nameservers(); |
| 263 | 263 | const queries = queries_buffer[0..nq]; |
| 264 | 264 | const answers = answers_buffer[0..queries.len]; |
| 265 | var answers_remaining = answers.len; | |
| 265 | 266 | for (answers) |*answer| answer.len = 0; |
| 266 | 267 | |
| 267 | var now_ts = try io.now(.MONOTONIC); | |
| 268 | const final_ts = now_ts.addDuration(.seconds(rc.timeout_seconds)); | |
| 268 | // boottime is chosen because time the computer is suspended should count | |
| 269 | // against time spent waiting for external messages to arrive. | |
| 270 | var now_ts = try Io.Timestamp.now(io, .boottime); | |
| 271 | const final_ts = now_ts.addDuration(.fromSeconds(rc.timeout_seconds)); | |
| 269 | 272 | const attempt_duration: Io.Duration = .{ |
| 270 | 273 | .nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts, |
| 271 | 274 | }; |
| 272 | 275 | |
| 273 | send: while (now_ts.compare(.lt, final_ts)) : (now_ts = try io.now(.MONOTONIC)) { | |
| 274 | var message_buffer: [queries_buffer.len * ResolvConf.max_nameservers]Io.net.OutgoingMessage = undefined; | |
| 275 | var message_i: usize = 0; | |
| 276 | for (queries, answers) |query, *answer| { | |
| 277 | if (answer.len != 0) continue; | |
| 278 | for (mapped_nameservers) |*ns| { | |
| 279 | message_buffer[message_i] = .{ | |
| 280 | .address = ns, | |
| 281 | .data_ptr = query.ptr, | |
| 282 | .data_len = query.len, | |
| 283 | }; | |
| 284 | message_i += 1; | |
| 276 | send: while (now_ts.compare(.lt, final_ts)) : (now_ts = try Io.Timestamp.now(io, .boottime)) { | |
| 277 | const max_messages = queries_buffer.len * ResolvConf.max_nameservers; | |
| 278 | { | |
| 279 | var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined; | |
| 280 | var message_i: usize = 0; | |
| 281 | for (queries, answers) |query, *answer| { | |
| 282 | if (answer.len != 0) continue; | |
| 283 | for (mapped_nameservers) |*ns| { | |
| 284 | message_buffer[message_i] = .{ | |
| 285 | .address = ns, | |
| 286 | .data_ptr = query.ptr, | |
| 287 | .data_len = query.len, | |
| 288 | }; | |
| 289 | message_i += 1; | |
| 290 | } | |
| 285 | 291 | } |
| 292 | _ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{}); | |
| 286 | 293 | } |
| 287 | io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{}) catch {}; | |
| 288 | 294 | |
| 289 | 295 | const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) }; |
| 290 | 296 | |
| 291 | 297 | while (true) { |
| 292 | const buf = &answer_buffers[next_answer_buffer]; | |
| 293 | const reply = socket.receiveTimeout(io, buf, timeout) catch |err| switch (err) { | |
| 298 | var message_buffer: [max_messages]Io.net.IncomingMessage = undefined; | |
| 299 | const buf = answer_buffer[answer_buffer_i..]; | |
| 300 | const recv_err, const recv_n = socket.receiveManyTimeout(io, &message_buffer, buf, .{}, timeout); | |
| 301 | for (message_buffer[0..recv_n]) |*received_message| { | |
| 302 | const reply = received_message.data; | |
| 303 | // Ignore non-identifiable packets. | |
| 304 | if (reply.len < 4) continue; | |
| 305 | ||
| 306 | // Ignore replies from addresses we didn't send to. | |
| 307 | const ns = for (mapped_nameservers) |*ns| { | |
| 308 | if (received_message.from.eql(ns)) break ns; | |
| 309 | } else { | |
| 310 | continue; | |
| 311 | }; | |
| 312 | ||
| 313 | // Find which query this answer goes with, if any. | |
| 314 | const query, const answer = for (queries, answers) |query, *answer| { | |
| 315 | if (reply[0] == query[0] and reply[1] == query[1]) break .{ query, answer }; | |
| 316 | } else { | |
| 317 | continue; | |
| 318 | }; | |
| 319 | if (answer.len != 0) continue; | |
| 320 | ||
| 321 | // Only accept positive or negative responses; retry immediately on | |
| 322 | // server failure, and ignore all other codes such as refusal. | |
| 323 | switch (reply[3] & 15) { | |
| 324 | 0, 3 => { | |
| 325 | answer.* = reply; | |
| 326 | answer_buffer_i += reply.len; | |
| 327 | answers_remaining -= 1; | |
| 328 | if (answer_buffer.len - answer_buffer_i == 0) break :send; | |
| 329 | if (answers_remaining == 0) break :send; | |
| 330 | }, | |
| 331 | 2 => { | |
| 332 | var retry_message: Io.net.OutgoingMessage = .{ | |
| 333 | .address = ns, | |
| 334 | .data_ptr = query.ptr, | |
| 335 | .data_len = query.len, | |
| 336 | }; | |
| 337 | _ = io.vtable.netSend(io.userdata, socket.handle, (&retry_message)[0..1], .{}); | |
| 338 | continue; | |
| 339 | }, | |
| 340 | else => continue, | |
| 341 | } | |
| 342 | } | |
| 343 | if (recv_err) |err| switch (err) { | |
| 294 | 344 | error.Canceled => return error.Canceled, |
| 295 | 345 | error.Timeout => continue :send, |
| 296 | 346 | else => continue, |
| 297 | 347 | }; |
| 298 | ||
| 299 | // Ignore non-identifiable packets. | |
| 300 | if (reply.len < 4) continue; | |
| 301 | ||
| 302 | // Ignore replies from addresses we didn't send to. | |
| 303 | const ns = for (mapped_nameservers) |*ns| { | |
| 304 | if (reply.from.eql(ns)) break ns; | |
| 305 | } else { | |
| 306 | continue; | |
| 307 | }; | |
| 308 | ||
| 309 | const reply_msg = buf[0..reply.len]; | |
| 310 | ||
| 311 | // Find which query this answer goes with, if any. | |
| 312 | const query, const answer = for (queries, answers) |query, *answer| { | |
| 313 | if (reply_msg[0] == query[0] and reply_msg[1] == query[1]) break .{ query, answer }; | |
| 314 | } else { | |
| 315 | continue; | |
| 316 | }; | |
| 317 | if (answer.len != 0) continue; | |
| 318 | ||
| 319 | // Only accept positive or negative responses; retry immediately on | |
| 320 | // server failure, and ignore all other codes such as refusal. | |
| 321 | switch (reply_msg[3] & 15) { | |
| 322 | 0, 3 => { | |
| 323 | answer.* = reply_msg; | |
| 324 | next_answer_buffer += 1; | |
| 325 | if (next_answer_buffer == answers.len) break :send; | |
| 326 | }, | |
| 327 | 2 => { | |
| 328 | var message: Io.net.OutgoingMessage = .{ | |
| 329 | .address = ns, | |
| 330 | .data_ptr = query.ptr, | |
| 331 | .data_len = query.len, | |
| 332 | }; | |
| 333 | io.vtable.netSend(io.userdata, socket.handle, (&message)[0..1], .{}) catch {}; | |
| 334 | continue; | |
| 335 | }, | |
| 336 | else => continue, | |
| 337 | } | |
| 338 | 348 | } |
| 339 | 349 | } else { |
| 340 | 350 | return error.NameServerFailure; |
lib/std/net.zig+4-4| ... | ... | @@ -1917,7 +1917,7 @@ pub const Stream = struct { |
| 1917 | 1917 | MessageTooBig, |
| 1918 | 1918 | NetworkSubsystemFailed, |
| 1919 | 1919 | ConnectionResetByPeer, |
| 1920 | SocketNotConnected, | |
| 1920 | SocketUnconnected, | |
| 1921 | 1921 | }; |
| 1922 | 1922 | |
| 1923 | 1923 | pub const WriteError = posix.SendMsgError || error{ |
| ... | ... | @@ -1926,7 +1926,7 @@ pub const Stream = struct { |
| 1926 | 1926 | MessageTooBig, |
| 1927 | 1927 | NetworkSubsystemFailed, |
| 1928 | 1928 | SystemResources, |
| 1929 | SocketNotConnected, | |
| 1929 | SocketUnconnected, | |
| 1930 | 1930 | Unexpected, |
| 1931 | 1931 | }; |
| 1932 | 1932 | |
| ... | ... | @@ -2004,7 +2004,7 @@ pub const Stream = struct { |
| 2004 | 2004 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 2005 | 2005 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2006 | 2006 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2007 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 2007 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 2008 | 2008 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 2009 | 2009 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 2010 | 2010 | .WSA_IO_PENDING => unreachable, |
| ... | ... | @@ -2171,7 +2171,7 @@ pub const Stream = struct { |
| 2171 | 2171 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2172 | 2172 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2173 | 2173 | .WSAENOBUFS => return error.SystemResources, |
| 2174 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 2174 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 2175 | 2175 | .WSAENOTSOCK => unreachable, // not a socket |
| 2176 | 2176 | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets |
| 2177 | 2177 | .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown |
lib/std/posix.zig+21-21| ... | ... | @@ -840,7 +840,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 840 | 840 | .ISDIR => return error.IsDir, |
| 841 | 841 | .NOBUFS => return error.SystemResources, |
| 842 | 842 | .NOMEM => return error.SystemResources, |
| 843 | .NOTCONN => return error.SocketNotConnected, | |
| 843 | .NOTCONN => return error.SocketUnconnected, | |
| 844 | 844 | .CONNRESET => return error.ConnectionResetByPeer, |
| 845 | 845 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 846 | 846 | .NOTCAPABLE => return error.AccessDenied, |
| ... | ... | @@ -869,7 +869,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 869 | 869 | .ISDIR => return error.IsDir, |
| 870 | 870 | .NOBUFS => return error.SystemResources, |
| 871 | 871 | .NOMEM => return error.SystemResources, |
| 872 | .NOTCONN => return error.SocketNotConnected, | |
| 872 | .NOTCONN => return error.SocketUnconnected, | |
| 873 | 873 | .CONNRESET => return error.ConnectionResetByPeer, |
| 874 | 874 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 875 | 875 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -909,7 +909,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 909 | 909 | .ISDIR => return error.IsDir, |
| 910 | 910 | .NOBUFS => return error.SystemResources, |
| 911 | 911 | .NOMEM => return error.SystemResources, |
| 912 | .NOTCONN => return error.SocketNotConnected, | |
| 912 | .NOTCONN => return error.SocketUnconnected, | |
| 913 | 913 | .CONNRESET => return error.ConnectionResetByPeer, |
| 914 | 914 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 915 | 915 | .NOTCAPABLE => return error.AccessDenied, |
| ... | ... | @@ -931,7 +931,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 931 | 931 | .ISDIR => return error.IsDir, |
| 932 | 932 | .NOBUFS => return error.SystemResources, |
| 933 | 933 | .NOMEM => return error.SystemResources, |
| 934 | .NOTCONN => return error.SocketNotConnected, | |
| 934 | .NOTCONN => return error.SocketUnconnected, | |
| 935 | 935 | .CONNRESET => return error.ConnectionResetByPeer, |
| 936 | 936 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 937 | 937 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -978,7 +978,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 978 | 978 | .ISDIR => return error.IsDir, |
| 979 | 979 | .NOBUFS => return error.SystemResources, |
| 980 | 980 | .NOMEM => return error.SystemResources, |
| 981 | .NOTCONN => return error.SocketNotConnected, | |
| 981 | .NOTCONN => return error.SocketUnconnected, | |
| 982 | 982 | .CONNRESET => return error.ConnectionResetByPeer, |
| 983 | 983 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 984 | 984 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1011,7 +1011,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 1011 | 1011 | .ISDIR => return error.IsDir, |
| 1012 | 1012 | .NOBUFS => return error.SystemResources, |
| 1013 | 1013 | .NOMEM => return error.SystemResources, |
| 1014 | .NOTCONN => return error.SocketNotConnected, | |
| 1014 | .NOTCONN => return error.SocketUnconnected, | |
| 1015 | 1015 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1016 | 1016 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1017 | 1017 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1129,7 +1129,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1129 | 1129 | .ISDIR => return error.IsDir, |
| 1130 | 1130 | .NOBUFS => return error.SystemResources, |
| 1131 | 1131 | .NOMEM => return error.SystemResources, |
| 1132 | .NOTCONN => return error.SocketNotConnected, | |
| 1132 | .NOTCONN => return error.SocketUnconnected, | |
| 1133 | 1133 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1134 | 1134 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1135 | 1135 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1155,7 +1155,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1155 | 1155 | .ISDIR => return error.IsDir, |
| 1156 | 1156 | .NOBUFS => return error.SystemResources, |
| 1157 | 1157 | .NOMEM => return error.SystemResources, |
| 1158 | .NOTCONN => return error.SocketNotConnected, | |
| 1158 | .NOTCONN => return error.SocketUnconnected, | |
| 1159 | 1159 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1160 | 1160 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1161 | 1161 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -3711,7 +3711,7 @@ pub const ShutdownError = error{ |
| 3711 | 3711 | NetworkSubsystemFailed, |
| 3712 | 3712 | |
| 3713 | 3713 | /// The socket is not connected (connection-oriented sockets only). |
| 3714 | SocketNotConnected, | |
| 3714 | SocketUnconnected, | |
| 3715 | 3715 | SystemResources, |
| 3716 | 3716 | } || UnexpectedError; |
| 3717 | 3717 | |
| ... | ... | @@ -3731,7 +3731,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3731 | 3731 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, |
| 3732 | 3732 | .WSAEINVAL => unreachable, |
| 3733 | 3733 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 3734 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 3734 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 3735 | 3735 | .WSAENOTSOCK => unreachable, |
| 3736 | 3736 | .WSANOTINITIALISED => unreachable, |
| 3737 | 3737 | else => |err| return windows.unexpectedWSAError(err), |
| ... | ... | @@ -3746,7 +3746,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3746 | 3746 | .SUCCESS => return, |
| 3747 | 3747 | .BADF => unreachable, |
| 3748 | 3748 | .INVAL => unreachable, |
| 3749 | .NOTCONN => return error.SocketNotConnected, | |
| 3749 | .NOTCONN => return error.SocketUnconnected, | |
| 3750 | 3750 | .NOTSOCK => unreachable, |
| 3751 | 3751 | .NOBUFS => return error.SystemResources, |
| 3752 | 3752 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -6181,7 +6181,7 @@ pub const SendMsgError = SendError || error{ |
| 6181 | 6181 | NotDir, |
| 6182 | 6182 | |
| 6183 | 6183 | /// The socket is not connected (connection-oriented sockets only). |
| 6184 | SocketNotConnected, | |
| 6184 | SocketUnconnected, | |
| 6185 | 6185 | AddressNotAvailable, |
| 6186 | 6186 | }; |
| 6187 | 6187 | |
| ... | ... | @@ -6212,7 +6212,7 @@ pub fn sendmsg( |
| 6212 | 6212 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6213 | 6213 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6214 | 6214 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6215 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6215 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6216 | 6216 | .WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH. |
| 6217 | 6217 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6218 | 6218 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | ... | @@ -6248,7 +6248,7 @@ pub fn sendmsg( |
| 6248 | 6248 | .NOTDIR => return error.NotDir, |
| 6249 | 6249 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6250 | 6250 | .NETUNREACH => return error.NetworkUnreachable, |
| 6251 | .NOTCONN => return error.SocketNotConnected, | |
| 6251 | .NOTCONN => return error.SocketUnconnected, | |
| 6252 | 6252 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6253 | 6253 | else => |err| return unexpectedErrno(err), |
| 6254 | 6254 | } |
| ... | ... | @@ -6315,7 +6315,7 @@ pub fn sendto( |
| 6315 | 6315 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6316 | 6316 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6317 | 6317 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6318 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6318 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6319 | 6319 | .WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH. |
| 6320 | 6320 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6321 | 6321 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | ... | @@ -6353,7 +6353,7 @@ pub fn sendto( |
| 6353 | 6353 | .NOTDIR => return error.NotDir, |
| 6354 | 6354 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6355 | 6355 | .NETUNREACH => return error.NetworkUnreachable, |
| 6356 | .NOTCONN => return error.SocketNotConnected, | |
| 6356 | .NOTCONN => return error.SocketUnconnected, | |
| 6357 | 6357 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6358 | 6358 | else => |err| return unexpectedErrno(err), |
| 6359 | 6359 | } |
| ... | ... | @@ -6393,7 +6393,7 @@ pub fn send( |
| 6393 | 6393 | error.NotDir => unreachable, |
| 6394 | 6394 | error.NetworkUnreachable => unreachable, |
| 6395 | 6395 | error.AddressNotAvailable => unreachable, |
| 6396 | error.SocketNotConnected => unreachable, | |
| 6396 | error.SocketUnconnected => unreachable, | |
| 6397 | 6397 | error.UnreachableAddress => unreachable, |
| 6398 | 6398 | else => |e| return e, |
| 6399 | 6399 | }; |
| ... | ... | @@ -6579,7 +6579,7 @@ pub const RecvFromError = error{ |
| 6579 | 6579 | NetworkSubsystemFailed, |
| 6580 | 6580 | |
| 6581 | 6581 | /// The socket is not connected (connection-oriented sockets only). |
| 6582 | SocketNotConnected, | |
| 6582 | SocketUnconnected, | |
| 6583 | 6583 | |
| 6584 | 6584 | /// The other end closed the socket unexpectedly or a read is executed on a shut down socket |
| 6585 | 6585 | BrokenPipe, |
| ... | ... | @@ -6608,7 +6608,7 @@ pub fn recvfrom( |
| 6608 | 6608 | .WSAEINVAL => return error.SocketNotBound, |
| 6609 | 6609 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 6610 | 6610 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6611 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6611 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6612 | 6612 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6613 | 6613 | .WSAETIMEDOUT => return error.ConnectionTimedOut, |
| 6614 | 6614 | // TODO: handle more errors |
| ... | ... | @@ -6623,7 +6623,7 @@ pub fn recvfrom( |
| 6623 | 6623 | .BADF => unreachable, // always a race condition |
| 6624 | 6624 | .FAULT => unreachable, |
| 6625 | 6625 | .INVAL => unreachable, |
| 6626 | .NOTCONN => return error.SocketNotConnected, | |
| 6626 | .NOTCONN => return error.SocketUnconnected, | |
| 6627 | 6627 | .NOTSOCK => unreachable, |
| 6628 | 6628 | .INTR => continue, |
| 6629 | 6629 | .AGAIN => return error.WouldBlock, |
| ... | ... | @@ -6675,7 +6675,7 @@ pub fn recvmsg( |
| 6675 | 6675 | .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified |
| 6676 | 6676 | .NOBUFS => return error.SystemResources, |
| 6677 | 6677 | .NOMEM => return error.SystemResources, |
| 6678 | .NOTCONN => return error.SocketNotConnected, | |
| 6678 | .NOTCONN => return error.SocketUnconnected, | |
| 6679 | 6679 | .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. |
| 6680 | 6680 | .MSGSIZE => return error.MessageTooBig, |
| 6681 | 6681 | .PIPE => return error.BrokenPipe, |
lib/std/posix/test.zig+1-1| ... | ... | @@ -634,7 +634,7 @@ test "shutdown socket" { |
| 634 | 634 | } |
| 635 | 635 | const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0); |
| 636 | 636 | posix.shutdown(sock, .both) catch |err| switch (err) { |
| 637 | error.SocketNotConnected => {}, | |
| 637 | error.SocketUnconnected => {}, | |
| 638 | 638 | else => |e| return e, |
| 639 | 639 | }; |
| 640 | 640 | std.net.Stream.close(.{ .handle = sock }); |
lib/std/zig/system.zig+1-1| ... | ... | @@ -1283,7 +1283,7 @@ fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usi |
| 1283 | 1283 | error.Unseekable => return error.UnableToReadElfFile, |
| 1284 | 1284 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, |
| 1285 | 1285 | error.ConnectionTimedOut => return error.UnableToReadElfFile, |
| 1286 | error.SocketNotConnected => return error.UnableToReadElfFile, | |
| 1286 | error.SocketUnconnected => return error.UnableToReadElfFile, | |
| 1287 | 1287 | error.Unexpected => return error.Unexpected, |
| 1288 | 1288 | error.InputOutput => return error.FileSystem, |
| 1289 | 1289 | error.AccessDenied => return error.Unexpected, |