x/net: generalize tcp.Address into ip.Address

Generalize `tcp.Address` into `ip.Address` given that multiple transport
protocols apart from TCP (i.e. UDP) operate solely over IP.
This commit is contained in:
lithdew 2021-05-02 18:51:32 +09:00
parent cc6714a929
commit 5c4fbc4014
3 changed files with 67 additions and 57 deletions

View File

@ -12,6 +12,7 @@ pub const os = struct {
};
pub const net = struct {
pub const ip = @import("x/net/ip.zig");
pub const tcp = @import("x/net/tcp.zig");
};

52
lib/std/x/net/ip.zig Normal file
View File

@ -0,0 +1,52 @@
const std = @import("../../std.zig");
const IPv4 = std.x.os.IPv4;
const IPv6 = std.x.os.IPv6;
const Socket = std.x.os.Socket;
const ip = @This();
/// A union of all eligible types of IP addresses.
pub const Address = union(enum) {
ipv4: IPv4.Address,
ipv6: IPv6.Address,
/// Instantiate a new address with a IPv4 host and port.
pub fn initIPv4(host: IPv4, port: u16) Address {
return .{ .ipv4 = .{ .host = host, .port = port } };
}
/// Instantiate a new address with a IPv6 host and port.
pub fn initIPv6(host: IPv6, port: u16) Address {
return .{ .ipv6 = .{ .host = host, .port = port } };
}
/// Re-interpret a generic socket address into an IP address.
pub fn from(address: Socket.Address) ip.Address {
return switch (address) {
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
};
}
/// Re-interpret an IP address into a generic socket address.
pub fn into(self: ip.Address) Socket.Address {
return switch (self) {
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
};
}
/// Implements the `std.fmt.format` API.
pub fn format(
self: ip.Address,
comptime layout: []const u8,
opts: fmt.FormatOptions,
writer: anytype,
) !void {
switch (self) {
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
}
}
};

View File

@ -7,6 +7,8 @@
const std = @import("../../std.zig");
const os = std.os;
const ip = std.x.net.ip;
const fmt = std.fmt;
const mem = std.mem;
const builtin = std.builtin;
@ -19,61 +21,16 @@ const Socket = std.x.os.Socket;
/// A generic TCP socket abstraction.
const tcp = @This();
/// A union of all eligible types of socket addresses over TCP.
pub const Address = union(enum) {
ipv4: IPv4.Address,
ipv6: IPv6.Address,
/// Instantiate a new address with a IPv4 host and port.
pub fn initIPv4(host: IPv4, port: u16) Address {
return .{ .ipv4 = .{ .host = host, .port = port } };
}
/// Instantiate a new address with a IPv6 host and port.
pub fn initIPv6(host: IPv6, port: u16) Address {
return .{ .ipv6 = .{ .host = host, .port = port } };
}
/// Re-interpret a generic socket address into a TCP socket address.
pub fn from(address: Socket.Address) tcp.Address {
return switch (address) {
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
};
}
/// Re-interpret a TCP socket address into a generic socket address.
pub fn into(self: tcp.Address) Socket.Address {
return switch (self) {
.ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
.ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
};
}
/// Implements the `std.fmt.format` API.
pub fn format(
self: tcp.Address,
comptime layout: []const u8,
opts: fmt.FormatOptions,
writer: anytype,
) !void {
switch (self) {
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
}
}
};
/// A TCP client-address pair.
pub const Connection = struct {
client: tcp.Client,
address: tcp.Address,
address: ip.Address,
/// Enclose a TCP client and address into a client-address pair.
pub fn from(conn: Socket.Connection) tcp.Connection {
return .{
.client = tcp.Client.from(conn.socket),
.address = tcp.Address.from(conn.address),
.address = ip.Address.from(conn.address),
};
}
@ -128,7 +85,7 @@ pub const Client = struct {
}
/// Have the client attempt to the connect to an address.
pub fn connect(self: Client, address: tcp.Address) !void {
pub fn connect(self: Client, address: ip.Address) !void {
return self.socket.connect(address.into());
}
@ -185,8 +142,8 @@ pub const Client = struct {
}
/// Query the address that the client's socket is locally bounded to.
pub fn getLocalAddress(self: Client) !tcp.Address {
return tcp.Address.from(try self.socket.getLocalAddress());
pub fn getLocalAddress(self: Client) !ip.Address {
return ip.Address.from(try self.socket.getLocalAddress());
}
/// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
@ -253,7 +210,7 @@ pub const Listener = struct {
}
/// Binds the listener's socket to an address.
pub fn bind(self: Listener, address: tcp.Address) !void {
pub fn bind(self: Listener, address: ip.Address) !void {
return self.socket.bind(address.into());
}
@ -274,8 +231,8 @@ pub const Listener = struct {
}
/// Query the address that the listener's socket is locally bounded to.
pub fn getLocalAddress(self: Listener) !tcp.Address {
return tcp.Address.from(try self.socket.getLocalAddress());
pub fn getLocalAddress(self: Listener) !ip.Address {
return ip.Address.from(try self.socket.getLocalAddress());
}
/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
@ -322,7 +279,7 @@ test "tcp: create client/listener pair" {
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
defer listener.deinit();
try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
try listener.listen(128);
const binded_address = try listener.getLocalAddress();
@ -342,7 +299,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
defer listener.deinit();
try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
try listener.listen(128);
const binded_address = try listener.getLocalAddress();
@ -366,7 +323,7 @@ test "tcp/listener: bind to unspecified ipv4 address" {
const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
defer listener.deinit();
try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
try listener.listen(128);
const address = try listener.getLocalAddress();
@ -379,7 +336,7 @@ test "tcp/listener: bind to unspecified ipv6 address" {
const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
defer listener.deinit();
try listener.bind(tcp.Address.initIPv6(IPv6.unspecified, 0));
try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0));
try listener.listen(128);
const address = try listener.getLocalAddress();