make std.net more portable

* Delete `std.net.TmpWinAddr`. I don't think that was ever meant to
   be a real thing.
 * Delete `std.net.OsAddress`. This abstraction was not helpful.
 * Rename `std.net.Address` to `std.net.IpAddress`. It is now an extern
   union of IPv4 and IPv6 addresses.
 * Move `std.net.parseIp4` and `std.net.parseIp6` to the
   `std.net.IpAddress` namespace. They now return `IpAddress` instead of
   `u32` and `std.net.Ip6Addr`, which is deleted.
 * Add `std.net.IpAddress.parse` which accepts a port and parses either
   an IPv4 or IPv6 address.
 * Add `std.net.IpAddress.parseExpectingFamily` which additionally
   accepts a `family` parameter.
 * `std.net.IpAddress.initIp4` and `std.net.IpAddress.initIp6` are
   improved to directly take the address fields instead of a weird
   in-between type.
 * `std.net.IpAddress.port` is renamed to `std.net.IpAddress.getPort`.
 * Added `std.net.IpAddress.setPort`.
 * `os.sockaddr` struct on all targets is improved to match the
   corresponding system struct. Previously I had made it a union of
   sockaddr_in, sockaddr_in6, and sockaddr_un. The new abstraction for
   this is now `std.net.IpAddress`.
 * `os.sockaddr` and related bits are added for Windows.
 * `os.sockaddr` and related bits now have the `zero` fields default
   to zero initialization, and `len` fields default to the correct size.
   This is enough to abstract the differences across targets, and so
   no more switch on the target OS is needed in `std.net.IpAddress`.
 * Add the missing `os.sockaddr_un` on FreeBSD and NetBSD.
 * `std.net.IpAddress.initPosix` now takes a pointer to `os.sockaddr`.
This commit is contained in:
Andrew Kelley 2019-10-30 19:27:42 -04:00
parent 618ee5b63a
commit 0de862e8ba
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
10 changed files with 468 additions and 429 deletions

View File

