-
Notifications
You must be signed in to change notification settings - Fork 724
Add support for getifaddrs. #667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
One area I'm not quite sure about is the use of the nix specific This works for me, ATM. However, I think nix should better provide some way to represent those entries as well. |
src/ifaddrs.rs
Outdated
|
|
||
| use sys::socket::InetAddr; | ||
|
|
||
| #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to use a module here. Please use a single libc_bitflags instance and annotate each entry with a cfg attribute with their platform support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think Android supports all these as well (you can find this out easily by searching the libc repo).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Android doesn't support getifaddrs, that's probably why I excluded it. But you're right, the flags themselves are known to Android as well.
Maybe I should move InterfaceFlags to net/if_.rs, as those constants are defined in /usr/include/net/if.h and not in ifaddrs.h.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Android does, but libc does need to have it added.
I think it's fine having them here for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and: I used the module to reduce the amount of #[cfg()] conditions. I only used the module as I didn't find any good way to write this without repeating the conditions many times. I'm fine if you prefer the latter and changed things accordingly.
src/ifaddrs.rs
Outdated
| mod flags { | ||
| use libc; | ||
| libc_bitflags!( | ||
| /// Flags for `InterfaceAddress` entries returned by `getifaddrs` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That comment doesn't really provide any detail. Can you summarize what these values actually refer to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I duplicated the comment from the C header, now.
src/ifaddrs.rs
Outdated
|
|
||
| /// Describes a single address for an interface as returned by `getifaddrs`. | ||
| pub struct InterfaceAddress { | ||
| /// name of the interface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please capitalize the first character of all of these comments
src/ifaddrs.rs
Outdated
|
|
||
| /// Get interface addresses using libc's `getifaddrs` | ||
| /// | ||
| /// Note that the underlying implementation differs between implementations and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"the underlying implementation differs between implementations", that's pretty redundant. Can you rephrase this to be a little more clear?
src/ifaddrs.rs
Outdated
| /// } | ||
| /// } | ||
| /// ``` | ||
| #[cfg(not(any(target_os = "android", target_os = "haiku")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check that this isn't on Android? According to this it should.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the BSDs, too. They all have it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it's already defined in libc for all BSDs and Solaris as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked against rust's libc bindings, where src/unix/notbsd/android/mod.rs doesn't define getifaddrs (at least not in 3f903a1d from master as of Jul 11).
And: Huh? not(any(target_os = "android", target_os = "haiku")) already includes the BSDs.
src/sys/socket/addr.rs
Outdated
| /// Creates an `IpAddr` struct from libc's sockaddr. | ||
| /// | ||
| /// Note that this supports only IPv4 and IPv6 address families. | ||
| pub unsafe fn from_libc_sockaddr(addr: *mut libc::sockaddr) -> Option<InetAddr> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this unsafe and the other from_libc isn't? What's the reason for providing this API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I marked this one unsafe because it takes a raw pointer, which could point anywhere and yield a segfault. Again, this is not a public function, but only used internally (by that other InterfaceAddress::from_libc_ifaddrs function)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's not a public function, you should remove the pub
|
Thanks for the PR! There are a few things to address from this, notably a lack of tests besides the doctest that you added (which is great BTW). |
asomers
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the start of a pretty good API. I like that you used Iterator. In addition to the inline comments I made, I think that this could really use some better tests. I think you'll need to find a way to mock libc::getifaddrs and return some canned data. Does Rust have a mocking library yet?
src/sys/socket/addr.rs
Outdated
| } | ||
| } | ||
|
|
||
| /// Creates an `IpAddr` struct from libc's sockaddr. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/IpAddr/InetAddr/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, that's a last-minute typo. I didn't notice SockAddr before and currently think the getifaddrs API shoud rather use SockAddr.
src/sys/socket/addr.rs
Outdated
| None | ||
| } else { | ||
| let family = (*addr).sa_family as u32; | ||
| match mem::transmute::<u32, AddressFamily>(family) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using transmute here, it's better to provide an AddressFamily::from_u32 method.
src/ifaddrs.rs
Outdated
|
|
||
| use sys::socket::InetAddr; | ||
|
|
||
| #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nix doesn't support emscripten or fuschia, so you don't need to mention them here. It doesn't hurt, though, so you can leave it in if you want to. But why not enable it for the BSDs? They support all this stuff. If there are a few Linux specific flags, you can #[cfg()] individual flags instead of the whole thing.
src/ifaddrs.rs
Outdated
| target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", | ||
| target_os = "bitrig", target_os = "solaris"))] | ||
| { | ||
| addr.destination = unsafe { InetAddr::from_libc_sockaddr(info.ifa_dstaddr) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you forgot to set the broadcast for non-Linux platforms. You can do it the same way as on Linux. Depending on the flags, either ifa_dstaddr or ifa_broadaddr is set. The only difference is that on BSD, one of those is a macro for the other, whereas on Linux they're a union.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it's the same field for BSDs as well? I did it that way due to rust's libc bindings, where there is not ifa_broadaddr or ifa_broadcastaddr defined. I'll check the C headers from FreeBSD and adjust.
Given the BSDs also lack IFF_BROADCAST and IFF_POINTOPOINT, how do they distinguish between broadcast vs destination address?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just checked, and libc does define both IFF_BROADCAST and IFF_POINTOPOINT for most, if not all, platforms.
src/ifaddrs.rs
Outdated
| /// | ||
| /// # Example | ||
| /// ``` | ||
| /// match nix::ifaddrs::getifaddrs() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the example code, it would probably be clearer to use unwrap instead of a match block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An unwrap is very likely to fail due to the many address = None cases you'll encounter. It certainly makes cargo test fail on my box (Debian, with many AF_PACKET entries that cannot be represented ATM).
src/ifaddrs.rs
Outdated
| /// } | ||
| /// } | ||
| /// ``` | ||
| #[cfg(not(any(target_os = "android", target_os = "haiku")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the BSDs, too. They all have it.
src/ifaddrs.rs
Outdated
| #[cfg(not(any(target_os = "android", target_os = "haiku")))] | ||
| pub fn getifaddrs() -> Result<InterfaceAddressIterator> { | ||
| let mut addrs: *mut libc::ifaddrs = unsafe { mem::zeroed() }; | ||
| match unsafe { libc::getifaddrs(&mut addrs) } { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can probably simplify this logic to something like:
Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| Ok(InterfaceAddressIterator{base: addrs, next:addrs}))
|
Proper support for BSDs depends on corrections in libc, see rust-lang/libc#682. I'm currently in favour of disabling |
src/net/if_.rs
Outdated
| libc_bitflags!( | ||
| /// Standard interface flags, used by `getifaddrs` | ||
| pub flags InterfaceFlags: libc::c_int { | ||
| #[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The target_os list should be alphabetized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libc defines most of these constants for most platforms, not just Linux. You should expand the #[cfg()] directives appropriately.
|
I'd prefer to wait on this until rust-lang/libc#682 gets addressed assuming you're willing to take that on. Were you planning on doing that? |
Not really, sorry. The itch I was trying to scratch originally was |
|
@mwanner I'm fine with that as long as the code documents why we aren't exposing it everywhere and it references a bug filed with |
|
@posborne I think there are two options, one is deliver this just for Linux or the second is get someone working on resolving the |
|
Actually, the libc definition is only wrong for NetBSD. FreeBSD is fine. |
asomers
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is really close. You shouldn't need access to a BSD machine in order to fix the IFF_* definitions. It's simply a matter of going through libc and checking which operating systems define which flags.
src/ifaddrs.rs
Outdated
| target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd", | ||
| target_os = "bitrig", target_os = "solaris"))] | ||
| { | ||
| addr.destination = unsafe { InetAddr::from_libc_sockaddr(info.ifa_dstaddr) }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just checked, and libc does define both IFF_BROADCAST and IFF_POINTOPOINT for most, if not all, platforms.
src/net/if_.rs
Outdated
| libc_bitflags!( | ||
| /// Standard interface flags, used by `getifaddrs` | ||
| pub flags InterfaceFlags: libc::c_int { | ||
| #[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libc defines most of these constants for most platforms, not just Linux. You should expand the #[cfg()] directives appropriately.
src/sys/socket/addr.rs
Outdated
| /// Creates an `IpAddr` struct from libc's sockaddr. | ||
| /// | ||
| /// Note that this supports only IPv4 and IPv6 address families. | ||
| pub unsafe fn from_libc_sockaddr(addr: *mut libc::sockaddr) -> Option<InetAddr> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's not a public function, you should remove the pub
|
Thanks for the heads up, @asomers. Looks like I made an attempt to update this PR to match current libc sources. |
|
@asomers wrote:
Given |
|
I can take a look at Android support as well. I happen to need to target Android aarch64 myself and bionic has had getifaddrs for some time but the libc bindings appear to be missing that on the rust side (explicitly). No need to gate this on that work though, as it will definitely require libc changes. |
|
@posborne It looks like |
Susurrus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good! I just noticed a few style/convention issues that would be nice to cleanup before merging. Good work!
src/ifaddrs.rs
Outdated
| /// } | ||
| /// ``` | ||
| pub fn getifaddrs() -> Result<InterfaceAddressIterator> { | ||
| let mut addrs: *mut libc::ifaddrs = unsafe { mem::zeroed() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this not be mem::uninitialized() instead?
| libc_bitflags!( | ||
| /// Standard interface flags, used by `getifaddrs` | ||
| pub struct InterfaceFlags: libc::c_int { | ||
| IFF_UP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add doccomments for each variant.
src/net/if_.rs
Outdated
| IFF_DEBUG; | ||
| IFF_LOOPBACK; | ||
| IFF_POINTOPOINT; | ||
| #[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "haiku")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please alphabetize all OSes listed in #[cfgs. Additionally please use a whitelist instead of a blacklist for targets for consistency.
| } | ||
|
|
||
| impl AddressFamily { | ||
| pub fn from_i32(family: i32) -> Option<AddressFamily> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a doccomment for this function as it's public.
src/sys/socket/addr.rs
Outdated
| libc::AF_UNIX => Some(AddressFamily::Unix), | ||
| libc::AF_INET => Some(AddressFamily::Inet), | ||
| libc::AF_INET6 => Some(AddressFamily::Inet6), | ||
| #[cfg(any(target_os = "linux", target_os = "android"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please alphabetize the OSes.
src/lib.rs
Outdated
|
|
||
| pub mod net; | ||
|
|
||
| #[cfg(not(any(target_os = "android", target_os = "haiku")))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We prefer to avoid blocklists with #cfgs, can you instead whitelist all appropriate platforms?
src/ifaddrs.rs
Outdated
|
|
||
| let ifu : *mut libc::sockaddr; | ||
|
|
||
| #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably want to use cfg_if! here instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't manage to use a cfg_if! for just these two statements, but extracted a small private function, now. Seems cleaner to me that way, but YMMV.
src/ifaddrs.rs
Outdated
| destination: None, | ||
| }; | ||
|
|
||
| let ifu : *mut libc::sockaddr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the space before the colon.
src/ifaddrs.rs
Outdated
| @@ -0,0 +1,137 @@ | |||
| //! Query network interface addresses | |||
| //! | |||
| //! Uses the Linux and/or BSD specific function getifaddrs to query the list | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put backticks around getifaddrs so it renders nicely with rustdoc.
src/sys/socket/addr.rs
Outdated
| #[cfg(any(target_os = "ios", target_os = "macos"))] | ||
| Some(AddressFamily::System) => Some(SockAddr::SysControl( | ||
| SysControlAddr(*(addr as *mut sys_control::sockaddr_ctl)))), | ||
| // No other address families are supported, including netlink and syscontrol. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a TODO or FIXME or just impossible? Please clarify this comment further.
|
@Susurrus thanks for your review. I think I covered all points. |
src/ifaddrs.rs
Outdated
| /// Get interface addresses using libc's `getifaddrs` | ||
| /// | ||
| /// Note that the underlying implementation differs between OSes and the nix | ||
| /// crate doesn't support `AF_PACKET` entries. Therefore, the returned list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be a nice change in the future to support AF_PACKET/AF_LINK in order to be able to build something out for getting MAC addresses (useful for, among other things, getting a node id for UUID V1 generation). Not gating for the first pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment could be made more clear as to why this isn't implemented. Was it because we were lazy or because the OSes differed enough it'd be quite difficult to expose a nice API here?
| use net::if_::*; | ||
|
|
||
| /// Describes a single address for an interface as returned by `getifaddrs`. | ||
| pub struct InterfaceAddress { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we implement or derive Debug/Display for this. Also, I think deriving Clone, PartialEq, and Hash would be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this as well, should definitely have Clone, Copy, Debug, Eq, Hash, and PartialEq. We shouldn't implement Display here and I don't think we should implement Default here either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit ef40c9c, I added derives for Clone, Eq, Hash, and PartialEq, but not Copy. The struct uses Strings, so I don't this that marker is applicable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and Debug. I wasn't quite sure how much or in what format to return from fn fmt. Also note that SockAddr doesn't implement Debug, but Display. Is this really consistent?
Susurrus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few more style changes and some derives to get sorted, but definitely almost there!
| #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "ios", | ||
| target_os = "linux", target_os = "macos", target_os = "netbsd", | ||
| target_os = "openbsd"))] | ||
| /// Avoid use of trailers. (see |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put the doccomments for items above any #[cfgs for those items. Applies in several places here.
src/lib.rs
Outdated
|
|
||
| pub mod net; | ||
|
|
||
| #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linux is out of alphabetical order, and could you list these 1-per-line? When cfg's get longer than a line we like to wrap with each target on its own line.
src/ifaddrs.rs
Outdated
| /// Get interface addresses using libc's `getifaddrs` | ||
| /// | ||
| /// Note that the underlying implementation differs between OSes and the nix | ||
| /// crate doesn't support `AF_PACKET` entries. Therefore, the returned list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment could be made more clear as to why this isn't implemented. Was it because we were lazy or because the OSes differed enough it'd be quite difficult to expose a nice API here?
| use net::if_::*; | ||
|
|
||
| /// Describes a single address for an interface as returned by `getifaddrs`. | ||
| pub struct InterfaceAddress { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with this as well, should definitely have Clone, Copy, Debug, Eq, Hash, and PartialEq. We shouldn't implement Display here and I don't think we should implement Default here either.
| /// Use the function `getifaddrs` to create this Iterator. Note that the | ||
| /// actual list of interfaces can be iterated once and will be freed as | ||
| /// soon as the Iterator goes out of scope. | ||
| pub struct InterfaceAddressIterator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should definitely derive Debug here, but does it make sense to derive any of the other standard ones (Clone, Copy, Eq, Hash, and PartialEq)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clone certainly doesnt make much sense, as the InterfaceAddressIteratoris used to govern the memory allocated bygetifaddrs. I added Debug, Eq, Hash, and PartialEq`.
src/net/if_.rs
Outdated
| /// Avoid use of trailers. (see | ||
| /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) | ||
| IFF_NOTRAILERS; | ||
| #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "fuchsia", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please list targets one-per-line when wrapping these cfgs.
Susurrus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very minor things left, then we're GTM.
src/ifaddrs.rs
Outdated
| } | ||
|
|
||
| cfg_if! { | ||
| if #[cfg(any(target_os = "emscripten", target_os = "fuchsia", target_os="linux"))] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs spacing around the = before linux.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, corrected.
src/ifaddrs.rs
Outdated
| /// | ||
| /// Note that the underlying implementation differs between OSes. Only the | ||
| /// most common address families are supported by the nix crate (due to | ||
| /// lack of time and complexity of testing). For any entry not supported, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I was looking at this as a user, my first thought would be oh, what are those specific address families? I think this information is embedded in InterfaceFlags, yes? If so, that should be mentioned in this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe some of the InterfaceFlags are specific per address family, yes. However, it's the returned SockAddr type(s) that directly map to an AddressFamily, see from_libc_sockaddr. I tried to improve the comment.
|
Also, could you squash this down into 1 commit? Makes viewing the history of |
ad5488e to
f1e5db7
Compare
src/net/if_.rs
Outdated
| IFF_RUNNING; | ||
| /// Resources allocated. | ||
| #[cfg(any(target_os = "freebsd"))] | ||
| IFF_DRV_RUNNING; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be IFF_RUNNING instead of IFF_DRV_RUNNING. The former is an alias for the latter. But you may need to add it to libc first. Ditto for IFF_OACTIVE below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libc defines only IFF_DRV_RUNNING and IFF_DRV_OACTIVE for FreeBSD, so that's what I used. Given I don't really use - let alone know - FreeBSD, I don't quite feel in the position to open a PR on libc.
Especially since FreeBSD seems to prefer the DRV variant since version 8.1:
https://www.freebsd.org/cgi/man.cgi?query=ifnet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The distinction between the DRV variants and the non-DRV variants only matters for kernel code. You can read the gory details at https://svnweb.freebsd.org/base?view=revision&revision=148886 . It's perfectly fine to use the non-DRV variants in userland code, especially since their values are identical. For a cross-platform library like nix, the non-DRV variants are better, because they're portable. The current definitions are at https://svnweb.freebsd.org/base/head/sys/net/if.h?view=markup#l170 . You can go ahead and submit a PR to libc based on those definitions, even if you don't have a FreeBSD VM to test on. If you like, CC me as a reviewer on the libc PR.
src/net/if_.rs
Outdated
| /// Avoid use of trailers. (see | ||
| /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) | ||
| #[cfg(any(target_os = "android", | ||
| target_os = "bitrig", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to worry about bitrig anymore. A future nix PR will probably remove all references. For now, it doesn't really matter whether or not you leave it in.
https://www.phoronix.com/scan.php?page=news_item&px=Bitrig-Fork-Dead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks for the hint.
| /// Is able to select media type via ifmap. (see | ||
| /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) | ||
| #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "fuchsia", target_os = "linux"))] | ||
| IFF_PORTSEL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what caused your build failure. IFF_PORTSEL is not defined on FreeBSD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. That's clearly wrong. Corrected.
src/net/if_.rs
Outdated
| /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html)) | ||
| IFF_PROMISC; | ||
|
|
||
| // bitmask: 0x0200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all these "bitmask: 0xXXX" constants and the blank line between all enum entries here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those greatly simplified assembling the list of IFF_ constants and will help maintaining it in the future. Can you please suggest a viable alternative? Dropping that information is not a good option, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are all listed in /usr/include/linux/if.h, so was this helpful for the other platforms? I don't know how this will help make things more maintainable except be incorrect or out of date possible since these values will never likely be updated. I think it's best we remove them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Susurrus Yes, because I could map to the other OSes' header files by bitmask and ensure I got the complete list covered (these flags aren't alphabetically ordered, but by value). If you want to take over and keep the list in sync with libc, I'm fine with having the bitmasks removed. However, I'm certainly not ever gonna do it again w/o the information these hints provide.
That being said, maybe there's a better way to "encode" them that better conforms to the style guide applicable for nix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand how it helped you to compile the list, but it won't be helpful moving forward in maintaining it as I mentioned above. That being said, I'm not going to throw too much more of a fight over it as I don't think this is that important. Please do, however, remove the blank lines in between the variants.
Use IFF_OACTIVE and IFF_RUNNING even on FreeBSD. Deprecate the DRV ones. According to @asomers, libc should propagate the use of the portable constants `IFF_OACTIVE` and `IFF_RUNNING` for user-space applications, instead of `IFF_DRV_OACTIVE` and `IFF_DRV_RUNNING`. It least that's my understanding of [his comment](nix-rust/nix#667 (comment)) in nix-rust/nix#667.
|
@lucab It's basically whichever gets there first at this point. I would recommend we focus our efforts on this PR since #764 hasn't been touched in months and I don't expect it to ever resolve. @mwanner Please remove the blank lines from |
src/ifaddrs.rs
Outdated
| /// | ||
| /// Note that the underlying implementation differs between OSes. Only the | ||
| /// most common address families are supported by the nix crate (due to | ||
| /// lack of time and complexity of testing). The address familiy is encoded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/familiy/family/
src/ifaddrs.rs
Outdated
| /// } | ||
| /// }, | ||
| /// Err(err) => { | ||
| /// println!("error getting interface addresses: {}", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would simplify this example in order to show just the getifaddrs, by doing:
- a
try!/unwrap/expecton thegetifaddrs - a
while leton the interator
The resulting example would be less indented and more compact:
let addrs = getifaddrs()?;
while let Ok(a) = addrs.next() {
println!(...)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I stripped the error handling.
Note however, that the iterator is not over a Result<..>, but over multiple InterfaceAddress structs, where always get an interface_name, but for which we do not (yet) support the address type. Therefore, neither while let Ok(..) nor while let Some(..) work and the simple for loop likely is the easiest. I tried to clarify the example in that regard.
|
I agree it would be nice to have Except for typos and very verbose example, this PR looks nice at a first glance. Thanks for this! |
e200bc4 to
8dc8137
Compare
|
@mwanner #801 changed the scope of bit-constants, see #801 (comment). Those are now |
8dc8137 to
985ea01
Compare
|
@Susurrus, @asomers, @lucab: I think I covered all concerns and the result now passes CI tests as well. As two of you voted against the bitmask comments and the corresponding grouping by empty lines, I removed those. Given the lack of that information, I wonder if alphabetical ordering of the To track progress on the requested support of Given @lucab's simplified example wasn't correct, I fear the Compared to #764, this variant is closer to the libc interface, not providing a |
The way maintenance of this will work is that someone will find a constant that's missing. So they'll just add them. There really isn't going to be someone doing a full audit of these per-platform, so I think we're fine here. I think you're overly concerned with the maintenance burden of that bitmask.
Perfect, thanks.
I don't think we need a complete solution on the first pass, I think this one is pretty good. And I agree with keeping a verbose example. My only question here would be how to make sure that incorrect usage of this API fails at compile time. I think @lucab's example would have failed at compile time, so I think concerns about confusion about this API might be unfounded.
That's a good thing. Overall, I think this looks pretty good. I suggest we merge it. I'll wait until @asomers responds (@lucab feel free to chime in here as well if you have anything to add). |
|
Yep, LGTM. bors r+ |
|
Thanks for doing this, and sorry my PR died. I over estimated my ability to do open source while in school, but I'm glad to see that the functionality has been added! |
This function never should've been public, since it's basically impossible to use directly. It's only public due to an oversight from PR nix-rust#667 .
1215: Remove sys::socket::addr::from_libc_sockaddr from the public API r=posborne a=asomers This function never should've been public, since it's basically impossible to use directly. It's only public due to an oversight from PR #667 . Co-authored-by: Alan Somers <[email protected]>
Here's a first attempt at a rustian interface for
getifaddrs, please review.Changes for the changelog:
nix::ifaddrs::{getifaddrs, InterfaceAddressIterator, InterfaceAddress and InterfaceFlags}Closes #650.
Closes #764.