zig/lib/std/x/os/socket.zig
lithdew d3871af724 x/net/tcp, x/os/socket: tcp.Client.{Reader, Writer}
Only allow SOCK_STREAM (std.x.net.tcp.Client) sockets to have wrappers
for std.io.Reader and std.io.Writer provided, instead of Socket's in
general.
2021-05-10 19:22:31 +09:00

118 lines
4.7 KiB
Zig

// 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 fmt = std.fmt;
const mem = std.mem;
const time = std.time;
const builtin = std.builtin;
/// Import in a `Socket` abstraction depending on the platform we are compiling against.
pub usingnamespace switch (builtin.os.tag) {
.windows => @import("socket_windows.zig"),
else => @import("socket_posix.zig"),
};
/// A common subset of shared structs across cross-platform abstractions over socket syscalls.
pub fn Mixin(comptime Self: type) type {
return struct {
/// A socket-address pair.
pub const Connection = struct {
socket: Self,
address: Self.Address,
/// Enclose a socket and address into a socket-address pair.
pub fn from(socket: Self, address: Self.Address) Self.Connection {
return .{ .socket = socket, .address = address };
}
};
/// A generic socket address abstraction. It is safe to directly access and modify
/// the fields of a `Self.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) Self.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) Self.Address {
return .{ .ipv6 = .{ .host = host, .port = port } };
}
/// Parses a `sockaddr` into a generic socket address.
pub fn fromNative(address: *align(4) const os.sockaddr) Self.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 Self.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 Self.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: Self.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: Self.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: Self.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 }),
}
}
};
};
}