| author | |
| committer | |
| log | c6764fd254170a32f34a7c08341b90b926552389 |
| tree | e1138d3a1deeded1bb23ace3e614103561087877 |
| parent | 8f4bc772604e708a150b279ffbaff0076c4b212d |
| parent | 0d32f4acf715bfe053890a86de1acba47cdb1ddb |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
support name resolution on windows6 files changed, 140 insertions(+), 10 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+20-7| ... | @@ -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,8 +451,20 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -450,8 +451,20 @@ 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) switch (@intToEnum(os.windows.ws2_32.WinsockError, @intCast(u16, rc))) { |
| 456 | @intToEnum(os.windows.ws2_32.WinsockError, 0) => {}, | ||
| 457 | .WSATRY_AGAIN => return error.TemporaryNameServerFailure, | ||
| 458 | .WSANO_RECOVERY => return error.NameServerFailure, | ||
| 459 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | ||
| 460 | .WSA_NOT_ENOUGH_MEMORY => return error.OutOfMemory, | ||
| 461 | .WSAHOST_NOT_FOUND => return error.UnknownHostName, | ||
| 462 | .WSATYPE_NOT_FOUND => return error.ServiceUnavailable, | ||
| 463 | .WSAEINVAL => unreachable, | ||
| 464 | .WSAESOCKTNOSUPPORT => unreachable, | ||
| 465 | else => |err| return os.windows.unexpectedWSAError(err), | ||
| 466 | } else switch (rc) { | ||
| 467 | @intToEnum(sys.EAI, 0) => {}, | ||
| 455 | .ADDRFAMILY => return error.HostLacksNetworkAddresses, | 468 | .ADDRFAMILY => return error.HostLacksNetworkAddresses, |
| 456 | .AGAIN => return error.TemporaryNameServerFailure, | 469 | .AGAIN => return error.TemporaryNameServerFailure, |
| 457 | .BADFLAGS => unreachable, // Invalid hints | 470 | .BADFLAGS => unreachable, // Invalid hints |
| ... | @@ -467,7 +480,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* | ... | @@ -467,7 +480,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !* |
| 467 | }, | 480 | }, |
| 468 | else => unreachable, | 481 | else => unreachable, |
| 469 | } | 482 | } |
| 470 | defer os.system.freeaddrinfo(res); | 483 | defer sys.freeaddrinfo(res); |
| 471 | 484 | ||
| 472 | const addr_count = blk: { | 485 | const addr_count = blk: { |
| 473 | var count: usize = 0; | 486 | var count: usize = 0; |
lib/std/net/test.zig+4-1| ... | @@ -68,7 +68,10 @@ test "parse and render IPv4 addresses" { | ... | @@ -68,7 +68,10 @@ test "parse and render IPv4 addresses" { |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | test "resolve DNS" { | 70 | test "resolve DNS" { |
| 71 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi) { | 71 | if (std.builtin.os.tag == .windows) { |
| 72 | _ = try std.os.windows.WSAStartup(2, 2); | ||
| 73 | } | ||
| 74 | if (builtin.os.tag == .wasi) { | ||
| 72 | // DNS resolution not implemented on Windows yet. | 75 | // DNS resolution not implemented on Windows yet. |
| 73 | return error.SkipZigTest; | 76 | return error.SkipZigTest; |
| 74 | } | 77 | } |
lib/std/os.zig+53-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 |
| ... | @@ -2445,7 +2447,33 @@ pub const SocketError = error{ | ... | @@ -2445,7 +2447,33 @@ pub const SocketError = error{ |
| 2445 | SocketTypeNotSupported, | 2447 | SocketTypeNotSupported, |
| 2446 | } || UnexpectedError; | 2448 | } || UnexpectedError; |
| 2447 | 2449 | ||
| 2448 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t { | 2450 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t { |
| 2451 | if (builtin.os.tag == .windows) { | ||
| 2452 | // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations | ||
| 2453 | const filtered_sock_type = socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC); | ||
| 2454 | const flags : u32 = if ((socket_type & SOCK_CLOEXEC) != 0) windows.ws2_32.WSA_FLAG_NO_HANDLE_INHERIT else 0; | ||
| 2455 | const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), | ||
| 2456 | @intCast(c_int, protocol), null, 0, flags); | ||
| 2457 | if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2458 | .WSAEMFILE => return error.ProcessFdQuotaExceeded, | ||
| 2459 | .WSAENOBUFS => return error.SystemResources, | ||
| 2460 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | ||
| 2461 | .WSAEPROTONOSUPPORT => return error.ProtocolNotSupported, | ||
| 2462 | else => |err| return windows.unexpectedWSAError(err), | ||
| 2463 | }; | ||
| 2464 | errdefer windows.closesocket(rc) catch unreachable; | ||
| 2465 | if ((socket_type & SOCK_NONBLOCK) != 0) { | ||
| 2466 | var mode : c_ulong = 1; // nonblocking | ||
| 2467 | if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) { | ||
| 2468 | switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2469 | // have not identified any error codes that should be handled yet | ||
| 2470 | else => unreachable, | ||
| 2471 | } | ||
| 2472 | } | ||
| 2473 | } | ||
| 2474 | return rc; | ||
| 2475 | } | ||
| 2476 | |||
| 2449 | const have_sock_flags = comptime !std.Target.current.isDarwin(); | 2477 | const have_sock_flags = comptime !std.Target.current.isDarwin(); |
| 2450 | const filtered_sock_type = if (!have_sock_flags) | 2478 | const filtered_sock_type = if (!have_sock_flags) |
| 2451 | socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) | 2479 | socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC) |
| ... | @@ -2820,7 +2848,30 @@ pub const ConnectError = error{ | ... | @@ -2820,7 +2848,30 @@ pub const ConnectError = error{ |
| 2820 | } || UnexpectedError; | 2848 | } || UnexpectedError; |
| 2821 | 2849 | ||
| 2822 | /// Initiate a connection on a socket. | 2850 | /// Initiate a connection on a socket. |
| 2823 | pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { | 2851 | pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void { |
| 2852 | if (builtin.os.tag == .windows) { | ||
| 2853 | const rc = windows.ws2_32.connect(sockfd, sock_addr, len); | ||
| 2854 | if (rc == 0) return; | ||
| 2855 | switch (windows.ws2_32.WSAGetLastError()) { | ||
| 2856 | .WSAEADDRINUSE => return error.AddressInUse, | ||
| 2857 | .WSAEADDRNOTAVAIL => return error.AddressNotAvailable, | ||
| 2858 | .WSAECONNREFUSED => return error.ConnectionRefused, | ||
| 2859 | .WSAETIMEDOUT => return error.ConnectionTimedOut, | ||
| 2860 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? | ||
| 2861 | ,.WSAENETUNREACH => return error.NetworkUnreachable, | ||
| 2862 | .WSAEFAULT => unreachable, | ||
| 2863 | .WSAEINVAL => unreachable, | ||
| 2864 | .WSAEISCONN => unreachable, | ||
| 2865 | .WSAENOTSOCK => unreachable, | ||
| 2866 | .WSAEWOULDBLOCK => unreachable, | ||
| 2867 | .WSAEACCES => unreachable, | ||
| 2868 | .WSAENOBUFS => return error.SystemResources, | ||
| 2869 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | ||
| 2870 | else => |err| return windows.unexpectedWSAError(err), | ||
| 2871 | } | ||
| 2872 | return; | ||
| 2873 | } | ||
| 2874 | |||
| 2824 | while (true) { | 2875 | while (true) { |
| 2825 | switch (errno(system.connect(sockfd, sock_addr, len))) { | 2876 | switch (errno(system.connect(sockfd, sock_addr, len))) { |
| 2826 | 0 => return, | 2877 | 0 => return, |
lib/std/os/bits/windows.zig+11| ... | @@ -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; |
| ... | @@ -219,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW; | ... | @@ -219,6 +221,15 @@ pub const SOCK_RAW = ws2_32.SOCK_RAW; |
| 219 | pub const SOCK_RDM = ws2_32.SOCK_RDM; | 221 | pub const SOCK_RDM = ws2_32.SOCK_RDM; |
| 220 | pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET; | 222 | pub const SOCK_SEQPACKET = ws2_32.SOCK_SEQPACKET; |
| 221 | 223 | ||
| 224 | /// WARNING: this flag is not supported by windows socket functions directly, | ||
| 225 | /// it is only supported by std.os.socket. Be sure that this value does | ||
| 226 | /// not share any bits with any of the SOCK_* values. | ||
| 227 | pub const SOCK_CLOEXEC = 0x10000; | ||
| 228 | /// WARNING: this flag is not supported by windows socket functions directly, | ||
| 229 | /// it is only supported by std.os.socket. Be sure that this value does | ||
| 230 | /// not share any bits with any of the SOCK_* values. | ||
| 231 | pub const SOCK_NONBLOCK = 0x20000; | ||
| 232 | |||
| 222 | pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP; | 233 | pub const IPPROTO_ICMP = ws2_32.IPPROTO_ICMP; |
| 223 | pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP; | 234 | pub const IPPROTO_IGMP = ws2_32.IPPROTO_IGMP; |
| 224 | pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM; | 235 | pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM; |
lib/std/os/windows/ws2_32.zig+38| ... | @@ -163,11 +163,35 @@ pub const IPPROTO_UDP = 17; | ... | @@ -163,11 +163,35 @@ 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 | |||
| 177 | pub const FIONBIO = -2147195266; | ||
| 178 | |||
| 166 | pub const sockaddr = extern struct { | 179 | pub const sockaddr = extern struct { |
| 167 | family: ADDRESS_FAMILY, | 180 | family: ADDRESS_FAMILY, |
| 168 | data: [14]u8, | 181 | data: [14]u8, |
| 169 | }; | 182 | }; |
| 170 | 183 | ||
| 184 | pub const addrinfo = extern struct { | ||
| 185 | flags: i32, | ||
| 186 | family: i32, | ||
| 187 | socktype: i32, | ||
| 188 | protocol: i32, | ||
| 189 | addrlen: usize, | ||
| 190 | canonname: ?[*:0]u8, | ||
| 191 | addr: ?*sockaddr, | ||
| 192 | next: ?*addrinfo, | ||
| 193 | }; | ||
| 194 | |||
| 171 | /// IPv4 socket address | 195 | /// IPv4 socket address |
| 172 | pub const sockaddr_in = extern struct { | 196 | pub const sockaddr_in = extern struct { |
| 173 | family: ADDRESS_FAMILY = AF_INET, | 197 | family: ADDRESS_FAMILY = AF_INET, |
| ... | @@ -752,3 +776,17 @@ pub extern "ws2_32" fn WSASendTo( | ... | @@ -752,3 +776,17 @@ pub extern "ws2_32" fn WSASendTo( |
| 752 | lpOverlapped: ?*WSAOVERLAPPED, | 776 | lpOverlapped: ?*WSAOVERLAPPED, |
| 753 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, | 777 | lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE, |
| 754 | ) callconv(.Stdcall) c_int; | 778 | ) callconv(.Stdcall) c_int; |
| 779 | pub extern "ws2_32" fn getaddrinfo( | ||
| 780 | pNodeName: [*:0]const u8, | ||
| 781 | pServiceName: [*:0]const u8, | ||
| 782 | pHints: *const addrinfo, | ||
| 783 | ppResult: **addrinfo, | ||
| 784 | ) callconv(.Stdcall) i32; | ||
| 785 | pub extern "ws2_32" fn freeaddrinfo( | ||
| 786 | pAddrInfo: *addrinfo, | ||
| 787 | ) callconv(.Stdcall) void; | ||
| 788 | pub extern "ws2_32" fn ioctlsocket( | ||
| 789 | s: SOCKET, | ||
| 790 | cmd: c_long, | ||
| 791 | argp: *c_ulong, | ||
| 792 | ) callconv(.Stdcall) c_int; |