mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Update comments
This commit is contained in:
+57
-131
@@ -31,10 +31,10 @@ import "core:fmt"
|
|||||||
|
|
||||||
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
|
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
|
||||||
|
|
||||||
If `non_decimal_address` is true, `aton` is told each component must be decimal and max 255.
|
If `allow_non_decimal` is true, `aton` is told each component must be decimal and max 255.
|
||||||
*/
|
*/
|
||||||
parse_ip4_address :: proc(address_and_maybe_port: string, non_decimal_address := false) -> (addr: IP4_Address, ok: bool) {
|
parse_ip4_address :: proc(address_and_maybe_port: string, allow_non_decimal := false) -> (addr: IP4_Address, ok: bool) {
|
||||||
res, res_ok := aton(address_and_maybe_port, .IP4, !non_decimal_address)
|
res, res_ok := aton(address_and_maybe_port, .IP4, !allow_non_decimal)
|
||||||
if ip4, ip4_ok := res.(IP4_Address); ip4_ok {
|
if ip4, ip4_ok := res.(IP4_Address); ip4_ok {
|
||||||
return ip4, res_ok
|
return ip4, res_ok
|
||||||
}
|
}
|
||||||
@@ -58,12 +58,10 @@ parse_ip4_address :: proc(address_and_maybe_port: string, non_decimal_address :=
|
|||||||
|
|
||||||
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
|
The port, if present, is required to be a base 10 number in the range 0-65535, inclusive.
|
||||||
*/
|
*/
|
||||||
aton :: proc(address_and_maybe_port: string, family: Address_Family, is_decimal_only := false) -> (addr: Address, ok: bool) {
|
aton :: proc(address_and_maybe_port: string, family: Address_Family, allow_decimal_only := false) -> (addr: Address, ok: bool) {
|
||||||
switch family {
|
switch family {
|
||||||
case .IP4:
|
case .IP4:
|
||||||
/*
|
// There is no valid address shorter than `0.0.0.0`.
|
||||||
There is no valid address shorter than `0.0.0.0`.
|
|
||||||
*/
|
|
||||||
if len(address_and_maybe_port) < 7 {
|
if len(address_and_maybe_port) < 7 {
|
||||||
return {}, false
|
return {}, false
|
||||||
}
|
}
|
||||||
@@ -76,7 +74,7 @@ aton :: proc(address_and_maybe_port: string, family: Address_Family, is_decimal_
|
|||||||
max_value := u64(max(u32))
|
max_value := u64(max(u32))
|
||||||
bases := DEFAULT_DIGIT_BASES
|
bases := DEFAULT_DIGIT_BASES
|
||||||
|
|
||||||
if is_decimal_only {
|
if allow_decimal_only {
|
||||||
max_value = 255
|
max_value = 255
|
||||||
bases = {.Dec}
|
bases = {.Dec}
|
||||||
}
|
}
|
||||||
@@ -86,10 +84,8 @@ aton :: proc(address_and_maybe_port: string, family: Address_Family, is_decimal_
|
|||||||
return {}, false
|
return {}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Decimal-only addresses may not have a leading zero.
|
||||||
Decimal-only addresses may not have a leading zero.
|
if allow_decimal_only && len(address) > 1 && address[0] == '0' && address[1] != '.' {
|
||||||
*/
|
|
||||||
if is_decimal_only && len(address) > 1 && address[0] == '0' && address[1] != '.' {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,9 +104,7 @@ aton :: proc(address_and_maybe_port: string, family: Address_Family, is_decimal_
|
|||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Distribute parts.
|
||||||
Distribute parts.
|
|
||||||
*/
|
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
buf[1] = buf[0] & 0xffffff
|
buf[1] = buf[0] & 0xffffff
|
||||||
@@ -155,14 +149,10 @@ IPv6_MIN_COLONS :: 2
|
|||||||
IPv6_PIECE_COUNT :: 8
|
IPv6_PIECE_COUNT :: 8
|
||||||
|
|
||||||
parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, ok: bool) {
|
parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, ok: bool) {
|
||||||
/*
|
// If we have an IPv6 address of the form [IP]:Port, first get us just the IP.
|
||||||
If we have an IPv6 address of the form [IP]:Port, first get us just the IP.
|
|
||||||
*/
|
|
||||||
address, _ := split_port(address_and_maybe_port) or_return
|
address, _ := split_port(address_and_maybe_port) or_return
|
||||||
|
|
||||||
/*
|
// Early bailouts based on length and number of pieces.
|
||||||
Early bailouts based on length and number of pieces.
|
|
||||||
*/
|
|
||||||
if len(address) < IPv6_MIN_STRING_LENGTH || len(address) > IPv6_MAX_STRING_LENGTH { return }
|
if len(address) < IPv6_MIN_STRING_LENGTH || len(address) > IPv6_MAX_STRING_LENGTH { return }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -186,10 +176,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
piece_end += 1
|
piece_end += 1
|
||||||
|
|
||||||
case ':':
|
case ':':
|
||||||
/*
|
// If we see a `:` after a `.`, it means an IPv4 part was sandwiched between IPv6, instead of it being the tail: invalid.
|
||||||
If we see a `:` after a `.`, it means an IPv4 part was sandwiched between IPv6,
|
|
||||||
instead of it being the tail: invalid.
|
|
||||||
*/
|
|
||||||
if dot_count > 0 { return }
|
if dot_count > 0 { return }
|
||||||
|
|
||||||
pieces_temp[colon_count] = address[piece_start:piece_end]
|
pieces_temp[colon_count] = address[piece_start:piece_end]
|
||||||
@@ -197,19 +184,14 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
colon_count += 1
|
colon_count += 1
|
||||||
if colon_count > IPv6_PIECE_COUNT { return }
|
if colon_count > IPv6_PIECE_COUNT { return }
|
||||||
|
|
||||||
/*
|
// If there's anything left, put it in the next piece.
|
||||||
If there's anything left, put it in the next piece.
|
|
||||||
*/
|
|
||||||
piece_start = i + 1
|
piece_start = i + 1
|
||||||
piece_end = piece_start
|
piece_end = piece_start
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
/*
|
// IPv4 address is treated as one piece. No need to update `piece_*`.
|
||||||
IPv4 address is treated as one piece. No need to update `piece_*`.
|
|
||||||
*/
|
|
||||||
dot_count += 1
|
dot_count += 1
|
||||||
|
|
||||||
|
|
||||||
case: // Invalid character, return early
|
case: // Invalid character, return early
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -217,19 +199,13 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
|
|
||||||
if colon_count < IPv6_MIN_COLONS { return }
|
if colon_count < IPv6_MIN_COLONS { return }
|
||||||
|
|
||||||
/*
|
// Assign the last piece string.
|
||||||
Assign the last piece string.
|
|
||||||
*/
|
|
||||||
pieces_temp[colon_count] = address[piece_start:]
|
pieces_temp[colon_count] = address[piece_start:]
|
||||||
|
|
||||||
/*
|
// `pieces` now holds the same output as it would if had used `strings.split`.
|
||||||
`pieces` now holds the same output as it would if had used `strings.split`.
|
|
||||||
*/
|
|
||||||
pieces := pieces_temp[:colon_count + 1]
|
pieces := pieces_temp[:colon_count + 1]
|
||||||
|
|
||||||
/*
|
// Check if we have what looks like an embedded IPv4 address.
|
||||||
Check if we have what looks like an embedded IPv4 address.
|
|
||||||
*/
|
|
||||||
ipv4: IP4_Address
|
ipv4: IP4_Address
|
||||||
have_ipv4: bool
|
have_ipv4: bool
|
||||||
|
|
||||||
@@ -252,19 +228,12 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
if !have_ipv4 { return }
|
if !have_ipv4 { return }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Check for `::` being used more than once, and save the skip.
|
||||||
Check for `::` being used more than once, and save the skip.
|
|
||||||
*/
|
|
||||||
zero_skip := -1
|
zero_skip := -1
|
||||||
for i in 1..<len(pieces) - 1 {
|
for i in 1..<colon_count {
|
||||||
if pieces[i] == "" {
|
if pieces[i] == "" {
|
||||||
/*
|
// Return if skip has already been set.
|
||||||
Return if skip has already been set.
|
if zero_skip != -1 { return }
|
||||||
*/
|
|
||||||
if zero_skip != -1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
zero_skip = i
|
zero_skip = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,28 +248,22 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
|
|
||||||
if zero_skip != -1 {
|
if zero_skip != -1 {
|
||||||
before_skip = zero_skip
|
before_skip = zero_skip
|
||||||
after_skip = len(pieces) - zero_skip - 1
|
after_skip = colon_count - zero_skip
|
||||||
|
|
||||||
/*
|
// An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
|
||||||
An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
|
|
||||||
*/
|
|
||||||
if have_ipv4 {
|
if have_ipv4 {
|
||||||
after_skip += 1
|
after_skip += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Adjust for leading `::`.
|
||||||
Adjust for leading `::`.
|
|
||||||
*/
|
|
||||||
if pieces[0] == "" {
|
if pieces[0] == "" {
|
||||||
before_skip -= 1
|
before_skip -= 1
|
||||||
// Leading `:` can only be part of `::`.
|
// Leading `:` can only be part of `::`.
|
||||||
if before_skip > 0 { return }
|
if before_skip > 0 { return }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Adjust for trailing `::`.
|
||||||
Adjust for trailing `::`.
|
if pieces[colon_count] == "" {
|
||||||
*/
|
|
||||||
if pieces[len(pieces) - 1] == "" {
|
|
||||||
after_skip -= 1
|
after_skip -= 1
|
||||||
// Trailing `:` can only be part of `::`.
|
// Trailing `:` can only be part of `::`.
|
||||||
if after_skip > 0 { return }
|
if after_skip > 0 { return }
|
||||||
@@ -318,20 +281,16 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
No zero skip means everything is part of "before the skip".
|
No zero skip means everything is part of "before the skip".
|
||||||
An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
|
An IPv4 "piece" accounts for 2 IPv6 pieces we haven't added to the pieces slice, so add 1.
|
||||||
*/
|
*/
|
||||||
piece_count := len(pieces)
|
piece_count := colon_count + 1
|
||||||
if have_ipv4 {
|
if have_ipv4 {
|
||||||
piece_count += 1
|
piece_count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Do we have the complete set?
|
||||||
Do we have the complete set?
|
|
||||||
*/
|
|
||||||
if piece_count != IPv6_PIECE_COUNT { return }
|
if piece_count != IPv6_PIECE_COUNT { return }
|
||||||
|
|
||||||
/*
|
// Validate leading and trailing empty parts, as they can only be part of a `::`.
|
||||||
Validate leading and trailing empty parts, as they can only be part of a `::`.
|
if pieces[0] == "" || pieces[colon_count] == "" { return }
|
||||||
*/
|
|
||||||
if pieces[0] == "" || pieces[len(pieces) - 1] == "" { return }
|
|
||||||
|
|
||||||
|
|
||||||
before_skip = piece_count
|
before_skip = piece_count
|
||||||
@@ -339,9 +298,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
num_skipped = 0
|
num_skipped = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Now try to parse the pieces into a 8 16-bit pieces.
|
||||||
Now try to parse the pieces into a 8 16-bit pieces.
|
|
||||||
*/
|
|
||||||
piece_values: [IPv6_PIECE_COUNT]u16be
|
piece_values: [IPv6_PIECE_COUNT]u16be
|
||||||
|
|
||||||
idx := 0
|
idx := 0
|
||||||
@@ -358,9 +315,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
|
|
||||||
piece := pieces[idx]
|
piece := pieces[idx]
|
||||||
|
|
||||||
/*
|
// An IPv6 piece can at most contain 4 hex digits.
|
||||||
An IPv6 piece can at most contain 4 hex digits.
|
|
||||||
*/
|
|
||||||
if len(piece) > 4 { return }
|
if len(piece) > 4 { return }
|
||||||
|
|
||||||
if piece != "" {
|
if piece != "" {
|
||||||
@@ -393,9 +348,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
|
|
||||||
piece := pieces[idx]
|
piece := pieces[idx]
|
||||||
|
|
||||||
/*
|
// An IPv6 piece can contain at most 4 hex digits.
|
||||||
An IPv6 piece can at most contain 4 hex digits.
|
|
||||||
*/
|
|
||||||
if len(piece) > 4 { return }
|
if len(piece) > 4 { return }
|
||||||
|
|
||||||
if piece != "" {
|
if piece != "" {
|
||||||
@@ -408,20 +361,16 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Distribute IPv4 address into last two pieces, if applicable.
|
||||||
Distribute IPv4 address into last two pieces, if applicable.
|
|
||||||
*/
|
|
||||||
if have_ipv4 {
|
if have_ipv4 {
|
||||||
val := u16(ipv4[0]) << 8
|
val := u16(ipv4[0]) << 8
|
||||||
val |= u16(ipv4[1])
|
val |= u16(ipv4[1])
|
||||||
piece_values[6] = u16be(val)
|
piece_values[6] = u16be(val)
|
||||||
|
|
||||||
|
|
||||||
val = u16(ipv4[2]) << 8
|
val = u16(ipv4[2]) << 8
|
||||||
val |= u16(ipv4[3])
|
val |= u16(ipv4[3])
|
||||||
piece_values[7] = u16be(val)
|
piece_values[7] = u16be(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transmute(IP6_Address)piece_values, true
|
return transmute(IP6_Address)piece_values, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,22 +379,21 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address,
|
|||||||
If it's determined not to be, try as an IPv4 address, optionally in non-decimal format.
|
If it's determined not to be, try as an IPv4 address, optionally in non-decimal format.
|
||||||
*/
|
*/
|
||||||
parse_address :: proc(address_and_maybe_port: string, non_decimal_address := false) -> Address {
|
parse_address :: proc(address_and_maybe_port: string, non_decimal_address := false) -> Address {
|
||||||
addr6, ok6 := parse_ip6_address(address_and_maybe_port)
|
if addr6, ok6 := parse_ip6_address(address_and_maybe_port); ok6 {
|
||||||
if ok6 do return addr6
|
return addr6
|
||||||
addr4, ok4 := parse_ip4_address(address_and_maybe_port, non_decimal_address)
|
}
|
||||||
if ok4 do return addr4
|
if addr4, ok4 := parse_ip4_address(address_and_maybe_port, non_decimal_address); ok4 {
|
||||||
|
return addr4
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_endpoint :: proc(endpoint_str: string) -> (ep: Endpoint, ok: bool) {
|
parse_endpoint :: proc(endpoint_str: string) -> (ep: Endpoint, ok: bool) {
|
||||||
addr_str, port, split_ok := split_port(endpoint_str)
|
if addr_str, port, split_ok := split_port(endpoint_str); split_ok {
|
||||||
if !split_ok do return
|
if addr := parse_address(addr_str); addr != nil {
|
||||||
|
return Endpoint { address = addr, port = port }, true
|
||||||
addr := parse_address(addr_str)
|
}
|
||||||
if addr == nil do return
|
}
|
||||||
|
|
||||||
ep = Endpoint { address = addr, port = port }
|
|
||||||
ok = true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,9 +513,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
|
|||||||
case IP4_Address:
|
case IP4_Address:
|
||||||
fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3])
|
fmt.sbprintf(&b, "%v.%v.%v.%v", v[0], v[1], v[2], v[3])
|
||||||
case IP6_Address:
|
case IP6_Address:
|
||||||
/*
|
// First find the longest run of zeroes.
|
||||||
First find the longest run of zeroes.
|
|
||||||
*/
|
|
||||||
Zero_Run :: struct {
|
Zero_Run :: struct {
|
||||||
start: int,
|
start: int,
|
||||||
end: int,
|
end: int,
|
||||||
@@ -609,9 +555,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// If we were in a run, this is where we reset it.
|
||||||
If we were in a run, this is where we reset it.
|
|
||||||
*/
|
|
||||||
if val != 0 {
|
if val != 0 {
|
||||||
run = {-1, -1}
|
run = {-1, -1}
|
||||||
}
|
}
|
||||||
@@ -621,9 +565,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) ->
|
|||||||
|
|
||||||
for val, i in addr {
|
for val, i in addr {
|
||||||
if best.start == i || best.end == i {
|
if best.start == i || best.end == i {
|
||||||
/*
|
// For the left and right side of the best zero run, print a `:`.
|
||||||
For the left and right side of the best zero run, print a `:`.
|
|
||||||
*/
|
|
||||||
fmt.sbprint(&b, ":")
|
fmt.sbprint(&b, ":")
|
||||||
} else if i < best.start {
|
} else if i < best.start {
|
||||||
/*
|
/*
|
||||||
@@ -710,9 +652,7 @@ DEFAULT_DIGIT_BASES :: Digit_Parse_Bases{.Dec, .Oct, .Hex}
|
|||||||
Numbers will otherwise be considered to be in base 10.
|
Numbers will otherwise be considered to be in base 10.
|
||||||
*/
|
*/
|
||||||
parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := DEFAULT_DIGIT_BASES) -> (value: u64, bytes_consumed: int, ok: bool) {
|
parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := DEFAULT_DIGIT_BASES) -> (value: u64, bytes_consumed: int, ok: bool) {
|
||||||
/*
|
// Default to base 10
|
||||||
Default to base 10
|
|
||||||
*/
|
|
||||||
base := u64(10)
|
base := u64(10)
|
||||||
input := input
|
input := input
|
||||||
|
|
||||||
@@ -732,9 +672,7 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D
|
|||||||
if bases != {.IPv6} { return } // Must be used on its own.
|
if bases != {.IPv6} { return } // Must be used on its own.
|
||||||
base = 16
|
base = 16
|
||||||
} else {
|
} else {
|
||||||
/*
|
// Scan for and consume prefix, if applicable.
|
||||||
Scan for and consume prefix, if applicable.
|
|
||||||
*/
|
|
||||||
if len(input) >= 2 && input[0] == '0' {
|
if len(input) >= 2 && input[0] == '0' {
|
||||||
if .Hex in bases && (input[1] == 'x' || input[1] == 'X') {
|
if .Hex in bases && (input[1] == 'x' || input[1] == 'X') {
|
||||||
base = 16
|
base = 16
|
||||||
@@ -759,9 +697,7 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D
|
|||||||
digit_bytes += 1
|
digit_bytes += 1
|
||||||
|
|
||||||
if base == 8 {
|
if base == 8 {
|
||||||
/*
|
// Out of range for octal numbers.
|
||||||
Out of range for octal numbers.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, false
|
return value, digit_bytes + prefix_bytes, false
|
||||||
}
|
}
|
||||||
value = value * base + u64(ch - '0')
|
value = value * base + u64(ch - '0')
|
||||||
@@ -770,9 +706,7 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D
|
|||||||
digit_bytes += 1
|
digit_bytes += 1
|
||||||
|
|
||||||
if base == 8 || base == 10 {
|
if base == 8 || base == 10 {
|
||||||
/*
|
// Out of range for octal and decimal numbers.
|
||||||
Out of range for octal and decimal numbers.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, false
|
return value, digit_bytes + prefix_bytes, false
|
||||||
}
|
}
|
||||||
value = value * base + (u64(ch - 'a') + 10)
|
value = value * base + (u64(ch - 'a') + 10)
|
||||||
@@ -781,9 +715,7 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D
|
|||||||
digit_bytes += 1
|
digit_bytes += 1
|
||||||
|
|
||||||
if base == 8 || base == 10 {
|
if base == 8 || base == 10 {
|
||||||
/*
|
// Out of range for octal and decimal numbers.
|
||||||
Out of range for octal and decimal numbers.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, false
|
return value, digit_bytes + prefix_bytes, false
|
||||||
}
|
}
|
||||||
value = value * base + (u64(ch - 'A') + 10)
|
value = value * base + (u64(ch - 'A') + 10)
|
||||||
@@ -797,22 +729,16 @@ parse_ip_component :: proc(input: string, max_value := u64(max(u32)), bases := D
|
|||||||
break parse_loop
|
break parse_loop
|
||||||
|
|
||||||
case:
|
case:
|
||||||
/*
|
// Invalid character encountered.
|
||||||
Invalid character encountered.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, false
|
return value, digit_bytes + prefix_bytes, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if value > max_value {
|
if value > max_value {
|
||||||
/*
|
// Out-of-range number.
|
||||||
Out-of-range number.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, false
|
return value, digit_bytes + prefix_bytes, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// If we consumed at least 1 digit byte, `value` *should* continue a valid number in an appropriate base in the allowable range.
|
||||||
If we consumed at least 1 digit byte, `value` *should* continue a valid number in an appropriate base in the allowable range.
|
|
||||||
*/
|
|
||||||
return value, digit_bytes + prefix_bytes, digit_bytes >= 1
|
return value, digit_bytes + prefix_bytes, digit_bytes >= 1
|
||||||
}
|
}
|
||||||
@@ -84,8 +84,7 @@ sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint)
|
|||||||
port = port,
|
port = port,
|
||||||
}
|
}
|
||||||
case:
|
case:
|
||||||
//panic("native_addr is neither IP4 or IP6 address")
|
panic("native_addr is neither IP4 or IP6 address")
|
||||||
return {}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-49
@@ -22,10 +22,8 @@ package net
|
|||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TUNEABLES
|
TUNEABLES - See also top of `dns.odin` for DNS configuration.
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Determines the default value for whether dial_tcp() and accept_tcp() will set TCP_NODELAY on the new
|
Determines the default value for whether dial_tcp() and accept_tcp() will set TCP_NODELAY on the new
|
||||||
socket, and the client socket, respectively.
|
socket, and the client socket, respectively.
|
||||||
This can also be set on a per-socket basis using the 'options' optional parameter to those procedures.
|
This can also be set on a per-socket basis using the 'options' optional parameter to those procedures.
|
||||||
@@ -44,25 +42,17 @@ import "core:runtime"
|
|||||||
However, you can avoid this by buffering things up yourself if you wish to send a lot of
|
However, you can avoid this by buffering things up yourself if you wish to send a lot of
|
||||||
short data chunks, when TCP_NODELAY is enabled on that socket.
|
short data chunks, when TCP_NODELAY is enabled on that socket.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ODIN_NET_TCP_NODELAY_DEFAULT :: #config(ODIN_NET_TCP_NODELAY_DEFAULT, true)
|
ODIN_NET_TCP_NODELAY_DEFAULT :: #config(ODIN_NET_TCP_NODELAY_DEFAULT, true)
|
||||||
|
|
||||||
/*
|
// COMMON DEFINITIONS
|
||||||
See also top of `dns.odin` for DNS configuration.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
COMMON DEFINITIONS
|
|
||||||
*/
|
|
||||||
|
|
||||||
Maybe :: runtime.Maybe
|
Maybe :: runtime.Maybe
|
||||||
|
|
||||||
General_Error :: enum {
|
General_Error :: enum {
|
||||||
Unable_To_Enumerate_Network_Interfaces = 1,
|
Unable_To_Enumerate_Network_Interfaces = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// `Platform_Error` is used to wrap errors returned by the different platforms that don't fit a common error.
|
||||||
`Platform_Error` is used to wrap errors returned by the different platforms that defy translation into a common error.
|
|
||||||
*/
|
|
||||||
Platform_Error :: enum u32 {}
|
Platform_Error :: enum u32 {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -93,7 +83,6 @@ Network_Error :: union {
|
|||||||
DNS_Error,
|
DNS_Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Resolve_Error :: enum {
|
Resolve_Error :: enum {
|
||||||
Unable_To_Resolve = 1,
|
Unable_To_Resolve = 1,
|
||||||
}
|
}
|
||||||
@@ -107,10 +96,7 @@ DNS_Error :: enum {
|
|||||||
System_Error,
|
System_Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// SOCKET OPTIONS & DEFINITIONS
|
||||||
SOCKET OPTIONS & DEFINITIONS
|
|
||||||
*/
|
|
||||||
|
|
||||||
TCP_Options :: struct {
|
TCP_Options :: struct {
|
||||||
no_delay: bool,
|
no_delay: bool,
|
||||||
}
|
}
|
||||||
@@ -195,9 +181,7 @@ Network_Interface :: struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Empty bit set is unknown state.
|
||||||
Empty bit set is unknown state.
|
|
||||||
*/
|
|
||||||
Link_States :: enum u32 {
|
Link_States :: enum u32 {
|
||||||
Up = 1,
|
Up = 1,
|
||||||
Down = 2,
|
Down = 2,
|
||||||
@@ -261,18 +245,14 @@ Address_Duplication :: enum i32 {
|
|||||||
Preferred = 4,
|
Preferred = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// DNS DEFINITIONS
|
||||||
DNS DEFINITIONS
|
|
||||||
*/
|
|
||||||
|
|
||||||
DNS_Configuration :: struct {
|
DNS_Configuration :: struct {
|
||||||
/*
|
// Configuration files.
|
||||||
Configuration files.
|
|
||||||
*/
|
|
||||||
resolv_conf: string,
|
resolv_conf: string,
|
||||||
hosts_file: string,
|
hosts_file: string,
|
||||||
|
|
||||||
// TODO: Allow loading these up with `reload_configuration()` call or the like so we don't have to do it each call.
|
// TODO: Allow loading these up with `reload_configuration()` call or the like,
|
||||||
|
// so we don't have to do it each call.
|
||||||
name_servers: []Endpoint,
|
name_servers: []Endpoint,
|
||||||
hosts_file_entries: []DNS_Record,
|
hosts_file_entries: []DNS_Record,
|
||||||
}
|
}
|
||||||
@@ -295,25 +275,19 @@ DNS_Record_Type :: enum u16 {
|
|||||||
SRV = DNS_TYPE_SRV,
|
SRV = DNS_TYPE_SRV,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Base DNS Record. All DNS responses will carry a hostname and TTL (time to live) field.
|
||||||
Base DNS Record. All DNS responses will carry a hostname and TTL (time to live) field.
|
|
||||||
*/
|
|
||||||
DNS_Record_Base :: struct {
|
DNS_Record_Base :: struct {
|
||||||
record_name: string,
|
record_name: string,
|
||||||
ttl_seconds: u32, // The time in seconds that this service will take to update, after the record is updated.
|
ttl_seconds: u32, // The time in seconds that this service will take to update, after the record is updated.
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// An IP4 address that the domain name maps to. There can be any number of these.
|
||||||
An IP4 address that the domain name maps to. There can be any number of these.
|
|
||||||
*/
|
|
||||||
DNS_Record_IP4 :: struct {
|
DNS_Record_IP4 :: struct {
|
||||||
using base: DNS_Record_Base,
|
using base: DNS_Record_Base,
|
||||||
address: IP4_Address,
|
address: IP4_Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// An IPv6 address that the domain name maps to. There can be any number of these.
|
||||||
An IPv6 address that the domain name maps to. There can be any number of these.
|
|
||||||
*/
|
|
||||||
DNS_Record_IP6 :: struct {
|
DNS_Record_IP6 :: struct {
|
||||||
using base: DNS_Record_Base,
|
using base: DNS_Record_Base,
|
||||||
address: IP6_Address,
|
address: IP6_Address,
|
||||||
@@ -356,15 +330,17 @@ DNS_Record_MX :: struct {
|
|||||||
preference: int,
|
preference: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
// An endpoint for a service that is available through the domain name.
|
/*
|
||||||
// This is the way to discover the services that a domain name provides.
|
An endpoint for a service that is available through the domain name.
|
||||||
//
|
This is the way to discover the services that a domain name provides.
|
||||||
// Clients MUST attempt to contact the host with the lowest priority that they can reach.
|
|
||||||
// If two hosts have the same priority, they should be contacted in the order according to their weight.
|
Clients MUST attempt to contact the host with the lowest priority that they can reach.
|
||||||
// Hosts with larger weights should have a proportionally higher chance of being contacted by clients.
|
If two hosts have the same priority, they should be contacted in the order according to their weight.
|
||||||
// A weight of zero indicates a very low weight, or, when there is no choice (to reduce visual noise).
|
Hosts with larger weights should have a proportionally higher chance of being contacted by clients.
|
||||||
//
|
A weight of zero indicates a very low weight, or, when there is no choice (to reduce visual noise).
|
||||||
// The host may be "." to indicate that it is "decidedly not available" on this domain.
|
|
||||||
|
The host may be "." to indicate that it is "decidedly not available" on this domain.
|
||||||
|
*/
|
||||||
DNS_Record_SRV :: struct {
|
DNS_Record_SRV :: struct {
|
||||||
// base contains the full name of this record.
|
// base contains the full name of this record.
|
||||||
// e.g: _sip._tls.example.com
|
// e.g: _sip._tls.example.com
|
||||||
|
|||||||
+5
-14
@@ -54,13 +54,9 @@ destroy_dns_configuration :: proc() {
|
|||||||
|
|
||||||
dns_configuration := DEFAULT_DNS_CONFIGURATION
|
dns_configuration := DEFAULT_DNS_CONFIGURATION
|
||||||
|
|
||||||
/*
|
// Always allocates for consistency.
|
||||||
Always allocates for consistency.
|
|
||||||
*/
|
|
||||||
replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) {
|
replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) {
|
||||||
/*
|
// Nothing to replace. Return a clone of the original.
|
||||||
Nothing to replace. Return a clone of the original.
|
|
||||||
*/
|
|
||||||
if strings.count(path, "%") != 2 {
|
if strings.count(path, "%") != 2 {
|
||||||
return strings.clone(path), true
|
return strings.clone(path), true
|
||||||
}
|
}
|
||||||
@@ -76,7 +72,6 @@ replace_environment_path :: proc(path: string, allocator := context.allocator) -
|
|||||||
defer delete(env_val)
|
defer delete(env_val)
|
||||||
|
|
||||||
res, _ = strings.replace(path, path[left - 1: right + 1], env_val, 1)
|
res, _ = strings.replace(path, path[left - 1: right + 1], env_val, 1)
|
||||||
|
|
||||||
return res, true
|
return res, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,9 +166,7 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net
|
|||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// `get_dns_records` uses OS-specific methods to query DNS records.
|
||||||
`get_dns_records` uses OS-specific methods to query DNS records.
|
|
||||||
*/
|
|
||||||
when ODIN_OS == .Windows {
|
when ODIN_OS == .Windows {
|
||||||
get_dns_records_from_os :: get_dns_records_windows
|
get_dns_records_from_os :: get_dns_records_windows
|
||||||
} else when ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
} else when ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
|
||||||
@@ -434,9 +427,7 @@ load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> (
|
|||||||
return _hosts[:], true
|
return _hosts[:], true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// www.google.com -> 3www6google3com0
|
||||||
www.google.com -> 3www6google3com0
|
|
||||||
*/
|
|
||||||
encode_hostname :: proc(b: ^strings.Builder, hostname: string, allocator := context.allocator) -> (ok: bool) {
|
encode_hostname :: proc(b: ^strings.Builder, hostname: string, allocator := context.allocator) -> (ok: bool) {
|
||||||
_hostname := hostname
|
_hostname := hostname
|
||||||
for section in strings.split_iterator(&_hostname, ".") {
|
for section in strings.split_iterator(&_hostname, ".") {
|
||||||
@@ -861,4 +852,4 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
return _records[:], true
|
return _records[:], true
|
||||||
}
|
}
|
||||||
@@ -80,4 +80,4 @@ get_dns_records_unix :: proc(hostname: string, type: DNS_Record_Type, allocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:])
|
return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:])
|
||||||
}
|
}
|
||||||
+11
-10
@@ -22,14 +22,16 @@ import "core:mem"
|
|||||||
|
|
||||||
import win "core:sys/windows"
|
import win "core:sys/windows"
|
||||||
|
|
||||||
// Performs a recursive DNS query for records of a particular type for the hostname.
|
/*
|
||||||
//
|
Performs a recursive DNS query for records of a particular type for the hostname.
|
||||||
// NOTE: This procedure instructs the DNS resolver to recursively perform CNAME requests on our behalf,
|
|
||||||
// meaning that DNS queries for a hostname will resolve through CNAME records until an
|
NOTE: This procedure instructs the DNS resolver to recursively perform CNAME requests on our behalf,
|
||||||
// IP address is reached.
|
meaning that DNS queries for a hostname will resolve through CNAME records until an
|
||||||
//
|
IP address is reached.
|
||||||
// WARNING: This procedure allocates memory for each record returned; deleting just the returned slice is not enough!
|
|
||||||
// See `destroy_records`.
|
WARNING: This procedure allocates memory for each record returned; deleting just the returned slice is not enough!
|
||||||
|
See `destroy_records`.
|
||||||
|
*/
|
||||||
get_dns_records_windows :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
|
get_dns_records_windows :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
@@ -55,7 +57,6 @@ get_dns_records_windows :: proc(hostname: string, type: DNS_Record_Type, allocat
|
|||||||
count += 1
|
count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
recs := make([dynamic]DNS_Record, 0, count)
|
recs := make([dynamic]DNS_Record, 0, count)
|
||||||
if recs == nil do return nil, .System_Error // return no results if OOM.
|
if recs == nil do return nil, .System_Error // return no results if OOM.
|
||||||
|
|
||||||
@@ -163,4 +164,4 @@ get_dns_records_windows :: proc(hostname: string, type: DNS_Record_Type, allocat
|
|||||||
|
|
||||||
records = recs[:]
|
records = recs[:]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,5 @@
|
|||||||
this and panic to avoid temp allocations prematurely overwriting data and garbling results,
|
this and panic to avoid temp allocations prematurely overwriting data and garbling results,
|
||||||
or worse. This means that should you replace the temp allocator with an insufficient one,
|
or worse. This means that should you replace the temp allocator with an insufficient one,
|
||||||
we'll do our best to loudly complain the first time you try it.
|
we'll do our best to loudly complain the first time you try it.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package net
|
package net
|
||||||
@@ -16,10 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package net
|
package net
|
||||||
|
|
||||||
//
|
|
||||||
// TODO(tetra): Bluetooth, Raw
|
// TODO(tetra): Bluetooth, Raw
|
||||||
//
|
|
||||||
|
|
||||||
any_socket_to_socket :: proc(any_socket: Any_Socket) -> Socket {
|
any_socket_to_socket :: proc(any_socket: Any_Socket) -> Socket {
|
||||||
switch s in any_socket {
|
switch s in any_socket {
|
||||||
case TCP_Socket: return Socket(s)
|
case TCP_Socket: return Socket(s)
|
||||||
|
|||||||
Reference in New Issue
Block a user