| author | |
| committer | |
| log | 2eaab1e65e23ebc0a736ce96073a43bf59c916ea |
| tree | 3a97f20c608dbae93781dd9d6556181660744b3d |
| parent | 65c3833ec2793747961f532510feb4fbb52fd6a6 |
5 files changed, 132 insertions(+), 23 deletions(-)
lib/std/c.zig+14| ... | @@ -194,6 +194,20 @@ pub usingnamespace switch (builtin.os.tag) { | ... | @@ -194,6 +194,20 @@ pub usingnamespace switch (builtin.os.tag) { |
| 194 | pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; | 194 | pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; |
| 195 | pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; | 195 | pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; |
| 196 | }, | 196 | }, |
| 197 | .windows => struct { | ||
| 198 | // TODO: copied the else case and removed the socket function (because its in ws2_32) | ||
| 199 | // need to verify which of these is actually supported on windows | ||
| 200 | pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; | ||
| 201 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; | ||
| 202 | pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; | ||
| 203 | pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; | ||
| 204 | pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; | ||
| 205 | pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; | ||
| 206 | pub extern "c" fn sched_yield() c_int; | ||
| 207 | pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; | ||
| 208 | pub extern "c" fn sigprocmask(how: c_int, noalias set: ?*const sigset_t, noalias oset: ?*sigset_t) c_int; | ||
| 209 | pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int; | ||
| 210 | }, | ||
| 197 | else => struct { | 211 | else => struct { |
| 198 | pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; | 212 | pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; |
| 199 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; | 213 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; |
lib/std/net.zig+40-21| ... | @@ -406,7 +406,8 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) | ... | @@ -406,7 +406,8 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 406 | 406 | ||
| 407 | pub fn tcpConnectToAddress(address: Address) !fs.File { | 407 | pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 408 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 408 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 409 | const sock_flags = os.SOCK_STREAM | os.SOCK_CLOEXEC | nonblock; | 409 | const sock_flags = os.SOCK_STREAM | nonblock | |
| 410 | (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC); | ||
| 410 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); | 411 | const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP); |
| 411 | errdefer os.close(sockfd); | 412 | errdefer os.close(sockfd); |
| 412 | try os.connect(sockfd, &address.any, address.getOsSockLen()); | 413 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| ... | @@ -431,16 +432,16 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -431,16 +432,16 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 431 | const arena = &result.arena.allocator; | 432 | const arena = &result.arena.allocator; |
| 432 | errdefer result.arena.deinit(); | 433 | errdefer result.arena.deinit(); |
| 433 | 434 | ||
| 434 | if (builtin.link_libc) { | 435 | if (builtin.os.tag == .windows or builtin.link_libc) { |
| 435 | const c = std.c; | ||
| 436 | const name_c = try std.cstr.addNullByte(allocator, name); | 436 | const name_c = try std.cstr.addNullByte(allocator, name); |
| 437 | defer allocator.free(name_c); | 437 | defer allocator.free(name_c); |
| 438 | 438 | ||
| 439 | const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port}); | 439 | const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port}); |
| 440 | defer allocator.free(port_c); | 440 | defer allocator.free(port_c); |
| 441 | 441 | ||
| 442 | const sys = if (builtin.os.tag == .windows) os.windows.ws2_32 else os.system; | ||
| 442 | const hints = os.addrinfo{ | 443 | const hints = os.addrinfo{ |
| 443 | .flags = c.AI_NUMERICSERV, | 444 | .flags = sys.AI_NUMERICSERV, |
| 444 | .family = os.AF_UNSPEC, | 445 | .family = os.AF_UNSPEC, |
| 445 | .socktype = os.SOCK_STREAM, | 446 | .socktype = os.SOCK_STREAM, |
| 446 | .protocol = os.IPPROTO_TCP, | 447 | .protocol = os.IPPROTO_TCP, |
| ... | @@ -450,24 +451,42 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -450,24 +451,42 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 450 | .next = null, | 451 | .next = null, |
| 451 | }; | 452 | }; |
| 452 | var res: *os.addrinfo = undefined; | 453 | var res: *os.addrinfo = undefined; |
| 453 | switch (os.system.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res)) { | 454 | const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res); |
| 454 | @intToEnum(os.system.EAI, 0) => {}, | 455 | if (builtin.os.tag == .windows) { |
| 455 | .ADDRFAMILY => return error.HostLacksNetworkAddresses, | 456 | const ws2_32 = os.windows.ws2_32; |
| 456 | .AGAIN => return error.TemporaryNameServerFailure, | 457 | switch (rc) { |
| 457 | .BADFLAGS => unreachable, // Invalid hints | 458 | 0 => {}, |
| 458 | .FAIL => return error.NameServerFailure, | 459 | @enumToInt(ws2_32.WinsockError.WSATRY_AGAIN) => return error.TemporaryNameServerFailure, |
| 459 | .FAMILY => return error.AddressFamilyNotSupported, | 460 | @enumToInt(ws2_32.WinsockError.WSANO_RECOVERY) => return error.NameServerFailure, |
| 460 | .MEMORY => return error.OutOfMemory, | 461 | @enumToInt(ws2_32.WinsockError.WSAEAFNOSUPPORT) => return error.AddressFamilyNotSupported, |
| 461 | .NODATA => return error.HostLacksNetworkAddresses, | 462 | @enumToInt(ws2_32.WinsockError.WSA_NOT_ENOUGH_MEMORY) => return error.OutOfMemory, |
| 462 | .NONAME => return error.UnknownHostName, | 463 | @enumToInt(ws2_32.WinsockError.WSAHOST_NOT_FOUND) => return error.UnknownHostName, |
| 463 | .SERVICE => return error.ServiceUnavailable, | 464 | @enumToInt(ws2_32.WinsockError.WSATYPE_NOT_FOUND) => return error.ServiceUnavailable, |
| 464 | .SOCKTYPE => unreachable, // Invalid socket type requested in hints | 465 | @enumToInt(ws2_32.WinsockError.WSAEINVAL) => unreachable, |
| 465 | .SYSTEM => switch (os.errno(-1)) { | 466 | @enumToInt(ws2_32.WinsockError.WSAESOCKTNOSUPPORT) => unreachable, |
| 466 | else => |e| return os.unexpectedErrno(e), | 467 | else => |err| return os.windows.unexpectedWSAError( |
| 467 | }, | 468 | std.meta.intToEnum(ws2_32.WinsockError, err) catch unreachable), |
| 468 | else => unreachable, | 469 | } |
| 470 | } else { | ||
| 471 | switch (rc) { | ||
| 472 | @intToEnum(sys.EAI, 0) => {}, | ||
| 473 | .ADDRFAMILY => return error.HostLacksNetworkAddresses, | ||
| 474 | .AGAIN => return error.TemporaryNameServerFailure, | ||
| 475 | .BADFLAGS => unreachable, // Invalid hints | ||
| 476 | .FAIL => return error.NameServerFailure, | ||
| 477 | .FAMILY => return error.AddressFamilyNotSupported, | ||
| 478 | .MEMORY => return error.OutOfMemory, | ||
| 479 | .NODATA => return error.HostLacksNetworkAddresses, | ||
| 480 | .NONAME => return error.UnknownHostName, | ||
| 481 | .SERVICE => return error.ServiceUnavailable, | ||
| 482 | .SOCKTYPE => unreachable, // Invalid socket type requested in hints | ||
| 483 | .SYSTEM => switch (os.errno(-1)) { | ||
| 484 | else => |e| return os.unexpectedErrno(e), | ||
| 485 | }, | ||
| 486 | else => unreachable, | ||
| 487 | } | ||
| 469 | } | 488 | } |
| 470 | defer os.system.freeaddrinfo(res); | 489 | defer sys.freeaddrinfo(res); |
| 471 | 490 | ||
| 472 | const addr_count = blk: { | 491 | const addr_count = blk: { |
| 473 | var count: usize = 0; | 492 | var count: usize = 0; |
lib/std/os.zig+40-2| ... | @@ -69,6 +69,8 @@ else switch (builtin.os.tag) { | ... | @@ -69,6 +69,8 @@ else switch (builtin.os.tag) { |
| 69 | 69 | ||
| 70 | pub usingnamespace @import("os/bits.zig"); | 70 | pub usingnamespace @import("os/bits.zig"); |
| 71 | 71 | ||
| 72 | pub const socket_t = if (builtin.os.tag == .windows) windows.ws2_32.SOCKET else fd_t; | ||
| 73 | |||
| 72 | /// See also `getenv`. Populated by startup code before main(). | 74 | /// See also `getenv`. Populated by startup code before main(). |
| 73 | /// TODO this is a footgun because the value will be undefined when using `zig build-lib`. | 75 | /// TODO this is a footgun because the value will be undefined when using `zig build-lib`. |
| 74 | /// https://github.com/ziglang/zig/issues/4524 | 76 | /// https://github.com/ziglang/zig/issues/4524 |
| ... | @@ -2443,7 +2445,21 @@ pub const SocketError = error{ | ... | @@ -2443,7 +2445,21 @@ pub const SocketError = error{ |
| 2443 | SocketTypeNotSupported, | 2445 | SocketTypeNotSupported, |
| 2444 | } || UnexpectedError; | 2446 | } || UnexpectedError; |
| 2445 | 2447 | ||
| 2446 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t { | 2448 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t { |
| 2449 | if (builtin.os.tag == .windows) { | ||
| 2450 | // NOTE: cannot remove SOCK_NONBLOCK and SOCK_CLOEXEC from socket_type because | ||
| 2451 | // windows does not define this flags yet | ||
| 2452 | const rc = windows.ws2_32.socket(@intCast(c_int, domain), @intCast(c_int, socket_type), @intCast(c_int, protocol)); | ||
| 2453 | if (rc != windows.ws2_32.INVALID_SOCKET) return rc; | ||
| 2454 | switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2455 | .WSAEMFILE => return error.ProcessFdQuotaExceeded, | ||
| 2456 | .WSAENOBUFS => return error.SystemResources, | ||
| 2457 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | ||
| 2458 | .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, | ||
| 2459 | else => |err| return windows.unexpectedWSAError(err), | ||
| 2460 | } | ||
| 2461 | } | ||
| 2462 | |||
| 2447 | const have_sock_flags = comptime !std.Target.current.isDarwin(); | 2463 | const have_sock_flags = comptime !std.Target.current.isDarwin(); |
| 2448 | const filtered_sock_type = if (!have_sock_flags) | 2464 | const filtered_sock_type = if (!have_sock_flags) |
| 2449 | socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) | 2465 | socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) |
| ... | @@ -2818,7 +2834,29 @@ pub const ConnectError = error{ | ... | @@ -2818,7 +2834,29 @@ pub const ConnectError = error{ |
| 2818 | } || UnexpectedError; | 2834 | } || UnexpectedError; |
| 2819 | 2835 | ||
| 2820 | /// Initiate a connection on a socket. | 2836 | /// Initiate a connection on a socket. |
| 2821 | pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { | 2837 | pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { |
| 2838 | if (builtin.os.tag == .windows) { | ||
| 2839 | const rc = windows.ws2_32.connect(sockfd, sock_addr, len); | ||
| 2840 | if (rc == 0) return; | ||
| 2841 | switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2842 | .WSAEADDRINUSE => return error.AddressInUse, | ||
| 2843 | .WSAEADDRNOTAVAIL => return error.AddressNotAvailable, | ||
| 2844 | .WSAECONNREFUSED => return error.ConnectionRefused, | ||
| 2845 | .WSAETIMEDOUT => return error.ConnectionTimedOut, | ||
| 2846 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? | ||
| 2847 | ,.WSAENETUNREACH => return error.NetworkUnreachable, | ||
| 2848 | .WSAEFAULT => unreachable, | ||
| 2849 | .WSAEINVAL => unreachable, | ||
| 2850 | .WSAEISCONN => unreachable, | ||
| 2851 | .WSAENOTSOCK => unreachable, | ||
| 2852 | .WSAEWOULDBLOCK => unreachable, | ||
| 2853 | .WSAEACCES => unreachable, | ||
| 2854 | .WSAENOBUFS => return error.SystemResources, | ||
| 2855 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | ||
| 2856 | else => |err| return windows.unexpectedWSAError(err), | ||
| 2857 | } | ||
| 2858 | } | ||
| 2859 | |||
| 2822 | while (true) { | 2860 | while (true) { |
| 2823 | switch (errno(system.connect(sockfd, sock_addr, len))) { | 2861 | switch (errno(system.connect(sockfd, sock_addr, len))) { |
| 2824 | 0 => return, | 2862 | 0 => return, |
lib/std/os/bits/windows.zig+2| ... | @@ -177,6 +177,8 @@ pub const sockaddr_un = ws2_32.sockaddr_un; | ... | @@ -177,6 +177,8 @@ pub const sockaddr_un = ws2_32.sockaddr_un; |
| 177 | pub const in6_addr = [16]u8; | 177 | pub const in6_addr = [16]u8; |
| 178 | pub const in_addr = u32; | 178 | pub const in_addr = u32; |
| 179 | 179 | ||
| 180 | pub const addrinfo = ws2_32.addrinfo; | ||
| 181 | |||
| 180 | pub const AF_UNSPEC = ws2_32.AF_UNSPEC; | 182 | pub const AF_UNSPEC = ws2_32.AF_UNSPEC; |
| 181 | pub const AF_UNIX = ws2_32.AF_UNIX; | 183 | pub const AF_UNIX = ws2_32.AF_UNIX; |
| 182 | pub const AF_INET = ws2_32.AF_INET; | 184 | pub const AF_INET = ws2_32.AF_INET; |
lib/std/os/windows/ws2_32.zig+36| ... | @@ -163,11 +163,33 @@ pub const IPPROTO_UDP = 17; | ... | @@ -163,11 +163,33 @@ pub const IPPROTO_UDP = 17; |
| 163 | pub const IPPROTO_ICMPV6 = 58; | 163 | pub const IPPROTO_ICMPV6 = 58; |
| 164 | pub const IPPROTO_RM = 113; | 164 | pub const IPPROTO_RM = 113; |
| 165 | 165 | ||
| 166 | pub const AI_PASSIVE = 0x00001; | ||
| 167 | pub const AI_CANONNAME = 0x00002; | ||
| 168 | pub const AI_NUMERICHOST = 0x00004; | ||
| 169 | pub const AI_NUMERICSERV = 0x00008; | ||
| 170 | pub const AI_ADDRCONFIG = 0x00400; | ||
| 171 | pub const AI_V4MAPPED = 0x00800; | ||
| 172 | pub const AI_NON_AUTHORITATIVE = 0x04000; | ||
| 173 | pub const AI_SECURE = 0x08000; | ||
| 174 | pub const AI_RETURN_PREFERRED_NAMES = 0x10000; | ||
| 175 | pub const AI_DISABLE_IDN_ENCODING = 0x80000; | ||
| 176 | |||
| 166 | pub const sockaddr = extern struct { | 177 | pub const sockaddr = extern struct { |
| 167 | family: ADDRESS_FAMILY, | 178 | family: ADDRESS_FAMILY, |
| 168 | data: [14]u8, | 179 | data: [14]u8, |
| 169 | }; | 180 | }; |
| 170 | 181 | ||
| 182 | pub const addrinfo = extern struct { | ||
| 183 | flags: i32, | ||
| 184 | family: i32, | ||
| 185 | socktype: i32, | ||
| 186 | protocol: i32, | ||
| 187 | addrlen: usize, | ||
| 188 | canonname: ?[*:0]u8, | ||
| 189 | addr: ?*sockaddr, | ||
| 190 | next: ?*addrinfo, | ||
| 191 | }; | ||
| 192 | |||
| 171 | /// IPv4 socket address | 193 | /// IPv4 socket address |
| 172 | pub const sockaddr_in = extern struct { | 194 | pub const sockaddr_in = extern struct { |
| 173 | family: ADDRESS_FAMILY = AF_INET, | 195 | family: ADDRESS_FAMILY = AF_INET, |
| ... | @@ -702,6 +724,11 @@ pub extern "ws2_32" fn WSAIoctl( | ... | @@ -702,6 +724,11 @@ pub extern "ws2_32" fn WSAIoctl( |
| 702 | lpOverlapped: ?*WSAOVERLAPPED, | 724 | lpOverlapped: ?*WSAOVERLAPPED, |
| 703 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, | 725 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, |
| 704 | ) callconv(.Stdcall) c_int; | 726 | ) callconv(.Stdcall) c_int; |
| 727 | pub extern "ws2_32" fn socket( | ||
| 728 | af: c_int, | ||
| 729 | type: c_int, | ||
| 730 | protocol: c_int, | ||
| 731 | ) callconv(.Stdcall) SOCKET; | ||
| 705 | pub extern "ws2_32" fn accept( | 732 | pub extern "ws2_32" fn accept( |
| 706 | s: SOCKET, | 733 | s: SOCKET, |
| 707 | addr: ?*sockaddr, | 734 | addr: ?*sockaddr, |
| ... | @@ -752,3 +779,12 @@ pub extern "ws2_32" fn WSASendTo( | ... | @@ -752,3 +779,12 @@ pub extern "ws2_32" fn WSASendTo( |
| 752 | lpOverlapped: ?*WSAOVERLAPPED, | 779 | lpOverlapped: ?*WSAOVERLAPPED, |
| 753 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, | 780 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, |
| 754 | ) callconv(.Stdcall) c_int; | 781 | ) callconv(.Stdcall) c_int; |
| 782 | pub extern "ws2_32" fn getaddrinfo( | ||
| 783 | pNodeName: [*:0]const u8, | ||
| 784 | pServiceName: [*:0]const u8, | ||
| 785 | pHints: *const addrinfo, | ||
| 786 | ppResult: **addrinfo, | ||
| 787 | ) callconv(.Stdcall) i32; | ||
| 788 | pub extern "ws2_32" fn freeaddrinfo( | ||
| 789 | pAddrInfo: *addrinfo, | ||
| 790 | ) callconv(.Stdcall) void; |