authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-01 23:52:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-02 16:30:59-07:00
log8d03ec6766fef7833057daa27b264c808bb6c2a2
treebd7b8fb9c1f4af7b0da7d4f69226f3806b3e81a6
parent062d17ccab495d63799e3ac8831eed485ca8cffe

std.Io.net: implement receiving connectionless messages


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,
667667
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,
670670
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{
700pub const Dir = @import("Io/Dir.zig");700pub const Dir = @import("Io/Dir.zig");
701pub const File = @import("Io/File.zig");701pub const File = @import("Io/File.zig");
702702
703pub const Timestamp = enum(i96) {703pub 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 };
705737
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 }
709742
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 }
713749
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 }
718766
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
723pub const Duration = struct {791pub const Duration = struct {
724 nanoseconds: i96,792 nanoseconds: i96,
725793
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 }
729797
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`.
734pub const Timeout = union(enum) {812pub const Timeout = union(enum) {
735 none,813 none,
736 duration: Duration,814 duration: ClockAndDuration,
737 deadline: Timestamp,815 deadline: Timestamp,
738816
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};
741pub const NowError = std.posix.ClockGetTimeError || Cancelable;
742pub const SleepError = error{ UnsupportedClock, Unexpected, Canceled };
743832
744pub const AnyFuture = opaque {};833pub const AnyFuture = opaque {};
745834
...@@ -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}
12331322
1234pub fn now(io: Io, clockid: std.posix.clockid_t) NowError!Timestamp {1323pub const SleepError = error{UnsupportedClock} || UnexpectedError || Cancelable;
1235 return io.vtable.now(io.userdata, clockid);
1236}
12371324
1238pub fn sleep(io: Io, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void {1325pub 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}
12411328
1242pub fn sleepDuration(io: Io, duration: Duration) SleepError!void {1329pub 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}
10011001
1002fn now(userdata: ?*anyopaque, clockid: posix.clockid_t) Io.NowError!Io.Timestamp {1002fn 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}
10081013
1009fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, timeout: Io.Timeout) Io.SleepError!void {1014fn 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));
13181327
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 }
13261338
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(
1405fn netReceive(1417fn 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();
14131426
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}
14191543
1420fn netWritePosix(1544fn netWritePosix(
...@@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 {...@@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 {
1653fn recoverableOsBugDetected() void {1777fn recoverableOsBugDetected() void {
1654 if (builtin.mode == .Debug) unreachable;1778 if (builtin.mode == .Debug) unreachable;
1655}1779}
1780
1781fn 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};
697697
698pub const ReceivedMessage = struct {698pub const ReceiveFlags = packed struct(u8) {
699 oob: bool = false,
700 peek: bool = false,
701 trunc: bool = false,
702 _: u5 = 0,
703};
704
705pub 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};
702734
703pub const OutgoingMessage = struct {735pub 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};
720752
753pub const SendResult = union(enum) {
754 success,
755 fail: struct {
756 err: Socket.SendError,
757 sent: usize,
758 },
759};
760
721pub const Interface = struct {761pub 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, or880 /// 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;
844884
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 }
855895
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;
857915
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 }
865925
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};
883966
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;
5656
57pub const LookupResult = struct {57pub 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;
230230
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;
266267
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 };
272275
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 {};
288294
289 const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) };295 const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) };
290296
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 };
19211921
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 };
19311931
...@@ -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 function2008 .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 socket2174 .WSAENOTSOCK => unreachable, // not a socket
2175 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets2175 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
2176 .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown2176 .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,
36973697
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;
37023702
...@@ -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,
61676167
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};
61726172
...@@ -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,
65656565
6566 /// The socket is not connected (connection-oriented sockets only).6566 /// The socket is not connected (connection-oriented sockets only).
6567 SocketNotConnected,6567 SocketUnconnected,
65686568
6569 /// The other end closed the socket unexpectedly or a read is executed on a shut down socket6569 /// 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 errors6599 // TODO: handle more errors
...@@ -6608,7 +6608,7 @@ pub fn recvfrom(...@@ -6608,7 +6608,7 @@ pub fn recvfrom(
6608 .BADF => unreachable, // always a race condition6608 .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 specified6660 .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,