authorgravatar for kenta@lithdew.netKenta Iwasaki <kenta@lithdew.net> 2021-09-11 19:03:14+09:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-12 23:36:44-04:00
logc4f97d336528d5b795c6584053f072cf8e28495e
tree4a165e46fe4332404ddd2d965e8ea827dbe6eeb6
parent211856693193b6e5ba4d58bdec1afdb839071fb3

os: usingnamespace fixes for std.x.os.Socket and std.os.TCP

Extract existing constants to do with TCP socket options into a 'TCP' namespace. Export 'MSG' and 'TCP' from std.os.{linux, windows} into std.c. Fix compile errors to do with std.x.os.Socket methods related to setting TCP socket options. Handle errors in the case that an interface could not be resolved in an IPv6 address on Windows. Tested using Wine with the loopback interface disabled. Have all instantiations of std.x.os.Socket on Windows instantiate an overlapped socket descriptor. Fixes the '1ms read timeout' test in std.x.net.tcp.Client. The test would previously deadlock, as read timeouts only apply to overlapped sockets. Windows documentation by default recommends that most instantiations of sockets on Windows be overlapped sockets (s.t. they may operate in both blocking or nonblocking mode when operated with WSA* syscalls). Refer to the documentation for WSASocketA for more info.

8 files changed, 135 insertions(+), 112 deletions(-)

