diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-05-10 19:00:53 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-10 19:00:53 -0400 |
| commit | 55d235dc389635f16f4c38f70ad685677d04e6e5 (patch) | |
| tree | d528bf8e150274efc436ca60749a8b3eb009486c /lib | |
| parent | 2e4a48ef295fee2180079a01c59b47e47a414efb (diff) | |
| parent | 0d0edd23a81a195947950d4daa9c40a30fd5dfc9 (diff) | |
| download | zig-55d235dc389635f16f4c38f70ad685677d04e6e5.tar.gz zig-55d235dc389635f16f4c38f70ad685677d04e6e5.zip | |
Merge pull request #8711 from lithdew/master
std/os, x/os/socket: windows support, socket helpers, getpeername()
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/c.zig | 1 | ||||
| -rw-r--r-- | lib/std/os.zig | 37 | ||||
| -rw-r--r-- | lib/std/os/bits/darwin.zig | 7 | ||||
| -rw-r--r-- | lib/std/os/bits/dragonfly.zig | 10 | ||||
| -rw-r--r-- | lib/std/os/bits/freebsd.zig | 8 | ||||
| -rw-r--r-- | lib/std/os/bits/haiku.zig | 8 | ||||
| -rw-r--r-- | lib/std/os/bits/linux.zig | 7 | ||||
| -rw-r--r-- | lib/std/os/bits/netbsd.zig | 8 | ||||
| -rw-r--r-- | lib/std/os/bits/openbsd.zig | 8 | ||||
| -rw-r--r-- | lib/std/os/bits/windows.zig | 2 | ||||
| -rw-r--r-- | lib/std/os/windows.zig | 95 | ||||
| -rw-r--r-- | lib/std/os/windows/bits.zig | 15 | ||||
| -rw-r--r-- | lib/std/os/windows/kernel32.zig | 18 | ||||
| -rw-r--r-- | lib/std/os/windows/ws2_32.zig | 1914 | ||||
| -rw-r--r-- | lib/std/x.zig | 2 | ||||
| -rw-r--r-- | lib/std/x/net/tcp.zig | 116 | ||||
| -rw-r--r-- | lib/std/x/os/Socket.zig | 295 | ||||
| -rw-r--r-- | lib/std/x/os/net.zig | 9 | ||||
| -rw-r--r-- | lib/std/x/os/socket.zig | 123 | ||||
| -rw-r--r-- | lib/std/x/os/socket_posix.zig | 251 | ||||
| -rw-r--r-- | lib/std/x/os/socket_windows.zig | 448 |
21 files changed, 2797 insertions, 585 deletions
diff --git a/lib/std/c.zig b/lib/std/c.zig index f66376f812..58ebaaa804 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -151,6 +151,7 @@ pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: soc pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int; pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; +pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; pub extern "c" fn accept(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t) c_int; pub extern "c" fn accept4(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t, flags: c_uint) c_int; diff --git a/lib/std/os.zig b/lib/std/os.zig index 4cdecf5231..8bfebb362c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2758,9 +2758,9 @@ pub const ShutdownHow = enum { recv, send, both }; pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void { if (builtin.os.tag == .windows) { const result = windows.ws2_32.shutdown(sock, switch (how) { - .recv => windows.SD_RECEIVE, - .send => windows.SD_SEND, - .both => windows.SD_BOTH, + .recv => windows.ws2_32.SD_RECEIVE, + .send => windows.ws2_32.SD_SEND, + .both => windows.ws2_32.SD_BOTH, }); if (0 != result) switch (windows.ws2_32.WSAGetLastError()) { .WSAECONNABORTED => return error.ConnectionAborted, @@ -3217,6 +3217,35 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock } } +pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { + if (builtin.os.tag == .windows) { + const rc = windows.getpeername(sock, addr, addrlen); + if (rc == windows.ws2_32.SOCKET_ERROR) { + switch (windows.ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEINVAL => return error.SocketNotBound, + else => |err| return windows.unexpectedWSAError(err), + } + } + return; + } else { + const rc = system.getpeername(sock, addr, addrlen); + switch (errno(rc)) { + 0 => return, + else => |err| return unexpectedErrno(err), + + EBADF => unreachable, // always a race condition + EFAULT => unreachable, + EINVAL => unreachable, // invalid parameters + ENOTSOCK => return error.FileDescriptorNotASocket, + ENOBUFS => return error.SystemResources, + } + } +} + pub const ConnectError = error{ /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket /// file, or search permission is denied for one of the directories in the path prefix. @@ -5722,7 +5751,7 @@ pub const SetSockOptError = error{ /// Set a socket's options. pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void { if (builtin.os.tag == .windows) { - const rc = windows.ws2_32.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)); + const rc = windows.ws2_32.setsockopt(fd, @intCast(i32, level), @intCast(i32, optname), opt.ptr, @intCast(i32, opt.len)); if (rc == windows.ws2_32.SOCKET_ERROR) { switch (windows.ws2_32.WSAGetLastError()) { .WSANOTINITIALISED => unreachable, diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index e8a477c5d6..e3e09bfb5b 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -23,6 +23,13 @@ pub const sockaddr = extern struct { family: sa_family_t, data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig index 3df6eb43de..e0cfa387bd 100644 --- a/lib/std/os/bits/dragonfly.zig +++ b/lib/std/os/bits/dragonfly.zig @@ -380,6 +380,14 @@ pub const sockaddr = extern struct { sa_data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; + pub const Kevent = extern struct { ident: usize, filter: c_short, @@ -640,7 +648,7 @@ pub const socklen_t = c_uint; pub const sockaddr_storage = extern struct { ss_len: u8, ss_family: sa_family_t, - __ss_pad1: [6]u8, + __ss_pad1: [5]u8, __ss_align: i64, __ss_pad2: [112]u8, }; diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig index 8529c5e3db..1a8f29e793 100644 --- a/lib/std/os/bits/freebsd.zig +++ b/lib/std/os/bits/freebsd.zig @@ -206,6 +206,14 @@ pub const sockaddr = extern struct { data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; + pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/haiku.zig b/lib/std/os/bits/haiku.zig index 25a881ba56..8d170baebd 100644 --- a/lib/std/os/bits/haiku.zig +++ b/lib/std/os/bits/haiku.zig @@ -239,6 +239,14 @@ pub const sockaddr = extern struct { data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; + pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 61a432673a..048a7b3552 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -1149,6 +1149,13 @@ pub const sockaddr = extern struct { data: [14]u8, }; +pub const sockaddr_storage = extern struct { + family: sa_family_t, + __pad1: [6]u8, + __align: i64, + __pad2: [112]u8, +}; + /// IPv4 socket address pub const sockaddr_in = extern struct { family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index dfb6c3bdf9..e205f6042c 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -226,6 +226,14 @@ pub const sockaddr = extern struct { data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; + pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/openbsd.zig b/lib/std/os/bits/openbsd.zig index 1aa5ce1c9c..4104041891 100644 --- a/lib/std/os/bits/openbsd.zig +++ b/lib/std/os/bits/openbsd.zig @@ -246,6 +246,14 @@ pub const sockaddr = extern struct { data: [14]u8, }; +pub const sockaddr_storage = extern struct { + len: u8, + family: sa_family_t, + __pad1: [5]u8, + __align: i64, + __pad2: [112]u8, +}; + pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), family: sa_family_t = AF_INET, diff --git a/lib/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig index 00ca2a1532..c5b101296b 100644 --- a/lib/std/os/bits/windows.zig +++ b/lib/std/os/bits/windows.zig @@ -321,3 +321,5 @@ pub const O_NOATIME = 0o1000000; pub const O_PATH = 0o10000000; pub const O_TMPFILE = 0o20200000; pub const O_NDELAY = O_NONBLOCK; + +pub const IFNAMESIZE = 30; diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 86d1012319..12238ba776 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -389,6 +389,43 @@ pub fn GetQueuedCompletionStatus( return GetQueuedCompletionStatusResult.Normal; } +pub const GetQueuedCompletionStatusError = error{ + Aborted, + Cancelled, + EOF, + Timeout, +} || std.os.UnexpectedError; + +pub fn GetQueuedCompletionStatusEx( + completion_port: HANDLE, + completion_port_entries: []OVERLAPPED_ENTRY, + timeout_ms: ?DWORD, + alertable: bool, +) GetQueuedCompletionStatusError!u32 { + var num_entries_removed: u32 = 0; + + const success = kernel32.GetQueuedCompletionStatusEx( + completion_port, + completion_port_entries.ptr, + @intCast(ULONG, completion_port_entries.len), + &num_entries_removed, + timeout_ms orelse INFINITE, + @boolToInt(alertable), + ); + + if (success == FALSE) { + return switch (kernel32.GetLastError()) { + .ABANDONED_WAIT_0 => error.Aborted, + .OPERATION_ABORTED => error.Cancelled, + .HANDLE_EOF => error.EOF, + .IMEOUT => error.Timeout, + else => |err| unexpectedError(err), + }; + } + + return num_entries_removed; +} + pub fn CloseHandle(hObject: HANDLE) void { assert(ntdll.NtClose(hObject) == .SUCCESS); } @@ -1291,6 +1328,10 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen)); } +pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 { + return ws2_32.getpeername(s, name, @ptrCast(*i32, namelen)); +} + pub fn sendmsg( s: ws2_32.SOCKET, msg: *const ws2_32.WSAMSG, @@ -1404,6 +1445,28 @@ pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetCon } } +pub fn SetConsoleCtrlHandler(handler_routine: ?HANDLER_ROUTINE, add: bool) !void { + const success = kernel32.SetConsoleCtrlHandler( + handler_routine, + if (add) TRUE else FALSE, + ); + + if (success == FALSE) { + return switch (kernel32.GetLastError()) { + else => |err| unexpectedError(err), + }; + } +} + +pub fn SetFileCompletionNotificationModes(handle: HANDLE, flags: UCHAR) !void { + const success = kernel32.SetFileCompletionNotificationModes(handle, flags); + if (success == FALSE) { + return switch (kernel32.GetLastError()) { + else => |err| unexpectedError(err), + }; + } +} + pub const GetEnvironmentStringsError = error{OutOfMemory}; pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*:0]u16 { @@ -1686,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID { return (s << 10) | p; } +/// Loads a Winsock extension function in runtime specified by a GUID. +pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: GUID) !T { + var function: T = undefined; + var num_bytes: DWORD = undefined; + + const rc = ws2_32.WSAIoctl( + sock, + ws2_32.SIO_GET_EXTENSION_FUNCTION_POINTER, + @ptrCast(*const c_void, &guid), + @sizeOf(GUID), + &function, + @sizeOf(T), + &num_bytes, + null, + null, + ); + + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + else => |err| unexpectedWSAError(err), + }; + } + + if (num_bytes != @sizeOf(T)) { + return error.ShortRead; + } + + return function; +} + /// Call this when you made a windows DLL call or something that does SetLastError /// and you get an unexpected error. pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index cbeb0b483d..1e08dbbf5c 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -1619,10 +1619,6 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct { }; pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008; -pub const SD_RECEIVE = 0; -pub const SD_SEND = 1; -pub const SD_BOTH = 2; - pub const OBJECT_INFORMATION_CLASS = extern enum { ObjectBasicInformation = 0, ObjectNameInformation = 1, @@ -1642,3 +1638,14 @@ pub const SRWLOCK = usize; pub const SRWLOCK_INIT: SRWLOCK = 0; pub const CONDITION_VARIABLE = usize; pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = 0; + +pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1; +pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2; + +pub const CTRL_C_EVENT: DWORD = 0; +pub const CTRL_BREAK_EVENT: DWORD = 1; +pub const CTRL_CLOSE_EVENT: DWORD = 2; +pub const CTRL_LOGOFF_EVENT: DWORD = 5; +pub const CTRL_SHUTDOWN_EVENT: DWORD = 6; + +pub const HANDLER_ROUTINE = fn (dwCtrlType: DWORD) callconv(.C) BOOL; diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig index 734059a08a..e117f362eb 100644 --- a/lib/std/os/windows/kernel32.zig +++ b/lib/std/os/windows/kernel32.zig @@ -140,6 +140,14 @@ pub extern "kernel32" fn GetOverlappedResult(hFile: HANDLE, lpOverlapped: *OVERL pub extern "kernel32" fn GetProcessHeap() callconv(WINAPI) ?HANDLE; pub extern "kernel32" fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) callconv(WINAPI) BOOL; +pub extern "kernel32" fn GetQueuedCompletionStatusEx( + CompletionPort: HANDLE, + lpCompletionPortEntries: [*]OVERLAPPED_ENTRY, + ulCount: ULONG, + ulNumEntriesRemoved: *ULONG, + dwMilliseconds: DWORD, + fAlertable: BOOL, +) callconv(WINAPI) BOOL; pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void; pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void; @@ -197,6 +205,16 @@ pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(W pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL; +pub extern "kernel32" fn SetConsoleCtrlHandler( + HandlerRoutine: ?HANDLER_ROUTINE, + Add: BOOL, +) callconv(WINAPI) BOOL; + +pub extern "kernel32" fn SetFileCompletionNotificationModes( + FileHandle: HANDLE, + Flags: UCHAR, +) callconv(WINAPI) BOOL; + pub extern "kernel32" fn SetFilePointerEx( in_fFile: HANDLE, in_liDistanceToMove: LARGE_INTEGER, diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index 1dd2ce738b..1fa5110b52 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -7,10 +7,929 @@ usingnamespace @import("bits.zig"); pub const SOCKET = *opaque {}; pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0)); -pub const SOCKET_ERROR = -1; +pub const GROUP = u32; +pub const ADDRESS_FAMILY = u16; +pub const WSAEVENT = HANDLE; + +// Microsoft use the signed c_int for this, but it should never be negative +pub const socklen_t = u32; + +pub const LM_HB_Extension = 128; +pub const LM_HB1_PnP = 1; +pub const LM_HB1_PDA_Palmtop = 2; +pub const LM_HB1_Computer = 4; +pub const LM_HB1_Printer = 8; +pub const LM_HB1_Modem = 16; +pub const LM_HB1_Fax = 32; +pub const LM_HB1_LANAccess = 64; +pub const LM_HB2_Telephony = 1; +pub const LM_HB2_FileServer = 2; +pub const ATMPROTO_AALUSER = 0; +pub const ATMPROTO_AAL1 = 1; +pub const ATMPROTO_AAL2 = 2; +pub const ATMPROTO_AAL34 = 3; +pub const ATMPROTO_AAL5 = 5; +pub const SAP_FIELD_ABSENT = 4294967294; +pub const SAP_FIELD_ANY = 4294967295; +pub const SAP_FIELD_ANY_AESA_SEL = 4294967290; +pub const SAP_FIELD_ANY_AESA_REST = 4294967291; +pub const ATM_E164 = 1; +pub const ATM_NSAP = 2; +pub const ATM_AESA = 2; +pub const ATM_ADDR_SIZE = 20; +pub const BLLI_L2_ISO_1745 = 1; +pub const BLLI_L2_Q921 = 2; +pub const BLLI_L2_X25L = 6; +pub const BLLI_L2_X25M = 7; +pub const BLLI_L2_ELAPB = 8; +pub const BLLI_L2_HDLC_ARM = 9; +pub const BLLI_L2_HDLC_NRM = 10; +pub const BLLI_L2_HDLC_ABM = 11; +pub const BLLI_L2_LLC = 12; +pub const BLLI_L2_X75 = 13; +pub const BLLI_L2_Q922 = 14; +pub const BLLI_L2_USER_SPECIFIED = 16; +pub const BLLI_L2_ISO_7776 = 17; +pub const BLLI_L3_X25 = 6; +pub const BLLI_L3_ISO_8208 = 7; +pub const BLLI_L3_X223 = 8; +pub const BLLI_L3_SIO_8473 = 9; +pub const BLLI_L3_T70 = 10; +pub const BLLI_L3_ISO_TR9577 = 11; +pub const BLLI_L3_USER_SPECIFIED = 16; +pub const BLLI_L3_IPI_SNAP = 128; +pub const BLLI_L3_IPI_IP = 204; +pub const BHLI_ISO = 0; +pub const BHLI_UserSpecific = 1; +pub const BHLI_HighLayerProfile = 2; +pub const BHLI_VendorSpecificAppId = 3; +pub const AAL5_MODE_MESSAGE = 1; +pub const AAL5_MODE_STREAMING = 2; +pub const AAL5_SSCS_NULL = 0; +pub const AAL5_SSCS_SSCOP_ASSURED = 1; +pub const AAL5_SSCS_SSCOP_NON_ASSURED = 2; +pub const AAL5_SSCS_FRAME_RELAY = 4; +pub const BCOB_A = 1; +pub const BCOB_C = 3; +pub const BCOB_X = 16; +pub const TT_NOIND = 0; +pub const TT_CBR = 4; +pub const TT_VBR = 8; +pub const TR_NOIND = 0; +pub const TR_END_TO_END = 1; +pub const TR_NO_END_TO_END = 2; +pub const CLIP_NOT = 0; +pub const CLIP_SUS = 32; +pub const UP_P2P = 0; +pub const UP_P2MP = 1; +pub const BLLI_L2_MODE_NORMAL = 64; +pub const BLLI_L2_MODE_EXT = 128; +pub const BLLI_L3_MODE_NORMAL = 64; +pub const BLLI_L3_MODE_EXT = 128; +pub const BLLI_L3_PACKET_16 = 4; +pub const BLLI_L3_PACKET_32 = 5; +pub const BLLI_L3_PACKET_64 = 6; +pub const BLLI_L3_PACKET_128 = 7; +pub const BLLI_L3_PACKET_256 = 8; +pub const BLLI_L3_PACKET_512 = 9; +pub const BLLI_L3_PACKET_1024 = 10; +pub const BLLI_L3_PACKET_2048 = 11; +pub const BLLI_L3_PACKET_4096 = 12; +pub const PI_ALLOWED = 0; +pub const PI_RESTRICTED = 64; +pub const PI_NUMBER_NOT_AVAILABLE = 128; +pub const SI_USER_NOT_SCREENED = 0; +pub const SI_USER_PASSED = 1; +pub const SI_USER_FAILED = 2; +pub const SI_NETWORK = 3; +pub const CAUSE_LOC_USER = 0; +pub const CAUSE_LOC_PRIVATE_LOCAL = 1; +pub const CAUSE_LOC_PUBLIC_LOCAL = 2; +pub const CAUSE_LOC_TRANSIT_NETWORK = 3; +pub const CAUSE_LOC_PUBLIC_REMOTE = 4; +pub const CAUSE_LOC_PRIVATE_REMOTE = 5; +pub const CAUSE_LOC_INTERNATIONAL_NETWORK = 7; +pub const CAUSE_LOC_BEYOND_INTERWORKING = 10; +pub const CAUSE_UNALLOCATED_NUMBER = 1; +pub const CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK = 2; +pub const CAUSE_NO_ROUTE_TO_DESTINATION = 3; +pub const CAUSE_VPI_VCI_UNACCEPTABLE = 10; +pub const CAUSE_NORMAL_CALL_CLEARING = 16; +pub const CAUSE_USER_BUSY = 17; +pub const CAUSE_NO_USER_RESPONDING = 18; +pub const CAUSE_CALL_REJECTED = 21; +pub const CAUSE_NUMBER_CHANGED = 22; +pub const CAUSE_USER_REJECTS_CLIR = 23; +pub const CAUSE_DESTINATION_OUT_OF_ORDER = 27; +pub const CAUSE_INVALID_NUMBER_FORMAT = 28; +pub const CAUSE_STATUS_ENQUIRY_RESPONSE = 30; +pub const CAUSE_NORMAL_UNSPECIFIED = 31; +pub const CAUSE_VPI_VCI_UNAVAILABLE = 35; +pub const CAUSE_NETWORK_OUT_OF_ORDER = 38; +pub const CAUSE_TEMPORARY_FAILURE = 41; +pub const CAUSE_ACCESS_INFORMAION_DISCARDED = 43; +pub const CAUSE_NO_VPI_VCI_AVAILABLE = 45; +pub const CAUSE_RESOURCE_UNAVAILABLE = 47; +pub const CAUSE_QOS_UNAVAILABLE = 49; +pub const CAUSE_USER_CELL_RATE_UNAVAILABLE = 51; +pub const CAUSE_BEARER_CAPABILITY_UNAUTHORIZED = 57; +pub const CAUSE_BEARER_CAPABILITY_UNAVAILABLE = 58; +pub const CAUSE_OPTION_UNAVAILABLE = 63; +pub const CAUSE_BEARER_CAPABILITY_UNIMPLEMENTED = 65; +pub const CAUSE_UNSUPPORTED_TRAFFIC_PARAMETERS = 73; +pub const CAUSE_INVALID_CALL_REFERENCE = 81; +pub const CAUSE_CHANNEL_NONEXISTENT = 82; +pub const CAUSE_INCOMPATIBLE_DESTINATION = 88; +pub const CAUSE_INVALID_ENDPOINT_REFERENCE = 89; +pub const CAUSE_INVALID_TRANSIT_NETWORK_SELECTION = 91; +pub const CAUSE_TOO_MANY_PENDING_ADD_PARTY = 92; +pub const CAUSE_AAL_PARAMETERS_UNSUPPORTED = 93; +pub const CAUSE_MANDATORY_IE_MISSING = 96; +pub const CAUSE_UNIMPLEMENTED_MESSAGE_TYPE = 97; +pub const CAUSE_UNIMPLEMENTED_IE = 99; +pub const CAUSE_INVALID_IE_CONTENTS = 100; +pub const CAUSE_INVALID_STATE_FOR_MESSAGE = 101; +pub const CAUSE_RECOVERY_ON_TIMEOUT = 102; +pub const CAUSE_INCORRECT_MESSAGE_LENGTH = 104; +pub const CAUSE_PROTOCOL_ERROR = 111; +pub const CAUSE_COND_UNKNOWN = 0; +pub const CAUSE_COND_PERMANENT = 1; +pub const CAUSE_COND_TRANSIENT = 2; +pub const CAUSE_REASON_USER = 0; +pub const CAUSE_REASON_IE_MISSING = 4; +pub const CAUSE_REASON_IE_INSUFFICIENT = 8; +pub const CAUSE_PU_PROVIDER = 0; +pub const CAUSE_PU_USER = 8; +pub const CAUSE_NA_NORMAL = 0; +pub const CAUSE_NA_ABNORMAL = 4; +pub const QOS_CLASS0 = 0; +pub const QOS_CLASS1 = 1; +pub const QOS_CLASS2 = 2; +pub const QOS_CLASS3 = 3; +pub const QOS_CLASS4 = 4; +pub const TNS_TYPE_NATIONAL = 64; +pub const TNS_PLAN_CARRIER_ID_CODE = 1; +pub const SIO_GET_NUMBER_OF_ATM_DEVICES = 1343619073; +pub const SIO_GET_ATM_ADDRESS = 3491102722; +pub const SIO_ASSOCIATE_PVC = 2417360899; +pub const SIO_GET_ATM_CONNECTION_ID = 1343619076; +pub const RIO_MSG_DONT_NOTIFY = 1; +pub const RIO_MSG_DEFER = 2; +pub const RIO_MSG_WAITALL = 4; +pub const RIO_MSG_COMMIT_ONLY = 8; +pub const RIO_MAX_CQ_SIZE = 134217728; +pub const RIO_CORRUPT_CQ = 4294967295; +pub const WINDOWS_AF_IRDA = 26; +pub const WCE_AF_IRDA = 22; +pub const IRDA_PROTO_SOCK_STREAM = 1; +pub const SOL_IRLMP = 255; +pub const IRLMP_ENUMDEVICES = 16; +pub const IRLMP_IAS_SET = 17; +pub const IRLMP_IAS_QUERY = 18; +pub const IRLMP_SEND_PDU_LEN = 19; +pub const IRLMP_EXCLUSIVE_MODE = 20; +pub const IRLMP_IRLPT_MODE = 21; +pub const IRLMP_9WIRE_MODE = 22; +pub const IRLMP_TINYTP_MODE = 23; +pub const IRLMP_PARAMETERS = 24; +pub const IRLMP_DISCOVERY_MODE = 25; +pub const IRLMP_SHARP_MODE = 32; +pub const IAS_ATTRIB_NO_CLASS = 16; +pub const IAS_ATTRIB_NO_ATTRIB = 0; +pub const IAS_ATTRIB_INT = 1; +pub const IAS_ATTRIB_OCTETSEQ = 2; +pub const IAS_ATTRIB_STR = 3; +pub const IAS_MAX_USER_STRING = 256; +pub const IAS_MAX_OCTET_STRING = 1024; +pub const IAS_MAX_CLASSNAME = 64; +pub const IAS_MAX_ATTRIBNAME = 256; +pub const LmCharSetASCII = 0; +pub const LmCharSetISO_8859_1 = 1; +pub const LmCharSetISO_8859_2 = 2; +pub const LmCharSetISO_8859_3 = 3; +pub const LmCharSetISO_8859_4 = 4; +pub const LmCharSetISO_8859_5 = 5; +pub const LmCharSetISO_8859_6 = 6; +pub const LmCharSetISO_8859_7 = 7; +pub const LmCharSetISO_8859_8 = 8; +pub const LmCharSetISO_8859_9 = 9; +pub const LmCharSetUNICODE = 255; +pub const LM_BAUD_1200 = 1200; +pub const LM_BAUD_2400 = 2400; +pub const LM_BAUD_9600 = 9600; +pub const LM_BAUD_19200 = 19200; +pub const LM_BAUD_38400 = 38400; +pub const LM_BAUD_57600 = 57600; +pub const LM_BAUD_115200 = 115200; +pub const LM_BAUD_576K = 576000; +pub const LM_BAUD_1152K = 1152000; +pub const LM_BAUD_4M = 4000000; +pub const LM_BAUD_16M = 16000000; +pub const IPX_PTYPE = 16384; +pub const IPX_FILTERPTYPE = 16385; +pub const IPX_STOPFILTERPTYPE = 16387; +pub const IPX_DSTYPE = 16386; +pub const IPX_EXTENDED_ADDRESS = 16388; +pub const IPX_RECVHDR = 16389; +pub const IPX_MAXSIZE = 16390; +pub const IPX_ADDRESS = 16391; +pub const IPX_GETNETINFO = 16392; +pub const IPX_GETNETINFO_NORIP = 16393; +pub const IPX_SPXGETCONNECTIONSTATUS = 16395; +pub const IPX_ADDRESS_NOTIFY = 16396; +pub const IPX_MAX_ADAPTER_NUM = 16397; +pub const IPX_RERIPNETNUMBER = 16398; +pub const IPX_RECEIVE_BROADCAST = 16399; +pub const IPX_IMMEDIATESPXACK = 16400; +pub const IPPROTO_RM = 113; +pub const MAX_MCAST_TTL = 255; +pub const RM_OPTIONSBASE = 1000; +pub const RM_RATE_WINDOW_SIZE = 1001; +pub const RM_SET_MESSAGE_BOUNDARY = 1002; +pub const RM_FLUSHCACHE = 1003; +pub const RM_SENDER_WINDOW_ADVANCE_METHOD = 1004; +pub const RM_SENDER_STATISTICS = 1005; +pub const RM_LATEJOIN = 1006; +pub const RM_SET_SEND_IF = 1007; +pub const RM_ADD_RECEIVE_IF = 1008; +pub const RM_DEL_RECEIVE_IF = 1009; +pub const RM_SEND_WINDOW_ADV_RATE = 1010; +pub const RM_USE_FEC = 1011; +pub const RM_SET_MCAST_TTL = 1012; +pub const RM_RECEIVER_STATISTICS = 1013; +pub const RM_HIGH_SPEED_INTRANET_OPT = 1014; +pub const SENDER_DEFAULT_RATE_KBITS_PER_SEC = 56; +pub const SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE = 15; +pub const MAX_WINDOW_INCREMENT_PERCENTAGE = 25; +pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0; +pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75; +pub const BITS_PER_BYTE = 8; +pub const LOG2_BITS_PER_BYTE = 3; + +pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}"); +pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}"); +pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}"); +pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}"); + +pub const WSAID_CONNECTEX = GUID{ + .Data1 = 0x25a207b9, + .Data2 = 0xddf3, + .Data3 = 0x4660, + .Data4 = [8]u8{ 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e }, +}; + +pub const WSAID_ACCEPTEX = GUID{ + .Data1 = 0xb5367df1, + .Data2 = 0xcbac, + .Data3 = 0x11cf, + .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 }, +}; + +pub const WSAID_GETACCEPTEXSOCKADDRS = GUID{ + .Data1 = 0xb5367df2, + .Data2 = 0xcbac, + .Data3 = 0x11cf, + .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 }, +}; + +pub const WSAID_WSARECVMSG = GUID{ + .Data1 = 0xf689d7c8, + .Data2 = 0x6f1f, + .Data3 = 0x436b, + .Data4 = [8]u8{ 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22 }, +}; + +pub const WSAID_WSAPOLL = GUID{ + .Data1 = 0x18C76F85, + .Data2 = 0xDC66, + .Data3 = 0x4964, + .Data4 = [8]u8{ 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B }, +}; + +pub const WSAID_WSASENDMSG = GUID{ + .Data1 = 0xa441e712, + .Data2 = 0x754f, + .Data3 = 0x43ca, + .Data4 = [8]u8{ 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d }, +}; + +pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0; +pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0; +pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1; +pub const SOCKET_SETTINGS_ALLOW_INSECURE = 2; +pub const SOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION = 1; +pub const SOCKET_SETTINGS_IPSEC_OPTIONAL_PEER_NAME_VERIFICATION = 2; +pub const SOCKET_SETTINGS_IPSEC_ALLOW_FIRST_INBOUND_PKT_UNENCRYPTED = 4; +pub const SOCKET_SETTINGS_IPSEC_PEER_NAME_IS_RAW_FORMAT = 8; +pub const SOCKET_QUERY_IPSEC2_ABORT_CONNECTION_ON_FIELD_CHANGE = 1; +pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_MM_SA_ID = 1; +pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_QM_SA_ID = 2; +pub const SOCKET_INFO_CONNECTION_SECURED = 1; +pub const SOCKET_INFO_CONNECTION_ENCRYPTED = 2; +pub const SOCKET_INFO_CONNECTION_IMPERSONATED = 4; +pub const IN4ADDR_LOOPBACK = 16777343; +pub const IN4ADDR_LOOPBACKPREFIX_LENGTH = 8; +pub const IN4ADDR_LINKLOCALPREFIX_LENGTH = 16; +pub const IN4ADDR_MULTICASTPREFIX_LENGTH = 4; +pub const IFF_UP = 1; +pub const IFF_BROADCAST = 2; +pub const IFF_LOOPBACK = 4; +pub const IFF_POINTTOPOINT = 8; +pub const IFF_MULTICAST = 16; +pub const IP_OPTIONS = 1; +pub const IP_HDRINCL = 2; +pub const IP_TOS = 3; +pub const IP_TTL = 4; +pub const IP_MULTICAST_IF = 9; +pub const IP_MULTICAST_TTL = 10; +pub const IP_MULTICAST_LOOP = 11; +pub const IP_ADD_MEMBERSHIP = 12; +pub const IP_DROP_MEMBERSHIP = 13; +pub const IP_DONTFRAGMENT = 14; +pub const IP_ADD_SOURCE_MEMBERSHIP = 15; +pub const IP_DROP_SOURCE_MEMBERSHIP = 16; +pub const IP_BLOCK_SOURCE = 17; +pub const IP_UNBLOCK_SOURCE = 18; +pub const IP_PKTINFO = 19; +pub const IP_HOPLIMIT = 21; +pub const IP_RECVTTL = 21; +pub const IP_RECEIVE_BROADCAST = 22; +pub const IP_RECVIF = 24; +pub const IP_RECVDSTADDR = 25; +pub const IP_IFLIST = 28; +pub const IP_ADD_IFLIST = 29; +pub const IP_DEL_IFLIST = 30; +pub const IP_UNICAST_IF = 31; +pub const IP_RTHDR = 32; +pub const IP_GET_IFLIST = 33; +pub const IP_RECVRTHDR = 38; +pub const IP_TCLASS = 39; +pub const IP_RECVTCLASS = 40; +pub const IP_RECVTOS = 40; +pub const IP_ORIGINAL_ARRIVAL_IF = 47; +pub const IP_ECN = 50; +pub const IP_PKTINFO_EX = 51; +pub const IP_WFP_REDIRECT_RECORDS = 60; +pub const IP_WFP_REDIRECT_CONTEXT = 70; +pub const IP_MTU_DISCOVER = 71; +pub const IP_MTU = 73; +pub const IP_NRT_INTERFACE = 74; +pub const IP_RECVERR = 75; +pub const IP_USER_MTU = 76; +pub const IP_UNSPECIFIED_TYPE_OF_SERVICE = -1; +pub const IN6ADDR_LINKLOCALPREFIX_LENGTH = 64; +pub const IN6ADDR_MULTICASTPREFIX_LENGTH = 8; +pub const IN6ADDR_SOLICITEDNODEMULTICASTPREFIX_LENGTH = 104; +pub const IN6ADDR_V4MAPPEDPREFIX_LENGTH = 96; +pub const IN6ADDR_6TO4PREFIX_LENGTH = 16; +pub const IN6ADDR_TEREDOPREFIX_LENGTH = 32; +pub const MCAST_JOIN_GROUP = 41; +pub const MCAST_LEAVE_GROUP = 42; +pub const MCAST_BLOCK_SOURCE = 43; +pub const MCAST_UNBLOCK_SOURCE = 44; +pub const MCAST_JOIN_SOURCE_GROUP = 45; +pub const MCAST_LEAVE_SOURCE_GROUP = 46; +pub const IPV6_HOPOPTS = 1; +pub const IPV6_HDRINCL = 2; +pub const IPV6_UNICAST_HOPS = 4; +pub const IPV6_MULTICAST_IF = 9; +pub const IPV6_MULTICAST_HOPS = 10; +pub const IPV6_MULTICAST_LOOP = 11; +pub const IPV6_ADD_MEMBERSHIP = 12; +pub const IPV6_DROP_MEMBERSHIP = 13; +pub const IPV6_DONTFRAG = 14; +pub const IPV6_PKTINFO = 19; +pub const IPV6_HOPLIMIT = 21; +pub const IPV6_PROTECTION_LEVEL = 23; +pub const IPV6_RECVIF = 24; +pub const IPV6_RECVDSTADDR = 25; +pub const IPV6_CHECKSUM = 26; +pub const IPV6_V6ONLY = 27; +pub const IPV6_IFLIST = 28; +pub const IPV6_ADD_IFLIST = 29; +pub const IPV6_DEL_IFLIST = 30; +pub const IPV6_UNICAST_IF = 31; +pub const IPV6_RTHDR = 32; +pub const IPV6_GET_IFLIST = 33; +pub const IPV6_RECVRTHDR = 38; +pub const IPV6_TCLASS = 39; +pub const IPV6_RECVTCLASS = 40; +pub const IPV6_ECN = 50; +pub const IPV6_PKTINFO_EX = 51; +pub const IPV6_WFP_REDIRECT_RECORDS = 60; +pub const IPV6_WFP_REDIRECT_CONTEXT = 70; +pub const IPV6_MTU_DISCOVER = 71; +pub const IPV6_MTU = 72; +pub const IPV6_NRT_INTERFACE = 74; +pub const IPV6_RECVERR = 75; +pub const IPV6_USER_MTU = 76; +pub const IP_UNSPECIFIED_HOP_LIMIT = -1; +pub const PROTECTION_LEVEL_UNRESTRICTED = 10; +pub const PROTECTION_LEVEL_EDGERESTRICTED = 20; +pub const PROTECTION_LEVEL_RESTRICTED = 30; +pub const INET_ADDRSTRLEN = 22; +pub const INET6_ADDRSTRLEN = 65; +pub const TCP_OFFLOAD_NO_PREFERENCE = 0; +pub const TCP_OFFLOAD_NOT_PREFERRED = 1; +pub const TCP_OFFLOAD_PREFERRED = 2; +pub const TCP_EXPEDITED_1122 = 2; +pub const TCP_KEEPALIVE = 3; +pub const TCP_MAXSEG = 4; +pub const TCP_MAXRT = 5; +pub const TCP_STDURG = 6; +pub const TCP_NOURG = 7; +pub const TCP_ATMARK = 8; +pub const TCP_NOSYNRETRIES = 9; +pub const TCP_TIMESTAMPS = 10; +pub const TCP_OFFLOAD_PREFERENCE = 11; +pub const TCP_CONGESTION_ALGORITHM = 12; +pub const TCP_DELAY_FIN_ACK = 13; +pub const TCP_MAXRTMS = 14; +pub const TCP_FASTOPEN = 15; +pub const TCP_KEEPCNT = 16; +pub const TCP_KEEPINTVL = 17; +pub const TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18; +pub const TCP_ICMP_ERROR_INFO = 19; +pub const UDP_SEND_MSG_SIZE = 2; +pub const UDP_RECV_MAX_COALESCED_SIZE = 3; +pub const UDP_COALESCED_INFO = 3; +pub const AF_UNSPEC = 0; +pub const AF_UNIX = 1; +pub const AF_INET = 2; +pub const AF_IMPLINK = 3; +pub const AF_PUP = 4; +pub const AF_CHAOS = 5; +pub const AF_NS = 6; +pub const AF_ISO = 7; +pub const AF_ECMA = 8; +pub const AF_DATAKIT = 9; +pub const AF_CCITT = 10; +pub const AF_SNA = 11; +pub const AF_DECnet = 12; +pub const AF_DLI = 13; +pub const AF_LAT = 14; +pub const AF_HYLINK = 15; +pub const AF_APPLETALK = 16; +pub const AF_NETBIOS = 17; +pub const AF_VOICEVIEW = 18; +pub const AF_FIREFOX = 19; +pub const AF_UNKNOWN1 = 20; +pub const AF_BAN = 21; +pub const AF_ATM = 22; +pub const AF_INET6 = 23; +pub const AF_CLUSTER = 24; +pub const AF_12844 = 25; +pub const AF_IRDA = 26; +pub const AF_NETDES = 28; +pub const AF_MAX = 29; +pub const AF_TCNPROCESS = 29; +pub const AF_TCNMESSAGE = 30; +pub const AF_ICLFXBM = 31; +pub const AF_LINK = 33; +pub const AF_HYPERV = 34; +pub const SOCK_STREAM = 1; +pub const SOCK_DGRAM = 2; +pub const SOCK_RAW = 3; +pub const SOCK_RDM = 4; +pub const SOCK_SEQPACKET = 5; +pub const SOL_SOCKET = 65535; +pub const SO_DEBUG = 1; +pub const SO_ACCEPTCONN = 2; +pub const SO_REUSEADDR = 4; +pub const SO_KEEPALIVE = 8; +pub const SO_DONTROUTE = 16; +pub const SO_BROADCAST = 32; +pub const SO_USELOOPBACK = 64; +pub const SO_LINGER = 128; +pub const SO_OOBINLINE = 256; +pub const SO_SNDBUF = 4097; +pub const SO_RCVBUF = 4098; +pub const SO_SNDLOWAT = 4099; +pub const SO_RCVLOWAT = 4100; +pub const SO_SNDTIMEO = 4101; +pub const SO_RCVTIMEO = 4102; +pub const SO_ERROR = 4103; +pub const SO_TYPE = 4104; +pub const SO_BSP_STATE = 4105; +pub const SO_GROUP_ID = 8193; +pub const SO_GROUP_PRIORITY = 8194; +pub const SO_MAX_MSG_SIZE = 8195; +pub const SO_CONDITIONAL_ACCEPT = 12290; +pub const SO_PAUSE_ACCEPT = 12291; +pub const SO_COMPARTMENT_ID = 12292; +pub const SO_RANDOMIZE_PORT = 12293; +pub const SO_PORT_SCALABILITY = 12294; +pub const SO_REUSE_UNICASTPORT = 12295; +pub const SO_REUSE_MULTICASTPORT = 12296; +pub const SO_ORIGINAL_DST = 12303; +pub const WSK_SO_BASE = 16384; +pub const TCP_NODELAY = 1; +pub const IOC_UNIX = 0; +pub const IOC_WS2 = 134217728; +pub const IOC_PROTOCOL = 268435456; +pub const IOC_VENDOR = 402653184; +pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6; +pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27; +pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28; +pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29; +pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34; +pub const IPPROTO_IP = 0; +pub const IPPORT_TCPMUX = 1; +pub const IPPORT_ECHO = 7; +pub const IPPORT_DISCARD = 9; +pub const IPPORT_SYSTAT = 11; +pub const IPPORT_DAYTIME = 13; +pub const IPPORT_NETSTAT = 15; +pub const IPPORT_QOTD = 17; +pub const IPPORT_MSP = 18; +pub const IPPORT_CHARGEN = 19; +pub const IPPORT_FTP_DATA = 20; +pub const IPPORT_FTP = 21; +pub const IPPORT_TELNET = 23; +pub const IPPORT_SMTP = 25; +pub const IPPORT_TIMESERVER = 37; +pub const IPPORT_NAMESERVER = 42; +pub const IPPORT_WHOIS = 43; +pub const IPPORT_MTP = 57; +pub const IPPORT_TFTP = 69; +pub const IPPORT_RJE = 77; +pub const IPPORT_FINGER = 79; +pub const IPPORT_TTYLINK = 87; +pub const IPPORT_SUPDUP = 95; +pub const IPPORT_POP3 = 110; +pub const IPPORT_NTP = 123; +pub const IPPORT_EPMAP = 135; +pub const IPPORT_NETBIOS_NS = 137; +pub const IPPORT_NETBIOS_DGM = 138; +pub const IPPORT_NETBIOS_SSN = 139; +pub const IPPORT_IMAP = 143; +pub const IPPORT_SNMP = 161; +pub const IPPORT_SNMP_TRAP = 162; +pub const IPPORT_IMAP3 = 220; +pub const IPPORT_LDAP = 389; +pub const IPPORT_HTTPS = 443; +pub const IPPORT_MICROSOFT_DS = 445; +pub const IPPORT_EXECSERVER = 512; +pub const IPPORT_LOGINSERVER = 513; +pub const IPPORT_CMDSERVER = 514; +pub const IPPORT_EFSSERVER = 520; +pub const IPPORT_BIFFUDP = 512; +pub const IPPORT_WHOSERVER = 513; +pub const IPPORT_ROUTESERVER = 520; +pub const IPPORT_RESERVED = 1024; +pub const IPPORT_REGISTERED_MAX = 49151; +pub const IPPORT_DYNAMIC_MIN = 49152; +pub const IPPORT_DYNAMIC_MAX = 65535; +pub const IN_CLASSA_NET = 4278190080; +pub const IN_CLASSA_NSHIFT = 24; +pub const IN_CLASSA_HOST = 16777215; +pub const IN_CLASSA_MAX = 128; +pub const IN_CLASSB_NET = 4294901760; +pub const IN_CLASSB_NSHIFT = 16; +pub const IN_CLASSB_HOST = 65535; +pub const IN_CLASSB_MAX = 65536; +pub const IN_CLASSC_NET = 4294967040; +pub const IN_CLASSC_NSHIFT = 8; +pub const IN_CLASSC_HOST = 255; +pub const IN_CLASSD_NET = 4026531840; +pub const IN_CLASSD_NSHIFT = 28; +pub const IN_CLASSD_HOST = 268435455; +pub const INADDR_LOOPBACK = 2130706433; +pub const INADDR_NONE = 4294967295; +pub const IOCPARM_MASK = 127; +pub const IOC_VOID = 536870912; +pub const IOC_OUT = 1073741824; +pub const IOC_IN = 2147483648; +pub const MSG_TRUNC = 256; +pub const MSG_CTRUNC = 512; +pub const MSG_BCAST = 1024; +pub const MSG_MCAST = 2048; +pub const MSG_ERRQUEUE = 4096; +pub const AI_PASSIVE = 1; +pub const AI_CANONNAME = 2; +pub const AI_NUMERICHOST = 4; +pub const AI_NUMERICSERV = 8; +pub const AI_DNS_ONLY = 16; +pub const AI_ALL = 256; +pub const AI_ADDRCONFIG = 1024; +pub const AI_V4MAPPED = 2048; +pub const AI_NON_AUTHORITATIVE = 16384; +pub const AI_SECURE = 32768; +pub const AI_RETURN_PREFERRED_NAMES = 65536; +pub const AI_FQDN = 131072; +pub const AI_FILESERVER = 262144; +pub const AI_DISABLE_IDN_ENCODING = 524288; +pub const AI_EXTENDED = 2147483648; +pub const AI_RESOLUTION_HANDLE = 1073741824; +pub const FIONBIO = -2147195266; +pub const ADDRINFOEX_VERSION_2 = 2; +pub const ADDRINFOEX_VERSION_3 = 3; +pub const ADDRINFOEX_VERSION_4 = 4; +pub const NS_ALL = 0; +pub const NS_SAP = 1; +pub const NS_NDS = 2; +pub const NS_PEER_BROWSE = 3; +pub const NS_SLP = 5; +pub const NS_DHCP = 6; +pub const NS_TCPIP_LOCAL = 10; +pub const NS_TCPIP_HOSTS = 11; +pub const NS_DNS = 12; +pub const NS_NETBT = 13; +pub const NS_WINS = 14; +pub const NS_NLA = 15; +pub const NS_NBP = 20; +pub const NS_MS = 30; +pub const NS_STDA = 31; +pub const NS_NTDS = 32; +pub const NS_EMAIL = 37; +pub const NS_X500 = 40; +pub const NS_NIS = 41; +pub const NS_NISPLUS = 42; +pub const NS_WRQ = 50; +pub const NS_NETDES = 60; +pub const NI_NOFQDN = 1; +pub const NI_NUMERICHOST = 2; +pub const NI_NAMEREQD = 4; +pub const NI_NUMERICSERV = 8; +pub const NI_DGRAM = 16; +pub const NI_MAXHOST = 1025; +pub const NI_MAXSERV = 32; +pub const INCL_WINSOCK_API_PROTOTYPES = 1; +pub const INCL_WINSOCK_API_TYPEDEFS = 0; +pub const FD_SETSIZE = 64; +pub const IMPLINK_IP = 155; +pub const IMPLINK_LOWEXPER = 156; +pub const IMPLINK_HIGHEXPER = 158; pub const WSADESCRIPTION_LEN = 256; pub const WSASYS_STATUS_LEN = 128; +pub const SOCKET_ERROR = -1; +pub const FROM_PROTOCOL_INFO = -1; +pub const SO_PROTOCOL_INFOA = 8196; +pub const SO_PROTOCOL_INFOW = 8197; +pub const PVD_CONFIG = 12289; +pub const SOMAXCONN = 2147483647; +pub const MSG_PEEK = 2; +pub const MSG_WAITALL = 8; +pub const MSG_PUSH_IMMEDIATE = 32; +pub const MSG_PARTIAL = 32768; +pub const MSG_INTERRUPT = 16; +pub const MSG_MAXIOVLEN = 16; +pub const MAXGETHOSTSTRUCT = 1024; +pub const FD_READ_BIT = 0; +pub const FD_WRITE_BIT = 1; +pub const FD_OOB_BIT = 2; +pub const FD_ACCEPT_BIT = 3; +pub const FD_CONNECT_BIT = 4; +pub const FD_CLOSE_BIT = 5; +pub const FD_QOS_BIT = 6; +pub const FD_GROUP_QOS_BIT = 7; +pub const FD_ROUTING_INTERFACE_CHANGE_BIT = 8; +pub const FD_ADDRESS_LIST_CHANGE_BIT = 9; +pub const FD_MAX_EVENTS = 10; +pub const CF_ACCEPT = 0; +pub const CF_REJECT = 1; +pub const CF_DEFER = 2; +pub const SD_RECEIVE = 0; +pub const SD_SEND = 1; +pub const SD_BOTH = 2; +pub const SG_UNCONSTRAINED_GROUP = 1; +pub const SG_CONSTRAINED_GROUP = 2; +pub const MAX_PROTOCOL_CHAIN = 7; +pub const BASE_PROTOCOL = 1; +pub const LAYERED_PROTOCOL = 0; +pub const WSAPROTOCOL_LEN = 255; +pub const PFL_MULTIPLE_PROTO_ENTRIES = 1; +pub const PFL_RECOMMENDED_PROTO_ENTRY = 2; +pub const PFL_HIDDEN = 4; +pub const PFL_MATCHES_PROTOCOL_ZERO = 8; +pub const PFL_NETWORKDIRECT_PROVIDER = 16; +pub const XP1_CONNECTIONLESS = 1; +pub const XP1_GUARANTEED_DELIVERY = 2; +pub const XP1_GUARANTEED_ORDER = 4; +pub const XP1_MESSAGE_ORIENTED = 8; +pub const XP1_PSEUDO_STREAM = 16; +pub const XP1_GRACEFUL_CLOSE = 32; +pub const XP1_EXPEDITED_DATA = 64; +pub const XP1_CONNECT_DATA = 128; +pub const XP1_DISCONNECT_DATA = 256; +pub const XP1_SUPPORT_BROADCAST = 512; +pub const XP1_SUPPORT_MULTIPOINT = 1024; +pub const XP1_MULTIPOINT_CONTROL_PLANE = 2048; +pub const XP1_MULTIPOINT_DATA_PLANE = 4096; +pub const XP1_QOS_SUPPORTED = 8192; +pub const XP1_INTERRUPT = 16384; +pub const XP1_UNI_SEND = 32768; +pub const XP1_UNI_RECV = 65536; +pub const XP1_IFS_HANDLES = 131072; +pub const XP1_PARTIAL_MESSAGE = 262144; +pub const XP1_SAN_SUPPORT_SDP = 524288; +pub const BIGENDIAN = 0; +pub const LITTLEENDIAN = 1; +pub const SECURITY_PROTOCOL_NONE = 0; +pub const JL_SENDER_ONLY = 1; +pub const JL_RECEIVER_ONLY = 2; +pub const JL_BOTH = 4; +pub const WSA_FLAG_OVERLAPPED = 1; +pub const WSA_FLAG_MULTIPOINT_C_ROOT = 2; +pub const WSA_FLAG_MULTIPOINT_C_LEAF = 4; +pub const WSA_FLAG_MULTIPOINT_D_ROOT = 8; +pub const WSA_FLAG_MULTIPOINT_D_LEAF = 16; +pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 64; +pub const WSA_FLAG_NO_HANDLE_INHERIT = 128; +pub const WSA_FLAG_REGISTERED_IO = 256; +pub const TH_NETDEV = 1; +pub const TH_TAPI = 2; +pub const SERVICE_MULTIPLE = 1; +pub const NS_LOCALNAME = 19; +pub const RES_UNUSED_1 = 1; +pub const RES_FLUSH_CACHE = 2; +pub const RES_SERVICE = 4; +pub const LUP_DEEP = 1; +pub const LUP_CONTAINERS = 2; +pub const LUP_NOCONTAINERS = 4; +pub const LUP_NEAREST = 8; +pub const LUP_RETURN_NAME = 16; +pub const LUP_RETURN_TYPE = 32; +pub const LUP_RETURN_VERSION = 64; +pub const LUP_RETURN_COMMENT = 128; +pub const LUP_RETURN_ADDR = 256; +pub const LUP_RETURN_BLOB = 512; +pub const LUP_RETURN_ALIASES = 1024; +pub const LUP_RETURN_QUERY_STRING = 2048; +pub const LUP_RETURN_ALL = 4080; +pub const LUP_RES_SERVICE = 32768; +pub const LUP_FLUSHCACHE = 4096; +pub const LUP_FLUSHPREVIOUS = 8192; +pub const LUP_NON_AUTHORITATIVE = 16384; +pub const LUP_SECURE = 32768; +pub const LUP_RETURN_PREFERRED_NAMES = 65536; +pub const LUP_DNS_ONLY = 131072; +pub const LUP_ADDRCONFIG = 1048576; +pub const LUP_DUAL_ADDR = 2097152; +pub const LUP_FILESERVER = 4194304; +pub const LUP_DISABLE_IDN_ENCODING = 8388608; +pub const LUP_API_ANSI = 16777216; +pub const LUP_RESOLUTION_HANDLE = 2147483648; +pub const RESULT_IS_ALIAS = 1; +pub const RESULT_IS_ADDED = 16; +pub const RESULT_IS_CHANGED = 32; +pub const RESULT_IS_DELETED = 64; +pub const POLLRDNORM = 256; +pub const POLLRDBAND = 512; +pub const POLLPRI = 1024; +pub const POLLWRNORM = 16; +pub const POLLWRBAND = 32; +pub const POLLERR = 1; +pub const POLLHUP = 2; +pub const POLLNVAL = 4; +pub const SO_CONNDATA = 28672; +pub const SO_CONNOPT = 28673; +pub const SO_DISCDATA = 28674; +pub const SO_DISCOPT = 28675; +pub const SO_CONNDATALEN = 28676; +pub const SO_CONNOPTLEN = 28677; +pub const SO_DISCDATALEN = 28678; +pub const SO_DISCOPTLEN = 28679; +pub const SO_OPENTYPE = 28680; +pub const SO_SYNCHRONOUS_ALERT = 16; +pub const SO_SYNCHRONOUS_NONALERT = 32; +pub const SO_MAXDG = 28681; +pub const SO_MAXPATHDG = 28682; +pub const SO_UPDATE_ACCEPT_CONTEXT = 28683; +pub const SO_CONNECT_TIME = 28684; +pub const SO_UPDATE_CONNECT_CONTEXT = 28688; +pub const TCP_BSDURGENT = 28672; +pub const TF_DISCONNECT = 1; +pub const TF_REUSE_SOCKET = 2; +pub const TF_WRITE_BEHIND = 4; +pub const TF_USE_DEFAULT_WORKER = 0; +pub const TF_USE_SYSTEM_THREAD = 16; +pub const TF_USE_KERNEL_APC = 32; +pub const TP_ELEMENT_MEMORY = 1; +pub const TP_ELEMENT_FILE = 2; +pub const TP_ELEMENT_EOP = 4; +pub const NLA_ALLUSERS_NETWORK = 1; +pub const NLA_FRIENDLY_NAME = 2; +pub const WSPDESCRIPTION_LEN = 255; +pub const WSS_OPERATION_IN_PROGRESS = 259; +pub const LSP_SYSTEM = 2147483648; +pub const LSP_INSPECTOR = 1; +pub const LSP_REDIRECTOR = 2; +pub const LSP_PROXY = 4; +pub const LSP_FIREWALL = 8; +pub const LSP_INBOUND_MODIFY = 16; +pub const LSP_OUTBOUND_MODIFY = 32; +pub const LSP_CRYPTO_COMPRESS = 64; +pub const LSP_LOCAL_CACHE = 128; +pub const IPPROTO_ICMP = 1; +pub const IPPROTO_IGMP = 2; +pub const IPPROTO_GGP = 3; +pub const IPPROTO_TCP = 6; +pub const IPPROTO_PUP = 12; +pub const IPPROTO_UDP = 17; +pub const IPPROTO_IDP = 22; +pub const IPPROTO_ND = 77; +pub const IPPROTO_RAW = 255; +pub const IPPROTO_MAX = 256; +pub const IP_DEFAULT_MULTICAST_TTL = 1; +pub const IP_DEFAULT_MULTICAST_LOOP = 1; +pub const IP_MAX_MEMBERSHIPS = 20; +pub const AF_IPX = 6; +pub const FD_READ = 1; +pub const FD_WRITE = 2; +pub const FD_OOB = 4; +pub const FD_ACCEPT = 8; +pub const FD_CONNECT = 16; +pub const FD_CLOSE = 32; +pub const SERVICE_RESOURCE = 1; +pub const SERVICE_SERVICE = 2; +pub const SERVICE_LOCAL = 4; +pub const SERVICE_FLAG_DEFER = 1; +pub const SERVICE_FLAG_HARD = 2; +pub const PROP_COMMENT = 1; +pub const PROP_LOCALE = 2; +pub const PROP_DISPLAY_HINT = 4; +pub const PROP_VERSION = 8; +pub const PROP_START_TIME = 16; +pub const PROP_MACHINE = 32; +pub const PROP_ADDRESSES = 256; +pub const PROP_SD = 512; +pub const PROP_ALL = 2147483648; +pub const SERVICE_ADDRESS_FLAG_RPC_CN = 1; +pub const SERVICE_ADDRESS_FLAG_RPC_DG = 2; +pub const SERVICE_ADDRESS_FLAG_RPC_NB = 4; +pub const NS_DEFAULT = 0; +pub const NS_VNS = 50; +pub const NSTYPE_HIERARCHICAL = 1; +pub const NSTYPE_DYNAMIC = 2; +pub const NSTYPE_ENUMERABLE = 4; +pub const NSTYPE_WORKGROUP = 8; +pub const XP_CONNECTIONLESS = 1; +pub const XP_GUARANTEED_DELIVERY = 2; +pub const XP_GUARANTEED_ORDER = 4; +pub const XP_MESSAGE_ORIENTED = 8; +pub const XP_PSEUDO_STREAM = 16; +pub const XP_GRACEFUL_CLOSE = 32; +pub const XP_EXPEDITED_DATA = 64; +pub const XP_CONNECT_DATA = 128; +pub const XP_DISCONNECT_DATA = 256; +pub const XP_SUPPORTS_BROADCAST = 512; +pub const XP_SUPPORTS_MULTICAST = 1024; +pub const XP_BANDWIDTH_ALLOCATION = 2048; +pub const XP_FRAGMENTATION = 4096; +pub const XP_ENCRYPTS = 8192; +pub const RES_SOFT_SEARCH = 1; +pub const RES_FIND_MULTIPLE = 2; +pub const SET_SERVICE_PARTIAL_SUCCESS = 1; +pub const UDP_NOCHECKSUM = 1; +pub const UDP_CHECKSUM_COVERAGE = 20; +pub const GAI_STRERROR_BUFFER_SIZE = 1024; + +pub const LPCONDITIONPROC = fn ( + lpCallerId: *WSABUF, + lpCallerData: *WSABUF, + lpSQOS: *QOS, + lpGQOS: *QOS, + lpCalleeId: *WSABUF, + lpCalleeData: *WSABUF, + g: *u32, + dwCallbackData: usize, +) callconv(WINAPI) i32; + +pub const LPWSAOVERLAPPED_COMPLETION_ROUTINE = fn ( + dwError: u32, + cbTransferred: u32, + lpOverlapped: *OVERLAPPED, + dwFlags: u32, +) callconv(WINAPI) void; + +pub const FLOWSPEC = extern struct { + TokenRate: u32, + TokenBucketSize: u32, + PeakBandwidth: u32, + Latency: u32, + DelayVariation: u32, + ServiceType: u32, + MaxSduSize: u32, + MinimumPolicedSize: u32, +}; + +pub const QOS = extern struct { + SendingFlowspec: FLOWSPEC, + ReceivingFlowspec: FLOWSPEC, + ProviderSpecific: WSABUF, +}; + +pub const SOCKET_ADDRESS = extern struct { + lpSockaddr: *sockaddr, + iSockaddrLength: i32, +}; + +pub const SOCKET_ADDRESS_LIST = extern struct { + iAddressCount: i32, + Address: [1]SOCKET_ADDRESS, +}; pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64)) extern struct { @@ -33,15 +952,11 @@ else lpVendorInfo: *u8, }; -pub const MAX_PROTOCOL_CHAIN = 7; - pub const WSAPROTOCOLCHAIN = extern struct { ChainLen: c_int, ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD, }; -pub const WSAPROTOCOL_LEN = 255; - pub const WSAPROTOCOL_INFOA = extern struct { dwServiceFlags1: DWORD, dwServiceFlags2: DWORD, @@ -88,20 +1003,20 @@ pub const WSAPROTOCOL_INFOW = extern struct { szProtocol: [WSAPROTOCOL_LEN + 1]WCHAR, }; -pub const GROUP = u32; - -pub const SG_UNCONSTRAINED_GROUP = 0x1; -pub const SG_CONSTRAINED_GROUP = 0x2; +pub const sockproto = extern struct { + sp_family: u16, + sp_protocol: u16, +}; -pub const WSA_FLAG_OVERLAPPED = 0x01; -pub const WSA_FLAG_MULTIPOINT_C_ROOT = 0x02; -pub const WSA_FLAG_MULTIPOINT_C_LEAF = 0x04; -pub const WSA_FLAG_MULTIPOINT_D_ROOT = 0x08; -pub const WSA_FLAG_MULTIPOINT_D_LEAF = 0x10; -pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 0x40; -pub const WSA_FLAG_NO_HANDLE_INHERIT = 0x80; +pub const linger = extern struct { + l_onoff: u16, + l_linger: u16, +}; -pub const WSAEVENT = HANDLE; +pub const WSANETWORKEVENTS = extern struct { + lNetworkEvents: i32, + iErrorCode: [10]i32, +}; pub const WSAOVERLAPPED = extern struct { Internal: DWORD, @@ -111,82 +1026,9 @@ pub const WSAOVERLAPPED = extern struct { hEvent: ?WSAEVENT, }; -pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred: DWORD, lpOverlapped: *WSAOVERLAPPED, dwFlags: DWORD) callconv(.C) void; - -pub const ADDRESS_FAMILY = u16; - -// Microsoft use the signed c_int for this, but it should never be negative -pub const socklen_t = u32; +pub const addrinfo = addrinfoa; -pub const AF_UNSPEC = 0; -pub const AF_UNIX = 1; -pub const AF_INET = 2; -pub const AF_IMPLINK = 3; -pub const AF_PUP = 4; -pub const AF_CHAOS = 5; -pub const AF_NS = 6; -pub const AF_IPX = AF_NS; -pub const AF_ISO = 7; -pub const AF_OSI = AF_ISO; -pub const AF_ECMA = 8; -pub const AF_DATAKIT = 9; -pub const AF_CCITT = 10; -pub const AF_SNA = 11; -pub const AF_DECnet = 12; -pub const AF_DLI = 13; -pub const AF_LAT = 14; -pub const AF_HYLINK = 15; -pub const AF_APPLETALK = 16; -pub const AF_NETBIOS = 17; -pub const AF_VOICEVIEW = 18; -pub const AF_FIREFOX = 19; -pub const AF_UNKNOWN1 = 20; -pub const AF_BAN = 21; -pub const AF_ATM = 22; -pub const AF_INET6 = 23; -pub const AF_CLUSTER = 24; -pub const AF_12844 = 25; -pub const AF_IRDA = 26; -pub const AF_NETDES = 28; -pub const AF_TCNPROCESS = 29; -pub const AF_TCNMESSAGE = 30; -pub const AF_ICLFXBM = 31; -pub const AF_BTH = 32; -pub const AF_MAX = 33; - -pub const SOCK_STREAM = 1; -pub const SOCK_DGRAM = 2; -pub const SOCK_RAW = 3; -pub const SOCK_RDM = 4; -pub const SOCK_SEQPACKET = 5; - -pub const IPPROTO_ICMP = 1; -pub const IPPROTO_IGMP = 2; -pub const BTHPROTO_RFCOMM = 3; -pub const IPPROTO_TCP = 6; -pub const IPPROTO_UDP = 17; -pub const IPPROTO_ICMPV6 = 58; -pub const IPPROTO_RM = 113; - -pub const AI_PASSIVE = 0x00001; -pub const AI_CANONNAME = 0x00002; -pub const AI_NUMERICHOST = 0x00004; -pub const AI_NUMERICSERV = 0x00008; -pub const AI_ADDRCONFIG = 0x00400; -pub const AI_V4MAPPED = 0x00800; -pub const AI_NON_AUTHORITATIVE = 0x04000; -pub const AI_SECURE = 0x08000; -pub const AI_RETURN_PREFERRED_NAMES = 0x10000; -pub const AI_DISABLE_IDN_ENCODING = 0x80000; - -pub const FIONBIO = -2147195266; - -pub const sockaddr = extern struct { - family: ADDRESS_FAMILY, - data: [14]u8, -}; - -pub const addrinfo = extern struct { +pub const addrinfoa = extern struct { flags: i32, family: i32, socktype: i32, @@ -197,6 +1039,32 @@ pub const addrinfo = extern struct { next: ?*addrinfo, }; +pub const addrinfoexA = extern struct { + ai_flags: i32, + ai_family: i32, + ai_socktype: i32, + ai_protocol: i32, + ai_addrlen: usize, + ai_canonname: [*:0]u8, + ai_addr: *sockaddr, + ai_blob: *c_void, + ai_bloblen: usize, + ai_provider: *GUID, + ai_next: *addrinfoexA, +}; + +pub const sockaddr = extern struct { + family: ADDRESS_FAMILY, + data: [14]u8, +}; + +pub const sockaddr_storage = extern struct { + family: ADDRESS_FAMILY, + __pad1: [6]u8, + __align: i64, + __pad2: [112]u8, +}; + /// IPv4 socket address pub const sockaddr_in = extern struct { family: ADDRESS_FAMILY = AF_INET, @@ -225,7 +1093,10 @@ pub const WSABUF = extern struct { buf: [*]u8, }; -pub const WSAMSG = extern struct { +pub const msghdr = WSAMSG; +pub const msghdr_const = WSAMSG_const; + +pub const WSAMSG_const = extern struct { name: *const sockaddr, namelen: INT, lpBuffers: [*]WSABUF, @@ -234,26 +1105,108 @@ pub const WSAMSG = extern struct { dwFlags: DWORD, }; +pub const WSAMSG = extern struct { + name: *sockaddr, + namelen: INT, + lpBuffers: [*]WSABUF, + dwBufferCount: DWORD, + Control: WSABUF, + dwFlags: DWORD, +}; + +pub const WSAPOLLFD = pollfd; + pub const pollfd = extern struct { fd: SOCKET, events: SHORT, revents: SHORT, }; -// Event flag definitions for WSAPoll(). +pub const TRANSMIT_FILE_BUFFERS = extern struct { + Head: *c_void, + HeadLength: u32, + Tail: *c_void, + TailLength: u32, +}; + +pub const LPFN_TRANSMITFILE = fn ( + hSocket: SOCKET, + hFile: HANDLE, + nNumberOfBytesToWrite: u32, + nNumberOfBytesPerSend: u32, + lpOverlapped: ?*OVERLAPPED, + lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS, + dwReserved: u32, +) callconv(WINAPI) BOOL; + +pub const LPFN_ACCEPTEX = fn ( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: *c_void, + dwReceiveDataLength: u32, + dwLocalAddressLength: u32, + dwRemoteAddressLength: u32, + lpdwBytesReceived: *u32, + lpOverlapped: *OVERLAPPED, +) callconv(WINAPI) BOOL; + +pub const LPFN_GETACCEPTEXSOCKADDRS = fn ( + lpOutputBuffer: *c_void, + dwReceiveDataLength: u32, + dwLocalAddressLength: u32, + dwRemoteAddressLength: u32, + LocalSockaddr: **sockaddr, + LocalSockaddrLength: *i32, + RemoteSockaddr: **sockaddr, + RemoteSockaddrLength: *i32, +) callconv(WINAPI) void; + +pub const LPFN_WSASENDMSG = fn ( + s: SOCKET, + lpMsg: *const WSAMSG_const, + dwFlags: u32, + lpNumberOfBytesSent: ?*u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; -pub const POLLRDNORM = 0x0100; -pub const POLLRDBAND = 0x0200; -pub const POLLIN = (POLLRDNORM | POLLRDBAND); -pub const POLLPRI = 0x0400; +pub const LPFN_WSARECVMSG = fn ( + s: SOCKET, + lpMsg: *WSAMSG, + lpdwNumberOfBytesRecv: ?*u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; -pub const POLLWRNORM = 0x0010; -pub const POLLOUT = (POLLWRNORM); -pub const POLLWRBAND = 0x0020; +pub const LPSERVICE_CALLBACK_PROC = fn ( + lParam: LPARAM, + hAsyncTaskHandle: HANDLE, +) callconv(WINAPI) void; -pub const POLLERR = 0x0001; -pub const POLLHUP = 0x0002; -pub const POLLNVAL = 0x0004; +pub const SERVICE_ASYNC_INFO = extern struct { + lpServiceCallbackProc: LPSERVICE_CALLBACK_PROC, + lParam: LPARAM, + hAsyncTaskHandle: HANDLE, +}; + +pub const LPLOOKUPSERVICE_COMPLETION_ROUTINE = fn ( + dwError: u32, + dwBytes: u32, + lpOverlapped: *OVERLAPPED, +) callconv(WINAPI) void; + +pub const fd_set = extern struct { + fd_count: u32, + fd_array: [64]SOCKET, +}; + +pub const hostent = extern struct { + h_name: [*]u8, + h_aliases: **i8, + h_addrtype: i16, + h_length: i16, + h_addr_list: **i8, +}; // https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2 pub const WinsockError = extern enum(u16) { @@ -704,180 +1657,649 @@ pub const WinsockError = extern enum(u16) { _, }; -/// no parameters -const IOC_VOID = 0x80000000; +pub extern "ws2_32" fn accept( + s: SOCKET, + addr: ?*sockaddr, + addrlen: ?*i32, +) callconv(WINAPI) SOCKET; -/// copy out parameters -const IOC_OUT = 0x40000000; +pub extern "ws2_32" fn bind( + s: SOCKET, + name: *const sockaddr, + namelen: i32, +) callconv(WINAPI) i32; -/// copy in parameters -const IOC_IN = 0x80000000; +pub extern "ws2_32" fn closesocket( + s: SOCKET, +) callconv(WINAPI) i32; -/// The IOCTL is a generic Windows Sockets 2 IOCTL code. New IOCTL codes defined for Windows Sockets 2 will have T == 1. -const IOC_WS2 = 0x08000000; +pub extern "ws2_32" fn connect( + s: SOCKET, + name: *const sockaddr, + namelen: i32, +) callconv(WINAPI) i32; -pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34; +pub extern "ws2_32" fn ioctlsocket( + s: SOCKET, + cmd: i32, + argp: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn getpeername( + s: SOCKET, + name: *sockaddr, + namelen: *i32, +) callconv(WINAPI) i32; -pub const SOL_SOCKET = 0xffff; - -pub const SO_DEBUG = 0x0001; -pub const SO_ACCEPTCONN = 0x0002; -pub const SO_REUSEADDR = 0x0004; -pub const SO_KEEPALIVE = 0x0008; -pub const SO_DONTROUTE = 0x0010; -pub const SO_BROADCAST = 0x0020; -pub const SO_USELOOPBACK = 0x0040; -pub const SO_LINGER = 0x0080; -pub const SO_OOBINLINE = 0x0100; - -pub const SO_DONTLINGER = ~@as(u32, SO_LINGER); -pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR); - -pub const SO_SNDBUF = 0x1001; -pub const SO_RCVBUF = 0x1002; -pub const SO_SNDLOWAT = 0x1003; -pub const SO_RCVLOWAT = 0x1004; -pub const SO_SNDTIMEO = 0x1005; -pub const SO_RCVTIMEO = 0x1006; -pub const SO_ERROR = 0x1007; -pub const SO_TYPE = 0x1008; - -pub const SO_GROUP_ID = 0x2001; -pub const SO_GROUP_PRIORITY = 0x2002; -pub const SO_MAX_MSG_SIZE = 0x2003; -pub const SO_PROTOCOL_INFOA = 0x2004; -pub const SO_PROTOCOL_INFOW = 0x2005; - -pub const PVD_CONFIG = 0x3001; -pub const SO_CONDITIONAL_ACCEPT = 0x3002; - -pub const TCP_NODELAY = 0x0001; +pub extern "ws2_32" fn getsockname( + s: SOCKET, + name: *sockaddr, + namelen: *i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn getsockopt( + s: SOCKET, + level: i32, + optname: i32, + optval: [*]u8, + optlen: *i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn htonl( + hostlong: u32, +) callconv(WINAPI) u32; + +pub extern "ws2_32" fn htons( + hostshort: u16, +) callconv(WINAPI) u16; + +pub extern "ws2_32" fn inet_addr( + cp: ?[*]const u8, +) callconv(WINAPI) u32; + +pub extern "ws2_32" fn listen( + s: SOCKET, + backlog: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn ntohl( + netlong: u32, +) callconv(WINAPI) u32; + +pub extern "ws2_32" fn ntohs( + netshort: u16, +) callconv(WINAPI) u16; + +pub extern "ws2_32" fn recv( + s: SOCKET, + buf: [*]u8, + len: i32, + flags: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn recvfrom( + s: SOCKET, + buf: [*]u8, + len: i32, + flags: i32, + from: ?*sockaddr, + fromlen: ?*i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn select( + nfds: i32, + readfds: ?*fd_set, + writefds: ?*fd_set, + exceptfds: ?*fd_set, + timeout: ?*const timeval, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn send( + s: SOCKET, + buf: [*]const u8, + len: i32, + flags: u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn sendto( + s: SOCKET, + buf: [*]const u8, + len: i32, + flags: i32, + to: *const sockaddr, + tolen: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn setsockopt( + s: SOCKET, + level: i32, + optname: i32, + optval: ?[*]const u8, + optlen: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn shutdown( + s: SOCKET, + how: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn socket( + af: i32, + @"type": i32, + protocol: i32, +) callconv(WINAPI) SOCKET; pub extern "ws2_32" fn WSAStartup( wVersionRequired: WORD, lpWSAData: *WSADATA, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) c_int; +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSASetLastError(iError: i32) callconv(WINAPI) void; + pub extern "ws2_32" fn WSAGetLastError() callconv(WINAPI) WinsockError; -pub extern "ws2_32" fn WSASocketA( - af: c_int, - type: c_int, - protocol: c_int, - lpProtocolInfo: ?*WSAPROTOCOL_INFOA, - g: GROUP, - dwFlags: DWORD, -) callconv(WINAPI) SOCKET; -pub extern "ws2_32" fn WSASocketW( - af: c_int, - type: c_int, - protocol: c_int, - lpProtocolInfo: ?*WSAPROTOCOL_INFOW, - g: GROUP, - dwFlags: DWORD, -) callconv(WINAPI) SOCKET; -pub extern "ws2_32" fn closesocket(s: SOCKET) callconv(WINAPI) c_int; -pub extern "ws2_32" fn WSAIoctl( + +pub extern "ws2_32" fn WSAIsBlocking() callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAUnhookBlockingHook() callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSASetBlockingHook(lpBlockFunc: FARPROC) callconv(WINAPI) FARPROC; + +pub extern "ws2_32" fn WSACancelBlockingCall() callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAAsyncGetServByName( + hWnd: HWND, + wMsg: u32, + name: [*:0]const u8, + proto: ?[*:0]const u8, + buf: [*]u8, + buflen: i32, +) callconv(WINAPI) HANDLE; + +pub extern "ws2_32" fn WSAAsyncGetServByPort( + hWnd: HWND, + wMsg: u32, + port: i32, + proto: ?[*:0]const u8, + buf: [*]u8, + buflen: i32, +) callconv(WINAPI) HANDLE; + +pub extern "ws2_32" fn WSAAsyncGetProtoByName( + hWnd: HWND, + wMsg: u32, + name: [*:0]const u8, + buf: [*]u8, + buflen: i32, +) callconv(WINAPI) HANDLE; + +pub extern "ws2_32" fn WSAAsyncGetProtoByNumber( + hWnd: HWND, + wMsg: u32, + number: i32, + buf: [*]u8, + buflen: i32, +) callconv(WINAPI) HANDLE; + +pub extern "ws2_32" fn WSACancelAsyncRequest(hAsyncTaskHandle: HANDLE) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAAsyncSelect( s: SOCKET, - dwIoControlCode: DWORD, - lpvInBuffer: ?*const c_void, - cbInBuffer: DWORD, - lpvOutBuffer: ?LPVOID, - cbOutBuffer: DWORD, - lpcbBytesReturned: LPDWORD, - lpOverlapped: ?*WSAOVERLAPPED, - lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn accept( + hWnd: HWND, + wMsg: u32, + lEvent: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAAccept( s: SOCKET, addr: ?*sockaddr, - addrlen: ?*c_int, + addrlen: ?*i32, + lpfnCondition: ?LPCONDITIONPROC, + dwCallbackData: usize, ) callconv(WINAPI) SOCKET; -pub extern "ws2_32" fn bind( + +pub extern "ws2_32" fn WSACloseEvent(hEvent: HANDLE) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAConnect( s: SOCKET, - addr: ?*const sockaddr, - addrlen: c_int, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn connect( + name: *const sockaddr, + namelen: i32, + lpCallerData: ?*WSABUF, + lpCalleeData: ?*WSABUF, + lpSQOS: ?*QOS, + lpGQOS: ?*QOS, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAConnectByNameW( + s: SOCKET, + nodename: [*:0]const u16, + servicename: [*:0]const u16, + LocalAddressLength: ?*u32, + LocalAddress: ?*sockaddr, + RemoteAddressLength: ?*u32, + RemoteAddress: ?*sockaddr, + timeout: ?*const timeval, + Reserved: *OVERLAPPED, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAConnectByNameA( + s: SOCKET, + nodename: [*:0]const u8, + servicename: [*:0]const u8, + LocalAddressLength: ?*u32, + LocalAddress: ?*sockaddr, + RemoteAddressLength: ?*u32, + RemoteAddress: ?*sockaddr, + timeout: ?*const timeval, + Reserved: *OVERLAPPED, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAConnectByList( + s: SOCKET, + SocketAddress: *SOCKET_ADDRESS_LIST, + LocalAddressLength: ?*u32, + LocalAddress: ?*sockaddr, + RemoteAddressLength: ?*u32, + RemoteAddress: ?*sockaddr, + timeout: ?*const timeval, + Reserved: *OVERLAPPED, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSACreateEvent() callconv(WINAPI) HANDLE; + +pub extern "ws2_32" fn WSADuplicateSocketA( + s: SOCKET, + dwProcessId: u32, + lpProtocolInfo: *WSAPROTOCOL_INFOA, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSADuplicateSocketW( + s: SOCKET, + dwProcessId: u32, + lpProtocolInfo: *WSAPROTOCOL_INFOW, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAEnumNetworkEvents( + s: SOCKET, + hEventObject: HANDLE, + lpNetworkEvents: *WSANETWORKEVENTS, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAEnumProtocolsA( + lpiProtocols: ?*i32, + lpProtocolBuffer: ?*WSAPROTOCOL_INFOA, + lpdwBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAEnumProtocolsW( + lpiProtocols: ?*i32, + lpProtocolBuffer: ?*WSAPROTOCOL_INFOW, + lpdwBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAEventSelect( + s: SOCKET, + hEventObject: HANDLE, + lNetworkEvents: i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAGetOverlappedResult( + s: SOCKET, + lpOverlapped: *OVERLAPPED, + lpcbTransfer: *u32, + fWait: BOOL, + lpdwFlags: *u32, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAGetQOSByName( + s: SOCKET, + lpQOSName: *WSABUF, + lpQOS: *QOS, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSAHtonl( + s: SOCKET, + hostlong: u32, + lpnetlong: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAHtons( + s: SOCKET, + hostshort: u16, + lpnetshort: *u16, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAIoctl( + s: SOCKET, + dwIoControlCode: u32, + lpvInBuffer: ?*const c_void, + cbInBuffer: u32, + lpvOutbuffer: ?*c_void, + cbOutbuffer: u32, + lpcbBytesReturned: *u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAJoinLeaf( s: SOCKET, name: *const sockaddr, - namelen: c_int, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn listen( + namelen: i32, + lpCallerdata: ?*WSABUF, + lpCalleeData: ?*WSABUF, + lpSQOS: ?*QOS, + lpGQOS: ?*QOS, + dwFlags: u32, +) callconv(WINAPI) SOCKET; + +pub extern "ws2_32" fn WSANtohl( + s: SOCKET, + netlong: u32, + lphostlong: *u32, +) callconv(WINAPI) u32; + +pub extern "ws2_32" fn WSANtohs( s: SOCKET, - backlog: c_int, -) callconv(WINAPI) c_int; + netshort: u16, + lphostshort: *u16, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn WSARecv( s: SOCKET, - lpBuffers: [*]const WSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesRecvd: ?*DWORD, - lpFlags: *DWORD, - lpOverlapped: ?*WSAOVERLAPPED, - lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(WINAPI) c_int; + lpBuffers: [*]WSABUF, + dwBufferCouynt: u32, + lpNumberOfBytesRecv: ?*u32, + lpFlags: *u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSARecvDisconnect( + s: SOCKET, + lpInboundDisconnectData: ?*WSABUF, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn WSARecvFrom( s: SOCKET, - lpBuffers: [*]const WSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesRecvd: ?*DWORD, - lpFlags: *DWORD, + lpBuffers: [*]WSABUF, + dwBuffercount: u32, + lpNumberOfBytesRecvd: ?*u32, + lpFlags: *u32, lpFrom: ?*sockaddr, - lpFromlen: ?*socklen_t, - lpOverlapped: ?*WSAOVERLAPPED, - lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(WINAPI) c_int; + lpFromlen: ?*i32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAResetEvent(hEvent: HANDLE) callconv(WINAPI) i32; + pub extern "ws2_32" fn WSASend( s: SOCKET, lpBuffers: [*]WSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesSent: ?*DWORD, - dwFlags: DWORD, - lpOverlapped: ?*WSAOVERLAPPED, - lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(WINAPI) c_int; + dwBufferCount: u32, + lpNumberOfBytesSent: ?*u32, + dwFlags: u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSASendMsg( + s: SOCKET, + lpMsg: *const WSAMSG_const, + dwFlags: u32, + lpNumberOfBytesSent: ?*u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSARecvMsg( + s: SOCKET, + lpMsg: *WSAMSG, + lpdwNumberOfBytesRecv: ?*u32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSASendDisconnect( + s: SOCKET, + lpOutboundDisconnectData: ?*WSABUF, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn WSASendTo( s: SOCKET, lpBuffers: [*]WSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesSent: ?*DWORD, - dwFlags: DWORD, + dwBufferCount: u32, + lpNumberOfBytesSent: ?*u32, + dwFlags: u32, lpTo: ?*const sockaddr, - iTolen: c_int, - lpOverlapped: ?*WSAOVERLAPPED, - lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(WINAPI) c_int; + iToLen: i32, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRounte: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSASetEvent( + hEvent: HANDLE, +) callconv(WINAPI) BOOL; + +pub extern "ws2_32" fn WSASocketA( + af: i32, + @"type": i32, + protocol: i32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOA, + g: u32, + dwFlags: u32, +) callconv(WINAPI) SOCKET; + +pub extern "ws2_32" fn WSASocketW( + af: i32, + @"type": i32, + protocol: i32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOW, + g: u32, + dwFlags: u32, +) callconv(WINAPI) SOCKET; + +pub extern "ws2_32" fn WSAWaitForMultipleEvents( + cEvents: u32, + lphEvents: [*]const HANDLE, + fWaitAll: BOOL, + dwTimeout: u32, + fAlertable: BOOL, +) callconv(WINAPI) u32; + +pub extern "ws2_32" fn WSAAddressToStringA( + lpsaAddress: *sockaddr, + dwAddressLength: u32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOA, + lpszAddressString: [*]u8, + lpdwAddressStringLength: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAAddressToStringW( + lpsaAddress: *sockaddr, + dwAddressLength: u32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOW, + lpszAddressString: [*]u16, + lpdwAddressStringLength: *u32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAStringToAddressA( + AddressString: [*:0]const u8, + AddressFamily: i32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOA, + lpAddress: *sockaddr, + lpAddressLength: *i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAStringToAddressW( + AddressString: [*:0]const u16, + AddressFamily: i32, + lpProtocolInfo: ?*WSAPROTOCOL_INFOW, + lpAddrses: *sockaddr, + lpAddressLength: *i32, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn WSAProviderConfigChange( + lpNotificationHandle: *HANDLE, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn WSAPoll( - fdArray: [*]pollfd, - fds: c_ulong, - timeout: c_int, -) callconv(WINAPI) c_int; + fdArray: [*]WSAPOLLFD, + fds: u32, + timeout: i32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn WSARecvEx( + s: SOCKET, + buf: [*]u8, + len: i32, + flags: *i32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn TransmitFile( + hSocket: SOCKET, + hFile: HANDLE, + nNumberOfBytesToWrite: u32, + nNumberOfBytesPerSend: u32, + lpOverlapped: ?*OVERLAPPED, + lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS, + dwReserved: u32, +) callconv(WINAPI) BOOL; + +pub extern "mswsock" fn AcceptEx( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: *c_void, + dwReceiveDataLength: u32, + dwLocalAddressLength: u32, + dwRemoteAddressLength: u32, + lpdwBytesReceived: *u32, + lpOverlapped: *OVERLAPPED, +) callconv(WINAPI) BOOL; + +pub extern "mswsock" fn GetAcceptExSockaddrs( + lpOutputBuffer: *c_void, + dwReceiveDataLength: u32, + dwLocalAddressLength: u32, + dwRemoteAddressLength: u32, + LocalSockaddr: **sockaddr, + LocalSockaddrLength: *i32, + RemoteSockaddr: **sockaddr, + RemoteSockaddrLength: *i32, +) callconv(WINAPI) void; + +pub extern "ws2_32" fn WSAProviderCompleteAsyncCall( + hAsyncCall: HANDLE, + iRetCode: i32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn EnumProtocolsA( + lpiProtocols: ?*i32, + lpProtocolBuffer: *c_void, + lpdwBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn EnumProtocolsW( + lpiProtocols: ?*i32, + lpProtocolBuffer: *c_void, + lpdwBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetAddressByNameA( + dwNameSpace: u32, + lpServiceType: *GUID, + lpServiceName: ?[*:0]u8, + lpiProtocols: ?*i32, + dwResolution: u32, + lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO, + lpCsaddrBuffer: *c_void, + lpAliasBuffer: ?[*:0]const u8, + lpdwAliasBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetAddressByNameW( + dwNameSpace: u32, + lpServiceType: *GUID, + lpServiceName: ?[*:0]u16, + lpiProtocols: ?*i32, + dwResolution: u32, + lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO, + lpCsaddrBuffer: *c_void, + ldwBufferLEngth: *u32, + lpAliasBuffer: ?[*:0]u16, + lpdwAliasBufferLength: *u32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetTypeByNameA( + lpServiceName: [*:0]u8, + lpServiceType: *GUID, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetTypeByNameW( + lpServiceName: [*:0]u16, + lpServiceType: *GUID, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetNameByTypeA( + lpServiceType: *GUID, + lpServiceName: [*:0]u8, + dwNameLength: u32, +) callconv(WINAPI) i32; + +pub extern "mswsock" fn GetNameByTypeW( + lpServiceType: *GUID, + lpServiceName: [*:0]u16, + dwNameLength: u32, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn getaddrinfo( - pNodeName: [*:0]const u8, - pServiceName: [*:0]const u8, - pHints: *const addrinfo, - ppResult: **addrinfo, + pNodeName: ?[*:0]const u8, + pServiceName: ?[*:0]const u8, + pHints: ?*const addrinfoa, + ppResult: **addrinfoa, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn GetAddrInfoExA( + pName: ?[*:0]const u8, + pServiceName: ?[*:0]const u8, + dwNameSapce: u32, + lpNspId: ?*GUID, + hints: ?*const addrinfoexA, + ppResult: **addrinfoexA, + timeout: ?*timeval, + lpOverlapped: ?*OVERLAPPED, + lpCompletionRoutine: ?LPLOOKUPSERVICE_COMPLETION_ROUTINE, ) callconv(WINAPI) i32; + +pub extern "ws2_32" fn GetAddrInfoExCancel( + lpHandle: *HANDLE, +) callconv(WINAPI) i32; + +pub extern "ws2_32" fn GetAddrInfoExOverlappedResult( + lpOverlapped: *OVERLAPPED, +) callconv(WINAPI) i32; + pub extern "ws2_32" fn freeaddrinfo( - pAddrInfo: *addrinfo, + pAddrInfo: ?*addrinfoa, ) callconv(WINAPI) void; -pub extern "ws2_32" fn ioctlsocket( - s: SOCKET, - cmd: c_long, - argp: *c_ulong, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn getsockname( - s: SOCKET, - name: *sockaddr, - namelen: *c_int, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn setsockopt( - s: SOCKET, - level: u32, - optname: u32, - optval: ?*const c_void, - optlen: socklen_t, -) callconv(WINAPI) c_int; -pub extern "ws2_32" fn shutdown( - s: SOCKET, - how: c_int, -) callconv(WINAPI) c_int; + +pub extern "ws2_32" fn FreeAddrInfoEx( + pAddrInfoEx: ?*addrinfoexA, +) callconv(WINAPI) void; + +pub extern "ws2_32" fn getnameinfo( + pSockaddr: *const sockaddr, + SockaddrLength: i32, + pNodeBuffer: ?[*]u8, + NodeBufferSize: u32, + pServiceBuffer: ?[*]u8, + ServiceBufferName: u32, + Flags: i32, +) callconv(WINAPI) i32; + +pub extern "IPHLPAPI" fn if_nametoindex( + InterfaceName: [*:0]const u8, +) callconv(WINAPI) u32; diff --git a/lib/std/x.zig b/lib/std/x.zig index a123591470..022261bf3b 100644 --- a/lib/std/x.zig +++ b/lib/std/x.zig @@ -7,7 +7,7 @@ const std = @import("std.zig"); pub const os = struct { - pub const Socket = @import("x/os/Socket.zig"); + pub const Socket = @import("x/os/socket.zig").Socket; pub usingnamespace @import("x/os/net.zig"); }; diff --git a/lib/std/x/net/tcp.zig b/lib/std/x/net/tcp.zig index 0740e3ab4f..ec20d13388 100644 --- a/lib/std/x/net/tcp.zig +++ b/lib/std/x/net/tcp.zig @@ -6,6 +6,7 @@ const std = @import("../../std.zig"); +const io = std.io; const os = std.os; const ip = std.x.net.ip; @@ -58,6 +59,28 @@ pub const Domain = extern enum(u16) { pub const Client = struct { socket: Socket, + /// Implements `std.io.Reader`. + pub const Reader = struct { + client: Client, + flags: u32, + + /// Implements `readFn` for `std.io.Reader`. + pub fn read(self: Client.Reader, buffer: []u8) !usize { + return self.client.read(buffer, self.flags); + } + }; + + /// Implements `std.io.Writer`. + pub const Writer = struct { + client: Client, + flags: u32, + + /// Implements `writeFn` for `std.io.Writer`. + pub fn write(self: Client.Writer, buffer: []const u8) !usize { + return self.client.write(buffer, self.flags); + } + }; + /// Opens a new client. pub fn init(domain: tcp.Domain, flags: u32) !Client { return Client{ @@ -89,41 +112,46 @@ pub const Client = struct { return self.socket.connect(address.into()); } - /// Read data from the socket into the buffer provided. It returns the - /// number of bytes read into the buffer provided. - pub fn read(self: Client, buf: []u8) !usize { - return self.socket.read(buf); + /// Extracts the error set of a function. + /// TODO: remove after Socket.{read, write} error unions are well-defined across different platforms + fn ErrorSetOf(comptime Function: anytype) type { + return @typeInfo(@typeInfo(@TypeOf(Function)).Fn.return_type.?).ErrorUnion.error_set; } - /// Read data from the socket into the buffer provided with a set of flags - /// specified. It returns the number of bytes read into the buffer provided. - pub fn recv(self: Client, buf: []u8, flags: u32) !usize { - return self.socket.recv(buf, flags); + /// Wrap `tcp.Client` into `std.io.Reader`. + pub fn reader(self: Client, flags: u32) io.Reader(Client.Reader, ErrorSetOf(Client.Reader.read), Client.Reader.read) { + return .{ .context = .{ .client = self, .flags = flags } }; } - /// Write a buffer of data provided to the socket. It returns the number - /// of bytes that are written to the socket. - pub fn write(self: Client, buf: []const u8) !usize { - return self.socket.write(buf); + /// Wrap `tcp.Client` into `std.io.Writer`. + pub fn writer(self: Client, flags: u32) io.Writer(Client.Writer, ErrorSetOf(Client.Writer.write), Client.Writer.write) { + return .{ .context = .{ .client = self, .flags = flags } }; } - /// Writes multiple I/O vectors to the socket. It returns the number - /// of bytes that are written to the socket. - pub fn writev(self: Client, buffers: []const os.iovec_const) !usize { - return self.socket.writev(buffers); + /// Read data from the socket into the buffer provided with a set of flags + /// specified. It returns the number of bytes read into the buffer provided. + pub fn read(self: Client, buf: []u8, flags: u32) !usize { + return self.socket.read(buf, flags); } /// Write a buffer of data provided to the socket with a set of flags specified. /// It returns the number of bytes that are written to the socket. - pub fn send(self: Client, buf: []const u8, flags: u32) !usize { - return self.socket.send(buf, flags); + pub fn write(self: Client, buf: []const u8, flags: u32) !usize { + return self.socket.write(buf, flags); } /// Writes multiple I/O vectors with a prepended message header to the socket /// with a set of flags specified. It returns the number of bytes that are /// written to the socket. - pub fn sendmsg(self: Client, msg: os.msghdr_const, flags: u32) !usize { - return self.socket.sendmsg(msg, flags); + pub fn writeVectorized(self: Client, msg: os.msghdr_const, flags: u32) !usize { + return self.socket.writeVectorized(msg, flags); + } + + /// Read multiple I/O vectors with a prepended message header from the socket + /// with a set of flags specified. It returns the number of bytes that were + /// read into the buffer provided. + pub fn readVectorized(self: Client, msg: *os.msghdr, flags: u32) !usize { + return self.socket.readVectorized(msg, flags); } /// Query and return the latest cached error on the client's underlying socket. @@ -146,12 +174,41 @@ pub const Client = struct { return ip.Address.from(try self.socket.getLocalAddress()); } + /// Query the address that the socket is connected to. + pub fn getRemoteAddress(self: Client) !ip.Address { + return ip.Address.from(try self.socket.getRemoteAddress()); + } + + /// Have close() or shutdown() syscalls block until all queued messages in the client have been successfully + /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption` + /// if the host does not support the option for a socket to linger around up until a timeout specified in + /// seconds. + pub fn setLinger(self: Client, timeout_seconds: ?u16) !void { + return self.socket.setLinger(timeout_seconds); + } + + /// Have keep-alive messages be sent periodically. The timing in which keep-alive messages are sent are + /// dependant on operating system settings. It returns `error.UnsupportedSocketOption` if the host does + /// not support periodically sending keep-alive messages on connection-oriented sockets. + pub fn setKeepAlive(self: Client, enabled: bool) !void { + return self.socket.setKeepAlive(enabled); + } + /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if /// the host does not support sockets disabling Nagle's algorithm. pub fn setNoDelay(self: Client, enabled: bool) !void { if (comptime @hasDecl(os, "TCP_NODELAY")) { const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled))); - return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_NODELAY, bytes); + return self.socket.setOption(os.IPPROTO_TCP, os.TCP_NODELAY, bytes); + } + return error.UnsupportedSocketOption; + } + + /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns + /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK. + pub fn setQuickACK(self: Client, enabled: bool) !void { + if (comptime @hasDecl(os, "TCP_QUICKACK")) { + return self.socket.setOption(os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(u32, @boolToInt(enabled)))); } return error.UnsupportedSocketOption; } @@ -169,7 +226,7 @@ pub const Client = struct { /// Set a timeout on the socket that is to occur if no messages are successfully written /// to its bound destination after a specified number of milliseconds. A subsequent write /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded. - pub fn setWriteTimeout(self: Client, milliseconds: usize) !void { + pub fn setWriteTimeout(self: Client, milliseconds: u32) !void { return self.socket.setWriteTimeout(milliseconds); } @@ -177,7 +234,7 @@ pub const Client = struct { /// from its bound destination after a specified number of milliseconds. A subsequent /// read from the socket will thereafter return `error.WouldBlock` should the timeout be /// exceeded. - pub fn setReadTimeout(self: Client, milliseconds: usize) !void { + pub fn setReadTimeout(self: Client, milliseconds: u32) !void { return self.socket.setReadTimeout(milliseconds); } }; @@ -251,16 +308,7 @@ pub const Listener = struct { /// support TCP Fast Open. pub fn setFastOpen(self: Listener, enabled: bool) !void { if (comptime @hasDecl(os, "TCP_FASTOPEN")) { - return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled)))); - } - return error.UnsupportedSocketOption; - } - - /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns - /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK. - pub fn setQuickACK(self: Listener, enabled: bool) !void { - if (comptime @hasDecl(os, "TCP_QUICKACK")) { - return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled)))); + return self.socket.setOption(os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(u32, @boolToInt(enabled)))); } return error.UnsupportedSocketOption; } @@ -322,7 +370,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" { defer conn.deinit(); var buf: [1]u8 = undefined; - try testing.expectError(error.WouldBlock, client.read(&buf)); + try testing.expectError(error.WouldBlock, client.reader(0).read(&buf)); } test "tcp/listener: bind to unspecified ipv4 address" { diff --git a/lib/std/x/os/Socket.zig b/lib/std/x/os/Socket.zig deleted file mode 100644 index 3656899aea..0000000000 --- a/lib/std/x/os/Socket.zig +++ /dev/null @@ -1,295 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. - -const std = @import("../../std.zig"); -const net = @import("net.zig"); - -const os = std.os; -const fmt = std.fmt; -const mem = std.mem; -const time = std.time; - -/// A generic socket abstraction. -const Socket = @This(); - -/// A socket-address pair. -pub const Connection = struct { - socket: Socket, - address: Socket.Address, - - /// Enclose a socket and address into a socket-address pair. - pub fn from(socket: Socket, address: Socket.Address) Socket.Connection { - return .{ .socket = socket, .address = address }; - } -}; - -/// A generic socket address abstraction. It is safe to directly access and modify -/// the fields of a `Socket.Address`. -pub const Address = union(enum) { - ipv4: net.IPv4.Address, - ipv6: net.IPv6.Address, - - /// Instantiate a new address with a IPv4 host and port. - pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address { - return .{ .ipv4 = .{ .host = host, .port = port } }; - } - - /// Instantiate a new address with a IPv6 host and port. - pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address { - return .{ .ipv6 = .{ .host = host, .port = port } }; - } - - /// Parses a `sockaddr` into a generic socket address. - pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address { - switch (address.family) { - os.AF_INET => { - const info = @ptrCast(*const os.sockaddr_in, address); - const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) }; - const port = mem.bigToNative(u16, info.port); - return Socket.Address.initIPv4(host, port); - }, - os.AF_INET6 => { - const info = @ptrCast(*const os.sockaddr_in6, address); - const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id }; - const port = mem.bigToNative(u16, info.port); - return Socket.Address.initIPv6(host, port); - }, - else => unreachable, - } - } - - /// Encodes a generic socket address into an extern union that may be reliably - /// casted into a `sockaddr` which may be passed into socket syscalls. - pub fn toNative(self: Socket.Address) extern union { - ipv4: os.sockaddr_in, - ipv6: os.sockaddr_in6, - } { - return switch (self) { - .ipv4 => |address| .{ - .ipv4 = .{ - .addr = @bitCast(u32, address.host.octets), - .port = mem.nativeToBig(u16, address.port), - }, - }, - .ipv6 => |address| .{ - .ipv6 = .{ - .addr = address.host.octets, - .port = mem.nativeToBig(u16, address.port), - .scope_id = address.host.scope_id, - .flowinfo = 0, - }, - }, - }; - } - - /// Returns the number of bytes that make up the `sockaddr` equivalent to the address. - pub fn getNativeSize(self: Socket.Address) u32 { - return switch (self) { - .ipv4 => @sizeOf(os.sockaddr_in), - .ipv6 => @sizeOf(os.sockaddr_in6), - }; - } - - /// Implements the `std.fmt.format` API. - pub fn format( - self: Socket.Address, - comptime layout: []const u8, - opts: fmt.FormatOptions, - writer: anytype, - ) !void { - switch (self) { - .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }), - .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }), - } - } -}; - -/// The underlying handle of a socket. -fd: os.socket_t, - -/// Open a new socket. -pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket { - return Socket{ .fd = try os.socket(domain, socket_type, protocol) }; -} - -/// Enclose a socket abstraction over an existing socket file descriptor. -pub fn from(fd: os.socket_t) Socket { - return Socket{ .fd = fd }; -} - -/// Closes the socket. -pub fn deinit(self: Socket) void { - os.closeSocket(self.fd); -} - -/// Shutdown either the read side, write side, or all side of the socket. -pub fn shutdown(self: Socket, how: os.ShutdownHow) !void { - return os.shutdown(self.fd, how); -} - -/// Binds the socket to an address. -pub fn bind(self: Socket, address: Socket.Address) !void { - return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize()); -} - -/// Start listening for incoming connections on the socket. -pub fn listen(self: Socket, max_backlog_size: u31) !void { - return os.listen(self.fd, max_backlog_size); -} - -/// Have the socket attempt to the connect to an address. -pub fn connect(self: Socket, address: Socket.Address) !void { - return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize()); -} - -/// Accept a pending incoming connection queued to the kernel backlog -/// of the socket. -pub fn accept(self: Socket, flags: u32) !Socket.Connection { - var address: os.sockaddr = undefined; - var address_len: u32 = @sizeOf(os.sockaddr); - - const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) }; - const socket_address = Socket.Address.fromNative(@alignCast(4, &address)); - - return Socket.Connection.from(socket, socket_address); -} - -/// Read data from the socket into the buffer provided. It returns the -/// number of bytes read into the buffer provided. -pub fn read(self: Socket, buf: []u8) !usize { - return os.read(self.fd, buf); -} - -/// Read data from the socket into the buffer provided with a set of flags -/// specified. It returns the number of bytes read into the buffer provided. -pub fn recv(self: Socket, buf: []u8, flags: u32) !usize { - return os.recv(self.fd, buf, flags); -} - -/// Write a buffer of data provided to the socket. It returns the number -/// of bytes that are written to the socket. -pub fn write(self: Socket, buf: []const u8) !usize { - return os.write(self.fd, buf); -} - -/// Writes multiple I/O vectors to the socket. It returns the number -/// of bytes that are written to the socket. -pub fn writev(self: Socket, buffers: []const os.iovec_const) !usize { - return os.writev(self.fd, buffers); -} - -/// Write a buffer of data provided to the socket with a set of flags specified. -/// It returns the number of bytes that are written to the socket. -pub fn send(self: Socket, buf: []const u8, flags: u32) !usize { - return os.send(self.fd, buf, flags); -} - -/// Writes multiple I/O vectors with a prepended message header to the socket -/// with a set of flags specified. It returns the number of bytes that are -/// written to the socket. -pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize { - return os.sendmsg(self.fd, msg, flags); -} - -/// Query the address that the socket is locally bounded to. -pub fn getLocalAddress(self: Socket) !Socket.Address { - var address: os.sockaddr = undefined; - var address_len: u32 = @sizeOf(os.sockaddr); - try os.getsockname(self.fd, &address, &address_len); - return Socket.Address.fromNative(@alignCast(4, &address)); -} - -/// Query and return the latest cached error on the socket. -pub fn getError(self: Socket) !void { - return os.getsockoptError(self.fd); -} - -/// Query the read buffer size of the socket. -pub fn getReadBufferSize(self: Socket) !u32 { - var value: u32 = undefined; - var value_len: u32 = @sizeOf(u32); - - const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len); - return switch (os.errno(rc)) { - 0 => value, - os.EBADF => error.BadFileDescriptor, - os.EFAULT => error.InvalidAddressSpace, - os.EINVAL => error.InvalidSocketOption, - os.ENOPROTOOPT => error.UnknownSocketOption, - os.ENOTSOCK => error.NotASocket, - else => |err| os.unexpectedErrno(err), - }; -} - -/// Query the write buffer size of the socket. -pub fn getWriteBufferSize(self: Socket) !u32 { - var value: u32 = undefined; - var value_len: u32 = @sizeOf(u32); - - const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len); - return switch (os.errno(rc)) { - 0 => value, - os.EBADF => error.BadFileDescriptor, - os.EFAULT => error.InvalidAddressSpace, - os.EINVAL => error.InvalidSocketOption, - os.ENOPROTOOPT => error.UnknownSocketOption, - os.ENOTSOCK => error.NotASocket, - else => |err| os.unexpectedErrno(err), - }; -} - -/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if -/// the host does not support sockets listening the same address. -pub fn setReuseAddress(self: Socket, enabled: bool) !void { - if (comptime @hasDecl(os, "SO_REUSEADDR")) { - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(usize, @boolToInt(enabled)))); - } - return error.UnsupportedSocketOption; -} - -/// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if -/// the host does not supports sockets listening on the same port. -pub fn setReusePort(self: Socket, enabled: bool) !void { - if (comptime @hasDecl(os, "SO_REUSEPORT")) { - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(usize, @boolToInt(enabled)))); - } - return error.UnsupportedSocketOption; -} - -/// Set the write buffer size of the socket. -pub fn setWriteBufferSize(self: Socket, size: u32) !void { - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size)); -} - -/// Set the read buffer size of the socket. -pub fn setReadBufferSize(self: Socket, size: u32) !void { - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size)); -} - -/// Set a timeout on the socket that is to occur if no messages are successfully written -/// to its bound destination after a specified number of milliseconds. A subsequent write -/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded. -pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void { - const timeout = os.timeval{ - .tv_sec = @intCast(i32, milliseconds / time.ms_per_s), - .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms), - }; - - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout)); -} - -/// Set a timeout on the socket that is to occur if no messages are successfully read -/// from its bound destination after a specified number of milliseconds. A subsequent -/// read from the socket will thereafter return `error.WouldBlock` should the timeout be -/// exceeded. -pub fn setReadTimeout(self: Socket, milliseconds: usize) !void { - const timeout = os.timeval{ - .tv_sec = @intCast(i32, milliseconds / time.ms_per_s), - .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms), - }; - - return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout)); -} diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig index 7cd400cc0a..0d13e6c7e0 100644 --- a/lib/std/x/os/net.zig +++ b/lib/std/x/os/net.zig @@ -20,6 +20,14 @@ pub fn resolveScopeID(name: []const u8) !u32 { if (comptime @hasDecl(os, "IFNAMESIZE")) { if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong; + if (comptime builtin.os.tag == .windows) { + var interface_name: [os.IFNAMESIZE]u8 = undefined; + mem.copy(u8, &interface_name, name); + interface_name[name.len] = 0; + + return os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name)); + } + const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0); defer os.closeSocket(fd); @@ -31,6 +39,7 @@ pub fn resolveScopeID(name: []const u8) !u32 { return @bitCast(u32, f.ifru.ivalue); } + return error.Unsupported; } diff --git a/lib/std/x/os/socket.zig b/lib/std/x/os/socket.zig new file mode 100644 index 0000000000..963a1adca6 --- /dev/null +++ b/lib/std/x/os/socket.zig @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +const std = @import("../../std.zig"); +const net = @import("net.zig"); + +const os = std.os; +const fmt = std.fmt; +const mem = std.mem; +const time = std.time; +const builtin = std.builtin; + +/// A generic, cross-platform socket abstraction. +pub const Socket = struct { + /// A socket-address pair. + pub const Connection = struct { + socket: Socket, + address: Socket.Address, + + /// Enclose a socket and address into a socket-address pair. + pub fn from(socket: Socket, address: Socket.Address) Socket.Connection { + return .{ .socket = socket, .address = address }; + } + }; + + /// A generic socket address abstraction. It is safe to directly access and modify + /// the fields of a `Socket.Address`. + pub const Address = union(enum) { + ipv4: net.IPv4.Address, + ipv6: net.IPv6.Address, + + /// Instantiate a new address with a IPv4 host and port. + pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address { + return .{ .ipv4 = .{ .host = host, .port = port } }; + } + + /// Instantiate a new address with a IPv6 host and port. + pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address { + return .{ .ipv6 = .{ .host = host, .port = port } }; + } + + /// Parses a `sockaddr` into a generic socket address. + pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address { + switch (address.family) { + os.AF_INET => { + const info = @ptrCast(*const os.sockaddr_in, address); + const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) }; + const port = mem.bigToNative(u16, info.port); + return Socket.Address.initIPv4(host, port); + }, + os.AF_INET6 => { + const info = @ptrCast(*const os.sockaddr_in6, address); + const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id }; + const port = mem.bigToNative(u16, info.port); + return Socket.Address.initIPv6(host, port); + }, + else => unreachable, + } + } + + /// Encodes a generic socket address into an extern union that may be reliably + /// casted into a `sockaddr` which may be passed into socket syscalls. + pub fn toNative(self: Socket.Address) extern union { + ipv4: os.sockaddr_in, + ipv6: os.sockaddr_in6, + } { + return switch (self) { + .ipv4 => |address| .{ + .ipv4 = .{ + .addr = @bitCast(u32, address.host.octets), + .port = mem.nativeToBig(u16, address.port), + }, + }, + .ipv6 => |address| .{ + .ipv6 = .{ + .addr = address.host.octets, + .port = mem.nativeToBig(u16, address.port), + .scope_id = address.host.scope_id, + .flowinfo = 0, + }, + }, + }; + } + + /// Returns the number of bytes that make up the `sockaddr` equivalent to the address. + pub fn getNativeSize(self: Socket.Address) u32 { + return switch (self) { + .ipv4 => @sizeOf(os.sockaddr_in), + .ipv6 => @sizeOf(os.sockaddr_in6), + }; + } + + /// Implements the `std.fmt.format` API. + pub fn format( + self: Socket.Address, + comptime layout: []const u8, + opts: fmt.FormatOptions, + writer: anytype, + ) !void { + switch (self) { + .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }), + .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }), + } + } + }; + + /// The underlying handle of a socket. + fd: os.socket_t, + + /// Enclose a socket abstraction over an existing socket file descriptor. + pub fn from(fd: os.socket_t) Socket { + return Socket{ .fd = fd }; + } + + /// Mix in socket syscalls depending on the platform we are compiling against. + pub usingnamespace switch (builtin.os.tag) { + .windows => @import("socket_windows.zig"), + else => @import("socket_posix.zig"), + }.Mixin(Socket); +}; diff --git a/lib/std/x/os/socket_posix.zig b/lib/std/x/os/socket_posix.zig new file mode 100644 index 0000000000..1e54c5c7a2 --- /dev/null +++ b/lib/std/x/os/socket_posix.zig @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +const std = @import("../../std.zig"); + +const os = std.os; +const mem = std.mem; +const time = std.time; + +pub fn Mixin(comptime Socket: type) type { + return struct { + /// Open a new socket. + pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket { + return Socket{ .fd = try os.socket(domain, socket_type, protocol) }; + } + + /// Closes the socket. + pub fn deinit(self: Socket) void { + os.closeSocket(self.fd); + } + + /// Shutdown either the read side, write side, or all side of the socket. + pub fn shutdown(self: Socket, how: os.ShutdownHow) !void { + return os.shutdown(self.fd, how); + } + + /// Binds the socket to an address. + pub fn bind(self: Socket, address: Socket.Address) !void { + return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize()); + } + + /// Start listening for incoming connections on the socket. + pub fn listen(self: Socket, max_backlog_size: u31) !void { + return os.listen(self.fd, max_backlog_size); + } + + /// Have the socket attempt to the connect to an address. + pub fn connect(self: Socket, address: Socket.Address) !void { + return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize()); + } + + /// Accept a pending incoming connection queued to the kernel backlog + /// of the socket. + pub fn accept(self: Socket, flags: u32) !Socket.Connection { + var address: os.sockaddr_storage = undefined; + var address_len: u32 = @sizeOf(os.sockaddr_storage); + + const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) }; + const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address)); + + return Socket.Connection.from(socket, socket_address); + } + + /// Read data from the socket into the buffer provided with a set of flags + /// specified. It returns the number of bytes read into the buffer provided. + pub fn read(self: Socket, buf: []u8, flags: u32) !usize { + return os.recv(self.fd, buf, flags); + } + + /// Write a buffer of data provided to the socket with a set of flags specified. + /// It returns the number of bytes that are written to the socket. + pub fn write(self: Socket, buf: []const u8, flags: u32) !usize { + return os.send(self.fd, buf, flags); + } + + /// Writes multiple I/O vectors with a prepended message header to the socket + /// with a set of flags specified. It returns the number of bytes that are + /// written to the socket. + pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize { + return os.sendmsg(self.fd, msg, flags); + } + + /// Read multiple I/O vectors with a prepended message header from the socket + /// with a set of flags specified. It returns the number of bytes that were + /// read into the buffer provided. + pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize { + if (comptime @hasDecl(os.system, "recvmsg")) { + while (true) { + const rc = os.system.recvmsg(self.fd, msg, flags); + return switch (os.errno(rc)) { + 0 => @intCast(usize, rc), + os.EBADF => unreachable, // always a race condition + os.EFAULT => unreachable, + os.EINVAL => unreachable, + os.ENOTCONN => unreachable, + os.ENOTSOCK => unreachable, + os.EINTR => continue, + os.EAGAIN => error.WouldBlock, + os.ENOMEM => error.SystemResources, + os.ECONNREFUSED => error.ConnectionRefused, + os.ECONNRESET => error.ConnectionResetByPeer, + else => |err| os.unexpectedErrno(err), + }; + } + } + return error.NotSupported; + } + + /// Query the address that the socket is locally bounded to. + pub fn getLocalAddress(self: Socket) !Socket.Address { + var address: os.sockaddr_storage = undefined; + var address_len: u32 = @sizeOf(os.sockaddr_storage); + try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len); + return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address)); + } + + /// Query the address that the socket is connected to. + pub fn getRemoteAddress(self: Socket) !Socket.Address { + var address: os.sockaddr_storage = undefined; + var address_len: u32 = @sizeOf(os.sockaddr_storage); + try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len); + return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address)); + } + + /// Query and return the latest cached error on the socket. + pub fn getError(self: Socket) !void { + return os.getsockoptError(self.fd); + } + + /// Query the read buffer size of the socket. + pub fn getReadBufferSize(self: Socket) !u32 { + var value: u32 = undefined; + var value_len: u32 = @sizeOf(u32); + + const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len); + return switch (os.errno(rc)) { + 0 => value, + os.EBADF => error.BadFileDescriptor, + os.EFAULT => error.InvalidAddressSpace, + os.EINVAL => error.InvalidSocketOption, + os.ENOPROTOOPT => error.UnknownSocketOption, + os.ENOTSOCK => error.NotASocket, + else => |err| os.unexpectedErrno(err), + }; + } + + /// Query the write buffer size of the socket. + pub fn getWriteBufferSize(self: Socket) !u32 { + var value: u32 = undefined; + var value_len: u32 = @sizeOf(u32); + + const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len); + return switch (os.errno(rc)) { + 0 => value, + os.EBADF => error.BadFileDescriptor, + os.EFAULT => error.InvalidAddressSpace, + os.EINVAL => error.InvalidSocketOption, + os.ENOPROTOOPT => error.UnknownSocketOption, + os.ENOTSOCK => error.NotASocket, + else => |err| os.unexpectedErrno(err), + }; + } + + /// Set a socket option. + pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void { + return os.setsockopt(self.fd, level, code, value); + } + + /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully + /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption` + /// if the host does not support the option for a socket to linger around up until a timeout specified in + /// seconds. + pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void { + if (comptime @hasDecl(os, "SO_LINGER")) { + const settings = extern struct { + l_onoff: c_int, + l_linger: c_int, + }{ + .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)), + .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0, + }; + + return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings)); + } + + return error.UnsupportedSocketOption; + } + + /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive + /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if + /// the host does not support periodically sending keep-alive messages on connection-oriented sockets. + pub fn setKeepAlive(self: Socket, enabled: bool) !void { + if (comptime @hasDecl(os, "SO_KEEPALIVE")) { + return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + } + return error.UnsupportedSocketOption; + } + + /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if + /// the host does not support sockets listening the same address. + pub fn setReuseAddress(self: Socket, enabled: bool) !void { + if (comptime @hasDecl(os, "SO_REUSEADDR")) { + return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + } + return error.UnsupportedSocketOption; + } + + /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if + /// the host does not supports sockets listening on the same port. + pub fn setReusePort(self: Socket, enabled: bool) !void { + if (comptime @hasDecl(os, "SO_REUSEPORT")) { + return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + } + return error.UnsupportedSocketOption; + } + + /// Set the write buffer size of the socket. + pub fn setWriteBufferSize(self: Socket, size: u32) !void { + return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size)); + } + + /// Set the read buffer size of the socket. + pub fn setReadBufferSize(self: Socket, size: u32) !void { + return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size)); + } + + /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is + /// set on a non-blocking socket. + /// + /// Set a timeout on the socket that is to occur if no messages are successfully written + /// to its bound destination after a specified number of milliseconds. A subsequent write + /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded. + pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void { + const timeout = os.timeval{ + .tv_sec = @intCast(i32, milliseconds / time.ms_per_s), + .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms), + }; + + return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout)); + } + + /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is + /// set on a non-blocking socket. + /// + /// Set a timeout on the socket that is to occur if no messages are successfully read + /// from its bound destination after a specified number of milliseconds. A subsequent + /// read from the socket will thereafter return `error.WouldBlock` should the timeout be + /// exceeded. + pub fn setReadTimeout(self: Socket, milliseconds: usize) !void { + const timeout = os.timeval{ + .tv_sec = @intCast(i32, milliseconds / time.ms_per_s), + .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms), + }; + + return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout)); + } + }; +} diff --git a/lib/std/x/os/socket_windows.zig b/lib/std/x/os/socket_windows.zig new file mode 100644 index 0000000000..6dd1f9a6a9 --- /dev/null +++ b/lib/std/x/os/socket_windows.zig @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +const std = @import("../../std.zig"); +const net = @import("net.zig"); + +const os = std.os; +const mem = std.mem; + +const windows = std.os.windows; +const ws2_32 = windows.ws2_32; + +pub fn Mixin(comptime Socket: type) type { + return struct { + /// Open a new socket. + pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket { + var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC); + + var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED; + if (socket_type & os.SOCK_CLOEXEC != 0) { + filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT; + } + + const fd = ws2_32.WSASocketW( + @intCast(i32, domain), + @intCast(i32, filtered_socket_type), + @intCast(i32, protocol), + null, + 0, + filtered_flags, + ); + if (fd == ws2_32.INVALID_SOCKET) { + return switch (ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => { + _ = try windows.WSAStartup(2, 2); + return Socket.init(domain, socket_type, protocol); + }, + .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported, + .WSAEMFILE => error.ProcessFdQuotaExceeded, + .WSAENOBUFS => error.SystemResources, + .WSAEPROTONOSUPPORT => error.ProtocolNotSupported, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return Socket{ .fd = fd }; + } + + /// Closes the socket. + pub fn deinit(self: Socket) void { + _ = ws2_32.closesocket(self.fd); + } + + /// Shutdown either the read side, write side, or all side of the socket. + pub fn shutdown(self: Socket, how: os.ShutdownHow) !void { + const rc = ws2_32.shutdown(self.fd, switch (how) { + .recv => ws2_32.SD_RECEIVE, + .send => ws2_32.SD_SEND, + .both => ws2_32.SD_BOTH, + }); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAECONNABORTED => return error.ConnectionAborted, + .WSAECONNRESET => return error.ConnectionResetByPeer, + .WSAEINPROGRESS => return error.BlockingOperationInProgress, + .WSAEINVAL => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAENOTCONN => return error.SocketNotConnected, + .WSAENOTSOCK => unreachable, + .WSANOTINITIALISED => unreachable, + else => |err| return windows.unexpectedWSAError(err), + }; + } + } + + /// Binds the socket to an address. + pub fn bind(self: Socket, address: Socket.Address) !void { + const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize())); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAEACCES => error.AccessDenied, + .WSAEADDRINUSE => error.AddressInUse, + .WSAEADDRNOTAVAIL => error.AddressNotAvailable, + .WSAEFAULT => error.BadAddress, + .WSAEINPROGRESS => error.WouldBlock, + .WSAEINVAL => error.AlreadyBound, + .WSAENOBUFS => error.NoEphemeralPortsAvailable, + .WSAENOTSOCK => error.NotASocket, + else => |err| windows.unexpectedWSAError(err), + }; + } + } + + /// Start listening for incoming connections on the socket. + pub fn listen(self: Socket, max_backlog_size: u31) !void { + const rc = ws2_32.listen(self.fd, max_backlog_size); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAEADDRINUSE => error.AddressInUse, + .WSAEISCONN => error.AlreadyConnected, + .WSAEINVAL => error.SocketNotBound, + .WSAEMFILE, .WSAENOBUFS => error.SystemResources, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAEINPROGRESS => error.WouldBlock, + else => |err| windows.unexpectedWSAError(err), + }; + } + } + + /// Have the socket attempt to the connect to an address. + pub fn connect(self: Socket, address: Socket.Address) !void { + const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize())); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAEADDRINUSE => error.AddressInUse, + .WSAEADDRNOTAVAIL => error.AddressNotAvailable, + .WSAECONNREFUSED => error.ConnectionRefused, + .WSAETIMEDOUT => error.ConnectionTimedOut, + .WSAEFAULT => error.BadAddress, + .WSAEINVAL => error.ListeningSocket, + .WSAEISCONN => error.AlreadyConnected, + .WSAENOTSOCK => error.NotASocket, + .WSAEACCES => error.BroadcastNotEnabled, + .WSAENOBUFS => error.SystemResources, + .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported, + .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock, + .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable, + else => |err| windows.unexpectedWSAError(err), + }; + } + } + + /// Accept a pending incoming connection queued to the kernel backlog + /// of the socket. + pub fn accept(self: Socket, flags: u32) !Socket.Connection { + var address: ws2_32.sockaddr_storage = undefined; + var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage); + + const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len); + if (rc == ws2_32.INVALID_SOCKET) { + return switch (ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEFAULT => unreachable, + .WSAEINVAL => error.SocketNotListening, + .WSAEMFILE => error.ProcessFdQuotaExceeded, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENOBUFS => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAEWOULDBLOCK => error.WouldBlock, + else => |err| windows.unexpectedWSAError(err), + }; + } + + const socket = Socket.from(rc); + const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address)); + + return Socket.Connection.from(socket, socket_address); + } + + /// Read data from the socket into the buffer provided with a set of flags + /// specified. It returns the number of bytes read into the buffer provided. + pub fn read(self: Socket, buf: []u8, flags: u32) !usize { + var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }}; + var num_bytes: u32 = undefined; + var flags_ = flags; + + const rc = ws2_32.WSARecv(self.fd, bufs, 1, &num_bytes, &flags_, null, null); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAECONNABORTED => error.ConnectionAborted, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEDISCON => error.ConnectionClosedByPeer, + .WSAEFAULT => error.BadBuffer, + .WSAEINPROGRESS, + .WSAEWOULDBLOCK, + .WSA_IO_PENDING, + .WSAETIMEDOUT, + => error.WouldBlock, + .WSAEINTR => error.Cancelled, + .WSAEINVAL => error.SocketNotBound, + .WSAEMSGSIZE => error.MessageTooLarge, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.NetworkReset, + .WSAENOTCONN => error.SocketNotConnected, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAESHUTDOWN => error.AlreadyShutdown, + .WSA_OPERATION_ABORTED => error.OperationAborted, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return @intCast(usize, num_bytes); + } + + /// Write a buffer of data provided to the socket with a set of flags specified. + /// It returns the number of bytes that are written to the socket. + pub fn write(self: Socket, buf: []const u8, flags: u32) !usize { + var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = @intToPtr([*]u8, @ptrToInt(buf.ptr)) }}; + var num_bytes: u32 = undefined; + + const rc = ws2_32.WSASend(self.fd, bufs, 1, &num_bytes, flags, null, null); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAECONNABORTED => error.ConnectionAborted, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEFAULT => error.BadBuffer, + .WSAEINPROGRESS, + .WSAEWOULDBLOCK, + .WSA_IO_PENDING, + .WSAETIMEDOUT, + => error.WouldBlock, + .WSAEINTR => error.Cancelled, + .WSAEINVAL => error.SocketNotBound, + .WSAEMSGSIZE => error.MessageTooLarge, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.NetworkReset, + .WSAENOBUFS => error.BufferDeadlock, + .WSAENOTCONN => error.SocketNotConnected, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAESHUTDOWN => error.AlreadyShutdown, + .WSA_OPERATION_ABORTED => error.OperationAborted, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return @intCast(usize, num_bytes); + } + + /// Writes multiple I/O vectors with a prepended message header to the socket + /// with a set of flags specified. It returns the number of bytes that are + /// written to the socket. + pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize { + const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG); + + var num_bytes: u32 = undefined; + + const rc = call(self.fd, &msg, flags, &num_bytes, null, null); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAECONNABORTED => error.ConnectionAborted, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEFAULT => error.BadBuffer, + .WSAEINPROGRESS, + .WSAEWOULDBLOCK, + .WSA_IO_PENDING, + .WSAETIMEDOUT, + => error.WouldBlock, + .WSAEINTR => error.Cancelled, + .WSAEINVAL => error.SocketNotBound, + .WSAEMSGSIZE => error.MessageTooLarge, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.NetworkReset, + .WSAENOBUFS => error.BufferDeadlock, + .WSAENOTCONN => error.SocketNotConnected, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAESHUTDOWN => error.AlreadyShutdown, + .WSA_OPERATION_ABORTED => error.OperationAborted, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return @intCast(usize, num_bytes); + } + + /// Read multiple I/O vectors with a prepended message header from the socket + /// with a set of flags specified. It returns the number of bytes that were + /// read into the buffer provided. + pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize { + const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG); + + var num_bytes: u32 = undefined; + + const rc = call(self.fd, msg, &num_bytes, null, null); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSAECONNABORTED => error.ConnectionAborted, + .WSAECONNRESET => error.ConnectionResetByPeer, + .WSAEDISCON => error.ConnectionClosedByPeer, + .WSAEFAULT => error.BadBuffer, + .WSAEINPROGRESS, + .WSAEWOULDBLOCK, + .WSA_IO_PENDING, + .WSAETIMEDOUT, + => error.WouldBlock, + .WSAEINTR => error.Cancelled, + .WSAEINVAL => error.SocketNotBound, + .WSAEMSGSIZE => error.MessageTooLarge, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENETRESET => error.NetworkReset, + .WSAENOTCONN => error.SocketNotConnected, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEOPNOTSUPP => error.OperationNotSupported, + .WSAESHUTDOWN => error.AlreadyShutdown, + .WSA_OPERATION_ABORTED => error.OperationAborted, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return @intCast(usize, num_bytes); + } + + /// Query the address that the socket is locally bounded to. + pub fn getLocalAddress(self: Socket) !Socket.Address { + var address: ws2_32.sockaddr_storage = undefined; + var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage); + + const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAEFAULT => unreachable, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEINVAL => error.SocketNotBound, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address)); + } + + /// Query the address that the socket is connected to. + pub fn getRemoteAddress(self: Socket) !Socket.Address { + var address: ws2_32.sockaddr_storage = undefined; + var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage); + + const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAEFAULT => unreachable, + .WSAENETDOWN => error.NetworkSubsystemFailed, + .WSAENOTSOCK => error.FileDescriptorNotASocket, + .WSAEINVAL => error.SocketNotBound, + else => |err| windows.unexpectedWSAError(err), + }; + } + + return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address)); + } + + /// Query and return the latest cached error on the socket. + pub fn getError(self: Socket) !void { + return {}; + } + + /// Query the read buffer size of the socket. + pub fn getReadBufferSize(self: Socket) !u32 { + return 0; + } + + /// Query the write buffer size of the socket. + pub fn getWriteBufferSize(self: Socket) !u32 { + return 0; + } + + /// Set a socket option. + pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void { + const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len)); + if (rc == ws2_32.SOCKET_ERROR) { + return switch (ws2_32.WSAGetLastError()) { + .WSANOTINITIALISED => unreachable, + .WSAENETDOWN => return error.NetworkSubsystemFailed, + .WSAEFAULT => unreachable, + .WSAENOTSOCK => return error.FileDescriptorNotASocket, + .WSAEINVAL => return error.SocketNotBound, + else => |err| windows.unexpectedWSAError(err), + }; + } + } + + /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully + /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption` + /// if the host does not support the option for a socket to linger around up until a timeout specified in + /// seconds. + pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void { + const settings = ws2_32.linger{ + .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)), + .l_linger = if (timeout_seconds) |seconds| seconds else 0, + }; + + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings)); + } + + /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive + /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if + /// the host does not support periodically sending keep-alive messages on connection-oriented sockets. + pub fn setKeepAlive(self: Socket, enabled: bool) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + } + + /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if + /// the host does not support sockets listening the same address. + pub fn setReuseAddress(self: Socket, enabled: bool) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + } + + /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if + /// the host does not supports sockets listening on the same port. + /// + /// TODO: verify if this truly mimicks SO_REUSEPORT behavior, or if SO_REUSE_UNICASTPORT provides the correct behavior + pub fn setReusePort(self: Socket, enabled: bool) !void { + try self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_BROADCAST, mem.asBytes(&@as(u32, @boolToInt(enabled)))); + try self.setReuseAddress(enabled); + } + + /// Set the write buffer size of the socket. + pub fn setWriteBufferSize(self: Socket, size: u32) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDBUF, mem.asBytes(&size)); + } + + /// Set the read buffer size of the socket. + pub fn setReadBufferSize(self: Socket, size: u32) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVBUF, mem.asBytes(&size)); + } + + /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is + /// set on a non-blocking socket. + /// + /// Set a timeout on the socket that is to occur if no messages are successfully written + /// to its bound destination after a specified number of milliseconds. A subsequent write + /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded. + pub fn setWriteTimeout(self: Socket, milliseconds: u32) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDTIMEO, mem.asBytes(&milliseconds)); + } + + /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is + /// set on a non-blocking socket. + /// + /// Set a timeout on the socket that is to occur if no messages are successfully read + /// from its bound destination after a specified number of milliseconds. A subsequent + /// read from the socket will thereafter return `error.WouldBlock` should the timeout be + /// exceeded. + pub fn setReadTimeout(self: Socket, milliseconds: u32) !void { + return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVTIMEO, mem.asBytes(&milliseconds)); + } + }; +} |
