Skip to content
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

Support EtherAddr and impl Debug for InterfaceAddress/SockAddr #813

Merged
merged 2 commits into from
Jan 11, 2018

Conversation

LuoZijun
Copy link
Contributor

@LuoZijun LuoZijun commented Dec 6, 2017

  1. Add EtherAddr .
  2. impl Debug for InterfaceAddress and SockAddr.

Closes #809

@Susurrus
Copy link
Contributor

Susurrus commented Dec 6, 2017

This is a lot of changes, and the commits don't really tell me what has happened here. Each discrete change should really be a separate commit with a description that provides context as to why it's a desired change. I can't really follow what all is being changed here easily, so I'd ask you split this up into separate commits that can evaluated individually.

@LuoZijun
Copy link
Contributor Author

LuoZijun commented Dec 6, 2017

@Susurrus could you review again ? thx.

@Susurrus
Copy link
Contributor

Susurrus commented Dec 6, 2017

You have 2 commits with identical names and one commit with no name. Neither of which have a description.

Please break off the impl Debug changes from your changes that add EtherAddr at a minimum. The goal is to make code changes as small as possible will still being understandable. I have no context for what these changes are about and there seems to be a bunch of changes that aren't necessary, so this is quite hard for me to wrap my head around.

@@ -886,6 +916,20 @@ impl fmt::Display for SockAddr {
}
}

impl fmt::Debug for SockAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't you just #[derive(Debug)] instead on line 692?


impl fmt::Debug for EtherAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "EtherAddr({})", self)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this implemented differently than the others?

// Will be unsafe
// when sdl_nlen > 40.
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
pub struct sockaddr_dl {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please read the CONTRIBUTING.md document. Structs should not be declared here, but instead in libc directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this struct from apple/xnu , and not defined in libc .

so, what can i do?

any suggestion ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's likely fine to add to libc. libc has been including types that aren't strictly in libc for a while now as long as they're included in system headers. You can make an issue about it in that repo first if you'd like to make sure, but it's likely fine to include. Also note that this will need to work on more than just these 2 platforms for this to get merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, see rust-lang/libc#866

@Susurrus
Copy link
Contributor

Susurrus commented Dec 6, 2017

So it looks like there are a lot less changes now, so not sure what happened there.

}
}

#[derive(PartialEq, Eq, Clone, Copy, Hash)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be sorted alphabetically.

}
}
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this extra newline