lib/std/c/linux.zig+2
......@@ -31,6 +31,7 @@ pub const MAP = struct {
3131 pub const FAILED = @intToPtr(*c_void, maxInt(usize));
3232};
3333pub const MMAP2_UNIT = linux.MMAP2_UNIT;
34pub const MSG = linux.MSG;
3435pub const NAME_MAX = linux.NAME_MAX;
3536pub const O = linux.O;
3637pub const PATH_MAX = linux.PATH_MAX;
......@@ -54,6 +55,7 @@ pub const STDIN_FILENO = linux.STDIN_FILENO;
5455pub const STDOUT_FILENO = linux.STDOUT_FILENO;
5556pub const SYS = linux.SYS;
5657pub const Sigaction = linux.Sigaction;
58pub const TCP = linux.TCP;
5759pub const VDSO = linux.VDSO;
5860pub const W = linux.W;
5961pub const W_OK = linux.W_OK;
lib/std/c/windows.zig+2-1
......@@ -204,7 +204,9 @@ pub const in_addr = u32;
204204
205205pub const addrinfo = ws2_32.addrinfo;
206206pub const AF = ws2_32.AF;
207pub const MSG = ws2_32.MSG;
207208pub const SOCK = ws2_32.SOCK;
209pub const TCP = ws2_32.TCP;
208210pub const IPPROTO = ws2_32.IPPROTO;
209211pub const BTHPROTO_RFCOMM = ws2_32.BTHPROTO_RFCOMM;
210212
......@@ -214,7 +216,6 @@ pub const POLL = ws2_32.POLL;
214216pub const SOL = ws2_32.SOL;
215217pub const SO = ws2_32.SO;
216218pub const PVD_CONFIG = ws2_32.PVD_CONFIG;
217pub const TCP_NODELAY = ws2_32.TCP_NODELAY;
218219
219220pub const O = struct {
220221 pub const RDONLY = 0o0;
lib/std/os.zig+1
......@@ -115,6 +115,7 @@ pub const SYS = system.SYS;
115115pub const Sigaction = system.Sigaction;
116116pub const Stat = system.Stat;
117117pub const TCSA = system.TCSA;
118pub const TCP = system.TCP;
118119pub const VDSO = system.VDSO;
119120pub const W = system.W;
120121pub const addrinfo = system.addrinfo;
lib/std/os/linux.zig+76-74
......@@ -2007,6 +2007,82 @@ pub const SOCK = struct {
20072007 pub const NONBLOCK = if (is_mips) 0o200 else 0o4000;
20082008};
20092009
2010pub const TCP = struct {
2011 /// Turn off Nagle's algorithm
2012 pub const NODELAY = 1;
2013 /// Limit MSS
2014 pub const MAXSEG = 2;
2015 /// Never send partially complete segments.
2016 pub const CORK = 3;
2017 /// Start keeplives after this period, in seconds
2018 pub const KEEPIDLE = 4;
2019 /// Interval between keepalives
2020 pub const KEEPINTVL = 5;
2021 /// Number of keepalives before death
2022 pub const KEEPCNT = 6;
2023 /// Number of SYN retransmits
2024 pub const SYNCNT = 7;
2025 /// Life time of orphaned FIN-WAIT-2 state
2026 pub const LINGER2 = 8;
2027 /// Wake up listener only when data arrive
2028 pub const DEFER_ACCEPT = 9;
2029 /// Bound advertised window
2030 pub const WINDOW_CLAMP = 10;
2031 /// Information about this connection.
2032 pub const INFO = 11;
2033 /// Block/reenable quick acks
2034 pub const QUICKACK = 12;
2035 /// Congestion control algorithm
2036 pub const CONGESTION = 13;
2037 /// TCP MD5 Signature (RFC2385)
2038 pub const MD5SIG = 14;
2039 /// Use linear timeouts for thin streams
2040 pub const THIN_LINEAR_TIMEOUTS = 16;
2041 /// Fast retrans. after 1 dupack
2042 pub const THIN_DUPACK = 17;
2043 /// How long for loss retry before timeout
2044 pub const USER_TIMEOUT = 18;
2045 /// TCP sock is under repair right now
2046 pub const REPAIR = 19;
2047 pub const REPAIR_QUEUE = 20;
2048 pub const QUEUE_SEQ = 21;
2049 pub const REPAIR_OPTIONS = 22;
2050 /// Enable FastOpen on listeners
2051 pub const FASTOPEN = 23;
2052 pub const TIMESTAMP = 24;
2053 /// limit number of unsent bytes in write queue
2054 pub const NOTSENT_LOWAT = 25;
2055 /// Get Congestion Control (optional) info
2056 pub const CC_INFO = 26;
2057 /// Record SYN headers for new connections
2058 pub const SAVE_SYN = 27;
2059 /// Get SYN headers recorded for connection
2060 pub const SAVED_SYN = 28;
2061 /// Get/set window parameters
2062 pub const REPAIR_WINDOW = 29;
2063 /// Attempt FastOpen with connect
2064 pub const FASTOPEN_CONNECT = 30;
2065 /// Attach a ULP to a TCP connection
2066 pub const ULP = 31;
2067 /// TCP MD5 Signature with extensions
2068 pub const MD5SIG_EXT = 32;
2069 /// Set the key for Fast Open (cookie)
2070 pub const FASTOPEN_KEY = 33;
2071 /// Enable TFO without a TFO cookie
2072 pub const FASTOPEN_NO_COOKIE = 34;
2073 pub const ZEROCOPY_RECEIVE = 35;
2074 /// Notify bytes available to read as a cmsg on read
2075 pub const INQ = 36;
2076 pub const CM_INQ = INQ;
2077 /// delay outgoing packets by XX usec
2078 pub const TX_DELAY = 37;
2079
2080 pub const REPAIR_ON = 1;
2081 pub const REPAIR_OFF = 0;
2082 /// Turn off without window probes
2083 pub const REPAIR_OFF_NO_WP = -1;
2084};
2085
20102086pub const PF = struct {
20112087 pub const UNSPEC = 0;
20122088 pub const LOCAL = 1;
......@@ -3606,80 +3682,6 @@ pub const RR = struct {
36063682 pub const AAAA = 28;
36073683};
36083684
3609/// Turn off Nagle's algorithm
3610pub const TCP_NODELAY = 1;
3611/// Limit MSS
3612pub const TCP_MAXSEG = 2;
3613/// Never send partially complete segments.
3614pub const TCP_CORK = 3;
3615/// Start keeplives after this period, in seconds
3616pub const TCP_KEEPIDLE = 4;
3617/// Interval between keepalives
3618pub const TCP_KEEPINTVL = 5;
3619/// Number of keepalives before death
3620pub const TCP_KEEPCNT = 6;
3621/// Number of SYN retransmits
3622pub const TCP_SYNCNT = 7;
3623/// Life time of orphaned FIN-WAIT-2 state
3624pub const TCP_LINGER2 = 8;
3625/// Wake up listener only when data arrive
3626pub const TCP_DEFER_ACCEPT = 9;
3627/// Bound advertised window
3628pub const TCP_WINDOW_CLAMP = 10;
3629/// Information about this connection.
3630pub const TCP_INFO = 11;
3631/// Block/reenable quick acks
3632pub const TCP_QUICKACK = 12;
3633/// Congestion control algorithm
3634pub const TCP_CONGESTION = 13;
3635/// TCP MD5 Signature (RFC2385)
3636pub const TCP_MD5SIG = 14;
3637/// Use linear timeouts for thin streams
3638pub const TCP_THIN_LINEAR_TIMEOUTS = 16;
3639/// Fast retrans. after 1 dupack
3640pub const TCP_THIN_DUPACK = 17;
3641/// How long for loss retry before timeout
3642pub const TCP_USER_TIMEOUT = 18;
3643/// TCP sock is under repair right now
3644pub const TCP_REPAIR = 19;
3645pub const TCP_REPAIR_QUEUE = 20;
3646pub const TCP_QUEUE_SEQ = 21;
3647pub const TCP_REPAIR_OPTIONS = 22;
3648/// Enable FastOpen on listeners
3649pub const TCP_FASTOPEN = 23;
3650pub const TCP_TIMESTAMP = 24;
3651/// limit number of unsent bytes in write queue
3652pub const TCP_NOTSENT_LOWAT = 25;
3653/// Get Congestion Control (optional) info
3654pub const TCP_CC_INFO = 26;
3655/// Record SYN headers for new connections
3656pub const TCP_SAVE_SYN = 27;
3657/// Get SYN headers recorded for connection
3658pub const TCP_SAVED_SYN = 28;
3659/// Get/set window parameters
3660pub const TCP_REPAIR_WINDOW = 29;
3661/// Attempt FastOpen with connect
3662pub const TCP_FASTOPEN_CONNECT = 30;
3663/// Attach a ULP to a TCP connection
3664pub const TCP_ULP = 31;
3665/// TCP MD5 Signature with extensions
3666pub const TCP_MD5SIG_EXT = 32;
3667/// Set the key for Fast Open (cookie)
3668pub const TCP_FASTOPEN_KEY = 33;
3669/// Enable TFO without a TFO cookie
3670pub const TCP_FASTOPEN_NO_COOKIE = 34;
3671pub const TCP_ZEROCOPY_RECEIVE = 35;
3672/// Notify bytes available to read as a cmsg on read
3673pub const TCP_INQ = 36;
3674pub const TCP_CM_INQ = TCP_INQ;
3675/// delay outgoing packets by XX usec
3676pub const TCP_TX_DELAY = 37;
3677
3678pub const TCP_REPAIR_ON = 1;
3679pub const TCP_REPAIR_OFF = 0;
3680/// Turn off without window probes
3681pub const TCP_REPAIR_OFF_NO_WP = -1;
3682
36833685pub const tcp_repair_opt = extern struct {
36843686 opt_code: u32,
36853687 opt_val: u32,
lib/std/os/windows/ws2_32.zig+27-23
......@@ -442,27 +442,33 @@ pub const PROTECTION_LEVEL_EDGERESTRICTED = 20;
442442pub const PROTECTION_LEVEL_RESTRICTED = 30;
443443pub const INET_ADDRSTRLEN = 22;
444444pub const INET6_ADDRSTRLEN = 65;
445pub const TCP_OFFLOAD_NO_PREFERENCE = 0;
446pub const TCP_OFFLOAD_NOT_PREFERRED = 1;
447pub const TCP_OFFLOAD_PREFERRED = 2;
448pub const TCP_EXPEDITED_1122 = 2;
449pub const TCP_KEEPALIVE = 3;
450pub const TCP_MAXSEG = 4;
451pub const TCP_MAXRT = 5;
452pub const TCP_STDURG = 6;
453pub const TCP_NOURG = 7;
454pub const TCP_ATMARK = 8;
455pub const TCP_NOSYNRETRIES = 9;
456pub const TCP_TIMESTAMPS = 10;
457pub const TCP_OFFLOAD_PREFERENCE = 11;
458pub const TCP_CONGESTION_ALGORITHM = 12;
459pub const TCP_DELAY_FIN_ACK = 13;
460pub const TCP_MAXRTMS = 14;
461pub const TCP_FASTOPEN = 15;
462pub const TCP_KEEPCNT = 16;
463pub const TCP_KEEPINTVL = 17;
464pub const TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18;
465pub const TCP_ICMP_ERROR_INFO = 19;
445
446pub const TCP = struct {
447 pub const NODELAY = 1;
448 pub const EXPEDITED_1122 = 2;
449 pub const OFFLOAD_NO_PREFERENCE = 0;
450 pub const OFFLOAD_NOT_PREFERRED = 1;
451 pub const OFFLOAD_PREFERRED = 2;
452 pub const KEEPALIVE = 3;
453 pub const MAXSEG = 4;
454 pub const MAXRT = 5;
455 pub const STDURG = 6;
456 pub const NOURG = 7;
457 pub const ATMARK = 8;
458 pub const NOSYNRETRIES = 9;
459 pub const TIMESTAMPS = 10;
460 pub const OFFLOAD_PREFERENCE = 11;
461 pub const CONGESTION_ALGORITHM = 12;
462 pub const DELAY_FIN_ACK = 13;
463 pub const MAXRTMS = 14;
464 pub const FASTOPEN = 15;
465 pub const KEEPCNT = 16;
466 pub const KEEPINTVL = 17;
467 pub const FAIL_CONNECT_ON_ICMP_ERROR = 18;
468 pub const ICMP_ERROR_INFO = 19;
469 pub const BSDURGENT = 28672;
470};
471
466472pub const UDP_SEND_MSG_SIZE = 2;
467473pub const UDP_RECV_MAX_COALESCED_SIZE = 3;
468474pub const UDP_COALESCED_INFO = 3;
......@@ -578,7 +584,6 @@ pub const SO = struct {
578584};
579585
580586pub const WSK_SO_BASE = 16384;
581pub const TCP_NODELAY = 1;
582587pub const IOC_UNIX = 0;
583588pub const IOC_WS2 = 134217728;
584589pub const IOC_PROTOCOL = 268435456;
......@@ -846,7 +851,6 @@ pub const POLL = struct {
846851 pub const NVAL = 4;
847852};
848853
849pub const TCP_BSDURGENT = 28672;
850854pub const TF_DISCONNECT = 1;
851855pub const TF_REUSE_SOCKET = 2;
852856pub const TF_WRITE_BEHIND = 4;
lib/std/x/net/tcp.zig+3-3
......@@ -195,7 +195,7 @@ pub const Client = struct {
195195 pub fn setNoDelay(self: Client, enabled: bool) !void {
196196 if (@hasDecl(os.TCP, "NODELAY")) {
197197 const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));
198 return self.socket.setOption(os.IPPROTO.TCP, os.TCP_NODELAY, bytes);
198 return self.socket.setOption(os.IPPROTO.TCP, os.TCP.NODELAY, bytes);
199199 }
200200 return error.UnsupportedSocketOption;
201201 }
......@@ -204,7 +204,7 @@ pub const Client = struct {
204204 /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
205205 pub fn setQuickACK(self: Client, enabled: bool) !void {
206206 if (@hasDecl(os.TCP, "QUICKACK")) {
207 return self.socket.setOption(os.IPPROTO.TCP, os.TCP_QUICKACK, mem.asBytes(&@as(u32, @boolToInt(enabled))));
207 return self.socket.setOption(os.IPPROTO.TCP, os.TCP.QUICKACK, mem.asBytes(&@as(u32, @boolToInt(enabled))));
208208 }
209209 return error.UnsupportedSocketOption;
210210 }
......@@ -305,7 +305,7 @@ pub const Listener = struct {
305305 /// support TCP Fast Open.
306306 pub fn setFastOpen(self: Listener, enabled: bool) !void {
307307 if (@hasDecl(os.TCP, "FASTOPEN")) {
308 return self.socket.setOption(os.IPPROTO.TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(u32, @boolToInt(enabled))));
308 return self.socket.setOption(os.IPPROTO.TCP, os.TCP.FASTOPEN, mem.asBytes(&@as(u32, @boolToInt(enabled))));
309309 }
310310 return error.UnsupportedSocketOption;
311311 }
lib/std/x/os/net.zig+23-10
......@@ -11,16 +11,20 @@ const have_ifnamesize = @hasDecl(os.system, "IFNAMESIZE");
1111/// Resolves a network interface name into a scope/zone ID. It returns
1212/// an error if either resolution fails, or if the interface name is
1313/// too long.
14pub fn resolveScopeID(name: []const u8) !u32 {
14pub fn resolveScopeId(name: []const u8) !u32 {
1515 if (have_ifnamesize) {
16 if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;
16 if (name.len >= os.IFNAMESIZE) return error.NameTooLong;
1717
1818 if (native_os.tag == .windows) {
19 var interface_name: [os.IFNAMESIZE]u8 = undefined;
19 var interface_name: [os.IFNAMESIZE:0]u8 = undefined;
2020 mem.copy(u8, &interface_name, name);
2121 interface_name[name.len] = 0;
2222
23 return os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name));
23 const rc = os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name));
24 if (rc == 0) {
25 return error.InterfaceNotFound;
26 }
27 return rc;
2428 }
2529
2630 const fd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM, 0);
......@@ -35,7 +39,7 @@ pub fn resolveScopeID(name: []const u8) !u32 {
3539 return @bitCast(u32, f.ifru.ivalue);
3640 }
3741
38 return error.Unsupported;
42 return error.InterfaceNotFound;
3943}
4044
4145/// An IPv4 address comprised of 4 bytes.
......@@ -403,7 +407,8 @@ pub const IPv6 = extern struct {
403407 /// address.
404408 pub const ParseError = error{
405409 MalformedV4Mapping,
406 BadScopeID,
410 InterfaceNotFound,
411 UnknownScopeId,
407412 } || IPv4.ParseError;
408413
409414 /// Parses an arbitrary IPv6 address, including link-local addresses.
......@@ -412,12 +417,15 @@ pub const IPv6 = extern struct {
412417 const ip_slice = buf[0..index];
413418 const scope_id_slice = buf[index + 1 ..];
414419
415 if (scope_id_slice.len == 0) return error.BadScopeID;
420 if (scope_id_slice.len == 0) return error.UnknownScopeId;
416421
417422 const scope_id: u32 = switch (scope_id_slice[0]) {
418423 '0'...'9' => fmt.parseInt(u32, scope_id_slice, 10),
419 else => resolveScopeID(scope_id_slice),
420 } catch return error.BadScopeID;
424 else => resolveScopeId(scope_id_slice) catch |err| switch (err) {
425 error.InterfaceNotFound => return error.InterfaceNotFound,
426 else => err,
427 },
428 } catch return error.UnknownScopeId;
421429
422430 return parseWithScopeID(ip_slice, scope_id);
423431 }
......@@ -568,6 +576,11 @@ test "ipv6: parse & format addresses with scope ids" {
568576 };
569577
570578 for (inputs) |input, i| {
571 try testing.expectFmt(outputs[i], "{}", .{try IPv6.parse(input)});
579 const parsed = IPv6.parse(input) catch |err| switch (err) {
580 error.InterfaceNotFound => continue,
581 else => return err,
582 };
583
584 try testing.expectFmt(outputs[i], "{}", .{parsed});
572585 }
573586}
lib/std/x/os/socket_windows.zig+1-1
......@@ -11,7 +11,7 @@ pub fn Mixin(comptime Socket: type) type {
1111 return struct {
1212 /// Open a new socket.
1313 pub fn init(domain: u32, socket_type: u32, protocol: u32, flags: std.enums.EnumFieldStruct(Socket.InitFlags, bool, false)) !Socket {
14 var raw_flags: u32 = 0;
14 var raw_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;
1515 const set = std.EnumSet(Socket.InitFlags).init(flags);
1616 if (set.contains(.close_on_exec)) raw_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
1717