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 {
17491749 return (s << 10) | p;
17501750}
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
17521784/// Call this when you made a windows DLL call or something that does SetLastError
17531785/// and you get an unexpected error.
17541786pub 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;
266266pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75;
267267pub const BITS_PER_BYTE = 8;
268268pub const LOG2_BITS_PER_BYTE = 3;
269
269270pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}");
270271pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}");
271272pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}");
272273pub 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
273317pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0;
274318pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0;
275319pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1;
......@@ -485,6 +529,7 @@ pub const IOC_UNIX = 0;
485529pub const IOC_WS2 = 134217728;
486530pub const IOC_PROTOCOL = 268435456;
487531pub const IOC_VENDOR = 402653184;
532pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6;
488533pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27;
489534pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28;
490535pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29;
......@@ -1115,9 +1160,9 @@ pub const LPFN_GETACCEPTEXSOCKADDRS = fn (
11151160 RemoteSockaddrLength: *i32,
11161161) callconv(WINAPI) void;
11171162
1118pub const LFN_WSASENDMSG = fn (
1163pub const LPFN_WSASENDMSG = fn (
11191164 s: SOCKET,
1120 lpMsg: *WSAMSG_const,
1165 lpMsg: *const WSAMSG_const,
11211166 dwFlags: u32,
11221167 lpNumberOfBytesSent: ?*u32,
11231168 lpOverlapped: ?*OVERLAPPED,
......@@ -1927,7 +1972,7 @@ pub extern "ws2_32" fn WSAHtons(
19271972pub extern "ws2_32" fn WSAIoctl(
19281973 s: SOCKET,
19291974 dwIoControlCode: u32,
1930 lpvInBuffer: ?*c_void,
1975 lpvInBuffer: ?*const c_void,
19311976 cbInBuffer: u32,
19321977 lpvOutbuffer: ?*c_void,
19331978 cbOutbuffer: u32,
......@@ -1992,7 +2037,7 @@ pub extern "ws2_32" fn WSASend(
19922037 s: SOCKET,
19932038 lpBuffers: [*]WSABUF,
19942039 dwBufferCount: u32,
1995 lpNumberOfBytesSent: ?*U32,
2040 lpNumberOfBytesSent: ?*u32,
19962041 dwFlags: u32,
19972042 lpOverlapped: ?*OVERLAPPED,
19982043 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
......@@ -2000,7 +2045,7 @@ pub extern "ws2_32" fn WSASend(
20002045
20012046pub extern "ws2_32" fn WSASendMsg(
20022047 s: SOCKET,
2003 lpMsg: *WSAMSG_const,
2048 lpMsg: *const WSAMSG_const,
20042049 dwFlags: u32,
20052050 lpNumberOfBytesSent: ?*u32,
20062051 lpOverlapped: ?*OVERLAPPED,
lib/std/x/os/socket.zig+95-89
......@@ -13,105 +13,111 @@ const mem = std.mem;
1313const time = std.time;
1414const builtin = std.builtin;
1515
16/// Import in a `Socket` abstraction depending on the platform we are compiling against.
17pub usingnamespace switch (builtin.os.tag) {
18 .windows => @import("socket_windows.zig"),
19 else => @import("socket_posix.zig"),
20};
16/// A generic, cross-platform socket abstraction.
17pub const Socket = struct {
18 /// A socket-address pair.
19 pub const Connection = struct {
20 socket: Socket,
21 address: Socket.Address,
2122
22/// A common subset of shared structs across cross-platform abstractions over socket syscalls.
23pub fn Mixin(comptime Self: type) type {
24 return struct {
25 /// A socket-address pair.
26 pub const Connection = struct {
27 socket: Self,
28 address: Self.Address,
23 /// Enclose a socket and address into a socket-address pair.
24 pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
25 return .{ .socket = socket, .address = address };
26 }
27 };
2928
30 /// Enclose a socket and address into a socket-address pair.
31 pub fn from(socket: Self, address: Self.Address) Self.Connection {
32 return .{ .socket = socket, .address = address };
33 }
34 };
29 /// A generic socket address abstraction. It is safe to directly access and modify
30 /// the fields of a `Socket.Address`.
31 pub const Address = union(enum) {
32 ipv4: net.IPv4.Address,
33 ipv6: net.IPv6.Address,
3534
36 /// A generic socket address abstraction. It is safe to directly access and modify
37 /// the fields of a `Self.Address`.
38 pub const Address = union(enum) {
39 ipv4: net.IPv4.Address,
40 ipv6: net.IPv6.Address,
35 /// Instantiate a new address with a IPv4 host and port.
36 pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
37 return .{ .ipv4 = .{ .host = host, .port = port } };
38 }
4139
42 /// Instantiate a new address with a IPv4 host and port.
43 pub fn initIPv4(host: net.IPv4, port: u16) Self.Address {
44 return .{ .ipv4 = .{ .host = host, .port = port } };
45 }
40 /// Instantiate a new address with a IPv6 host and port.
41 pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
42 return .{ .ipv6 = .{ .host = host, .port = port } };
43 }
4644
47 /// Instantiate a new address with a IPv6 host and port.
48 pub fn initIPv6(host: net.IPv6, port: u16) Self.Address {
49 return .{ .ipv6 = .{ .host = host, .port = port } };
50 }
51
52 /// Parses a `sockaddr` into a generic socket address.
53 pub fn fromNative(address: *align(4) const os.sockaddr) Self.Address {
54 switch (address.family) {
55 os.AF_INET => {
56 const info = @ptrCast(*const os.sockaddr_in, address);
57 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
58 const port = mem.bigToNative(u16, info.port);
59 return Self.Address.initIPv4(host, port);
60 },
61 os.AF_INET6 => {
62 const info = @ptrCast(*const os.sockaddr_in6, address);
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 }
45 /// Parses a `sockaddr` into a generic socket address.
46 pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
47 switch (address.family) {
48 os.AF_INET => {
49 const info = @ptrCast(*const os.sockaddr_in, address);
50 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
51 const port = mem.bigToNative(u16, info.port);
52 return Socket.Address.initIPv4(host, port);
53 },
54 os.AF_INET6 => {
55 const info = @ptrCast(*const os.sockaddr_in6, address);
56 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
57 const port = mem.bigToNative(u16, info.port);
58 return Socket.Address.initIPv6(host, port);
59 },
60 else => unreachable,
6961 }
62 }
7063
71 /// 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.
73 pub fn toNative(self: Self.Address) extern union {
74 ipv4: os.sockaddr_in,
75 ipv6: os.sockaddr_in6,
76 } {
77 return switch (self) {
78 .ipv4 => |address| .{
79 .ipv4 = .{
80 .addr = @bitCast(u32, address.host.octets),
81 .port = mem.nativeToBig(u16, address.port),
82 },
64 /// Encodes a generic socket address into an extern union that may be reliably
65 /// casted into a `sockaddr` which may be passed into socket syscalls.
66 pub fn toNative(self: Socket.Address) extern union {
67 ipv4: os.sockaddr_in,
68 ipv6: os.sockaddr_in6,
69 } {
70 return switch (self) {
71 .ipv4 => |address| .{
72 .ipv4 = .{
73 .addr = @bitCast(u32, address.host.octets),
74 .port = mem.nativeToBig(u16, address.port),
8375 },
84 .ipv6 => |address| .{
85 .ipv6 = .{
86 .addr = address.host.octets,
87 .port = mem.nativeToBig(u16, address.port),
88 .scope_id = address.host.scope_id,
89 .flowinfo = 0,
90 },
76 },
77 .ipv6 => |address| .{
78 .ipv6 = .{
79 .addr = address.host.octets,
80 .port = mem.nativeToBig(u16, address.port),
81 .scope_id = address.host.scope_id,
82 .flowinfo = 0,
9183 },
92 };
93 }
84 },
85 };
86 }
9487
95 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
96 pub fn getNativeSize(self: Self.Address) u32 {
97 return switch (self) {
98 .ipv4 => @sizeOf(os.sockaddr_in),
99 .ipv6 => @sizeOf(os.sockaddr_in6),
100 };
101 }
88 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
89 pub fn getNativeSize(self: Socket.Address) u32 {
90 return switch (self) {
91 .ipv4 => @sizeOf(os.sockaddr_in),
92 .ipv6 => @sizeOf(os.sockaddr_in6),
93 };
94 }
10295
103 /// Implements the `std.fmt.format` API.
104 pub fn format(
105 self: Self.Address,
106 comptime layout: []const u8,
107 opts: fmt.FormatOptions,
108 writer: anytype,
109 ) !void {
110 switch (self) {
111 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
112 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
113 }
96 /// Implements the `std.fmt.format` API.
97 pub fn format(
98 self: Socket.Address,
99 comptime layout: []const u8,
100 opts: fmt.FormatOptions,
101 writer: anytype,
102 ) !void {
103 switch (self) {
104 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
105 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
114106 }
115 };
107 }
116108 };
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;
1010const mem = std.mem;
1111const time = std.time;
1212
13pub const Socket = struct {
14 /// Import in `Socket.Address` and `Socket.Connection`.
15 pub usingnamespace @import("socket.zig").Mixin(Socket);
16
17 /// The underlying handle of a socket.
18 fd: os.socket_t,
19
20 /// Open a new socket.
21 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
22 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
23 }
24
25 /// Enclose a socket abstraction over an existing socket file descriptor.
26 pub fn from(fd: os.socket_t) Socket {
27 return Socket{ .fd = fd };
28 }
29
30 /// Closes the socket.
31 pub fn deinit(self: Socket) void {
32 os.closeSocket(self.fd);
33 }
34
35 /// Shutdown either the read side, write side, or all side of the socket.
36 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
37 return os.shutdown(self.fd, how);
38 }
39
40 /// Binds the socket to an address.
41 pub fn bind(self: Socket, address: Socket.Address) !void {
42 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
43 }
44
45 /// Start listening for incoming connections on the socket.
46 pub fn listen(self: Socket, max_backlog_size: u31) !void {
47 return os.listen(self.fd, max_backlog_size);
48 }
49
50 /// Have the socket attempt to the connect to an address.
51 pub fn connect(self: Socket, address: Socket.Address) !void {
52 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
53 }
54
55 /// Accept a pending incoming connection queued to the kernel backlog
56 /// of the socket.
57 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
58 var address: os.sockaddr_storage = undefined;
59 var address_len: u32 = @sizeOf(os.sockaddr_storage);
60
61 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
62 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
63
64 return Socket.Connection.from(socket, socket_address);
65 }
66
67 /// Read data from the socket into the buffer provided with a set of flags
68 /// specified. It returns the number of bytes read into the buffer provided.
69 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
70 return os.recv(self.fd, buf, flags);
71 }
72
73 /// Write a buffer of data provided to the socket with a set of flags specified.
74 /// It returns the number of bytes that are written to the socket.
75 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
76 return os.send(self.fd, buf, flags);
77 }
78
79 /// Writes multiple I/O vectors with a prepended message header to the socket
80 /// with a set of flags specified. It returns the number of bytes that are
81 /// written to the socket.
82 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
83 return os.sendmsg(self.fd, msg, flags);
84 }
85
86 /// Read multiple I/O vectors with a prepended message header from the socket
87 /// with a set of flags specified. It returns the number of bytes that were
88 /// read into the buffer provided.
89 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
90 return error.NotImplemented;
91 }
92
93 /// Query the address that the socket is locally bounded to.
94 pub fn getLocalAddress(self: Socket) !Socket.Address {
95 var address: os.sockaddr_storage = undefined;
96 var address_len: u32 = @sizeOf(os.sockaddr_storage);
97 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
98 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
99 }
100
101 /// Query the address that the socket is connected to.
102 pub fn getRemoteAddress(self: Socket) !Socket.Address {
103 var address: os.sockaddr_storage = undefined;
104 var address_len: u32 = @sizeOf(os.sockaddr_storage);
105 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
106 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
107 }
108
109 /// Query and return the latest cached error on the socket.
110 pub fn getError(self: Socket) !void {
111 return os.getsockoptError(self.fd);
112 }
113
114 /// Query the read buffer size of the socket.
115 pub fn getReadBufferSize(self: Socket) !u32 {
116 var value: u32 = undefined;
117 var value_len: u32 = @sizeOf(u32);
118
119 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
120 return switch (os.errno(rc)) {
121 0 => value,
122 os.EBADF => error.BadFileDescriptor,
123 os.EFAULT => error.InvalidAddressSpace,
124 os.EINVAL => error.InvalidSocketOption,
125 os.ENOPROTOOPT => error.UnknownSocketOption,
126 os.ENOTSOCK => error.NotASocket,
127 else => |err| os.unexpectedErrno(err),
128 };
129 }
130
131 /// Query the write buffer size of the socket.
132 pub fn getWriteBufferSize(self: Socket) !u32 {
133 var value: u32 = undefined;
134 var value_len: u32 = @sizeOf(u32);
135
136 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
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,
13pub fn Mixin(comptime Socket: type) type {
14 return struct {
15 /// Open a new socket.
16 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
17 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
18 }
19
20 /// Closes the socket.
21 pub fn deinit(self: Socket) void {
22 os.closeSocket(self.fd);
23 }
24
25 /// Shutdown either the read side, write side, or all side of the socket.
26 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
27 return os.shutdown(self.fd, how);
28 }
29
30 /// Binds the socket to an address.
31 pub fn bind(self: Socket, address: Socket.Address) !void {
32 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
33 }
34
35 /// Start listening for incoming connections on the socket.
36 pub fn listen(self: Socket, max_backlog_size: u31) !void {
37 return os.listen(self.fd, max_backlog_size);
38 }
39
40 /// Have the socket attempt to the connect to an address.
41 pub fn connect(self: Socket, address: Socket.Address) !void {
42 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
43 }
44
45 /// Accept a pending incoming connection queued to the kernel backlog
46 /// of the socket.
47 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
48 var address: os.sockaddr_storage = undefined;
49 var address_len: u32 = @sizeOf(os.sockaddr_storage);
50
51 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
52 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
53
54 return Socket.Connection.from(socket, socket_address);
55 }
56
57 /// Read data from the socket into the buffer provided with a set of flags
58 /// specified. It returns the number of bytes read into the buffer provided.
59 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
60 return os.recv(self.fd, buf, flags);
61 }
62
63 /// Write a buffer of data provided to the socket with a set of flags specified.
64 /// It returns the number of bytes that are written to the socket.
65 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
66 return os.send(self.fd, buf, flags);
67 }
68
69 /// Writes multiple I/O vectors with a prepended message header to the socket
70 /// with a set of flags specified. It returns the number of bytes that are
71 /// written to the socket.
72 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
73 return os.sendmsg(self.fd, msg, flags);
74 }
75
76 /// Read multiple I/O vectors with a prepended message header from the socket
77 /// with a set of flags specified. It returns the number of bytes that were
78 /// read into the buffer provided.
79 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
80 if (comptime @hasDecl(os.system, "recvmsg")) {
81 while (true) {
82 const rc = os.system.recvmsg(self.fd, msg, flags);
83 return switch (os.errno(rc)) {
84 0 => @intCast(usize, rc),
85 os.EBADF => unreachable, // always a race condition
86 os.EFAULT => unreachable,
87 os.EINVAL => unreachable,
88 os.ENOTCONN => unreachable,
89 os.ENOTSOCK => unreachable,
90 os.EINTR => continue,
91 os.EAGAIN => error.WouldBlock,
92 os.ENOMEM => error.SystemResources,
93 os.ECONNREFUSED => error.ConnectionRefused,
94 os.ECONNRESET => error.ConnectionResetByPeer,
95 else => |err| os.unexpectedErrno(err),
96 };
97 }
98 }
99 return error.NotSupported;
100 }
101
102 /// Query the address that the socket is locally bounded to.
103 pub fn getLocalAddress(self: Socket) !Socket.Address {
104 var address: os.sockaddr_storage = undefined;
105 var address_len: u32 = @sizeOf(os.sockaddr_storage);
106 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
107 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
108 }
109
110 /// Query the address that the socket is connected to.
111 pub fn getRemoteAddress(self: Socket) !Socket.Address {
112 var address: os.sockaddr_storage = undefined;
113 var address_len: u32 = @sizeOf(os.sockaddr_storage);
114 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
115 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
116 }
117
118 /// Query and return the latest cached error on the socket.
119 pub fn getError(self: Socket) !void {
120 return os.getsockoptError(self.fd);
121 }
122
123 /// Query the read buffer size of the socket.
124 pub fn getReadBufferSize(self: Socket) !u32 {
125 var value: u32 = undefined;
126 var value_len: u32 = @sizeOf(u32);
127
128 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
129 return switch (os.errno(rc)) {
130 0 => value,
131 os.EBADF => error.BadFileDescriptor,
132 os.EFAULT => error.InvalidAddressSpace,
133 os.EINVAL => error.InvalidSocketOption,
134 os.ENOPROTOOPT => error.UnknownSocketOption,
135 os.ENOTSOCK => error.NotASocket,
136 else => |err| os.unexpectedErrno(err),
165137 };
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));
168 }
169
170 return error.UnsupportedSocketOption;
171 }
172
173 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
174 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
175 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
176 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
177 if (comptime @hasDecl(os, "SO_KEEPALIVE")) {
178 return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
179 }
180 return error.UnsupportedSocketOption;
181 }
182
183 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
184 /// the host does not support sockets listening the same address.
185 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
186 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
187 return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, 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 port. It returns `error.UnsupportedSocketOption` if
193 /// the host does not supports sockets listening on the same port.
194 pub fn setReusePort(self: Socket, enabled: bool) !void {
195 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
196 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));
197 }
198 return error.UnsupportedSocketOption;
199 }
200
201 /// Set the write buffer size of the socket.
202 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
203 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
204 }
205
206 /// Set the read buffer size of the socket.
207 pub fn setReadBufferSize(self: Socket, size: u32) !void {
208 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
209 }
210
211 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
212 /// set on a non-blocking socket.
213 ///
214 /// Set a timeout on the socket that is to occur if no messages are successfully written
215 /// to its bound destination after a specified number of milliseconds. A subsequent write
216 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
217 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
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};
201 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
202 /// the host does not supports sockets listening on the same port.
203 pub fn setReusePort(self: Socket, enabled: bool) !void {
204 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
205 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));
206 }
207 return error.UnsupportedSocketOption;
208 }
209
210 /// Set the write buffer size of the socket.
211 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
212 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
213 }
214
215 /// Set the read buffer size of the socket.
216 pub fn setReadBufferSize(self: Socket, size: u32) !void {
217 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
218 }
219
220 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
221 /// set on a non-blocking socket.
222 ///
223 /// Set a timeout on the socket that is to occur if no messages are successfully written
224 /// to its bound destination after a specified number of milliseconds. A subsequent write
225 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
226 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
227 const timeout = os.timeval{
228 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
229 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
230 };
231
232 return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
233 }
234
235 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
236 /// set on a non-blocking socket.
237 ///
238 /// Set a timeout on the socket that is to occur if no messages are successfully read
239 /// from its bound destination after a specified number of milliseconds. A subsequent
240 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
241 /// exceeded.
242 pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
243 const timeout = os.timeval{
244 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
245 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
246 };
247
248 return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
249 }
250 };
251}
lib/std/x/os/socket_windows.zig+412-360
......@@ -13,386 +13,438 @@ const mem = std.mem;
1313const windows = std.os.windows;
1414const ws2_32 = windows.ws2_32;
1515
16pub const Socket = struct {
17 /// Import in `Socket.Address` and `Socket.Connection`.
18 pub usingnamespace @import("socket.zig").Mixin(Socket);
16pub fn Mixin(comptime Socket: type) type {
17 return struct {
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.
21 fd: os.socket_t,
52 /// Closes the socket.
53 pub fn deinit(self: Socket) void {
54 _ = ws2_32.closesocket(self.fd);
55 }
2256
23 /// Open a new socket.
24 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
25 var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);
57 /// Shutdown either the read side, write side, or all side of the socket.
58 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
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;
28 if (socket_type & os.SOCK_CLOEXEC != 0) {
29 filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
79 /// Binds the socket to an address.
80 pub fn bind(self: Socket, address: Socket.Address) !void {
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 }
3096 }
3197
32 const fd = ws2_32.WSASocketW(
33 @intCast(i32, domain),
34 @intCast(i32, filtered_socket_type),
35 @intCast(i32, protocol),
36 null,
37 0,
38 filtered_flags,
39 );
40 if (fd == ws2_32.INVALID_SOCKET) {
41 return switch (ws2_32.WSAGetLastError()) {
42 .WSANOTINITIALISED => {
43 _ = try windows.WSAStartup(2, 2);
44 return Socket.init(domain, socket_type, protocol);
45 },
46 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
47 .WSAEMFILE => error.ProcessFdQuotaExceeded,
48 .WSAENOBUFS => error.SystemResources,
49 .WSAEPROTONOSUPPORT => error.ProtocolNotSupported,
50 else => |err| windows.unexpectedWSAError(err),
51 };
98 /// Start listening for incoming connections on the socket.
99 pub fn listen(self: Socket, max_backlog_size: u31) !void {
100 const rc = ws2_32.listen(self.fd, max_backlog_size);
101 if (rc == ws2_32.SOCKET_ERROR) {
102 return switch (ws2_32.WSAGetLastError()) {
103 .WSAENETDOWN => error.NetworkSubsystemFailed,
104 .WSAEADDRINUSE => error.AddressInUse,
105 .WSAEISCONN => error.AlreadyConnected,
106 .WSAEINVAL => error.SocketNotBound,
107 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,
108 .WSAENOTSOCK => error.FileDescriptorNotASocket,
109 .WSAEOPNOTSUPP => error.OperationNotSupported,
110 .WSAEINPROGRESS => error.WouldBlock,
111 else => |err| windows.unexpectedWSAError(err),
112 };
113 }
52114 }
53115
54 return Socket{ .fd = fd };
55 }
56
57 /// Enclose a socket abstraction over an existing socket file descriptor.
58 pub fn from(fd: os.socket_t) Socket {
59 return Socket{ .fd = fd };
60 }
61
62 /// Closes the socket.
63 pub fn deinit(self: Socket) void {
64 _ = ws2_32.closesocket(self.fd);
65 }
66
67 /// Shutdown either the read side, write side, or all side of the socket.
68 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
69 const rc = ws2_32.shutdown(self.fd, switch (how) {
70 .recv => ws2_32.SD_RECEIVE,
71 .send => ws2_32.SD_SEND,
72 .both => ws2_32.SD_BOTH,
73 });
74 if (rc == ws2_32.SOCKET_ERROR) {
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 };
116 /// Have the socket attempt to the connect to an address.
117 pub fn connect(self: Socket, address: Socket.Address) !void {
118 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
119 if (rc == ws2_32.SOCKET_ERROR) {
120 return switch (ws2_32.WSAGetLastError()) {
121 .WSAEADDRINUSE => error.AddressInUse,
122 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
123 .WSAECONNREFUSED => error.ConnectionRefused,
124 .WSAETIMEDOUT => error.ConnectionTimedOut,
125 .WSAEFAULT => error.BadAddress,
126 .WSAEINVAL => error.ListeningSocket,
127 .WSAEISCONN => error.AlreadyConnected,
128 .WSAENOTSOCK => error.NotASocket,
129 .WSAEACCES => error.BroadcastNotEnabled,
130 .WSAENOBUFS => error.SystemResources,
131 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
132 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,
133 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,
134 else => |err| windows.unexpectedWSAError(err),
135 };
136 }
86137 }
87 }
88
89 /// Binds the socket to an address.
90 pub fn bind(self: Socket, address: Socket.Address) !void {
91 const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
92 if (rc == ws2_32.SOCKET_ERROR) {
93 return switch (ws2_32.WSAGetLastError()) {
94 .WSAENETDOWN => error.NetworkSubsystemFailed,
95 .WSAEACCES => error.AccessDenied,
96 .WSAEADDRINUSE => error.AddressInUse,
97 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
98 .WSAEFAULT => error.BadAddress,
99 .WSAEINPROGRESS => error.WouldBlock,
100 .WSAEINVAL => error.AlreadyBound,
101 .WSAENOBUFS => error.NoEphemeralPortsAvailable,
102 .WSAENOTSOCK => error.NotASocket,
103 else => |err| windows.unexpectedWSAError(err),
104 };
138
139 /// Accept a pending incoming connection queued to the kernel backlog
140 /// of the socket.
141 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
142 var address: ws2_32.sockaddr_storage = undefined;
143 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
144
145 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
146 if (rc == ws2_32.INVALID_SOCKET) {
147 return switch (ws2_32.WSAGetLastError()) {
148 .WSANOTINITIALISED => unreachable,
149 .WSAECONNRESET => error.ConnectionResetByPeer,
150 .WSAEFAULT => unreachable,
151 .WSAEINVAL => error.SocketNotListening,
152 .WSAEMFILE => error.ProcessFdQuotaExceeded,
153 .WSAENETDOWN => error.NetworkSubsystemFailed,
154 .WSAENOBUFS => error.FileDescriptorNotASocket,
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);
105165 }
106 }
107
108 /// Start listening for incoming connections on the socket.
109 pub fn listen(self: Socket, max_backlog_size: u31) !void {
110 const rc = ws2_32.listen(self.fd, max_backlog_size);
111 if (rc == ws2_32.SOCKET_ERROR) {
112 return switch (ws2_32.WSAGetLastError()) {
113 .WSAENETDOWN => error.NetworkSubsystemFailed,
114 .WSAEADDRINUSE => error.AddressInUse,
115 .WSAEISCONN => error.AlreadyConnected,
116 .WSAEINVAL => error.SocketNotBound,
117 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,
118 .WSAENOTSOCK => error.FileDescriptorNotASocket,
119 .WSAEOPNOTSUPP => error.OperationNotSupported,
120 .WSAEINPROGRESS => error.WouldBlock,
121 else => |err| windows.unexpectedWSAError(err),
122 };
166
167 /// Read data from the socket into the buffer provided with a set of flags
168 /// specified. It returns the number of bytes read into the buffer provided.
169 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
170 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
171 var num_bytes: u32 = undefined;
172 var flags_ = flags;
173
174 const rc = ws2_32.WSARecv(self.fd, bufs, 1, &num_bytes, &flags_, null, null);
175 if (rc == ws2_32.SOCKET_ERROR) {
176 return switch (ws2_32.WSAGetLastError()) {
177 .WSAECONNABORTED => error.ConnectionAborted,
178 .WSAECONNRESET => error.ConnectionResetByPeer,
179 .WSAEDISCON => error.ConnectionClosedByPeer,
180 .WSAEFAULT => error.BadBuffer,
181 .WSAEINPROGRESS,
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);
123201 }
124 }
125
126 /// Have the socket attempt to the connect to an address.
127 pub fn connect(self: Socket, address: Socket.Address) !void {
128 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
129 if (rc == ws2_32.SOCKET_ERROR) {
130 return switch (ws2_32.WSAGetLastError()) {
131 .WSAEADDRINUSE => error.AddressInUse,
132 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
133 .WSAECONNREFUSED => error.ConnectionRefused,
134 .WSAETIMEDOUT => error.ConnectionTimedOut,
135 .WSAEFAULT => error.BadAddress,
136 .WSAEINVAL => error.ListeningSocket,
137 .WSAEISCONN => error.AlreadyConnected,
138 .WSAENOTSOCK => error.NotASocket,
139 .WSAEACCES => error.BroadcastNotEnabled,
140 .WSAENOBUFS => error.SystemResources,
141 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
142 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,
143 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,
144 else => |err| windows.unexpectedWSAError(err),
145 };
202
203 /// Write a buffer of data provided to the socket with a set of flags specified.
204 /// It returns the number of bytes that are written to the socket.
205 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
206 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = @intToPtr([*]u8, @ptrToInt(buf.ptr)) }};
207 var num_bytes: u32 = undefined;
208
209 const rc = ws2_32.WSASend(self.fd, bufs, 1, &num_bytes, flags, null, null);
210 if (rc == ws2_32.SOCKET_ERROR) {
211 return switch (ws2_32.WSAGetLastError()) {
212 .WSAECONNABORTED => error.ConnectionAborted,
213 .WSAECONNRESET => error.ConnectionResetByPeer,
214 .WSAEFAULT => error.BadBuffer,
215 .WSAEINPROGRESS,
216 .WSAEWOULDBLOCK,
217 .WSA_IO_PENDING,
218 .WSAETIMEDOUT,
219 => error.WouldBlock,
220 .WSAEINTR => error.Cancelled,
221 .WSAEINVAL => error.SocketNotBound,
222 .WSAEMSGSIZE => error.MessageTooLarge,
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);
146236 }
147 }
148
149 /// Accept a pending incoming connection queued to the kernel backlog
150 /// of the socket.
151 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
152 var address: ws2_32.sockaddr_storage = undefined;
153 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
154
155 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
156 if (rc == ws2_32.INVALID_SOCKET) {
157 return switch (ws2_32.WSAGetLastError()) {
158 .WSANOTINITIALISED => unreachable,
159 .WSAECONNRESET => error.ConnectionResetByPeer,
160 .WSAEFAULT => unreachable,
161 .WSAEINVAL => error.SocketNotListening,
162 .WSAEMFILE => error.ProcessFdQuotaExceeded,
163 .WSAENETDOWN => error.NetworkSubsystemFailed,
164 .WSAENOBUFS => error.FileDescriptorNotASocket,
165 .WSAEOPNOTSUPP => error.OperationNotSupported,
166 .WSAEWOULDBLOCK => error.WouldBlock,
167 else => |err| windows.unexpectedWSAError(err),
168 };
237
238 /// Writes multiple I/O vectors with a prepended message header to the socket
239 /// with a set of flags specified. It returns the number of bytes that are
240 /// written to the socket.
241 pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize {
242 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG);
243
244 var num_bytes: u32 = undefined;
245
246 const rc = call(self.fd, &msg, flags, &num_bytes, null, null);
247 if (rc == ws2_32.SOCKET_ERROR) {
248 return switch (ws2_32.WSAGetLastError()) {
249 .WSAECONNABORTED => error.ConnectionAborted,
250 .WSAECONNRESET => error.ConnectionResetByPeer,
251 .WSAEFAULT => error.BadBuffer,
252 .WSAEINPROGRESS,
253 .WSAEWOULDBLOCK,
254 .WSA_IO_PENDING,
255 .WSAETIMEDOUT,
256 => error.WouldBlock,
257 .WSAEINTR => error.Cancelled,
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);
169273 }
170274
171 const socket = Socket.from(rc);
172 const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
173
174 return Socket.Connection.from(socket, socket_address);
175 }
176
177 /// Read data from the socket into the buffer provided with a set of flags
178 /// specified. It returns the number of bytes read into the buffer provided.
179 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
180 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
181 var flags_ = flags;
182
183 const rc = ws2_32.WSARecv(self.fd, bufs, 1, null, &flags_, null, null);
184 if (rc == ws2_32.SOCKET_ERROR) {
185 return switch (ws2_32.WSAGetLastError()) {
186 .WSAECONNABORTED => error.ConnectionAborted,
187 .WSAECONNRESET => error.ConnectionResetByPeer,
188 .WSAEDISCON => error.ConnectionClosedByPeer,
189 .WSAEFAULT => error.BadBuffer,
190 .WSAEINPROGRESS,
191 .WSAEWOULDBLOCK,
192 .WSA_IO_PENDING,
193 .WSAETIMEDOUT,
194 => error.WouldBlock,
195 .WSAEINTR => error.Cancelled,
196 .WSAEINVAL => error.SocketNotBound,
197 .WSAEMSGSIZE => error.MessageTooLarge,
198 .WSAENETDOWN => error.NetworkSubsystemFailed,
199 .WSAENETRESET => error.NetworkReset,
200 .WSAENOTCONN => error.SocketNotConnected,
201 .WSAENOTSOCK => error.FileDescriptorNotASocket,
202 .WSAEOPNOTSUPP => error.OperationNotSupported,
203 .WSAESHUTDOWN => error.AlreadyShutdown,
204 .WSA_OPERATION_ABORTED => error.OperationAborted,
205 else => |err| windows.unexpectedWSAError(err),
206 };
275 /// Read multiple I/O vectors with a prepended message header from the socket
276 /// with a set of flags specified. It returns the number of bytes that were
277 /// read into the buffer provided.
278 pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize {
279 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG);
280
281 var num_bytes: u32 = undefined;
282
283 const rc = call(self.fd, msg, &num_bytes, null, null);
284 if (rc == ws2_32.SOCKET_ERROR) {
285 return switch (ws2_32.WSAGetLastError()) {
286 .WSAECONNABORTED => error.ConnectionAborted,
287 .WSAECONNRESET => error.ConnectionResetByPeer,
288 .WSAEDISCON => error.ConnectionClosedByPeer,
289 .WSAEFAULT => error.BadBuffer,
290 .WSAEINPROGRESS,
291 .WSAEWOULDBLOCK,
292 .WSA_IO_PENDING,
293 .WSAETIMEDOUT,
294 => error.WouldBlock,
295 .WSAEINTR => error.Cancelled,
296 .WSAEINVAL => error.SocketNotBound,
297 .WSAEMSGSIZE => error.MessageTooLarge,
298 .WSAENETDOWN => error.NetworkSubsystemFailed,
299 .WSAENETRESET => error.NetworkReset,
300 .WSAENOTCONN => error.SocketNotConnected,
301 .WSAENOTSOCK => error.FileDescriptorNotASocket,
302 .WSAEOPNOTSUPP => error.OperationNotSupported,
303 .WSAESHUTDOWN => error.AlreadyShutdown,
304 .WSA_OPERATION_ABORTED => error.OperationAborted,
305 else => |err| windows.unexpectedWSAError(err),
306 };
307 }
308
309 return @intCast(usize, num_bytes);
207310 }
208311
209 return @intCast(usize, rc);
210 }
211
212 /// Write a buffer of data provided to the socket with a set of flags specified.
213 /// It returns the number of bytes that are written to the socket.
214 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
215 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
216 var flags_ = flags;
217
218 const rc = ws2_32.WSASend(self.fd, bufs, 1, null, &flags_, null, null);
219 if (rc == ws2_32.SOCKET_ERROR) {
220 return switch (ws2_32.WSAGetLastError()) {
221 .WSAECONNABORTED => error.ConnectionAborted,
222 .WSAECONNRESET => error.ConnectionResetByPeer,
223 .WSAEFAULT => error.BadBuffer,
224 .WSAEINPROGRESS,
225 .WSAEWOULDBLOCK,
226 .WSA_IO_PENDING,
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 };
312 /// Query the address that the socket is locally bounded to.
313 pub fn getLocalAddress(self: Socket) !Socket.Address {
314 var address: ws2_32.sockaddr_storage = undefined;
315 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
316
317 const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
318 if (rc == ws2_32.SOCKET_ERROR) {
319 return switch (ws2_32.WSAGetLastError()) {
320 .WSANOTINITIALISED => unreachable,
321 .WSAEFAULT => unreachable,
322 .WSAENETDOWN => error.NetworkSubsystemFailed,
323 .WSAENOTSOCK => error.FileDescriptorNotASocket,
324 .WSAEINVAL => error.SocketNotBound,
325 else => |err| windows.unexpectedWSAError(err),
326 };
327 }
328
329 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
242330 }
243331
244 return @intCast(usize, rc);
245 }
246
247 /// Writes multiple I/O vectors with a prepended message header to the socket
248 /// with a set of flags specified. It returns the number of bytes that are
249 /// written to the socket.
250 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
251 return error.NotImplemented;
252 }
253
254 /// Read multiple I/O vectors with a prepended message header from the socket
255 /// with a set of flags specified. It returns the number of bytes that were
256 /// read into the buffer provided.
257 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
258 return error.NotImplemented;
259 }
260
261 /// Query the address that the socket is locally bounded to.
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 };
332 /// Query the address that the socket is connected to.
333 pub fn getRemoteAddress(self: Socket) !Socket.Address {
334 var address: ws2_32.sockaddr_storage = undefined;
335 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
336
337 const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
338 if (rc == ws2_32.SOCKET_ERROR) {
339 return switch (ws2_32.WSAGetLastError()) {
340 .WSANOTINITIALISED => unreachable,
341 .WSAEFAULT => unreachable,
342 .WSAENETDOWN => error.NetworkSubsystemFailed,
343 .WSAENOTSOCK => error.FileDescriptorNotASocket,
344 .WSAEINVAL => error.SocketNotBound,
345 else => |err| windows.unexpectedWSAError(err),
346 };
347 }
348
349 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
276350 }
277351
278 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
279 }
280
281 /// Query the address that the socket is connected to.
282 pub fn getRemoteAddress(self: Socket) !Socket.Address {
283 var address: ws2_32.sockaddr_storage = undefined;
284 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
285
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 };
352 /// Query and return the latest cached error on the socket.
353 pub fn getError(self: Socket) !void {
354 return {};
355 }
356
357 /// Query the read buffer size of the socket.
358 pub fn getReadBufferSize(self: Socket) !u32 {
359 return 0;
296360 }
297361
298 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
299 }
300
301 /// Query and return the latest cached error on the socket.
302 pub fn getError(self: Socket) !void {
303 return {};
304 }
305
306 /// Query the read buffer size of the socket.
307 pub fn getReadBufferSize(self: Socket) !u32 {
308 return 0;
309 }
310
311 /// Query the write buffer size of the socket.
312 pub fn getWriteBufferSize(self: Socket) !u32 {
313 return 0;
314 }
315
316 /// Set a socket option.
317 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
318 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));
319 if (rc == ws2_32.SOCKET_ERROR) {
320 return switch (ws2_32.WSAGetLastError()) {
321 .WSANOTINITIALISED => unreachable,
322 .WSAENETDOWN => return error.NetworkSubsystemFailed,
323 .WSAEFAULT => unreachable,
324 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
325 .WSAEINVAL => return error.SocketNotBound,
326 .WSAENOTCONN => return error.SocketNotConnected,
327 .WSAESHUTDOWN => return error.AlreadyShutdown,
328 else => |err| windows.unexpectedWSAError(err),
362 /// Query the write buffer size of the socket.
363 pub fn getWriteBufferSize(self: Socket) !u32 {
364 return 0;
365 }
366
367 /// Set a socket option.
368 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
369 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));
370 if (rc == ws2_32.SOCKET_ERROR) {
371 return switch (ws2_32.WSAGetLastError()) {
372 .WSANOTINITIALISED => unreachable,
373 .WSAENETDOWN => return error.NetworkSubsystemFailed,
374 .WSAEFAULT => unreachable,
375 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
376 .WSAEINVAL => return error.SocketNotBound,
377 .WSAENOTCONN => return error.SocketNotConnected,
378 .WSAESHUTDOWN => return error.AlreadyShutdown,
379 else => |err| windows.unexpectedWSAError(err),
380 };
381 }
382 }
383
384 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
385 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
386 /// if the host does not support the option for a socket to linger around up until a timeout specified in
387 /// seconds.
388 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
389 const settings = ws2_32.linger{
390 .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
391 .l_linger = if (timeout_seconds) |seconds| seconds else 0,
329392 };
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));
330448 }
331 }
332
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};
449 };
450}