@@ -782,6 +871,9 @@ impl PartialEq for SockAddr {
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
a == b
}
(SockAddr::Ether(ref a), SockAddr::Ether(ref b)) => {
a == b
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't properly indented, see the block above.

#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Ether(..) => AddressFamily::Packet,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't aligned properly, the target_os part should all be vertically aligned.

@@ -712,6 +754,10 @@ impl SockAddr {
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
}

pub fn new_ether(addr: EtherAddr) -> SockAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need this helper function.

pub enum SockAddr {
Inet(InetAddr),
Unix(UnixAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink(NetlinkAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
Ether(EtherAddr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put a comma at the end of this line and this should also have doccomments. It'd be very much appreciated if you could provide doc comments for the other variants here as well.

#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_PACKET => Some(AddressFamily::Packet),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also improperly indended.

@LuoZijun
Copy link
Contributor Author

@Susurrus this PR rust-lang/libc#866 has merged on libc .

so i will remove struct sockaddr_dl in sys/socket/ffi.rs .

and cloud i rebase all change into one commit ?

@Susurrus
Copy link
Contributor

The goal with the commits is to have changes that are as small and self-contained as possible while still being readable. So in this case I'd like to see two commits: 1) implement Debug for all the types and 2) add the EtherAddr implementation.

I'd also appreciate any tests or example code that could be easily written. This will give us a sense of how this API ends up being used and make sure we don't break anything during major refactorings.

@LuoZijun
Copy link
Contributor Author

@Susurrus ping ...

Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And please squash your commits down from the 13 that they currently are into 2: the first that implements debug and the 2nd that does everything else. There should also not be any Merge commits, please rebase when you sync with HEAD.

}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct EtherAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a newtype around either sockaddr_dl or sockaddr_ll depending on the platform.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what?

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct EtherAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl EtherAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have some getters probably to extract the desired info across platforms. Like for your specific use case extracting the address.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extracting the address from EtherAddr , that's easy:

    let mac_addr = EtherAddr::new(20,20,20, 20,20,20);
    let a = mac_addr.0;
    let b = mac_addr.1;
    let c = mac_addr.2;
    // ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relates to my point above how the data should not be stored as a tuple, but the backing data store should be a sockaddr_ll or sockaddr_dl struct. Since this backing store will vary across platforms, having a method on EtherAddr that will return just the mac address would be useful.

// #[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(target_os = "linux")]
Some(AddressFamily::Packet) => {
let sll: *const libc::sockaddr_ll = mem::transmute(addr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work the same way as the other variants and not use mem::transmute().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

@@ -748,6 +798,53 @@ impl SockAddr {
#[cfg(any(target_os = "ios", target_os = "macos"))]
Some(AddressFamily::System) => Some(SockAddr::SysControl(
SysControlAddr(*(addr as *const sys_control::sockaddr_ctl)))),
// FIXME: android is same ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please resolve this FIXME.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

Some(SockAddr::Ether(mac))
},
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please indent so target_os is always vertically aligned. There are other places in this document you can reference for the specific style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

@LuoZijun
Copy link
Contributor Author

easy merge:

git merge 4e7a6ecd2b6fbbb7e0e6de40b93e9da7ccb8a034  # impl `Debug` for all sockaddr types
git merge 640e2fe5fadd4c28a497248f98fd0c7aece6c700  # Impl EtherAddr(MAC Addr)
git merge c3d3ea6062a415da75901d70709dc6d7d43ee618  # Add example for list interfaces

@Susurrus
Copy link
Contributor

You should be rebasing on top of master, squashing your commits to just 3 as you do, and then force-push into this branch. So it'd be something like:

$ git fetch upstream
$ git rebase -i upstream/master

And on the commits you want to squash, change the pick to a s (for squash). It'll then ask you to modify the commit message if there wasn't a merge conflict. This link describes some of these actions.

Given where you're at, you'll likely want to git fetch upstream && git reset upstream/master to get back to a sane state. Then just make your two commits using git add --patch to choose just the right parts, and the git push origin -f to overwrite the branch this PR is tracking.

@LuoZijun
Copy link
Contributor Author

LuoZijun commented Dec 16, 2017

@Susurrus wow, that's magic 👍

thank you!

@Susurrus
Copy link
Contributor

Awesome, nicely done! Git can be tricky to use, and even harder to explain, I'm surprised what I said helped!

Anyways, let's remove that last commit as that example isn't very useful. And this will also need a CHANGELOG entry.

@@ -206,7 +206,7 @@ impl AddressFamily {
/// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
/// the `sa_family` field of a `sockaddr`.
///
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it support Packet as well?

}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct EtherAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a new type around the underlying libc types, not a custom strict. See how the other types are declared for what time talking about. You'll just have to make them different definitions for the two different platforms types since the libc types are different.

@LuoZijun LuoZijun force-pushed the patch-4 branch 6 times, most recently from d8cbaae to 925cd87 Compare December 17, 2017 14:25


#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct EtherAddr {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why didn't you make this a newtype around the underlying libc type as I asked? You add a lot of types that I don't think are necessary.

cfg_if! {
    if #[cfg(any(target_os = "android", target_os = "linux"))] {
        pub struct EtherAddr(libc::sockaddr_ll);
    else if #[cfg(any(target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "ios",
          target_os = "macos",
          target_os = "netbsd",
          target_os = "openbsd"))] {
        pub struct EtherAddr(libc::sockaddr_dl);
}

Then to access the MAC address, you can implement a EtherAddr.mac() or something like that. You can defer on all the other struct contents and just implement the MAC address part for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code:

#[cfg(any(target_os = "android", target_os = "linux"))]
pub struct EtherAddr(libc::sockaddr_ll);

#[cfg(any(target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "ios",
          target_os = "macos",
          target_os = "netbsd",
          target_os = "openbsd"))]
pub struct EtherAddr(libc::sockaddr_dl);

impl EtherAddr {
    pub fn addr(&self) -> [u8; 6];
}

is that ok ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's more what I was thinking. Is there any other data in there that's common across platforms that we could expose besides addr()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just hwaddr ([u8; 6]) . no more other data.

i hope u know i havn't english skill.

sry for that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LuoZijun No worries about your language skills, we seem to be communicating just fine! And then that's fine if that's the only data there, I think we're on the right track for a nice API here!

@LuoZijun LuoZijun force-pushed the patch-4 branch 2 times, most recently from b9fda8b to cfacb5b Compare December 21, 2017 03:08
@LuoZijun
Copy link
Contributor Author

@Susurrus hi, need any changes ?

Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a ton of #[cfg...] statements around. There's a common idiom of creating a new module for the different platforms that has a single #[cfg..] for it and then you can just pub use ... depending on the platform. This results in a lot less #[cfg...] throughout the code. I'd suggest refactoring to use this approach (see the const module in sys/ioctl/platform/linux.rs)

target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These all need to be alphabetized.

target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
SockAddr::Ether(_) => unimplemented!()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not positive what as_ffi_pair() is used for, but why can't this be implemented for Ether? It needs a comment here explaining why it's unimplemented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Susurrus libc::sockaddr and libc::sockaddr_dl/libc::sockaddr_ll has diffences size (mem::size_of) . i think i can't implement.

}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the extra blank line.

