Commit 3600508fe1
Changed files (21)
lib/std/os/bits/linux/arm-eabi.zig
@@ -526,26 +526,6 @@ pub const Flock = extern struct {
__unused: [4]u8,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
pub const blksize_t = i32;
pub const nlink_t = u32;
pub const time_t = isize;
lib/std/os/bits/linux/arm64.zig
@@ -395,30 +395,6 @@ pub const Flock = extern struct {
__unused: [4]u8,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- __pad1: i32 = 0,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t = 0,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- __pad1: i32 = 0,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t = 0,
- msg_flags: i32,
-};
-
pub const blksize_t = i32;
pub const nlink_t = u32;
pub const time_t = isize;
lib/std/os/bits/linux/i386.zig
@@ -523,26 +523,6 @@ pub const Flock = extern struct {
l_pid: pid_t,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
pub const blksize_t = i32;
pub const nlink_t = u32;
pub const time_t = isize;
lib/std/os/bits/linux/powerpc.zig
@@ -515,26 +515,6 @@ pub const Flock = extern struct {
l_pid: pid_t,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: usize,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: usize,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: i32,
-};
-
pub const blksize_t = i32;
pub const nlink_t = u32;
pub const time_t = isize;
lib/std/os/bits/linux/powerpc64.zig
@@ -491,26 +491,6 @@ pub const Flock = extern struct {
__unused: [4]u8,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: usize,
- msg_control: ?*c_void,
- msg_controllen: usize,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: usize,
- msg_control: ?*c_void,
- msg_controllen: usize,
- msg_flags: i32,
-};
-
pub const blksize_t = i64;
pub const nlink_t = u64;
pub const time_t = i64;
lib/std/os/bits/linux/sparc64.zig
@@ -465,26 +465,6 @@ pub const Flock = extern struct {
l_pid: pid_t,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: u64,
- msg_control: ?*c_void,
- msg_controllen: u64,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: u64,
- msg_control: ?*c_void,
- msg_controllen: u64,
- msg_flags: i32,
-};
-
pub const off_t = i64;
pub const ino_t = u64;
pub const mode_t = u32;
lib/std/os/bits/linux/x86_64.zig
@@ -489,30 +489,6 @@ pub const Flock = extern struct {
l_pid: pid_t,
};
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- __pad1: i32 = 0,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t = 0,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- __pad1: i32 = 0,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t = 0,
- msg_flags: i32,
-};
-
pub const off_t = i64;
pub const ino_t = u64;
pub const dev_t = u64;
lib/std/os/bits/dragonfly.zig
@@ -768,15 +768,6 @@ pub const dl_phdr_info = extern struct {
dlpi_phdr: [*]std.elf.Phdr,
dlpi_phnum: u16,
};
-pub const msghdr = extern struct {
- msg_name: ?*c_void,
- msg_namelen: socklen_t,
- msg_iov: [*c]iovec,
- msg_iovlen: c_int,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- msg_flags: c_int,
-};
pub const cmsghdr = extern struct {
cmsg_len: socklen_t,
cmsg_level: c_int,
lib/std/os/bits/freebsd.zig
@@ -82,52 +82,6 @@ pub const Flock = extern struct {
__unused: [4]u8,
};
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
pub const libc_stat = extern struct {
dev: dev_t,
ino: ino_t,
lib/std/os/bits/haiku.zig
@@ -73,52 +73,6 @@ pub const Flock = extern struct {
__unused: [4]u8,
};
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
pub const off_t = i64;
pub const ino_t = u64;
lib/std/os/bits/linux.zig
@@ -1180,12 +1180,12 @@ pub const sockaddr_un = extern struct {
};
pub const mmsghdr = extern struct {
- msg_hdr: msghdr,
+ msg_hdr: std.x.os.Socket.Message,
msg_len: u32,
};
pub const mmsghdr_const = extern struct {
- msg_hdr: msghdr_const,
+ msg_hdr: std.x.os.Socket.Message,
msg_len: u32,
};
lib/std/os/bits/netbsd.zig
@@ -108,52 +108,6 @@ pub const EAI = enum(c_int) {
pub const EAI_MAX = 15;
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
pub const libc_stat = extern struct {
dev: dev_t,
mode: mode_t,
lib/std/os/bits/openbsd.zig
@@ -124,52 +124,6 @@ pub const EAI = enum(c_int) {
pub const EAI_MAX = 15;
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: c_uint,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: c_int,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: c_uint,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: c_int,
-};
-
pub const libc_stat = extern struct {
mode: mode_t,
dev: dev_t,
lib/std/os/windows/ws2_32.zig
@@ -3,6 +3,7 @@
// 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");
usingnamespace @import("bits.zig");
pub const SOCKET = *opaque {};
@@ -1093,27 +1094,6 @@ pub const WSABUF = extern struct {
buf: [*]u8,
};
-pub const msghdr = WSAMSG;
-pub const msghdr_const = WSAMSG_const;
-
-pub const WSAMSG_const = extern struct {
- name: *const sockaddr,
- namelen: INT,
- lpBuffers: [*]WSABUF,
- dwBufferCount: DWORD,
- Control: WSABUF,
- dwFlags: DWORD,
-};
-
-pub const WSAMSG = extern struct {
- name: *sockaddr,
- namelen: INT,
- lpBuffers: [*]WSABUF,
- dwBufferCount: DWORD,
- Control: WSABUF,
- dwFlags: DWORD,
-};
-
pub const WSAPOLLFD = pollfd;
pub const pollfd = extern struct {
@@ -1163,7 +1143,7 @@ pub const LPFN_GETACCEPTEXSOCKADDRS = fn (
pub const LPFN_WSASENDMSG = fn (
s: SOCKET,
- lpMsg: *const WSAMSG_const,
+ lpMsg: *const std.x.os.Socket.Message,
dwFlags: u32,
lpNumberOfBytesSent: ?*u32,
lpOverlapped: ?*OVERLAPPED,
@@ -1172,7 +1152,7 @@ pub const LPFN_WSASENDMSG = fn (
pub const LPFN_WSARECVMSG = fn (
s: SOCKET,
- lpMsg: *WSAMSG,
+ lpMsg: *std.x.os.Socket.Message,
lpdwNumberOfBytesRecv: ?*u32,
lpOverlapped: ?*OVERLAPPED,
lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
@@ -2046,7 +2026,7 @@ pub extern "ws2_32" fn WSASend(
pub extern "ws2_32" fn WSASendMsg(
s: SOCKET,
- lpMsg: *const WSAMSG_const,
+ lpMsg: *const std.x.os.Socket.Message,
dwFlags: u32,
lpNumberOfBytesSent: ?*u32,
lpOverlapped: ?*OVERLAPPED,
@@ -2055,7 +2035,7 @@ pub extern "ws2_32" fn WSASendMsg(
pub extern "ws2_32" fn WSARecvMsg(
s: SOCKET,
- lpMsg: *WSAMSG,
+ lpMsg: *std.x.os.Socket.Message,
lpdwNumberOfBytesRecv: ?*u32,
lpOverlapped: ?*OVERLAPPED,
lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
lib/std/x/net/tcp.zig
@@ -18,6 +18,7 @@ const testing = std.testing;
const IPv4 = std.x.os.IPv4;
const IPv6 = std.x.os.IPv6;
const Socket = std.x.os.Socket;
+const Buffer = std.x.os.Buffer;
/// A generic TCP socket abstraction.
const tcp = @This();
@@ -82,12 +83,13 @@ pub const Client = struct {
};
/// Opens a new client.
- pub fn init(domain: tcp.Domain, flags: u32) !Client {
+ pub fn init(domain: tcp.Domain, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Client {
return Client{
.socket = try Socket.init(
@enumToInt(domain),
- os.SOCK_STREAM | flags,
+ os.SOCK_STREAM,
os.IPPROTO_TCP,
+ flags,
),
};
}
@@ -143,14 +145,14 @@ pub const Client = struct {
/// Writes multiple I/O vectors with a prepended message header to the socket
/// with a set of flags specified. It returns the number of bytes that are
/// written to the socket.
- pub fn writeVectorized(self: Client, msg: os.msghdr_const, flags: u32) !usize {
+ pub fn writeVectorized(self: Client, msg: Socket.Message, flags: u32) !usize {
return self.socket.writeVectorized(msg, flags);
}
/// Read multiple I/O vectors with a prepended message header from the socket
/// with a set of flags specified. It returns the number of bytes that were
/// read into the buffer provided.
- pub fn readVectorized(self: Client, msg: *os.msghdr, flags: u32) !usize {
+ pub fn readVectorized(self: Client, msg: *Socket.Message, flags: u32) !usize {
return self.socket.readVectorized(msg, flags);
}
@@ -244,12 +246,13 @@ 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: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Listener {
return Listener{
.socket = try Socket.init(
@enumToInt(domain),
- os.SOCK_STREAM | flags,
+ os.SOCK_STREAM,
os.IPPROTO_TCP,
+ flags,
),
};
}
@@ -278,7 +281,7 @@ 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 {
+ pub fn accept(self: Listener, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !tcp.Connection {
return tcp.Connection.from(try self.socket.accept(flags));
}
@@ -324,7 +327,7 @@ pub const Listener = struct {
test "tcp: create client/listener pair" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
- const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
+ const listener = try tcp.Listener.init(.ip, .{ .close_on_exec = true });
defer listener.deinit();
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
@@ -336,19 +339,19 @@ test "tcp: create client/listener pair" {
.ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
}
- const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
+ const client = try tcp.Client.init(.ip, .{ .close_on_exec = true });
defer client.deinit();
try client.connect(binded_address);
- const conn = try listener.accept(os.SOCK_CLOEXEC);
+ const conn = try listener.accept(.{ .close_on_exec = true });
defer conn.deinit();
}
-test "tcp/client: set read timeout of 1 millisecond on blocking client" {
+test "tcp/client: 1ms read timeout" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
- const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
+ const listener = try tcp.Listener.init(.ip, .{ .close_on_exec = true });
defer listener.deinit();
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
@@ -360,23 +363,62 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {
.ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
}
- const client = try tcp.Client.init(.ip, os.SOCK_CLOEXEC);
+ const client = try tcp.Client.init(.ip, .{ .close_on_exec = true });
defer client.deinit();
try client.connect(binded_address);
try client.setReadTimeout(1);
- const conn = try listener.accept(os.SOCK_CLOEXEC);
+ const conn = try listener.accept(.{ .close_on_exec = true });
defer conn.deinit();
var buf: [1]u8 = undefined;
try testing.expectError(error.WouldBlock, client.reader(0).read(&buf));
}
+test "tcp/client: read and write multiple vectors" {
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+ const listener = try tcp.Listener.init(.ip, .{ .close_on_exec = true });
+ defer listener.deinit();
+
+ try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
+ try listener.listen(128);
+
+ var binded_address = try listener.getLocalAddress();
+ switch (binded_address) {
+ .ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
+ .ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
+ }
+
+ const client = try tcp.Client.init(.ip, .{ .close_on_exec = true });
+ defer client.deinit();
+
+ try client.connect(binded_address);
+
+ const conn = try listener.accept(.{ .close_on_exec = true });
+ defer conn.deinit();
+
+ const message = "hello world";
+ _ = try conn.client.writeVectorized(Socket.Message.fromBuffers(&[_]Buffer{
+ Buffer.from(message[0 .. message.len / 2]),
+ Buffer.from(message[message.len / 2 ..]),
+ }), 0);
+
+ var buf: [message.len]u8 = undefined;
+ var msg = Socket.Message.fromBuffers(&[_]Buffer{
+ Buffer.from(buf[0 .. message.len / 2]),
+ Buffer.from(buf[message.len / 2 ..]),
+ });
+ _ = try client.readVectorized(&msg, 0);
+
+ try testing.expectEqualStrings(message, &buf);
+}
+
test "tcp/listener: bind to unspecified ipv4 address" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
- const listener = try tcp.Listener.init(.ip, os.SOCK_CLOEXEC);
+ const listener = try tcp.Listener.init(.ip, .{ .close_on_exec = true });
defer listener.deinit();
try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
@@ -389,7 +431,7 @@ test "tcp/listener: bind to unspecified ipv4 address" {
test "tcp/listener: bind to unspecified ipv6 address" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
- const listener = try tcp.Listener.init(.ipv6, os.SOCK_CLOEXEC);
+ const listener = try tcp.Listener.init(.ipv6, .{ .close_on_exec = true });
defer listener.deinit();
try listener.bind(ip.Address.initIPv6(IPv6.unspecified, 0));
lib/std/x/os/io.zig
@@ -0,0 +1,205 @@
+const std = @import("../../std.zig");
+
+const os = std.os;
+const mem = std.mem;
+const builtin = std.builtin;
+const testing = std.testing;
+
+/// POSIX `iovec`, or Windows `WSABUF`. The difference between the two are the ordering
+/// of fields, alongside the length being represented as either a ULONG or a size_t.
+pub const Buffer = if (builtin.os.tag == .windows)
+ extern struct {
+ len: c_ulong,
+ ptr: usize,
+
+ pub fn from(slice: []const u8) Buffer {
+ return .{ .len = @intCast(c_ulong, slice.len), .ptr = @ptrToInt(slice.ptr) };
+ }
+
+ pub fn into(self: Buffer) []const u8 {
+ return @intToPtr([*]const u8, self.ptr)[0..self.len];
+ }
+
+ pub fn intoMutable(self: Buffer) []u8 {
+ return @intToPtr([*]u8, self.ptr)[0..self.len];
+ }
+ }
+else
+ extern struct {
+ ptr: usize,
+ len: usize,
+
+ pub fn from(slice: []const u8) Buffer {
+ return .{ .ptr = @ptrToInt(slice.ptr), .len = slice.len };
+ }
+
+ pub fn into(self: Buffer) []const u8 {
+ return @intToPtr([*]const u8, self.ptr)[0..self.len];
+ }
+
+ pub fn intoMutable(self: Buffer) []u8 {
+ return @intToptr([*]u8, self.ptr)[0..self.len];
+ }
+ };
+
+pub const Reactor = struct {
+ pub const InitFlags = enum {
+ close_on_exec,
+ };
+
+ pub const Event = struct {
+ data: usize,
+ is_error: bool,
+ is_hup: bool,
+ is_readable: bool,
+ is_writable: bool,
+ };
+
+ pub const Interest = struct {
+ hup: bool = false,
+ oneshot: bool = false,
+ readable: bool = false,
+ writable: bool = false,
+ };
+
+ fd: os.fd_t,
+
+ pub fn init(flags: std.enums.EnumFieldStruct(Reactor.InitFlags, bool, false)) !Reactor {
+ var raw_flags: u32 = 0;
+ const set = std.EnumSet(Reactor.InitFlags).init(flags);
+ if (set.contains(.close_on_exec)) raw_flags |= os.EPOLL_CLOEXEC;
+ return Reactor{ .fd = try os.epoll_create1(raw_flags) };
+ }
+
+ pub fn deinit(self: Reactor) void {
+ os.close(self.fd);
+ }
+
+ pub fn update(self: Reactor, fd: os.fd_t, identifier: usize, interest: Reactor.Interest) !void {
+ var flags: u32 = 0;
+ flags |= if (interest.oneshot) os.EPOLLONESHOT else os.EPOLLET;
+ if (interest.hup) flags |= os.EPOLLRDHUP;
+ if (interest.readable) flags |= os.EPOLLIN;
+ if (interest.writable) flags |= os.EPOLLOUT;
+
+ const event = &os.epoll_event{
+ .events = flags,
+ .data = .{ .ptr = identifier },
+ };
+
+ os.epoll_ctl(self.fd, os.EPOLL_CTL_MOD, fd, event) catch |err| switch (err) {
+ error.FileDescriptorNotRegistered => try os.epoll_ctl(self.fd, os.EPOLL_CTL_ADD, fd, event),
+ else => return err,
+ };
+ }
+
+ pub fn poll(self: Reactor, comptime max_num_events: comptime_int, closure: anytype, timeout_milliseconds: ?u64) !void {
+ var events: [max_num_events]os.epoll_event = undefined;
+
+ const num_events = os.epoll_wait(self.fd, &events, if (timeout_milliseconds) |ms| @intCast(i32, ms) else -1);
+ for (events[0..num_events]) |ev| {
+ const is_error = ev.events & os.EPOLLERR != 0;
+ const is_hup = ev.events & (os.EPOLLHUP | os.EPOLLRDHUP) != 0;
+ const is_readable = ev.events & os.EPOLLIN != 0;
+ const is_writable = ev.events & os.EPOLLOUT != 0;
+
+ try closure.call(Reactor.Event{
+ .data = ev.data.ptr,
+ .is_error = is_error,
+ .is_hup = is_hup,
+ .is_readable = is_readable,
+ .is_writable = is_writable,
+ });
+ }
+ }
+};
+
+test "reactor/linux: drive async tcp client/listener pair" {
+ if (builtin.os.tag != .linux) return error.SkipZigTest;
+
+ const ip = std.x.net.ip;
+ const tcp = std.x.net.tcp;
+
+ const IPv4 = std.x.os.IPv4;
+ const IPv6 = std.x.os.IPv6;
+ const Socket = std.x.os.Socket;
+
+ const reactor = try Reactor.init(.{ .close_on_exec = true });
+ defer reactor.deinit();
+
+ const listener = try tcp.Listener.init(.ip, .{
+ .close_on_exec = true,
+ .nonblocking = true,
+ });
+ defer listener.deinit();
+
+ try reactor.update(listener.socket.fd, 0, .{ .readable = true });
+ try reactor.poll(1, struct {
+ fn call(event: Reactor.Event) !void {
+ try testing.expectEqual(Reactor.Event{
+ .data = 0,
+ .is_error = false,
+ .is_hup = true,
+ .is_readable = false,
+ .is_writable = false,
+ }, event);
+ }
+ }, null);
+
+ try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 0));
+ try listener.listen(128);
+
+ var binded_address = try listener.getLocalAddress();
+ switch (binded_address) {
+ .ipv4 => |*ipv4| ipv4.host = IPv4.localhost,
+ .ipv6 => |*ipv6| ipv6.host = IPv6.localhost,
+ }
+
+ const client = try tcp.Client.init(.ip, .{
+ .close_on_exec = true,
+ .nonblocking = true,
+ });
+ defer client.deinit();
+
+ try reactor.update(client.socket.fd, 1, .{ .readable = true, .writable = true });
+ try reactor.poll(1, struct {
+ fn call(event: Reactor.Event) !void {
+ try testing.expectEqual(Reactor.Event{
+ .data = 1,
+ .is_error = false,
+ .is_hup = true,
+ .is_readable = false,
+ .is_writable = true,
+ }, event);
+ }
+ }, null);
+
+ client.connect(binded_address) catch |err| switch (err) {
+ error.WouldBlock => {},
+ else => return err,
+ };
+
+ try reactor.poll(1, struct {
+ fn call(event: Reactor.Event) !void {
+ try testing.expectEqual(Reactor.Event{
+ .data = 1,
+ .is_error = false,
+ .is_hup = false,
+ .is_readable = false,
+ .is_writable = true,
+ }, event);
+ }
+ }, null);
+
+ try reactor.poll(1, struct {
+ fn call(event: Reactor.Event) !void {
+ try testing.expectEqual(Reactor.Event{
+ .data = 0,
+ .is_error = false,
+ .is_hup = false,
+ .is_readable = true,
+ .is_writable = false,
+ }, event);
+ }
+ }, null);
+}
lib/std/x/os/socket.zig
@@ -11,8 +11,13 @@ const os = std.os;
const fmt = std.fmt;
const mem = std.mem;
const time = std.time;
+const meta = std.meta;
const builtin = std.builtin;
+const Buffer = std.x.os.Buffer;
+
+const assert = std.debug.assert;
+
/// A generic, cross-platform socket abstraction.
pub const Socket = struct {
/// A socket-address pair.
@@ -29,6 +34,32 @@ pub const Socket = struct {
/// A generic socket address abstraction. It is safe to directly access and modify
/// the fields of a `Socket.Address`.
pub const Address = union(enum) {
+ pub const Native = struct {
+ pub const requires_prepended_length = builtin.os.getVersionRange() == .semver;
+ pub const Length = if (requires_prepended_length) u8 else [0]u8;
+
+ pub const Family = if (requires_prepended_length) u8 else c_ushort;
+
+ /// POSIX `sockaddr_storage`. The expected size and alignment is specified in IETF RFC 2553.
+ pub const Storage = extern struct {
+ pub const expected_size = 128;
+ pub const expected_alignment = 8;
+
+ pub const padding_size = expected_size -
+ mem.alignForward(@sizeOf(Address.Native.Length), expected_alignment) -
+ mem.alignForward(@sizeOf(Address.Native.Family), expected_alignment);
+
+ len: Address.Native.Length align(expected_alignment) = undefined,
+ family: Address.Native.Family align(expected_alignment) = undefined,
+ padding: [padding_size]u8 align(expected_alignment) = undefined,
+
+ comptime {
+ assert(@sizeOf(Storage) == Storage.expected_size);
+ assert(@alignOf(Storage) == Storage.expected_alignment);
+ }
+ };
+ };
+
ipv4: net.IPv4.Address,
ipv6: net.IPv6.Address,
@@ -107,6 +138,174 @@ pub const Socket = struct {
}
};
+ /// POSIX `msghdr`. Denotes a destination address, set of buffers, control data, and flags. Ported
+ /// directly from musl.
+ pub const Message = if (builtin.os.isAtLeast(.windows, .vista) != null and builtin.os.isAtLeast(.windows, .vista).?)
+ extern struct {
+ name: usize = @ptrToInt(@as(?[*]u8, null)),
+ name_len: c_int = 0,
+
+ buffers: usize = undefined,
+ buffers_len: c_ulong = undefined,
+
+ control: Buffer = .{
+ .ptr = @ptrToInt(@as(?[*]u8, null)),
+ .len = 0,
+ },
+ flags: c_ulong = 0,
+
+ pub usingnamespace MessageMixin(Message);
+ }
+ else if (builtin.os.tag == .windows)
+ extern struct {
+ name: usize = @ptrToInt(@as(?[*]u8, null)),
+ name_len: c_int = 0,
+
+ buffers: usize = undefined,
+ buffers_len: u32 = undefined,
+
+ control: Buffer = .{
+ .ptr = @ptrToInt(@as(?[*]u8, null)),
+ .len = 0,
+ },
+ flags: u32 = 0,
+
+ pub usingnamespace MessageMixin(Message);
+ }
+ else if (@sizeOf(usize) > 4 and builtin.endian == .Big)
+ extern struct {
+ name: usize = @ptrToInt(@as(?[*]u8, null)),
+ name_len: c_uint = 0,
+
+ buffers: usize = undefined,
+ _pad_1: c_int = 0,
+ buffers_len: c_int = undefined,
+
+ control: usize = @ptrToInt(@as(?[*]u8, null)),
+ _pad_2: c_int = 0,
+ control_len: c_uint = 0,
+
+ flags: c_int = 0,
+
+ pub usingnamespace MessageMixin(Message);
+ }
+ else if (@sizeOf(usize) > 4 and builtin.endian == .Little)
+ extern struct {
+ name: usize = @ptrToInt(@as(?[*]u8, null)),
+ name_len: c_uint = 0,
+
+ buffers: usize = undefined,
+ buffers_len: c_int = undefined,
+ _pad_1: c_int = 0,
+
+ control: usize = @ptrToInt(@as(?[*]u8, null)),
+ control_len: c_uint = 0,
+ _pad_2: c_int = 0,
+
+ flags: c_int = 0,
+
+ pub usingnamespace MessageMixin(Message);
+ }
+ else
+ extern struct {
+ name: usize = @ptrToInt(@as(?[*]u8, null)),
+ name_len: c_uint = 0,
+
+ buffers: usize = undefined,
+ buffers_len: c_int,
+
+ control: usize = null,
+ control_len: c_uint = 0,
+
+ flags: c_int = 0,
+
+ pub usingnamespace MessageMixin(Message);
+ };
+
+ fn MessageMixin(comptime Self: type) type {
+ return struct {
+ pub fn fromBuffers(buffers: []const Buffer) Self {
+ var self: Self = .{};
+ self.setBuffers(buffers);
+ return self;
+ }
+
+ pub fn setName(self: *Self, name: []const u8) void {
+ self.name = @ptrToInt(name.ptr);
+ self.name_len = @intCast(meta.fieldInfo(Self, .name_len).field_type, name.len);
+ }
+
+ pub fn setBuffers(self: *Self, buffers: []const Buffer) void {
+ self.buffers = @ptrToInt(buffers.ptr);
+ self.buffers_len = @intCast(meta.fieldInfo(Self, .buffers_len).field_type, buffers.len);
+ }
+
+ pub fn setControl(self: *Self, control: []const u8) void {
+ if (builtin.os.tag == .windows) {
+ self.control = Buffer.from(control);
+ } else {
+ self.control = @ptrToInt(control.ptr);
+ self.control_len = @intCast(meta.fieldInfo(Self, .control_len).field_type, control.len);
+ }
+ }
+
+ pub fn setFlags(self: *Self, flags: u32) void {
+ self.flags = @intCast(meta.fieldInfo(Self, .flags).field_type, flags);
+ }
+
+ pub fn getName(self: Self) []const u8 {
+ return @intToPtr([*]const u8, self.name)[0..@intCast(usize, self.name_len)];
+ }
+
+ pub fn getBuffers(self: Self) []const Buffer {
+ return @intToPtr([*]const Buffer, self.buffers)[0..@intCast(usize, self.buffers_len)];
+ }
+
+ pub fn getControl(self: Self) []const u8 {
+ if (builtin.os.tag == .windows) {
+ return self.control.into();
+ } else {
+ return @intToPtr([*]const u8, self.control)[0..@intCast(usize, self.control_len)];
+ }
+ }
+
+ pub fn getFlags(self: Self) u32 {
+ return @intCast(u32, self.flags);
+ }
+ };
+ }
+
+ /// POSIX `linger`, denoting the linger settings of a socket.
+ ///
+ /// Microsoft's documentation and glibc denote the fields to be unsigned
+ /// short's on Windows, whereas glibc and musl denote the fields to be
+ /// int's on every other platform.
+ pub const Linger = extern struct {
+ pub const Field = switch (builtin.os.tag) {
+ .windows => c_ushort,
+ else => c_int,
+ };
+
+ enabled: Field,
+ timeout_seconds: Field,
+
+ pub fn init(timeout_seconds: ?u16) Socket.Linger {
+ return .{
+ .enabled = @intCast(Socket.Linger.Field, @boolToInt(timeout_seconds != null)),
+ .timeout_seconds = if (timeout_seconds) |seconds| @intCast(Socket.Linger.Field, seconds) else 0,
+ };
+ }
+ };
+
+ /// Possible set of flags to initialize a socket with.
+ pub const InitFlags = enum {
+ // Initialize a socket to be non-blocking.
+ nonblocking,
+
+ // Have a socket close itself on exec syscalls.
+ close_on_exec,
+ };
+
/// The underlying handle of a socket.
fd: os.socket_t,
lib/std/x/os/socket_posix.zig
@@ -13,8 +13,12 @@ const time = std.time;
pub fn Mixin(comptime Socket: type) type {
return struct {
/// Open a new socket.
- pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
- return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
+ pub fn init(domain: u32, socket_type: u32, protocol: u32, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Socket {
+ var raw_flags: u32 = socket_type;
+ const set = std.EnumSet(Socket.InitFlags).init(flags);
+ if (set.contains(.close_on_exec)) raw_flags |= os.SOCK_CLOEXEC;
+ if (set.contains(.nonblocking)) raw_flags |= os.SOCK_NONBLOCK;
+ return Socket{ .fd = try os.socket(domain, raw_flags, protocol) };
}
/// Closes the socket.
@@ -44,11 +48,16 @@ pub fn Mixin(comptime Socket: type) type {
/// Accept a pending incoming connection queued to the kernel backlog
/// of the socket.
- pub fn accept(self: Socket, flags: u32) !Socket.Connection {
- var address: os.sockaddr_storage = undefined;
- var address_len: u32 = @sizeOf(os.sockaddr_storage);
+ pub fn accept(self: Socket, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Socket.Connection {
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: u32 = @sizeOf(Socket.Address.Native.Storage);
- const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
+ var raw_flags: u32 = 0;
+ const set = std.EnumSet(Socket.InitFlags).init(flags);
+ if (set.contains(.close_on_exec)) raw_flags |= os.SOCK_CLOEXEC;
+ if (set.contains(.nonblocking)) raw_flags |= os.SOCK_NONBLOCK;
+
+ const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, raw_flags) };
const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
return Socket.Connection.from(socket, socket_address);
@@ -69,48 +78,45 @@ pub fn Mixin(comptime Socket: type) type {
/// Writes multiple I/O vectors with a prepended message header to the socket
/// with a set of flags specified. It returns the number of bytes that are
/// written to the socket.
- pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
+ pub fn writeVectorized(self: Socket, msg: Socket.Message, flags: u32) !usize {
return os.sendmsg(self.fd, msg, flags);
}
/// Read multiple I/O vectors with a prepended message header from the socket
/// with a set of flags specified. It returns the number of bytes that were
/// read into the buffer provided.
- pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
- if (comptime @hasDecl(os.system, "recvmsg")) {
- while (true) {
- const rc = os.system.recvmsg(self.fd, msg, flags);
- return switch (os.errno(rc)) {
- 0 => @intCast(usize, rc),
- os.EBADF => unreachable, // always a race condition
- os.EFAULT => unreachable,
- os.EINVAL => unreachable,
- os.ENOTCONN => unreachable,
- os.ENOTSOCK => unreachable,
- os.EINTR => continue,
- os.EAGAIN => error.WouldBlock,
- os.ENOMEM => error.SystemResources,
- os.ECONNREFUSED => error.ConnectionRefused,
- os.ECONNRESET => error.ConnectionResetByPeer,
- else => |err| os.unexpectedErrno(err),
- };
- }
+ pub fn readVectorized(self: Socket, msg: *Socket.Message, flags: u32) !usize {
+ while (true) {
+ const rc = os.system.recvmsg(self.fd, msg, flags);
+ return switch (os.errno(rc)) {
+ 0 => @intCast(usize, rc),
+ os.EBADF => unreachable, // always a race condition
+ os.EFAULT => unreachable,
+ os.EINVAL => unreachable,
+ os.ENOTCONN => unreachable,
+ os.ENOTSOCK => unreachable,
+ os.EINTR => continue,
+ os.EAGAIN => error.WouldBlock,
+ os.ENOMEM => error.SystemResources,
+ os.ECONNREFUSED => error.ConnectionRefused,
+ os.ECONNRESET => error.ConnectionResetByPeer,
+ else => |err| os.unexpectedErrno(err),
+ };
}
- return error.NotSupported;
}
/// Query the address that the socket is locally bounded to.
pub fn getLocalAddress(self: Socket) !Socket.Address {
- var address: os.sockaddr_storage = undefined;
- var address_len: u32 = @sizeOf(os.sockaddr_storage);
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: u32 = @sizeOf(Socket.Address.Native.Storage);
try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
}
/// Query the address that the socket is connected to.
pub fn getRemoteAddress(self: Socket) !Socket.Address {
- var address: os.sockaddr_storage = undefined;
- var address_len: u32 = @sizeOf(os.sockaddr_storage);
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: u32 = @sizeOf(Socket.Address.Native.Storage);
try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
}
@@ -165,14 +171,7 @@ pub fn Mixin(comptime Socket: type) type {
/// seconds.
pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
if (comptime @hasDecl(os, "SO_LINGER")) {
- const settings = extern struct {
- l_onoff: c_int,
- l_linger: c_int,
- }{
- .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)),
- .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0,
- };
-
+ const settings = Socket.Linger.init(timeout_seconds);
return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings));
}
lib/std/x/os/socket_windows.zig
@@ -16,27 +16,24 @@ const ws2_32 = windows.ws2_32;
pub fn Mixin(comptime Socket: type) type {
return struct {
/// Open a new socket.
- pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
- var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);
-
- var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;
- if (socket_type & os.SOCK_CLOEXEC != 0) {
- filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
- }
+ pub fn init(domain: u32, socket_type: u32, protocol: u32, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Socket {
+ var raw_flags: u32 = 0;
+ const set = std.EnumSet(Socket.InitFlags).init(flags);
+ if (set.contains(.close_on_exec)) raw_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
const fd = ws2_32.WSASocketW(
@intCast(i32, domain),
- @intCast(i32, filtered_socket_type),
+ @intCast(i32, socket_type),
@intCast(i32, protocol),
null,
0,
- filtered_flags,
+ raw_flags,
);
if (fd == ws2_32.INVALID_SOCKET) {
return switch (ws2_32.WSAGetLastError()) {
.WSANOTINITIALISED => {
_ = try windows.WSAStartup(2, 2);
- return Socket.init(domain, socket_type, protocol);
+ return Socket.init(domain, socket_type, protocol, flags);
},
.WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
.WSAEMFILE => error.ProcessFdQuotaExceeded,
@@ -46,6 +43,14 @@ pub fn Mixin(comptime Socket: type) type {
};
}
+ if (set.contains(.nonblocking)) {
+ var enabled: c_ulong = 1;
+ const rc = ws2_32.ioctlsocket(fd, ws2_32.FIONBIO, &enabled);
+ if (rc == ws2_32.SOCKET_ERROR) {
+ return windows.unexpectedWSAError(ws2_32.WSAGetLastError());
+ }
+ }
+
return Socket{ .fd = fd };
}
@@ -138,12 +143,12 @@ pub fn Mixin(comptime Socket: type) type {
/// Accept a pending incoming connection queued to the kernel backlog
/// of the socket.
- pub fn accept(self: Socket, flags: u32) !Socket.Connection {
- var address: ws2_32.sockaddr_storage = undefined;
- var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
+ pub fn accept(self: Socket, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Socket.Connection {
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: c_int = @sizeOf(Socket.Address.Native.Storage);
- const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
- if (rc == ws2_32.INVALID_SOCKET) {
+ const fd = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
+ if (fd == ws2_32.INVALID_SOCKET) {
return switch (ws2_32.WSAGetLastError()) {
.WSANOTINITIALISED => unreachable,
.WSAECONNRESET => error.ConnectionResetByPeer,
@@ -158,9 +163,20 @@ pub fn Mixin(comptime Socket: type) type {
};
}
- const socket = Socket.from(rc);
+ const socket = Socket.from(fd);
+ errdefer socket.deinit();
+
const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
+ const set = std.EnumSet(Socket.InitFlags).init(flags);
+ if (set.contains(.nonblocking)) {
+ var enabled: c_ulong = 1;
+ const rc = ws2_32.ioctlsocket(fd, ws2_32.FIONBIO, &enabled);
+ if (rc == ws2_32.SOCKET_ERROR) {
+ return windows.unexpectedWSAError(ws2_32.WSAGetLastError());
+ }
+ }
+
return Socket.Connection.from(socket, socket_address);
}
@@ -238,7 +254,7 @@ pub fn Mixin(comptime Socket: type) type {
/// Writes multiple I/O vectors with a prepended message header to the socket
/// with a set of flags specified. It returns the number of bytes that are
/// written to the socket.
- pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize {
+ pub fn writeVectorized(self: Socket, msg: Socket.Message, flags: u32) !usize {
const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG);
var num_bytes: u32 = undefined;
@@ -275,7 +291,7 @@ pub fn Mixin(comptime Socket: type) type {
/// Read multiple I/O vectors with a prepended message header from the socket
/// with a set of flags specified. It returns the number of bytes that were
/// read into the buffer provided.
- pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize {
+ pub fn readVectorized(self: Socket, msg: *Socket.Message, flags: u32) !usize {
const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG);
var num_bytes: u32 = undefined;
@@ -311,8 +327,8 @@ pub fn Mixin(comptime Socket: type) type {
/// Query the address that the socket is locally bounded to.
pub fn getLocalAddress(self: Socket) !Socket.Address {
- var address: ws2_32.sockaddr_storage = undefined;
- var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: c_int = @sizeOf(Socket.Address.Native.Storage);
const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
if (rc == ws2_32.SOCKET_ERROR) {
@@ -331,8 +347,8 @@ pub fn Mixin(comptime Socket: type) type {
/// Query the address that the socket is connected to.
pub fn getRemoteAddress(self: Socket) !Socket.Address {
- var address: ws2_32.sockaddr_storage = undefined;
- var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
+ var address: Socket.Address.Native.Storage = undefined;
+ var address_len: c_int = @sizeOf(Socket.Address.Native.Storage);
const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
if (rc == ws2_32.SOCKET_ERROR) {
@@ -384,11 +400,7 @@ pub fn Mixin(comptime Socket: type) type {
/// if the host does not support the option for a socket to linger around up until a timeout specified in
/// seconds.
pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
- const settings = ws2_32.linger{
- .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
- .l_linger = if (timeout_seconds) |seconds| seconds else 0,
- };
-
+ const settings = Socket.Linger.init(timeout_seconds);
return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings));
}
lib/std/os.zig
@@ -4994,7 +4994,7 @@ pub fn sendmsg(
/// The file descriptor of the sending socket.
sockfd: socket_t,
/// Message header and iovecs
- msg: msghdr_const,
+ msg: std.x.os.Socket.Message,
flags: u32,
) SendMsgError!usize {
while (true) {
lib/std/x.zig
@@ -8,6 +8,7 @@ const std = @import("std.zig");
pub const os = struct {
pub const Socket = @import("x/os/socket.zig").Socket;
+ pub usingnamespace @import("x/os/io.zig");
pub usingnamespace @import("x/os/net.zig");
};