mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 19:23:08 +00:00
Io.net: implement sortLookupResults
This commit is contained in:
parent
676f1b492e
commit
4e887625d4
@ -132,9 +132,58 @@ pub const HostName = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sortLookupResults(options: LookupOptions, result: LookupResult) !LookupResult {
|
fn sortLookupResults(options: LookupOptions, result: LookupResult) !LookupResult {
|
||||||
_ = options;
|
const addresses = options.addresses_buffer[0..result.addresses_len];
|
||||||
_ = result;
|
// No further processing is needed if there are fewer than 2 results or
|
||||||
@panic("TODO");
|
// if there are only IPv4 results.
|
||||||
|
if (addresses.len < 2) return result;
|
||||||
|
const all_ip4 = for (addresses) |a| switch (a) {
|
||||||
|
.ip4 => continue,
|
||||||
|
.ip6 => break false,
|
||||||
|
} else true;
|
||||||
|
if (all_ip4) return result;
|
||||||
|
|
||||||
|
// RFC 3484/6724 describes how destination address selection is
|
||||||
|
// supposed to work. However, to implement it requires making a bunch
|
||||||
|
// of networking syscalls, which is unnecessarily high latency,
|
||||||
|
// especially if implemented serially. Furthermore, rules 3, 4, and 7
|
||||||
|
// have excessive runtime and code size cost and dubious benefit.
|
||||||
|
//
|
||||||
|
// Therefore, this logic sorts only using values available without
|
||||||
|
// doing any syscalls, relying on the calling code to have a
|
||||||
|
// meta-strategy such as attempting connection to multiple results at
|
||||||
|
// once and keeping the fastest response while canceling the others.
|
||||||
|
|
||||||
|
const S = struct {
|
||||||
|
pub fn lessThan(s: @This(), lhs: IpAddress, rhs: IpAddress) bool {
|
||||||
|
return sortKey(s, lhs) < sortKey(s, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sortKey(s: @This(), a: IpAddress) i32 {
|
||||||
|
_ = s;
|
||||||
|
var da6: Ip6Address = .{
|
||||||
|
.port = 65535,
|
||||||
|
.bytes = undefined,
|
||||||
|
};
|
||||||
|
switch (a) {
|
||||||
|
.ip6 => |ip6| {
|
||||||
|
da6.bytes = ip6.bytes;
|
||||||
|
da6.scope_id = ip6.scope_id;
|
||||||
|
},
|
||||||
|
.ip4 => |ip4| {
|
||||||
|
da6.bytes[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
||||||
|
da6.bytes[12..].* = ip4.bytes;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const da6_scope: i32 = da6.scope();
|
||||||
|
const da6_prec: i32 = da6.policy().prec;
|
||||||
|
var key: i32 = 0;
|
||||||
|
key |= da6_prec << 20;
|
||||||
|
key |= (15 - da6_scope) << 16;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std.mem.sort(IpAddress, addresses, @as(S, .{}), S.lessThan);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookupDns(io: Io, options: LookupOptions) !LookupResult {
|
fn lookupDns(io: Io, options: LookupOptions) !LookupResult {
|
||||||
@ -406,6 +455,14 @@ pub const Ip6Address = struct {
|
|||||||
Incomplete,
|
Incomplete,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Policy = struct {
|
||||||
|
addr: [16]u8,
|
||||||
|
len: u8,
|
||||||
|
mask: u8,
|
||||||
|
prec: u8,
|
||||||
|
label: u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn localhost(port: u16) Ip6Address {
|
pub fn localhost(port: u16) Ip6Address {
|
||||||
return .{
|
return .{
|
||||||
.bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
.bytes = .{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||||
@ -597,6 +654,98 @@ pub const Ip6Address = struct {
|
|||||||
pub fn eql(a: Ip6Address, b: Ip6Address) bool {
|
pub fn eql(a: Ip6Address, b: Ip6Address) bool {
|
||||||
return a.port == b.port and std.mem.eql(u8, &a.bytes, &b.bytes);
|
return a.port == b.port and std.mem.eql(u8, &a.bytes, &b.bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isMultiCast(a: Ip6Address) bool {
|
||||||
|
return a.bytes[0] == 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isLinkLocal(a: Ip6Address) bool {
|
||||||
|
const b = &a.bytes;
|
||||||
|
return b[0] == 0xfe and (b[1] & 0xc0) == 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isLoopBack(a: Ip6Address) bool {
|
||||||
|
const b = &a.bytes;
|
||||||
|
return b[0] == 0 and b[1] == 0 and
|
||||||
|
b[2] == 0 and
|
||||||
|
b[12] == 0 and b[13] == 0 and
|
||||||
|
b[14] == 0 and b[15] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isSiteLocal(a: Ip6Address) bool {
|
||||||
|
const b = &a.bytes;
|
||||||
|
return b[0] == 0xfe and (b[1] & 0xc0) == 0xc0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn policy(a: Ip6Address) *const Policy {
|
||||||
|
const b = &a.bytes;
|
||||||
|
for (&defined_policies) |*p| {
|
||||||
|
if (!std.mem.eql(u8, b[0..p.len], p.addr[0..p.len])) continue;
|
||||||
|
if ((b[p.len] & p.mask) != p.addr[p.len]) continue;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scope(a: Ip6Address) u8 {
|
||||||
|
if (isMultiCast(a)) return a.bytes[1] & 15;
|
||||||
|
if (isLinkLocal(a)) return 2;
|
||||||
|
if (isLoopBack(a)) return 2;
|
||||||
|
if (isSiteLocal(a)) return 5;
|
||||||
|
return 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defined_policies = [_]Policy{
|
||||||
|
.{
|
||||||
|
.addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".*,
|
||||||
|
.len = 15,
|
||||||
|
.mask = 0xff,
|
||||||
|
.prec = 50,
|
||||||
|
.label = 0,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00".*,
|
||||||
|
.len = 11,
|
||||||
|
.mask = 0xff,
|
||||||
|
.prec = 35,
|
||||||
|
.label = 4,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
|
||||||
|
.len = 1,
|
||||||
|
.mask = 0xff,
|
||||||
|
.prec = 30,
|
||||||
|
.label = 2,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
|
||||||
|
.len = 3,
|
||||||
|
.mask = 0xff,
|
||||||
|
.prec = 5,
|
||||||
|
.label = 5,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
|
||||||
|
.len = 0,
|
||||||
|
.mask = 0xfe,
|
||||||
|
.prec = 3,
|
||||||
|
.label = 13,
|
||||||
|
},
|
||||||
|
// These are deprecated and/or returned to the address
|
||||||
|
// pool, so despite the RFC, treating them as special
|
||||||
|
// is probably wrong.
|
||||||
|
// { "", 11, 0xff, 1, 3 },
|
||||||
|
// { "\xfe\xc0", 1, 0xc0, 1, 11 },
|
||||||
|
// { "\x3f\xfe", 1, 0xff, 1, 12 },
|
||||||
|
// Last rule must match all addresses to stop loop.
|
||||||
|
.{
|
||||||
|
.addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*,
|
||||||
|
.len = 0,
|
||||||
|
.mask = 0,
|
||||||
|
.prec = 40,
|
||||||
|
.label = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Stream = struct {
|
pub const Stream = struct {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user