mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-07 06:14:33 +00:00
std.net: add explicit error sets for IP parsing
Inferred errors in switch statements prevented IP address parsing at comptime. Adding explicit error sets fixes it. Closes #18276
This commit is contained in:
parent
779b8e2598
commit
90a19f7411
2 changed files with 42 additions and 7 deletions
|
|
@ -14,6 +14,19 @@ pub const has_unix_sockets = @hasDecl(os.sockaddr, "un") and
|
||||||
(builtin.target.os.tag != .windows or
|
(builtin.target.os.tag != .windows or
|
||||||
builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false);
|
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 {
|
pub const Address = extern union {
|
||||||
any: os.sockaddr,
|
any: os.sockaddr,
|
||||||
in: Ip4Address,
|
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) };
|
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) };
|
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) };
|
return Address{ .in = try Ip4Address.parse(buf, port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,7 +211,7 @@ pub const Address = extern union {
|
||||||
pub const Ip4Address = extern struct {
|
pub const Ip4Address = extern struct {
|
||||||
sa: os.sockaddr.in,
|
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{
|
var result = Ip4Address{
|
||||||
.sa = .{
|
.sa = .{
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
|
|
@ -307,7 +320,7 @@ pub const Ip6Address = extern struct {
|
||||||
/// Parse a given IPv6 address string into an Address.
|
/// Parse a given IPv6 address string into an Address.
|
||||||
/// Assumes the Scope ID of the address is fully numeric.
|
/// Assumes the Scope ID of the address is fully numeric.
|
||||||
/// For non-numeric addresses, see `resolveIp6`.
|
/// 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{
|
var result = Ip6Address{
|
||||||
.sa = os.sockaddr.in6{
|
.sa = os.sockaddr.in6{
|
||||||
.scope_id = 0,
|
.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.
|
// TODO: Unify the implementations of resolveIp6 and parseIp6.
|
||||||
var result = Ip6Address{
|
var result = Ip6Address{
|
||||||
.sa = os.sockaddr.in6{
|
.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) {
|
if (builtin.target.os.tag == .linux) {
|
||||||
var ifr: os.ifreq = undefined;
|
var ifr: os.ifreq = undefined;
|
||||||
const sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0);
|
const sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,28 @@ const net = std.net;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const testing = std.testing;
|
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" {
|
test "parse and render IPv6 addresses" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue