authorgravatar for kenta@lithdew.netlithdew <kenta@lithdew.net> 2021-05-02 18:51:32+09:00
committergravatar for kenta@lithdew.netlithdew <kenta@lithdew.net> 2021-05-03 14:49:10+09:00
log5c4fbc40140ec6e30aa2954c13a5799b40e7afe4
tree8aa125ffdc48bae56af9397f62370203656fe871
parentcc6714a92923075d32adc44ade226ededc5da7db

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.

3 files changed, 67 insertions(+), 57 deletions(-)

lib/std/x.zig+1
......@@ -12,6 +12,7 @@ pub const os = struct {
1212};
1313
1414pub const net = struct {
15 pub const ip = @import("x/net/ip.zig");
1516 pub const tcp = @import("x/net/tcp.zig");
1617};
1718
lib/std/x/net/ip.zig created+52
......@@ -0,0 +1,52 @@
1const std = @import("../../std.zig");
2
3const IPv4 = std.x.os.IPv4;
4const IPv6 = std.x.os.IPv6;
5const Socket = std.x.os.Socket;
6
7const ip = @This();
8
9/// A union of all eligible types of IP addresses.
10pub const Address = union(enum) {
11 ipv4: IPv4.Address,
12 ipv6: IPv6.Address,
13
14 /// Instantiate a new address with a IPv4 host and port.
15 pub fn initIPv4(host: IPv4, port: u16) Address {
16 return .{ .ipv4 = .{ .host = host, .port = port } };
17 }
18
19 /// Instantiate a new address with a IPv6 host and port.
20 pub fn initIPv6(host: IPv6, port: u16) Address {
21 return .{ .ipv6 = .{ .host = host, .port = port } };
22 }
23
24 /// Re-interpret a generic socket address into an IP address.
25 pub fn from(address: Socket.Address) ip.Address {
26 return switch (address) {
27 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
28 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
29 };
30 }
31
32 /// Re-interpret an IP address into a generic socket address.
33 pub fn into(self: ip.Address) Socket.Address {
34 return switch (self) {
35 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
36 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
37 };
38 }
39
40 /// Implements the `std.fmt.format` API.
41 pub fn format(
42 self: ip.Address,
43 comptime layout: []const u8,
44 opts: fmt.FormatOptions,
45 writer: anytype,
46 ) !void {
47 switch (self) {
48 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
49 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
50 }
51 }
52};
lib/std/x/net/tcp.zig+14-57
......@@ -7,6 +7,8 @@
77const std = @import("../../std.zig");
88
99const os = std.os;
10const ip = std.x.net.ip;
11
1012const fmt = std.fmt;
1113const mem = std.mem;
1214const builtin = std.builtin;
......@@ -19,61 +21,16 @@ const Socket = std.x.os.Socket;
1921/// A generic TCP socket abstraction.
2022const tcp = @This();
2123
22/// A union of all eligible types of socket addresses over TCP.
23pub const Address = union(enum) {
24 ipv4: IPv4.Address,
25 ipv6: IPv6.Address,
26
27 /// Instantiate a new address with a IPv4 host and port.
28 pub fn initIPv4(host: IPv4, port: u16) Address {
29 return .{ .ipv4 = .{ .host = host, .port = port } };
30 }
31
32 /// Instantiate a new address with a IPv6 host and port.
33 pub fn initIPv6(host: IPv6, port: u16) Address {
34 return .{ .ipv6 = .{ .host = host, .port = port } };
35 }
36
37 /// Re-interpret a generic socket address into a TCP socket address.
38 pub fn from(address: Socket.Address) tcp.Address {
39 return switch (address) {
40 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
41 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
42 };
43 }
44
45 /// Re-interpret a TCP socket address into a generic socket address.
46 pub fn into(self: tcp.Address) Socket.Address {
47 return switch (self) {
48 .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
49 .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
50 };
51 }
52
53 /// Implements the `std.fmt.format` API.
54 pub fn format(
55 self: tcp.Address,
56 comptime layout: []const u8,
57 opts: fmt.FormatOptions,
58 writer: anytype,
59 ) !void {
60 switch (self) {
61 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
62 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
63 }
64 }
65};
66
6724/// A TCP client-address pair.
6825pub const Connection = struct {
6926 client: tcp.Client,
70 address: tcp.Address,
27 address: ip.Address,
7128
7229 /// Enclose a TCP client and address into a client-address pair.
7330 pub fn from(conn: Socket.Connection) tcp.Connection {
7431 return .{
7532 .client = tcp.Client.from(conn.socket),
76 .address = tcp.Address.from(conn.address),
33 .address = ip.Address.from(conn.address),
7734 };
7835 }
7936
......@@ -128,7 +85,7 @@ pub const Client = struct {
12885 }
12986
13087 /// Have the client attempt to the connect to an address.
131 pub fn connect(self: Client, address: tcp.Address) !void {
88 pub fn connect(self: Client, address: ip.Address) !void {
13289 return self.socket.connect(address.into());
13390 }
13491
......@@ -185,8 +142,8 @@ pub const Client = struct {
185142 }
186143
187144 /// Query the address that the client's socket is locally bounded to.
188 pub fn getLocalAddress(self: Client) !tcp.Address {
189 return tcp.Address.from(try self.socket.getLocalAddress());
145 pub fn getLocalAddress(self: Client) !ip.Address {
146 return ip.Address.from(try self.socket.getLocalAddress());
190147 }
191148
192149 /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
......@@ -253,7 +210,7 @@ pub const Listener = struct {
253210 }
254211
255212 /// Binds the listener's socket to an address.
256 pub fn bind(self: Listener, address: tcp.Address) !void {
213 pub fn bind(self: Listener, address: ip.Address) !void {
257214 return self.socket.bind(address.into());
258215 }
259216
......@@ -274,8 +231,8 @@ pub const Listener = struct {
274231 }
275232
276233 /// Query the address that the listener's socket is locally bounded to.
277 pub fn getLocalAddress(self: Listener) !tcp.Address {
278 return tcp.Address.from(try self.socket.getLocalAddress());
234 pub fn getLocalAddress(self: Listener) !ip.Address {
235 return ip.Address.from(try self.socket.getLocalAddress());
279236 }
280237
281238 /// 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" {
322279 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
323280 defer listener.deinit();
324281
325 try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
282 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
326283 try listener.listen(128);
327284
328285 const binded_address = try listener.getLocalAddress();
......@@ -342,7 +299,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {
342299 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
343300 defer listener.deinit();
344301
345 try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
302 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
346303 try listener.listen(128);
347304
348305 const binded_address = try listener.getLocalAddress();
......@@ -366,7 +323,7 @@ test "tcp/listener: bind to unspecified ipv4 address" {
366323 const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
367324 defer listener.deinit();
368325
369 try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
326 try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
370327 try listener.listen(128);
371328
372329 const address = try listener.getLocalAddress();
......@@ -379,7 +336,7 @@ test "tcp/listener: bind to unspecified ipv6 address" {
379336 const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
380337 defer listener.deinit();
381338
382 try listener.bind(tcp.Address.initIPv6(IPv6.unspecified, 0));
339 try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0));
383340 try listener.listen(128);
384341
385342 const address = try listener.getLocalAddress();