addr.odin 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. #+build windows, linux, darwin, freebsd
  2. package net
  3. /*
  4. Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
  5. For other protocols and their features, see subdirectories of this package.
  6. */
  7. /*
  8. Copyright 2022 Tetralux <[email protected]>
  9. Copyright 2022 Colin Davidson <[email protected]>
  10. Copyright 2022 Jeroen van Rijn <[email protected]>.
  11. Copyright 2024 Feoramund <[email protected]>.
  12. Made available under Odin's BSD-3 license.
  13. List of contributors:
  14. Tetralux: Initial implementation
  15. Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
  16. Jeroen van Rijn: Cross platform unification, code style, documentation
  17. Feoramund: FreeBSD platform code
  18. */
  19. import "core:strconv"
  20. import "core:strings"
  21. import "core:fmt"
  22. /*
  23. Expects an IPv4 address with no leading or trailing whitespace:
  24. - a.b.c.d
  25. - a.b.c.d:port
  26. - [a.b.c.d]:port
  27. If the IP address is bracketed, the port must be present and valid (though it will be ignored):
  28. - [a.b.c.d] will be treated as a parsing failure.
  29. The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
  30. If `allow_non_decimal` is false, `aton` is told each component must be decimal and max 255.
  31. */
  32. parse_ip4_address :: proc(address_and_maybe_port: string, allow_non_decimal := false) -> (addr: IP4_Address, ok: bool) {
  33. res := aton(address_and_maybe_port, .IP4, !allow_non_decimal) or_return
  34. return res.?
  35. }
  36. /*
  37. Parses an IP address in "non-decimal" `inet_aton` form.
  38. e.g."00377.0x0ff.65534" = 255.255.255.254
  39. 00377 = 255 in octal
  40. 0x0ff = 255 in hexadecimal
  41. This leaves 16 bits worth of address
  42. .65534 then accounts for the last two digits
  43. For the address part the allowed forms are:
  44. a.b.c.d - where each part represents a byte
  45. a.b.c - where `a` & `b` represent a byte and `c` a u16
  46. a.b - where `a` represents a byte and `b` supplies the trailing 24 bits
  47. a - where `a` gives the entire 32-bit value
  48. The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
  49. */
  50. aton :: proc(address_and_maybe_port: string, family: Address_Family, allow_decimal_only := false) -> (addr: Address, ok: bool) {
  51. switch family {
  52. case .IP4:
  53. // There is no valid address shorter than `0.0.0.0`.
  54. if len(address_and_maybe_port) < 7 {
  55. return {}, false
  56. }
  57. address, _ := split_port(address_and_maybe_port) or_return // This call doesn't allocate
  58. buf: [4]u64 = {}
  59. i := 0
  60. max_value := u64(max(u32))
  61. bases := DEFAULT_DIGIT_BASES
  62. if allow_decimal_only {
  63. max_value = 255
  64. bases = {.Dec}
  65. }
  66. for len(address) > 0 {
  67. if i == 4 {
  68. return {}, false
  69. }
  70. // Decimal-only addresses may not have a leading zero.
  71. if allow_decimal_only && len(address) > 1 && address[0] == '0' && address[1] != '.' {
  72. return
  73. }
  74. number, consumed, number_ok := parse_ip_component(address, max_value, bases)
  75. if !number_ok || consumed == 0 {
  76. return {}, false
  77. }
  78. buf[i] = number
  79. address = address[consumed:]
  80. if len(address) > 0 && address[0] == '.' {
  81. address = address[1:]
  82. }
  83. i += 1
  84. }
  85. // Distribute parts.
  86. switch i {
  87. case 1:
  88. buf[1] = buf[0] & 0xffffff
  89. buf[0] >>= 24
  90. fallthrough
  91. case 2:
  92. buf[2] = buf[1] & 0xffff
  93. buf[1] >>= 16
  94. fallthrough
  95. case 3:
  96. buf[3] = buf[2] & 0xff
  97. buf[2] >>= 8
  98. }
  99. a: [4]u8 = ---
  100. for v, j in buf {
  101. if v > 255 { return {}, false }
  102. a[j] = u8(v)
  103. }
  104. return IP4_Address(a), true
  105. case .IP6:
  106. return parse_ip6_address(address_and_maybe_port)
  107. case:
  108. return nil, false
  109. }
  110. }
  111. /*
  112. The minimum length of a valid IPv6 address string is 2, e.g. `::`
  113. The maximum length of a valid IPv6 address string is 45, when it embeds an IPv4,
  114. e.g. `0000:0000:0000:0000:0000:ffff:255.255.255.255`
  115. An IPv6 address must contain at least 3 pieces, e.g. `::`,
  116. and at most 9 (using `::` for a trailing or leading 0)
  117. */
  118. IPv6_MIN_STRING_LENGTH :: 2
  119. IPv6_MAX_STRING_LENGTH :: 45
  120. IPv6_MIN_COLONS :: 2
  121. IPv6_PIECE_COUNT :: 8
  122. parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, ok: bool) {
  123. // If we have an IPv6 address of the form [IP]:Port, first get us just the IP.
  124. address, _ := split_port(address_and_maybe_port) or_return
  125. // Early bailouts based on length and number of pieces.
  126. if len(address) < IPv6_MIN_STRING_LENGTH || len(address) > IPv6_MAX_STRING_LENGTH { return }
  127. /*
  128. Do a pre-pass on the string that checks how many `:` and `.` we have,
  129. if they're in the right order, and if the things between them are digits as expected.
  130. It's not strictly necessary considering we could use `strings.split`,
  131. but this way we can avoid using an allocator and return earlier on bogus input. Win-win.
  132. */
  133. colon_count := 0
  134. dot_count := 0
  135. pieces_temp: [IPv6_PIECE_COUNT + 1]string
  136. piece_start := 0
  137. piece_end := 0
  138. for ch, i in address {
  139. switch ch {
  140. case '0'..='9', 'a'..='f', 'A'..='F':
  141. piece_end += 1
  142. case ':':
  143. // If we see a `:` after a `.`, it means an IPv4 part was sandwiched between IPv6, instead of it being the tail: invalid.
  144. if dot_count > 0 { return }
  145. pieces_temp[colon_count] = address[piece_start:piece_end]
  146. colon_count += 1
  147. if colon_count > IPv6_PIECE_COUNT { return }
  148. // If there's anything left, put it in the next piece.
  149. piece_start = i + 1
  150. piece_end = piece_start
  151. case '.':
  152. // IPv4 address is treated as one piece. No need to update `piece_*`.
  153. dot_count += 1
  154. case: // Invalid character, return early
  155. return
  156. }
  157. }
  158. if colon_count < IPv6_MIN_COLONS { return }
  159. // Assign the last piece string.
  160. pieces_temp[colon_count] = address[piece_start:]
  161. // `pieces` now holds the same output as it would if had used `strings.split`.
  162. pieces := pieces_temp[:colon_count + 1]
  163. // Check if we have what looks like an embedded IPv4 address.
  164. ipv4: IP4_Address
  165. have_ipv4: bool
  166. if dot_count > 0 {
  167. /*
  168. If we have an IPv4 address accounting for the last 32 bits,
  169. this means we can have at most 6 IPv6 pieces, like so: `x:x:X:x:x:x:d.d.d.d`
  170. Or, put differently: 6 pieces IPv6 (5 colons), a colon, 1 piece IPv4 (3 dots),
  171. for a total of 6 colons and 3 dots.
  172. */
  173. if dot_count != 3 || colon_count > 6 { return }
  174. /*
  175. Try to parse IPv4 address.
  176. If successful, we have our least significant 32 bits.
  177. If not, it invalidates the whole address and we can bail.
  178. */
  179. ipv4, have_ipv4 = parse_ip4_address(pieces_temp[colon_count])
  180. if !have_ipv4 { return }
  181. }
  182. // Check for `::` being used more than once, and save the skip.
  183. zero_skip := -1
  184. for i in 1..<colon_count {
  185. if pieces[i] == "" {
  186. // Return if skip has already been set.
  187. if zero_skip != -1 { return }
  188. zero_skip = i
  189. }
  190. }
  191. /*
  192. Now check if we have the necessary number pieces, accounting for any `::`,
  193. and how many were skipped by it if applicable.
  194. */
  195. before_skip := 0
  196. after_skip := 0
  197. num_skipped := 0
  198. if zero_skip != -1 {
  199. before_skip = zero_skip
  200. after_skip = colon_count - zero_skip
  201. // An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
  202. if have_ipv4 {
  203. after_skip += 1
  204. }
  205. // Adjust for leading `::`.
  206. if pieces[0] == "" {
  207. before_skip -= 1
  208. // Leading `:` can only be part of `::`.
  209. if before_skip > 0 { return }
  210. }
  211. // Adjust for trailing `::`.
  212. if pieces[colon_count] == "" {
  213. after_skip -= 1
  214. // Trailing `:` can only be part of `::`.
  215. if after_skip > 0 { return }
  216. }
  217. /*
  218. Calculate how many zero pieces we skipped.
  219. It should be at least one, considering we encountered a `::`.
  220. */
  221. num_skipped = IPv6_PIECE_COUNT - before_skip - after_skip
  222. if num_skipped < 1 { return }
  223. } else {
  224. /*
  225. No zero skip means everything is part of "before the skip".
  226. An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
  227. */
  228. piece_count := colon_count + 1
  229. if have_ipv4 {
  230. piece_count += 1
  231. }
  232. // Do we have the complete set?
  233. if piece_count != IPv6_PIECE_COUNT { return }
  234. // Validate leading and trailing empty parts, as they can only be part of a `::`.
  235. if pieces[0] == "" || pieces[colon_count] == "" { return }
  236. before_skip = piece_count
  237. after_skip = 0
  238. num_skipped = 0
  239. }
  240. // Now try to parse the pieces into a 8 16-bit pieces.
  241. piece_values: [IPv6_PIECE_COUNT]u16be
  242. idx := 0
  243. val_idx := 0
  244. for _ in 0..<before_skip {
  245. /*
  246. An empty piece is the default zero. Otherwise, try to parse as an IPv6 hex piece.
  247. If we have an IPv4 address, stop on the penultimate index.
  248. */
  249. if have_ipv4 && val_idx == 6 {
  250. break
  251. }
  252. piece := pieces[idx]
  253. // An IPv6 piece can at most contain 4 hex digits.
  254. if len(piece) > 4 { return }
  255. if piece != "" {
  256. val, _ := parse_ip_component(piece, 65535, {.IPv6}) or_return
  257. piece_values[val_idx] = u16be(val)
  258. }
  259. idx += 1
  260. val_idx += 1
  261. }
  262. if before_skip == 0 {
  263. idx += 1
  264. }
  265. if num_skipped > 0 {
  266. idx += 1
  267. val_idx += num_skipped
  268. }
  269. if after_skip > 0 {
  270. for _ in 0..<after_skip {
  271. /*
  272. An empty piece is the default zero. Otherwise, try to parse as an IPv6 hex piece.
  273. If we have an IPv4 address, stop on the penultimate index.
  274. */
  275. if have_ipv4 && val_idx == 6 {
  276. break
  277. }
  278. piece := pieces[idx]
  279. // An IPv6 piece can contain at most 4 hex digits.
  280. if len(piece) > 4 { return }
  281. if piece != "" {
  282. val, _ := parse_ip_component(piece, 65535, {.IPv6}) or_return
  283. piece_values[val_idx] = u16be(val)
  284. }
  285. idx += 1
  286. val_idx += 1
  287. }
  288. }
  289. // Distribute IPv4 address into last two pieces, if applicable.
  290. if have_ipv4 {
  291. val := u16(ipv4[0]) << 8
  292. val |= u16(ipv4[1])
  293. piece_values[6] = u16be(val)
  294. val = u16(ipv4[2]) << 8
  295. val |= u16(ipv4[3])
  296. piece_values[7] = u16be(val)
  297. }
  298. return IP6_Address(piece_values), true
  299. }
  300. /*
  301. Try parsing as an IPv6 address.
  302. If it's determined not to be, try as an IPv4 address, optionally in non-decimal format.
  303. */
  304. parse_address :: proc(address_and_maybe_port: string, non_decimal_address := false) -> Address {
  305. if addr6, ok6 := parse_ip6_address(address_and_maybe_port); ok6 {
  306. return addr6
  307. }
  308. if addr4, ok4 := parse_ip4_address(address_and_maybe_port, non_decimal_address); ok4 {
  309. return addr4
  310. }
  311. return nil
  312. }
  313. parse_endpoint :: proc(endpoint_str: string) -> (ep: Endpoint, ok: bool) {
  314. if addr_str, port, split_ok := split_port(endpoint_str); split_ok {
  315. if addr := parse_address(addr_str); addr != nil {
  316. return Endpoint { address = addr, port = port }, true
  317. }
  318. }
  319. return
  320. }
  321. Host :: struct {
  322. hostname: string,
  323. port: int,
  324. }
  325. Host_Or_Endpoint :: union {
  326. Host,
  327. Endpoint,
  328. }
  329. // Takes a string consisting of a hostname or IP address, and an optional port,
  330. // and return the component parts in a useful form.
  331. parse_hostname_or_endpoint :: proc(endpoint_str: string) -> (target: Host_Or_Endpoint, err: Parse_Endpoint_Error) {
  332. host, port, port_ok := split_port(endpoint_str)
  333. if !port_ok {
  334. return nil, .Bad_Port
  335. }
  336. if addr := parse_address(host); addr != nil {
  337. return Endpoint{addr, port}, .None
  338. }
  339. if !validate_hostname(host) {
  340. return nil, .Bad_Hostname
  341. }
  342. return Host{host, port}, .None
  343. }
  344. // Takes an endpoint string and returns its parts.
  345. // Returns ok=false if port is not a number.
  346. split_port :: proc(endpoint_str: string) -> (addr_or_host: string, port: int, ok: bool) {
  347. // IP6 [addr_or_host]:port
  348. if i := strings.last_index(endpoint_str, "]:"); i >= 0 {
  349. addr_or_host = endpoint_str[1:i]
  350. port, ok = strconv.parse_int(endpoint_str[i+2:], 10)
  351. if port > 65535 {
  352. ok = false
  353. }
  354. return
  355. }
  356. if n := strings.count(endpoint_str, ":"); n == 1 {
  357. // IP4 addr_or_host:port
  358. i := strings.last_index(endpoint_str, ":")
  359. assert(i != -1)
  360. addr_or_host = endpoint_str[:i]
  361. port, ok = strconv.parse_int(endpoint_str[i+1:], 10)
  362. if port > 65535 {
  363. ok = false
  364. }
  365. return
  366. } else if n > 1 {
  367. // IP6 address without port
  368. }
  369. // No port
  370. addr_or_host = endpoint_str
  371. port = 0
  372. ok = true
  373. return
  374. }
  375. // Joins an address or hostname with a port.
  376. join_port :: proc(address_or_host: string, port: int, allocator := context.allocator) -> string {
  377. addr_or_host, _, ok := split_port(address_or_host)
  378. if !ok {
  379. return addr_or_host
  380. }
  381. b := strings.builder_make(allocator)
  382. addr := parse_address(addr_or_host)
  383. if addr == nil {
  384. // hostname
  385. fmt.sbprintf(&b, "%v:%v", addr_or_host, port)
  386. } else {
  387. switch _ in addr {
  388. case IP4_Address:
  389. fmt.sbprintf(&b, "%v:%v", address_to_string(addr), port)
  390. case IP6_Address:
  391. fmt.sbprintf(&b, "[%v]:%v", address_to_string(addr), port)
  392. }
  393. }
  394. return strings.to_string(b)
  395. }
  396. // TODO(tetra): Do we need this?
  397. map_to_ip6 :: proc(addr: Address) -> Address {
  398. if addr6, ok := addr.(IP6_Address); ok {
  399. return addr6
  400. }
  401. addr4 := addr.(IP4_Address)
  402. addr4_u16 := transmute([2]u16be) addr4
  403. addr6: IP6_Address
  404. addr6[4] = 0xffff
  405. copy(addr6[5:], addr4_u16[:])
  406. return addr6
  407. }
  408. /*
  409. Returns a temporarily-allocated string representation of the address.
  410. See RFC 5952 section 4 for IPv6 representation recommendations.
  411. */
  412. address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> string {
  413. b := strings.builder_make(allocator)
  414. switch v in addr {
  415. case IP4_Address:
  416. fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3])
  417. case IP6_Address:
  418. // First find the longest run of zeroes.
  419. Zero_Run :: struct {
  420. start: int,
  421. end: int,
  422. }
  423. /*
  424. We're dealing with 0-based indices, appropriately enough for runs of zeroes.
  425. Still, it means we need to initialize runs with some value outside of the possible range.
  426. */
  427. run := Zero_Run{-1, -1}
  428. best := Zero_Run{-1, -1}
  429. last := u16be(1)
  430. for val, i in v {
  431. /*
  432. If we encounter adjacent zeroes, then start a new run if not already in one.
  433. Also remember the rightmost index regardless, because it'll be the new
  434. frontier of both new and existing runs.
  435. */
  436. if last == 0 && val == 0 {
  437. run.end = i
  438. if run.start == -1 {
  439. run.start = i - 1
  440. }
  441. }
  442. /*
  443. If we're in a run check if its length is better than the best recorded so far.
  444. If so, update the best run's start and end.
  445. */
  446. if run.start != -1 {
  447. length_to_beat := best.end - best.start
  448. length := run.end - run.start
  449. if length > length_to_beat {
  450. best = run
  451. }
  452. }
  453. // If we were in a run, this is where we reset it.
  454. if val != 0 {
  455. run = {-1, -1}
  456. }
  457. last = val
  458. }
  459. for val, i in v {
  460. if best.start == i || best.end == i {
  461. // For the left and right side of the best zero run, print a `:`.
  462. fmt.sbprint(&b, ":")
  463. } else if i < best.start {
  464. /*
  465. If we haven't made it to the best run yet, print the digit.
  466. Make sure we only print a `:` after the digit if it's not
  467. immediately followed by the run's own leftmost `:`.
  468. */
  469. fmt.sbprintf(&b, "%x", val)
  470. if i < best.start - 1 {
  471. fmt.sbprintf(&b, ":")
  472. }
  473. } else if i > best.end {
  474. /*
  475. If there are any digits after the zero run, print them.
  476. But don't print the `:` at the end of the IP number.
  477. */
  478. fmt.sbprintf(&b, "%x", val)
  479. if i != 7 {
  480. fmt.sbprintf(&b, ":")
  481. }
  482. }
  483. }
  484. }
  485. return strings.to_string(b)
  486. }
  487. // Returns a temporarily-allocated string representation of the endpoint.
  488. // If there's a port, uses the `ip4address:port` or `[ip6address]:port` format, respectively.
  489. endpoint_to_string :: proc(ep: Endpoint, allocator := context.temp_allocator) -> string {
  490. if ep.port == 0 {
  491. return address_to_string(ep.address, allocator)
  492. } else {
  493. s := address_to_string(ep.address, context.temp_allocator)
  494. b := strings.builder_make(allocator)
  495. switch a in ep.address {
  496. case IP4_Address: fmt.sbprintf(&b, "%v:%v", s, ep.port)
  497. case IP6_Address: fmt.sbprintf(&b, "[%v]:%v", s, ep.port)
  498. }
  499. return strings.to_string(b)
  500. }
  501. }
  502. to_string :: proc{address_to_string, endpoint_to_string}
  503. family_from_address :: proc(addr: Address) -> Address_Family {
  504. switch _ in addr {
  505. case IP4_Address: return .IP4
  506. case IP6_Address: return .IP6
  507. case:
  508. unreachable()
  509. }
  510. }
  511. family_from_endpoint :: proc(ep: Endpoint) -> Address_Family {
  512. return family_from_address(ep.address)
  513. }
  514. Digit_Parse_Base :: enum u8 {
  515. Dec = 0, // No prefix
  516. Oct = 1, // Leading zero
  517. Hex = 2, // 0x prefix
  518. IPv6 = 3, // Unprefixed IPv6 piece hex. Can't be used with other bases.
  519. }
  520. Digit_Parse_Bases :: bit_set[Digit_Parse_Base; u8]
  521. DEFAULT_DIGIT_BASES :: Digit_Parse_Bases{.Dec, .Oct, .Hex}
  522. /*
  523. Parses a single unsigned number in requested `bases` from `input`.
  524. `max_value` represents the maximum allowed value for this number.
  525. Returns the `value`, the `bytes_consumed` so far, and `ok` to signal success or failure.
  526. An out-of-range or invalid number will return the accumulated value so far (which can be out of range),
  527. the number of bytes consumed leading up the error, and `ok = false`.
  528. When `.` or `:` are encountered, they'll be considered valid separators and will stop parsing,
  529. returning the valid number leading up to it.
  530. Other non-digit characters are treated as an error.
  531. Octal numbers are expected to have a leading zero, with no 'o' format specifier.
  532. Hexadecimal numbers are expected to be preceded by '0x' or '0X'.
  533. Numbers will otherwise be considered to be in base 10.
  534. */
  535. parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := DEFAULT_DIGIT_BASES) -> (value: u64, bytes_consumed: int, ok: bool) {
  536. // Default to base 10
  537. base := u64(10)
  538. input := input
  539. /*
  540. We keep track of the number of prefix bytes and digit bytes separately.
  541. This way if a prefix is consumed and we encounter a separator or the end of the string,
  542. the number is only considered valid if at least 1 digit byte has been consumed and the value is within range.
  543. */
  544. prefix_bytes := 0
  545. digit_bytes := 0
  546. /*
  547. IPv6 hex bytes are unprefixed and can't be disambiguated from octal or hex unless the digit is out of range.
  548. If we got the `.IPv6` option, skip prefix scanning and other flags aren't also used.
  549. */
  550. if .IPv6 in bases {
  551. if bases != {.IPv6} { return } // Must be used on its own.
  552. base = 16
  553. } else {
  554. // Scan for and consume prefix, if applicable.
  555. if len(input) >= 2 && input[0] == '0' {
  556. if .Hex in bases && (input[1] == 'x' || input[1] == 'X') {
  557. base = 16
  558. input = input[2:]
  559. prefix_bytes = 2
  560. }
  561. if prefix_bytes == 0 && .Oct in bases {
  562. base = 8
  563. input = input[1:]
  564. prefix_bytes = 1
  565. }
  566. }
  567. }
  568. parse_loop: for ch in input {
  569. switch ch {
  570. case '0'..='7':
  571. digit_bytes += 1
  572. value = value * base + u64(ch - '0')
  573. case '8'..='9':
  574. digit_bytes += 1
  575. if base == 8 {
  576. // Out of range for octal numbers.
  577. return value, digit_bytes + prefix_bytes, false
  578. }
  579. value = value * base + u64(ch - '0')
  580. case 'a'..='f':
  581. digit_bytes += 1
  582. if base == 8 || base == 10 {
  583. // Out of range for octal and decimal numbers.
  584. return value, digit_bytes + prefix_bytes, false
  585. }
  586. value = value * base + (u64(ch - 'a') + 10)
  587. case 'A'..='F':
  588. digit_bytes += 1
  589. if base == 8 || base == 10 {
  590. // Out of range for octal and decimal numbers.
  591. return value, digit_bytes + prefix_bytes, false
  592. }
  593. value = value * base + (u64(ch - 'A') + 10)
  594. case '.', ':':
  595. /*
  596. Number separator. Return early.
  597. We don't need to check if the number is in range.
  598. We do that each time through the loop.
  599. */
  600. break parse_loop
  601. case:
  602. // Invalid character encountered.
  603. return value, digit_bytes + prefix_bytes, false
  604. }
  605. if value > max_value {
  606. // Out-of-range number.
  607. return value, digit_bytes + prefix_bytes, false
  608. }
  609. }
  610. // If we consumed at least 1 digit byte, `value` *should* continue a valid number in an appropriate base in the allowable range.
  611. return value, digit_bytes + prefix_bytes, digit_bytes >= 1
  612. }
  613. // Returns an address for each interface that can be bound to.
  614. get_network_interfaces :: proc() -> []Address {
  615. // TODO: Implement using `enumerate_interfaces` and returning only the addresses of active interfaces.
  616. return nil
  617. }