authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2020-05-29 22:38:48-06:00
committergravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2020-05-29 22:38:48-06:00
log2eaab1e65e23ebc0a736ce96073a43bf59c916ea
tree3a97f20c608dbae93781dd9d6556181660744b3d
parent65c3833ec2793747961f532510feb4fbb52fd6a6

more windows network support, including dns


5 files changed, 132 insertions(+), 23 deletions(-)

lib/std/c.zig+14
......@@ -194,6 +194,20 @@ pub usingnamespace switch (builtin.os.tag) {
194194 pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
195195 pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *Stat) c_int;
196196 },
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 },
197211 else => struct {
198212 pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
199213 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)
406406
407407pub fn tcpConnectToAddress(address: Address) !fs.File {
408408 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);
410411 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
411412 errdefer os.close(sockfd);
412413 try os.connect(sockfd, &address.any, address.getOsSockLen());
......@@ -431,16 +432,16 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
431432 const arena = &result.arena.allocator;
432433 errdefer result.arena.deinit();
433434
434 if (builtin.link_libc) {
435 const c = std.c;
435 if (builtin.os.tag == .windows or builtin.link_libc) {
436436 const name_c = try std.cstr.addNullByte(allocator, name);
437437 defer allocator.free(name_c);
438438
439439 const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port});
440440 defer allocator.free(port_c);
441441
442 const sys = if (builtin.os.tag == .windows) os.windows.ws2_32 else os.system;
442443 const hints = os.addrinfo{
443 .flags = c.AI_NUMERICSERV,
444 .flags = sys.AI_NUMERICSERV,
444445 .family = os.AF_UNSPEC,
445446 .socktype = os.SOCK_STREAM,
446447 .protocol = os.IPPROTO_TCP,
......@@ -450,24 +451,42 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
450451 .next = null,
451452 };
452453 var res: *os.addrinfo = undefined;
453 switch (os.system.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res)) {
454 @intToEnum(os.system.EAI, 0) => {},
455 .ADDRFAMILY => return error.HostLacksNetworkAddresses,
456 .AGAIN => return error.TemporaryNameServerFailure,
457 .BADFLAGS => unreachable, // Invalid hints
458 .FAIL => return error.NameServerFailure,
459 .FAMILY => return error.AddressFamilyNotSupported,
460 .MEMORY => return error.OutOfMemory,
461 .NODATA => return error.HostLacksNetworkAddresses,
462 .NONAME => return error.UnknownHostName,
463 .SERVICE => return error.ServiceUnavailable,
464 .SOCKTYPE => unreachable, // Invalid socket type requested in hints
465 .SYSTEM => switch (os.errno(-1)) {
466 else => |e| return os.unexpectedErrno(e),
467 },
468 else => unreachable,
454 const rc = sys.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res);
455 if (builtin.os.tag == .windows) {
456 const ws2_32 = os.windows.ws2_32;
457 switch (rc) {
458 0 => {},
459 @enumToInt(ws2_32.WinsockError.WSATRY_AGAIN) => return error.TemporaryNameServerFailure,
460 @enumToInt(ws2_32.WinsockError.WSANO_RECOVERY) => return error.NameServerFailure,
461 @enumToInt(ws2_32.WinsockError.WSAEAFNOSUPPORT) => return error.AddressFamilyNotSupported,
462 @enumToInt(ws2_32.WinsockError.WSA_NOT_ENOUGH_MEMORY) => return error.OutOfMemory,
463 @enumToInt(ws2_32.WinsockError.WSAHOST_NOT_FOUND) => return error.UnknownHostName,
464 @enumToInt(ws2_32.WinsockError.WSATYPE_NOT_FOUND) => return error.ServiceUnavailable,
465 @enumToInt(ws2_32.WinsockError.WSAEINVAL) => unreachable,
466 @enumToInt(ws2_32.WinsockError.WSAESOCKTNOSUPPORT) => unreachable,
467 else => |err| return os.windows.unexpectedWSAError(
468 std.meta.intToEnum(ws2_32.WinsockError, err) catch 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 }
469488 }
470 defer os.system.freeaddrinfo(res);
489 defer sys.freeaddrinfo(res);
471490
472491 const addr_count = blk: {
473492 var count: usize = 0;
lib/std/os.zig+40-2
......@@ -69,6 +69,8 @@ else switch (builtin.os.tag) {
6969
7070pub usingnamespace @import("os/bits.zig");
7171
72pub const socket_t = if (builtin.os.tag == .windows) windows.ws2_32.SOCKET else fd_t;
73
7274/// See also `getenv`. Populated by startup code before main().
7375/// TODO this is a footgun because the value will be undefined when using `zig build-lib`.
7476/// https://github.com/ziglang/zig/issues/4524
......@@ -2443,7 +2445,21 @@ pub const SocketError = error{
24432445 SocketTypeNotSupported,
24442446} || UnexpectedError;
24452447
2446pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!fd_t {
2448pub 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
24472463 const have_sock_flags = comptime !std.Target.current.isDarwin();
24482464 const filtered_sock_type = if (!have_sock_flags)
24492465 socket_type & ~@as(u32, SOCK_NONBLOCK | SOCK_CLOEXEC)
......@@ -2818,7 +2834,29 @@ pub const ConnectError = error{
28182834} || UnexpectedError;
28192835
28202836/// Initiate a connection on a socket.
2821pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) ConnectError!void {
2837pub 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
28222860 while (true) {
28232861 switch (errno(system.connect(sockfd, sock_addr, len))) {
28242862 0 => return,
lib/std/os/bits/windows.zig+2
......@@ -177,6 +177,8 @@ pub const sockaddr_un = ws2_32.sockaddr_un;
177177pub const in6_addr = [16]u8;
178178pub const in_addr = u32;
179179
180pub const addrinfo = ws2_32.addrinfo;
181
180182pub const AF_UNSPEC = ws2_32.AF_UNSPEC;
181183pub const AF_UNIX = ws2_32.AF_UNIX;
182184pub const AF_INET = ws2_32.AF_INET;
lib/std/os/windows/ws2_32.zig+36
......@@ -163,11 +163,33 @@ pub const IPPROTO_UDP = 17;
163163pub const IPPROTO_ICMPV6 = 58;
164164pub const IPPROTO_RM = 113;
165165
166pub const AI_PASSIVE = 0x00001;
167pub const AI_CANONNAME = 0x00002;
168pub const AI_NUMERICHOST = 0x00004;
169pub const AI_NUMERICSERV = 0x00008;
170pub const AI_ADDRCONFIG = 0x00400;
171pub const AI_V4MAPPED = 0x00800;
172pub const AI_NON_AUTHORITATIVE = 0x04000;
173pub const AI_SECURE = 0x08000;
174pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
175pub const AI_DISABLE_IDN_ENCODING = 0x80000;
176
166177pub const sockaddr = extern struct {
167178 family: ADDRESS_FAMILY,
168179 data: [14]u8,
169180};
170181
182pub 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
171193/// IPv4 socket address
172194pub const sockaddr_in = extern struct {
173195 family: ADDRESS_FAMILY = AF_INET,
......@@ -702,6 +724,11 @@ pub extern "ws2_32" fn WSAIoctl(
702724 lpOverlapped: ?*WSAOVERLAPPED,
703725 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
704726) callconv(.Stdcall) c_int;
727pub extern "ws2_32" fn socket(
728 af: c_int,
729 type: c_int,
730 protocol: c_int,
731) callconv(.Stdcall) SOCKET;
705732pub extern "ws2_32" fn accept(
706733 s: SOCKET,
707734 addr: ?*sockaddr,
......@@ -752,3 +779,12 @@ pub extern "ws2_32" fn WSASendTo(
752779 lpOverlapped: ?*WSAOVERLAPPED,
753780 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
754781) callconv(.Stdcall) c_int;
782pub 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;
788pub extern "ws2_32" fn freeaddrinfo(
789 pAddrInfo: *addrinfo,
790) callconv(.Stdcall) void;