messense / if-addrs

Retrieve IP addresses for all interfaces. POSIX & Windows
BSD 3-Clause "New" or "Revised" License
22 stars 15 forks source link

Add blocking "wait for network interface changes" API #36

Closed mon closed 2 months ago

mon commented 3 months ago

Closes #35.

Has a timeout, so I think most use cases will get by with a check loop with a ~100ms timeout. However, I suspect there is a very narrow race condition possible in this approach while the notifier isn't active, a persistent struct might make more sense. Feedback appreciated.

Tested in Windows, as well as posix by adding/removing a dummy ethernet adapter in WSL2.

Not really sure if there's a good way to test inside CI.

mon commented 3 months ago

I hope you didn't get spammed with as many "Action failed" emails as I did 😅 I've tested the 1.52-compatible Posix impl as well, with both timeouts and no timeout.

Also looking for thoughts on whether it's a sane thing to disable support for macOS/iOS. I suspect there's probably some workaround for macOS, but iOS seems to defer to higher level Swift APIs for network availability and routing changes.

mon commented 3 months ago

After reading into it more, and at the risk of going to too much effort, I've found some deficiencies in my implementation

So, wait a while and I will make these changes, so there's a notifier struct with a wait function that returns io::Result<(ChangeType, Interface)>, where ChangeType is one of Added/Removed/Modified. I think this API will be much more ergonomic instead of needing the consumer to re-scan the interface list when something changes.

There is still an open question of whether I can populate the entire Interface struct with just the callback info, it might need to be just an Ipv4Addr or Ipv6Addr`, without the extended details.

mon commented 3 months ago

There'll be a few more pushes while I make the pipeline pass (since I can't build on osx) but the functionality is done and tested. On both Linux and Windows, the new example script will post notifications like:

Network interfaces changed: [
    Removed(
        Interface {
            name: "Ethernet",
            addr: V4(
                Ifv4Addr {
                    ip: 169.254.176.153,
                    netmask: 255.255.0.0,
                    prefixlen: 16,
                    broadcast: Some(
                        169.254.255.255,
                    ),
                },
            ),
            index: Some(
                22,
            ),
            adapter_name: "{AAE8AAB6-E8E3-45A5-BFC8-148C51A33CA8}",
        },
    ),
]
Network interfaces changed: [
    Added(
        Interface {
            name: "Ethernet",
            addr: V4(
                Ifv4Addr {
                    ip: 169.254.176.153,
                    netmask: 255.255.0.0,
                    prefixlen: 16,
                    broadcast: Some(
                        169.254.255.255,
                    ),
                },
            ),
            index: Some(
                22,
            ),
            adapter_name: "{AAE8AAB6-E8E3-45A5-BFC8-148C51A33CA8}",
        },
    ),
]

This to me feels like the most pleasing API to use, because almost all the time if I wanted a network change notification, I wanted to know what changed. If an interface has an ipv6 address, there are two removed/added messages, which matches how the full list works.