|
@@ -19,14 +19,106 @@ package net
|
|
|
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+import "core:os"
|
|
|
|
+import "core:strings"
|
|
|
|
+
|
|
@(private)
|
|
@(private)
|
|
_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
|
|
_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
|
|
context.allocator = allocator
|
|
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()
|
|
|
|
-}
|
|
|
|
|
|
+ /*
|
|
|
|
+ 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[:], {}
|
|
|
|
+}
|