Skip to content

[WIP] Netlink bits #202

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::{fmt, hash, mem, net, ptr};
use std::ffi::OsStr;
use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "linux", target_os = "android"))]
use ::sys::socket::addr::netlink::NetlinkAddr;

// TODO: uncomment out IpAddr functions: rust-lang/rfcs#988

Expand All @@ -15,12 +17,24 @@ use std::os::unix::ffi::OsStrExt;
*
*/

#[cfg(any(target_os = "linux", target_os = "android"))]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[repr(C)]
pub struct sockaddr_nl {
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

(sorry for the derive suggestion, should have realised this was present)

Copy link
Member

Choose a reason for hiding this comment

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

I also just realised this would mean none of those impls would be present. unclear if they're required or not?

Copy link
Contributor

Choose a reason for hiding this comment

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

libc already defines Clone and Copy for most or all of its structs (see s! macro: http://rust-lang-nursery.github.io/libc/x86_64-unknown-linux-gnu/src/libc/macros.rs.html#42). So unless PartialEq, Eq, Debug and Hash are necessary, it should be fine to use the libc version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

If they make sense for the raw struct in our code, they would probably make sense for the corresponding raw struct in libc. Would you create a PR for libc?

Copy link
Member

Choose a reason for hiding this comment

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

I just created rust-lang/libc#159 for that.

Copy link
Member

Choose a reason for hiding this comment

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

PR was rejected, with rationale:

At this time we're not looking for higher level abstractions in libc (e.g. any other form of "Rust code" like Eq or Hash). That's in general left to higher level libraries.

Copy link
Member

Choose a reason for hiding this comment

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

I think it still makes sense to use the struct from libc and implement the required traits as in:

diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index eadd990..1f38c4d 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -17,16 +17,6 @@ use ::sys::socket::addr::netlink::NetlinkAddr;
  *
  */

-#[cfg(any(target_os = "linux", target_os = "android"))]
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-#[repr(C)]
-pub struct sockaddr_nl {
-    pub nl_family: sa_family_t,
-    nl_pad: libc::c_ushort,
-    pub nl_pid: u32,
-    pub nl_groups: u32
-}
-
 #[repr(i32)]
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub enum AddressFamily {
@@ -503,7 +493,7 @@ impl SockAddr {
             SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
             SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + mem::size_of::<libc::sa_family_t>()) as libc::socklen_t),
             #[cfg(any(target_os = "linux", target_os = "android"))]
-            SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sockaddr_nl>() as libc::socklen_t),
+            SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
         }
     }
 }
