mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
181 lines
5.8 KiB
Odin
181 lines
5.8 KiB
Odin
#+build windows
|
|
package net
|
|
|
|
/*
|
|
Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
|
|
For other protocols and their features, see subdirectories of this package.
|
|
*/
|
|
|
|
/*
|
|
Copyright 2022 Tetralux <tetraluxonpc@gmail.com>
|
|
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
|
|
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
|
Copyright 2024 Feoramund <rune@swevencraft.org>.
|
|
Made available under Odin's BSD-3 license.
|
|
|
|
List of contributors:
|
|
Tetralux: Initial implementation
|
|
Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
|
|
Jeroen van Rijn: Cross platform unification, code style, documentation
|
|
Feoramund: FreeBSD platform code
|
|
*/
|
|
|
|
import sys "core:sys/windows"
|
|
import strings "core:strings"
|
|
|
|
_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) {
|
|
context.allocator = allocator
|
|
|
|
buf: []u8
|
|
defer delete(buf)
|
|
|
|
buf_size: u32
|
|
res: u32
|
|
|
|
gaa: for _ in 1..=MAX_INTERFACE_ENUMERATION_TRIES {
|
|
res = sys.get_adapters_addresses(
|
|
.Unspecified, // Return both IPv4 and IPv6 adapters.
|
|
sys.GAA_Flags{
|
|
.Include_Prefix, // (XP SP1+) Return a list of IP address prefixes on this adapter. When this flag is set, IP address prefixes are returned for both IPv6 and IPv4 addresses.
|
|
.Include_Gateways, // (Vista+) Return the addresses of default gateways.
|
|
.Include_Tunnel_Binding_Order, // (Vista+) Return the adapter addresses sorted in tunnel binding order.
|
|
},
|
|
nil, // Reserved
|
|
(^sys.IP_Adapter_Addresses)(raw_data(buf)),
|
|
&buf_size,
|
|
)
|
|
|
|
switch res {
|
|
case 111: // ERROR_BUFFER_OVERFLOW:
|
|
delete(buf)
|
|
buf = make([]u8, buf_size)
|
|
case 0:
|
|
break gaa
|
|
case:
|
|
set_last_platform_error(i32(res))
|
|
return {}, .Unknown
|
|
}
|
|
}
|
|
|
|
if res != 0 {
|
|
return {}, .Unable_To_Enumerate_Network_Interfaces
|
|
}
|
|
|
|
_interfaces := make([dynamic]Network_Interface, 0, allocator)
|
|
for adapter := (^sys.IP_Adapter_Addresses)(raw_data(buf)); adapter != nil; adapter = adapter.Next {
|
|
friendly_name, err1 := sys.wstring_to_utf8(sys.wstring(adapter.FriendlyName), 256, allocator)
|
|
if err1 != nil { return {}, .Allocation_Failure }
|
|
|
|
description, err2 := sys.wstring_to_utf8(sys.wstring(adapter.Description), 256, allocator)
|
|
if err2 != nil { return {}, .Allocation_Failure }
|
|
|
|
dns_suffix, err3 := sys.wstring_to_utf8(sys.wstring(adapter.DnsSuffix), 256, allocator)
|
|
if err3 != nil { return {}, .Allocation_Failure }
|
|
|
|
interface := Network_Interface{
|
|
adapter_name = strings.clone(string(adapter.AdapterName)),
|
|
friendly_name = friendly_name,
|
|
description = description,
|
|
dns_suffix = dns_suffix,
|
|
|
|
mtu = adapter.MTU,
|
|
|
|
link = {
|
|
transmit_speed = adapter.TransmitLinkSpeed,
|
|
receive_speed = adapter.ReceiveLinkSpeed,
|
|
},
|
|
}
|
|
|
|
if adapter.PhysicalAddressLength > 0 && adapter.PhysicalAddressLength <= len(adapter.PhysicalAddress) {
|
|
interface.physical_address = physical_address_to_string(adapter.PhysicalAddress[:adapter.PhysicalAddressLength])
|
|
}
|
|
|
|
for u_addr := (^sys.IP_ADAPTER_UNICAST_ADDRESS_LH)(adapter.FirstUnicastAddress); u_addr != nil; u_addr = u_addr.Next {
|
|
win_addr := parse_socket_address(u_addr.Address)
|
|
|
|
lease := Lease{
|
|
address = win_addr.address,
|
|
origin = {
|
|
prefix = Prefix_Origin(u_addr.PrefixOrigin),
|
|
suffix = Suffix_Origin(u_addr.SuffixOrigin),
|
|
},
|
|
lifetime = {
|
|
valid = u_addr.ValidLifetime,
|
|
preferred = u_addr.PreferredLifetime,
|
|
lease = u_addr.LeaseLifetime,
|
|
},
|
|
address_duplication = Address_Duplication(u_addr.DadState),
|
|
}
|
|
append(&interface.unicast, lease)
|
|
}
|
|
|
|
for a_addr := (^sys.IP_ADAPTER_ANYCAST_ADDRESS_XP)(adapter.FirstAnycastAddress); a_addr != nil; a_addr = a_addr.Next {
|
|
addr := parse_socket_address(a_addr.Address)
|
|
append(&interface.anycast, addr.address)
|
|
}
|
|
|
|
for m_addr := (^sys.IP_ADAPTER_MULTICAST_ADDRESS_XP)(adapter.FirstMulticastAddress); m_addr != nil; m_addr = m_addr.Next {
|
|
addr := parse_socket_address(m_addr.Address)
|
|
append(&interface.multicast, addr.address)
|
|
}
|
|
|
|
for g_addr := (^sys.IP_ADAPTER_GATEWAY_ADDRESS_LH)(adapter.FirstGatewayAddress); g_addr != nil; g_addr = g_addr.Next {
|
|
addr := parse_socket_address(g_addr.Address)
|
|
append(&interface.gateways, addr.address)
|
|
}
|
|
|
|
interface.dhcp_v4 = parse_socket_address(adapter.Dhcpv4Server).address
|
|
interface.dhcp_v6 = parse_socket_address(adapter.Dhcpv6Server).address
|
|
|
|
switch adapter.OperStatus {
|
|
case .Up: interface.link.state = {.Up}
|
|
case .Down: interface.link.state = {.Down}
|
|
case .Testing: interface.link.state = {.Testing}
|
|
case .Dormant: interface.link.state = {.Dormant}
|
|
case .NotPresent: interface.link.state = {.Not_Present}
|
|
case .LowerLayerDown: interface.link.state = {.Lower_Layer_Down}
|
|
case .Unknown: fallthrough
|
|
case: interface.link.state = {}
|
|
}
|
|
|
|
interface.tunnel_type = Tunnel_Type(adapter.TunnelType)
|
|
|
|
append(&_interfaces, interface)
|
|
}
|
|
|
|
return _interfaces[:], {}
|
|
}
|
|
|
|
/*
|
|
Interpret SOCKET_ADDRESS as an Address
|
|
*/
|
|
parse_socket_address :: proc(addr_in: sys.SOCKET_ADDRESS) -> (addr: Endpoint) {
|
|
if addr_in.lpSockaddr == nil {
|
|
return // Empty or invalid address type
|
|
}
|
|
|
|
sock := addr_in.lpSockaddr^
|
|
|
|
switch sock.sa_family {
|
|
case u16(sys.AF_INET):
|
|
win_addr := cast(^sys.sockaddr_in)addr_in.lpSockaddr
|
|
port := int(win_addr.sin_port)
|
|
return Endpoint {
|
|
address = IP4_Address(transmute([4]byte)win_addr.sin_addr),
|
|
port = port,
|
|
}
|
|
|
|
case u16(sys.AF_INET6):
|
|
win_addr := cast(^sys.sockaddr_in6)addr_in.lpSockaddr
|
|
port := int(win_addr.sin6_port)
|
|
return Endpoint {
|
|
address = IP6_Address(transmute([8]u16be)win_addr.sin6_addr),
|
|
port = port,
|
|
}
|
|
|
|
|
|
case: return // Empty or invalid address type
|
|
}
|
|
unreachable()
|
|
}
|