interface_linux.odin 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package net
  2. //+build linux
  3. /*
  4. Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
  5. For other protocols and their features, see subdirectories of this package.
  6. */
  7. /*
  8. Copyright 2022 Tetralux <[email protected]>
  9. Copyright 2022 Colin Davidson <[email protected]>
  10. Copyright 2022 Jeroen van Rijn <[email protected]>.
  11. Made available under Odin's BSD-3 license.
  12. List of contributors:
  13. Tetralux: Initial implementation
  14. Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
  15. Jeroen van Rijn: Cross platform unification, code style, documentation
  16. This file uses `getifaddrs` libc call to enumerate interfaces.
  17. TODO: When we have raw sockets, split off into its own file for Linux so we can use the NETLINK protocol and bypass libc.
  18. */
  19. import "core:os"
  20. import "core:strings"
  21. @(private)
  22. _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
  23. context.allocator = allocator
  24. head: ^os.ifaddrs
  25. if res := os._getifaddrs(&head); res < 0 {
  26. return {}, .Unable_To_Enumerate_Network_Interfaces
  27. }
  28. /*
  29. Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct.
  30. We're going to have to iterate over a list and coalesce information as we go.
  31. */
  32. ifaces: map[string]^Network_Interface
  33. defer delete(ifaces)
  34. for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next {
  35. adapter_name := string(ifaddr.name)
  36. /*
  37. Check if we have seen this interface name before so we can reuse the `Network_Interface`.
  38. Else, create a new one.
  39. */
  40. if adapter_name not_in ifaces {
  41. ifaces[adapter_name] = new(Network_Interface)
  42. ifaces[adapter_name].adapter_name = strings.clone(adapter_name)
  43. }
  44. iface := ifaces[adapter_name]
  45. address: Address
  46. netmask: Netmask
  47. if ifaddr.address != nil {
  48. switch int(ifaddr.address.sa_family) {
  49. case os.AF_INET, os.AF_INET6:
  50. address = _sockaddr_basic_to_endpoint(ifaddr.address).address
  51. case os.AF_PACKET:
  52. /*
  53. For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a
  54. 32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count
  55. is truncated beyond usefulness.
  56. We're not going to retrieve stats now. Instead this serves as a reminder to use
  57. the NETLINK protocol for this purpose.
  58. But in case you were curious:
  59. stats := transmute(^os.rtnl_link_stats)ifaddr.data
  60. fmt.println(stats)
  61. */
  62. case:
  63. }
  64. }
  65. if ifaddr.netmask != nil {
  66. switch int(ifaddr.netmask.sa_family) {
  67. case os.AF_INET, os.AF_INET6:
  68. netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address)
  69. case:
  70. }
  71. }
  72. if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags {
  73. switch int(ifaddr.broadcast_or_dest.sa_family) {
  74. case os.AF_INET, os.AF_INET6:
  75. broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address
  76. append(&iface.multicast, broadcast)
  77. case:
  78. }
  79. }
  80. if address != nil {
  81. lease := Lease{
  82. address = address,
  83. netmask = netmask,
  84. }
  85. append(&iface.unicast, lease)
  86. }
  87. /*
  88. TODO: Refine this based on the type of adapter.
  89. */
  90. state := Link_State{}
  91. if .UP in ifaddr.flags {
  92. state |= {.Up}
  93. }
  94. if .DORMANT in ifaddr.flags {
  95. state |= {.Dormant}
  96. }
  97. if .LOOPBACK in ifaddr.flags {
  98. state |= {.Loopback}
  99. }
  100. iface.link.state = state
  101. }
  102. /*
  103. Free the OS structures.
  104. */
  105. os._freeifaddrs(head)
  106. /*
  107. Turn the map into a slice to return.
  108. */
  109. _interfaces := make([dynamic]Network_Interface, 0, allocator)
  110. for _, iface in ifaces {
  111. append(&_interfaces, iface^)
  112. free(iface)
  113. }
  114. return _interfaces[:], {}
  115. }