| ... | @@ -50,19 +50,22 @@ pub const IpAddress = extern union { | ... | @@ -50,19 +50,22 @@ pub const IpAddress = extern union { |
| 50 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { | 50 | pub fn parseIp6(buf: []const u8, port: u16) !IpAddress { |
| 51 | var result = IpAddress{ | 51 | var result = IpAddress{ |
| 52 | .in6 = os.sockaddr_in6{ | 52 | .in6 = os.sockaddr_in6{ |
| 53 | .scope_id = undefined, | 53 | .scope_id = 0, |
| 54 | .port = mem.nativeToBig(u16, port), | 54 | .port = mem.nativeToBig(u16, port), |
| 55 | .flowinfo = 0, | 55 | .flowinfo = 0, |
| 56 | .addr = undefined, | 56 | .addr = undefined, |
| 57 | }, | 57 | }, |
| 58 | }; | 58 | }; |
| 59 | const ip_slice = result.in6.addr[0..]; | 59 | var ip_slice = result.in6.addr[0..]; |
| | 60 | |
| | 61 | var tail: [16]u8 = undefined; |
| 60 | | 62 | |
| 61 | var x: u16 = 0; | 63 | var x: u16 = 0; |
| 62 | var saw_any_digits = false; | 64 | var saw_any_digits = false; |
| 63 | var index: u8 = 0; | 65 | var index: u8 = 0; |
| 64 | var scope_id = false; | 66 | var scope_id = false; |
| 65 | for (buf) |c| { | 67 | var abbrv = false; |
| | 68 | for (buf) |c, i| { |
| 66 | if (scope_id) { | 69 | if (scope_id) { |
| 67 | if (c >= '0' and c <= '9') { | 70 | if (c >= '0' and c <= '9') { |
| 68 | const digit = c - '0'; | 71 | const digit = c - '0'; |
| ... | @@ -77,7 +80,12 @@ pub const IpAddress = extern union { | ... | @@ -77,7 +80,12 @@ pub const IpAddress = extern union { |
| 77 | } | 80 | } |
| 78 | } else if (c == ':') { | 81 | } else if (c == ':') { |
| 79 | if (!saw_any_digits) { | 82 | if (!saw_any_digits) { |
| 80 | return error.InvalidCharacter; | 83 | if (abbrv) return error.InvalidCharacter; // ':::' |
| | 84 | if (i != 0) abbrv = true; |
| | 85 | mem.set(u8, ip_slice[index..], 0); |
| | 86 | ip_slice = tail[0..]; |
| | 87 | index = 0; |
| | 88 | continue; |
| 81 | } | 89 | } |
| 82 | if (index == 14) { | 90 | if (index == 14) { |
| 83 | return error.InvalidEnd; | 91 | return error.InvalidEnd; |
| ... | @@ -93,12 +101,6 @@ pub const IpAddress = extern union { | ... | @@ -93,12 +101,6 @@ pub const IpAddress = extern union { |
| 93 | if (!saw_any_digits) { | 101 | if (!saw_any_digits) { |
| 94 | return error.InvalidCharacter; | 102 | return error.InvalidCharacter; |
| 95 | } | 103 | } |
| 96 | if (index == 14) { | | |
| 97 | ip_slice[index] = @truncate(u8, x >> 8); | | |
| 98 | index += 1; | | |
| 99 | ip_slice[index] = @truncate(u8, x); | | |
| 100 | index += 1; | | |
| 101 | } | | |
| 102 | scope_id = true; | 104 | scope_id = true; |
| 103 | saw_any_digits = false; | 105 | saw_any_digits = false; |
| 104 | } else { | 106 | } else { |
| ... | @@ -113,21 +115,22 @@ pub const IpAddress = extern union { | ... | @@ -113,21 +115,22 @@ pub const IpAddress = extern union { |
| 113 | } | 115 | } |
| 114 | } | 116 | } |
| 115 | | 117 | |
| 116 | if (!saw_any_digits) { | 118 | if (!saw_any_digits and !abbrv) { |
| 117 | return error.Incomplete; | 119 | return error.Incomplete; |
| 118 | } | 120 | } |
| 119 | | 121 | |
| 120 | if (scope_id) { | | |
| 121 | return result; | | |
| 122 | } | | |
| 123 | | | |
| 124 | if (index == 14) { | 122 | if (index == 14) { |
| 125 | ip_slice[14] = @truncate(u8, x >> 8); | 123 | ip_slice[14] = @truncate(u8, x >> 8); |
| 126 | ip_slice[15] = @truncate(u8, x); | 124 | ip_slice[15] = @truncate(u8, x); |
| 127 | return result; | 125 | return result; |
| | 126 | } else { |
| | 127 | ip_slice[index] = @truncate(u8, x >> 8); |
| | 128 | index += 1; |
| | 129 | ip_slice[index] = @truncate(u8, x); |
| | 130 | index += 1; |
| | 131 | mem.copy(u8, result.in6.addr[16 - index ..], ip_slice[0..index]); |
| | 132 | return result; |
| 128 | } | 133 | } |
| 129 | | | |
| 130 | return error.Incomplete; | | |
| 131 | } | 134 | } |
| 132 | | 135 | |
| 133 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { | 136 | pub fn parseIp4(buf: []const u8, port: u16) !IpAddress { |
| ... | @@ -246,10 +249,6 @@ pub const IpAddress = extern union { | ... | @@ -246,10 +249,6 @@ pub const IpAddress = extern union { |
| 246 | ); | 249 | ); |
| 247 | }, | 250 | }, |
| 248 | os.AF_INET6 => { | 251 | os.AF_INET6 => { |
| 249 | const ZeroRun = struct { | | |
| 250 | index: usize, | | |
| 251 | count: usize, | | |
| 252 | }; | | |
| 253 | const port = mem.bigToNative(u16, self.in6.port); | 252 | const port = mem.bigToNative(u16, self.in6.port); |
| 254 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); | 253 | const big_endian_parts = @ptrCast(*align(1) const [8]u16, &self.in6.addr); |
| 255 | const native_endian_parts = switch (builtin.endian) { | 254 | const native_endian_parts = switch (builtin.endian) { |
| ... | @@ -262,44 +261,21 @@ pub const IpAddress = extern union { | ... | @@ -262,44 +261,21 @@ pub const IpAddress = extern union { |
| 262 | break :blk buf; | 261 | break :blk buf; |
| 263 | }, | 262 | }, |
| 264 | }; | 263 | }; |
| 265 | | | |
| 266 | var longest_zero_run: ?ZeroRun = null; | | |
| 267 | var this_zero_run: ?ZeroRun = null; | | |
| 268 | for (native_endian_parts) |part, i| { | | |
| 269 | if (part == 0) { | | |
| 270 | if (this_zero_run) |*zr| { | | |
| 271 | zr.count += 1; | | |
| 272 | } else { | | |
| 273 | this_zero_run = ZeroRun{ | | |
| 274 | .index = i, | | |
| 275 | .count = 1, | | |
| 276 | }; | | |
| 277 | } | | |
| 278 | } else if (this_zero_run) |zr| { | | |
| 279 | if (longest_zero_run) |lzr| { | | |
| 280 | if (zr.count > lzr.count and zr.count > 1) { | | |
| 281 | longest_zero_run = zr; | | |
| 282 | } | | |
| 283 | } else { | | |
| 284 | longest_zero_run = zr; | | |
| 285 | } | | |
| 286 | } | | |
| 287 | } | | |
| 288 | try output(context, "["); | 264 | try output(context, "["); |
| 289 | var i: usize = 0; | 265 | var i: usize = 0; |
| 290 | while (i < native_endian_parts.len) { | 266 | var abbrv = false; |
| 291 | if (i != 0) try output(context, ":"); | 267 | while (i < native_endian_parts.len) : (i += 1) { |
| 292 | | 268 | if (native_endian_parts[i] == 0) { |
| 293 | if (longest_zero_run) |lzr| { | 269 | if (!abbrv) { |
| 294 | if (lzr.index == i) { | 270 | try output(context, if (i == 0) "::" else ":"); |
| 295 | i += lzr.count; | 271 | abbrv = true; |
| 296 | continue; | | |
| 297 | } | 272 | } |
| | 273 | continue; |
| | 274 | } |
| | 275 | try std.fmt.format(context, Errors, output, "{x}", native_endian_parts[i]); |
| | 276 | if (i != native_endian_parts.len - 1) { |
| | 277 | try output(context, ":"); |
| 298 | } | 278 | } |
| 299 | | | |
| 300 | const part = native_endian_parts[i]; | | |
| 301 | try std.fmt.format(context, Errors, output, "{x}", part); | | |
| 302 | i += 1; | | |
| 303 | } | 279 | } |
| 304 | try std.fmt.format(context, Errors, output, "]:{}", port); | 280 | try std.fmt.format(context, Errors, output, "]:{}", port); |
| 305 | }, | 281 | }, |