mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Merge pull request #2833 from simonwashere/darwin_net_interface
darwin enumerate_interfaces
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
// TODO: Implement. Can probably use the (current) Linux implementation,
|
if res := os._getifaddrs(&head); res < 0 {
|
||||||
// which will itself be switched over to talking to the kernel via NETLINK protocol
|
return {}, .Unable_To_Enumerate_Network_Interfaces
|
||||||
// once we have raw sockets.
|
}
|
||||||
|
|
||||||
unimplemented()
|
/*
|
||||||
}
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Free the OS structures.
|
||||||
|
*/
|
||||||
|
os._freeifaddrs(head)
|
||||||
|
|
||||||
|
/*
|
||||||
|
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[:], {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import "core:os"
|
|||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
Socket_Option :: enum c.int {
|
Socket_Option :: enum c.int {
|
||||||
|
Broadcast = c.int(os.SO_BROADCAST),
|
||||||
Reuse_Address = c.int(os.SO_REUSEADDR),
|
Reuse_Address = c.int(os.SO_REUSEADDR),
|
||||||
Keep_Alive = c.int(os.SO_KEEPALIVE),
|
Keep_Alive = c.int(os.SO_KEEPALIVE),
|
||||||
Out_Of_Bounds_Data_Inline = c.int(os.SO_OOBINLINE),
|
Out_Of_Bounds_Data_Inline = c.int(os.SO_OOBINLINE),
|
||||||
@@ -238,6 +239,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
|
|||||||
|
|
||||||
switch option {
|
switch option {
|
||||||
case
|
case
|
||||||
|
.Broadcast,
|
||||||
.Reuse_Address,
|
.Reuse_Address,
|
||||||
.Keep_Alive,
|
.Keep_Alive,
|
||||||
.Out_Of_Bounds_Data_Inline,
|
.Out_Of_Bounds_Data_Inline,
|
||||||
@@ -369,3 +371,26 @@ _sockaddr_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endp
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint) {
|
||||||
|
switch u16(native_addr.family) {
|
||||||
|
case u16(os.AF_INET):
|
||||||
|
addr := cast(^os.sockaddr_in) native_addr
|
||||||
|
port := int(addr.sin_port)
|
||||||
|
ep = Endpoint {
|
||||||
|
address = IP4_Address(transmute([4]byte) addr.sin_addr),
|
||||||
|
port = port,
|
||||||
|
}
|
||||||
|
case u16(os.AF_INET6):
|
||||||
|
addr := cast(^os.sockaddr_in6) native_addr
|
||||||
|
port := int(addr.sin6_port)
|
||||||
|
ep = Endpoint {
|
||||||
|
address = IP6_Address(transmute([8]u16be) addr.sin6_addr),
|
||||||
|
port = port,
|
||||||
|
}
|
||||||
|
case:
|
||||||
|
panic("native_addr is neither IP4 or IP6 address")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -354,6 +354,30 @@ in6_addr :: struct #packed {
|
|||||||
s6_addr: [16]u8,
|
s6_addr: [16]u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SIOCGIFFLAG :: enum c.int {
|
||||||
|
UP = 0, /* Interface is up. */
|
||||||
|
BROADCAST = 1, /* Broadcast address valid. */
|
||||||
|
DEBUG = 2, /* Turn on debugging. */
|
||||||
|
LOOPBACK = 3, /* Is a loopback net. */
|
||||||
|
POINT_TO_POINT = 4, /* Interface is point-to-point link. */
|
||||||
|
NO_TRAILERS = 5, /* Avoid use of trailers. */
|
||||||
|
RUNNING = 6, /* Resources allocated. */
|
||||||
|
NOARP = 7, /* No address resolution protocol. */
|
||||||
|
PROMISC = 8, /* Receive all packets. */
|
||||||
|
ALL_MULTI = 9, /* Receive all multicast packets. Unimplemented. */
|
||||||
|
}
|
||||||
|
SIOCGIFFLAGS :: bit_set[SIOCGIFFLAG; c.int]
|
||||||
|
|
||||||
|
ifaddrs :: struct {
|
||||||
|
next: ^ifaddrs,
|
||||||
|
name: cstring,
|
||||||
|
flags: SIOCGIFFLAGS,
|
||||||
|
address: ^SOCKADDR,
|
||||||
|
netmask: ^SOCKADDR,
|
||||||
|
broadcast_or_dest: ^SOCKADDR, // Broadcast or Point-to-Point address
|
||||||
|
data: rawptr, // Address-specific data.
|
||||||
|
}
|
||||||
|
|
||||||
Timeval :: struct {
|
Timeval :: struct {
|
||||||
seconds: i64,
|
seconds: i64,
|
||||||
microseconds: int,
|
microseconds: int,
|
||||||
@@ -474,6 +498,9 @@ foreign libc {
|
|||||||
@(link_name="send") _unix_send :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
|
@(link_name="send") _unix_send :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t ---
|
||||||
@(link_name="shutdown") _unix_shutdown :: proc(socket: int, how: int) -> int ---
|
@(link_name="shutdown") _unix_shutdown :: proc(socket: int, how: int) -> int ---
|
||||||
|
|
||||||
|
@(link_name="getifaddrs") _getifaddrs :: proc(ifap: ^^ifaddrs) -> (c.int) ---
|
||||||
|
@(link_name="freeifaddrs") _freeifaddrs :: proc(ifa: ^ifaddrs) ---
|
||||||
|
|
||||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user