| author | |
| committer | |
| log | 8d03ec6766fef7833057daa27b264c808bb6c2a2 |
| tree | bd7b8fb9c1f4af7b0da7d4f69226f3806b3e81a6 |
| parent | 062d17ccab495d63799e3ac8831eed485ca8cffe |
10 files changed, 457 insertions(+), 145 deletions(-)
lib/std/Io.zig+109-22| ... | @@ -665,14 +665,14 @@ pub const VTable = struct { | ... | @@ -665,14 +665,14 @@ pub const VTable = struct { |
| 665 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, | 665 | fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void, |
| 666 | fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void, | 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, | 668 | now: *const fn (?*anyopaque, Timestamp.Clock) Timestamp.Error!i96, |
| 669 | sleep: *const fn (?*anyopaque, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void, | 669 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, |
| 670 | 670 | ||
| 671 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, | 671 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server, |
| 672 | accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Stream, | 672 | accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Stream, |
| 673 | ipBind: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.BindOptions) net.IpAddress.BindError!net.Socket, | 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, | 674 | netSend: *const fn (?*anyopaque, net.Socket.Handle, []net.OutgoingMessage, net.SendFlags) net.SendResult, |
| 675 | netReceive: *const fn (?*anyopaque, handle: net.Socket.Handle, buffer: []u8, timeout: Timeout) net.Socket.ReceiveTimeoutError!net.ReceivedMessage, | 675 | netReceive: *const fn (?*anyopaque, net.Socket.Handle, message_buffer: []net.IncomingMessage, data_buffer: []u8, net.ReceiveFlags, Timeout) struct { ?net.Socket.ReceiveTimeoutError, usize }, |
| 676 | netRead: *const fn (?*anyopaque, src: net.Stream, data: [][]u8) net.Stream.Reader.Error!usize, | 676 | netRead: *const fn (?*anyopaque, src: net.Stream, data: [][]u8) net.Stream.Reader.Error!usize, |
| 677 | netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, | 677 | netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, |
| 678 | netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void, | 678 | netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void, |
| ... | @@ -700,46 +700,135 @@ pub const UnexpectedError = error{ | ... | @@ -700,46 +700,135 @@ pub const UnexpectedError = error{ |
| 700 | pub const Dir = @import("Io/Dir.zig"); | 700 | pub const Dir = @import("Io/Dir.zig"); |
| 701 | pub const File = @import("Io/File.zig"); | 701 | pub const File = @import("Io/File.zig"); |
| 702 | 702 | ||
| 703 | pub const Timestamp = enum(i96) { | 703 | pub const Timestamp = struct { |
| 704 | _, | 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 | pub fn durationTo(from: Timestamp, to: Timestamp) Duration { | 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 | pub fn addDuration(from: Timestamp, duration: Duration) Timestamp { | 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 { | 750 | pub const Error = error{UnsupportedClock} || UnexpectedError; |
| 715 | const now_ts = try now(io, clockid); | 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 | return addDuration(now_ts, duration); | 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 | pub fn compare(lhs: Timestamp, op: std.math.CompareOperator, rhs: Timestamp) bool { | 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 | pub const Duration = struct { | 791 | pub const Duration = struct { |
| 724 | nanoseconds: i96, | 792 | nanoseconds: i96, |
| 725 | 793 | ||
| 726 | pub fn ms(x: u64) Duration { | 794 | pub fn fromMilliseconds(x: i64) Duration { |
| 727 | return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_ms }; | 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 | return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_s }; | 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 | pub const Timeout = union(enum) { | 812 | pub const Timeout = union(enum) { |
| 735 | none, | 813 | none, |
| 736 | duration: Duration, | 814 | duration: ClockAndDuration, |
| 737 | deadline: Timestamp, | 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 | pub const AnyFuture = opaque {}; | 833 | pub const AnyFuture = opaque {}; |
| 745 | 834 | ||
| ... | @@ -1231,12 +1320,10 @@ pub fn cancelRequested(io: Io) bool { | ... | @@ -1231,12 +1320,10 @@ pub fn cancelRequested(io: Io) bool { |
| 1231 | return io.vtable.cancelRequested(io.userdata); | 1320 | return io.vtable.cancelRequested(io.userdata); |
| 1232 | } | 1321 | } |
| 1233 | 1322 | ||
| 1234 | pub fn now(io: Io, clockid: std.posix.clockid_t) NowError!Timestamp { | 1323 | pub const SleepError = error{UnsupportedClock} || UnexpectedError || Cancelable; |
| 1235 | return io.vtable.now(io.userdata, clockid); | ||
| 1236 | } | ||
| 1237 | 1324 | ||
| 1238 | pub fn sleep(io: Io, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void { | 1325 | pub fn sleep(io: Io, timeout: Timeout) SleepError!void { |
| 1239 | return io.vtable.sleep(io.userdata, clockid, timeout); | 1326 | return io.vtable.sleep(io.userdata, timeout); |
| 1240 | } | 1327 | } |
| 1241 | 1328 | ||
| 1242 | pub fn sleepDuration(io: Io, duration: Duration) SleepError!void { | 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,7 +1406,7 @@ fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: std.posix.o |
| 1406 | .ISDIR => return error.IsDir, | 1406 | .ISDIR => return error.IsDir, |
| 1407 | .NOBUFS => return error.SystemResources, | 1407 | .NOBUFS => return error.SystemResources, |
| 1408 | .NOMEM => return error.SystemResources, | 1408 | .NOMEM => return error.SystemResources, |
| 1409 | .NOTCONN => return error.SocketNotConnected, | 1409 | .NOTCONN => return error.SocketUnconnected, |
| 1410 | .CONNRESET => return error.ConnectionResetByPeer, | 1410 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1411 | .TIMEDOUT => return error.ConnectionTimedOut, | 1411 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1412 | .NXIO => return error.Unseekable, | 1412 | .NXIO => return error.Unseekable, |
lib/std/Io/File.zig+1-1| ... | @@ -157,7 +157,7 @@ pub const ReadStreamingError = error{ | ... | @@ -157,7 +157,7 @@ pub const ReadStreamingError = error{ |
| 157 | ConnectionResetByPeer, | 157 | ConnectionResetByPeer, |
| 158 | ConnectionTimedOut, | 158 | ConnectionTimedOut, |
| 159 | NotOpenForReading, | 159 | NotOpenForReading, |
| 160 | SocketNotConnected, | 160 | SocketUnconnected, |
| 161 | /// This error occurs when no global event loop is configured, | 161 | /// This error occurs when no global event loop is configured, |
| 162 | /// and reading from the file descriptor would block. | 162 | /// and reading from the file descriptor would block. |
| 163 | WouldBlock, | 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,7 +811,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File |
| 811 | .ISDIR => return error.IsDir, | 811 | .ISDIR => return error.IsDir, |
| 812 | .NOBUFS => return error.SystemResources, | 812 | .NOBUFS => return error.SystemResources, |
| 813 | .NOMEM => return error.SystemResources, | 813 | .NOMEM => return error.SystemResources, |
| 814 | .NOTCONN => return error.SocketNotConnected, | 814 | .NOTCONN => return error.SocketUnconnected, |
| 815 | .CONNRESET => return error.ConnectionResetByPeer, | 815 | .CONNRESET => return error.ConnectionResetByPeer, |
| 816 | .TIMEDOUT => return error.ConnectionTimedOut, | 816 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 817 | .NOTCAPABLE => return error.AccessDenied, | 817 | .NOTCAPABLE => return error.AccessDenied, |
| ... | @@ -834,7 +834,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File | ... | @@ -834,7 +834,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File |
| 834 | .ISDIR => return error.IsDir, | 834 | .ISDIR => return error.IsDir, |
| 835 | .NOBUFS => return error.SystemResources, | 835 | .NOBUFS => return error.SystemResources, |
| 836 | .NOMEM => return error.SystemResources, | 836 | .NOMEM => return error.SystemResources, |
| 837 | .NOTCONN => return error.SocketNotConnected, | 837 | .NOTCONN => return error.SocketUnconnected, |
| 838 | .CONNRESET => return error.ConnectionResetByPeer, | 838 | .CONNRESET => return error.ConnectionResetByPeer, |
| 839 | .TIMEDOUT => return error.ConnectionTimedOut, | 839 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 840 | else => |err| return posix.unexpectedErrno(err), | 840 | else => |err| return posix.unexpectedErrno(err), |
| ... | @@ -933,7 +933,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset | ... | @@ -933,7 +933,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset |
| 933 | .ISDIR => return error.IsDir, | 933 | .ISDIR => return error.IsDir, |
| 934 | .NOBUFS => return error.SystemResources, | 934 | .NOBUFS => return error.SystemResources, |
| 935 | .NOMEM => return error.SystemResources, | 935 | .NOMEM => return error.SystemResources, |
| 936 | .NOTCONN => return error.SocketNotConnected, | 936 | .NOTCONN => return error.SocketUnconnected, |
| 937 | .CONNRESET => return error.ConnectionResetByPeer, | 937 | .CONNRESET => return error.ConnectionResetByPeer, |
| 938 | .TIMEDOUT => return error.ConnectionTimedOut, | 938 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 939 | .NXIO => return error.Unseekable, | 939 | .NXIO => return error.Unseekable, |
| ... | @@ -960,7 +960,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset | ... | @@ -960,7 +960,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset |
| 960 | .ISDIR => return error.IsDir, | 960 | .ISDIR => return error.IsDir, |
| 961 | .NOBUFS => return error.SystemResources, | 961 | .NOBUFS => return error.SystemResources, |
| 962 | .NOMEM => return error.SystemResources, | 962 | .NOMEM => return error.SystemResources, |
| 963 | .NOTCONN => return error.SocketNotConnected, | 963 | .NOTCONN => return error.SocketUnconnected, |
| 964 | .CONNRESET => return error.ConnectionResetByPeer, | 964 | .CONNRESET => return error.ConnectionResetByPeer, |
| 965 | .TIMEDOUT => return error.ConnectionTimedOut, | 965 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 966 | .NXIO => return error.Unseekable, | 966 | .NXIO => return error.Unseekable, |
| ... | @@ -999,19 +999,29 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi | ... | @@ -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 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1003 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1004 | try pool.checkCancel(); | 1004 | _ = pool; |
| 1005 | const timespec = try posix.clock_gettime(clockid); | 1005 | const clock_id: posix.clockid_t = clockToPosix(clock); |
| 1006 | return @enumFromInt(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec); | 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 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 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 | const deadline_nanoseconds: i96 = switch (timeout) { | 1021 | const deadline_nanoseconds: i96 = switch (timeout) { |
| 1012 | .none => std.math.maxInt(i96), | 1022 | .none => std.math.maxInt(i96), |
| 1013 | .duration => |duration| duration.nanoseconds, | 1023 | .duration => |d| d.duration.nanoseconds, |
| 1014 | .deadline => |deadline| @intFromEnum(deadline), | 1024 | .deadline => |deadline| deadline.nanoseconds, |
| 1015 | }; | 1025 | }; |
| 1016 | var timespec: posix.timespec = .{ | 1026 | var timespec: posix.timespec = .{ |
| 1017 | .sec = @intCast(@divFloor(deadline_nanoseconds, std.time.ns_per_s)), | 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,13 +1029,12 @@ fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, timeout: Io.Timeout) I |
| 1019 | }; | 1029 | }; |
| 1020 | while (true) { | 1030 | while (true) { |
| 1021 | try pool.checkCancel(); | 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 | .none, .duration => false, | 1033 | .none, .duration => false, |
| 1024 | .deadline => true, | 1034 | .deadline => true, |
| 1025 | } }, &timespec, &timespec))) { | 1035 | } }, &timespec, &timespec))) { |
| 1026 | .SUCCESS => return, | 1036 | .SUCCESS => return, |
| 1027 | .FAULT => |err| return errnoBug(err), | 1037 | .INTR => continue, |
| 1028 | .INTR => {}, | ||
| 1029 | .INVAL => return error.UnsupportedClock, | 1038 | .INVAL => return error.UnsupportedClock, |
| 1030 | else => |err| return posix.unexpectedErrno(err), | 1039 | else => |err| return posix.unexpectedErrno(err), |
| 1031 | } | 1040 | } |
| ... | @@ -1313,15 +1322,18 @@ fn netSend( | ... | @@ -1313,15 +1322,18 @@ fn netSend( |
| 1313 | handle: Io.net.Socket.Handle, | 1322 | handle: Io.net.Socket.Handle, |
| 1314 | messages: []Io.net.OutgoingMessage, | 1323 | messages: []Io.net.OutgoingMessage, |
| 1315 | flags: Io.net.SendFlags, | 1324 | flags: Io.net.SendFlags, |
| 1316 | ) Io.net.Socket.SendError!void { | 1325 | ) Io.net.SendResult { |
| 1317 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1326 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1318 | 1327 | ||
| 1319 | if (have_sendmmsg) { | 1328 | if (have_sendmmsg) { |
| 1320 | var i: usize = 0; | 1329 | var i: usize = 0; |
| 1321 | while (messages.len - i != 0) { | 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 | try pool.checkCancel(); | 1339 | try pool.checkCancel(); |
| ... | @@ -1391,11 +1403,11 @@ fn netSendMany( | ... | @@ -1391,11 +1403,11 @@ fn netSendMany( |
| 1391 | .NOMEM => return error.SystemResources, | 1403 | .NOMEM => return error.SystemResources, |
| 1392 | .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket. | 1404 | .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket. |
| 1393 | .OPNOTSUPP => |err| return errnoBug(err), // Some bit in the flags argument is inappropriate for the socket type. | 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 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, | 1407 | .AFNOSUPPORT => return error.AddressFamilyUnsupported, |
| 1396 | .HOSTUNREACH => return error.NetworkUnreachable, | 1408 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 1397 | .NETUNREACH => return error.NetworkUnreachable, | 1409 | .NETUNREACH => return error.NetworkUnreachable, |
| 1398 | .NOTCONN => return error.SocketNotConnected, | 1410 | .NOTCONN => return error.SocketUnconnected, |
| 1399 | .NETDOWN => return error.NetworkDown, | 1411 | .NETDOWN => return error.NetworkDown, |
| 1400 | else => |err| return posix.unexpectedErrno(err), | 1412 | else => |err| return posix.unexpectedErrno(err), |
| 1401 | } | 1413 | } |
| ... | @@ -1405,16 +1417,128 @@ fn netSendMany( | ... | @@ -1405,16 +1417,128 @@ fn netSendMany( |
| 1405 | fn netReceive( | 1417 | fn netReceive( |
| 1406 | userdata: ?*anyopaque, | 1418 | userdata: ?*anyopaque, |
| 1407 | handle: Io.net.Socket.Handle, | 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 | timeout: Io.Timeout, | 1423 | timeout: Io.Timeout, |
| 1410 | ) Io.net.Socket.ReceiveTimeoutError!Io.net.ReceivedMessage { | 1424 | ) struct { ?Io.net.Socket.ReceiveTimeoutError, usize } { |
| 1411 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 1425 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1412 | try pool.checkCancel(); | ||
| 1413 | 1426 | ||
| 1414 | _ = handle; | 1427 | // recvmmsg is useless, here's why: |
| 1415 | _ = buffer; | 1428 | // * [timeout bug](https://bugzilla.kernel.org/show_bug.cgi?id=75371) |
| 1416 | _ = timeout; | 1429 | // * it wants iovecs for each message but we have a better API: one data |
| 1417 | @panic("TODO"); | 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 | fn netWritePosix( | 1544 | fn netWritePosix( |
| ... | @@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 { | ... | @@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 { |
| 1653 | fn recoverableOsBugDetected() void { | 1777 | fn recoverableOsBugDetected() void { |
| 1654 | if (builtin.mode == .Debug) unreachable; | 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,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 | from: IpAddress, | 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 | pub const OutgoingMessage = struct { | 735 | pub const OutgoingMessage = struct { |
| ... | @@ -718,6 +750,14 @@ pub const SendFlags = packed struct(u8) { | ... | @@ -718,6 +750,14 @@ pub const SendFlags = packed struct(u8) { |
| 718 | _: u3 = 0, | 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 | pub const Interface = struct { | 761 | pub const Interface = struct { |
| 722 | /// Value 0 indicates `none`. | 762 | /// Value 0 indicates `none`. |
| 723 | index: u32, | 763 | index: u32, |
| ... | @@ -839,7 +879,7 @@ pub const Socket = struct { | ... | @@ -839,7 +879,7 @@ pub const Socket = struct { |
| 839 | ConnectionResetByPeer, | 879 | ConnectionResetByPeer, |
| 840 | /// Local end has been shut down on a connection-oriented socket, or | 880 | /// Local end has been shut down on a connection-oriented socket, or |
| 841 | /// the socket was never connected. | 881 | /// the socket was never connected. |
| 842 | SocketNotConnected, | 882 | SocketUnconnected, |
| 843 | } || Io.UnexpectedError || Io.Cancelable; | 883 | } || Io.UnexpectedError || Io.Cancelable; |
| 844 | 884 | ||
| 845 | /// Transfers `data` to `dest`, connectionless, in one packet. | 885 | /// Transfers `data` to `dest`, connectionless, in one packet. |
| ... | @@ -853,14 +893,34 @@ pub const Socket = struct { | ... | @@ -853,14 +893,34 @@ pub const Socket = struct { |
| 853 | return io.vtable.netSend(io.userdata, s.handle, messages, flags); | 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 | /// Waits for data. Connectionless. | 916 | /// Waits for data. Connectionless. |
| 859 | /// | 917 | /// |
| 860 | /// See also: | 918 | /// See also: |
| 861 | /// * `receiveTimeout` | 919 | /// * `receiveTimeout` |
| 862 | pub fn receive(s: *const Socket, io: Io, source: *const IpAddress, buffer: []u8) ReceiveError!ReceivedMessage { | 920 | pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage { |
| 863 | return io.vtable.netReceive(io.userdata, s.handle, source, buffer, .none); | 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 | pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error; | 926 | pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error; |
| ... | @@ -871,13 +931,36 @@ pub const Socket = struct { | ... | @@ -871,13 +931,36 @@ pub const Socket = struct { |
| 871 | /// | 931 | /// |
| 872 | /// See also: | 932 | /// See also: |
| 873 | /// * `receive` | 933 | /// * `receive` |
| 934 | /// * `receiveManyTimeout` | ||
| 874 | pub fn receiveTimeout( | 935 | pub fn receiveTimeout( |
| 875 | s: *const Socket, | 936 | s: *const Socket, |
| 876 | io: Io, | 937 | io: Io, |
| 877 | buffer: []u8, | 938 | buffer: []u8, |
| 878 | timeout: Io.Timeout, | 939 | timeout: Io.Timeout, |
| 879 | ) ReceiveTimeoutError!ReceivedMessage { | 940 | ) ReceiveTimeoutError!IncomingMessage { |
| 880 | return io.vtable.netReceive(io.userdata, s.handle, buffer, timeout); | 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,7 +52,7 @@ pub const LookupError = error{ |
| 52 | InvalidDnsARecord, | 52 | InvalidDnsARecord, |
| 53 | InvalidDnsAAAARecord, | 53 | InvalidDnsAAAARecord, |
| 54 | NameServerFailure, | 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 | pub const LookupResult = struct { | 57 | pub const LookupResult = struct { |
| 58 | /// How many `LookupOptions.addresses_buffer` elements are populated. | 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,11 +222,11 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 222 | .{ .af = .ip4, .rr = std.posix.RR.AAAA }, | 222 | .{ .af = .ip4, .rr = std.posix.RR.AAAA }, |
| 223 | }; | 223 | }; |
| 224 | var query_buffers: [2][280]u8 = undefined; | 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 | var queries_buffer: [2][]const u8 = undefined; | 226 | var queries_buffer: [2][]const u8 = undefined; |
| 227 | var answers_buffer: [2][]const u8 = undefined; | 227 | var answers_buffer: [2][]const u8 = undefined; |
| 228 | var nq: usize = 0; | 228 | var nq: usize = 0; |
| 229 | var next_answer_buffer: usize = 0; | 229 | var answer_buffer_i: usize = 0; |
| 230 | 230 | ||
| 231 | for (family_records) |fr| { | 231 | for (family_records) |fr| { |
| 232 | if (options.family != fr.af) { | 232 | if (options.family != fr.af) { |
| ... | @@ -262,79 +262,89 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio | ... | @@ -262,79 +262,89 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio |
| 262 | const mapped_nameservers = if (any_ip6) ip4_mapped[0..rc.nameservers_len] else rc.nameservers(); | 262 | const mapped_nameservers = if (any_ip6) ip4_mapped[0..rc.nameservers_len] else rc.nameservers(); |
| 263 | const queries = queries_buffer[0..nq]; | 263 | const queries = queries_buffer[0..nq]; |
| 264 | const answers = answers_buffer[0..queries.len]; | 264 | const answers = answers_buffer[0..queries.len]; |
| 265 | var answers_remaining = answers.len; | ||
| 265 | for (answers) |*answer| answer.len = 0; | 266 | for (answers) |*answer| answer.len = 0; |
| 266 | 267 | ||
| 267 | var now_ts = try io.now(.MONOTONIC); | 268 | // boottime is chosen because time the computer is suspended should count |
| 268 | const final_ts = now_ts.addDuration(.seconds(rc.timeout_seconds)); | 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 | const attempt_duration: Io.Duration = .{ | 272 | const attempt_duration: Io.Duration = .{ |
| 270 | .nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts, | 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)) { | 276 | send: while (now_ts.compare(.lt, final_ts)) : (now_ts = try Io.Timestamp.now(io, .boottime)) { |
| 274 | var message_buffer: [queries_buffer.len * ResolvConf.max_nameservers]Io.net.OutgoingMessage = undefined; | 277 | const max_messages = queries_buffer.len * ResolvConf.max_nameservers; |
| 275 | var message_i: usize = 0; | 278 | { |
| 276 | for (queries, answers) |query, *answer| { | 279 | var message_buffer: [max_messages]Io.net.OutgoingMessage = undefined; |
| 277 | if (answer.len != 0) continue; | 280 | var message_i: usize = 0; |
| 278 | for (mapped_nameservers) |*ns| { | 281 | for (queries, answers) |query, *answer| { |
| 279 | message_buffer[message_i] = .{ | 282 | if (answer.len != 0) continue; |
| 280 | .address = ns, | 283 | for (mapped_nameservers) |*ns| { |
| 281 | .data_ptr = query.ptr, | 284 | message_buffer[message_i] = .{ |
| 282 | .data_len = query.len, | 285 | .address = ns, |
| 283 | }; | 286 | .data_ptr = query.ptr, |
| 284 | message_i += 1; | 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 | const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) }; | 295 | const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) }; |
| 290 | 296 | ||
| 291 | while (true) { | 297 | while (true) { |
| 292 | const buf = &answer_buffers[next_answer_buffer]; | 298 | var message_buffer: [max_messages]Io.net.IncomingMessage = undefined; |
| 293 | const reply = socket.receiveTimeout(io, buf, timeout) catch |err| switch (err) { | 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 | error.Canceled => return error.Canceled, | 344 | error.Canceled => return error.Canceled, |
| 295 | error.Timeout => continue :send, | 345 | error.Timeout => continue :send, |
| 296 | else => continue, | 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 | } else { | 349 | } else { |
| 340 | return error.NameServerFailure; | 350 | return error.NameServerFailure; |
lib/std/net.zig+4-4| ... | @@ -1916,7 +1916,7 @@ pub const Stream = struct { | ... | @@ -1916,7 +1916,7 @@ pub const Stream = struct { |
| 1916 | MessageTooBig, | 1916 | MessageTooBig, |
| 1917 | NetworkSubsystemFailed, | 1917 | NetworkSubsystemFailed, |
| 1918 | ConnectionResetByPeer, | 1918 | ConnectionResetByPeer, |
| 1919 | SocketNotConnected, | 1919 | SocketUnconnected, |
| 1920 | }; | 1920 | }; |
| 1921 | 1921 | ||
| 1922 | pub const WriteError = posix.SendMsgError || error{ | 1922 | pub const WriteError = posix.SendMsgError || error{ |
| ... | @@ -1925,7 +1925,7 @@ pub const Stream = struct { | ... | @@ -1925,7 +1925,7 @@ pub const Stream = struct { |
| 1925 | MessageTooBig, | 1925 | MessageTooBig, |
| 1926 | NetworkSubsystemFailed, | 1926 | NetworkSubsystemFailed, |
| 1927 | SystemResources, | 1927 | SystemResources, |
| 1928 | SocketNotConnected, | 1928 | SocketUnconnected, |
| 1929 | Unexpected, | 1929 | Unexpected, |
| 1930 | }; | 1930 | }; |
| 1931 | 1931 | ||
| ... | @@ -2003,7 +2003,7 @@ pub const Stream = struct { | ... | @@ -2003,7 +2003,7 @@ pub const Stream = struct { |
| 2003 | .WSAEMSGSIZE => return error.MessageTooBig, | 2003 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 2004 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 2004 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2005 | .WSAENETRESET => return error.ConnectionResetByPeer, | 2005 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2006 | .WSAENOTCONN => return error.SocketNotConnected, | 2006 | .WSAENOTCONN => return error.SocketUnconnected, |
| 2007 | .WSAEWOULDBLOCK => return error.WouldBlock, | 2007 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 2008 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function | 2008 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 2009 | .WSA_IO_PENDING => unreachable, | 2009 | .WSA_IO_PENDING => unreachable, |
| ... | @@ -2170,7 +2170,7 @@ pub const Stream = struct { | ... | @@ -2170,7 +2170,7 @@ pub const Stream = struct { |
| 2170 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 2170 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2171 | .WSAENETRESET => return error.ConnectionResetByPeer, | 2171 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2172 | .WSAENOBUFS => return error.SystemResources, | 2172 | .WSAENOBUFS => return error.SystemResources, |
| 2173 | .WSAENOTCONN => return error.SocketNotConnected, | 2173 | .WSAENOTCONN => return error.SocketUnconnected, |
| 2174 | .WSAENOTSOCK => unreachable, // not a socket | 2174 | .WSAENOTSOCK => unreachable, // not a socket |
| 2175 | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets | 2175 | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets |
| 2176 | .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown | 2176 | .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown |
lib/std/posix.zig+21-21| ... | @@ -841,7 +841,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -841,7 +841,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 841 | .ISDIR => return error.IsDir, | 841 | .ISDIR => return error.IsDir, |
| 842 | .NOBUFS => return error.SystemResources, | 842 | .NOBUFS => return error.SystemResources, |
| 843 | .NOMEM => return error.SystemResources, | 843 | .NOMEM => return error.SystemResources, |
| 844 | .NOTCONN => return error.SocketNotConnected, | 844 | .NOTCONN => return error.SocketUnconnected, |
| 845 | .CONNRESET => return error.ConnectionResetByPeer, | 845 | .CONNRESET => return error.ConnectionResetByPeer, |
| 846 | .TIMEDOUT => return error.ConnectionTimedOut, | 846 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 847 | .NOTCAPABLE => return error.AccessDenied, | 847 | .NOTCAPABLE => return error.AccessDenied, |
| ... | @@ -870,7 +870,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -870,7 +870,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 870 | .ISDIR => return error.IsDir, | 870 | .ISDIR => return error.IsDir, |
| 871 | .NOBUFS => return error.SystemResources, | 871 | .NOBUFS => return error.SystemResources, |
| 872 | .NOMEM => return error.SystemResources, | 872 | .NOMEM => return error.SystemResources, |
| 873 | .NOTCONN => return error.SocketNotConnected, | 873 | .NOTCONN => return error.SocketUnconnected, |
| 874 | .CONNRESET => return error.ConnectionResetByPeer, | 874 | .CONNRESET => return error.ConnectionResetByPeer, |
| 875 | .TIMEDOUT => return error.ConnectionTimedOut, | 875 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 876 | else => |err| return unexpectedErrno(err), | 876 | else => |err| return unexpectedErrno(err), |
| ... | @@ -910,7 +910,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | ... | @@ -910,7 +910,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 910 | .ISDIR => return error.IsDir, | 910 | .ISDIR => return error.IsDir, |
| 911 | .NOBUFS => return error.SystemResources, | 911 | .NOBUFS => return error.SystemResources, |
| 912 | .NOMEM => return error.SystemResources, | 912 | .NOMEM => return error.SystemResources, |
| 913 | .NOTCONN => return error.SocketNotConnected, | 913 | .NOTCONN => return error.SocketUnconnected, |
| 914 | .CONNRESET => return error.ConnectionResetByPeer, | 914 | .CONNRESET => return error.ConnectionResetByPeer, |
| 915 | .TIMEDOUT => return error.ConnectionTimedOut, | 915 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 916 | .NOTCAPABLE => return error.AccessDenied, | 916 | .NOTCAPABLE => return error.AccessDenied, |
| ... | @@ -932,7 +932,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | ... | @@ -932,7 +932,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 932 | .ISDIR => return error.IsDir, | 932 | .ISDIR => return error.IsDir, |
| 933 | .NOBUFS => return error.SystemResources, | 933 | .NOBUFS => return error.SystemResources, |
| 934 | .NOMEM => return error.SystemResources, | 934 | .NOMEM => return error.SystemResources, |
| 935 | .NOTCONN => return error.SocketNotConnected, | 935 | .NOTCONN => return error.SocketUnconnected, |
| 936 | .CONNRESET => return error.ConnectionResetByPeer, | 936 | .CONNRESET => return error.ConnectionResetByPeer, |
| 937 | .TIMEDOUT => return error.ConnectionTimedOut, | 937 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 938 | else => |err| return unexpectedErrno(err), | 938 | else => |err| return unexpectedErrno(err), |
| ... | @@ -979,7 +979,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { | ... | @@ -979,7 +979,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 979 | .ISDIR => return error.IsDir, | 979 | .ISDIR => return error.IsDir, |
| 980 | .NOBUFS => return error.SystemResources, | 980 | .NOBUFS => return error.SystemResources, |
| 981 | .NOMEM => return error.SystemResources, | 981 | .NOMEM => return error.SystemResources, |
| 982 | .NOTCONN => return error.SocketNotConnected, | 982 | .NOTCONN => return error.SocketUnconnected, |
| 983 | .CONNRESET => return error.ConnectionResetByPeer, | 983 | .CONNRESET => return error.ConnectionResetByPeer, |
| 984 | .TIMEDOUT => return error.ConnectionTimedOut, | 984 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 985 | .NXIO => return error.Unseekable, | 985 | .NXIO => return error.Unseekable, |
| ... | @@ -1012,7 +1012,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { | ... | @@ -1012,7 +1012,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 1012 | .ISDIR => return error.IsDir, | 1012 | .ISDIR => return error.IsDir, |
| 1013 | .NOBUFS => return error.SystemResources, | 1013 | .NOBUFS => return error.SystemResources, |
| 1014 | .NOMEM => return error.SystemResources, | 1014 | .NOMEM => return error.SystemResources, |
| 1015 | .NOTCONN => return error.SocketNotConnected, | 1015 | .NOTCONN => return error.SocketUnconnected, |
| 1016 | .CONNRESET => return error.ConnectionResetByPeer, | 1016 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1017 | .TIMEDOUT => return error.ConnectionTimedOut, | 1017 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1018 | .NXIO => return error.Unseekable, | 1018 | .NXIO => return error.Unseekable, |
| ... | @@ -1130,7 +1130,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { | ... | @@ -1130,7 +1130,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1130 | .ISDIR => return error.IsDir, | 1130 | .ISDIR => return error.IsDir, |
| 1131 | .NOBUFS => return error.SystemResources, | 1131 | .NOBUFS => return error.SystemResources, |
| 1132 | .NOMEM => return error.SystemResources, | 1132 | .NOMEM => return error.SystemResources, |
| 1133 | .NOTCONN => return error.SocketNotConnected, | 1133 | .NOTCONN => return error.SocketUnconnected, |
| 1134 | .CONNRESET => return error.ConnectionResetByPeer, | 1134 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1135 | .TIMEDOUT => return error.ConnectionTimedOut, | 1135 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1136 | .NXIO => return error.Unseekable, | 1136 | .NXIO => return error.Unseekable, |
| ... | @@ -1156,7 +1156,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { | ... | @@ -1156,7 +1156,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1156 | .ISDIR => return error.IsDir, | 1156 | .ISDIR => return error.IsDir, |
| 1157 | .NOBUFS => return error.SystemResources, | 1157 | .NOBUFS => return error.SystemResources, |
| 1158 | .NOMEM => return error.SystemResources, | 1158 | .NOMEM => return error.SystemResources, |
| 1159 | .NOTCONN => return error.SocketNotConnected, | 1159 | .NOTCONN => return error.SocketUnconnected, |
| 1160 | .CONNRESET => return error.ConnectionResetByPeer, | 1160 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1161 | .TIMEDOUT => return error.ConnectionTimedOut, | 1161 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1162 | .NXIO => return error.Unseekable, | 1162 | .NXIO => return error.Unseekable, |
| ... | @@ -3696,7 +3696,7 @@ pub const ShutdownError = error{ | ... | @@ -3696,7 +3696,7 @@ pub const ShutdownError = error{ |
| 3696 | NetworkSubsystemFailed, | 3696 | NetworkSubsystemFailed, |
| 3697 | 3697 | ||
| 3698 | /// The socket is not connected (connection-oriented sockets only). | 3698 | /// The socket is not connected (connection-oriented sockets only). |
| 3699 | SocketNotConnected, | 3699 | SocketUnconnected, |
| 3700 | SystemResources, | 3700 | SystemResources, |
| 3701 | } || UnexpectedError; | 3701 | } || UnexpectedError; |
| 3702 | 3702 | ||
| ... | @@ -3716,7 +3716,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { | ... | @@ -3716,7 +3716,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3716 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, | 3716 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, |
| 3717 | .WSAEINVAL => unreachable, | 3717 | .WSAEINVAL => unreachable, |
| 3718 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 3718 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 3719 | .WSAENOTCONN => return error.SocketNotConnected, | 3719 | .WSAENOTCONN => return error.SocketUnconnected, |
| 3720 | .WSAENOTSOCK => unreachable, | 3720 | .WSAENOTSOCK => unreachable, |
| 3721 | .WSANOTINITIALISED => unreachable, | 3721 | .WSANOTINITIALISED => unreachable, |
| 3722 | else => |err| return windows.unexpectedWSAError(err), | 3722 | else => |err| return windows.unexpectedWSAError(err), |
| ... | @@ -3731,7 +3731,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { | ... | @@ -3731,7 +3731,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3731 | .SUCCESS => return, | 3731 | .SUCCESS => return, |
| 3732 | .BADF => unreachable, | 3732 | .BADF => unreachable, |
| 3733 | .INVAL => unreachable, | 3733 | .INVAL => unreachable, |
| 3734 | .NOTCONN => return error.SocketNotConnected, | 3734 | .NOTCONN => return error.SocketUnconnected, |
| 3735 | .NOTSOCK => unreachable, | 3735 | .NOTSOCK => unreachable, |
| 3736 | .NOBUFS => return error.SystemResources, | 3736 | .NOBUFS => return error.SystemResources, |
| 3737 | else => |err| return unexpectedErrno(err), | 3737 | else => |err| return unexpectedErrno(err), |
| ... | @@ -6166,7 +6166,7 @@ pub const SendMsgError = SendError || error{ | ... | @@ -6166,7 +6166,7 @@ pub const SendMsgError = SendError || error{ |
| 6166 | NotDir, | 6166 | NotDir, |
| 6167 | 6167 | ||
| 6168 | /// The socket is not connected (connection-oriented sockets only). | 6168 | /// The socket is not connected (connection-oriented sockets only). |
| 6169 | SocketNotConnected, | 6169 | SocketUnconnected, |
| 6170 | AddressNotAvailable, | 6170 | AddressNotAvailable, |
| 6171 | }; | 6171 | }; |
| 6172 | 6172 | ||
| ... | @@ -6197,7 +6197,7 @@ pub fn sendmsg( | ... | @@ -6197,7 +6197,7 @@ pub fn sendmsg( |
| 6197 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 6197 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6198 | .WSAENETRESET => return error.ConnectionResetByPeer, | 6198 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6199 | .WSAENETUNREACH => return error.NetworkUnreachable, | 6199 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6200 | .WSAENOTCONN => return error.SocketNotConnected, | 6200 | .WSAENOTCONN => return error.SocketUnconnected, |
| 6201 | .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. | 6201 | .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. |
| 6202 | .WSAEWOULDBLOCK => return error.WouldBlock, | 6202 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6203 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. | 6203 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | @@ -6233,7 +6233,7 @@ pub fn sendmsg( | ... | @@ -6233,7 +6233,7 @@ pub fn sendmsg( |
| 6233 | .NOTDIR => return error.NotDir, | 6233 | .NOTDIR => return error.NotDir, |
| 6234 | .HOSTUNREACH => return error.NetworkUnreachable, | 6234 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6235 | .NETUNREACH => return error.NetworkUnreachable, | 6235 | .NETUNREACH => return error.NetworkUnreachable, |
| 6236 | .NOTCONN => return error.SocketNotConnected, | 6236 | .NOTCONN => return error.SocketUnconnected, |
| 6237 | .NETDOWN => return error.NetworkSubsystemFailed, | 6237 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6238 | else => |err| return unexpectedErrno(err), | 6238 | else => |err| return unexpectedErrno(err), |
| 6239 | } | 6239 | } |
| ... | @@ -6300,7 +6300,7 @@ pub fn sendto( | ... | @@ -6300,7 +6300,7 @@ pub fn sendto( |
| 6300 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 6300 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6301 | .WSAENETRESET => return error.ConnectionResetByPeer, | 6301 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6302 | .WSAENETUNREACH => return error.NetworkUnreachable, | 6302 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6303 | .WSAENOTCONN => return error.SocketNotConnected, | 6303 | .WSAENOTCONN => return error.SocketUnconnected, |
| 6304 | .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. | 6304 | .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. |
| 6305 | .WSAEWOULDBLOCK => return error.WouldBlock, | 6305 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6306 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. | 6306 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | @@ -6338,7 +6338,7 @@ pub fn sendto( | ... | @@ -6338,7 +6338,7 @@ pub fn sendto( |
| 6338 | .NOTDIR => return error.NotDir, | 6338 | .NOTDIR => return error.NotDir, |
| 6339 | .HOSTUNREACH => return error.NetworkUnreachable, | 6339 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6340 | .NETUNREACH => return error.NetworkUnreachable, | 6340 | .NETUNREACH => return error.NetworkUnreachable, |
| 6341 | .NOTCONN => return error.SocketNotConnected, | 6341 | .NOTCONN => return error.SocketUnconnected, |
| 6342 | .NETDOWN => return error.NetworkSubsystemFailed, | 6342 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6343 | else => |err| return unexpectedErrno(err), | 6343 | else => |err| return unexpectedErrno(err), |
| 6344 | } | 6344 | } |
| ... | @@ -6378,7 +6378,7 @@ pub fn send( | ... | @@ -6378,7 +6378,7 @@ pub fn send( |
| 6378 | error.NotDir => unreachable, | 6378 | error.NotDir => unreachable, |
| 6379 | error.NetworkUnreachable => unreachable, | 6379 | error.NetworkUnreachable => unreachable, |
| 6380 | error.AddressNotAvailable => unreachable, | 6380 | error.AddressNotAvailable => unreachable, |
| 6381 | error.SocketNotConnected => unreachable, | 6381 | error.SocketUnconnected => unreachable, |
| 6382 | error.UnreachableAddress => unreachable, | 6382 | error.UnreachableAddress => unreachable, |
| 6383 | else => |e| return e, | 6383 | else => |e| return e, |
| 6384 | }; | 6384 | }; |
| ... | @@ -6564,7 +6564,7 @@ pub const RecvFromError = error{ | ... | @@ -6564,7 +6564,7 @@ pub const RecvFromError = error{ |
| 6564 | NetworkSubsystemFailed, | 6564 | NetworkSubsystemFailed, |
| 6565 | 6565 | ||
| 6566 | /// The socket is not connected (connection-oriented sockets only). | 6566 | /// The socket is not connected (connection-oriented sockets only). |
| 6567 | SocketNotConnected, | 6567 | SocketUnconnected, |
| 6568 | 6568 | ||
| 6569 | /// The other end closed the socket unexpectedly or a read is executed on a shut down socket | 6569 | /// The other end closed the socket unexpectedly or a read is executed on a shut down socket |
| 6570 | BrokenPipe, | 6570 | BrokenPipe, |
| ... | @@ -6593,7 +6593,7 @@ pub fn recvfrom( | ... | @@ -6593,7 +6593,7 @@ pub fn recvfrom( |
| 6593 | .WSAEINVAL => return error.SocketNotBound, | 6593 | .WSAEINVAL => return error.SocketNotBound, |
| 6594 | .WSAEMSGSIZE => return error.MessageTooBig, | 6594 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 6595 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | 6595 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6596 | .WSAENOTCONN => return error.SocketNotConnected, | 6596 | .WSAENOTCONN => return error.SocketUnconnected, |
| 6597 | .WSAEWOULDBLOCK => return error.WouldBlock, | 6597 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6598 | .WSAETIMEDOUT => return error.ConnectionTimedOut, | 6598 | .WSAETIMEDOUT => return error.ConnectionTimedOut, |
| 6599 | // TODO: handle more errors | 6599 | // TODO: handle more errors |
| ... | @@ -6608,7 +6608,7 @@ pub fn recvfrom( | ... | @@ -6608,7 +6608,7 @@ pub fn recvfrom( |
| 6608 | .BADF => unreachable, // always a race condition | 6608 | .BADF => unreachable, // always a race condition |
| 6609 | .FAULT => unreachable, | 6609 | .FAULT => unreachable, |
| 6610 | .INVAL => unreachable, | 6610 | .INVAL => unreachable, |
| 6611 | .NOTCONN => return error.SocketNotConnected, | 6611 | .NOTCONN => return error.SocketUnconnected, |
| 6612 | .NOTSOCK => unreachable, | 6612 | .NOTSOCK => unreachable, |
| 6613 | .INTR => continue, | 6613 | .INTR => continue, |
| 6614 | .AGAIN => return error.WouldBlock, | 6614 | .AGAIN => return error.WouldBlock, |
| ... | @@ -6660,7 +6660,7 @@ pub fn recvmsg( | ... | @@ -6660,7 +6660,7 @@ pub fn recvmsg( |
| 6660 | .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified | 6660 | .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified |
| 6661 | .NOBUFS => return error.SystemResources, | 6661 | .NOBUFS => return error.SystemResources, |
| 6662 | .NOMEM => return error.SystemResources, | 6662 | .NOMEM => return error.SystemResources, |
| 6663 | .NOTCONN => return error.SocketNotConnected, | 6663 | .NOTCONN => return error.SocketUnconnected, |
| 6664 | .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | 6664 | .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. |
| 6665 | .MSGSIZE => return error.MessageTooBig, | 6665 | .MSGSIZE => return error.MessageTooBig, |
| 6666 | .PIPE => return error.BrokenPipe, | 6666 | .PIPE => return error.BrokenPipe, |
lib/std/posix/test.zig+1-1| ... | @@ -630,7 +630,7 @@ test "shutdown socket" { | ... | @@ -630,7 +630,7 @@ test "shutdown socket" { |
| 630 | } | 630 | } |
| 631 | const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0); | 631 | const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0); |
| 632 | posix.shutdown(sock, .both) catch |err| switch (err) { | 632 | posix.shutdown(sock, .both) catch |err| switch (err) { |
| 633 | error.SocketNotConnected => {}, | 633 | error.SocketUnconnected => {}, |
| 634 | else => |e| return e, | 634 | else => |e| return e, |
| 635 | }; | 635 | }; |
| 636 | std.net.Stream.close(.{ .handle = sock }); | 636 | std.net.Stream.close(.{ .handle = sock }); |
lib/std/zig/system.zig+1-1| ... | @@ -1263,7 +1263,7 @@ fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usi | ... | @@ -1263,7 +1263,7 @@ fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usi |
| 1263 | error.Unseekable => return error.UnableToReadElfFile, | 1263 | error.Unseekable => return error.UnableToReadElfFile, |
| 1264 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, | 1264 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, |
| 1265 | error.ConnectionTimedOut => return error.UnableToReadElfFile, | 1265 | error.ConnectionTimedOut => return error.UnableToReadElfFile, |
| 1266 | error.SocketNotConnected => return error.UnableToReadElfFile, | 1266 | error.SocketUnconnected => return error.UnableToReadElfFile, |
| 1267 | error.Unexpected => return error.Unexpected, | 1267 | error.Unexpected => return error.Unexpected, |
| 1268 | error.InputOutput => return error.FileSystem, | 1268 | error.InputOutput => return error.FileSystem, |
| 1269 | error.AccessDenied => return error.Unexpected, | 1269 | error.AccessDenied => return error.Unexpected, |