diff options
| author | simon <simon@xengames.com> | 2023-09-30 20:09:29 +0100 |
|---|---|---|
| committer | simon <simon@xengames.com> | 2023-09-30 20:09:29 +0100 |
| commit | 98f9f7d42e9a487ea4198ae237465133c6bae120 (patch) | |
| tree | 71b7f1f4fe3bf015a927667d505301484a772c6c /core/net/interface_darwin.odin | |
| parent | 3e0fd6368225ddfa6820be72d194b7cd1daf52dc (diff) | |
darwin _enumerate_interfaces
Diffstat (limited to 'core/net/interface_darwin.odin')
| -rw-r--r-- | core/net/interface_darwin.odin | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/core/net/interface_darwin.odin b/core/net/interface_darwin.odin index 90d996a4a..54b2a0b3b 100644 --- a/core/net/interface_darwin.odin +++ b/core/net/interface_darwin.odin @@ -19,14 +19,106 @@ package net */ +import "core:os" +import "core:strings" + @(private) _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { context.allocator = allocator + head: ^os.ifaddrs + + if res := os._getifaddrs(&head); res < 0 { + return {}, .Unable_To_Enumerate_Network_Interfaces + } + + /* + Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct. + We're going to have to iterate over a list and coalesce information as we go. + */ + ifaces: map[string]^Network_Interface + defer delete(ifaces) + + for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next { + adapter_name := string(ifaddr.name) + + /* + Check if we have seen this interface name before so we can reuse the `Network_Interface`. + Else, create a new one. + */ + if adapter_name not_in ifaces { + ifaces[adapter_name] = new(Network_Interface) + ifaces[adapter_name].adapter_name = strings.clone(adapter_name) + } + iface := ifaces[adapter_name] + + address: Address + netmask: Netmask + + if ifaddr.address != nil { + switch int(ifaddr.address.family) { + case os.AF_INET, os.AF_INET6: + address = _sockaddr_basic_to_endpoint(ifaddr.address).address + case: + } + } + + if ifaddr.netmask != nil { + switch int(ifaddr.netmask.family) { + case os.AF_INET, os.AF_INET6: + netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) + case: + } + } + + if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags { + switch int(ifaddr.broadcast_or_dest.family) { + case os.AF_INET, os.AF_INET6: + broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address + append(&iface.multicast, broadcast) + case: + } + } + + if address != nil { + lease := Lease{ + address = address, + netmask = netmask, + } + append(&iface.unicast, lease) + } + + /* + TODO: Refine this based on the type of adapter. + */ + state := Link_State{} + + if .UP in ifaddr.flags { + state |= {.Up} + } + + if .DORMANT in ifaddr.flags { + state |= {.Dormant} + } + + if .LOOPBACK in ifaddr.flags { + state |= {.Loopback} + } + iface.link.state = state + } - // TODO: Implement. Can probably use the (current) Linux implementation, - // which will itself be switched over to talking to the kernel via NETLINK protocol - // once we have raw sockets. + /* + Free the OS structures. + */ + os._freeifaddrs(head) - unimplemented() -}
\ No newline at end of file + /* + Turn the map into a slice to return. + */ + _interfaces := make([dynamic]Network_Interface, 0, allocator) + for _, iface in ifaces { + append(&_interfaces, iface^) + free(iface) + } + return _interfaces[:], {} +} |