mirror of
https://github.com/ziglang/zig.git
synced 2025-12-18 04:03:14 +00:00
commit
ce70a9be24
104
lib/std/net.zig
104
lib/std/net.zig
@ -32,6 +32,7 @@ pub const IpAddress = extern union {
|
|||||||
error.InvalidEnd,
|
error.InvalidEnd,
|
||||||
error.InvalidCharacter,
|
error.InvalidCharacter,
|
||||||
error.Incomplete,
|
error.Incomplete,
|
||||||
|
error.InvalidIpv4Mapping,
|
||||||
=> {},
|
=> {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,19 +51,22 @@ pub const IpAddress = extern union {
|
|||||||
pub fn parseIp6(buf: []const u8, port: u16) !IpAddress {
|
pub fn parseIp6(buf: []const u8, port: u16) !IpAddress {
|
||||||
var result = IpAddress{
|
var result = IpAddress{
|
||||||
.in6 = os.sockaddr_in6{
|
.in6 = os.sockaddr_in6{
|
||||||
.scope_id = undefined,
|
.scope_id = 0,
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
.flowinfo = 0,
|
.flowinfo = 0,
|
||||||
.addr = undefined,
|
.addr = undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const ip_slice = result.in6.addr[0..];
|
var ip_slice = result.in6.addr[0..];
|
||||||
|
|
||||||
|
var tail: [16]u8 = undefined;
|
||||||
|
|
||||||
var x: u16 = 0;
|
var x: u16 = 0;
|
||||||
var saw_any_digits = false;
|
var saw_any_digits = false;
|
||||||
var index: u8 = 0;
|
var index: u8 = 0;
|
||||||
var scope_id = false;
|
var scope_id = false;
|
||||||
for (buf) |c| {
|
var abbrv = false;
|
||||||
|
for (buf) |c, i| {
|
||||||
if (scope_id) {
|
if (scope_id) {
|
||||||
if (c >= '0' and c <= '9') {
|
if (c >= '0' and c <= '9') {
|
||||||
const digit = c - '0';
|
const digit = c - '0';
|
||||||
@ -77,7 +81,12 @@ pub const IpAddress = extern union {
|
|||||||
}
|
}
|
||||||
} else if (c == ':') {
|
} else if (c == ':') {
|
||||||
if (!saw_any_digits) {
|
if (!saw_any_digits) {
|
||||||
return error.InvalidCharacter;
|
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) {
|
if (index == 14) {
|
||||||
return error.InvalidEnd;
|
return error.InvalidEnd;
|
||||||
@ -93,14 +102,26 @@ pub const IpAddress = extern union {
|
|||||||
if (!saw_any_digits) {
|
if (!saw_any_digits) {
|
||||||
return error.InvalidCharacter;
|
return error.InvalidCharacter;
|
||||||
}
|
}
|
||||||
if (index == 14) {
|
|
||||||
ip_slice[index] = @truncate(u8, x >> 8);
|
|
||||||
index += 1;
|
|
||||||
ip_slice[index] = @truncate(u8, x);
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
scope_id = true;
|
scope_id = true;
|
||||||
saw_any_digits = false;
|
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;
|
||||||
|
|
||||||
|
ip_slice[12] = @truncate(u8, addr >> 24 & 0xff);
|
||||||
|
ip_slice[13] = @truncate(u8, addr >> 16 & 0xff);
|
||||||
|
ip_slice[14] = @truncate(u8, addr >> 8 & 0xff);
|
||||||
|
ip_slice[15] = @truncate(u8, addr & 0xff);
|
||||||
|
return result;
|
||||||
} else {
|
} else {
|
||||||
const digit = try std.fmt.charToDigit(c, 16);
|
const digit = try std.fmt.charToDigit(c, 16);
|
||||||
if (@mulWithOverflow(u16, x, 16, &x)) {
|
if (@mulWithOverflow(u16, x, 16, &x)) {
|
||||||
@ -113,21 +134,22 @@ pub const IpAddress = extern union {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!saw_any_digits) {
|
if (!saw_any_digits and !abbrv) {
|
||||||
return error.Incomplete;
|
return error.Incomplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope_id) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 14) {
|
if (index == 14) {
|
||||||
ip_slice[14] = @truncate(u8, x >> 8);
|
ip_slice[14] = @truncate(u8, x >> 8);
|
||||||
ip_slice[15] = @truncate(u8, x);
|
ip_slice[15] = @truncate(u8, x);
|
||||||
return result;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error.Incomplete;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseIp4(buf: []const u8, port: u16) !IpAddress {
|
pub fn parseIp4(buf: []const u8, port: u16) !IpAddress {
|
||||||
@ -246,10 +268,6 @@ pub const IpAddress = extern union {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
os.AF_INET6 => {
|
os.AF_INET6 => {
|
||||||
const ZeroRun = struct {
|
|
||||||
index: usize,
|
|
||||||
count: usize,
|
|
||||||
};
|
|
||||||
const port = mem.bigToNative(u16, self.in6.port);
|
const port = mem.bigToNative(u16, self.in6.port);
|
||||||
const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr);
|
const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr);
|
||||||
const native_endian_parts = switch (builtin.endian) {
|
const native_endian_parts = switch (builtin.endian) {
|
||||||
@ -262,44 +280,21 @@ pub const IpAddress = extern union {
|
|||||||
break :blk buf;
|
break :blk buf;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var longest_zero_run: ?ZeroRun = null;
|
|
||||||
var this_zero_run: ?ZeroRun = null;
|
|
||||||
for (native_endian_parts) |part, i| {
|
|
||||||
if (part == 0) {
|
|
||||||
if (this_zero_run) |*zr| {
|
|
||||||
zr.count += 1;
|
|
||||||
} else {
|
|
||||||
this_zero_run = ZeroRun{
|
|
||||||
.index = i,
|
|
||||||
.count = 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else if (this_zero_run) |zr| {
|
|
||||||
if (longest_zero_run) |lzr| {
|
|
||||||
if (zr.count > lzr.count and zr.count > 1) {
|
|
||||||
longest_zero_run = zr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
longest_zero_run = zr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try output(context, "[");
|
try output(context, "[");
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < native_endian_parts.len) {
|
var abbrv = false;
|
||||||
if (i != 0) try output(context, ":");
|
while (i < native_endian_parts.len) : (i += 1) {
|
||||||
|
if (native_endian_parts[i] == 0) {
|
||||||
if (longest_zero_run) |lzr| {
|
if (!abbrv) {
|
||||||
if (lzr.index == i) {
|
try output(context, if (i == 0) "::" else ":");
|
||||||
i += lzr.count;
|
abbrv = true;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
try std.fmt.format(context, Errors, output, "{x}", native_endian_parts[i]);
|
||||||
|
if (i != native_endian_parts.len - 1) {
|
||||||
|
try output(context, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
const part = native_endian_parts[i];
|
|
||||||
try std.fmt.format(context, Errors, output, "{x}", part);
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
try std.fmt.format(context, Errors, output, "]:{}", port);
|
try std.fmt.format(context, Errors, output, "]:{}", port);
|
||||||
},
|
},
|
||||||
@ -807,6 +802,7 @@ fn linuxLookupNameFromHosts(
|
|||||||
error.InvalidCharacter,
|
error.InvalidCharacter,
|
||||||
error.Incomplete,
|
error.Incomplete,
|
||||||
error.InvalidIPAddressFormat,
|
error.InvalidIPAddressFormat,
|
||||||
|
error.InvalidIpv4Mapping,
|
||||||
=> continue,
|
=> continue,
|
||||||
};
|
};
|
||||||
try addrs.append(LookupAddr{ .addr = addr });
|
try addrs.append(LookupAddr{ .addr = addr });
|
||||||
|
|||||||
@ -4,10 +4,41 @@ const mem = std.mem;
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
test "parse and render IPv6 addresses" {
|
test "parse and render IPv6 addresses" {
|
||||||
const addr = try net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
|
var buffer: [100]u8 = undefined;
|
||||||
var buf: [100]u8 = undefined;
|
const ips = [_][]const u8{
|
||||||
const printed = try std.fmt.bufPrint(&buf, "{}", addr);
|
"FF01:0:0:0:0:0:0:FB",
|
||||||
std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
|
"FF01::Fb",
|
||||||
|
"::1",
|
||||||
|
"::",
|
||||||
|
"2001:db8::",
|
||||||
|
"::1234:5678",
|
||||||
|
"2001:db8::1234:5678",
|
||||||
|
"FF01::FB%1234",
|
||||||
|
"::ffff:123.123.123.123",
|
||||||
|
};
|
||||||
|
const printed = [_][]const u8{
|
||||||
|
"ff01::fb",
|
||||||
|
"ff01::fb",
|
||||||
|
"::1",
|
||||||
|
"::",
|
||||||
|
"2001:db8::",
|
||||||
|
"::1234:5678",
|
||||||
|
"2001:db8::1234:5678",
|
||||||
|
"ff01::fb",
|
||||||
|
"::ffff:7b7b:7b7b",
|
||||||
|
};
|
||||||
|
for (ips) |ip, i| {
|
||||||
|
var addr = net.IpAddress.parseIp6(ip, 0) catch unreachable;
|
||||||
|
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
|
||||||
|
std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp6(":::", 0));
|
||||||
|
testing.expectError(error.Overflow, net.IpAddress.parseIp6("FF001::FB", 0));
|
||||||
|
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp6("FF01::Fb:zig", 0));
|
||||||
|
testing.expectError(error.InvalidEnd, net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB:", 0));
|
||||||
|
testing.expectError(error.Incomplete, net.IpAddress.parseIp6("FF01:", 0));
|
||||||
|
testing.expectError(error.InvalidIpv4Mapping, net.IpAddress.parseIp6("::123.123.123.123", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "parse and render IPv4 addresses" {
|
test "parse and render IPv4 addresses" {
|
||||||
@ -19,7 +50,7 @@ test "parse and render IPv4 addresses" {
|
|||||||
"123.255.0.91",
|
"123.255.0.91",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
}) |ip| {
|
}) |ip| {
|
||||||
var addr = net.IpAddress.parseIp4(ip, 0);
|
var addr = net.IpAddress.parseIp4(ip, 0) catch unreachable;
|
||||||
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
|
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
|
||||||
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
|
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user