| 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 | 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| ... | ... | @@ -1916,7 +1916,7 @@ pub const Stream = struct { |
| 1916 | 1916 | MessageTooBig, |
| 1917 | 1917 | NetworkSubsystemFailed, |
| 1918 | 1918 | ConnectionResetByPeer, |
| 1919 | SocketNotConnected, | |
| 1919 | SocketUnconnected, | |
| 1920 | 1920 | }; |
| 1921 | 1921 | |
| 1922 | 1922 | pub const WriteError = posix.SendMsgError || error{ |
| ... | ... | @@ -1925,7 +1925,7 @@ pub const Stream = struct { |
| 1925 | 1925 | MessageTooBig, |
| 1926 | 1926 | NetworkSubsystemFailed, |
| 1927 | 1927 | SystemResources, |
| 1928 | SocketNotConnected, | |
| 1928 | SocketUnconnected, | |
| 1929 | 1929 | Unexpected, |
| 1930 | 1930 | }; |
| 1931 | 1931 | |
| ... | ... | @@ -2003,7 +2003,7 @@ pub const Stream = struct { |
| 2003 | 2003 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 2004 | 2004 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2005 | 2005 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2006 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 2006 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 2007 | 2007 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 2008 | 2008 | .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function |
| 2009 | 2009 | .WSA_IO_PENDING => unreachable, |
| ... | ... | @@ -2170,7 +2170,7 @@ pub const Stream = struct { |
| 2170 | 2170 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 2171 | 2171 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 2172 | 2172 | .WSAENOBUFS => return error.SystemResources, |
| 2173 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 2173 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 2174 | 2174 | .WSAENOTSOCK => unreachable, // not a socket |
| 2175 | 2175 | .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets |
| 2176 | 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 | 841 | .ISDIR => return error.IsDir, |
| 842 | 842 | .NOBUFS => return error.SystemResources, |
| 843 | 843 | .NOMEM => return error.SystemResources, |
| 844 | .NOTCONN => return error.SocketNotConnected, | |
| 844 | .NOTCONN => return error.SocketUnconnected, | |
| 845 | 845 | .CONNRESET => return error.ConnectionResetByPeer, |
| 846 | 846 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 847 | 847 | .NOTCAPABLE => return error.AccessDenied, |
| ... | ... | @@ -870,7 +870,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 870 | 870 | .ISDIR => return error.IsDir, |
| 871 | 871 | .NOBUFS => return error.SystemResources, |
| 872 | 872 | .NOMEM => return error.SystemResources, |
| 873 | .NOTCONN => return error.SocketNotConnected, | |
| 873 | .NOTCONN => return error.SocketUnconnected, | |
| 874 | 874 | .CONNRESET => return error.ConnectionResetByPeer, |
| 875 | 875 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 876 | 876 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -910,7 +910,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 910 | 910 | .ISDIR => return error.IsDir, |
| 911 | 911 | .NOBUFS => return error.SystemResources, |
| 912 | 912 | .NOMEM => return error.SystemResources, |
| 913 | .NOTCONN => return error.SocketNotConnected, | |
| 913 | .NOTCONN => return error.SocketUnconnected, | |
| 914 | 914 | .CONNRESET => return error.ConnectionResetByPeer, |
| 915 | 915 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 916 | 916 | .NOTCAPABLE => return error.AccessDenied, |
| ... | ... | @@ -932,7 +932,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 932 | 932 | .ISDIR => return error.IsDir, |
| 933 | 933 | .NOBUFS => return error.SystemResources, |
| 934 | 934 | .NOMEM => return error.SystemResources, |
| 935 | .NOTCONN => return error.SocketNotConnected, | |
| 935 | .NOTCONN => return error.SocketUnconnected, | |
| 936 | 936 | .CONNRESET => return error.ConnectionResetByPeer, |
| 937 | 937 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 938 | 938 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -979,7 +979,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 979 | 979 | .ISDIR => return error.IsDir, |
| 980 | 980 | .NOBUFS => return error.SystemResources, |
| 981 | 981 | .NOMEM => return error.SystemResources, |
| 982 | .NOTCONN => return error.SocketNotConnected, | |
| 982 | .NOTCONN => return error.SocketUnconnected, | |
| 983 | 983 | .CONNRESET => return error.ConnectionResetByPeer, |
| 984 | 984 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 985 | 985 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1012,7 +1012,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize { |
| 1012 | 1012 | .ISDIR => return error.IsDir, |
| 1013 | 1013 | .NOBUFS => return error.SystemResources, |
| 1014 | 1014 | .NOMEM => return error.SystemResources, |
| 1015 | .NOTCONN => return error.SocketNotConnected, | |
| 1015 | .NOTCONN => return error.SocketUnconnected, | |
| 1016 | 1016 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1017 | 1017 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1018 | 1018 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1130,7 +1130,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1130 | 1130 | .ISDIR => return error.IsDir, |
| 1131 | 1131 | .NOBUFS => return error.SystemResources, |
| 1132 | 1132 | .NOMEM => return error.SystemResources, |
| 1133 | .NOTCONN => return error.SocketNotConnected, | |
| 1133 | .NOTCONN => return error.SocketUnconnected, | |
| 1134 | 1134 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1135 | 1135 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1136 | 1136 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -1156,7 +1156,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 1156 | 1156 | .ISDIR => return error.IsDir, |
| 1157 | 1157 | .NOBUFS => return error.SystemResources, |
| 1158 | 1158 | .NOMEM => return error.SystemResources, |
| 1159 | .NOTCONN => return error.SocketNotConnected, | |
| 1159 | .NOTCONN => return error.SocketUnconnected, | |
| 1160 | 1160 | .CONNRESET => return error.ConnectionResetByPeer, |
| 1161 | 1161 | .TIMEDOUT => return error.ConnectionTimedOut, |
| 1162 | 1162 | .NXIO => return error.Unseekable, |
| ... | ... | @@ -3696,7 +3696,7 @@ pub const ShutdownError = error{ |
| 3696 | 3696 | NetworkSubsystemFailed, |
| 3697 | 3697 | |
| 3698 | 3698 | /// The socket is not connected (connection-oriented sockets only). |
| 3699 | SocketNotConnected, | |
| 3699 | SocketUnconnected, | |
| 3700 | 3700 | SystemResources, |
| 3701 | 3701 | } || UnexpectedError; |
| 3702 | 3702 | |
| ... | ... | @@ -3716,7 +3716,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3716 | 3716 | .WSAEINPROGRESS => return error.BlockingOperationInProgress, |
| 3717 | 3717 | .WSAEINVAL => unreachable, |
| 3718 | 3718 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 3719 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 3719 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 3720 | 3720 | .WSAENOTSOCK => unreachable, |
| 3721 | 3721 | .WSANOTINITIALISED => unreachable, |
| 3722 | 3722 | else => |err| return windows.unexpectedWSAError(err), |
| ... | ... | @@ -3731,7 +3731,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { |
| 3731 | 3731 | .SUCCESS => return, |
| 3732 | 3732 | .BADF => unreachable, |
| 3733 | 3733 | .INVAL => unreachable, |
| 3734 | .NOTCONN => return error.SocketNotConnected, | |
| 3734 | .NOTCONN => return error.SocketUnconnected, | |
| 3735 | 3735 | .NOTSOCK => unreachable, |
| 3736 | 3736 | .NOBUFS => return error.SystemResources, |
| 3737 | 3737 | else => |err| return unexpectedErrno(err), |
| ... | ... | @@ -6166,7 +6166,7 @@ pub const SendMsgError = SendError || error{ |
| 6166 | 6166 | NotDir, |
| 6167 | 6167 | |
| 6168 | 6168 | /// The socket is not connected (connection-oriented sockets only). |
| 6169 | SocketNotConnected, | |
| 6169 | SocketUnconnected, | |
| 6170 | 6170 | AddressNotAvailable, |
| 6171 | 6171 | }; |
| 6172 | 6172 | |
| ... | ... | @@ -6197,7 +6197,7 @@ pub fn sendmsg( |
| 6197 | 6197 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6198 | 6198 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6199 | 6199 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6200 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6200 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6201 | 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 | 6202 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6203 | 6203 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | ... | @@ -6233,7 +6233,7 @@ pub fn sendmsg( |
| 6233 | 6233 | .NOTDIR => return error.NotDir, |
| 6234 | 6234 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6235 | 6235 | .NETUNREACH => return error.NetworkUnreachable, |
| 6236 | .NOTCONN => return error.SocketNotConnected, | |
| 6236 | .NOTCONN => return error.SocketUnconnected, | |
| 6237 | 6237 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6238 | 6238 | else => |err| return unexpectedErrno(err), |
| 6239 | 6239 | } |
| ... | ... | @@ -6300,7 +6300,7 @@ pub fn sendto( |
| 6300 | 6300 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6301 | 6301 | .WSAENETRESET => return error.ConnectionResetByPeer, |
| 6302 | 6302 | .WSAENETUNREACH => return error.NetworkUnreachable, |
| 6303 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6303 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6304 | 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 | 6305 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6306 | 6306 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. |
| ... | ... | @@ -6338,7 +6338,7 @@ pub fn sendto( |
| 6338 | 6338 | .NOTDIR => return error.NotDir, |
| 6339 | 6339 | .HOSTUNREACH => return error.NetworkUnreachable, |
| 6340 | 6340 | .NETUNREACH => return error.NetworkUnreachable, |
| 6341 | .NOTCONN => return error.SocketNotConnected, | |
| 6341 | .NOTCONN => return error.SocketUnconnected, | |
| 6342 | 6342 | .NETDOWN => return error.NetworkSubsystemFailed, |
| 6343 | 6343 | else => |err| return unexpectedErrno(err), |
| 6344 | 6344 | } |
| ... | ... | @@ -6378,7 +6378,7 @@ pub fn send( |
| 6378 | 6378 | error.NotDir => unreachable, |
| 6379 | 6379 | error.NetworkUnreachable => unreachable, |
| 6380 | 6380 | error.AddressNotAvailable => unreachable, |
| 6381 | error.SocketNotConnected => unreachable, | |
| 6381 | error.SocketUnconnected => unreachable, | |
| 6382 | 6382 | error.UnreachableAddress => unreachable, |
| 6383 | 6383 | else => |e| return e, |
| 6384 | 6384 | }; |
| ... | ... | @@ -6564,7 +6564,7 @@ pub const RecvFromError = error{ |
| 6564 | 6564 | NetworkSubsystemFailed, |
| 6565 | 6565 | |
| 6566 | 6566 | /// The socket is not connected (connection-oriented sockets only). |
| 6567 | SocketNotConnected, | |
| 6567 | SocketUnconnected, | |
| 6568 | 6568 | |
| 6569 | 6569 | /// The other end closed the socket unexpectedly or a read is executed on a shut down socket |
| 6570 | 6570 | BrokenPipe, |
| ... | ... | @@ -6593,7 +6593,7 @@ pub fn recvfrom( |
| 6593 | 6593 | .WSAEINVAL => return error.SocketNotBound, |
| 6594 | 6594 | .WSAEMSGSIZE => return error.MessageTooBig, |
| 6595 | 6595 | .WSAENETDOWN => return error.NetworkSubsystemFailed, |
| 6596 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 6596 | .WSAENOTCONN => return error.SocketUnconnected, | |
| 6597 | 6597 | .WSAEWOULDBLOCK => return error.WouldBlock, |
| 6598 | 6598 | .WSAETIMEDOUT => return error.ConnectionTimedOut, |
| 6599 | 6599 | // TODO: handle more errors |
| ... | ... | @@ -6608,7 +6608,7 @@ pub fn recvfrom( |
| 6608 | 6608 | .BADF => unreachable, // always a race condition |
| 6609 | 6609 | .FAULT => unreachable, |
| 6610 | 6610 | .INVAL => unreachable, |
| 6611 | .NOTCONN => return error.SocketNotConnected, | |
| 6611 | .NOTCONN => return error.SocketUnconnected, | |
| 6612 | 6612 | .NOTSOCK => unreachable, |
| 6613 | 6613 | .INTR => continue, |
| 6614 | 6614 | .AGAIN => return error.WouldBlock, |
| ... | ... | @@ -6660,7 +6660,7 @@ pub fn recvmsg( |
| 6660 | 6660 | .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified |
| 6661 | 6661 | .NOBUFS => return error.SystemResources, |
| 6662 | 6662 | .NOMEM => return error.SystemResources, |
| 6663 | .NOTCONN => return error.SocketNotConnected, | |
| 6663 | .NOTCONN => return error.SocketUnconnected, | |
| 6664 | 6664 | .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. |
| 6665 | 6665 | .MSGSIZE => return error.MessageTooBig, |
| 6666 | 6666 | .PIPE => return error.BrokenPipe, |
lib/std/posix/test.zig+1-1| ... | ... | @@ -630,7 +630,7 @@ test "shutdown socket" { |
| 630 | 630 | } |
| 631 | 631 | const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0); |
| 632 | 632 | posix.shutdown(sock, .both) catch |err| switch (err) { |
| 633 | error.SocketNotConnected => {}, | |
| 633 | error.SocketUnconnected => {}, | |
| 634 | 634 | else => |e| return e, |
| 635 | 635 | }; |
| 636 | 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 | 1263 | error.Unseekable => return error.UnableToReadElfFile, |
| 1264 | 1264 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, |
| 1265 | 1265 | error.ConnectionTimedOut => return error.UnableToReadElfFile, |
| 1266 | error.SocketNotConnected => return error.UnableToReadElfFile, | |
| 1266 | error.SocketUnconnected => return error.UnableToReadElfFile, | |
| 1267 | 1267 | error.Unexpected => return error.Unexpected, |
| 1268 | 1268 | error.InputOutput => return error.FileSystem, |
| 1269 | 1269 | error.AccessDenied => return error.Unexpected, |