Commit 13068da43e
Changed files (7)
lib
std
lib/std/compress/deflate.zig
@@ -662,14 +662,12 @@ test "lengths overflow" {
// malformed final dynamic block, tries to write 321 code lengths (MAXCODES is 316)
// f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
// 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
- const stream = [_]u8{
- 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110
- };
+ const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
const reader = std.io.fixedBufferStream(&stream).reader();
var window: [0x8000]u8 = undefined;
var inflate = inflateStream(reader, &window);
var buf: [1]u8 = undefined;
- std.testing.expectError(error.InvalidLength, inflate.read(&buf));
+ std.testing.expectError(error.InvalidLength, inflate.read(&buf));
}
lib/std/os/bits/linux/arm64.zig
@@ -9,6 +9,7 @@
const std = @import("../../../std.zig");
const linux = std.os.linux;
const socklen_t = linux.socklen_t;
+const sockaddr = linux.sockaddr;
const iovec = linux.iovec;
const iovec_const = linux.iovec_const;
const uid_t = linux.uid_t;
lib/std/x/net/TCP.zig → lib/std/x/net/tcp.zig
@@ -1,3 +1,9 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2021 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+
const std = @import("../../std.zig");
const os = std.os;
@@ -10,20 +16,76 @@ const IPv6 = std.x.os.IPv6;
const Socket = std.x.os.Socket;
/// A generic TCP socket abstraction.
-const TCP = @This();
+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,
+ client: tcp.Client,
+ address: tcp.Address,
/// Enclose a TCP client and address into a client-address pair.
- pub fn from(socket: Socket, address: TCP.Address) Connection {
- return .{ .client = TCP.Client.from(socket), .address = address };
+ pub fn from(conn: Socket.Connection) tcp.Connection {
+ return .{
+ .client = tcp.Client.from(conn.socket),
+ .address = tcp.Address.from(conn.address),
+ };
+ }
+
+ /// Unravel a TCP client-address pair into a socket-address pair.
+ pub fn into(self: tcp.Connection) Socket.Connection {
+ return .{
+ .socket = self.client.socket,
+ .address = self.address.into(),
+ };
}
/// Closes the underlying client of the connection.
- pub fn deinit(self: TCP.Connection) void {
+ pub fn deinit(self: tcp.Connection) void {
self.client.deinit();
}
};
@@ -39,7 +101,7 @@ pub const Client = struct {
socket: Socket,
/// Opens a new client.
- pub fn init(domain: TCP.Domain, flags: u32) !Client {
+ pub fn init(domain: tcp.Domain, flags: u32) !Client {
return Client{
.socket = try Socket.init(
@enumToInt(domain),
@@ -65,8 +127,8 @@ pub const Client = struct {
}
/// Have the client attempt to the connect to an address.
- pub fn connect(self: Client, address: TCP.Address) !void {
- return self.socket.connect(TCP.Address, address);
+ pub fn connect(self: Client, address: tcp.Address) !void {
+ return self.socket.connect(address.into());
}
/// Read data from the socket into the buffer provided. It returns the
@@ -122,8 +184,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 self.socket.getLocalAddress(TCP.Address);
+ pub fn getLocalAddress(self: Client) !tcp.Address {
+ return tcp.Address.from(try self.socket.getLocalAddress());
}
/// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
@@ -167,7 +229,7 @@ pub const Listener = struct {
socket: Socket,
/// Opens a new listener.
- pub fn init(domain: TCP.Domain, flags: u32) !Listener {
+ pub fn init(domain: tcp.Domain, flags: u32) !Listener {
return Listener{
.socket = try Socket.init(
@enumToInt(domain),
@@ -190,8 +252,8 @@ pub const Listener = struct {
}
/// Binds the listener's socket to an address.
- pub fn bind(self: Listener, address: TCP.Address) !void {
- return self.socket.bind(TCP.Address, address);
+ pub fn bind(self: Listener, address: tcp.Address) !void {
+ return self.socket.bind(address.into());
}
/// Start listening for incoming connections.
@@ -201,8 +263,8 @@ pub const Listener = struct {
/// Accept a pending incoming connection queued to the kernel backlog
/// of the listener's socket.
- pub fn accept(self: Listener, flags: u32) !TCP.Connection {
- return self.socket.accept(TCP.Connection, TCP.Address, flags);
+ pub fn accept(self: Listener, flags: u32) !tcp.Connection {
+ return tcp.Connection.from(try self.socket.accept(flags));
}
/// Query and return the latest cached error on the listener's underlying socket.
@@ -211,8 +273,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 self.socket.getLocalAddress(TCP.Address);
+ pub fn getLocalAddress(self: Listener) !tcp.Address {
+ return tcp.Address.from(try self.socket.getLocalAddress());
}
/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
@@ -253,147 +315,69 @@ pub const Listener = struct {
}
};
-/// A TCP socket address designated by a host IP and port. A TCP socket
-/// address comprises of 28 bytes. It may freely be used in place of
-/// `sockaddr` when working with socket syscalls.
-///
-/// It is not recommended to touch the fields of an `Address`, but to
-/// instead make use of its available accessor methods.
-pub const Address = extern struct {
- family: u16,
- port: u16,
- host: extern union {
- ipv4: extern struct {
- address: IPv4,
- },
- ipv6: extern struct {
- flow_info: u32 = 0,
- address: IPv6,
- },
- },
-
- /// Instantiate a new TCP address with a IPv4 host and port.
- pub fn initIPv4(host: IPv4, port: u16) Address {
- return Address{
- .family = os.AF_INET,
- .port = mem.nativeToBig(u16, port),
- .host = .{
- .ipv4 = .{
- .address = host,
- },
- },
- };
- }
-
- /// Instantiate a new TCP address with a IPv6 host and port.
- pub fn initIPv6(host: IPv6, port: u16) Address {
- return Address{
- .family = os.AF_INET6,
- .port = mem.nativeToBig(u16, port),
- .host = .{
- .ipv6 = .{
- .address = host,
- },
- },
- };
- }
-
- /// Extract the host of the address.
- pub fn getHost(self: Address) union(enum) { v4: IPv4, v6: IPv6 } {
- return switch (self.family) {
- os.AF_INET => .{ .v4 = self.host.ipv4.address },
- os.AF_INET6 => .{ .v6 = self.host.ipv6.address },
- else => unreachable,
- };
- }
-
- /// Extract the port of the address.
- pub fn getPort(self: Address) u16 {
- return mem.nativeToBig(u16, self.port);
- }
-
- /// Set the port of the address.
- pub fn setPort(self: *Address, port: u16) void {
- self.port = mem.nativeToBig(u16, port);
- }
-
- /// Implements the `std.fmt.format` API.
- pub fn format(
- self: Address,
- comptime layout: []const u8,
- opts: fmt.FormatOptions,
- writer: anytype,
- ) !void {
- switch (self.getHost()) {
- .v4 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }),
- .v6 => |host| try fmt.format(writer, "{}:{}", .{ host, self.getPort() }),
- }
- }
-};
-
test {
testing.refAllDecls(@This());
}
test "tcp: create non-blocking pair" {
- const a = try TCP.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
- defer a.deinit();
+ const listener = try tcp.Listener.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
+ defer listener.deinit();
- try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0));
- try a.listen(128);
+ try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
+ try listener.listen(128);
- const binded_address = try a.getLocalAddress();
+ const binded_address = try listener.getLocalAddress();
- const b = try TCP.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
- defer b.deinit();
+ const client = try tcp.Client.init(.ip, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
+ defer client.deinit();
- testing.expectError(error.WouldBlock, b.connect(binded_address));
- try b.getError();
+ testing.expectError(error.WouldBlock, client.connect(binded_address));
+ try client.getError();
- const ab = try a.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
- defer ab.deinit();
+ const conn = try listener.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC);
+ defer conn.deinit();
}
test "tcp/client: set read timeout of 1 millisecond on blocking client" {
- const a = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC);
- defer a.deinit();
+ const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
+ defer listener.deinit();
- try a.bind(TCP.Address.initIPv4(IPv4.unspecified, 0));
- try a.listen(128);
+ try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
+ try listener.listen(128);
- const binded_address = try a.getLocalAddress();
+ const binded_address = try listener.getLocalAddress();
- const b = try TCP.Client.init(.ip, os.SOCK_CLOEXEC);
- defer b.deinit();
+ const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
+ defer client.deinit();
- try b.connect(binded_address);
- try b.setReadTimeout(1);
+ try client.connect(binded_address);
+ try client.setReadTimeout(1);
- const ab = try a.accept(os.SOCK_CLOEXEC);
- defer ab.deinit();
+ const conn = try listener.accept(os.SOCK_CLOEXEC);
+ defer conn.deinit();
var buf: [1]u8 = undefined;
- testing.expectError(error.WouldBlock, b.read(&buf));
+ testing.expectError(error.WouldBlock, client.read(&buf));
}
test "tcp/listener: bind to unspecified ipv4 address" {
- const socket = try TCP.Listener.init(.ip, os.SOCK_CLOEXEC);
- defer socket.deinit();
+ const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
+ defer listener.deinit();
- try socket.bind(TCP.Address.initIPv4(IPv4.unspecified, 0));
- try socket.listen(128);
+ try listener.bind(tcp.Address.initIPv4(IPv4.unspecified, 0));
+ try listener.listen(128);
- const address = try socket.getLocalAddress();
- testing.expect(address.getHost() == .v4);
+ const address = try listener.getLocalAddress();
+ testing.expect(address == .ipv4);
}
test "tcp/listener: bind to unspecified ipv6 address" {
- const socket = try TCP.Listener.init(.ipv6, os.SOCK_CLOEXEC);
- defer socket.deinit();
+ const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
+ defer listener.deinit();
- try socket.bind(TCP.Address.initIPv6(IPv6.unspecified, 0));
- try socket.listen(128);
+ try listener.bind(tcp.Address.initIPv6(IPv6.unspecified, 0));
+ try listener.listen(128);
- const address = try socket.getLocalAddress();
- testing.expect(address.getHost() == .v6);
+ const address = try listener.getLocalAddress();
+ testing.expect(address == .ipv6);
}
lib/std/x/os/net.zig
@@ -1,3 +1,9 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2021 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+
const std = @import("../../std.zig");
const os = std.os;
@@ -27,6 +33,12 @@ pub fn resolveScopeID(name: []const u8) !u32 {
/// An IPv4 address comprised of 4 bytes.
pub const IPv4 = extern struct {
+ /// A IPv4 host-port pair.
+ pub const Address = extern struct {
+ host: IPv4,
+ port: u16,
+ };
+
/// Octets of a IPv4 address designating the local host.
pub const localhost_octets = [_]u8{ 127, 0, 0, 1 };
@@ -200,6 +212,12 @@ pub const IPv4 = extern struct {
/// An IPv6 address comprised of 16 bytes for an address, and 4 bytes
/// for a scope ID; cumulatively summing to 20 bytes in total.
pub const IPv6 = extern struct {
+ /// A IPv6 host-port pair.
+ pub const Address = extern struct {
+ host: IPv6,
+ port: u16,
+ };
+
/// Octets of a IPv6 address designating the local host.
pub const localhost_octets = [_]u8{0} ** 15 ++ [_]u8{0x01};
lib/std/x/os/Socket.zig
@@ -1,4 +1,11 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2021 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+
const std = @import("../../std.zig");
+const net = @import("net.zig");
const os = std.os;
const mem = std.mem;
@@ -7,6 +14,98 @@ const time = std.time;
/// A generic socket abstraction.
const Socket = @This();
+/// A socket-address pair.
+pub const Connection = struct {
+ socket: Socket,
+ address: Socket.Address,
+
+ /// Enclose a socket and address into a socket-address pair.
+ pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
+ return .{ .socket = socket, .address = address };
+ }
+};
+
+/// A generic socket address abstraction. It is safe to directly access and modify
+/// the fields of a `Socket.Address`.
+pub const Address = union(enum) {
+ ipv4: net.IPv4.Address,
+ ipv6: net.IPv6.Address,
+
+ /// Instantiate a new address with a IPv4 host and port.
+ pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
+ return .{ .ipv4 = .{ .host = host, .port = port } };
+ }
+
+ /// Instantiate a new address with a IPv6 host and port.
+ pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
+ return .{ .ipv6 = .{ .host = host, .port = port } };
+ }
+
+ /// Parses a `sockaddr` into a generic socket address.
+ pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
+ switch (address.family) {
+ os.AF_INET => {
+ const info = @ptrCast(*const os.sockaddr_in, address);
+ const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
+ const port = mem.bigToNative(u16, info.port);
+ return Socket.Address.initIPv4(host, port);
+ },
+ os.AF_INET6 => {
+ const info = @ptrCast(*const os.sockaddr_in6, address);
+ const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
+ const port = mem.bigToNative(u16, info.port);
+ return Socket.Address.initIPv6(host, port);
+ },
+ else => unreachable,
+ }
+ }
+
+ /// Encodes a generic socket address into an extern union that may be reliably
+ /// casted into a `sockaddr` which may be passed into socket syscalls.
+ pub fn toNative(self: Socket.Address) extern union {
+ ipv4: os.sockaddr_in,
+ ipv6: os.sockaddr_in6,
+ } {
+ return switch (self) {
+ .ipv4 => |address| .{
+ .ipv4 = .{
+ .addr = @bitCast(u32, address.host.octets),
+ .port = mem.nativeToBig(u16, address.port),
+ },
+ },
+ .ipv6 => |address| .{
+ .ipv6 = .{
+ .addr = address.host.octets,
+ .port = mem.nativeToBig(u16, address.port),
+ .scope_id = address.host.scope_id,
+ .flowinfo = 0,
+ },
+ },
+ };
+ }
+
+ /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
+ pub fn getNativeSize(self: Socket.Address) u32 {
+ return switch (self) {
+ .ipv4 => @sizeOf(os.sockaddr_in),
+ .ipv6 => @sizeOf(os.sockaddr_in6),
+ };
+ }
+
+ /// Implements the `std.fmt.format` API.
+ pub fn format(
+ self: Socket.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 }),
+ }
+ }
+};
+
/// The underlying handle of a socket.
fd: os.socket_t,
@@ -31,8 +130,8 @@ pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
}
/// Binds the socket to an address.
-pub fn bind(self: Socket, comptime Address: type, address: Address) !void {
- return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address));
+pub fn bind(self: Socket, address: Socket.Address) !void {
+ return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
}
/// Start listening for incoming connections on the socket.
@@ -41,19 +140,20 @@ pub fn listen(self: Socket, max_backlog_size: u31) !void {
}
/// Have the socket attempt to the connect to an address.
-pub fn connect(self: Socket, comptime Address: type, address: Address) !void {
- return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address), @sizeOf(Address));
+pub fn connect(self: Socket, address: Socket.Address) !void {
+ return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
}
/// Accept a pending incoming connection queued to the kernel backlog
/// of the socket.
-pub fn accept(self: Socket, comptime Connection: type, comptime Address: type, flags: u32) !Connection {
- var address: Address = undefined;
- var address_len: u32 = @sizeOf(Address);
+pub fn accept(self: Socket, flags: u32) !Socket.Connection {
+ var address: os.sockaddr = undefined;
+ var address_len: u32 = @sizeOf(os.sockaddr);
- const fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags);
+ const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) };
+ const socket_address = Socket.Address.fromNative(@alignCast(4, &address));
- return Connection.from(.{ .fd = fd }, address);
+ return Socket.Connection.from(socket, socket_address);
}
/// Read data from the socket into the buffer provided. It returns the
@@ -94,11 +194,11 @@ pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
}
/// Query the address that the socket is locally bounded to.
-pub fn getLocalAddress(self: Socket, comptime Address: type) !Address {
- var address: Address = undefined;
- var address_len: u32 = @sizeOf(Address);
- try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
- return address;
+pub fn getLocalAddress(self: Socket) !Socket.Address {
+ var address: os.sockaddr = undefined;
+ var address_len: u32 = @sizeOf(os.sockaddr);
+ try os.getsockname(self.fd, &address, &address_len);
+ return Socket.Address.fromNative(@alignCast(4, &address));
}
/// Query and return the latest cached error on the socket.
lib/std/builtin.zig
@@ -150,23 +150,7 @@ pub const Mode = enum {
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
-pub const CallingConvention = enum {
- Unspecified,
- C,
- Naked,
- Async,
- Inline,
- Interrupt,
- Signal,
- Stdcall,
- Fastcall,
- Vectorcall,
- Thiscall,
- APCS,
- AAPCS,
- AAPCSVFP,
- SysV
-};
+pub const CallingConvention = enum { Unspecified, C, Naked, Async, Inline, Interrupt, Signal, Stdcall, Fastcall, Vectorcall, Thiscall, APCS, AAPCS, AAPCSVFP, SysV };
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
lib/std/x.zig
@@ -1,8 +1,22 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2021 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+
+const std = @import("std.zig");
+
pub const os = struct {
pub const Socket = @import("x/os/Socket.zig");
pub usingnamespace @import("x/os/net.zig");
};
pub const net = struct {
- pub const TCP = @import("x/net/TCP.zig");
+ pub const tcp = @import("x/net/tcp.zig");
};
+
+test {
+ inline for (.{ os, net }) |module| {
+ std.testing.refAllDecls(module);
+ }
+}