Add basics of resolveIp6
Instead of streaming the scope id digits to an u32, we keep a [32]u8 in the stack and fill it up with the characters we get for scope id.master
parent
bae0c9b554
commit
b816303122
135
lib/std/net.zig
135
lib/std/net.zig
|
@ -21,6 +21,9 @@ pub const Address = extern union {
|
|||
// TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512
|
||||
//pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0);
|
||||
|
||||
/// Parse the given IP address string into an Address value.
|
||||
/// It is recommended to use Address.resolveIp instead, to handle
|
||||
/// IPv6 link-local unix addresses.
|
||||
pub fn parseIp(name: []const u8, port: u16) !Address {
|
||||
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
|
||||
error.Overflow,
|
||||
|
@ -42,6 +45,27 @@ pub const Address = extern union {
|
|||
return error.InvalidIPAddressFormat;
|
||||
}
|
||||
|
||||
pub fn resolveIp(name: []const u8, port: u16) !Address {
|
||||
if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) {
|
||||
error.Overflow,
|
||||
error.InvalidEnd,
|
||||
error.InvalidCharacter,
|
||||
error.Incomplete,
|
||||
=> {},
|
||||
}
|
||||
|
||||
if (resolveIp6(name, port)) |ip6| return ip6 else |err| switch (err) {
|
||||
error.Overflow,
|
||||
error.InvalidEnd,
|
||||
error.InvalidCharacter,
|
||||
error.Incomplete,
|
||||
error.InvalidIpv4Mapping,
|
||||
=> {},
|
||||
}
|
||||
|
||||
return error.InvalidIPAddressFormat;
|
||||
}
|
||||
|
||||
pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !Address {
|
||||
switch (family) {
|
||||
os.AF_INET => return parseIp4(name, port),
|
||||
|
@ -157,6 +181,117 @@ pub const Address = extern union {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resolveIp6(buf: []const u8, port: u16) !Address {
|
||||
// FIXME: implement if_nametoindex
|
||||
// FIXME: this is a very bad implementation, since it's only a copy
|
||||
// of parseIp6 with alphanumerical scope id support
|
||||
var result = Address{
|
||||
.in6 = os.sockaddr_in6{
|
||||
.scope_id = 0,
|
||||
.port = mem.nativeToBig(u16, port),
|
||||
.flowinfo = 0,
|
||||
.addr = undefined,
|
||||
},
|
||||
};
|
||||
var ip_slice = result.in6.addr[0..];
|
||||
|
||||
var tail: [16]u8 = undefined;
|
||||
|
||||
var x: u16 = 0;
|
||||
var saw_any_digits = false;
|
||||
var index: u8 = 0;
|
||||
var abbrv = false;
|
||||
|
||||
var scope_id = false;
|
||||
var scope_id_value: [32]u8 = undefined;
|
||||
var scope_id_index: usize = 0;
|
||||
|
||||
for (buf) |c, i| {
|
||||
if (scope_id) {
|
||||
scope_id_value[scope_id_index] = c;
|
||||
scope_id_index += 1;
|
||||
} else if (c == ':') {
|
||||
if (!saw_any_digits) {
|
||||
if (abbrv) return error.InvalidCharacter; // ':::'
|
||||
if (i != 0) abbrv = true;
|
||||
mem.set(u8, ip_slice[index..], 0);
|
||||
ip_slice = tail[0..];
|
||||
index = 0;
|
||||
continue;
|
||||
}
|
||||
if (index == 14) {
|
||||
return error.InvalidEnd;
|
||||
}
|
||||
ip_slice[index] = @truncate(u8, x >> 8);
|
||||
index += 1;
|
||||
ip_slice[index] = @truncate(u8, x);
|
||||
index += 1;
|
||||
|
||||
x = 0;
|
||||
saw_any_digits = false;
|
||||
} else if (c == '%') {
|
||||
if (!saw_any_digits) {
|
||||
return error.InvalidCharacter;
|
||||
}
|
||||
scope_id = true;
|
||||
saw_any_digits = false;
|
||||
} else if (c == '.') {
|
||||
if (!abbrv or ip_slice[0] != 0xff or ip_slice[1] != 0xff) {
|
||||
// must start with '::ffff:'
|
||||
return error.InvalidIpv4Mapping;
|
||||
}
|
||||
const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1;
|
||||
const addr = (parseIp4(buf[start_index..], 0) catch {
|
||||
return error.InvalidIpv4Mapping;
|
||||
}).in.addr;
|
||||
ip_slice = result.in6.addr[0..];
|
||||
ip_slice[10] = 0xff;
|
||||
ip_slice[11] = 0xff;
|
||||
|
||||
const ptr = mem.sliceAsBytes(@as(*const [1]u32, &addr)[0..]);
|
||||
|
||||
ip_slice[12] = ptr[0];
|
||||
ip_slice[13] = ptr[1];
|
||||
ip_slice[14] = ptr[2];
|
||||
ip_slice[15] = ptr[3];
|
||||
return result;
|
||||
} else {
|
||||
const digit = try std.fmt.charToDigit(c, 16);
|
||||
if (@mulWithOverflow(u16, x, 16, &x)) {
|
||||
return error.Overflow;
|
||||
}
|
||||
if (@addWithOverflow(u16, x, digit, &x)) {
|
||||
return error.Overflow;
|
||||
}
|
||||
saw_any_digits = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!saw_any_digits and !abbrv) {
|
||||
return error.Incomplete;
|
||||
}
|
||||
|
||||
const resolved_scope_id = std.fmt.parseInt(u32, scope_id_value, 10) catch |err| blk: {
|
||||
if (err != err.InvalidCharacter) return err;
|
||||
break :blk if_nametoindex(scope_id_value);
|
||||
}
|
||||
|
||||
result.in6.scope_id = resolved_scope_id;
|
||||
|
||||
if (index == 14) {
|
||||
ip_slice[14] = @truncate(u8, x >> 8);
|
||||
ip_slice[15] = @truncate(u8, x);
|
||||
return result;
|
||||
} else {
|
||||
ip_slice[index] = @truncate(u8, x >> 8);
|
||||
index += 1;
|
||||
ip_slice[index] = @truncate(u8, x);
|
||||
index += 1;
|
||||
mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parseIp4(buf: []const u8, port: u16) !Address {
|
||||
var result = Address{
|
||||
.in = os.sockaddr_in{
|
||||
|
|
Loading…
Reference in New Issue