#[cfg(any(target_os = "android", target_os = "linux"))]
impl EtherAddr {
pub fn new(sll: libc::sockaddr_ll) -> Option<EtherAddr> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you even implement new()? None of the other types implement it, so I suggest you drop it. You have this implemented to return an Option and then just unwrap the option ever time anyways, so I think this function is useless.

}

pub fn is_empty(&self) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this as I don't know why it's implemented.

let nlen = self.nlen();

[self.0.sdl_data[nlen ] as u8,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please run rustfmt on this as this is an odd way to type this out.

pub fn max_nlen(&self) -> usize { 46 }

pub fn addr(&self) -> [u8; 6] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, all pub fns and types need doc comments.

self.0.sdl_data[nlen + 5] as u8 ]
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this blank line.

impl Eq for EtherAddr {}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this blank line

target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, please alphabetize this list.

Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking pretty good! A couple minor style issues and I still want to figure out what to do about as_ffi_pair as I think it should be implemented.

And if you have any test code or examples that could be added that could at least provide compile-tests for this additional API, it'd be most appreciated!

// Other address families are currently not supported and simply yield a None
// entry instead of a proper conversion to a `SockAddr`.
Some(_) | None => None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave this as-is.

target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
// `libc::sockaddr` and `libc::sockaddr_dl`/`libc::sockaddr_ll` has diffences size.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's still correct to cast the datatype to sockaddr, though you'll need to do this differently for the sockaddr_dl and sockaddr_ll platforms. It looks like there are other libc APIs that do this kind of thing, which is why the length is being thrown around. I think a better way to look at this is that it's really returning a void pointer rather than one for an actual datatype.

And since we're having this conversation, can you add doccomments to this function?

I'm also wondering if we should alter the return type here to be (*const libc::sockaddr, libc::socklen_t). I think it's more clear how unsafe this is if we leave it a pointer. @asomers any comment on this as you might understand this stuff better than me.

@@ -27,6 +27,7 @@ pub use self::addr::{
IpAddr,
Ipv4Addr,
Ipv6Addr,
EtherAddr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comma at the end of this line.

assert!(!self.is_empty());

let a = data[nlen] as u8;
let b = data[nlen+1] as u8;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleas put a space around the + for all of these.

@LuoZijun LuoZijun force-pushed the patch-4 branch 2 times, most recently from 03bce40 to 3636de9 Compare December 29, 2017 05:50
@LuoZijun
Copy link
Contributor Author

@Susurrus updated.

@Susurrus
Copy link
Contributor

Susurrus commented Dec 31, 2017

@LuoZijun This isn't passing CI.

@LuoZijun
Copy link
Contributor Author

LuoZijun commented Jan 3, 2018

@Susurrus sorry for delay , i will fix that at tomorrow.

@LuoZijun
Copy link
Contributor Author

LuoZijun commented Jan 4, 2018

@Susurrus updated.

@nix-rust nix-rust deleted a comment from LuoZijun Jan 7, 2018
@nix-rust nix-rust deleted a comment from LuoZijun Jan 7, 2018
Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs a rebase now that another PR has landed.

// Other address families are currently not supported and simply yield a None
// entry instead of a proper conversion to a `SockAddr`.
Some(_) | None => None,
}
}
}

/// Conversion SockAddr to a libc's sockaddr.
Copy link
Contributor

@Susurrus Susurrus Jan 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Conversion from nix's SockAddr type to the underlying libc sockaddr type.

This is useful for interfacing with other libc functions that don't yet have nix wrappers.

Returns a reference to the underlying data type (as a sockaddr reference) along with the size of the actual data type. sockaddr is commonly used as a proxy for a superclass as C doesn't support inheritance, so many functions that take a sockaddr * need to take the size of the underlying type as well and then internally cast it back."

Please use my above comment instead, using backticks (`) around type and library names as I did here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, and how do u think rename EtherAddr to LinkAddr or HwAddr ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think LinkAddr would work nicely.

@LuoZijun
Copy link
Contributor Author

@Susurrus do u interesting one RawSocket API to nix?

look here: https://github.com/LuoZijun/exodus/blob/master/netif/src/raw_socket.rs

@Susurrus
Copy link
Contributor

I don't see a reason why that couldn't be added as well, but let's defer that work to another PR.

@Susurrus
Copy link
Contributor

LGTM.

bors r+

bors bot added a commit that referenced this pull request Jan 11, 2018
813: Support `EtherAddr` and impl `Debug` for `InterfaceAddress/SockAddr` r=Susurrus a=LuoZijun

1. Add `EtherAddr` .
2. impl `Debug` for `InterfaceAddress` and `SockAddr`.
  
Closes #809
@bors
Copy link
Contributor

bors bot commented Jan 11, 2018

@bors bors bot merged commit cf7c2dc into nix-rust:master Jan 11, 2018
@LuoZijun LuoZijun deleted the patch-4 branch January 13, 2018 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants