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 {
665665 fileSeekBy: *const fn (?*anyopaque, file: File, offset: i64) File.SeekError!void,
666666 fileSeekTo: *const fn (?*anyopaque, file: File, offset: u64) File.SeekError!void,
667667
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,
670670
671671 listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.IpAddress.ListenOptions) net.IpAddress.ListenError!net.Server,
672672 accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Stream,
673673 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 },
676676 netRead: *const fn (?*anyopaque, src: net.Stream, data: [][]u8) net.Stream.Reader.Error!usize,
677677 netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize,
678678 netClose: *const fn (?*anyopaque, handle: net.Socket.Handle) void,
......@@ -700,46 +700,135 @@ pub const UnexpectedError = error{
700700pub const Dir = @import("Io/Dir.zig");
701701pub const File = @import("Io/File.zig");
702702
703pub const Timestamp = enum(i96) {
704 _,
703pub 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 };
705737
706738 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 };
708741 }
709742
710743 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 };
712748 }
713749
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);
716764 return addDuration(now_ts, duration);
717765 }
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
719785 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);
721788 }
722789};
790
723791pub const Duration = struct {
724792 nanoseconds: i96,
725793
726 pub fn ms(x: u64) Duration {
794 pub fn fromMilliseconds(x: i64) Duration {
727795 return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_ms };
728796 }
729797
730 pub fn seconds(x: u64) Duration {
798 pub fn fromSeconds(x: i64) Duration {
731799 return .{ .nanoseconds = @as(i96, x) * std.time.ns_per_s };
732800 }
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 }
733809};
810
811/// Declares under what conditions an operation should return `error.Timeout`.
734812pub const Timeout = union(enum) {
735813 none,
736 duration: Duration,
814 duration: ClockAndDuration,
737815 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 }
740831};
741pub const NowError = std.posix.ClockGetTimeError || Cancelable;
742pub const SleepError = error{ UnsupportedClock, Unexpected, Canceled };
743832
744833pub const AnyFuture = opaque {};
745834
......@@ -1231,12 +1320,10 @@ pub fn cancelRequested(io: Io) bool {
12311320 return io.vtable.cancelRequested(io.userdata);
12321321}
12331322
1234pub fn now(io: Io, clockid: std.posix.clockid_t) NowError!Timestamp {
1235 return io.vtable.now(io.userdata, clockid);
1236}
1323pub const SleepError = error{UnsupportedClock} || UnexpectedError || Cancelable;
12371324
1238pub fn sleep(io: Io, clockid: std.posix.clockid_t, timeout: Timeout) SleepError!void {
1239 return io.vtable.sleep(io.userdata, clockid, timeout);
1325pub fn sleep(io: Io, timeout: Timeout) SleepError!void {
1326 return io.vtable.sleep(io.userdata, timeout);
12401327}
12411328
12421329pub 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
14061406 .ISDIR => return error.IsDir,
14071407 .NOBUFS => return error.SystemResources,
14081408 .NOMEM => return error.SystemResources,
1409 .NOTCONN => return error.SocketNotConnected,
1409 .NOTCONN => return error.SocketUnconnected,
14101410 .CONNRESET => return error.ConnectionResetByPeer,
14111411 .TIMEDOUT => return error.ConnectionTimedOut,
14121412 .NXIO => return error.Unseekable,
lib/std/Io/File.zig+1-1
......@@ -157,7 +157,7 @@ pub const ReadStreamingError = error{
157157 ConnectionResetByPeer,
158158 ConnectionTimedOut,
159159 NotOpenForReading,
160 SocketNotConnected,
160 SocketUnconnected,
161161 /// This error occurs when no global event loop is configured,
162162 /// and reading from the file descriptor would block.
163163 WouldBlock,
lib/std/Io/Threaded.zig+158-26
......@@ -811,7 +811,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File
811811 .ISDIR => return error.IsDir,
812812 .NOBUFS => return error.SystemResources,
813813 .NOMEM => return error.SystemResources,
814 .NOTCONN => return error.SocketNotConnected,
814 .NOTCONN => return error.SocketUnconnected,
815815 .CONNRESET => return error.ConnectionResetByPeer,
816816 .TIMEDOUT => return error.ConnectionTimedOut,
817817 .NOTCAPABLE => return error.AccessDenied,
......@@ -834,7 +834,7 @@ fn fileReadStreaming(userdata: ?*anyopaque, file: Io.File, data: [][]u8) Io.File
834834 .ISDIR => return error.IsDir,
835835 .NOBUFS => return error.SystemResources,
836836 .NOMEM => return error.SystemResources,
837 .NOTCONN => return error.SocketNotConnected,
837 .NOTCONN => return error.SocketUnconnected,
838838 .CONNRESET => return error.ConnectionResetByPeer,
839839 .TIMEDOUT => return error.ConnectionTimedOut,
840840 else => |err| return posix.unexpectedErrno(err),
......@@ -933,7 +933,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset
933933 .ISDIR => return error.IsDir,
934934 .NOBUFS => return error.SystemResources,
935935 .NOMEM => return error.SystemResources,
936 .NOTCONN => return error.SocketNotConnected,
936 .NOTCONN => return error.SocketUnconnected,
937937 .CONNRESET => return error.ConnectionResetByPeer,
938938 .TIMEDOUT => return error.ConnectionTimedOut,
939939 .NXIO => return error.Unseekable,
......@@ -960,7 +960,7 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset
960960 .ISDIR => return error.IsDir,
961961 .NOBUFS => return error.SystemResources,
962962 .NOMEM => return error.SystemResources,
963 .NOTCONN => return error.SocketNotConnected,
963 .NOTCONN => return error.SocketUnconnected,
964964 .CONNRESET => return error.ConnectionResetByPeer,
965965 .TIMEDOUT => return error.ConnectionTimedOut,
966966 .NXIO => return error.Unseekable,
......@@ -999,19 +999,29 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi
999999 };
10001000}
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 {
10031003 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 }
10071012}
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 {
10101015 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 });
10111021 const deadline_nanoseconds: i96 = switch (timeout) {
10121022 .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,
10151025 };
10161026 var timespec: posix.timespec = .{
10171027 .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
10191029 };
10201030 while (true) {
10211031 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) {
10231033 .none, .duration => false,
10241034 .deadline => true,
10251035 } }, &timespec, &timespec))) {
10261036 .SUCCESS => return,
1027 .FAULT => |err| return errnoBug(err),
1028 .INTR => {},
1037 .INTR => continue,
10291038 .INVAL => return error.UnsupportedClock,
10301039 else => |err| return posix.unexpectedErrno(err),
10311040 }
......@@ -1313,15 +1322,18 @@ fn netSend(
13131322 handle: Io.net.Socket.Handle,
13141323 messages: []Io.net.OutgoingMessage,
13151324 flags: Io.net.SendFlags,
1316) Io.net.Socket.SendError!void {
1325) Io.net.SendResult {
13171326 const pool: *Pool = @ptrCast(@alignCast(userdata));
13181327
13191328 if (have_sendmmsg) {
13201329 var i: usize = 0;
13211330 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 } };
13231335 }
1324 return;
1336 return .success;
13251337 }
13261338
13271339 try pool.checkCancel();
......@@ -1391,11 +1403,11 @@ fn netSendMany(
13911403 .NOMEM => return error.SystemResources,
13921404 .NOTSOCK => |err| return errnoBug(err), // The file descriptor sockfd does not refer to a socket.
13931405 .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,
13951407 .AFNOSUPPORT => return error.AddressFamilyUnsupported,
13961408 .HOSTUNREACH => return error.NetworkUnreachable,
13971409 .NETUNREACH => return error.NetworkUnreachable,
1398 .NOTCONN => return error.SocketNotConnected,
1410 .NOTCONN => return error.SocketUnconnected,
13991411 .NETDOWN => return error.NetworkDown,
14001412 else => |err| return posix.unexpectedErrno(err),
14011413 }
......@@ -1405,16 +1417,128 @@ fn netSendMany(
14051417fn netReceive(
14061418 userdata: ?*anyopaque,
14071419 handle: Io.net.Socket.Handle,
1408 buffer: []u8,
1420 message_buffer: []Io.net.IncomingMessage,
1421 data_buffer: []u8,
1422 flags: Io.net.ReceiveFlags,
14091423 timeout: Io.Timeout,
1410) Io.net.Socket.ReceiveTimeoutError!Io.net.ReceivedMessage {
1424) struct { ?Io.net.Socket.ReceiveTimeoutError, usize } {
14111425 const pool: *Pool = @ptrCast(@alignCast(userdata));
1412 try pool.checkCancel();
14131426
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 }
14181542}
14191543
14201544fn netWritePosix(
......@@ -1653,3 +1777,11 @@ fn posixProtocol(protocol: ?Io.net.Protocol) u32 {
16531777fn recoverableOsBugDetected() void {
16541778 if (builtin.mode == .Debug) unreachable;
16551779}
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 {
695695 };
696696};
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.
699707 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 };
701733};
702734
703735pub const OutgoingMessage = struct {
......@@ -718,6 +750,14 @@ pub const SendFlags = packed struct(u8) {
718750 _: u3 = 0,
719751};
720752
753pub const SendResult = union(enum) {
754 success,
755 fail: struct {
756 err: Socket.SendError,
757 sent: usize,
758 },
759};
760
721761pub const Interface = struct {
722762 /// Value 0 indicates `none`.
723763 index: u32,
......@@ -839,7 +879,7 @@ pub const Socket = struct {
839879 ConnectionResetByPeer,
840880 /// Local end has been shut down on a connection-oriented socket, or
841881 /// the socket was never connected.
842 SocketNotConnected,
882 SocketUnconnected,
843883 } || Io.UnexpectedError || Io.Cancelable;
844884
845885 /// Transfers `data` to `dest`, connectionless, in one packet.
......@@ -853,14 +893,34 @@ pub const Socket = struct {
853893 return io.vtable.netSend(io.userdata, s.handle, messages, flags);
854894 }
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
858916 /// Waits for data. Connectionless.
859917 ///
860918 /// See also:
861919 /// * `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;
864924 }
865925
866926 pub const ReceiveTimeoutError = ReceiveError || Io.Timeout.Error;
......@@ -871,13 +931,36 @@ pub const Socket = struct {
871931 ///
872932 /// See also:
873933 /// * `receive`
934 /// * `receiveManyTimeout`
874935 pub fn receiveTimeout(
875936 s: *const Socket,
876937 io: Io,
877938 buffer: []u8,
878939 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);
881964 }
882965};
883966
lib/std/Io/net/HostName.zig+70-60
......@@ -52,7 +52,7 @@ pub const LookupError = error{
5252 InvalidDnsARecord,
5353 InvalidDnsAAAARecord,
5454 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
5757pub const LookupResult = struct {
5858 /// 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
222222 .{ .af = .ip4, .rr = std.posix.RR.AAAA },
223223 };
224224 var query_buffers: [2][280]u8 = undefined;
225 var answer_buffers: [2][512]u8 = undefined;
225 var answer_buffer: [2 * 512]u8 = undefined;
226226 var queries_buffer: [2][]const u8 = undefined;
227227 var answers_buffer: [2][]const u8 = undefined;
228228 var nq: usize = 0;
229 var next_answer_buffer: usize = 0;
229 var answer_buffer_i: usize = 0;
230230
231231 for (family_records) |fr| {
232232 if (options.family != fr.af) {
......@@ -262,79 +262,89 @@ fn lookupDns(io: Io, lookup_canon_name: []const u8, rc: *const ResolvConf, optio
262262 const mapped_nameservers = if (any_ip6) ip4_mapped[0..rc.nameservers_len] else rc.nameservers();
263263 const queries = queries_buffer[0..nq];
264264 const answers = answers_buffer[0..queries.len];
265 var answers_remaining = answers.len;
265266 for (answers) |*answer| answer.len = 0;
266267
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));
269272 const attempt_duration: Io.Duration = .{
270273 .nanoseconds = std.time.ns_per_s * @as(usize, rc.timeout_seconds) / rc.attempts,
271274 };
272275
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 }
285291 }
292 _ = io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{});
286293 }
287 io.vtable.netSend(io.userdata, socket.handle, message_buffer[0..message_i], .{}) catch {};
288294
289295 const timeout: Io.Timeout = .{ .deadline = now_ts.addDuration(attempt_duration) };
290296
291297 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) {
294344 error.Canceled => return error.Canceled,
295345 error.Timeout => continue :send,
296346 else => continue,
297347 };
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 }
338348 }
339349 } else {
340350 return error.NameServerFailure;
lib/std/net.zig+4-4
......@@ -1916,7 +1916,7 @@ pub const Stream = struct {
19161916 MessageTooBig,
19171917 NetworkSubsystemFailed,
19181918 ConnectionResetByPeer,
1919 SocketNotConnected,
1919 SocketUnconnected,
19201920 };
19211921
19221922 pub const WriteError = posix.SendMsgError || error{
......@@ -1925,7 +1925,7 @@ pub const Stream = struct {
19251925 MessageTooBig,
19261926 NetworkSubsystemFailed,
19271927 SystemResources,
1928 SocketNotConnected,
1928 SocketUnconnected,
19291929 Unexpected,
19301930 };
19311931
......@@ -2003,7 +2003,7 @@ pub const Stream = struct {
20032003 .WSAEMSGSIZE => return error.MessageTooBig,
20042004 .WSAENETDOWN => return error.NetworkSubsystemFailed,
20052005 .WSAENETRESET => return error.ConnectionResetByPeer,
2006 .WSAENOTCONN => return error.SocketNotConnected,
2006 .WSAENOTCONN => return error.SocketUnconnected,
20072007 .WSAEWOULDBLOCK => return error.WouldBlock,
20082008 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
20092009 .WSA_IO_PENDING => unreachable,
......@@ -2170,7 +2170,7 @@ pub const Stream = struct {
21702170 .WSAENETDOWN => return error.NetworkSubsystemFailed,
21712171 .WSAENETRESET => return error.ConnectionResetByPeer,
21722172 .WSAENOBUFS => return error.SystemResources,
2173 .WSAENOTCONN => return error.SocketNotConnected,
2173 .WSAENOTCONN => return error.SocketUnconnected,
21742174 .WSAENOTSOCK => unreachable, // not a socket
21752175 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
21762176 .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 {
841841 .ISDIR => return error.IsDir,
842842 .NOBUFS => return error.SystemResources,
843843 .NOMEM => return error.SystemResources,
844 .NOTCONN => return error.SocketNotConnected,
844 .NOTCONN => return error.SocketUnconnected,
845845 .CONNRESET => return error.ConnectionResetByPeer,
846846 .TIMEDOUT => return error.ConnectionTimedOut,
847847 .NOTCAPABLE => return error.AccessDenied,
......@@ -870,7 +870,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
870870 .ISDIR => return error.IsDir,
871871 .NOBUFS => return error.SystemResources,
872872 .NOMEM => return error.SystemResources,
873 .NOTCONN => return error.SocketNotConnected,
873 .NOTCONN => return error.SocketUnconnected,
874874 .CONNRESET => return error.ConnectionResetByPeer,
875875 .TIMEDOUT => return error.ConnectionTimedOut,
876876 else => |err| return unexpectedErrno(err),
......@@ -910,7 +910,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
910910 .ISDIR => return error.IsDir,
911911 .NOBUFS => return error.SystemResources,
912912 .NOMEM => return error.SystemResources,
913 .NOTCONN => return error.SocketNotConnected,
913 .NOTCONN => return error.SocketUnconnected,
914914 .CONNRESET => return error.ConnectionResetByPeer,
915915 .TIMEDOUT => return error.ConnectionTimedOut,
916916 .NOTCAPABLE => return error.AccessDenied,
......@@ -932,7 +932,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
932932 .ISDIR => return error.IsDir,
933933 .NOBUFS => return error.SystemResources,
934934 .NOMEM => return error.SystemResources,
935 .NOTCONN => return error.SocketNotConnected,
935 .NOTCONN => return error.SocketUnconnected,
936936 .CONNRESET => return error.ConnectionResetByPeer,
937937 .TIMEDOUT => return error.ConnectionTimedOut,
938938 else => |err| return unexpectedErrno(err),
......@@ -979,7 +979,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
979979 .ISDIR => return error.IsDir,
980980 .NOBUFS => return error.SystemResources,
981981 .NOMEM => return error.SystemResources,
982 .NOTCONN => return error.SocketNotConnected,
982 .NOTCONN => return error.SocketUnconnected,
983983 .CONNRESET => return error.ConnectionResetByPeer,
984984 .TIMEDOUT => return error.ConnectionTimedOut,
985985 .NXIO => return error.Unseekable,
......@@ -1012,7 +1012,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
10121012 .ISDIR => return error.IsDir,
10131013 .NOBUFS => return error.SystemResources,
10141014 .NOMEM => return error.SystemResources,
1015 .NOTCONN => return error.SocketNotConnected,
1015 .NOTCONN => return error.SocketUnconnected,
10161016 .CONNRESET => return error.ConnectionResetByPeer,
10171017 .TIMEDOUT => return error.ConnectionTimedOut,
10181018 .NXIO => return error.Unseekable,
......@@ -1130,7 +1130,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
11301130 .ISDIR => return error.IsDir,
11311131 .NOBUFS => return error.SystemResources,
11321132 .NOMEM => return error.SystemResources,
1133 .NOTCONN => return error.SocketNotConnected,
1133 .NOTCONN => return error.SocketUnconnected,
11341134 .CONNRESET => return error.ConnectionResetByPeer,
11351135 .TIMEDOUT => return error.ConnectionTimedOut,
11361136 .NXIO => return error.Unseekable,
......@@ -1156,7 +1156,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
11561156 .ISDIR => return error.IsDir,
11571157 .NOBUFS => return error.SystemResources,
11581158 .NOMEM => return error.SystemResources,
1159 .NOTCONN => return error.SocketNotConnected,
1159 .NOTCONN => return error.SocketUnconnected,
11601160 .CONNRESET => return error.ConnectionResetByPeer,
11611161 .TIMEDOUT => return error.ConnectionTimedOut,
11621162 .NXIO => return error.Unseekable,
......@@ -3696,7 +3696,7 @@ pub const ShutdownError = error{
36963696 NetworkSubsystemFailed,
36973697
36983698 /// The socket is not connected (connection-oriented sockets only).
3699 SocketNotConnected,
3699 SocketUnconnected,
37003700 SystemResources,
37013701} || UnexpectedError;
37023702
......@@ -3716,7 +3716,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {
37163716 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
37173717 .WSAEINVAL => unreachable,
37183718 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3719 .WSAENOTCONN => return error.SocketNotConnected,
3719 .WSAENOTCONN => return error.SocketUnconnected,
37203720 .WSAENOTSOCK => unreachable,
37213721 .WSANOTINITIALISED => unreachable,
37223722 else => |err| return windows.unexpectedWSAError(err),
......@@ -3731,7 +3731,7 @@ pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {
37313731 .SUCCESS => return,
37323732 .BADF => unreachable,
37333733 .INVAL => unreachable,
3734 .NOTCONN => return error.SocketNotConnected,
3734 .NOTCONN => return error.SocketUnconnected,
37353735 .NOTSOCK => unreachable,
37363736 .NOBUFS => return error.SystemResources,
37373737 else => |err| return unexpectedErrno(err),
......@@ -6166,7 +6166,7 @@ pub const SendMsgError = SendError || error{
61666166 NotDir,
61676167
61686168 /// The socket is not connected (connection-oriented sockets only).
6169 SocketNotConnected,
6169 SocketUnconnected,
61706170 AddressNotAvailable,
61716171};
61726172
......@@ -6197,7 +6197,7 @@ pub fn sendmsg(
61976197 .WSAENETDOWN => return error.NetworkSubsystemFailed,
61986198 .WSAENETRESET => return error.ConnectionResetByPeer,
61996199 .WSAENETUNREACH => return error.NetworkUnreachable,
6200 .WSAENOTCONN => return error.SocketNotConnected,
6200 .WSAENOTCONN => return error.SocketUnconnected,
62016201 .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.
62026202 .WSAEWOULDBLOCK => return error.WouldBlock,
62036203 .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
......@@ -6233,7 +6233,7 @@ pub fn sendmsg(
62336233 .NOTDIR => return error.NotDir,
62346234 .HOSTUNREACH => return error.NetworkUnreachable,
62356235 .NETUNREACH => return error.NetworkUnreachable,
6236 .NOTCONN => return error.SocketNotConnected,
6236 .NOTCONN => return error.SocketUnconnected,
62376237 .NETDOWN => return error.NetworkSubsystemFailed,
62386238 else => |err| return unexpectedErrno(err),
62396239 }
......@@ -6300,7 +6300,7 @@ pub fn sendto(
63006300 .WSAENETDOWN => return error.NetworkSubsystemFailed,
63016301 .WSAENETRESET => return error.ConnectionResetByPeer,
63026302 .WSAENETUNREACH => return error.NetworkUnreachable,
6303 .WSAENOTCONN => return error.SocketNotConnected,
6303 .WSAENOTCONN => return error.SocketUnconnected,
63046304 .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.
63056305 .WSAEWOULDBLOCK => return error.WouldBlock,
63066306 .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
......@@ -6338,7 +6338,7 @@ pub fn sendto(
63386338 .NOTDIR => return error.NotDir,
63396339 .HOSTUNREACH => return error.NetworkUnreachable,
63406340 .NETUNREACH => return error.NetworkUnreachable,
6341 .NOTCONN => return error.SocketNotConnected,
6341 .NOTCONN => return error.SocketUnconnected,
63426342 .NETDOWN => return error.NetworkSubsystemFailed,
63436343 else => |err| return unexpectedErrno(err),
63446344 }
......@@ -6378,7 +6378,7 @@ pub fn send(
63786378 error.NotDir => unreachable,
63796379 error.NetworkUnreachable => unreachable,
63806380 error.AddressNotAvailable => unreachable,
6381 error.SocketNotConnected => unreachable,
6381 error.SocketUnconnected => unreachable,
63826382 error.UnreachableAddress => unreachable,
63836383 else => |e| return e,
63846384 };
......@@ -6564,7 +6564,7 @@ pub const RecvFromError = error{
65646564 NetworkSubsystemFailed,
65656565
65666566 /// The socket is not connected (connection-oriented sockets only).
6567 SocketNotConnected,
6567 SocketUnconnected,
65686568
65696569 /// The other end closed the socket unexpectedly or a read is executed on a shut down socket
65706570 BrokenPipe,
......@@ -6593,7 +6593,7 @@ pub fn recvfrom(
65936593 .WSAEINVAL => return error.SocketNotBound,
65946594 .WSAEMSGSIZE => return error.MessageTooBig,
65956595 .WSAENETDOWN => return error.NetworkSubsystemFailed,
6596 .WSAENOTCONN => return error.SocketNotConnected,
6596 .WSAENOTCONN => return error.SocketUnconnected,
65976597 .WSAEWOULDBLOCK => return error.WouldBlock,
65986598 .WSAETIMEDOUT => return error.ConnectionTimedOut,
65996599 // TODO: handle more errors
......@@ -6608,7 +6608,7 @@ pub fn recvfrom(
66086608 .BADF => unreachable, // always a race condition
66096609 .FAULT => unreachable,
66106610 .INVAL => unreachable,
6611 .NOTCONN => return error.SocketNotConnected,
6611 .NOTCONN => return error.SocketUnconnected,
66126612 .NOTSOCK => unreachable,
66136613 .INTR => continue,
66146614 .AGAIN => return error.WouldBlock,
......@@ -6660,7 +6660,7 @@ pub fn recvmsg(
66606660 .ISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
66616661 .NOBUFS => return error.SystemResources,
66626662 .NOMEM => return error.SystemResources,
6663 .NOTCONN => return error.SocketNotConnected,
6663 .NOTCONN => return error.SocketUnconnected,
66646664 .NOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
66656665 .MSGSIZE => return error.MessageTooBig,
66666666 .PIPE => return error.BrokenPipe,
lib/std/posix/test.zig+1-1
......@@ -630,7 +630,7 @@ test "shutdown socket" {
630630 }
631631 const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0);
632632 posix.shutdown(sock, .both) catch |err| switch (err) {
633 error.SocketNotConnected => {},
633 error.SocketUnconnected => {},
634634 else => |e| return e,
635635 };
636636 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
12631263 error.Unseekable => return error.UnableToReadElfFile,
12641264 error.ConnectionResetByPeer => return error.UnableToReadElfFile,
12651265 error.ConnectionTimedOut => return error.UnableToReadElfFile,
1266 error.SocketNotConnected => return error.UnableToReadElfFile,
1266 error.SocketUnconnected => return error.UnableToReadElfFile,
12671267 error.Unexpected => return error.Unexpected,
12681268 error.InputOutput => return error.FileSystem,
12691269 error.AccessDenied => return error.Unexpected,