authorgravatar for kenta@lithdew.netlithdew <kenta@lithdew.net> 2021-05-09 15:43:56+09:00
committergravatar for kenta@lithdew.netlithdew <kenta@lithdew.net> 2021-05-10 19:22:31+09:00
log77f8a9ae223370d43b4c02ff30f936b41e412535
tree13ef1b903a008e12b8537c37b4aaad4fd5e77d61
parent3d946ef5eb15d2333a5e376ab95dad2e70e0dfb9

x/os/socket, std/os/windows: implement loading winsock extensions

Implement loading Winsock extensions. Add missing Winsock extension GUID's. Implement readVectorized() for POSIX sockets and readVectorized() / writeVectorized() for Windows sockets. Inverse how mixins are used to implement platform-independent syscalls for the std.x.os.Socket abstraction. This cleans up the API as suggested by @komuw.

5 files changed, 826 insertions(+), 681 deletions(-)

lib/std/os/windows.zig+32
...@@ -1749,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID {...@@ -1749,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID {
1749 return (s << 10) | p;1749 return (s << 10) | p;
1750}1750}
17511751
1752/// Loads a Winsock extension function in runtime specified by a GUID.
1753pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: GUID) !T {
1754 var function: T = undefined;
1755 var num_bytes: DWORD = undefined;
1756
1757 const rc = ws2_32.WSAIoctl(
1758 sock,
1759 ws2_32.SIO_GET_EXTENSION_FUNCTION_POINTER,
1760 @ptrCast(*const c_void, &guid),
1761 @sizeOf(GUID),
1762 &function,
1763 @sizeOf(T),
1764 &num_bytes,
1765 null,
1766 null,
1767 );
1768
1769 if (rc == ws2_32.SOCKET_ERROR) {
1770 return switch (ws2_32.WSAGetLastError()) {
1771 .WSAEOPNOTSUPP => error.OperationNotSupported,
1772 .WSAENOTSOCK => error.FileDescriptorNotASocket,
1773 else => |err| unexpectedWSAError(err),
1774 };
1775 }
1776
1777 if (num_bytes != @sizeOf(T)) {
1778 return error.ShortRead;
1779 }
1780
1781 return function;
1782}
1783
1752/// Call this when you made a windows DLL call or something that does SetLastError1784/// Call this when you made a windows DLL call or something that does SetLastError
1753/// and you get an unexpected error.1785/// and you get an unexpected error.
1754pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {1786pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
lib/std/os/windows/ws2_32.zig+50-5
...@@ -266,10 +266,54 @@ pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0;...@@ -266,10 +266,54 @@ pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0;
266pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75;266pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75;
267pub const BITS_PER_BYTE = 8;267pub const BITS_PER_BYTE = 8;
268pub const LOG2_BITS_PER_BYTE = 3;268pub const LOG2_BITS_PER_BYTE = 3;
269
269pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}");270pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}");
270pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}");271pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}");
271pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}");272pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}");
272pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}");273pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}");
274
275pub const WSAID_CONNECTEX = GUID{
276 .Data1 = 0x25a207b9,
277 .Data2 = 0xddf3,
278 .Data3 = 0x4660,
279 .Data4 = [8]u8{ 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e },
280};
281
282pub const WSAID_ACCEPTEX = GUID{
283 .Data1 = 0xb5367df1,
284 .Data2 = 0xcbac,
285 .Data3 = 0x11cf,
286 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
287};
288
289pub const WSAID_GETACCEPTEXSOCKADDRS = GUID{
290 .Data1 = 0xb5367df2,
291 .Data2 = 0xcbac,
292 .Data3 = 0x11cf,
293 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
294};
295
296pub const WSAID_WSARECVMSG = GUID{
297 .Data1 = 0xf689d7c8,
298 .Data2 = 0x6f1f,
299 .Data3 = 0x436b,
300 .Data4 = [8]u8{ 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22 },
301};
302
303pub const WSAID_WSAPOLL = GUID{
304 .Data1 = 0x18C76F85,
305 .Data2 = 0xDC66,
306 .Data3 = 0x4964,
307 .Data4 = [8]u8{ 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B },
308};
309
310pub const WSAID_WSASENDMSG = GUID{
311 .Data1 = 0xa441e712,
312 .Data2 = 0x754f,
313 .Data3 = 0x43ca,
314 .Data4 = [8]u8{ 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d },
315};
316
273pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0;317pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0;
274pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0;318pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0;
275pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1;319pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1;
...@@ -485,6 +529,7 @@ pub const IOC_UNIX = 0;...@@ -485,6 +529,7 @@ pub const IOC_UNIX = 0;
485pub const IOC_WS2 = 134217728;529pub const IOC_WS2 = 134217728;
486pub const IOC_PROTOCOL = 268435456;530pub const IOC_PROTOCOL = 268435456;
487pub const IOC_VENDOR = 402653184;531pub const IOC_VENDOR = 402653184;
532pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6;
488pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27;533pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27;
489pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28;534pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28;
490pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29;535pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29;
...@@ -1115,9 +1160,9 @@ pub const LPFN_GETACCEPTEXSOCKADDRS = fn (...@@ -1115,9 +1160,9 @@ pub const LPFN_GETACCEPTEXSOCKADDRS = fn (
1115 RemoteSockaddrLength: *i32,1160 RemoteSockaddrLength: *i32,
1116) callconv(WINAPI) void;1161) callconv(WINAPI) void;
11171162
1118pub const LFN_WSASENDMSG = fn (1163pub const LPFN_WSASENDMSG = fn (
1119 s: SOCKET,1164 s: SOCKET,
1120 lpMsg: *WSAMSG_const,1165 lpMsg: *const WSAMSG_const,
1121 dwFlags: u32,1166 dwFlags: u32,
1122 lpNumberOfBytesSent: ?*u32,1167 lpNumberOfBytesSent: ?*u32,
1123 lpOverlapped: ?*OVERLAPPED,1168 lpOverlapped: ?*OVERLAPPED,
...@@ -1927,7 +1972,7 @@ pub extern "ws2_32" fn WSAHtons(...@@ -1927,7 +1972,7 @@ pub extern "ws2_32" fn WSAHtons(
1927pub extern "ws2_32" fn WSAIoctl(1972pub extern "ws2_32" fn WSAIoctl(
1928 s: SOCKET,1973 s: SOCKET,
1929 dwIoControlCode: u32,1974 dwIoControlCode: u32,
1930 lpvInBuffer: ?*c_void,1975 lpvInBuffer: ?*const c_void,
1931 cbInBuffer: u32,1976 cbInBuffer: u32,
1932 lpvOutbuffer: ?*c_void,1977 lpvOutbuffer: ?*c_void,
1933 cbOutbuffer: u32,1978 cbOutbuffer: u32,
...@@ -1992,7 +2037,7 @@ pub extern "ws2_32" fn WSASend(...@@ -1992,7 +2037,7 @@ pub extern "ws2_32" fn WSASend(
1992 s: SOCKET,2037 s: SOCKET,
1993 lpBuffers: [*]WSABUF,2038 lpBuffers: [*]WSABUF,
1994 dwBufferCount: u32,2039 dwBufferCount: u32,
1995 lpNumberOfBytesSent: ?*U32,2040 lpNumberOfBytesSent: ?*u32,
1996 dwFlags: u32,2041 dwFlags: u32,
1997 lpOverlapped: ?*OVERLAPPED,2042 lpOverlapped: ?*OVERLAPPED,
1998 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,2043 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
...@@ -2000,7 +2045,7 @@ pub extern "ws2_32" fn WSASend(...@@ -2000,7 +2045,7 @@ pub extern "ws2_32" fn WSASend(
20002045
2001pub extern "ws2_32" fn WSASendMsg(2046pub extern "ws2_32" fn WSASendMsg(
2002 s: SOCKET,2047 s: SOCKET,
2003 lpMsg: *WSAMSG_const,2048 lpMsg: *const WSAMSG_const,
2004 dwFlags: u32,2049 dwFlags: u32,
2005 lpNumberOfBytesSent: ?*u32,2050 lpNumberOfBytesSent: ?*u32,
2006 lpOverlapped: ?*OVERLAPPED,2051 lpOverlapped: ?*OVERLAPPED,
lib/std/x/os/socket.zig+95-89
...@@ -13,105 +13,111 @@ const mem = std.mem;...@@ -13,105 +13,111 @@ const mem = std.mem;
13const time = std.time;13const time = std.time;
14const builtin = std.builtin;14const builtin = std.builtin;
1515
16/// Import in a `Socket` abstraction depending on the platform we are compiling against.16/// A generic, cross-platform socket abstraction.
17pub usingnamespace switch (builtin.os.tag) {17pub const Socket = struct {
18 .windows => @import("socket_windows.zig"),18 /// A socket-address pair.
19 else => @import("socket_posix.zig"),19 pub const Connection = struct {
20};20 socket: Socket,
21 address: Socket.Address,
2122
22/// A common subset of shared structs across cross-platform abstractions over socket syscalls.23 /// Enclose a socket and address into a socket-address pair.
23pub fn Mixin(comptime Self: type) type {24 pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
24 return struct {25 return .{ .socket = socket, .address = address };
25 /// A socket-address pair.26 }
26 pub const Connection = struct {27 };
27 socket: Self,
28 address: Self.Address,
2928
30 /// Enclose a socket and address into a socket-address pair.29 /// A generic socket address abstraction. It is safe to directly access and modify
31 pub fn from(socket: Self, address: Self.Address) Self.Connection {30 /// the fields of a `Socket.Address`.
32 return .{ .socket = socket, .address = address };31 pub const Address = union(enum) {
33 }32 ipv4: net.IPv4.Address,
34 };33 ipv6: net.IPv6.Address,
3534
36 /// A generic socket address abstraction. It is safe to directly access and modify35 /// Instantiate a new address with a IPv4 host and port.
37 /// the fields of a `Self.Address`.36 pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
38 pub const Address = union(enum) {37 return .{ .ipv4 = .{ .host = host, .port = port } };
39 ipv4: net.IPv4.Address,38 }
40 ipv6: net.IPv6.Address,
4139
42 /// Instantiate a new address with a IPv4 host and port.40 /// Instantiate a new address with a IPv6 host and port.
43 pub fn initIPv4(host: net.IPv4, port: u16) Self.Address {41 pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
44 return .{ .ipv4 = .{ .host = host, .port = port } };42 return .{ .ipv6 = .{ .host = host, .port = port } };
45 }43 }
4644
47 /// Instantiate a new address with a IPv6 host and port.45 /// Parses a `sockaddr` into a generic socket address.
48 pub fn initIPv6(host: net.IPv6, port: u16) Self.Address {46 pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
49 return .{ .ipv6 = .{ .host = host, .port = port } };47 switch (address.family) {
50 }48 os.AF_INET => {
5149 const info = @ptrCast(*const os.sockaddr_in, address);
52 /// Parses a `sockaddr` into a generic socket address.50 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
53 pub fn fromNative(address: *align(4) const os.sockaddr) Self.Address {51 const port = mem.bigToNative(u16, info.port);
54 switch (address.family) {52 return Socket.Address.initIPv4(host, port);
55 os.AF_INET => {53 },
56 const info = @ptrCast(*const os.sockaddr_in, address);54 os.AF_INET6 => {
57 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };55 const info = @ptrCast(*const os.sockaddr_in6, address);
58 const port = mem.bigToNative(u16, info.port);56 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
59 return Self.Address.initIPv4(host, port);57 const port = mem.bigToNative(u16, info.port);
60 },58 return Socket.Address.initIPv6(host, port);
61 os.AF_INET6 => {59 },
62 const info = @ptrCast(*const os.sockaddr_in6, address);60 else => unreachable,
63 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
64 const port = mem.bigToNative(u16, info.port);
65 return Self.Address.initIPv6(host, port);
66 },
67 else => unreachable,
68 }
69 }61 }
62 }
7063
71 /// Encodes a generic socket address into an extern union that may be reliably64 /// Encodes a generic socket address into an extern union that may be reliably
72 /// casted into a `sockaddr` which may be passed into socket syscalls.65 /// casted into a `sockaddr` which may be passed into socket syscalls.
73 pub fn toNative(self: Self.Address) extern union {66 pub fn toNative(self: Socket.Address) extern union {
74 ipv4: os.sockaddr_in,67 ipv4: os.sockaddr_in,
75 ipv6: os.sockaddr_in6,68 ipv6: os.sockaddr_in6,
76 } {69 } {
77 return switch (self) {70 return switch (self) {
78 .ipv4 => |address| .{71 .ipv4 => |address| .{
79 .ipv4 = .{72 .ipv4 = .{
80 .addr = @bitCast(u32, address.host.octets),73 .addr = @bitCast(u32, address.host.octets),
81 .port = mem.nativeToBig(u16, address.port),74 .port = mem.nativeToBig(u16, address.port),
82 },
83 },75 },
84 .ipv6 => |address| .{76 },
85 .ipv6 = .{77 .ipv6 => |address| .{
86 .addr = address.host.octets,78 .ipv6 = .{
87 .port = mem.nativeToBig(u16, address.port),79 .addr = address.host.octets,
88 .scope_id = address.host.scope_id,80 .port = mem.nativeToBig(u16, address.port),
89 .flowinfo = 0,81 .scope_id = address.host.scope_id,
90 },82 .flowinfo = 0,
91 },83 },
92 };84 },
93 }85 };
86 }
9487
95 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address. 88 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
96 pub fn getNativeSize(self: Self.Address) u32 {89 pub fn getNativeSize(self: Socket.Address) u32 {
97 return switch (self) {90 return switch (self) {
98 .ipv4 => @sizeOf(os.sockaddr_in),91 .ipv4 => @sizeOf(os.sockaddr_in),
99 .ipv6 => @sizeOf(os.sockaddr_in6),92 .ipv6 => @sizeOf(os.sockaddr_in6),
100 };93 };
101 }94 }
10295
103 /// Implements the `std.fmt.format` API.96 /// Implements the `std.fmt.format` API.
104 pub fn format(97 pub fn format(
105 self: Self.Address,98 self: Socket.Address,
106 comptime layout: []const u8,99 comptime layout: []const u8,
107 opts: fmt.FormatOptions,100 opts: fmt.FormatOptions,
108 writer: anytype,101 writer: anytype,
109 ) !void {102 ) !void {
110 switch (self) {103 switch (self) {
111 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),104 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
112 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),105 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
113 }
114 }106 }
115 };107 }
116 };108 };
117}109
110 /// The underlying handle of a socket.
111 fd: os.socket_t,
112
113 /// Enclose a socket abstraction over an existing socket file descriptor.
114 pub fn from(fd: os.socket_t) Socket {
115 return Socket{ .fd = fd };
116 }
117
118 /// Mix in socket syscalls depending on the platform we are compiling against.
119 pub usingnamespace switch (builtin.os.tag) {
120 .windows => @import("socket_windows.zig"),
121 else => @import("socket_posix.zig"),
122 }.Mixin(Socket);
123};
lib/std/x/os/socket_posix.zig+237-227
...@@ -10,232 +10,242 @@ const os = std.os;...@@ -10,232 +10,242 @@ const os = std.os;
10const mem = std.mem;10const mem = std.mem;
11const time = std.time;11const time = std.time;
1212
13pub const Socket = struct {13pub fn Mixin(comptime Socket: type) type {
14 /// Import in `Socket.Address` and `Socket.Connection`.14 return struct {
15 pub usingnamespace @import("socket.zig").Mixin(Socket);15 /// Open a new socket.
1616 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
17 /// The underlying handle of a socket.17 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
18 fd: os.socket_t,18 }
1919
20 /// Open a new socket.20 /// Closes the socket.
21 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {21 pub fn deinit(self: Socket) void {
22 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };22 os.closeSocket(self.fd);
23 }23 }
2424
25 /// Enclose a socket abstraction over an existing socket file descriptor.25 /// Shutdown either the read side, write side, or all side of the socket.
26 pub fn from(fd: os.socket_t) Socket {26 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
27 return Socket{ .fd = fd };27 return os.shutdown(self.fd, how);
28 }28 }
2929
30 /// Closes the socket.30 /// Binds the socket to an address.
31 pub fn deinit(self: Socket) void {31 pub fn bind(self: Socket, address: Socket.Address) !void {
32 os.closeSocket(self.fd);32 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
33 }33 }
3434
35 /// Shutdown either the read side, write side, or all side of the socket.35 /// Start listening for incoming connections on the socket.
36 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {36 pub fn listen(self: Socket, max_backlog_size: u31) !void {
37 return os.shutdown(self.fd, how);37 return os.listen(self.fd, max_backlog_size);
38 }38 }
3939
40 /// Binds the socket to an address.40 /// Have the socket attempt to the connect to an address.
41 pub fn bind(self: Socket, address: Socket.Address) !void {41 pub fn connect(self: Socket, address: Socket.Address) !void {
42 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());42 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
43 }43 }
4444
45 /// Start listening for incoming connections on the socket.45 /// Accept a pending incoming connection queued to the kernel backlog
46 pub fn listen(self: Socket, max_backlog_size: u31) !void {46 /// of the socket.
47 return os.listen(self.fd, max_backlog_size);47 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
48 }48 var address: os.sockaddr_storage = undefined;
4949 var address_len: u32 = @sizeOf(os.sockaddr_storage);
50 /// Have the socket attempt to the connect to an address.50
51 pub fn connect(self: Socket, address: Socket.Address) !void {51 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
52 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());52 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
53 }53
5454 return Socket.Connection.from(socket, socket_address);
55 /// Accept a pending incoming connection queued to the kernel backlog55 }
56 /// of the socket.56
57 pub fn accept(self: Socket, flags: u32) !Socket.Connection {57 /// Read data from the socket into the buffer provided with a set of flags
58 var address: os.sockaddr_storage = undefined;58 /// specified. It returns the number of bytes read into the buffer provided.
59 var address_len: u32 = @sizeOf(os.sockaddr_storage);59 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
6060 return os.recv(self.fd, buf, flags);
61 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };61 }
62 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));62
6363 /// Write a buffer of data provided to the socket with a set of flags specified.
64 return Socket.Connection.from(socket, socket_address);64 /// It returns the number of bytes that are written to the socket.
65 }65 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
6666 return os.send(self.fd, buf, flags);
67 /// Read data from the socket into the buffer provided with a set of flags67 }
68 /// specified. It returns the number of bytes read into the buffer provided.68
69 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {69 /// Writes multiple I/O vectors with a prepended message header to the socket
70 return os.recv(self.fd, buf, flags);70 /// with a set of flags specified. It returns the number of bytes that are
71 }71 /// written to the socket.
7272 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
73 /// Write a buffer of data provided to the socket with a set of flags specified.73 return os.sendmsg(self.fd, msg, flags);
74 /// It returns the number of bytes that are written to the socket.74 }
75 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {75
76 return os.send(self.fd, buf, flags);76 /// Read multiple I/O vectors with a prepended message header from the socket
77 }77 /// with a set of flags specified. It returns the number of bytes that were
7878 /// read into the buffer provided.
79 /// Writes multiple I/O vectors with a prepended message header to the socket79 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
80 /// with a set of flags specified. It returns the number of bytes that are80 if (comptime @hasDecl(os.system, "recvmsg")) {
81 /// written to the socket.81 while (true) {
82 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {82 const rc = os.system.recvmsg(self.fd, msg, flags);
83 return os.sendmsg(self.fd, msg, flags);83 return switch (os.errno(rc)) {
84 }84 0 => @intCast(usize, rc),
8585 os.EBADF => unreachable, // always a race condition
86 /// Read multiple I/O vectors with a prepended message header from the socket86 os.EFAULT => unreachable,
87 /// with a set of flags specified. It returns the number of bytes that were87 os.EINVAL => unreachable,
88 /// read into the buffer provided.88 os.ENOTCONN => unreachable,
89 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {89 os.ENOTSOCK => unreachable,
90 return error.NotImplemented;90 os.EINTR => continue,
91 }91 os.EAGAIN => error.WouldBlock,
9292 os.ENOMEM => error.SystemResources,
93 /// Query the address that the socket is locally bounded to.93 os.ECONNREFUSED => error.ConnectionRefused,
94 pub fn getLocalAddress(self: Socket) !Socket.Address {94 os.ECONNRESET => error.ConnectionResetByPeer,
95 var address: os.sockaddr_storage = undefined;95 else => |err| os.unexpectedErrno(err),
96 var address_len: u32 = @sizeOf(os.sockaddr_storage);96 };
97 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);97 }
98 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));98 }
99 }99 return error.NotSupported;
100100 }
101 /// Query the address that the socket is connected to.101
102 pub fn getRemoteAddress(self: Socket) !Socket.Address {102 /// Query the address that the socket is locally bounded to.
103 var address: os.sockaddr_storage = undefined;103 pub fn getLocalAddress(self: Socket) !Socket.Address {
104 var address_len: u32 = @sizeOf(os.sockaddr_storage);104 var address: os.sockaddr_storage = undefined;
105 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);105 var address_len: u32 = @sizeOf(os.sockaddr_storage);
106 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));106 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
107 }107 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
108108 }
109 /// Query and return the latest cached error on the socket.109
110 pub fn getError(self: Socket) !void {110 /// Query the address that the socket is connected to.
111 return os.getsockoptError(self.fd);111 pub fn getRemoteAddress(self: Socket) !Socket.Address {
112 }112 var address: os.sockaddr_storage = undefined;
113113 var address_len: u32 = @sizeOf(os.sockaddr_storage);
114 /// Query the read buffer size of the socket.114 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
115 pub fn getReadBufferSize(self: Socket) !u32 {115 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
116 var value: u32 = undefined;116 }
117 var value_len: u32 = @sizeOf(u32);117
118118 /// Query and return the latest cached error on the socket.
119 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);119 pub fn getError(self: Socket) !void {
120 return switch (os.errno(rc)) {120 return os.getsockoptError(self.fd);
121 0 => value,121 }
122 os.EBADF => error.BadFileDescriptor,122
123 os.EFAULT => error.InvalidAddressSpace,123 /// Query the read buffer size of the socket.
124 os.EINVAL => error.InvalidSocketOption,124 pub fn getReadBufferSize(self: Socket) !u32 {
125 os.ENOPROTOOPT => error.UnknownSocketOption,125 var value: u32 = undefined;
126 os.ENOTSOCK => error.NotASocket,126 var value_len: u32 = @sizeOf(u32);
127 else => |err| os.unexpectedErrno(err),127
128 };128 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
129 }129 return switch (os.errno(rc)) {
130130 0 => value,
131 /// Query the write buffer size of the socket.131 os.EBADF => error.BadFileDescriptor,
132 pub fn getWriteBufferSize(self: Socket) !u32 {132 os.EFAULT => error.InvalidAddressSpace,
133 var value: u32 = undefined;133 os.EINVAL => error.InvalidSocketOption,
134 var value_len: u32 = @sizeOf(u32);134 os.ENOPROTOOPT => error.UnknownSocketOption,
135135 os.ENOTSOCK => error.NotASocket,
136 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);136 else => |err| os.unexpectedErrno(err),
137 return switch (os.errno(rc)) {
138 0 => value,
139 os.EBADF => error.BadFileDescriptor,
140 os.EFAULT => error.InvalidAddressSpace,
141 os.EINVAL => error.InvalidSocketOption,
142 os.ENOPROTOOPT => error.UnknownSocketOption,
143 os.ENOTSOCK => error.NotASocket,
144 else => |err| os.unexpectedErrno(err),
145 };
146 }
147
148 /// Set a socket option.
149 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
150 return os.setsockopt(self.fd, level, code, value);
151 }
152
153 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
154 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
155 /// if the host does not support the option for a socket to linger around up until a timeout specified in
156 /// seconds.
157 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
158 if (comptime @hasDecl(os, "SO_LINGER")) {
159 const settings = extern struct {
160 l_onoff: c_int,
161 l_linger: c_int,
162 }{
163 .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)),
164 .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0,
165 };137 };
138 }
139
140 /// Query the write buffer size of the socket.
141 pub fn getWriteBufferSize(self: Socket) !u32 {
142 var value: u32 = undefined;
143 var value_len: u32 = @sizeOf(u32);
144
145 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
146 return switch (os.errno(rc)) {
147 0 => value,
148 os.EBADF => error.BadFileDescriptor,
149 os.EFAULT => error.InvalidAddressSpace,
150 os.EINVAL => error.InvalidSocketOption,
151 os.ENOPROTOOPT => error.UnknownSocketOption,
152 os.ENOTSOCK => error.NotASocket,
153 else => |err| os.unexpectedErrno(err),
154 };
155 }
156
157 /// Set a socket option.
158 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
159 return os.setsockopt(self.fd, level, code, value);
160 }
161
162 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
163 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
164 /// if the host does not support the option for a socket to linger around up until a timeout specified in
165 /// seconds.
166 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
167 if (comptime @hasDecl(os, "SO_LINGER")) {
168 const settings = extern struct {
169 l_onoff: c_int,
170 l_linger: c_int,
171 }{
172 .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)),
173 .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0,
174 };
175
176 return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings));
177 }
178
179 return error.UnsupportedSocketOption;
180 }
181
182 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
183 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
184 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
185 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
186 if (comptime @hasDecl(os, "SO_KEEPALIVE")) {
187 return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
188 }
189 return error.UnsupportedSocketOption;
190 }
191
192 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
193 /// the host does not support sockets listening the same address.
194 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
195 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
196 return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
197 }
198 return error.UnsupportedSocketOption;
199 }
166200
167 return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings));201 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
168 }202 /// the host does not supports sockets listening on the same port.
169203 pub fn setReusePort(self: Socket, enabled: bool) !void {
170 return error.UnsupportedSocketOption;204 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
171 }205 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));
172206 }
173 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive207 return error.UnsupportedSocketOption;
174 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if208 }
175 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets. 209
176 pub fn setKeepAlive(self: Socket, enabled: bool) !void {210 /// Set the write buffer size of the socket.
177 if (comptime @hasDecl(os, "SO_KEEPALIVE")) {211 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
178 return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));212 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
179 }213 }
180 return error.UnsupportedSocketOption;214
181 }215 /// Set the read buffer size of the socket.
182216 pub fn setReadBufferSize(self: Socket, size: u32) !void {
183 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if217 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
184 /// the host does not support sockets listening the same address.218 }
185 pub fn setReuseAddress(self: Socket, enabled: bool) !void {219
186 if (comptime @hasDecl(os, "SO_REUSEADDR")) {220 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
187 return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));221 /// set on a non-blocking socket.
188 }222 ///
189 return error.UnsupportedSocketOption;223 /// Set a timeout on the socket that is to occur if no messages are successfully written
190 }224 /// to its bound destination after a specified number of milliseconds. A subsequent write
191225 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
192 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if226 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
193 /// the host does not supports sockets listening on the same port.227 const timeout = os.timeval{
194 pub fn setReusePort(self: Socket, enabled: bool) !void {228 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
195 if (comptime @hasDecl(os, "SO_REUSEPORT")) {229 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
196 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));230 };
197 }231
198 return error.UnsupportedSocketOption;232 return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
199 }233 }
200234
201 /// Set the write buffer size of the socket.235 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
202 pub fn setWriteBufferSize(self: Socket, size: u32) !void {236 /// set on a non-blocking socket.
203 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));237 ///
204 }238 /// Set a timeout on the socket that is to occur if no messages are successfully read
205239 /// from its bound destination after a specified number of milliseconds. A subsequent
206 /// Set the read buffer size of the socket.240 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
207 pub fn setReadBufferSize(self: Socket, size: u32) !void {241 /// exceeded.
208 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));242 pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
209 }243 const timeout = os.timeval{
210244 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
211 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is245 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
212 /// set on a non-blocking socket.246 };
213 /// 247
214 /// Set a timeout on the socket that is to occur if no messages are successfully written248 return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
215 /// to its bound destination after a specified number of milliseconds. A subsequent write249 }
216 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.250 };
217 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {251}
218 const timeout = os.timeval{
219 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
220 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
221 };
222
223 return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
224 }
225
226 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
227 /// set on a non-blocking socket.
228 ///
229 /// Set a timeout on the socket that is to occur if no messages are successfully read
230 /// from its bound destination after a specified number of milliseconds. A subsequent
231 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
232 /// exceeded.
233 pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
234 const timeout = os.timeval{
235 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
236 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
237 };
238
239 return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
240 }
241};
lib/std/x/os/socket_windows.zig+412-360
...@@ -13,386 +13,438 @@ const mem = std.mem;...@@ -13,386 +13,438 @@ const mem = std.mem;
13const windows = std.os.windows;13const windows = std.os.windows;
14const ws2_32 = windows.ws2_32;14const ws2_32 = windows.ws2_32;
1515
16pub const Socket = struct {16pub fn Mixin(comptime Socket: type) type {
17 /// Import in `Socket.Address` and `Socket.Connection`.17 return struct {
18 pub usingnamespace @import("socket.zig").Mixin(Socket);18 /// Open a new socket.
19 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
20 var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);
21
22 var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;
23 if (socket_type & os.SOCK_CLOEXEC != 0) {
24 filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
25 }
26
27 const fd = ws2_32.WSASocketW(
28 @intCast(i32, domain),
29 @intCast(i32, filtered_socket_type),
30 @intCast(i32, protocol),
31 null,
32 0,
33 filtered_flags,
34 );
35 if (fd == ws2_32.INVALID_SOCKET) {
36 return switch (ws2_32.WSAGetLastError()) {
37 .WSANOTINITIALISED => {
38 _ = try windows.WSAStartup(2, 2);
39 return Socket.init(domain, socket_type, protocol);
40 },
41 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
42 .WSAEMFILE => error.ProcessFdQuotaExceeded,
43 .WSAENOBUFS => error.SystemResources,
44 .WSAEPROTONOSUPPORT => error.ProtocolNotSupported,
45 else => |err| windows.unexpectedWSAError(err),
46 };
47 }
48
49 return Socket{ .fd = fd };
50 }
1951
20 /// The underlying handle of a socket.52 /// Closes the socket.
21 fd: os.socket_t,53 pub fn deinit(self: Socket) void {
54 _ = ws2_32.closesocket(self.fd);
55 }
2256
23 /// Open a new socket.57 /// Shutdown either the read side, write side, or all side of the socket.
24 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {58 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
25 var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);59 const rc = ws2_32.shutdown(self.fd, switch (how) {
60 .recv => ws2_32.SD_RECEIVE,
61 .send => ws2_32.SD_SEND,
62 .both => ws2_32.SD_BOTH,
63 });
64 if (rc == ws2_32.SOCKET_ERROR) {
65 return switch (ws2_32.WSAGetLastError()) {
66 .WSAECONNABORTED => return error.ConnectionAborted,
67 .WSAECONNRESET => return error.ConnectionResetByPeer,
68 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
69 .WSAEINVAL => unreachable,
70 .WSAENETDOWN => return error.NetworkSubsystemFailed,
71 .WSAENOTCONN => return error.SocketNotConnected,
72 .WSAENOTSOCK => unreachable,
73 .WSANOTINITIALISED => unreachable,
74 else => |err| return windows.unexpectedWSAError(err),
75 };
76 }
77 }
2678
27 var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;79 /// Binds the socket to an address.
28 if (socket_type & os.SOCK_CLOEXEC != 0) {80 pub fn bind(self: Socket, address: Socket.Address) !void {
29 filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;81 const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
82 if (rc == ws2_32.SOCKET_ERROR) {
83 return switch (ws2_32.WSAGetLastError()) {
84 .WSAENETDOWN => error.NetworkSubsystemFailed,
85 .WSAEACCES => error.AccessDenied,
86 .WSAEADDRINUSE => error.AddressInUse,
87 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
88 .WSAEFAULT => error.BadAddress,
89 .WSAEINPROGRESS => error.WouldBlock,
90 .WSAEINVAL => error.AlreadyBound,
91 .WSAENOBUFS => error.NoEphemeralPortsAvailable,
92 .WSAENOTSOCK => error.NotASocket,
93 else => |err| windows.unexpectedWSAError(err),
94 };
95 }
30 }96 }
3197
32 const fd = ws2_32.WSASocketW(98 /// Start listening for incoming connections on the socket.
33 @intCast(i32, domain),99 pub fn listen(self: Socket, max_backlog_size: u31) !void {
34 @intCast(i32, filtered_socket_type),100 const rc = ws2_32.listen(self.fd, max_backlog_size);
35 @intCast(i32, protocol),101 if (rc == ws2_32.SOCKET_ERROR) {
36 null,102 return switch (ws2_32.WSAGetLastError()) {
37 0,103 .WSAENETDOWN => error.NetworkSubsystemFailed,
38 filtered_flags,104 .WSAEADDRINUSE => error.AddressInUse,
39 );105 .WSAEISCONN => error.AlreadyConnected,
40 if (fd == ws2_32.INVALID_SOCKET) {106 .WSAEINVAL => error.SocketNotBound,
41 return switch (ws2_32.WSAGetLastError()) {107 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,
42 .WSANOTINITIALISED => {108 .WSAENOTSOCK => error.FileDescriptorNotASocket,
43 _ = try windows.WSAStartup(2, 2);109 .WSAEOPNOTSUPP => error.OperationNotSupported,
44 return Socket.init(domain, socket_type, protocol);110 .WSAEINPROGRESS => error.WouldBlock,
45 },111 else => |err| windows.unexpectedWSAError(err),
46 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,112 };
47 .WSAEMFILE => error.ProcessFdQuotaExceeded,113 }
48 .WSAENOBUFS => error.SystemResources,
49 .WSAEPROTONOSUPPORT => error.ProtocolNotSupported,
50 else => |err| windows.unexpectedWSAError(err),
51 };
52 }114 }
53115
54 return Socket{ .fd = fd };116 /// Have the socket attempt to the connect to an address.
55 }117 pub fn connect(self: Socket, address: Socket.Address) !void {
56118 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
57 /// Enclose a socket abstraction over an existing socket file descriptor.119 if (rc == ws2_32.SOCKET_ERROR) {
58 pub fn from(fd: os.socket_t) Socket {120 return switch (ws2_32.WSAGetLastError()) {
59 return Socket{ .fd = fd };121 .WSAEADDRINUSE => error.AddressInUse,
60 }122 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
61123 .WSAECONNREFUSED => error.ConnectionRefused,
62 /// Closes the socket.124 .WSAETIMEDOUT => error.ConnectionTimedOut,
63 pub fn deinit(self: Socket) void {125 .WSAEFAULT => error.BadAddress,
64 _ = ws2_32.closesocket(self.fd);126 .WSAEINVAL => error.ListeningSocket,
65 }127 .WSAEISCONN => error.AlreadyConnected,
66128 .WSAENOTSOCK => error.NotASocket,
67 /// Shutdown either the read side, write side, or all side of the socket.129 .WSAEACCES => error.BroadcastNotEnabled,
68 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {130 .WSAENOBUFS => error.SystemResources,
69 const rc = ws2_32.shutdown(self.fd, switch (how) {131 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
70 .recv => ws2_32.SD_RECEIVE,132 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,
71 .send => ws2_32.SD_SEND,133 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,
72 .both => ws2_32.SD_BOTH,134 else => |err| windows.unexpectedWSAError(err),
73 });135 };
74 if (rc == ws2_32.SOCKET_ERROR) {136 }
75 return switch (ws2_32.WSAGetLastError()) {
76 .WSAECONNABORTED => return error.ConnectionAborted,
77 .WSAECONNRESET => return error.ConnectionResetByPeer,
78 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
79 .WSAEINVAL => unreachable,
80 .WSAENETDOWN => return error.NetworkSubsystemFailed,
81 .WSAENOTCONN => return error.SocketNotConnected,
82 .WSAENOTSOCK => unreachable,
83 .WSANOTINITIALISED => unreachable,
84 else => |err| return windows.unexpectedWSAError(err),
85 };
86 }137 }
87 }138
88139 /// Accept a pending incoming connection queued to the kernel backlog
89 /// Binds the socket to an address.140 /// of the socket.
90 pub fn bind(self: Socket, address: Socket.Address) !void {141 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
91 const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));142 var address: ws2_32.sockaddr_storage = undefined;
92 if (rc == ws2_32.SOCKET_ERROR) {143 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
93 return switch (ws2_32.WSAGetLastError()) {144
94 .WSAENETDOWN => error.NetworkSubsystemFailed,145 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
95 .WSAEACCES => error.AccessDenied,146 if (rc == ws2_32.INVALID_SOCKET) {
96 .WSAEADDRINUSE => error.AddressInUse,147 return switch (ws2_32.WSAGetLastError()) {
97 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,148 .WSANOTINITIALISED => unreachable,
98 .WSAEFAULT => error.BadAddress,149 .WSAECONNRESET => error.ConnectionResetByPeer,
99 .WSAEINPROGRESS => error.WouldBlock,150 .WSAEFAULT => unreachable,
100 .WSAEINVAL => error.AlreadyBound,151 .WSAEINVAL => error.SocketNotListening,
101 .WSAENOBUFS => error.NoEphemeralPortsAvailable,152 .WSAEMFILE => error.ProcessFdQuotaExceeded,
102 .WSAENOTSOCK => error.NotASocket,153 .WSAENETDOWN => error.NetworkSubsystemFailed,
103 else => |err| windows.unexpectedWSAError(err),154 .WSAENOBUFS => error.FileDescriptorNotASocket,
104 };155 .WSAEOPNOTSUPP => error.OperationNotSupported,
156 .WSAEWOULDBLOCK => error.WouldBlock,
157 else => |err| windows.unexpectedWSAError(err),
158 };
159 }
160
161 const socket = Socket.from(rc);
162 const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
163
164 return Socket.Connection.from(socket, socket_address);
105 }165 }
106 }166
107167 /// Read data from the socket into the buffer provided with a set of flags
108 /// Start listening for incoming connections on the socket.168 /// specified. It returns the number of bytes read into the buffer provided.
109 pub fn listen(self: Socket, max_backlog_size: u31) !void {169 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
110 const rc = ws2_32.listen(self.fd, max_backlog_size);170 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
111 if (rc == ws2_32.SOCKET_ERROR) {171 var num_bytes: u32 = undefined;
112 return switch (ws2_32.WSAGetLastError()) {172 var flags_ = flags;
113 .WSAENETDOWN => error.NetworkSubsystemFailed,173
114 .WSAEADDRINUSE => error.AddressInUse,174 const rc = ws2_32.WSARecv(self.fd, bufs, 1, &num_bytes, &flags_, null, null);
115 .WSAEISCONN => error.AlreadyConnected,175 if (rc == ws2_32.SOCKET_ERROR) {
116 .WSAEINVAL => error.SocketNotBound,176 return switch (ws2_32.WSAGetLastError()) {
117 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,177 .WSAECONNABORTED => error.ConnectionAborted,
118 .WSAENOTSOCK => error.FileDescriptorNotASocket,178 .WSAECONNRESET => error.ConnectionResetByPeer,
119 .WSAEOPNOTSUPP => error.OperationNotSupported,179 .WSAEDISCON => error.ConnectionClosedByPeer,
120 .WSAEINPROGRESS => error.WouldBlock,180 .WSAEFAULT => error.BadBuffer,
121 else => |err| windows.unexpectedWSAError(err),181 .WSAEINPROGRESS,
122 };182 .WSAEWOULDBLOCK,
183 .WSA_IO_PENDING,
184 .WSAETIMEDOUT,
185 => error.WouldBlock,
186 .WSAEINTR => error.Cancelled,
187 .WSAEINVAL => error.SocketNotBound,
188 .WSAEMSGSIZE => error.MessageTooLarge,
189 .WSAENETDOWN => error.NetworkSubsystemFailed,
190 .WSAENETRESET => error.NetworkReset,
191 .WSAENOTCONN => error.SocketNotConnected,
192 .WSAENOTSOCK => error.FileDescriptorNotASocket,
193 .WSAEOPNOTSUPP => error.OperationNotSupported,
194 .WSAESHUTDOWN => error.AlreadyShutdown,
195 .WSA_OPERATION_ABORTED => error.OperationAborted,
196 else => |err| windows.unexpectedWSAError(err),
197 };
198 }
199
200 return @intCast(usize, num_bytes);
123 }201 }
124 }202
125203 /// Write a buffer of data provided to the socket with a set of flags specified.
126 /// Have the socket attempt to the connect to an address.204 /// It returns the number of bytes that are written to the socket.
127 pub fn connect(self: Socket, address: Socket.Address) !void {205 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
128 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));206 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = @intToPtr([*]u8, @ptrToInt(buf.ptr)) }};
129 if (rc == ws2_32.SOCKET_ERROR) {207 var num_bytes: u32 = undefined;
130 return switch (ws2_32.WSAGetLastError()) {208
131 .WSAEADDRINUSE => error.AddressInUse,209 const rc = ws2_32.WSASend(self.fd, bufs, 1, &num_bytes, flags, null, null);
132 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,210 if (rc == ws2_32.SOCKET_ERROR) {
133 .WSAECONNREFUSED => error.ConnectionRefused,211 return switch (ws2_32.WSAGetLastError()) {
134 .WSAETIMEDOUT => error.ConnectionTimedOut,212 .WSAECONNABORTED => error.ConnectionAborted,
135 .WSAEFAULT => error.BadAddress,213 .WSAECONNRESET => error.ConnectionResetByPeer,
136 .WSAEINVAL => error.ListeningSocket,214 .WSAEFAULT => error.BadBuffer,
137 .WSAEISCONN => error.AlreadyConnected,215 .WSAEINPROGRESS,
138 .WSAENOTSOCK => error.NotASocket,216 .WSAEWOULDBLOCK,
139 .WSAEACCES => error.BroadcastNotEnabled,217 .WSA_IO_PENDING,
140 .WSAENOBUFS => error.SystemResources,218 .WSAETIMEDOUT,
141 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,219 => error.WouldBlock,
142 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,220 .WSAEINTR => error.Cancelled,
143 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,221 .WSAEINVAL => error.SocketNotBound,
144 else => |err| windows.unexpectedWSAError(err),222 .WSAEMSGSIZE => error.MessageTooLarge,
145 };223 .WSAENETDOWN => error.NetworkSubsystemFailed,
224 .WSAENETRESET => error.NetworkReset,
225 .WSAENOBUFS => error.BufferDeadlock,
226 .WSAENOTCONN => error.SocketNotConnected,
227 .WSAENOTSOCK => error.FileDescriptorNotASocket,
228 .WSAEOPNOTSUPP => error.OperationNotSupported,
229 .WSAESHUTDOWN => error.AlreadyShutdown,
230 .WSA_OPERATION_ABORTED => error.OperationAborted,
231 else => |err| windows.unexpectedWSAError(err),
232 };
233 }
234
235 return @intCast(usize, num_bytes);
146 }236 }
147 }237
148238 /// Writes multiple I/O vectors with a prepended message header to the socket
149 /// Accept a pending incoming connection queued to the kernel backlog239 /// with a set of flags specified. It returns the number of bytes that are
150 /// of the socket.240 /// written to the socket.
151 pub fn accept(self: Socket, flags: u32) !Socket.Connection {241 pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize {
152 var address: ws2_32.sockaddr_storage = undefined;242 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG);
153 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);243
154244 var num_bytes: u32 = undefined;
155 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);245
156 if (rc == ws2_32.INVALID_SOCKET) {246 const rc = call(self.fd, &msg, flags, &num_bytes, null, null);
157 return switch (ws2_32.WSAGetLastError()) {247 if (rc == ws2_32.SOCKET_ERROR) {
158 .WSANOTINITIALISED => unreachable,248 return switch (ws2_32.WSAGetLastError()) {
159 .WSAECONNRESET => error.ConnectionResetByPeer,249 .WSAECONNABORTED => error.ConnectionAborted,
160 .WSAEFAULT => unreachable,250 .WSAECONNRESET => error.ConnectionResetByPeer,
161 .WSAEINVAL => error.SocketNotListening,251 .WSAEFAULT => error.BadBuffer,
162 .WSAEMFILE => error.ProcessFdQuotaExceeded,252 .WSAEINPROGRESS,
163 .WSAENETDOWN => error.NetworkSubsystemFailed,253 .WSAEWOULDBLOCK,
164 .WSAENOBUFS => error.FileDescriptorNotASocket,254 .WSA_IO_PENDING,
165 .WSAEOPNOTSUPP => error.OperationNotSupported,255 .WSAETIMEDOUT,
166 .WSAEWOULDBLOCK => error.WouldBlock,256 => error.WouldBlock,
167 else => |err| windows.unexpectedWSAError(err),257 .WSAEINTR => error.Cancelled,
168 };258 .WSAEINVAL => error.SocketNotBound,
259 .WSAEMSGSIZE => error.MessageTooLarge,
260 .WSAENETDOWN => error.NetworkSubsystemFailed,
261 .WSAENETRESET => error.NetworkReset,
262 .WSAENOBUFS => error.BufferDeadlock,
263 .WSAENOTCONN => error.SocketNotConnected,
264 .WSAENOTSOCK => error.FileDescriptorNotASocket,
265 .WSAEOPNOTSUPP => error.OperationNotSupported,
266 .WSAESHUTDOWN => error.AlreadyShutdown,
267 .WSA_OPERATION_ABORTED => error.OperationAborted,
268 else => |err| windows.unexpectedWSAError(err),
269 };
270 }
271
272 return @intCast(usize, num_bytes);
169 }273 }
170274
171 const socket = Socket.from(rc);275 /// Read multiple I/O vectors with a prepended message header from the socket
172 const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));276 /// with a set of flags specified. It returns the number of bytes that were
173277 /// read into the buffer provided.
174 return Socket.Connection.from(socket, socket_address);278 pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize {
175 }279 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG);
176280
177 /// Read data from the socket into the buffer provided with a set of flags281 var num_bytes: u32 = undefined;
178 /// specified. It returns the number of bytes read into the buffer provided.282
179 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {283 const rc = call(self.fd, msg, &num_bytes, null, null);
180 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};284 if (rc == ws2_32.SOCKET_ERROR) {
181 var flags_ = flags;285 return switch (ws2_32.WSAGetLastError()) {
182286 .WSAECONNABORTED => error.ConnectionAborted,
183 const rc = ws2_32.WSARecv(self.fd, bufs, 1, null, &flags_, null, null);287 .WSAECONNRESET => error.ConnectionResetByPeer,
184 if (rc == ws2_32.SOCKET_ERROR) {288 .WSAEDISCON => error.ConnectionClosedByPeer,
185 return switch (ws2_32.WSAGetLastError()) {289 .WSAEFAULT => error.BadBuffer,
186 .WSAECONNABORTED => error.ConnectionAborted,290 .WSAEINPROGRESS,
187 .WSAECONNRESET => error.ConnectionResetByPeer,291 .WSAEWOULDBLOCK,
188 .WSAEDISCON => error.ConnectionClosedByPeer,292 .WSA_IO_PENDING,
189 .WSAEFAULT => error.BadBuffer,293 .WSAETIMEDOUT,
190 .WSAEINPROGRESS,294 => error.WouldBlock,
191 .WSAEWOULDBLOCK,295 .WSAEINTR => error.Cancelled,
192 .WSA_IO_PENDING,296 .WSAEINVAL => error.SocketNotBound,
193 .WSAETIMEDOUT,297 .WSAEMSGSIZE => error.MessageTooLarge,
194 => error.WouldBlock,298 .WSAENETDOWN => error.NetworkSubsystemFailed,
195 .WSAEINTR => error.Cancelled,299 .WSAENETRESET => error.NetworkReset,
196 .WSAEINVAL => error.SocketNotBound,300 .WSAENOTCONN => error.SocketNotConnected,
197 .WSAEMSGSIZE => error.MessageTooLarge,301 .WSAENOTSOCK => error.FileDescriptorNotASocket,
198 .WSAENETDOWN => error.NetworkSubsystemFailed,302 .WSAEOPNOTSUPP => error.OperationNotSupported,
199 .WSAENETRESET => error.NetworkReset,303 .WSAESHUTDOWN => error.AlreadyShutdown,
200 .WSAENOTCONN => error.SocketNotConnected,304 .WSA_OPERATION_ABORTED => error.OperationAborted,
201 .WSAENOTSOCK => error.FileDescriptorNotASocket,305 else => |err| windows.unexpectedWSAError(err),
202 .WSAEOPNOTSUPP => error.OperationNotSupported,306 };
203 .WSAESHUTDOWN => error.AlreadyShutdown,307 }
204 .WSA_OPERATION_ABORTED => error.OperationAborted,308
205 else => |err| windows.unexpectedWSAError(err),309 return @intCast(usize, num_bytes);
206 };
207 }310 }
208311
209 return @intCast(usize, rc);312 /// Query the address that the socket is locally bounded to.
210 }313 pub fn getLocalAddress(self: Socket) !Socket.Address {
211314 var address: ws2_32.sockaddr_storage = undefined;
212 /// Write a buffer of data provided to the socket with a set of flags specified.315 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
213 /// It returns the number of bytes that are written to the socket.316
214 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {317 const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
215 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};318 if (rc == ws2_32.SOCKET_ERROR) {
216 var flags_ = flags;319 return switch (ws2_32.WSAGetLastError()) {
217320 .WSANOTINITIALISED => unreachable,
218 const rc = ws2_32.WSASend(self.fd, bufs, 1, null, &flags_, null, null);321 .WSAEFAULT => unreachable,
219 if (rc == ws2_32.SOCKET_ERROR) {322 .WSAENETDOWN => error.NetworkSubsystemFailed,
220 return switch (ws2_32.WSAGetLastError()) {323 .WSAENOTSOCK => error.FileDescriptorNotASocket,
221 .WSAECONNABORTED => error.ConnectionAborted,324 .WSAEINVAL => error.SocketNotBound,
222 .WSAECONNRESET => error.ConnectionResetByPeer,325 else => |err| windows.unexpectedWSAError(err),
223 .WSAEFAULT => error.BadBuffer,326 };
224 .WSAEINPROGRESS,327 }
225 .WSAEWOULDBLOCK,328
226 .WSA_IO_PENDING,329 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
227 .WSAETIMEDOUT,
228 => error.WouldBlock,
229 .WSAEINTR => error.Cancelled,
230 .WSAEINVAL => error.SocketNotBound,
231 .WSAEMSGSIZE => error.MessageTooLarge,
232 .WSAENETDOWN => error.NetworkSubsystemFailed,
233 .WSAENETRESET => error.NetworkReset,
234 .WSAENOBUFS => error.BufferDeadlock,
235 .WSAENOTCONN => error.SocketNotConnected,
236 .WSAENOTSOCK => error.FileDescriptorNotASocket,
237 .WSAEOPNOTSUPP => error.OperationNotSupported,
238 .WSAESHUTDOWN => error.AlreadyShutdown,
239 .WSA_OPERATION_ABORTED => error.OperationAborted,
240 else => |err| windows.unexpectedWSAError(err),
241 };
242 }330 }
243331
244 return @intCast(usize, rc);332 /// Query the address that the socket is connected to.
245 }333 pub fn getRemoteAddress(self: Socket) !Socket.Address {
246334 var address: ws2_32.sockaddr_storage = undefined;
247 /// Writes multiple I/O vectors with a prepended message header to the socket335 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
248 /// with a set of flags specified. It returns the number of bytes that are336
249 /// written to the socket.337 const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
250 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {338 if (rc == ws2_32.SOCKET_ERROR) {
251 return error.NotImplemented;339 return switch (ws2_32.WSAGetLastError()) {
252 }340 .WSANOTINITIALISED => unreachable,
253341 .WSAEFAULT => unreachable,
254 /// Read multiple I/O vectors with a prepended message header from the socket342 .WSAENETDOWN => error.NetworkSubsystemFailed,
255 /// with a set of flags specified. It returns the number of bytes that were343 .WSAENOTSOCK => error.FileDescriptorNotASocket,
256 /// read into the buffer provided.344 .WSAEINVAL => error.SocketNotBound,
257 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {345 else => |err| windows.unexpectedWSAError(err),
258 return error.NotImplemented;346 };
259 }347 }
260348
261 /// Query the address that the socket is locally bounded to.349 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
262 pub fn getLocalAddress(self: Socket) !Socket.Address {
263 var address: ws2_32.sockaddr_storage = undefined;
264 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
265
266 const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
267 if (rc == ws2_32.SOCKET_ERROR) {
268 return switch (ws2_32.WSAGetLastError()) {
269 .WSANOTINITIALISED => unreachable,
270 .WSAEFAULT => unreachable,
271 .WSAENETDOWN => error.NetworkSubsystemFailed,
272 .WSAENOTSOCK => error.FileDescriptorNotASocket,
273 .WSAEINVAL => error.SocketNotBound,
274 else => |err| windows.unexpectedWSAError(err),
275 };
276 }350 }
277351
278 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));352 /// Query and return the latest cached error on the socket.
279 }353 pub fn getError(self: Socket) !void {
280354 return {};
281 /// Query the address that the socket is connected to.355 }
282 pub fn getRemoteAddress(self: Socket) !Socket.Address {356
283 var address: ws2_32.sockaddr_storage = undefined;357 /// Query the read buffer size of the socket.
284 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);358 pub fn getReadBufferSize(self: Socket) !u32 {
285359 return 0;
286 const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
287 if (rc == ws2_32.SOCKET_ERROR) {
288 return switch (ws2_32.WSAGetLastError()) {
289 .WSANOTINITIALISED => unreachable,
290 .WSAEFAULT => unreachable,
291 .WSAENETDOWN => error.NetworkSubsystemFailed,
292 .WSAENOTSOCK => error.FileDescriptorNotASocket,
293 .WSAEINVAL => error.SocketNotBound,
294 else => |err| windows.unexpectedWSAError(err),
295 };
296 }360 }
297361
298 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));362 /// Query the write buffer size of the socket.
299 }363 pub fn getWriteBufferSize(self: Socket) !u32 {
300364 return 0;
301 /// Query and return the latest cached error on the socket.365 }
302 pub fn getError(self: Socket) !void {366
303 return {};367 /// Set a socket option.
304 }368 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
305369 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));
306 /// Query the read buffer size of the socket.370 if (rc == ws2_32.SOCKET_ERROR) {
307 pub fn getReadBufferSize(self: Socket) !u32 {371 return switch (ws2_32.WSAGetLastError()) {
308 return 0;372 .WSANOTINITIALISED => unreachable,
309 }373 .WSAENETDOWN => return error.NetworkSubsystemFailed,
310374 .WSAEFAULT => unreachable,
311 /// Query the write buffer size of the socket.375 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
312 pub fn getWriteBufferSize(self: Socket) !u32 {376 .WSAEINVAL => return error.SocketNotBound,
313 return 0;377 .WSAENOTCONN => return error.SocketNotConnected,
314 }378 .WSAESHUTDOWN => return error.AlreadyShutdown,
315379 else => |err| windows.unexpectedWSAError(err),
316 /// Set a socket option.380 };
317 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {381 }
318 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));382 }
319 if (rc == ws2_32.SOCKET_ERROR) {383
320 return switch (ws2_32.WSAGetLastError()) {384 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
321 .WSANOTINITIALISED => unreachable,385 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
322 .WSAENETDOWN => return error.NetworkSubsystemFailed,386 /// if the host does not support the option for a socket to linger around up until a timeout specified in
323 .WSAEFAULT => unreachable,387 /// seconds.
324 .WSAENOTSOCK => return error.FileDescriptorNotASocket,388 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
325 .WSAEINVAL => return error.SocketNotBound,389 const settings = ws2_32.linger{
326 .WSAENOTCONN => return error.SocketNotConnected,390 .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
327 .WSAESHUTDOWN => return error.AlreadyShutdown,391 .l_linger = if (timeout_seconds) |seconds| seconds else 0,
328 else => |err| windows.unexpectedWSAError(err),
329 };392 };
393
394 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings));
395 }
396
397 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
398 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
399 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
400 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
401 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
402 }
403
404 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
405 /// the host does not support sockets listening the same address.
406 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
407 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
408 }
409
410 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
411 /// the host does not supports sockets listening on the same port.
412 ///
413 /// TODO: verify if this truly mimicks SO_REUSEPORT behavior, or if SO_REUSE_UNICASTPORT provides the correct behavior
414 pub fn setReusePort(self: Socket, enabled: bool) !void {
415 try self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_BROADCAST, mem.asBytes(&@as(u32, @boolToInt(enabled))));
416 try self.setReuseAddress(enabled);
417 }
418
419 /// Set the write buffer size of the socket.
420 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
421 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDBUF, mem.asBytes(&size));
422 }
423
424 /// Set the read buffer size of the socket.
425 pub fn setReadBufferSize(self: Socket, size: u32) !void {
426 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVBUF, mem.asBytes(&size));
427 }
428
429 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
430 /// set on a non-blocking socket.
431 ///
432 /// Set a timeout on the socket that is to occur if no messages are successfully written
433 /// to its bound destination after a specified number of milliseconds. A subsequent write
434 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
435 pub fn setWriteTimeout(self: Socket, milliseconds: u32) !void {
436 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDTIMEO, mem.asBytes(&milliseconds));
437 }
438
439 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
440 /// set on a non-blocking socket.
441 ///
442 /// Set a timeout on the socket that is to occur if no messages are successfully read
443 /// from its bound destination after a specified number of milliseconds. A subsequent
444 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
445 /// exceeded.
446 pub fn setReadTimeout(self: Socket, milliseconds: u32) !void {
447 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVTIMEO, mem.asBytes(&milliseconds));
330 }448 }
331 }449 };
332450}
333 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
334 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
335 /// if the host does not support the option for a socket to linger around up until a timeout specified in
336 /// seconds.
337 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
338 const settings = ws2_32.linger{
339 .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
340 .l_linger = if (timeout_seconds) |seconds| seconds else 0,
341 };
342
343 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings));
344 }
345
346 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
347 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
348 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
349 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
350 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
351 }
352
353 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
354 /// the host does not support sockets listening the same address.
355 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
356 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
357 }
358
359 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
360 /// the host does not supports sockets listening on the same port.
361 ///
362 /// TODO: verify if this truly mimicks SO_REUSEPORT behavior, or if SO_REUSE_UNICASTPORT provides the correct behavior
363 pub fn setReusePort(self: Socket, enabled: bool) !void {
364 try self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_BROADCAST, mem.asBytes(&@as(u32, @boolToInt(enabled))));
365 try self.setReuseAddress(enabled);
366 }
367
368 /// Set the write buffer size of the socket.
369 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
370 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDBUF, mem.asBytes(&size));
371 }
372
373 /// Set the read buffer size of the socket.
374 pub fn setReadBufferSize(self: Socket, size: u32) !void {
375 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVBUF, mem.asBytes(&size));
376 }
377
378 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
379 /// set on a non-blocking socket.
380 ///
381 /// Set a timeout on the socket that is to occur if no messages are successfully written
382 /// to its bound destination after a specified number of milliseconds. A subsequent write
383 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
384 pub fn setWriteTimeout(self: Socket, milliseconds: u32) !void {
385 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDTIMEO, mem.asBytes(&milliseconds));
386 }
387
388 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
389 /// set on a non-blocking socket.
390 ///
391 /// Set a timeout on the socket that is to occur if no messages are successfully read
392 /// from its bound destination after a specified number of milliseconds. A subsequent
393 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
394 /// exceeded.
395 pub fn setReadTimeout(self: Socket, milliseconds: u32) !void {
396 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVTIMEO, mem.asBytes(&milliseconds));
397 }
398};