authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-29 15:10:29-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-10-29 15:10:29-04:00
log3a0e8c2b45e57e75cedd052b00fd7ae46def8383
treede7fc435f56bf6484aa40fa41a0f8a1b5890c1bf
parent844eb932f4a253863d36e01a713724141c1f6361
parent7f4667219339e92dc75e7dfd5f0078f229804567
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6838 from LemonBoy/netstuff

std: Add basic smoke test for net functionality

8 files changed, 222 insertions(+), 48 deletions(-)

lib/std/c.zig+2-2
...@@ -150,8 +150,8 @@ pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint...@@ -150,8 +150,8 @@ pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint
150pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;150pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
151pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;151pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
152pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;152pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
153pub extern "c" fn accept(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) c_int;153pub extern "c" fn accept(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t) c_int;
154pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;154pub extern "c" fn accept4(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t, flags: c_uint) c_int;
155pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int;155pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int;
156pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int;156pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int;
157pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;157pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize;
lib/std/net.zig+24-18
...@@ -11,11 +11,7 @@ const mem = std.mem;...@@ -11,11 +11,7 @@ const mem = std.mem;
11const os = std.os;11const os = std.os;
12const fs = std.fs;12const fs = std.fs;
1313
14test "" {14pub const has_unix_sockets = @hasDecl(os, "sockaddr_un");
15 _ = @import("net/test.zig");
16}
17
18const has_unix_sockets = @hasDecl(os, "sockaddr_un");
1915
20pub const Address = extern union {16pub const Address = extern union {
21 any: os.sockaddr,17 any: os.sockaddr,
...@@ -610,7 +606,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {...@@ -610,7 +606,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
610 os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block,606 os.SOCK_STREAM | os.SOCK_CLOEXEC | opt_non_block,
611 0,607 0,
612 );608 );
613 errdefer os.close(sockfd);609 errdefer os.closeSocket(sockfd);
614610
615 var addr = try std.net.Address.initUnix(path);611 var addr = try std.net.Address.initUnix(path);
616612
...@@ -629,7 +625,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {...@@ -629,7 +625,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File {
629fn if_nametoindex(name: []const u8) !u32 {625fn if_nametoindex(name: []const u8) !u32 {
630 var ifr: os.ifreq = undefined;626 var ifr: os.ifreq = undefined;
631 var sockfd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM | os.SOCK_CLOEXEC, 0);627 var sockfd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM | os.SOCK_CLOEXEC, 0);
632 defer os.close(sockfd);628 defer os.closeSocket(sockfd);
633629
634 std.mem.copy(u8, &ifr.ifrn.name, name);630 std.mem.copy(u8, &ifr.ifrn.name, name);
635 ifr.ifrn.name[name.len] = 0;631 ifr.ifrn.name[name.len] = 0;
...@@ -677,7 +673,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {...@@ -677,7 +673,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File {
677 const sock_flags = os.SOCK_STREAM | nonblock |673 const sock_flags = os.SOCK_STREAM | nonblock |
678 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);674 (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC);
679 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);675 const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO_TCP);
680 errdefer os.close(sockfd);676 errdefer os.closeSocket(sockfd);
681677
682 if (std.io.is_async) {678 if (std.io.is_async) {
683 const loop = std.event.Loop.instance orelse return error.WouldBlock;679 const loop = std.event.Loop.instance orelse return error.WouldBlock;
...@@ -912,7 +908,7 @@ fn linuxLookupName(...@@ -912,7 +908,7 @@ fn linuxLookupName(
912 var prefixlen: i32 = 0;908 var prefixlen: i32 = 0;
913 const sock_flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC;909 const sock_flags = os.SOCK_DGRAM | os.SOCK_CLOEXEC;
914 if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO_UDP)) |fd| syscalls: {910 if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO_UDP)) |fd| syscalls: {
915 defer os.close(fd);911 defer os.closeSocket(fd);
916 os.connect(fd, da, dalen) catch break :syscalls;912 os.connect(fd, da, dalen) catch break :syscalls;
917 key |= DAS_USABLE;913 key |= DAS_USABLE;
918 os.getsockname(fd, sa, &salen) catch break :syscalls;914 os.getsockname(fd, sa, &salen) catch break :syscalls;
...@@ -1392,7 +1388,7 @@ fn resMSendRc(...@@ -1392,7 +1388,7 @@ fn resMSendRc(
1392 },1388 },
1393 else => |e| return e,1389 else => |e| return e,
1394 };1390 };
1395 defer os.close(fd);1391 defer os.closeSocket(fd);
1396 try os.bind(fd, &sa.any, sl);1392 try os.bind(fd, &sa.any, sl);
13971393
1398 // Past this point, there are no errors. Each individual query will1394 // Past this point, there are no errors. Each individual query will
...@@ -1546,16 +1542,14 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)...@@ -1546,16 +1542,14 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8)
1546 if (data.len != 4) return error.InvalidDnsARecord;1542 if (data.len != 4) return error.InvalidDnsARecord;
1547 const new_addr = try ctx.addrs.addOne();1543 const new_addr = try ctx.addrs.addOne();
1548 new_addr.* = LookupAddr{1544 new_addr.* = LookupAddr{
1549 // TODO slice [0..4] to make this *[4]u8 without @ptrCast1545 .addr = Address.initIp4(data[0..4].*, ctx.port),
1550 .addr = Address.initIp4(@ptrCast(*const [4]u8, data.ptr).*, ctx.port),
1551 };1546 };
1552 },1547 },
1553 os.RR_AAAA => {1548 os.RR_AAAA => {
1554 if (data.len != 16) return error.InvalidDnsAAAARecord;1549 if (data.len != 16) return error.InvalidDnsAAAARecord;
1555 const new_addr = try ctx.addrs.addOne();1550 const new_addr = try ctx.addrs.addOne();
1556 new_addr.* = LookupAddr{1551 new_addr.* = LookupAddr{
1557 // TODO slice [0..16] to make this *[16]u8 without @ptrCast1552 .addr = Address.initIp6(data[0..16].*, ctx.port, 0, 0),
1558 .addr = Address.initIp6(@ptrCast(*const [16]u8, data.ptr).*, ctx.port, 0, 0),
1559 };1553 };
1560 },1554 },
1561 os.RR_CNAME => {1555 os.RR_CNAME => {
...@@ -1579,7 +1573,7 @@ pub const StreamServer = struct {...@@ -1579,7 +1573,7 @@ pub const StreamServer = struct {
1579 /// `undefined` until `listen` returns successfully.1573 /// `undefined` until `listen` returns successfully.
1580 listen_address: Address,1574 listen_address: Address,
15811575
1582 sockfd: ?os.fd_t,1576 sockfd: ?os.socket_t,
15831577
1584 pub const Options = struct {1578 pub const Options = struct {
1585 /// How many connections the kernel will accept on the application's behalf.1579 /// How many connections the kernel will accept on the application's behalf.
...@@ -1616,13 +1610,13 @@ pub const StreamServer = struct {...@@ -1616,13 +1610,13 @@ pub const StreamServer = struct {
1616 const sockfd = try os.socket(address.any.family, sock_flags, proto);1610 const sockfd = try os.socket(address.any.family, sock_flags, proto);
1617 self.sockfd = sockfd;1611 self.sockfd = sockfd;
1618 errdefer {1612 errdefer {
1619 os.close(sockfd);1613 os.closeSocket(sockfd);
1620 self.sockfd = null;1614 self.sockfd = null;
1621 }1615 }
16221616
1623 if (self.reuse_address) {1617 if (self.reuse_address) {
1624 try os.setsockopt(1618 try os.setsockopt(
1625 self.sockfd.?,1619 sockfd,
1626 os.SOL_SOCKET,1620 os.SOL_SOCKET,
1627 os.SO_REUSEADDR,1621 os.SO_REUSEADDR,
1628 &mem.toBytes(@as(c_int, 1)),1622 &mem.toBytes(@as(c_int, 1)),
...@@ -1640,7 +1634,7 @@ pub const StreamServer = struct {...@@ -1640,7 +1634,7 @@ pub const StreamServer = struct {
1640 /// not listening.1634 /// not listening.
1641 pub fn close(self: *StreamServer) void {1635 pub fn close(self: *StreamServer) void {
1642 if (self.sockfd) |fd| {1636 if (self.sockfd) |fd| {
1643 os.close(fd);1637 os.closeSocket(fd);
1644 self.sockfd = null;1638 self.sockfd = null;
1645 self.listen_address = undefined;1639 self.listen_address = undefined;
1646 }1640 }
...@@ -1670,6 +1664,14 @@ pub const StreamServer = struct {...@@ -1670,6 +1664,14 @@ pub const StreamServer = struct {
1670 /// Permission to create a socket of the specified type and/or1664 /// Permission to create a socket of the specified type and/or
1671 /// protocol is denied.1665 /// protocol is denied.
1672 PermissionDenied,1666 PermissionDenied,
1667
1668 FileDescriptorNotASocket,
1669
1670 ConnectionResetByPeer,
1671
1672 NetworkSubsystemFailed,
1673
1674 OperationNotSupported,
1673 } || os.UnexpectedError;1675 } || os.UnexpectedError;
16741676
1675 pub const Connection = struct {1677 pub const Connection = struct {
...@@ -1701,3 +1703,7 @@ pub const StreamServer = struct {...@@ -1701,3 +1703,7 @@ pub const StreamServer = struct {
1701 }1703 }
1702 }1704 }
1703};1705};
1706
1707test "" {
1708 _ = @import("net/test.zig");
1709}
lib/std/net/test.zig+67-8
...@@ -95,22 +95,81 @@ test "parse and render IPv4 addresses" {...@@ -95,22 +95,81 @@ test "parse and render IPv4 addresses" {
95}95}
9696
97test "resolve DNS" {97test "resolve DNS" {
98 if (builtin.os.tag == .wasi) return error.SkipZigTest;
99
98 if (std.builtin.os.tag == .windows) {100 if (std.builtin.os.tag == .windows) {
99 _ = try std.os.windows.WSAStartup(2, 2);101 _ = try std.os.windows.WSAStartup(2, 2);
100 }102 }
101 if (builtin.os.tag == .wasi) {103 defer {
102 // DNS resolution not implemented on Windows yet.104 if (std.builtin.os.tag == .windows) {
103 return error.SkipZigTest;105 std.os.windows.WSACleanup() catch unreachable;
106 }
104 }107 }
105108
106 const address_list = net.getAddressList(testing.allocator, "example.com", 80) catch |err| switch (err) {109 // Resolve localhost, this should not fail.
110 {
111 const localhost_v4 = try net.Address.parseIp("127.0.0.1", 80);
112 const localhost_v6 = try net.Address.parseIp("::2", 80);
113
114 const result = try net.getAddressList(testing.allocator, "localhost", 80);
115 defer result.deinit();
116 for (result.addrs) |addr| {
117 if (addr.eql(localhost_v4) or addr.eql(localhost_v6)) break;
118 } else @panic("unexpected address for localhost");
119 }
120
121 {
107 // The tests are required to work even when there is no Internet connection,122 // The tests are required to work even when there is no Internet connection,
108 // so some of these errors we must accept and skip the test.123 // so some of these errors we must accept and skip the test.
109 error.UnknownHostName => return error.SkipZigTest,124 const result = net.getAddressList(testing.allocator, "example.com", 80) catch |err| switch (err) {
110 error.TemporaryNameServerFailure => return error.SkipZigTest,125 error.UnknownHostName => return error.SkipZigTest,
111 else => return err,126 error.TemporaryNameServerFailure => return error.SkipZigTest,
127 else => return err,
128 };
129 result.deinit();
130 }
131}
132
133test "listen on a port, send bytes, receive bytes" {
134 if (builtin.single_threaded) return error.SkipZigTest;
135 if (builtin.os.tag == .wasi) return error.SkipZigTest;
136
137 if (std.builtin.os.tag == .windows) {
138 _ = try std.os.windows.WSAStartup(2, 2);
139 }
140 defer {
141 if (std.builtin.os.tag == .windows) {
142 std.os.windows.WSACleanup() catch unreachable;
143 }
144 }
145
146 // Try only the IPv4 variant as some CI builders have no IPv6 localhost
147 // configured.
148 const localhost = try net.Address.parseIp("127.0.0.1", 8080);
149
150 var server = net.StreamServer.init(.{});
151 defer server.deinit();
152
153 try server.listen(localhost);
154
155 const S = struct {
156 fn clientFn(server_address: net.Address) !void {
157 const socket = try net.tcpConnectToAddress(server_address);
158 defer socket.close();
159
160 _ = try socket.writer().writeAll("Hello world!");
161 }
112 };162 };
113 address_list.deinit();163
164 const t = try std.Thread.spawn(server.listen_address, S.clientFn);
165 defer t.wait();
166
167 var client = try server.accept();
168 var buf: [16]u8 = undefined;
169 const n = try client.file.reader().read(&buf);
170
171 testing.expectEqual(@as(usize, 12), n);
172 testing.expectEqualSlices(u8, "Hello world!", buf[0..n]);
114}173}
115174
116test "listen on a port, send bytes, receive bytes" {175test "listen on a port, send bytes, receive bytes" {
lib/std/os.zig+48-16
...@@ -2687,6 +2687,14 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t...@@ -2687,6 +2687,14 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t
2687 }2687 }
2688}2688}
26892689
2690pub fn closeSocket(sock: socket_t) void {
2691 if (builtin.os.tag == .windows) {
2692 windows.closesocket(sock) catch unreachable;
2693 } else {
2694 close(sock);
2695 }
2696}
2697
2690pub const BindError = error{2698pub const BindError = error{
2691 /// The address is protected, and the user is not the superuser.2699 /// The address is protected, and the user is not the superuser.
2692 /// For UNIX domain sockets: Search permission is denied on a component2700 /// For UNIX domain sockets: Search permission is denied on a component
...@@ -2731,8 +2739,8 @@ pub const BindError = error{...@@ -2731,8 +2739,8 @@ pub const BindError = error{
27312739
2732/// addr is `*const T` where T is one of the sockaddr2740/// addr is `*const T` where T is one of the sockaddr
2733pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void {2741pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void {
2734 const rc = system.bind(sock, addr, len);
2735 if (builtin.os.tag == .windows) {2742 if (builtin.os.tag == .windows) {
2743 const rc = windows.bind(sock, addr, len);
2736 if (rc == windows.ws2_32.SOCKET_ERROR) {2744 if (rc == windows.ws2_32.SOCKET_ERROR) {
2737 switch (windows.ws2_32.WSAGetLastError()) {2745 switch (windows.ws2_32.WSAGetLastError()) {
2738 .WSANOTINITIALISED => unreachable, // not initialized WSA2746 .WSANOTINITIALISED => unreachable, // not initialized WSA
...@@ -2750,6 +2758,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi...@@ -2750,6 +2758,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi
2750 }2758 }
2751 return;2759 return;
2752 } else {2760 } else {
2761 const rc = system.bind(sock, addr, len);
2753 switch (errno(rc)) {2762 switch (errno(rc)) {
2754 0 => return,2763 0 => return,
2755 EACCES => return error.AccessDenied,2764 EACCES => return error.AccessDenied,
...@@ -2800,8 +2809,8 @@ const ListenError = error{...@@ -2800,8 +2809,8 @@ const ListenError = error{
2800} || UnexpectedError;2809} || UnexpectedError;
28012810
2802pub fn listen(sock: socket_t, backlog: u31) ListenError!void {2811pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
2803 const rc = system.listen(sock, backlog);
2804 if (builtin.os.tag == .windows) {2812 if (builtin.os.tag == .windows) {
2813 const rc = windows.listen(sock, backlog);
2805 if (rc == windows.ws2_32.SOCKET_ERROR) {2814 if (rc == windows.ws2_32.SOCKET_ERROR) {
2806 switch (windows.ws2_32.WSAGetLastError()) {2815 switch (windows.ws2_32.WSAGetLastError()) {
2807 .WSANOTINITIALISED => unreachable, // not initialized WSA2816 .WSANOTINITIALISED => unreachable, // not initialized WSA
...@@ -2818,6 +2827,7 @@ pub fn listen(sock: socket_t, backlog: u31) ListenError!void {...@@ -2818,6 +2827,7 @@ pub fn listen(sock: socket_t, backlog: u31) ListenError!void {
2818 }2827 }
2819 return;2828 return;
2820 } else {2829 } else {
2830 const rc = system.listen(sock, backlog);
2821 switch (errno(rc)) {2831 switch (errno(rc)) {
2822 0 => return,2832 0 => return,
2823 EADDRINUSE => return error.AddressInUse,2833 EADDRINUSE => return error.AddressInUse,
...@@ -2905,6 +2915,8 @@ pub fn accept(...@@ -2905,6 +2915,8 @@ pub fn accept(
2905 const accepted_sock = while (true) {2915 const accepted_sock = while (true) {
2906 const rc = if (have_accept4)2916 const rc = if (have_accept4)
2907 system.accept4(sock, addr, addr_size, flags)2917 system.accept4(sock, addr, addr_size, flags)
2918 else if (builtin.os.tag == .windows)
2919 windows.accept(sock, addr, addr_size)
2908 else2920 else
2909 system.accept(sock, addr, addr_size);2921 system.accept(sock, addr, addr_size);
29102922
...@@ -3077,8 +3089,8 @@ pub const GetSockNameError = error{...@@ -3077,8 +3089,8 @@ pub const GetSockNameError = error{
3077} || UnexpectedError;3089} || UnexpectedError;
30783090
3079pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {3091pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
3080 const rc = system.getsockname(sock, addr, addrlen);
3081 if (builtin.os.tag == .windows) {3092 if (builtin.os.tag == .windows) {
3093 const rc = windows.getsockname(sock, addr, addrlen);
3082 if (rc == windows.ws2_32.SOCKET_ERROR) {3094 if (rc == windows.ws2_32.SOCKET_ERROR) {
3083 switch (windows.ws2_32.WSAGetLastError()) {3095 switch (windows.ws2_32.WSAGetLastError()) {
3084 .WSANOTINITIALISED => unreachable,3096 .WSANOTINITIALISED => unreachable,
...@@ -3091,6 +3103,7 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock...@@ -3091,6 +3103,7 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
3091 }3103 }
3092 return;3104 return;
3093 } else {3105 } else {
3106 const rc = system.getsockname(sock, addr, addrlen);
3094 switch (errno(rc)) {3107 switch (errno(rc)) {
3095 0 => return,3108 0 => return,
3096 else => |err| return unexpectedErrno(err),3109 else => |err| return unexpectedErrno(err),
...@@ -5378,22 +5391,41 @@ pub const SetSockOptError = error{...@@ -5378,22 +5391,41 @@ pub const SetSockOptError = error{
53785391
5379 /// Insufficient resources are available in the system to complete the call.5392 /// Insufficient resources are available in the system to complete the call.
5380 SystemResources,5393 SystemResources,
5394
5395 NetworkSubsystemFailed,
5396 FileDescriptorNotASocket,
5397 SocketNotBound,
5381} || UnexpectedError;5398} || UnexpectedError;
53825399
5383/// Set a socket's options.5400/// Set a socket's options.
5384pub fn setsockopt(fd: fd_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {5401pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
5385 switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {5402 if (builtin.os.tag == .windows) {
5386 0 => {},5403 const rc = windows.ws2_32.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len));
5387 EBADF => unreachable, // always a race condition5404 if (rc == windows.ws2_32.SOCKET_ERROR) {
5388 ENOTSOCK => unreachable, // always a race condition5405 switch (windows.ws2_32.WSAGetLastError()) {
5389 EINVAL => unreachable,5406 .WSANOTINITIALISED => unreachable,
5390 EFAULT => unreachable,5407 .WSAENETDOWN => return error.NetworkSubsystemFailed,
5391 EDOM => return error.TimeoutTooBig,5408 .WSAEFAULT => unreachable,
5392 EISCONN => return error.AlreadyConnected,5409 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
5393 ENOPROTOOPT => return error.InvalidProtocolOption,5410 .WSAEINVAL => return error.SocketNotBound,
5394 ENOMEM => return error.SystemResources,5411 else => |err| return windows.unexpectedWSAError(err),
5395 ENOBUFS => return error.SystemResources,5412 }
5396 else => |err| return unexpectedErrno(err),5413 }
5414 return;
5415 } else {
5416 switch (errno(system.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len)))) {
5417 0 => {},
5418 EBADF => unreachable, // always a race condition
5419 ENOTSOCK => unreachable, // always a race condition
5420 EINVAL => unreachable,
5421 EFAULT => unreachable,
5422 EDOM => return error.TimeoutTooBig,
5423 EISCONN => return error.AlreadyConnected,
5424 ENOPROTOOPT => return error.InvalidProtocolOption,
5425 ENOMEM => return error.SystemResources,
5426 ENOBUFS => return error.SystemResources,
5427 else => |err| return unexpectedErrno(err),
5428 }
5397 }5429 }
5398}5430}
53995431
lib/std/os/bits/windows.zig+35
...@@ -256,6 +256,41 @@ pub const POLLERR = ws2_32.POLLERR;...@@ -256,6 +256,41 @@ pub const POLLERR = ws2_32.POLLERR;
256pub const POLLHUP = ws2_32.POLLHUP;256pub const POLLHUP = ws2_32.POLLHUP;
257pub const POLLNVAL = ws2_32.POLLNVAL;257pub const POLLNVAL = ws2_32.POLLNVAL;
258258
259pub const SOL_SOCKET = ws2_32.SOL_SOCKET;
260
261pub const SO_DEBUG = ws2_32.SO_DEBUG;
262pub const SO_ACCEPTCONN = ws2_32.SO_ACCEPTCONN;
263pub const SO_REUSEADDR = ws2_32.SO_REUSEADDR;
264pub const SO_KEEPALIVE = ws2_32.SO_KEEPALIVE;
265pub const SO_DONTROUTE = ws2_32.SO_DONTROUTE;
266pub const SO_BROADCAST = ws2_32.SO_BROADCAST;
267pub const SO_USELOOPBACK = ws2_32.SO_USELOOPBACK;
268pub const SO_LINGER = ws2_32.SO_LINGER;
269pub const SO_OOBINLINE = ws2_32.SO_OOBINLINE;
270
271pub const SO_DONTLINGER = ws2_32.SO_DONTLINGER;
272pub const SO_EXCLUSIVEADDRUSE = ws2_32.SO_EXCLUSIVEADDRUSE;
273
274pub const SO_SNDBUF = ws2_32.SO_SNDBUF;
275pub const SO_RCVBUF = ws2_32.SO_RCVBUF;
276pub const SO_SNDLOWAT = ws2_32.SO_SNDLOWAT;
277pub const SO_RCVLOWAT = ws2_32.SO_RCVLOWAT;
278pub const SO_SNDTIMEO = ws2_32.SO_SNDTIMEO;
279pub const SO_RCVTIMEO = ws2_32.SO_RCVTIMEO;
280pub const SO_ERROR = ws2_32.SO_ERROR;
281pub const SO_TYPE = ws2_32.SO_TYPE;
282
283pub const SO_GROUP_ID = ws2_32.SO_GROUP_ID;
284pub const SO_GROUP_PRIORITY = ws2_32.SO_GROUP_PRIORITY;
285pub const SO_MAX_MSG_SIZE = ws2_32.SO_MAX_MSG_SIZE;
286pub const SO_PROTOCOL_INFOA = ws2_32.SO_PROTOCOL_INFOA;
287pub const SO_PROTOCOL_INFOW = ws2_32.SO_PROTOCOL_INFOW;
288
289pub const PVD_CONFIG = ws2_32.PVD_CONFIG;
290pub const SO_CONDITIONAL_ACCEPT = ws2_32.SO_CONDITIONAL_ACCEPT;
291
292pub const TCP_NODELAY = ws2_32.TCP_NODELAY;
293
259pub const O_RDONLY = 0o0;294pub const O_RDONLY = 0o0;
260pub const O_WRONLY = 0o1;295pub const O_WRONLY = 0o1;
261pub const O_RDWR = 0o2;296pub const O_RDWR = 0o2;
lib/std/os/linux.zig+3-3
...@@ -1003,14 +1003,14 @@ pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usiz...@@ -1003,14 +1003,14 @@ pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usiz
1003 return syscall4(.socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));1003 return syscall4(.socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
1004}1004}
10051005
1006pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {1006pub fn accept(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t) usize {
1007 if (builtin.arch == .i386) {1007 if (builtin.arch == .i386) {
1008 return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 });1008 return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 });
1009 }1009 }
1010 return accept4(fd, addr, len, 0);1010 return accept4(fd, addr, len, 0);
1011}1011}
10121012
1013pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {1013pub fn accept4(fd: i32, noalias addr: ?*sockaddr, noalias len: ?*socklen_t, flags: u32) usize {
1014 if (builtin.arch == .i386) {1014 if (builtin.arch == .i386) {
1015 return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags });1015 return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags });
1016 }1016 }
...@@ -1279,7 +1279,7 @@ pub fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: ?*const rlimit,...@@ -1279,7 +1279,7 @@ pub fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: ?*const rlimit,
1279 @bitCast(usize, @as(isize, pid)),1279 @bitCast(usize, @as(isize, pid)),
1280 @bitCast(usize, @as(isize, @enumToInt(resource))),1280 @bitCast(usize, @as(isize, @enumToInt(resource))),
1281 @ptrToInt(new_limit),1281 @ptrToInt(new_limit),
1282 @ptrToInt(old_limit)1282 @ptrToInt(old_limit),
1283 );1283 );
1284}1284}
12851285
lib/std/os/test.zig+1-1
...@@ -594,7 +594,7 @@ test "fsync" {...@@ -594,7 +594,7 @@ test "fsync" {
594594
595test "getrlimit and setrlimit" {595test "getrlimit and setrlimit" {
596 // TODO enable for other systems when implemented596 // TODO enable for other systems when implemented
597 if(builtin.os.tag != .linux){597 if (builtin.os.tag != .linux) {
598 return error.SkipZigTest;598 return error.SkipZigTest;
599 }599 }
600600
lib/std/os/windows/ws2_32.zig+42
...@@ -718,6 +718,41 @@ const IOC_WS2 = 0x08000000;...@@ -718,6 +718,41 @@ const IOC_WS2 = 0x08000000;
718718
719pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;719pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;
720720
721pub const SOL_SOCKET = 0xffff;
722
723pub const SO_DEBUG = 0x0001;
724pub const SO_ACCEPTCONN = 0x0002;
725pub const SO_REUSEADDR = 0x0004;
726pub const SO_KEEPALIVE = 0x0008;
727pub const SO_DONTROUTE = 0x0010;
728pub const SO_BROADCAST = 0x0020;
729pub const SO_USELOOPBACK = 0x0040;
730pub const SO_LINGER = 0x0080;
731pub const SO_OOBINLINE = 0x0100;
732
733pub const SO_DONTLINGER = ~@as(u32, SO_LINGER);
734pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR);
735
736pub const SO_SNDBUF = 0x1001;
737pub const SO_RCVBUF = 0x1002;
738pub const SO_SNDLOWAT = 0x1003;
739pub const SO_RCVLOWAT = 0x1004;
740pub const SO_SNDTIMEO = 0x1005;
741pub const SO_RCVTIMEO = 0x1006;
742pub const SO_ERROR = 0x1007;
743pub const SO_TYPE = 0x1008;
744
745pub const SO_GROUP_ID = 0x2001;
746pub const SO_GROUP_PRIORITY = 0x2002;
747pub const SO_MAX_MSG_SIZE = 0x2003;
748pub const SO_PROTOCOL_INFOA = 0x2004;
749pub const SO_PROTOCOL_INFOW = 0x2005;
750
751pub const PVD_CONFIG = 0x3001;
752pub const SO_CONDITIONAL_ACCEPT = 0x3002;
753
754pub const TCP_NODELAY = 0x0001;
755
721pub extern "ws2_32" fn WSAStartup(756pub extern "ws2_32" fn WSAStartup(
722 wVersionRequired: WORD,757 wVersionRequired: WORD,
723 lpWSAData: *WSADATA,758 lpWSAData: *WSADATA,
...@@ -835,3 +870,10 @@ pub extern "ws2_32" fn getsockname(...@@ -835,3 +870,10 @@ pub extern "ws2_32" fn getsockname(
835 name: *sockaddr,870 name: *sockaddr,
836 namelen: *c_int,871 namelen: *c_int,
837) callconv(.Stdcall) c_int;872) callconv(.Stdcall) c_int;
873pub extern "ws2_32" fn setsockopt(
874 s: SOCKET,
875 level: u32,
876 optname: u32,
877 optval: ?*const c_void,
878 optlen: socklen_t,
879) callconv(.Stdcall) c_int;