Commit 90a19f7411
lib/std/net/test.zig
@@ -4,6 +4,28 @@ const net = std.net;
const mem = std.mem;
const testing = std.testing;
+test "parse and render IP addresses at comptime" {
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+ comptime {
+ var ipAddrBuffer: [16]u8 = undefined;
+ // Parses IPv6 at comptime
+ const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable;
+ var ipv6 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv6addr}) catch unreachable;
+ try std.testing.expect(std.mem.eql(u8, "::1", ipv6[1 .. ipv6.len - 3]));
+
+ // Parses IPv4 at comptime
+ const ipv4addr = net.Address.parseIp("127.0.0.1", 0) catch unreachable;
+ var ipv4 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv4addr}) catch unreachable;
+ try std.testing.expect(std.mem.eql(u8, "127.0.0.1", ipv4[0 .. ipv4.len - 2]));
+
+ // Returns error for invalid IP addresses at comptime
+ try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("::123.123.123.123", 0));
+ try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("127.01.0.1", 0));
+ try testing.expectError(error.InvalidIPAddressFormat, net.Address.resolveIp("::123.123.123.123", 0));
+ try testing.expectError(error.InvalidIPAddressFormat, net.Address.resolveIp("127.01.0.1", 0));
+ }
+}
+
test "parse and render IPv6 addresses" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
lib/std/net.zig
@@ -14,6 +14,19 @@ pub const has_unix_sockets = @hasDecl(os.sockaddr, "un") and
(builtin.target.os.tag != .windows or
builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false);
+pub const IPParseError = error{
+ Overflow,
+ InvalidEnd,
+ InvalidCharacter,
+ Incomplete,
+};
+
+pub const IPv4ParseError = IPParseError || error{NonCanonical};
+
+pub const IPv6ParseError = IPParseError || error{InvalidIpv4Mapping};
+pub const IPv6InterfaceError = os.SocketError || os.IoCtl_SIOCGIFINDEX_Error || error{NameTooLong};
+pub const IPv6ResolveError = IPv6ParseError || IPv6InterfaceError;
+
pub const Address = extern union {
any: os.sockaddr,
in: Ip4Address,
@@ -77,15 +90,15 @@ pub const Address = extern union {
}
}
- pub fn parseIp6(buf: []const u8, port: u16) !Address {
+ pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
return Address{ .in6 = try Ip6Address.parse(buf, port) };
}
- pub fn resolveIp6(buf: []const u8, port: u16) !Address {
+ pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
return Address{ .in6 = try Ip6Address.resolve(buf, port) };
}
- pub fn parseIp4(buf: []const u8, port: u16) !Address {
+ pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
return Address{ .in = try Ip4Address.parse(buf, port) };
}
@@ -198,7 +211,7 @@ pub const Address = extern union {
pub const Ip4Address = extern struct {
sa: os.sockaddr.in,
- pub fn parse(buf: []const u8, port: u16) !Ip4Address {
+ pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {
var result = Ip4Address{
.sa = .{
.port = mem.nativeToBig(u16, port),
@@ -307,7 +320,7 @@ pub const Ip6Address = extern struct {
/// Parse a given IPv6 address string into an Address.
/// Assumes the Scope ID of the address is fully numeric.
/// For non-numeric addresses, see `resolveIp6`.
- pub fn parse(buf: []const u8, port: u16) !Ip6Address {
+ pub fn parse(buf: []const u8, port: u16) IPv6ParseError!Ip6Address {
var result = Ip6Address{
.sa = os.sockaddr.in6{
.scope_id = 0,
@@ -424,7 +437,7 @@ pub const Ip6Address = extern struct {
}
}
- pub fn resolve(buf: []const u8, port: u16) !Ip6Address {
+ pub fn resolve(buf: []const u8, port: u16) IPv6ResolveError!Ip6Address {
// TODO: Unify the implementations of resolveIp6 and parseIp6.
var result = Ip6Address{
.sa = os.sockaddr.in6{
@@ -659,7 +672,7 @@ pub fn connectUnixSocket(path: []const u8) !Stream {
};
}
-fn if_nametoindex(name: []const u8) !u32 {
+fn if_nametoindex(name: []const u8) IPv6InterfaceError!u32 {
if (builtin.target.os.tag == .linux) {
var ifr: os.ifreq = undefined;
const sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0);