@ -99,7 +99,7 @@ pub const Allocator = struct {
/// memory is no longer needed, to avoid a resource leak. If the
/// `Allocator` implementation is unknown, then correct code will
/// call `free` when done.
///
///
/// For allocating a single item, see `create`.
pub fn alloc(self: *Allocator, comptime T: type, n: usize) Error![]T {
return self.alignedAlloc(T, null, n);

File diff suppressed because it is too large Load Diff

View File

@ -3,44 +3,32 @@ const net = std.net;
const mem = std.mem;
const testing = std.testing;
test "parseIp4" {
testing.expect((try net.parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));
testParseIp4Fail("256.0.0.1", error.Overflow);
testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
testParseIp4Fail("127.0.0.", error.Incomplete);
testParseIp4Fail("100..0.1", error.InvalidCharacter);
}
fn testParseIp4Fail(buf: []const u8, expected_err: anyerror) void {
if (net.parseIp4(buf)) |_| {
@panic("expected error");
} else |e| {
testing.expect(e == expected_err);
}
}
test "parseIp6" {
const ip6 = try net.parseIp6("FF01:0:0:0:0:0:0:FB");
const addr = net.Address.initIp6(ip6, 80);
test "parse and render IPv6 addresses" {
const addr = net.IpAddress.parseIp6("FF01:0:0:0:0:0:0:FB", 80);
var buf: [100]u8 = undefined;
const printed = try std.fmt.bufPrint(&buf, "{}", addr);
std.testing.expect(mem.eql(u8, "[ff01::fb]:80", printed));
}
test "ip4s" {
test "parse and render IPv4 addresses" {
var buffer: [18]u8 = undefined;
for ([_][]const u8{
"0.0.0.0",
"255.255.255.255",
"1.2.3.4",
"123.255.0.91",
"127.0.0.1",
}) |ip| {
var addr = net.Address.initIp4(net.parseIp4(ip) catch unreachable, 0);
var addr = net.IpAddress.parseIp4(ip, 0);
var newIp = std.fmt.bufPrint(buffer[0..], "{}", addr) catch unreachable;
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
}
testing.expectError(error.Overflow, net.IpAddress.parseIp4("256.0.0.1", 0));
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("x.0.0.1", 0));
testing.expectError(error.InvalidEnd, net.IpAddress.parseIp4("127.0.0.1.1", 0));
testing.expectError(error.Incomplete, net.IpAddress.parseIp4("127.0.0.", 0));
testing.expectError(error.InvalidCharacter, net.IpAddress.parseIp4("100..0.1", 0));
}
test "resolve DNS" {
@ -72,7 +60,7 @@ test "listen on a port, send bytes, receive bytes" {
}
// TODO doing this at comptime crashed the compiler
const localhost = net.Address.initIp4(net.parseIp4("127.0.0.1") catch unreachable, 0);
const localhost = net.IpAddress.parse("127.0.0.1", 0);
var server = net.TcpServer.init(net.TcpServer.Options{});
defer server.deinit();
@ -85,7 +73,7 @@ test "listen on a port, send bytes, receive bytes" {
try await client_frame;
}
fn testClient(addr: net.Address) anyerror!void {
fn testClient(addr: net.IpAddress) anyerror!void {
const socket_file = try net.tcpConnectToAddress(addr);
defer socket_file.close();

View File

@ -1920,9 +1920,9 @@ pub const ConnectError = error{
} || UnexpectedError;
/// Initiate a connection on a socket.
pub fn connect(sockfd: fd_t, sock_addr: sockaddr, len: socklen_t) ConnectError!void {
pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
while (true) {
switch (errno(system.connect(sockfd, &sock_addr, len))) {
switch (errno(system.connect(sockfd, sock_addr, len))) {
0 => return,
EACCES => return error.PermissionDenied,
EPERM => return error.PermissionDenied,

View File

@ -9,28 +9,31 @@ pub const in_port_t = u16;
pub const sa_family_t = u8;
pub const socklen_t = u32;
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
un: sockaddr_un,
len: u8,
family: sa_family_t,
data: [14]u8,
};
pub const sockaddr_in = extern struct {
len: u8,
family: sa_family_t,
len: u8 = @sizeOf(sockaddr_in),
family: sa_family_t = AF_INET,
port: in_port_t,
addr: u32,
zero: [8]u8,
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
len: u8,
family: sa_family_t,
len: u8 = @sizeOf(sockaddr_in6),
family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
/// UNIX domain socket
pub const sockaddr_un = extern struct {
len: u8,
family: sa_family_t,
len: u8 = @sizeOf(sockaddr_un),
family: sa_family_t = AF_UNIX,
path: [104]u8,
};
pub const timeval = extern struct {

View File

@ -138,27 +138,39 @@ pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
/// total length
len: u8,
/// address family
family: sa_family_t,
/// actually longer; address value
data: [14]u8,
};
pub const sockaddr_in = extern struct {
len: u8,
family: sa_family_t,
len: u8 = @sizeOf(sockaddr_in),
family: sa_family_t = AF_INET,
port: in_port_t,
addr: [16]u8,
zero: [8]u8,
addr: u32,
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
len: u8,
family: sa_family_t,
len: u8 = @sizeOf(sockaddr_in6),
family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
pub const sockaddr_un = extern struct {
len: u8 = @sizeOf(sockaddr_un),
family: sa_family_t = AF_UNIX,
path: [104]u8,
};
pub const CTL_KERN = 1;
pub const CTL_DEBUG = 5;

View File

@ -846,30 +846,31 @@ pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const socklen_t = u32;
/// This intentionally only has ip4 and ip6
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
un: sockaddr_un,
family: sa_family_t,
data: [14]u8,
};
/// IPv4 socket address
pub const sockaddr_in = extern struct {
family: sa_family_t,
family: sa_family_t = AF_INET,
port: in_port_t,
addr: u32,
zero: [8]u8,
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
/// IPv6 socket address
pub const sockaddr_in6 = extern struct {
family: sa_family_t,
family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};
/// UNIX domain socket address
pub const sockaddr_un = extern struct {
family: sa_family_t,
family: sa_family_t = AF_UNIX,
path: [108]u8,
};

View File

@ -134,20 +134,26 @@ pub const in_port_t = u16;
pub const sa_family_t = u8;
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
/// total length
len: u8,
/// address family
family: sa_family_t,
/// actually longer; address value
data: [14]u8,
};
pub const sockaddr_in = extern struct {
len: u8,
len: u8 = @sizeOf(sockaddr_in),
family: sa_family_t,
port: in_port_t,
addr: u32,
zero: [8]u8,
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
len: u8,
len: u8 = @sizeOf(sockaddr_in6),
family: sa_family_t,
port: in_port_t,
flowinfo: u32,
@ -155,6 +161,18 @@ pub const sockaddr_in6 = extern struct {
scope_id: u32,
};
/// Definitions for UNIX IPC domain.
pub const sockaddr_un = extern struct {
/// total sockaddr length
len: u8 = @sizeOf(sockaddr_un),
/// AF_LOCAL
family: sa_family_t,
/// path name
path: [104]u8,
};
pub const CTL_KERN = 1;
pub const CTL_DEBUG = 5;

View File

@ -161,3 +161,63 @@ pub const F_OK = 0;
/// Remove directory instead of unlinking file
pub const AT_REMOVEDIR = 0x200;
pub const in_port_t = u16;
pub const sa_family_t = u16;
pub const socklen_t = u32;
pub const sockaddr = extern struct {
family: sa_family_t,
data: [14]u8,
};
pub const sockaddr_in = extern struct {
family: sa_family_t = AF_INET,
port: in_port_t,
addr: in_addr,
zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
pub const sockaddr_in6 = extern struct {
family: sa_family_t = AF_INET6,
port: in_port_t,
flowinfo: u32,
addr: in6_addr,
scope_id: u32,
};
pub const in6_addr = [16]u8;
pub const in_addr = u32;
pub const AF_UNSPEC = 0;
pub const AF_UNIX = 1;
pub const AF_INET = 2;
pub const AF_IMPLINK = 3;
pub const AF_PUP = 4;
pub const AF_CHAOS = 5;
pub const AF_NS = 6;
pub const AF_IPX = AF_NS;
pub const AF_ISO = 7;
pub const AF_OSI = AF_ISO;
pub const AF_ECMA = 8;
pub const AF_DATAKIT = 9;
pub const AF_CCITT = 10;
pub const AF_SNA = 11;
pub const AF_DECnet = 12;
pub const AF_DLI = 13;
pub const AF_LAT = 14;
pub const AF_HYLINK = 15;
pub const AF_APPLETALK = 16;
pub const AF_NETBIOS = 17;
pub const AF_VOICEVIEW = 18;
pub const AF_FIREFOX = 19;
pub const AF_UNKNOWN1 = 20;
pub const AF_BAN = 21;
pub const AF_ATM = 22;
pub const AF_INET6 = 23;
pub const AF_CLUSTER = 24;
pub const AF_12844 = 25;
pub const AF_IRDA = 26;
pub const AF_NETDES = 28;
pub const AF_TCNPROCESS = 29;
pub const AF_TCNMESSAGE = 30;
pub const AF_ICLFXBM = 31;
pub const AF_BTH = 32;
pub const AF_MAX = 33;

View File

@ -162,9 +162,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ const obj = AstObject{ .lhsExpr = lhsExpr };
\\}
,
"tmp.zig:1:17: error: struct 'LhsExpr' depends on itself",
"tmp.zig:5:5: note: while checking this field",
"tmp.zig:4:19: error: union 'AstObject' depends on itself",
"tmp.zig:2:5: note: while checking this field",
"tmp.zig:5:5: note: while checking this field",
);
cases.add(