Implement new sys/unix package

This commit is contained in:
flysand7
2023-10-18 01:57:26 +11:00
parent 8e4bdcfb98
commit 4d65b1ab9c
25 changed files with 6683 additions and 755 deletions

View File

@@ -21,120 +21,124 @@ package net
TODO: When we have raw sockets, split off into its own file for Linux so we can use the NETLINK protocol and bypass libc.
*/
import "core:os"
import "core:strings"
//import "core:strings"
// TODO(flysand): regression
// NOTE(flysand): https://man7.org/linux/man-pages/man7/netlink.7.html
// apparently musl libc uses this to enumerate network interfaces
@(private)
_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
context.allocator = allocator
head: ^os.ifaddrs
// head: ^os.ifaddrs
if res := os._getifaddrs(&head); res < 0 {
return {}, .Unable_To_Enumerate_Network_Interfaces
}
// 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)
// /*
// 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)
// 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]
// /*
// 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
// address: Address
// netmask: Netmask
if ifaddr.address != nil {
switch int(ifaddr.address.sa_family) {
case os.AF_INET, os.AF_INET6:
address = _sockaddr_basic_to_endpoint(ifaddr.address).address
// if ifaddr.address != nil {
// switch int(ifaddr.address.sa_family) {
// case os.AF_INET, os.AF_INET6:
// address = _sockaddr_basic_to_endpoint(ifaddr.address).address
case os.AF_PACKET:
/*
For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a
32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count
is truncated beyond usefulness.
// case os.AF_PACKET:
// /*
// For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a
// 32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count
// is truncated beyond usefulness.
We're not going to retrieve stats now. Instead this serves as a reminder to use
the NETLINK protocol for this purpose.
// We're not going to retrieve stats now. Instead this serves as a reminder to use
// the NETLINK protocol for this purpose.
But in case you were curious:
stats := transmute(^os.rtnl_link_stats)ifaddr.data
fmt.println(stats)
*/
case:
}
}
// But in case you were curious:
// stats := transmute(^os.rtnl_link_stats)ifaddr.data
// fmt.println(stats)
// */
// case:
// }
// }
if ifaddr.netmask != nil {
switch int(ifaddr.netmask.sa_family) {
case os.AF_INET, os.AF_INET6:
netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address)
case:
}
}
// if ifaddr.netmask != nil {
// switch int(ifaddr.netmask.sa_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.sa_family) {
case os.AF_INET, os.AF_INET6:
broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address
append(&iface.multicast, broadcast)
case:
}
}
// if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags {
// switch int(ifaddr.broadcast_or_dest.sa_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)
}
// 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{}
// /*
// TODO: Refine this based on the type of adapter.
// */
// state := Link_State{}
if .UP in ifaddr.flags {
state |= {.Up}
}
// if .UP in ifaddr.flags {
// state |= {.Up}
// }
if .DORMANT in ifaddr.flags {
state |= {.Dormant}
}
// if .DORMANT in ifaddr.flags {
// state |= {.Dormant}
// }
if .LOOPBACK in ifaddr.flags {
state |= {.Loopback}
}
iface.link.state = state
}
// if .LOOPBACK in ifaddr.flags {
// state |= {.Loopback}
// }
// iface.link.state = state
// }
/*
Free the OS structures.
*/
os._freeifaddrs(head)
// /*
// 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[:], {}
// /*
// 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[:], {}
return nil, {}
}