aboutsummaryrefslogtreecommitdiff
path: root/core/net/interface_darwin.odin
diff options
context:
space:
mode:
authorsimon <simon@xengames.com>2023-09-30 20:09:29 +0100
committersimon <simon@xengames.com>2023-09-30 20:09:29 +0100
commit98f9f7d42e9a487ea4198ae237465133c6bae120 (patch)
tree71b7f1f4fe3bf015a927667d505301484a772c6c /core/net/interface_darwin.odin
parent3e0fd6368225ddfa6820be72d194b7cd1daf52dc (diff)
darwin _enumerate_interfaces
Diffstat (limited to 'core/net/interface_darwin.odin')
-rw-r--r--core/net/interface_darwin.odin102
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[:], {}
+}