@@ -559,21 +549,41 @@ impl fmt::Display for SockAddr {

 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub mod netlink {
-    use ::sys::socket::addr::{AddressFamily,sockaddr_nl};
-    use libc::sa_family_t;
-    use std::fmt;
+    use ::sys::socket::addr::{AddressFamily};
+    use libc::{sa_family_t, sockaddr_nl};
+    use std::{fmt, mem};
+    use std::hash::{Hash, Hasher};

-    #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+    #[derive(Copy, Clone)]
     pub struct NetlinkAddr(pub sockaddr_nl);

+    // , PartialEq, Eq, Debug, Hash
+    impl PartialEq for NetlinkAddr {
+        fn eq(&self, other: &Self) -> bool {
+            let (inner, other) = (self.0, other.0);
+            (inner.nl_family, inner.nl_pid, inner.nl_groups) ==
+            (other.nl_family, other.nl_pid, other.nl_groups)
+        }
+    }
+
+    impl Eq for NetlinkAddr {}
+
+    impl Hash for NetlinkAddr {
+        fn hash<H: Hasher>(&self, s: &mut H) {
+            let inner = self.0;
+            (inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s);
+        }
+    }
+
+
     impl NetlinkAddr {
         pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
-            NetlinkAddr(sockaddr_nl {
-                nl_family: AddressFamily::Netlink as sa_family_t,
-                nl_pad: 0,
-                nl_pid: pid,
-                nl_groups: groups,
-            })
+            let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
+            addr.nl_family = AddressFamily::Netlink as sa_family_t;
+            addr.nl_pid = pid;
+            addr.nl_groups = groups;
+
+            NetlinkAddr(addr)
         }

         pub fn pid(&self) -> u32 {

Copy link
Member

Choose a reason for hiding this comment

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

(above patch should git apply cleanly on your PR)

pub nl_family: sa_family_t,
nl_pad: libc::c_ushort,
pub nl_pid: u32,
pub nl_groups: u32
}

#[repr(i32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum AddressFamily {
Unix = consts::AF_UNIX,
Inet = consts::AF_INET,
Inet6 = consts::AF_INET6,
#[cfg(any(target_os = "linux", target_os = "android"))]
Netlink = consts::AF_NETLINK,
}

#[derive(Copy)]
Expand Down Expand Up @@ -450,7 +464,9 @@ impl fmt::Display for UnixAddr {
#[derive(Copy)]
pub enum SockAddr {
Inet(InetAddr),
Unix(UnixAddr)
Unix(UnixAddr),
#[cfg(any(target_os = "linux", target_os = "android"))]
Netlink(NetlinkAddr)
}

impl SockAddr {
Expand All @@ -462,11 +478,18 @@ impl SockAddr {
Ok(SockAddr::Unix(try!(UnixAddr::new(path))))
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}

pub fn family(&self) -> AddressFamily {
match *self {
SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
}
}

Expand All @@ -479,6 +502,8 @@ impl SockAddr {
SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + mem::size_of::<libc::sa_family_t>()) as libc::socklen_t),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sockaddr_nl>() as libc::socklen_t),
}
}
}
Expand All @@ -492,6 +517,10 @@ impl PartialEq for SockAddr {
(SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => {
a == b
}
#[cfg(any(target_os = "linux", target_os = "android"))]
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
a == b
}
_ => false,
}
}
Expand All @@ -505,6 +534,8 @@ impl hash::Hash for SockAddr {
match *self {
SockAddr::Inet(ref a) => a.hash(s),
SockAddr::Unix(ref a) => a.hash(s),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(ref a) => a.hash(s),
}
}
}
Expand All @@ -520,6 +551,43 @@ impl fmt::Display for SockAddr {
match *self {
SockAddr::Inet(ref inet) => inet.fmt(f),
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "linux", target_os = "android"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
}
}
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod netlink {
use ::sys::socket::addr::{AddressFamily,sockaddr_nl};
use libc::sa_family_t;
use std::fmt;

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct NetlinkAddr(pub sockaddr_nl);
Copy link
Member

Choose a reason for hiding this comment

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

should the wrapped field be pub if new() sets it and there are getters?


impl NetlinkAddr {
pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
NetlinkAddr(sockaddr_nl {
nl_family: AddressFamily::Netlink as sa_family_t,
nl_pad: 0,
nl_pid: pid,
nl_groups: groups,
})
}

pub fn pid(&self) -> u32 {
self.0.nl_pid
}

pub fn groups(&self) -> u32 {
self.0.nl_groups
}
}

impl fmt::Display for NetlinkAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pid: {} groups: {}", self.pid(), self.groups())
}
}
}
2 changes: 2 additions & 0 deletions src/sys/socket/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod os {
pub const AF_LOCAL: c_int = AF_UNIX;
pub const AF_INET: c_int = 2;
pub const AF_INET6: c_int = 10;
pub const AF_NETLINK: c_int = 16;

pub const SOCK_STREAM: c_int = 1;
pub const SOCK_DGRAM: c_int = 2;
Expand All @@ -20,6 +21,7 @@ mod os {
pub const SOL_TCP: c_int = 6;
pub const SOL_UDP: c_int = 17;
pub const SOL_IPV6: c_int = 41;
pub const SOL_NETLINK: c_int = 270;
pub const IPPROTO_IP: c_int = SOL_IP;
pub const IPPROTO_IPV6: c_int = SOL_IPV6;
pub const IPPROTO_TCP: c_int = SOL_TCP;
Expand Down
5 changes: 5 additions & 0 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub use self::addr::{
Ipv4Addr,
Ipv6Addr,
};
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use ::sys::socket::addr::netlink::NetlinkAddr;

pub use libc::{
in_addr,
in6_addr,
Expand Down Expand Up @@ -577,6 +580,8 @@ pub enum SockLevel {
Ip = IPPROTO_IP,
Ipv6 = IPPROTO_IPV6,
Udp = IPPROTO_UDP,
#[cfg(any(target_os = "linux", target_os = "android"))]
Netlink = SOL_NETLINK,
}

/// Represents a socket option that can be accessed or set. Used as an argument
Expand Down