authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-04-20 14:20:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:27-07:00
logd7b081882a9dcfff68d2b5a3fb4fcdec8cb74e4b
tree0f29c69d9fc9ef6ed2ca323cb59b9170c39b7983
parente9fd9798f4d6e3cc5af6179881e0323f983095b5

std.net.Stream: fix interface() infinite recursion


1 files changed, 239 insertions(+), 238 deletions(-)

lib/std/net.zig+239-238
......@@ -1829,276 +1829,277 @@ pub const Stream = struct {
18291829 }
18301830 }
18311831
1832 pub const Reader = struct {
1833 impl: switch (native_os) {
1834 .windows => Stream,
1835 else => struct {
1836 fr: std.fs.File.Reader,
1837 err: Error!void,
1838 },
1839 },
1832 const ReadError = posix.ReadError;
1833
1834 const WriteError = posix.SendMsgError || error{
1835 ConnectionResetByPeer,
1836 SocketNotBound,
1837 MessageTooBig,
1838 NetworkSubsystemFailed,
1839 SystemResources,
1840 SocketNotConnected,
1841 Unexpected,
1842 };
18401843
1841 pub const Error = posix.ReadError;
1844 pub const Reader = switch (native_os) {
1845 .windows => struct {
1846 stream: Stream,
1847 err: ?Error = null,
18421848
1843 pub fn interface(r: *Reader) std.io.Reader {
1844 return switch (native_os) {
1845 .windows => .{
1846 .context = r.impl.stream.handle,
1849 pub const Error = ReadError;
1850
1851 pub fn interface(r: *Reader) std.io.Reader {
1852 return .{
1853 .context = r.stream.handle,
18471854 .vtable = &.{
1848 .read = windows_read,
1849 .readVec = windows_readVec,
1850 .discard = windows_discard,
1855 .read = read,
1856 .readVec = readVec,
1857 .discard = discard,
18511858 },
1852 },
1853 else => r.interface(),
1854 };
1855 }
1859 };
1860 }
18561861
1857 fn windows_read(
1858 context: ?*anyopaque,
1859 bw: *std.io.BufferedWriter,
1860 limit: std.io.Reader.Limit,
1861 ) std.io.Reader.Error!usize {
1862 const buf = limit.slice(try bw.writableSliceGreedy(1));
1863 const status = try windows_readVec(context, &.{buf});
1864 bw.advance(status.len);
1865 return status;
1866 }
1862 fn read(
1863 context: ?*anyopaque,
1864 bw: *std.io.BufferedWriter,
1865 limit: std.io.Reader.Limit,
1866 ) std.io.Reader.Error!usize {
1867 const buf = limit.slice(try bw.writableSliceGreedy(1));
1868 const status = try readVec(context, &.{buf});
1869 bw.advance(status.len);
1870 return status;
1871 }
18671872
1868 fn windows_readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
1869 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1870 var iovecs_i: usize = 0;
1871 for (data) |d| {
1872 // In case Windows checks pointer address before length, we must omit
1873 // length-zero vectors.
1874 if (d.len == 0) continue;
1875 iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len };
1876 iovecs_i += 1;
1877 if (iovecs_i >= iovecs.len) break;
1873 fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize {
1874 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1875 var iovecs_i: usize = 0;
1876 for (data) |d| {
1877 // In case Windows checks pointer address before length, we must omit
1878 // length-zero vectors.
1879 if (d.len == 0) continue;
1880 iovecs[iovecs_i] = .{ .buf = d.ptr, .len = d.len };
1881 iovecs_i += 1;
1882 if (iovecs_i >= iovecs.len) break;
1883 }
1884 const bufs = iovecs[0..iovecs_i];
1885 if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`.
1886 var n: u32 = undefined;
1887 var flags: u32 = 0;
1888 const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null);
1889 if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) {
1890 .WSAECONNRESET => return error.ConnectionResetByPeer,
1891 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1892 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1893 .WSAEINVAL => return error.SocketNotBound,
1894 .WSAEMSGSIZE => return error.MessageTooBig,
1895 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1896 .WSAENETRESET => return error.ConnectionResetByPeer,
1897 .WSAENOTCONN => return error.SocketNotConnected,
1898 .WSAEWOULDBLOCK => return error.WouldBlock,
1899 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1900 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1901 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1902 else => |err| return windows.unexpectedWSAError(err),
1903 };
1904 return .{ .len = n, .end = n == 0 };
18781905 }
1879 const bufs = iovecs[0..iovecs_i];
1880 if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`.
1881 var n: u32 = undefined;
1882 var flags: u32 = 0;
1883 const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null);
1884 if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) {
1885 .WSAECONNRESET => return error.ConnectionResetByPeer,
1886 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1887 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1888 .WSAEINVAL => return error.SocketNotBound,
1889 .WSAEMSGSIZE => return error.MessageTooBig,
1890 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1891 .WSAENETRESET => return error.ConnectionResetByPeer,
1892 .WSAENOTCONN => return error.SocketNotConnected,
1893 .WSAEWOULDBLOCK => return error.WouldBlock,
1894 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1895 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1896 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1897 else => |err| return windows.unexpectedWSAError(err),
1898 };
1899 return .{ .len = n, .end = n == 0 };
1900 }
19011906
1902 fn windows_discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
1903 _ = context;
1904 _ = limit;
1905 @panic("TODO");
1906 }
1907 };
1907 fn discard(context: ?*anyopaque, limit: std.io.Reader.Limit) std.io.Reader.Error!usize {
1908 _ = context;
1909 _ = limit;
1910 @panic("TODO");
1911 }
1912 },
1913 else => struct {
1914 file_reader: std.fs.File.Reader,
1915
1916 pub const Error = ReadError;
19081917
1909 pub const Writer = struct {
1910 impl: switch (native_os) {
1911 .windows => Stream,
1912 else => PosixImpl,
1918 pub fn interface(r: *Reader) std.io.Reader {
1919 return r.file_reader.interface();
1920 }
19131921 },
1922 };
19141923
1915 const PosixImpl = struct {
1916 fw: std.fs.File.Writer,
1917 err: Error!void,
1918 };
1924 pub const Writer = switch (native_os) {
1925 .windows => struct {
1926 stream: Stream,
19191927
1920 pub const Error = posix.SendMsgError || error{
1921 ConnectionResetByPeer,
1922 SocketNotBound,
1923 MessageTooBig,
1924 NetworkSubsystemFailed,
1925 SystemResources,
1926 SocketNotConnected,
1927 Unexpected,
1928 };
1928 pub const Error = WriteError;
19291929
1930 pub fn interface(w: *Writer) std.io.Writer {
1931 return switch (native_os) {
1932 .windows => .{
1933 .context = w.impl.stream.handle,
1930 pub fn interface(w: *Writer) std.io.Writer {
1931 return .{
1932 .context = w.stream.handle,
19341933 .vtable = &.{
1935 .writeSplat = windows_writeSplat,
1936 .writeFile = windows_writeFile,
1934 .writeSplat = writeSplat,
1935 .writeFile = writeFile,
19371936 },
1938 },
1939 else => .{
1940 .context = &w.impl,
1937 };
1938 }
1939
1940 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
1941 comptime assert(native_os == .windows);
1942 if (data.len == 1 and splat == 0) return 0;
1943 var splat_buffer: [256]u8 = undefined;
1944 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1945 var len: u32 = @min(iovecs.len, data.len);
1946 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
1947 .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ?
1948 .len = d.len,
1949 };
1950 switch (splat) {
1951 0 => len -= 1,
1952 1 => {},
1953 else => {
1954 const pattern = data[data.len - 1];
1955 if (pattern.len == 1) {
1956 const memset_len = @min(splat_buffer.len, splat);
1957 const buf = splat_buffer[0..memset_len];
1958 @memset(buf, pattern[0]);
1959 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
1960 var remaining_splat = splat - buf.len;
1961 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
1962 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
1963 remaining_splat -= splat_buffer.len;
1964 len += 1;
1965 }
1966 if (remaining_splat > 0 and len < iovecs.len) {
1967 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
1968 len += 1;
1969 }
1970 }
1971 },
1972 }
1973 var n: u32 = undefined;
1974 const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null);
1975 if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) {
1976 .WSAECONNABORTED => return error.ConnectionResetByPeer,
1977 .WSAECONNRESET => return error.ConnectionResetByPeer,
1978 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1979 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1980 .WSAEINVAL => return error.SocketNotBound,
1981 .WSAEMSGSIZE => return error.MessageTooBig,
1982 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1983 .WSAENETRESET => return error.ConnectionResetByPeer,
1984 .WSAENOBUFS => return error.SystemResources,
1985 .WSAENOTCONN => return error.SocketNotConnected,
1986 .WSAENOTSOCK => unreachable, // not a socket
1987 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
1988 .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown
1989 .WSAEWOULDBLOCK => return error.WouldBlock,
1990 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
1991 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
1992 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
1993 else => |err| return windows.unexpectedWSAError(err),
1994 };
1995 return n;
1996 }
1997
1998 fn writeFile(
1999 context: *anyopaque,
2000 in_file: std.fs.File,
2001 in_offset: u64,
2002 in_len: std.io.Writer.FileLen,
2003 headers_and_trailers: []const []const u8,
2004 headers_len: usize,
2005 ) std.io.Writer.FileError!usize {
2006 const len_int = switch (in_len) {
2007 .zero => return writeSplat(context, headers_and_trailers, 1),
2008 .entire_file => std.math.maxInt(usize),
2009 else => in_len.int(),
2010 };
2011 if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1);
2012 var file_contents_buffer: [4096]u8 = undefined;
2013 const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)];
2014 const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset);
2015 return writeSplat(context, &.{read_buffer[0..n]}, 1);
2016 }
2017 },
2018 else => struct {
2019 file_writer: std.fs.File.Writer,
2020 err: ?Error = null,
2021
2022 pub const Error = WriteError;
2023
2024 pub fn interface(w: *Writer) std.io.Writer {
2025 return .{
2026 .context = &w.file_writer,
19412027 .vtable = &.{
1942 .writeSplat = posix_writeSplat,
2028 .writeSplat = writeSplat,
19432029 .writeFile = std.fs.File.Writer.writeFile,
19442030 },
1945 },
1946 };
1947 }
1948
1949 fn windows_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
1950 comptime assert(native_os == .windows);
1951 if (data.len == 1 and splat == 0) return 0;
1952 var splat_buffer: [256]u8 = undefined;
1953 var iovecs: [max_buffers_len]windows.WSABUF = undefined;
1954 var len: u32 = @min(iovecs.len, data.len);
1955 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
1956 .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ?
1957 .len = d.len,
1958 };
1959 switch (splat) {
1960 0 => len -= 1,
1961 1 => {},
1962 else => {
1963 const pattern = data[data.len - 1];
1964 if (pattern.len == 1) {
1965 const memset_len = @min(splat_buffer.len, splat);
1966 const buf = splat_buffer[0..memset_len];
1967 @memset(buf, pattern[0]);
1968 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
1969 var remaining_splat = splat - buf.len;
1970 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
1971 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
1972 remaining_splat -= splat_buffer.len;
1973 len += 1;
1974 }
1975 if (remaining_splat > 0 and len < iovecs.len) {
1976 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
1977 len += 1;
1978 }
1979 }
1980 },
2031 };
19812032 }
1982 var n: u32 = undefined;
1983 const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null);
1984 if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) {
1985 .WSAECONNABORTED => return error.ConnectionResetByPeer,
1986 .WSAECONNRESET => return error.ConnectionResetByPeer,
1987 .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space.
1988 .WSAEINPROGRESS, .WSAEINTR => unreachable, // deprecated and removed in WSA 2.2
1989 .WSAEINVAL => return error.SocketNotBound,
1990 .WSAEMSGSIZE => return error.MessageTooBig,
1991 .WSAENETDOWN => return error.NetworkSubsystemFailed,
1992 .WSAENETRESET => return error.ConnectionResetByPeer,
1993 .WSAENOBUFS => return error.SystemResources,
1994 .WSAENOTCONN => return error.SocketNotConnected,
1995 .WSAENOTSOCK => unreachable, // not a socket
1996 .WSAEOPNOTSUPP => unreachable, // only for message-oriented sockets
1997 .WSAESHUTDOWN => unreachable, // cannot send on a socket after write shutdown
1998 .WSAEWOULDBLOCK => return error.WouldBlock,
1999 .WSANOTINITIALISED => unreachable, // WSAStartup must be called before this function
2000 .WSA_IO_PENDING => unreachable, // not using overlapped I/O
2001 .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O
2002 else => |err| return windows.unexpectedWSAError(err),
2003 };
2004 return n;
2005 }
20062033
2007 fn posix_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
2008 const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context));
2009 const impl: *PosixImpl = @fieldParentPtr("fw", fw);
2010 comptime assert(native_os != .windows);
2011 var splat_buffer: [256]u8 = undefined;
2012 var iovecs: [max_buffers_len]std.posix.iovec_const = undefined;
2013 var len: usize = @min(iovecs.len, data.len);
2014 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
2015 .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length.
2016 .len = d.len,
2017 };
2018 var msg: posix.msghdr_const = .{
2019 .name = null,
2020 .namelen = 0,
2021 .iov = &iovecs,
2022 .iovlen = len,
2023 .control = null,
2024 .controllen = 0,
2025 .flags = 0,
2026 };
2027 switch (splat) {
2028 0 => msg.iovlen = len - 1,
2029 1 => {},
2030 else => {
2031 const pattern = data[data.len - 1];
2032 if (pattern.len == 1) {
2033 const memset_len = @min(splat_buffer.len, splat);
2034 const buf = splat_buffer[0..memset_len];
2035 @memset(buf, pattern[0]);
2036 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
2037 var remaining_splat = splat - buf.len;
2038 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
2039 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
2040 remaining_splat -= splat_buffer.len;
2041 len += 1;
2042 }
2043 if (remaining_splat > 0 and len < iovecs.len) {
2044 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
2045 len += 1;
2034 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
2035 const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context));
2036 const w: *Writer = @fieldParentPtr("file_writer", fw);
2037 var splat_buffer: [256]u8 = undefined;
2038 var iovecs: [max_buffers_len]std.posix.iovec_const = undefined;
2039 var len: usize = @min(iovecs.len, data.len);
2040 for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{
2041 .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length.
2042 .len = d.len,
2043 };
2044 var msg: posix.msghdr_const = .{
2045 .name = null,
2046 .namelen = 0,
2047 .iov = &iovecs,
2048 .iovlen = len,
2049 .control = null,
2050 .controllen = 0,
2051 .flags = 0,
2052 };
2053 switch (splat) {
2054 0 => msg.iovlen = len - 1,
2055 1 => {},
2056 else => {
2057 const pattern = data[data.len - 1];
2058 if (pattern.len == 1) {
2059 const memset_len = @min(splat_buffer.len, splat);
2060 const buf = splat_buffer[0..memset_len];
2061 @memset(buf, pattern[0]);
2062 iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len };
2063 var remaining_splat = splat - buf.len;
2064 while (remaining_splat > splat_buffer.len and len < iovecs.len) {
2065 iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len };
2066 remaining_splat -= splat_buffer.len;
2067 len += 1;
2068 }
2069 if (remaining_splat > 0 and len < iovecs.len) {
2070 iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat };
2071 len += 1;
2072 }
2073 msg.iovlen = len;
20462074 }
2047 msg.iovlen = len;
2048 }
2049 },
2075 },
2076 }
2077 const flags = posix.MSG.NOSIGNAL;
2078 return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| {
2079 w.err = err;
2080 return error.WriteFailed;
2081 };
20502082 }
2051 const flags = posix.MSG.NOSIGNAL;
2052 return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| {
2053 impl.err = err;
2054 return error.WriteFailed;
2055 };
2056 }
2057
2058 fn windows_writeFile(
2059 context: *anyopaque,
2060 in_file: std.fs.File,
2061 in_offset: u64,
2062 in_len: std.io.Writer.FileLen,
2063 headers_and_trailers: []const []const u8,
2064 headers_len: usize,
2065 ) std.io.Writer.FileError!usize {
2066 const len_int = switch (in_len) {
2067 .zero => return windows_writeSplat(context, headers_and_trailers, 1),
2068 .entire_file => std.math.maxInt(usize),
2069 else => in_len.int(),
2070 };
2071 if (headers_len > 0) return windows_writeSplat(context, headers_and_trailers[0..headers_len], 1);
2072 var file_contents_buffer: [4096]u8 = undefined;
2073 const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)];
2074 const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset);
2075 return windows_writeSplat(context, &.{read_buffer[0..n]}, 1);
2076 }
2083 },
20772084 };
20782085
20792086 pub fn reader(stream: Stream) Reader {
20802087 return switch (native_os) {
2081 .windows => .{ .impl = stream },
2082 else => .{ .impl = .{
2083 .fr = .{
2084 .file = .{ .handle = stream.handle },
2085 .mode = .streaming,
2086 .seek_err = error.Unseekable,
2087 },
2088 .err = {},
2088 .windows => .{ .stream = stream },
2089 else => .{ .file_reader = .{
2090 .file = .{ .handle = stream.handle },
2091 .mode = .streaming,
2092 .seek_err = error.Unseekable,
20892093 } },
20902094 };
20912095 }
20922096
20932097 pub fn writer(stream: Stream) Writer {
20942098 return switch (native_os) {
2095 .windows => .{ .impl = stream },
2096 else => .{ .impl = .{
2097 .fw = .{
2098 .file = .{ .handle = stream.handle },
2099 .mode = .streaming,
2100 },
2101 .err = {},
2099 .windows => .{ .stream = stream },
2100 else => .{ .file_writer = .{
2101 .file = .{ .handle = stream.handle },
2102 .mode = .streaming,
21022103 } },
21032104 };
21042105 }