| author | |
| committer | |
| log | 3a0e8c2b45e57e75cedd052b00fd7ae46def8383 |
| tree | de7fc435f56bf6484aa40fa41a0f8a1b5890c1bf |
| parent | 844eb932f4a253863d36e01a713724141c1f6361 |
| parent | 7f4667219339e92dc75e7dfd5f0078f229804567 |
| signature |
std: Add basic smoke test for net functionality8 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 |
| 150 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; | 150 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; |
| 151 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; | 151 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; |
| 152 | pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; | 152 | pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; |
| 153 | pub extern "c" fn accept(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t) c_int; | 153 | pub extern "c" fn accept(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t) c_int; |
| 154 | pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; | 154 | pub extern "c" fn accept4(sockfd: fd_t, addr: ?*sockaddr, addrlen: ?*socklen_t, flags: c_uint) c_int; |
| 155 | pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int; | 155 | pub extern "c" fn getsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*c_void, optlen: *socklen_t) c_int; |
| 156 | pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int; | 156 | pub extern "c" fn setsockopt(sockfd: fd_t, level: u32, optname: u32, optval: ?*const c_void, optlen: socklen_t) c_int; |
| 157 | pub extern "c" fn send(sockfd: fd_t, buf: *const c_void, len: usize, flags: u32) isize; | 157 | pub 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; |
| 11 | const os = std.os; | 11 | const os = std.os; |
| 12 | const fs = std.fs; | 12 | const fs = std.fs; |
| 13 | 13 | ||
| 14 | test "" { | 14 | pub const has_unix_sockets = @hasDecl(os, "sockaddr_un"); |
| 15 | _ = @import("net/test.zig"); | ||
| 16 | } | ||
| 17 | |||
| 18 | const has_unix_sockets = @hasDecl(os, "sockaddr_un"); | ||
| 19 | 15 | ||
| 20 | pub const Address = extern union { | 16 | pub 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); |
| 614 | 610 | ||
| 615 | var addr = try std.net.Address.initUnix(path); | 611 | var addr = try std.net.Address.initUnix(path); |
| 616 | 612 | ||
| ... | @@ -629,7 +625,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { | ... | @@ -629,7 +625,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 629 | fn if_nametoindex(name: []const u8) !u32 { | 625 | fn 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); |
| 633 | 629 | ||
| 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); |
| 681 | 677 | ||
| 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); |
| 1397 | 1393 | ||
| 1398 | // Past this point, there are no errors. Each individual query will | 1394 | // 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 @ptrCast | 1545 | .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 @ptrCast | 1552 | .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, |
| 1581 | 1575 | ||
| 1582 | sockfd: ?os.fd_t, | 1576 | sockfd: ?os.socket_t, |
| 1583 | 1577 | ||
| 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 | } |
| 1622 | 1616 | ||
| 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/or | 1664 | /// 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; |
| 1674 | 1676 | ||
| 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 | |||
| 1707 | test "" { | ||
| 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 | } |
| 96 | 96 | ||
| 97 | test "resolve DNS" { | 97 | test "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 | } |
| 105 | 108 | ||
| 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 | |||
| 133 | test "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 | } |
| 115 | 174 | ||
| 116 | test "listen on a port, send bytes, receive bytes" { | 175 | test "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 | } |
| 2689 | 2689 | ||
| 2690 | pub 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 | |||
| 2690 | pub const BindError = error{ | 2698 | pub 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 component | 2700 | /// 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{ |
| 2731 | 2739 | ||
| 2732 | /// addr is `*const T` where T is one of the sockaddr | 2740 | /// addr is `*const T` where T is one of the sockaddr |
| 2733 | pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!void { | 2741 | pub 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 WSA | 2746 | .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; |
| 2801 | 2810 | ||
| 2802 | pub fn listen(sock: socket_t, backlog: u31) ListenError!void { | 2811 | pub 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 WSA | 2816 | .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 | else | 2920 | else |
| 2909 | system.accept(sock, addr, addr_size); | 2921 | system.accept(sock, addr, addr_size); |
| 2910 | 2922 | ||
| ... | @@ -3077,8 +3089,8 @@ pub const GetSockNameError = error{ | ... | @@ -3077,8 +3089,8 @@ pub const GetSockNameError = error{ |
| 3077 | } || UnexpectedError; | 3089 | } || UnexpectedError; |
| 3078 | 3090 | ||
| 3079 | pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void { | 3091 | pub 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{ |
| 5378 | 5391 | ||
| 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; |
| 5382 | 5399 | ||
| 5383 | /// Set a socket's options. | 5400 | /// Set a socket's options. |
| 5384 | pub fn setsockopt(fd: fd_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void { | 5401 | pub 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 condition | 5404 | if (rc == windows.ws2_32.SOCKET_ERROR) { |
| 5388 | ENOTSOCK => unreachable, // always a race condition | 5405 | 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 | } |
| 5399 | 5431 |
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; |
| 256 | pub const POLLHUP = ws2_32.POLLHUP; | 256 | pub const POLLHUP = ws2_32.POLLHUP; |
| 257 | pub const POLLNVAL = ws2_32.POLLNVAL; | 257 | pub const POLLNVAL = ws2_32.POLLNVAL; |
| 258 | 258 | ||
| 259 | pub const SOL_SOCKET = ws2_32.SOL_SOCKET; | ||
| 260 | |||
| 261 | pub const SO_DEBUG = ws2_32.SO_DEBUG; | ||
| 262 | pub const SO_ACCEPTCONN = ws2_32.SO_ACCEPTCONN; | ||
| 263 | pub const SO_REUSEADDR = ws2_32.SO_REUSEADDR; | ||
| 264 | pub const SO_KEEPALIVE = ws2_32.SO_KEEPALIVE; | ||
| 265 | pub const SO_DONTROUTE = ws2_32.SO_DONTROUTE; | ||
| 266 | pub const SO_BROADCAST = ws2_32.SO_BROADCAST; | ||
| 267 | pub const SO_USELOOPBACK = ws2_32.SO_USELOOPBACK; | ||
| 268 | pub const SO_LINGER = ws2_32.SO_LINGER; | ||
| 269 | pub const SO_OOBINLINE = ws2_32.SO_OOBINLINE; | ||
| 270 | |||
| 271 | pub const SO_DONTLINGER = ws2_32.SO_DONTLINGER; | ||
| 272 | pub const SO_EXCLUSIVEADDRUSE = ws2_32.SO_EXCLUSIVEADDRUSE; | ||
| 273 | |||
| 274 | pub const SO_SNDBUF = ws2_32.SO_SNDBUF; | ||
| 275 | pub const SO_RCVBUF = ws2_32.SO_RCVBUF; | ||
| 276 | pub const SO_SNDLOWAT = ws2_32.SO_SNDLOWAT; | ||
| 277 | pub const SO_RCVLOWAT = ws2_32.SO_RCVLOWAT; | ||
| 278 | pub const SO_SNDTIMEO = ws2_32.SO_SNDTIMEO; | ||
| 279 | pub const SO_RCVTIMEO = ws2_32.SO_RCVTIMEO; | ||
| 280 | pub const SO_ERROR = ws2_32.SO_ERROR; | ||
| 281 | pub const SO_TYPE = ws2_32.SO_TYPE; | ||
| 282 | |||
| 283 | pub const SO_GROUP_ID = ws2_32.SO_GROUP_ID; | ||
| 284 | pub const SO_GROUP_PRIORITY = ws2_32.SO_GROUP_PRIORITY; | ||
| 285 | pub const SO_MAX_MSG_SIZE = ws2_32.SO_MAX_MSG_SIZE; | ||
| 286 | pub const SO_PROTOCOL_INFOA = ws2_32.SO_PROTOCOL_INFOA; | ||
| 287 | pub const SO_PROTOCOL_INFOW = ws2_32.SO_PROTOCOL_INFOW; | ||
| 288 | |||
| 289 | pub const PVD_CONFIG = ws2_32.PVD_CONFIG; | ||
| 290 | pub const SO_CONDITIONAL_ACCEPT = ws2_32.SO_CONDITIONAL_ACCEPT; | ||
| 291 | |||
| 292 | pub const TCP_NODELAY = ws2_32.TCP_NODELAY; | ||
| 293 | |||
| 259 | pub const O_RDONLY = 0o0; | 294 | pub const O_RDONLY = 0o0; |
| 260 | pub const O_WRONLY = 0o1; | 295 | pub const O_WRONLY = 0o1; |
| 261 | pub const O_RDWR = 0o2; | 296 | pub 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 | } |
| 1005 | 1005 | ||
| 1006 | pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 1006 | pub 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 | } |
| 1012 | 1012 | ||
| 1013 | pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { | 1013 | pub 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 | } |
| 1285 | 1285 |
lib/std/os/test.zig+1-1| ... | @@ -594,7 +594,7 @@ test "fsync" { | ... | @@ -594,7 +594,7 @@ test "fsync" { |
| 594 | 594 | ||
| 595 | test "getrlimit and setrlimit" { | 595 | test "getrlimit and setrlimit" { |
| 596 | // TODO enable for other systems when implemented | 596 | // 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 | } |
| 600 | 600 |
lib/std/os/windows/ws2_32.zig+42| ... | @@ -718,6 +718,41 @@ const IOC_WS2 = 0x08000000; | ... | @@ -718,6 +718,41 @@ const IOC_WS2 = 0x08000000; |
| 718 | 718 | ||
| 719 | pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34; | 719 | pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34; |
| 720 | 720 | ||
| 721 | pub const SOL_SOCKET = 0xffff; | ||
| 722 | |||
| 723 | pub const SO_DEBUG = 0x0001; | ||
| 724 | pub const SO_ACCEPTCONN = 0x0002; | ||
| 725 | pub const SO_REUSEADDR = 0x0004; | ||
| 726 | pub const SO_KEEPALIVE = 0x0008; | ||
| 727 | pub const SO_DONTROUTE = 0x0010; | ||
| 728 | pub const SO_BROADCAST = 0x0020; | ||
| 729 | pub const SO_USELOOPBACK = 0x0040; | ||
| 730 | pub const SO_LINGER = 0x0080; | ||
| 731 | pub const SO_OOBINLINE = 0x0100; | ||
| 732 | |||
| 733 | pub const SO_DONTLINGER = ~@as(u32, SO_LINGER); | ||
| 734 | pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR); | ||
| 735 | |||
| 736 | pub const SO_SNDBUF = 0x1001; | ||
| 737 | pub const SO_RCVBUF = 0x1002; | ||
| 738 | pub const SO_SNDLOWAT = 0x1003; | ||
| 739 | pub const SO_RCVLOWAT = 0x1004; | ||
| 740 | pub const SO_SNDTIMEO = 0x1005; | ||
| 741 | pub const SO_RCVTIMEO = 0x1006; | ||
| 742 | pub const SO_ERROR = 0x1007; | ||
| 743 | pub const SO_TYPE = 0x1008; | ||
| 744 | |||
| 745 | pub const SO_GROUP_ID = 0x2001; | ||
| 746 | pub const SO_GROUP_PRIORITY = 0x2002; | ||
| 747 | pub const SO_MAX_MSG_SIZE = 0x2003; | ||
| 748 | pub const SO_PROTOCOL_INFOA = 0x2004; | ||
| 749 | pub const SO_PROTOCOL_INFOW = 0x2005; | ||
| 750 | |||
| 751 | pub const PVD_CONFIG = 0x3001; | ||
| 752 | pub const SO_CONDITIONAL_ACCEPT = 0x3002; | ||
| 753 | |||
| 754 | pub const TCP_NODELAY = 0x0001; | ||
| 755 | |||
| 721 | pub extern "ws2_32" fn WSAStartup( | 756 | pub 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; |
| 873 | pub 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; |