| ... | ... | @@ -13,6 +13,7 @@ const native_os = builtin.os.tag; |
| 13 | 13 | const windows = std.os.windows; |
| 14 | 14 | const Allocator = std.mem.Allocator; |
| 15 | 15 | const ArrayList = std.ArrayListUnmanaged; |
| 16 | const File = std.fs.File; |
| 16 | 17 | |
| 17 | 18 | // Windows 10 added support for unix sockets in build 17063, redstone 4 is the |
| 18 | 19 | // first release to support them. |
| ... | ... | @@ -853,7 +854,7 @@ pub fn tcpConnectToAddress(address: Address) TcpConnectToAddressError!Stream { |
| 853 | 854 | |
| 854 | 855 | // TODO: Instead of having a massive error set, make the error set have categories, and then |
| 855 | 856 | // store the sub-error as a diagnostic value. |
| 856 | | const GetAddressListError = Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || posix.SocketError || posix.BindError || posix.SetSockOptError || error{ |
| 857 | const GetAddressListError = Allocator.Error || File.OpenError || File.ReadError || posix.SocketError || posix.BindError || posix.SetSockOptError || error{ |
| 857 | 858 | TemporaryNameServerFailure, |
| 858 | 859 | NameServerFailure, |
| 859 | 860 | AddressFamilyNotSupported, |
| ... | ... | @@ -1363,9 +1364,8 @@ fn linuxLookupNameFromHosts( |
| 1363 | 1364 | defer file.close(); |
| 1364 | 1365 | |
| 1365 | 1366 | var line_buf: [512]u8 = undefined; |
| 1366 | | var file_reader = file.reader(); |
| 1367 | | var br = file_reader.interface().buffered(&line_buf); |
| 1368 | | return parseHosts(gpa, addrs, canon, name, family, port, &br) catch |err| switch (err) { |
| 1367 | var file_reader = file.reader(&line_buf); |
| 1368 | return parseHosts(gpa, addrs, canon, name, family, port, &file_reader.interface) catch |err| switch (err) { |
| 1369 | 1369 | error.OutOfMemory => return error.OutOfMemory, |
| 1370 | 1370 | error.ReadFailed => return file_reader.err.?, |
| 1371 | 1371 | }; |
| ... | ... | @@ -1378,7 +1378,7 @@ fn parseHosts( |
| 1378 | 1378 | name: []const u8, |
| 1379 | 1379 | family: posix.sa_family_t, |
| 1380 | 1380 | port: u16, |
| 1381 | | br: *std.io.Reader, |
| 1381 | br: *io.Reader, |
| 1382 | 1382 | ) error{ OutOfMemory, ReadFailed }!void { |
| 1383 | 1383 | while (true) { |
| 1384 | 1384 | const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) { |
| ... | ... | @@ -1584,15 +1584,14 @@ const ResolvConf = struct { |
| 1584 | 1584 | defer file.close(); |
| 1585 | 1585 | |
| 1586 | 1586 | var line_buf: [512]u8 = undefined; |
| 1587 | | var file_reader = file.reader(); |
| 1588 | | var br = file_reader.interface().buffered(&line_buf); |
| 1589 | | return parse(rc, &br) catch |err| switch (err) { |
| 1587 | var file_reader = file.reader(&line_buf); |
| 1588 | return parse(rc, &file_reader.interface) catch |err| switch (err) { |
| 1590 | 1589 | error.ReadFailed => return file_reader.err.?, |
| 1591 | 1590 | else => |e| return e, |
| 1592 | 1591 | }; |
| 1593 | 1592 | } |
| 1594 | 1593 | |
| 1595 | | fn parse(rc: *ResolvConf, br: *std.io.Reader) !void { |
| 1594 | fn parse(rc: *ResolvConf, br: *io.Reader) !void { |
| 1596 | 1595 | const gpa = rc.gpa; |
| 1597 | 1596 | while (br.takeSentinel('\n')) |line_with_comment| { |
| 1598 | 1597 | const line = line: { |
| ... | ... | @@ -1893,7 +1892,10 @@ pub const Stream = struct { |
| 1893 | 1892 | |
| 1894 | 1893 | pub const Reader = switch (native_os) { |
| 1895 | 1894 | .windows => struct { |
| 1896 | | stream: Stream, |
| 1895 | /// Use `interface` to access portably. |
| 1896 | interface_state: io.Reader, |
| 1897 | /// Use `getStream` to access portably. |
| 1898 | net_stream: Stream, |
| 1897 | 1899 | err: ?Error = null, |
| 1898 | 1900 | |
| 1899 | 1901 | pub const Error = ReadError; |
| ... | ... | @@ -1902,29 +1904,27 @@ pub const Stream = struct { |
| 1902 | 1904 | return r.stream; |
| 1903 | 1905 | } |
| 1904 | 1906 | |
| 1905 | | pub fn interface(r: *Reader) std.io.Reader { |
| 1907 | pub fn interface(r: *Reader) *io.Reader { |
| 1908 | return &r.interface_state; |
| 1909 | } |
| 1910 | |
| 1911 | pub fn init(net_stream: Stream, buffer: []u8) Reader { |
| 1906 | 1912 | return .{ |
| 1907 | | .context = r.stream.handle, |
| 1908 | | .vtable = &.{ |
| 1909 | | .read = read, |
| 1910 | | .readVec = readVec, |
| 1911 | | .discard = discard, |
| 1913 | .interface_state = .{ |
| 1914 | .context = undefined, |
| 1915 | .vtable = &.{ |
| 1916 | .stream = stream, |
| 1917 | .discard = discard, |
| 1918 | }, |
| 1919 | .buffer = buffer, |
| 1912 | 1920 | }, |
| 1921 | .net_stream = net_stream, |
| 1913 | 1922 | }; |
| 1914 | 1923 | } |
| 1915 | 1924 | |
| 1916 | | fn read( |
| 1917 | | context: ?*anyopaque, |
| 1918 | | bw: *std.io.Writer, |
| 1919 | | limit: std.io.Limit, |
| 1920 | | ) std.io.Reader.Error!usize { |
| 1921 | | const buf = limit.slice(try bw.writableSliceGreedy(1)); |
| 1922 | | const n = try readVec(context, &.{buf}); |
| 1923 | | bw.advance(n); |
| 1924 | | return n; |
| 1925 | | } |
| 1926 | | |
| 1927 | | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { |
| 1925 | fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize { |
| 1926 | const r: *Reader = @fieldParentPtr("interface", io_r); |
| 1927 | const data = io_w.writableVector(limit); |
| 1928 | 1928 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 1929 | 1929 | var iovecs_i: usize = 0; |
| 1930 | 1930 | for (data) |d| { |
| ... | ... | @@ -1939,7 +1939,7 @@ pub const Stream = struct { |
| 1939 | 1939 | if (bufs.len == 0) return .{}; // Prevent false positive end detection on empty `data`. |
| 1940 | 1940 | var n: u32 = undefined; |
| 1941 | 1941 | var flags: u32 = 0; |
| 1942 | | const rc = windows.ws2_32.WSARecvFrom(context, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); |
| 1942 | const rc = windows.ws2_32.WSARecvFrom(r.net_stream.handle, bufs.ptr, bufs.len, &n, &flags, null, null, null, null); |
| 1943 | 1943 | if (rc != 0) switch (windows.ws2_32.WSAGetLastError()) { |
| 1944 | 1944 | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| 1945 | 1945 | .WSAEFAULT => unreachable, // a pointer is not completely contained in user address space. |
| ... | ... | @@ -1955,22 +1955,35 @@ pub const Stream = struct { |
| 1955 | 1955 | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 1956 | 1956 | else => |err| return windows.unexpectedWSAError(err), |
| 1957 | 1957 | }; |
| 1958 | | return .{ .len = n, .end = n == 0 }; |
| 1958 | if (n == 0) return error.EndOfStream; |
| 1959 | return io_w.advanceVector(n); |
| 1959 | 1960 | } |
| 1960 | 1961 | |
| 1961 | | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { |
| 1962 | | _ = context; |
| 1962 | fn discard(io_r: *io.Reader, limit: io.Limit) io.Reader.Error!usize { |
| 1963 | const r: *Reader = @fieldParentPtr("interface", io_r); |
| 1964 | _ = r; |
| 1963 | 1965 | _ = limit; |
| 1964 | 1966 | @panic("TODO"); |
| 1965 | 1967 | } |
| 1966 | 1968 | }, |
| 1967 | 1969 | else => struct { |
| 1968 | | file_reader: std.fs.File.Reader, |
| 1970 | file_reader: File.Reader, |
| 1969 | 1971 | |
| 1970 | 1972 | pub const Error = ReadError; |
| 1971 | 1973 | |
| 1972 | | pub fn interface(r: *Reader) std.io.Reader { |
| 1973 | | return r.file_reader.interface(); |
| 1974 | pub fn interface(r: *Reader) *io.Reader { |
| 1975 | return &r.file_reader.interface; |
| 1976 | } |
| 1977 | |
| 1978 | pub fn init(net_stream: Stream, buffer: []u8) Reader { |
| 1979 | return .{ |
| 1980 | .file_reader = .{ |
| 1981 | .interface = File.Reader.initInterface(buffer), |
| 1982 | .file = .{ .handle = net_stream.handle }, |
| 1983 | .mode = .streaming, |
| 1984 | .seek_err = error.Unseekable, |
| 1985 | }, |
| 1986 | }; |
| 1974 | 1987 | } |
| 1975 | 1988 | |
| 1976 | 1989 | pub fn getStream(r: *const Reader) Stream { |
| ... | ... | @@ -1981,16 +1994,22 @@ pub const Stream = struct { |
| 1981 | 1994 | |
| 1982 | 1995 | pub const Writer = switch (native_os) { |
| 1983 | 1996 | .windows => struct { |
| 1997 | /// This field is present on all systems. |
| 1998 | interface: io.Writer, |
| 1999 | /// Use `getStream` for cross-platform support. |
| 1984 | 2000 | stream: Stream, |
| 1985 | 2001 | |
| 1986 | 2002 | pub const Error = WriteError; |
| 1987 | 2003 | |
| 1988 | | pub fn interface(w: *Writer) std.io.Writer { |
| 2004 | pub fn init(stream: Stream, buffer: []u8) Writer { |
| 1989 | 2005 | return .{ |
| 1990 | | .context = w.stream.handle, |
| 1991 | | .vtable = &.{ |
| 1992 | | .writeSplat = writeSplat, |
| 1993 | | .writeFile = writeFile, |
| 2006 | .stream = stream, |
| 2007 | .interface = .{ |
| 2008 | .context = undefined, |
| 2009 | .vtable = &.{ |
| 2010 | .drain = drain, |
| 2011 | }, |
| 2012 | .buffer = buffer, |
| 1994 | 2013 | }, |
| 1995 | 2014 | }; |
| 1996 | 2015 | } |
| ... | ... | @@ -1999,41 +2018,63 @@ pub const Stream = struct { |
| 1999 | 2018 | return w.stream; |
| 2000 | 2019 | } |
| 2001 | 2020 | |
| 2002 | | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 2021 | fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize { |
| 2022 | const w: *Writer = @fieldParentPtr("interface", io_w); |
| 2023 | const buffered = io_w.buffered(); |
| 2003 | 2024 | comptime assert(native_os == .windows); |
| 2004 | | if (data.len == 1 and splat == 0) return 0; |
| 2005 | | var splat_buffer: [256]u8 = undefined; |
| 2025 | var splat_buffer: [splat_buffer_len]u8 = undefined; |
| 2006 | 2026 | var iovecs: [max_buffers_len]windows.WSABUF = undefined; |
| 2007 | | var len: u32 = @min(iovecs.len, data.len); |
| 2008 | | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 2009 | | .buf = if (d.len == 0) "" else d.ptr, // TODO: does Windows allow ptr=undefined len=0 ? |
| 2010 | | .len = d.len, |
| 2011 | | }; |
| 2027 | var len: u32 = 0; |
| 2028 | if (buffered.len != 0) { |
| 2029 | iovecs[len] = .{ |
| 2030 | .base = buffered.ptr, |
| 2031 | .len = buffered.len, |
| 2032 | }; |
| 2033 | len += 1; |
| 2034 | } |
| 2035 | for (data[0..data.len]) |bytes| { |
| 2036 | if (bytes.len == 0) continue; |
| 2037 | iovecs[len] = .{ |
| 2038 | .buf = bytes.ptr, |
| 2039 | .len = bytes.len, |
| 2040 | }; |
| 2041 | len += 1; |
| 2042 | } |
| 2043 | const pattern = data[data.len - 1]; |
| 2012 | 2044 | switch (splat) { |
| 2013 | 2045 | 0 => len -= 1, |
| 2014 | 2046 | 1 => {}, |
| 2015 | | else => { |
| 2016 | | const pattern = data[data.len - 1]; |
| 2017 | | if (pattern.len == 1) { |
| 2047 | else => switch (pattern.len) { |
| 2048 | 0 => {}, |
| 2049 | 1 => { |
| 2050 | // Replace the 1-byte buffer with a bigger one. |
| 2018 | 2051 | const memset_len = @min(splat_buffer.len, splat); |
| 2019 | 2052 | const buf = splat_buffer[0..memset_len]; |
| 2020 | 2053 | @memset(buf, pattern[0]); |
| 2021 | | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2054 | iovecs[len - 1] = .{ .buf = buf.ptr, .len = buf.len }; |
| 2022 | 2055 | var remaining_splat = splat - buf.len; |
| 2023 | 2056 | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 2024 | | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2057 | iovecs[len] = .{ .buf = &splat_buffer, .len = splat_buffer.len }; |
| 2025 | 2058 | remaining_splat -= splat_buffer.len; |
| 2026 | 2059 | len += 1; |
| 2027 | 2060 | } |
| 2028 | 2061 | if (remaining_splat > 0 and len < iovecs.len) { |
| 2029 | | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2062 | iovecs[len] = .{ .buf = &splat_buffer, .len = remaining_splat }; |
| 2030 | 2063 | len += 1; |
| 2031 | 2064 | } |
| 2032 | | } |
| 2065 | }, |
| 2066 | else => for (0..splat - 1) |_| { |
| 2067 | if (iovecs.len - len == 0) break; |
| 2068 | iovecs[len] = .{ |
| 2069 | .buf = pattern.ptr, |
| 2070 | .len = pattern.len, |
| 2071 | }; |
| 2072 | len += 1; |
| 2073 | }, |
| 2033 | 2074 | }, |
| 2034 | 2075 | } |
| 2035 | 2076 | var n: u32 = undefined; |
| 2036 | | const rc = windows.ws2_32.WSASend(context, &iovecs, len, &n, 0, null, null); |
| 2077 | const rc = windows.ws2_32.WSASend(w.stream.handle, &iovecs, len, &n, 0, null, null); |
| 2037 | 2078 | if (rc == windows.ws2_32.SOCKET_ERROR) switch (windows.ws2_32.WSAGetLastError()) { |
| 2038 | 2079 | .WSAECONNABORTED => return error.ConnectionResetByPeer, |
| 2039 | 2080 | .WSAECONNRESET => return error.ConnectionResetByPeer, |
| ... | ... | @@ -2054,123 +2095,127 @@ pub const Stream = struct { |
| 2054 | 2095 | .WSA_OPERATION_ABORTED => unreachable, // not using overlapped I/O |
| 2055 | 2096 | else => |err| return windows.unexpectedWSAError(err), |
| 2056 | 2097 | }; |
| 2057 | | return n; |
| 2058 | | } |
| 2059 | | |
| 2060 | | fn writeFile( |
| 2061 | | context: *anyopaque, |
| 2062 | | in_file: std.fs.File, |
| 2063 | | in_offset: u64, |
| 2064 | | in_len: std.io.Writer.FileLen, |
| 2065 | | headers_and_trailers: []const []const u8, |
| 2066 | | headers_len: usize, |
| 2067 | | ) std.io.Writer.FileError!usize { |
| 2068 | | const len_int = switch (in_len) { |
| 2069 | | .zero => return writeSplat(context, headers_and_trailers, 1), |
| 2070 | | .entire_file => std.math.maxInt(usize), |
| 2071 | | else => in_len.int(), |
| 2072 | | }; |
| 2073 | | if (headers_len > 0) return writeSplat(context, headers_and_trailers[0..headers_len], 1); |
| 2074 | | var file_contents_buffer: [4096]u8 = undefined; |
| 2075 | | const read_buffer = file_contents_buffer[0..@min(file_contents_buffer.len, len_int)]; |
| 2076 | | const n = try windows.ReadFile(in_file.handle, read_buffer, in_offset); |
| 2077 | | return writeSplat(context, &.{read_buffer[0..n]}, 1); |
| 2098 | return io_w.consume(n); |
| 2078 | 2099 | } |
| 2079 | 2100 | }, |
| 2080 | 2101 | else => struct { |
| 2081 | | file_writer: std.fs.File.Writer, |
| 2102 | /// This field is present on all systems. |
| 2103 | interface: io.Writer, |
| 2104 | |
| 2082 | 2105 | err: ?Error = null, |
| 2106 | file_writer: File.Writer, |
| 2083 | 2107 | |
| 2084 | 2108 | pub const Error = WriteError; |
| 2085 | 2109 | |
| 2086 | | pub fn interface(w: *Writer) std.io.Writer { |
| 2110 | pub fn init(stream: Stream, buffer: []u8) Writer { |
| 2087 | 2111 | return .{ |
| 2088 | | .context = &w.file_writer, |
| 2089 | | .vtable = &.{ |
| 2090 | | .writeSplat = writeSplat, |
| 2091 | | .writeFile = std.fs.File.Writer.writeFile, |
| 2112 | .interface = .{ |
| 2113 | .context = undefined, |
| 2114 | .vtable = &.{ |
| 2115 | .drain = drain, |
| 2116 | .sendFile = sendFile, |
| 2117 | }, |
| 2118 | .buffer = buffer, |
| 2092 | 2119 | }, |
| 2120 | .file_writer = .initMode(stream.handle, &.{}, .streaming), |
| 2093 | 2121 | }; |
| 2094 | 2122 | } |
| 2095 | 2123 | |
| 2096 | | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 2097 | | const fw: *std.fs.File.Writer = @alignCast(@ptrCast(context)); |
| 2098 | | const w: *Writer = @fieldParentPtr("file_writer", fw); |
| 2099 | | var splat_buffer: [256]u8 = undefined; |
| 2124 | pub fn getStream(w: *const Writer) Stream { |
| 2125 | return .{ .handle = w.file_writer.file.handle }; |
| 2126 | } |
| 2127 | |
| 2128 | fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize { |
| 2129 | const w: *Writer = @fieldParentPtr("interface", io_w); |
| 2130 | const buffered = io_w.buffered(); |
| 2131 | var splat_buffer: [splat_buffer_len]u8 = undefined; |
| 2100 | 2132 | var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; |
| 2101 | | var len: usize = @min(iovecs.len, data.len); |
| 2102 | | for (iovecs[0..len], data[0..len]) |*v, d| v.* = .{ |
| 2103 | | .base = if (d.len == 0) "" else d.ptr, // OS sadly checks ptr addr before length. |
| 2104 | | .len = d.len, |
| 2105 | | }; |
| 2106 | | var msg: posix.msghdr_const = .{ |
| 2107 | | .name = null, |
| 2108 | | .namelen = 0, |
| 2109 | | .iov = &iovecs, |
| 2110 | | .iovlen = len, |
| 2111 | | .control = null, |
| 2112 | | .controllen = 0, |
| 2113 | | .flags = 0, |
| 2133 | var msg: posix.msghdr_const = msg: { |
| 2134 | var i: usize = 0; |
| 2135 | if (buffered.len != 0) { |
| 2136 | iovecs[i] = .{ |
| 2137 | .base = buffered.ptr, |
| 2138 | .len = buffered.len, |
| 2139 | }; |
| 2140 | i += 1; |
| 2141 | } |
| 2142 | for (data[0..data.len]) |bytes| { |
| 2143 | // OS checks ptr addr before length so zero length vectors must be omitted. |
| 2144 | if (bytes.len == 0) continue; |
| 2145 | iovecs[i] = .{ |
| 2146 | .base = bytes.ptr, |
| 2147 | .len = bytes.len, |
| 2148 | }; |
| 2149 | i += 1; |
| 2150 | if (iovecs.len - i == 0) break; |
| 2151 | } |
| 2152 | break :msg .{ |
| 2153 | .name = null, |
| 2154 | .namelen = 0, |
| 2155 | .iov = &iovecs, |
| 2156 | .iovlen = i, |
| 2157 | .control = null, |
| 2158 | .controllen = 0, |
| 2159 | .flags = 0, |
| 2160 | }; |
| 2114 | 2161 | }; |
| 2162 | const pattern = data[data.len - 1]; |
| 2115 | 2163 | switch (splat) { |
| 2116 | | 0 => msg.iovlen = len - 1, |
| 2164 | 0 => msg.iovlen -= 1, |
| 2117 | 2165 | 1 => {}, |
| 2118 | | else => { |
| 2119 | | const pattern = data[data.len - 1]; |
| 2120 | | if (pattern.len == 1) { |
| 2166 | else => switch (pattern.len) { |
| 2167 | 0 => {}, |
| 2168 | 1 => { |
| 2169 | // Replace the 1-byte buffer with a bigger one. |
| 2121 | 2170 | const memset_len = @min(splat_buffer.len, splat); |
| 2122 | 2171 | const buf = splat_buffer[0..memset_len]; |
| 2123 | 2172 | @memset(buf, pattern[0]); |
| 2124 | | iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2173 | iovecs[msg.iovlen - 1] = .{ .base = buf.ptr, .len = buf.len }; |
| 2125 | 2174 | var remaining_splat = splat - buf.len; |
| 2126 | | while (remaining_splat > splat_buffer.len and len < iovecs.len) { |
| 2127 | | iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2175 | while (remaining_splat > splat_buffer.len and msg.iovlen < iovecs.len) { |
| 2176 | iovecs[msg.iovlen] = .{ .base = &splat_buffer, .len = splat_buffer.len }; |
| 2128 | 2177 | remaining_splat -= splat_buffer.len; |
| 2129 | | len += 1; |
| 2178 | msg.iovlen += 1; |
| 2130 | 2179 | } |
| 2131 | | if (remaining_splat > 0 and len < iovecs.len) { |
| 2132 | | iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2133 | | len += 1; |
| 2180 | if (remaining_splat > 0 and msg.iovlen < iovecs.len) { |
| 2181 | iovecs[msg.iovlen] = .{ .base = &splat_buffer, .len = remaining_splat }; |
| 2182 | msg.iovlen += 1; |
| 2134 | 2183 | } |
| 2135 | | msg.iovlen = len; |
| 2136 | | } |
| 2184 | }, |
| 2185 | else => for (0..splat - 1) |_| { |
| 2186 | if (iovecs.len - msg.iovlen == 0) break; |
| 2187 | iovecs[msg.iovlen] = .{ |
| 2188 | .base = pattern.ptr, |
| 2189 | .len = pattern.len, |
| 2190 | }; |
| 2191 | msg.iovlen += 1; |
| 2192 | }, |
| 2137 | 2193 | }, |
| 2138 | 2194 | } |
| 2139 | 2195 | const flags = posix.MSG.NOSIGNAL; |
| 2140 | | return std.posix.sendmsg(fw.file.handle, &msg, flags) catch |err| { |
| 2196 | return io_w.consume(std.posix.sendmsg(w.file_writer.file.handle, &msg, flags) catch |err| { |
| 2141 | 2197 | w.err = err; |
| 2142 | 2198 | return error.WriteFailed; |
| 2143 | | }; |
| 2199 | }); |
| 2144 | 2200 | } |
| 2145 | 2201 | |
| 2146 | | pub fn getStream(w: *const Writer) Stream { |
| 2147 | | return .{ .handle = w.file_writer.file.handle }; |
| 2202 | fn sendFile(io_w: *io.Writer, file_reader: *File.Reader, limit: io.Limit) io.Writer.FileError!usize { |
| 2203 | const w: *Writer = @fieldParentPtr("interface", io_w); |
| 2204 | return io_w.sendFileTo(&w.file_writer.interface, file_reader, limit); |
| 2148 | 2205 | } |
| 2149 | 2206 | }, |
| 2150 | 2207 | }; |
| 2151 | 2208 | |
| 2152 | | pub fn reader(stream: Stream) Reader { |
| 2153 | | return switch (native_os) { |
| 2154 | | .windows => .{ .stream = stream }, |
| 2155 | | else => .{ .file_reader = .{ |
| 2156 | | .file = .{ .handle = stream.handle }, |
| 2157 | | .mode = .streaming, |
| 2158 | | .seek_err = error.Unseekable, |
| 2159 | | } }, |
| 2160 | | }; |
| 2209 | pub fn reader(stream: Stream, buffer: []u8) Reader { |
| 2210 | return .init(stream, buffer); |
| 2161 | 2211 | } |
| 2162 | 2212 | |
| 2163 | | pub fn writer(stream: Stream) Writer { |
| 2164 | | return switch (native_os) { |
| 2165 | | .windows => .{ .stream = stream }, |
| 2166 | | else => .{ .file_writer = .{ |
| 2167 | | .file = .{ .handle = stream.handle }, |
| 2168 | | .mode = .streaming, |
| 2169 | | } }, |
| 2170 | | }; |
| 2213 | pub fn writer(stream: Stream, buffer: []u8) Writer { |
| 2214 | return .init(stream, buffer); |
| 2171 | 2215 | } |
| 2172 | 2216 | |
| 2173 | 2217 | const max_buffers_len = 8; |
| 2218 | const splat_buffer_len = 256; |
| 2174 | 2219 | }; |
| 2175 | 2220 | |
| 2176 | 2221 | pub const Server = struct { |