milestone 5: blocklist filtering, local records and conditional forwarding
This commit is contained in:
@@ -199,11 +199,11 @@ fn tcpQuery(io: std.Io, address: net.IpAddress, id: u16) anyerror!void {
|
||||
var query_buf: [query_bytes.len]u8 = undefined;
|
||||
const query = queryWithId(&query_buf, id);
|
||||
|
||||
try writer.interface.writeAll(&tcp_server.framePrefix(@intCast(query.len)));
|
||||
try writer.interface.writeAll(&transport.framePrefix(@intCast(query.len)));
|
||||
try writer.interface.writeAll(query);
|
||||
try writer.interface.flush();
|
||||
|
||||
const len = tcp_server.parsePrefix((try reader.interface.takeArray(tcp_server.prefix_len)).*);
|
||||
const len = transport.parsePrefix((try reader.interface.takeArray(transport.prefix_len)).*);
|
||||
try expectAnswer(try reader.interface.take(len), id);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ const transport = @import("../upstream/transport.zig");
|
||||
|
||||
const log = std.log.scoped(.tcp_server);
|
||||
|
||||
/// RFC 1035 §4.2.2: the message length prefix is two bytes, big-endian.
|
||||
pub const prefix_len = 2;
|
||||
|
||||
/// The stream buffers only stage the framing bytes. A message longer than this
|
||||
/// is read straight into `Conn.query` and written straight from `Conn.reply`,
|
||||
/// so making them larger would buy nothing.
|
||||
@@ -220,7 +217,7 @@ pub const TcpServer = struct {
|
||||
const budget = self.options.idle_timeout;
|
||||
|
||||
while (true) {
|
||||
var prefix: [prefix_len]u8 = undefined;
|
||||
var prefix: [transport.prefix_len]u8 = undefined;
|
||||
var got: usize = 0;
|
||||
switch (race(io, budget, readPrefix, .{ &reader.interface, &prefix, &got })) {
|
||||
.ok => {},
|
||||
@@ -238,14 +235,14 @@ pub const TcpServer = struct {
|
||||
// A client that closes between messages has finished asking, which
|
||||
// is the normal end of a connection, not a failure.
|
||||
if (got == 0) return;
|
||||
if (got != prefix_len) {
|
||||
if (got != transport.prefix_len) {
|
||||
bump(&self.stats.connection_errors);
|
||||
return;
|
||||
}
|
||||
|
||||
// RFC 1035 §4.2.2 gives no meaning to a zero-length message, and
|
||||
// the prefix is a u16 so it can never exceed `max_message_len`.
|
||||
const len = parsePrefix(prefix);
|
||||
const len = transport.parsePrefix(prefix);
|
||||
if (len == 0) {
|
||||
bump(&self.stats.connection_errors);
|
||||
return;
|
||||
@@ -267,7 +264,7 @@ pub const TcpServer = struct {
|
||||
.reply => |b| b,
|
||||
};
|
||||
|
||||
const out = framePrefix(@intCast(bytes.len));
|
||||
const out = transport.framePrefix(@intCast(bytes.len));
|
||||
switch (race(io, budget, writeReply, .{ &writer.interface, &out, bytes })) {
|
||||
.ok => {},
|
||||
.canceled => return,
|
||||
@@ -333,17 +330,6 @@ pub const TcpServer = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// RFC 1035 §4.2.2: the message length as a 2-byte big-endian integer.
|
||||
pub fn framePrefix(len: u16) [prefix_len]u8 {
|
||||
var out: [prefix_len]u8 = undefined;
|
||||
std.mem.writeInt(u16, &out, len, .big);
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn parsePrefix(bytes: [prefix_len]u8) u16 {
|
||||
return std.mem.readInt(u16, &bytes, .big);
|
||||
}
|
||||
|
||||
/// The capacity rule, without the mutex, so it is testable without a backend.
|
||||
fn firstFree(conns: []const TcpServer.Conn) ?usize {
|
||||
for (conns, 0..) |*conn, index| {
|
||||
@@ -402,7 +388,7 @@ fn expire(io: std.Io, budget: std.Io.Clock.Duration) std.Io.Cancelable!void {
|
||||
|
||||
/// `readSliceShort` rather than `readSliceAll`: a zero-length read is a client
|
||||
/// that closed cleanly between messages, and only a partial prefix is an error.
|
||||
fn readPrefix(reader: *std.Io.Reader, buf: *[prefix_len]u8, out_len: *usize) anyerror!void {
|
||||
fn readPrefix(reader: *std.Io.Reader, buf: *[transport.prefix_len]u8, out_len: *usize) anyerror!void {
|
||||
out_len.* = try reader.readSliceShort(buf);
|
||||
}
|
||||
|
||||
@@ -410,7 +396,7 @@ fn readBody(reader: *std.Io.Reader, buf: []u8) anyerror!void {
|
||||
return reader.readSliceAll(buf);
|
||||
}
|
||||
|
||||
fn writeReply(writer: *std.Io.Writer, prefix: *const [prefix_len]u8, bytes: []const u8) anyerror!void {
|
||||
fn writeReply(writer: *std.Io.Writer, prefix: *const [transport.prefix_len]u8, bytes: []const u8) anyerror!void {
|
||||
try writer.writeAll(prefix);
|
||||
try writer.writeAll(bytes);
|
||||
try writer.flush();
|
||||
@@ -422,20 +408,6 @@ fn bump(counter: *std.atomic.Value(u64)) void {
|
||||
|
||||
const testing = std.testing;
|
||||
|
||||
test "the length prefix is big-endian and round-trips" {
|
||||
try testing.expectEqualSlices(u8, &.{ 0x00, 0x00 }, &framePrefix(0));
|
||||
try testing.expectEqualSlices(u8, &.{ 0x01, 0x00 }, &framePrefix(256));
|
||||
try testing.expectEqualSlices(u8, &.{ 0xff, 0xff }, &framePrefix(65535));
|
||||
|
||||
for ([_]u16{ 0, 1, 12, 512, 4096, 65534, 65535 }) |len| {
|
||||
try testing.expectEqual(len, parsePrefix(framePrefix(len)));
|
||||
}
|
||||
}
|
||||
|
||||
test "the prefix ceiling is the message ceiling" {
|
||||
try testing.expectEqual(@as(u16, transport.max_message_len), parsePrefix(.{ 0xff, 0xff }));
|
||||
}
|
||||
|
||||
fn testConns(count: usize) ![]TcpServer.Conn {
|
||||
const conns = try testing.allocator.alloc(TcpServer.Conn, count);
|
||||
for (conns) |*conn| conn.state = .free;
|
||||
|
||||
@@ -117,11 +117,11 @@ fn twoQueriesOnOneConnection(io: std.Io, address: net.IpAddress) anyerror!void {
|
||||
var writer = stream.writer(io, &write_buf);
|
||||
|
||||
for (0..2) |_| {
|
||||
try writer.interface.writeAll(&tcp_server.framePrefix(@intCast(query_bytes.len)));
|
||||
try writer.interface.writeAll(&transport.framePrefix(@intCast(query_bytes.len)));
|
||||
try writer.interface.writeAll(query_bytes);
|
||||
try writer.interface.flush();
|
||||
|
||||
const len = tcp_server.parsePrefix((try reader.interface.takeArray(tcp_server.prefix_len)).*);
|
||||
const len = transport.parsePrefix((try reader.interface.takeArray(transport.prefix_len)).*);
|
||||
try expectAnswersQuery(try reader.interface.take(len));
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,7 @@ fn sendZeroLength(io: std.Io, address: net.IpAddress) anyerror!void {
|
||||
|
||||
var write_buf: [64]u8 = undefined;
|
||||
var writer = stream.writer(io, &write_buf);
|
||||
try writer.interface.writeAll(&tcp_server.framePrefix(0));
|
||||
try writer.interface.writeAll(&transport.framePrefix(0));
|
||||
try writer.interface.flush();
|
||||
|
||||
var read_buf: [64]u8 = undefined;
|
||||
|
||||
Reference in New Issue
Block a user