| author | |
| committer | |
| log | 14d235dd6e79dba8d34e05f1912a1bcf9a3ef68c |
| tree | 9122d4a2eab8b9deef81e089cecee0e7699a08fa |
| parent | bae0c9b554105092297330c8beec977fe3468da6 |
| parent | 7fd937fef4547a98d7c33ea67eca76e6336f9152 |
closes #48646 files changed, 276 insertions(+), 15 deletions(-)
lib/std/c.zig+1| ... | @@ -132,6 +132,7 @@ pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; | ... | @@ -132,6 +132,7 @@ pub extern "c" fn tcgetattr(fd: fd_t, termios_p: *termios) c_int; |
| 132 | pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; | 132 | pub extern "c" fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) c_int; |
| 133 | pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; | 133 | pub extern "c" fn fcntl(fd: fd_t, cmd: c_int, ...) c_int; |
| 134 | pub extern "c" fn flock(fd: fd_t, operation: c_int) c_int; | 134 | pub extern "c" fn flock(fd: fd_t, operation: c_int) c_int; |
| 135 | pub extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; | ||
| 135 | pub extern "c" fn uname(buf: *utsname) c_int; | 136 | pub extern "c" fn uname(buf: *utsname) c_int; |
| 136 | 137 | ||
| 137 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; | 138 | pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int; |
lib/std/net.zig+173-1| ... | @@ -21,6 +21,9 @@ pub const Address = extern union { | ... | @@ -21,6 +21,9 @@ pub const Address = extern union { |
| 21 | // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 | 21 | // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 |
| 22 | //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); | 22 | //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); |
| 23 | 23 | ||
| 24 | /// Parse the given IP address string into an Address value. | ||
| 25 | /// It is recommended to use `resolveIp` instead, to handle | ||
| 26 | /// IPv6 link-local unix addresses. | ||
| 24 | pub fn parseIp(name: []const u8, port: u16) !Address { | 27 | pub fn parseIp(name: []const u8, port: u16) !Address { |
| 25 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { | 28 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { |
| 26 | error.Overflow, | 29 | error.Overflow, |
| ... | @@ -42,6 +45,28 @@ pub const Address = extern union { | ... | @@ -42,6 +45,28 @@ pub const Address = extern union { |
| 42 | return error.InvalidIPAddressFormat; | 45 | return error.InvalidIPAddressFormat; |
| 43 | } | 46 | } |
| 44 | 47 | ||
| 48 | pub fn resolveIp(name: []const u8, port: u16) !Address { | ||
| 49 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { | ||
| 50 | error.Overflow, | ||
| 51 | error.InvalidEnd, | ||
| 52 | error.InvalidCharacter, | ||
| 53 | error.Incomplete, | ||
| 54 | => {}, | ||
| 55 | } | ||
| 56 | |||
| 57 | if (resolveIp6(name, port)) |ip6| return ip6 else |err| switch (err) { | ||
| 58 | error.Overflow, | ||
| 59 | error.InvalidEnd, | ||
| 60 | error.InvalidCharacter, | ||
| 61 | error.Incomplete, | ||
| 62 | error.InvalidIpv4Mapping, | ||
| 63 | => {}, | ||
| 64 | else => return err, | ||
| 65 | } | ||
| 66 | |||
| 67 | return error.InvalidIPAddressFormat; | ||
| 68 | } | ||
| 69 | |||
| 45 | pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !Address { | 70 | pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !Address { |
| 46 | switch (family) { | 71 | switch (family) { |
| 47 | os.AF_INET => return parseIp4(name, port), | 72 | os.AF_INET => return parseIp4(name, port), |
| ... | @@ -51,6 +76,9 @@ pub const Address = extern union { | ... | @@ -51,6 +76,9 @@ pub const Address = extern union { |
| 51 | } | 76 | } |
| 52 | } | 77 | } |
| 53 | 78 | ||
| 79 | /// Parse a given IPv6 address string into an Address. | ||
| 80 | /// Assumes the Scope ID of the address is fully numeric. | ||
| 81 | /// For non-numeric addresses, see `resolveIp6`. | ||
| 54 | pub fn parseIp6(buf: []const u8, port: u16) !Address { | 82 | pub fn parseIp6(buf: []const u8, port: u16) !Address { |
| 55 | var result = Address{ | 83 | var result = Address{ |
| 56 | .in6 = os.sockaddr_in6{ | 84 | .in6 = os.sockaddr_in6{ |
| ... | @@ -157,6 +185,136 @@ pub const Address = extern union { | ... | @@ -157,6 +185,136 @@ pub const Address = extern union { |
| 157 | } | 185 | } |
| 158 | } | 186 | } |
| 159 | 187 | ||
| 188 | pub fn resolveIp6(buf: []const u8, port: u16) !Address { | ||
| 189 | // TODO: Unify the implementations of resolveIp6 and parseIp6. | ||
| 190 | var result = Address{ | ||
| 191 | .in6 = os.sockaddr_in6{ | ||
| 192 | .scope_id = 0, | ||
| 193 | .port = mem.nativeToBig(u16, port), | ||
| 194 | .flowinfo = 0, | ||
| 195 | .addr = undefined, | ||
| 196 | }, | ||
| 197 | }; | ||
| 198 | var ip_slice = result.in6.addr[0..]; | ||
| 199 | |||
| 200 | var tail: [16]u8 = undefined; | ||
| 201 | |||
| 202 | var x: u16 = 0; | ||
| 203 | var saw_any_digits = false; | ||
| 204 | var index: u8 = 0; | ||
| 205 | var abbrv = false; | ||
| 206 | |||
| 207 | var scope_id = false; | ||
| 208 | var scope_id_value: [os.IFNAMESIZE - 1]u8 = undefined; | ||
| 209 | var scope_id_index: usize = 0; | ||
| 210 | |||
| 211 | for (buf) |c, i| { | ||
| 212 | if (scope_id) { | ||
| 213 | // Handling of percent-encoding should be for an URI library. | ||
| 214 | if ((c >= '0' and c <= '9') or | ||
| 215 | (c >= 'A' and c <= 'Z') or | ||
| 216 | (c >= 'a' and c <= 'z') or | ||
| 217 | (c == '-') or (c == '.') or (c == '_') or (c == '~')) | ||
| 218 | { | ||
| 219 | if (scope_id_index >= scope_id_value.len) { | ||
| 220 | return error.Overflow; | ||
| 221 | } | ||
| 222 | |||
| 223 | scope_id_value[scope_id_index] = c; | ||
| 224 | scope_id_index += 1; | ||
| 225 | } else { | ||
| 226 | return error.InvalidCharacter; | ||
| 227 | } | ||
| 228 | } else if (c == ':') { | ||
| 229 | if (!saw_any_digits) { | ||
| 230 | if (abbrv) return error.InvalidCharacter; // ':::' | ||
| 231 | if (i != 0) abbrv = true; | ||
| 232 | mem.set(u8, ip_slice[index..], 0); | ||
| 233 | ip_slice = tail[0..]; | ||
| 234 | index = 0; | ||
| 235 | continue; | ||
| 236 | } | ||
| 237 | if (index == 14) { | ||
| 238 | return error.InvalidEnd; | ||
| 239 | } | ||
| 240 | ip_slice[index] = @truncate(u8, x >> 8); | ||
| 241 | index += 1; | ||
| 242 | ip_slice[index] = @truncate(u8, x); | ||
| 243 | index += 1; | ||
| 244 | |||
| 245 | x = 0; | ||
| 246 | saw_any_digits = false; | ||
| 247 | } else if (c == '%') { | ||
| 248 | if (!saw_any_digits) { | ||
| 249 | return error.InvalidCharacter; | ||
| 250 | } | ||
| 251 | scope_id = true; | ||
| 252 | saw_any_digits = false; | ||
| 253 | } else if (c == '.') { | ||
| 254 | if (!abbrv or ip_slice[0] != 0xff or ip_slice[1] != 0xff) { | ||
| 255 | // must start with '::ffff:' | ||
| 256 | return error.InvalidIpv4Mapping; | ||
| 257 | } | ||
| 258 | const start_index = mem.lastIndexOfScalar(u8, buf[0..i], ':').? + 1; | ||
| 259 | const addr = (parseIp4(buf[start_index..], 0) catch { | ||
| 260 | return error.InvalidIpv4Mapping; | ||
| 261 | }).in.addr; | ||
| 262 | ip_slice = result.in6.addr[0..]; | ||
| 263 | ip_slice[10] = 0xff; | ||
| 264 | ip_slice[11] = 0xff; | ||
| 265 | |||
| 266 | const ptr = mem.sliceAsBytes(@as(*const [1]u32, &addr)[0..]); | ||
| 267 | |||
| 268 | ip_slice[12] = ptr[0]; | ||
| 269 | ip_slice[13] = ptr[1]; | ||
| 270 | ip_slice[14] = ptr[2]; | ||
| 271 | ip_slice[15] = ptr[3]; | ||
| 272 | return result; | ||
| 273 | } else { | ||
| 274 | const digit = try std.fmt.charToDigit(c, 16); | ||
| 275 | if (@mulWithOverflow(u16, x, 16, &x)) { | ||
| 276 | return error.Overflow; | ||
| 277 | } | ||
| 278 | if (@addWithOverflow(u16, x, digit, &x)) { | ||
| 279 | return error.Overflow; | ||
| 280 | } | ||
| 281 | saw_any_digits = true; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | if (!saw_any_digits and !abbrv) { | ||
| 286 | return error.Incomplete; | ||
| 287 | } | ||
| 288 | |||
| 289 | if (scope_id and scope_id_index == 0) { | ||
| 290 | return error.Incomplete; | ||
| 291 | } | ||
| 292 | |||
| 293 | var resolved_scope_id: u32 = 0; | ||
| 294 | if (scope_id_index > 0) { | ||
| 295 | const scope_id_str = scope_id_value[0..scope_id_index]; | ||
| 296 | resolved_scope_id = std.fmt.parseInt(u32, scope_id_str, 10) catch |err| blk: { | ||
| 297 | if (err != error.InvalidCharacter) return err; | ||
| 298 | break :blk try if_nametoindex(scope_id_str); | ||
| 299 | }; | ||
| 300 | } | ||
| 301 | |||
| 302 | result.in6.scope_id = resolved_scope_id; | ||
| 303 | |||
| 304 | if (index == 14) { | ||
| 305 | ip_slice[14] = @truncate(u8, x >> 8); | ||
| 306 | ip_slice[15] = @truncate(u8, x); | ||
| 307 | return result; | ||
| 308 | } else { | ||
| 309 | ip_slice[index] = @truncate(u8, x >> 8); | ||
| 310 | index += 1; | ||
| 311 | ip_slice[index] = @truncate(u8, x); | ||
| 312 | index += 1; | ||
| 313 | mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]); | ||
| 314 | return result; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 160 | pub fn parseIp4(buf: []const u8, port: u16) !Address { | 318 | pub fn parseIp4(buf: []const u8, port: u16) !Address { |
| 161 | var result = Address{ | 319 | var result = Address{ |
| 162 | .in = os.sockaddr_in{ | 320 | .in = os.sockaddr_in{ |
| ... | @@ -380,6 +538,20 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { | ... | @@ -380,6 +538,20 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 380 | }; | 538 | }; |
| 381 | } | 539 | } |
| 382 | 540 | ||
| 541 | fn if_nametoindex(name: []const u8) !u32 { | ||
| 542 | var ifr: os.ifreq = undefined; | ||
| 543 | var sockfd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM | os.SOCK_CLOEXEC, 0); | ||
| 544 | defer os.close(sockfd); | ||
| 545 | |||
| 546 | std.mem.copy(u8, &ifr.ifrn.name, name); | ||
| 547 | ifr.ifrn.name[name.len] = 0; | ||
| 548 | |||
| 549 | // TODO investigate if this needs to be integrated with evented I/O. | ||
| 550 | try os.ioctl_SIOCGIFINDEX(sockfd, &ifr); | ||
| 551 | |||
| 552 | return @bitCast(u32, ifr.ifru.ivalue); | ||
| 553 | } | ||
| 554 | |||
| 383 | pub const AddressList = struct { | 555 | pub const AddressList = struct { |
| 384 | arena: std.heap.ArenaAllocator, | 556 | arena: std.heap.ArenaAllocator, |
| 385 | addrs: []Address, | 557 | addrs: []Address, |
| ... | @@ -1071,7 +1243,7 @@ fn linuxLookupNameFromNumericUnspec( | ... | @@ -1071,7 +1243,7 @@ fn linuxLookupNameFromNumericUnspec( |
| 1071 | name: []const u8, | 1243 | name: []const u8, |
| 1072 | port: u16, | 1244 | port: u16, |
| 1073 | ) !void { | 1245 | ) !void { |
| 1074 | const addr = try Address.parseIp(name, port); | 1246 | const addr = try Address.resolveIp(name, port); |
| 1075 | (try addrs.addOne()).* = LookupAddr{ .addr = addr }; | 1247 | (try addrs.addOne()).* = LookupAddr{ .addr = addr }; |
| 1076 | } | 1248 | } |
| 1077 | 1249 |
lib/std/net/test.zig+22| ... | @@ -34,6 +34,12 @@ test "parse and render IPv6 addresses" { | ... | @@ -34,6 +34,12 @@ test "parse and render IPv6 addresses" { |
| 34 | var addr = net.Address.parseIp6(ip, 0) catch unreachable; | 34 | var addr = net.Address.parseIp6(ip, 0) catch unreachable; |
| 35 | var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; | 35 | var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; |
| 36 | std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3])); | 36 | std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3])); |
| 37 | |||
| 38 | if (std.builtin.os.tag == .linux) { | ||
| 39 | var addr_via_resolve = net.Address.resolveIp6(ip, 0) catch unreachable; | ||
| 40 | var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr_via_resolve}) catch unreachable; | ||
| 41 | std.testing.expect(std.mem.eql(u8, printed[i], newResolvedIp[1 .. newResolvedIp.len - 3])); | ||
| 42 | } | ||
| 37 | } | 43 | } |
| 38 | 44 | ||
| 39 | testing.expectError(error.InvalidCharacter, net.Address.parseIp6(":::", 0)); | 45 | testing.expectError(error.InvalidCharacter, net.Address.parseIp6(":::", 0)); |
| ... | @@ -42,6 +48,22 @@ test "parse and render IPv6 addresses" { | ... | @@ -42,6 +48,22 @@ test "parse and render IPv6 addresses" { |
| 42 | testing.expectError(error.InvalidEnd, net.Address.parseIp6("FF01:0:0:0:0:0:0:FB:", 0)); | 48 | testing.expectError(error.InvalidEnd, net.Address.parseIp6("FF01:0:0:0:0:0:0:FB:", 0)); |
| 43 | testing.expectError(error.Incomplete, net.Address.parseIp6("FF01:", 0)); | 49 | testing.expectError(error.Incomplete, net.Address.parseIp6("FF01:", 0)); |
| 44 | testing.expectError(error.InvalidIpv4Mapping, net.Address.parseIp6("::123.123.123.123", 0)); | 50 | testing.expectError(error.InvalidIpv4Mapping, net.Address.parseIp6("::123.123.123.123", 0)); |
| 51 | // TODO Make this test pass on other operating systems. | ||
| 52 | if (std.builtin.os.tag == .linux) { | ||
| 53 | testing.expectError(error.Incomplete, net.Address.resolveIp6("ff01::fb%", 0)); | ||
| 54 | testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%wlp3s0s0s0s0s0s0s0s0", 0)); | ||
| 55 | testing.expectError(error.Overflow, net.Address.resolveIp6("ff01::fb%12345678901234", 0)); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | test "invalid but parseable IPv6 scope ids" { | ||
| 60 | if (std.builtin.os.tag != .linux) { | ||
| 61 | // Currently, resolveIp6 with alphanumerical scope IDs only works on Linux. | ||
| 62 | // TODO Make this test pass on other operating systems. | ||
| 63 | return error.SkipZigTest; | ||
| 64 | } | ||
| 65 | |||
| 66 | testing.expectError(error.InterfaceNotFound, net.Address.resolveIp6("ff01::fb%123s45678901234", 0)); | ||
| 45 | } | 67 | } |
| 46 | 68 | ||
| 47 | test "parse and render IPv4 addresses" { | 69 | test "parse and render IPv4 addresses" { |
lib/std/os.zig+44-14| ... | @@ -405,7 +405,6 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | ... | @@ -405,7 +405,6 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 405 | else => |err| return unexpectedErrno(err), | 405 | else => |err| return unexpectedErrno(err), |
| 406 | } | 406 | } |
| 407 | } | 407 | } |
| 408 | |||
| 409 | const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31); | 408 | const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31); |
| 410 | while (true) { | 409 | while (true) { |
| 411 | // TODO handle the case when iov_len is too large and get rid of this @intCast | 410 | // TODO handle the case when iov_len is too large and get rid of this @intCast |
| ... | @@ -2391,8 +2390,15 @@ pub fn isatty(handle: fd_t) bool { | ... | @@ -2391,8 +2390,15 @@ pub fn isatty(handle: fd_t) bool { |
| 2391 | return true; | 2390 | return true; |
| 2392 | } | 2391 | } |
| 2393 | if (builtin.os.tag == .linux) { | 2392 | if (builtin.os.tag == .linux) { |
| 2394 | var wsz: linux.winsize = undefined; | 2393 | while (true) { |
| 2395 | return linux.syscall3(.ioctl, @bitCast(usize, @as(isize, handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0; | 2394 | var wsz: linux.winsize = undefined; |
| 2395 | const fd = @bitCast(usize, @as(isize, handle)); | ||
| 2396 | switch (linux.syscall3(.ioctl, fd, linux.TIOCGWINSZ, @ptrToInt(&wsz))) { | ||
| 2397 | 0 => return true, | ||
| 2398 | EINTR => continue, | ||
| 2399 | else => return false, | ||
| 2400 | } | ||
| 2401 | } | ||
| 2396 | } | 2402 | } |
| 2397 | unreachable; | 2403 | unreachable; |
| 2398 | } | 2404 | } |
| ... | @@ -2451,9 +2457,8 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t | ... | @@ -2451,9 +2457,8 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t |
| 2451 | if (builtin.os.tag == .windows) { | 2457 | if (builtin.os.tag == .windows) { |
| 2452 | // NOTE: windows translates the SOCK_NONBLOCK/SOCK_CLOEXEC flags into windows-analagous operations | 2458 | // 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); | 2459 | 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; | 2460 | 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), | 2461 | const rc = windows.ws2_32.WSASocketW(@intCast(c_int, domain), @intCast(c_int, filtered_sock_type), @intCast(c_int, protocol), null, 0, flags); |
| 2456 | @intCast(c_int, protocol), null, 0, flags); | ||
| 2457 | if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { | 2462 | if (rc == windows.ws2_32.INVALID_SOCKET) switch (windows.ws2_32.WSAGetLastError()) { |
| 2458 | .WSAEMFILE => return error.ProcessFdQuotaExceeded, | 2463 | .WSAEMFILE => return error.ProcessFdQuotaExceeded, |
| 2459 | .WSAENOBUFS => return error.SystemResources, | 2464 | .WSAENOBUFS => return error.SystemResources, |
| ... | @@ -2463,7 +2468,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t | ... | @@ -2463,7 +2468,7 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t |
| 2463 | }; | 2468 | }; |
| 2464 | errdefer windows.closesocket(rc) catch unreachable; | 2469 | errdefer windows.closesocket(rc) catch unreachable; |
| 2465 | if ((socket_type & SOCK_NONBLOCK) != 0) { | 2470 | if ((socket_type & SOCK_NONBLOCK) != 0) { |
| 2466 | var mode : c_ulong = 1; // nonblocking | 2471 | var mode: c_ulong = 1; // nonblocking |
| 2467 | if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) { | 2472 | if (windows.ws2_32.SOCKET_ERROR == windows.ws2_32.ioctlsocket(rc, windows.ws2_32.FIONBIO, &mode)) { |
| 2468 | switch (windows.ws2_32.WSAGetLastError()) { | 2473 | switch (windows.ws2_32.WSAGetLastError()) { |
| 2469 | // have not identified any error codes that should be handled yet | 2474 | // have not identified any error codes that should be handled yet |
| ... | @@ -2858,7 +2863,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con | ... | @@ -2858,7 +2863,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con |
| 2858 | .WSAECONNREFUSED => return error.ConnectionRefused, | 2863 | .WSAECONNREFUSED => return error.ConnectionRefused, |
| 2859 | .WSAETIMEDOUT => return error.ConnectionTimedOut, | 2864 | .WSAETIMEDOUT => return error.ConnectionTimedOut, |
| 2860 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? | 2865 | .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? |
| 2861 | ,.WSAENETUNREACH => return error.NetworkUnreachable, | 2866 | , .WSAENETUNREACH => return error.NetworkUnreachable, |
| 2862 | .WSAEFAULT => unreachable, | 2867 | .WSAEFAULT => unreachable, |
| 2863 | .WSAEINVAL => unreachable, | 2868 | .WSAEINVAL => unreachable, |
| 2864 | .WSAEISCONN => unreachable, | 2869 | .WSAEISCONN => unreachable, |
| ... | @@ -4882,12 +4887,15 @@ pub fn getrusage(who: i32) rusage { | ... | @@ -4882,12 +4887,15 @@ pub fn getrusage(who: i32) rusage { |
| 4882 | pub const TermiosGetError = error{NotATerminal} || UnexpectedError; | 4887 | pub const TermiosGetError = error{NotATerminal} || UnexpectedError; |
| 4883 | 4888 | ||
| 4884 | pub fn tcgetattr(handle: fd_t) TermiosGetError!termios { | 4889 | pub fn tcgetattr(handle: fd_t) TermiosGetError!termios { |
| 4885 | var term: termios = undefined; | 4890 | while (true) { |
| 4886 | switch (errno(system.tcgetattr(handle, &term))) { | 4891 | var term: termios = undefined; |
| 4887 | 0 => return term, | 4892 | switch (errno(system.tcgetattr(handle, &term))) { |
| 4888 | EBADF => unreachable, | 4893 | 0 => return term, |
| 4889 | ENOTTY => return error.NotATerminal, | 4894 | EINTR => continue, |
| 4890 | else => |err| return unexpectedErrno(err), | 4895 | EBADF => unreachable, |
| 4896 | ENOTTY => return error.NotATerminal, | ||
| 4897 | else => |err| return unexpectedErrno(err), | ||
| 4898 | } | ||
| 4891 | } | 4899 | } |
| 4892 | } | 4900 | } |
| 4893 | 4901 | ||
| ... | @@ -4906,3 +4914,25 @@ pub fn tcsetattr(handle: fd_t, optional_action: TCSA, termios_p: termios) Termio | ... | @@ -4906,3 +4914,25 @@ pub fn tcsetattr(handle: fd_t, optional_action: TCSA, termios_p: termios) Termio |
| 4906 | } | 4914 | } |
| 4907 | } | 4915 | } |
| 4908 | } | 4916 | } |
| 4917 | |||
| 4918 | const IoCtl_SIOCGIFINDEX_Error = error{ | ||
| 4919 | FileSystem, | ||
| 4920 | InterfaceNotFound, | ||
| 4921 | } || UnexpectedError; | ||
| 4922 | |||
| 4923 | pub fn ioctl_SIOCGIFINDEX(fd: fd_t, ifr: *ifreq) IoCtl_SIOCGIFINDEX_Error!void { | ||
| 4924 | while (true) { | ||
| 4925 | switch (errno(system.ioctl(fd, SIOCGIFINDEX, @ptrToInt(ifr)))) { | ||
| 4926 | 0 => return, | ||
| 4927 | EINVAL => unreachable, // Bad parameters. | ||
| 4928 | ENOTTY => unreachable, | ||
| 4929 | ENXIO => unreachable, | ||
| 4930 | EBADF => unreachable, // Always a race condition. | ||
| 4931 | EFAULT => unreachable, // Bad pointer parameter. | ||
| 4932 | EINTR => continue, | ||
| 4933 | EIO => return error.FileSystem, | ||
| 4934 | ENODEV => return error.InterfaceNotFound, | ||
| 4935 | else => |err| return unexpectedErrno(err), | ||
| 4936 | } | ||
| 4937 | } | ||
| 4938 | } |
lib/std/os/bits/linux.zig+32| ... | @@ -1705,3 +1705,35 @@ pub const termios = extern struct { | ... | @@ -1705,3 +1705,35 @@ pub const termios = extern struct { |
| 1705 | ispeed: speed_t, | 1705 | ispeed: speed_t, |
| 1706 | ospeed: speed_t, | 1706 | ospeed: speed_t, |
| 1707 | }; | 1707 | }; |
| 1708 | |||
| 1709 | pub const SIOCGIFINDEX = 0x8933; | ||
| 1710 | pub const IFNAMESIZE = 16; | ||
| 1711 | |||
| 1712 | pub const ifmap = extern struct { | ||
| 1713 | mem_start: u32, | ||
| 1714 | mem_end: u32, | ||
| 1715 | base_addr: u16, | ||
| 1716 | irq: u8, | ||
| 1717 | dma: u8, | ||
| 1718 | port: u8, | ||
| 1719 | }; | ||
| 1720 | |||
| 1721 | pub const ifreq = extern struct { | ||
| 1722 | ifrn: extern union { | ||
| 1723 | name: [IFNAMESIZE]u8, | ||
| 1724 | }, | ||
| 1725 | ifru: extern union { | ||
| 1726 | addr: sockaddr, | ||
| 1727 | dstaddr: sockaddr, | ||
| 1728 | broadaddr: sockaddr, | ||
| 1729 | netmask: sockaddr, | ||
| 1730 | hwaddr: sockaddr, | ||
| 1731 | flags: i16, | ||
| 1732 | ivalue: i32, | ||
| 1733 | mtu: i32, | ||
| 1734 | map: ifmap, | ||
| 1735 | slave: [IFNAMESIZE - 1:0]u8, | ||
| 1736 | newname: [IFNAMESIZE - 1:0]u8, | ||
| 1737 | data: ?[*]u8, | ||
| 1738 | }, | ||
| 1739 | }; |
lib/std/os/linux.zig+4| ... | @@ -1193,6 +1193,10 @@ pub fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) usi | ... | @@ -1193,6 +1193,10 @@ pub fn tcsetattr(fd: fd_t, optional_action: TCSA, termios_p: *const termios) usi |
| 1193 | return syscall3(.ioctl, @bitCast(usize, @as(isize, fd)), TCSETS + @enumToInt(optional_action), @ptrToInt(termios_p)); | 1193 | return syscall3(.ioctl, @bitCast(usize, @as(isize, fd)), TCSETS + @enumToInt(optional_action), @ptrToInt(termios_p)); |
| 1194 | } | 1194 | } |
| 1195 | 1195 | ||
| 1196 | pub fn ioctl(fd: fd_t, request: u32, arg: usize) usize { | ||
| 1197 | return syscall3(.ioctl, @bitCast(usize, @as(isize, fd)), request, arg); | ||
| 1198 | } | ||
| 1199 | |||
| 1196 | test "" { | 1200 | test "" { |
| 1197 | if (builtin.os.tag == .linux) { | 1201 | if (builtin.os.tag == .linux) { |
| 1198 | _ = @import("linux/test.zig"); | 1202 | _ = @import("linux/test.zig"); |