mirror of
https://github.com/ziglang/zig.git
synced 2025-12-07 06:43:07 +00:00
120 lines
3.6 KiB
Zig
120 lines
3.6 KiB
Zig
stream: std.net.Stream,
|
|
|
|
read_buf: [buffer_size]u8,
|
|
read_start: u16,
|
|
read_end: u16,
|
|
|
|
pub const buffer_size = std.crypto.tls.max_ciphertext_record_len;
|
|
|
|
pub fn rawReadAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize {
|
|
return conn.stream.readAtLeast(buffer, len) catch |err| {
|
|
switch (err) {
|
|
error.ConnectionResetByPeer, error.BrokenPipe => return error.ConnectionResetByPeer,
|
|
else => return error.UnexpectedReadFailure,
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn fill(conn: *Connection) ReadError!void {
|
|
if (conn.read_end != conn.read_start) return;
|
|
|
|
const nread = try conn.rawReadAtLeast(conn.read_buf[0..], 1);
|
|
if (nread == 0) return error.EndOfStream;
|
|
conn.read_start = 0;
|
|
conn.read_end = @intCast(nread);
|
|
}
|
|
|
|
pub fn peek(conn: *Connection) []const u8 {
|
|
return conn.read_buf[conn.read_start..conn.read_end];
|
|
}
|
|
|
|
pub fn drop(conn: *Connection, num: u16) void {
|
|
conn.read_start += num;
|
|
}
|
|
|
|
pub fn readAtLeast(conn: *Connection, buffer: []u8, len: usize) ReadError!usize {
|
|
assert(len <= buffer.len);
|
|
|
|
var out_index: u16 = 0;
|
|
while (out_index < len) {
|
|
const available_read = conn.read_end - conn.read_start;
|
|
const available_buffer = buffer.len - out_index;
|
|
|
|
if (available_read > available_buffer) { // partially read buffered data
|
|
@memcpy(buffer[out_index..], conn.read_buf[conn.read_start..conn.read_end][0..available_buffer]);
|
|
out_index += @as(u16, @intCast(available_buffer));
|
|
conn.read_start += @as(u16, @intCast(available_buffer));
|
|
|
|
break;
|
|
} else if (available_read > 0) { // fully read buffered data
|
|
@memcpy(buffer[out_index..][0..available_read], conn.read_buf[conn.read_start..conn.read_end]);
|
|
out_index += available_read;
|
|
conn.read_start += available_read;
|
|
|
|
if (out_index >= len) break;
|
|
}
|
|
|
|
const leftover_buffer = available_buffer - available_read;
|
|
const leftover_len = len - out_index;
|
|
|
|
if (leftover_buffer > conn.read_buf.len) {
|
|
// skip the buffer if the output is large enough
|
|
return conn.rawReadAtLeast(buffer[out_index..], leftover_len);
|
|
}
|
|
|
|
try conn.fill();
|
|
}
|
|
|
|
return out_index;
|
|
}
|
|
|
|
pub fn read(conn: *Connection, buffer: []u8) ReadError!usize {
|
|
return conn.readAtLeast(buffer, 1);
|
|
}
|
|
|
|
pub const ReadError = error{
|
|
ConnectionTimedOut,
|
|
ConnectionResetByPeer,
|
|
UnexpectedReadFailure,
|
|
EndOfStream,
|
|
};
|
|
|
|
pub const Reader = std.io.Reader(*Connection, ReadError, read);
|
|
|
|
pub fn reader(conn: *Connection) Reader {
|
|
return .{ .context = conn };
|
|
}
|
|
|
|
pub fn writeAll(conn: *Connection, buffer: []const u8) WriteError!void {
|
|
return conn.stream.writeAll(buffer) catch |err| switch (err) {
|
|
error.BrokenPipe, error.ConnectionResetByPeer => return error.ConnectionResetByPeer,
|
|
else => return error.UnexpectedWriteFailure,
|
|
};
|
|
}
|
|
|
|
pub fn write(conn: *Connection, buffer: []const u8) WriteError!usize {
|
|
return conn.stream.write(buffer) catch |err| switch (err) {
|
|
error.BrokenPipe, error.ConnectionResetByPeer => return error.ConnectionResetByPeer,
|
|
else => return error.UnexpectedWriteFailure,
|
|
};
|
|
}
|
|
|
|
pub const WriteError = error{
|
|
ConnectionResetByPeer,
|
|
UnexpectedWriteFailure,
|
|
};
|
|
|
|
pub const Writer = std.io.Writer(*Connection, WriteError, write);
|
|
|
|
pub fn writer(conn: *Connection) Writer {
|
|
return .{ .context = conn };
|
|
}
|
|
|
|
pub fn close(conn: *Connection) void {
|
|
conn.stream.close();
|
|
}
|
|
|
|
const Connection = @This();
|
|
const std = @import("../../std.zig");
|
|
const assert = std.debug.assert;
|