From c69cd8d5a27ba42e077cdc7a041cf96ca35794aa Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Thu, 26 Oct 2023 19:59:59 -0400 Subject: [PATCH] Split out CanAddr into new addr module. --- src/addr.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +- src/socket.rs | 141 ++------------------------------------------- src/tokio.rs | 8 +-- 4 files changed, 167 insertions(+), 141 deletions(-) create mode 100644 src/addr.rs diff --git a/src/addr.rs b/src/addr.rs new file mode 100644 index 00000000..9ab94364 --- /dev/null +++ b/src/addr.rs @@ -0,0 +1,154 @@ +// socketcan/src/lib.rs +// +// The main lib file for the Rust SocketCAN library. +// +// This file is part of the Rust 'socketcan-rs' library. +// +// Licensed under the MIT license: +// +// This file may not be copied, modified, or distributed except according +// to those terms. + +//! SocketCAN address type. + +use libc::{ + sa_family_t, sockaddr, sockaddr_can, + sockaddr_storage, socklen_t, +}; +use nix::net::if_::if_nametoindex; +use socket2::SockAddr; +use std::{ + fmt, io, mem, + os::raw::c_int, +}; + +pub use libc::{AF_CAN, CAN_RAW, PF_CAN}; + + +/// CAN socket address. +/// +/// This is the address for use with CAN sockets. It is simply an addres to +/// the SocketCAN host interface. It can be created by looking up the name +/// of the interface, like "can0", "vcan0", etc, or an interface index can +/// be specified directly, if known. An index of zero can be used to read +/// frames from all interfaces. +/// +/// This is based on, and compatible with, the `sockaddr_can` struct from +/// libc. +/// [ref](https://docs.rs/libc/latest/libc/struct.sockaddr_can.html) +#[derive(Clone, Copy)] +pub struct CanAddr(sockaddr_can); + +impl CanAddr { + /// Creates a new CAN socket address for the specified interface by index. + /// An index of zero can be used to read from all interfaces. + pub fn new(ifindex: u32) -> Self { + let mut addr = Self::default(); + addr.0.can_ifindex = ifindex as c_int; + addr + } + + /// Try to create an address from an interface name. + pub fn from_iface(ifname: &str) -> io::Result { + let ifindex = if_nametoindex(ifname)?; + Ok(Self::new(ifindex)) + } + + /// Gets the address of the structure as a `sockaddr_can` pointer. + pub fn as_ptr(&self) -> *const sockaddr_can { + &self.0 + } + + /// Gets the address of the structure as a `sockaddr` pointer. + pub fn as_sockaddr_ptr(&self) -> *const sockaddr { + self.as_ptr().cast() + } + + /// Gets the size of the address structure. + pub fn len() -> usize { + mem::size_of::() + } + + /// Converts the address into a `sockaddr_storage` type. + /// This is a generic socket address container with enough space to hold + /// any address type in the system. + pub fn into_storage(self) -> (sockaddr_storage, socklen_t) { + let can_addr = crate::as_bytes(&self.0); + let len = can_addr.len(); + + let mut storage: sockaddr_storage = unsafe { mem::zeroed() }; + let sock_addr = crate::as_bytes_mut(&mut storage); + + sock_addr[0..len].copy_from_slice(can_addr); + (storage, len as socklen_t) + } + + /// Converts the address into a `socket2::SockAddr` + pub fn into_sock_addr(self) -> SockAddr { + SockAddr::from(self) + } +} + +impl Default for CanAddr { + fn default() -> Self { + let mut addr: sockaddr_can = unsafe { mem::zeroed() }; + addr.can_family = AF_CAN as sa_family_t; + Self(addr) + } +} + +impl fmt::Debug for CanAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "CanAddr {{ can_family: {}, can_ifindex: {} }}", + self.0.can_family, self.0.can_ifindex + ) + } +} + +impl From for CanAddr { + fn from(addr: sockaddr_can) -> Self { + Self(addr) + } +} + +impl From for SockAddr { + fn from(addr: CanAddr) -> Self { + let (storage, len) = addr.into_storage(); + unsafe { SockAddr::new(storage, len) } + } +} + +impl AsRef for CanAddr { + fn as_ref(&self) -> &sockaddr_can { + &self.0 + } +} + +///////////////////////////////////////////////////////////////////////////// + +#[cfg(test)] +mod tests { + use super::*; + use crate::as_bytes; + + const IDX: u32 = 42; + + #[test] + fn test_addr() { + let _addr = CanAddr::new(IDX); + + assert_eq!(mem::size_of::(), CanAddr::len()); + } + + #[test] + fn test_addr_to_sock_addr() { + let addr = CanAddr::new(IDX); + + let (sock_addr, len) = addr.clone().into_storage(); + + assert_eq!(CanAddr::len() as socklen_t, len); + assert_eq!(as_bytes(&addr), &as_bytes(&sock_addr)[0..len as usize]); + } +} diff --git a/src/lib.rs b/src/lib.rs index ab267e79..c6e123a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,6 +115,9 @@ pub use embedded_can::{ pub mod errors; pub use errors::{CanError, CanErrorDecodingFailure, ConstructionError, Error, Result}; +pub mod addr; +pub use addr::CanAddr; + pub mod frame; pub use frame::{ CanAnyFrame, CanDataFrame, CanErrorFrame, CanFdFrame, CanFrame, CanRemoteFrame, Frame, @@ -124,7 +127,7 @@ pub use frame::{ pub mod dump; pub mod socket; -pub use socket::{CanAddr, CanFdSocket, CanFilter, CanSocket, ShouldRetry, Socket, SocketOptions}; +pub use socket::{CanFdSocket, CanFilter, CanSocket, ShouldRetry, Socket, SocketOptions}; #[cfg(feature = "netlink")] pub mod nl; diff --git a/src/socket.rs b/src/socket.rs index 2859c6da..26082964 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -13,14 +13,13 @@ use crate::{ frame::{can_frame_default, canfd_frame_default, AsPtr, CAN_ERR_MASK}, - CanAnyFrame, CanFdFrame, CanFrame, + CanAddr, CanAnyFrame, CanFdFrame, CanFrame, }; use libc::{ - can_frame, canid_t, fcntl, read, sa_family_t, setsockopt, sockaddr, sockaddr_can, - sockaddr_storage, socklen_t, suseconds_t, time_t, timeval, write, EINPROGRESS, F_GETFL, + can_frame, canid_t, fcntl, read, setsockopt, + socklen_t, suseconds_t, time_t, timeval, write, AF_CAN, EINPROGRESS, F_GETFL, F_SETFL, O_NONBLOCK, SOL_SOCKET, SO_RCVTIMEO, SO_SNDTIMEO, }; -use nix::net::if_::if_nametoindex; use socket2::SockAddr; use std::{ fmt, io, mem, @@ -33,8 +32,8 @@ use std::{ }; pub use libc::{ - AF_CAN, CANFD_MTU, CAN_MTU, CAN_RAW, CAN_RAW_ERR_FILTER, CAN_RAW_FD_FRAMES, CAN_RAW_FILTER, - CAN_RAW_JOIN_FILTERS, CAN_RAW_LOOPBACK, CAN_RAW_RECV_OWN_MSGS, PF_CAN, SOL_CAN_BASE, + CANFD_MTU, CAN_MTU, CAN_RAW, CAN_RAW_ERR_FILTER, CAN_RAW_FD_FRAMES, CAN_RAW_FILTER, + CAN_RAW_JOIN_FILTERS, CAN_RAW_LOOPBACK, CAN_RAW_RECV_OWN_MSGS, SOL_CAN_BASE, SOL_CAN_RAW, }; @@ -77,109 +76,6 @@ impl ShouldRetry for io::Result { } } -// ===== CanAddr ===== - -/// CAN socket address. -/// -/// This is the address for use with CAN sockets. It is simply an addres to -/// the SocketCAN host interface. It can be created by looking up the name -/// of the interface, like "can0", "vcan0", etc, or an interface index can -/// be specified directly, if known. An index of zero can be used to read -/// frames from all interfaces. -/// -/// This is based on, and compatible with, the `sockaddr_can` struct from -/// libc. -/// [ref](https://docs.rs/libc/latest/libc/struct.sockaddr_can.html) -#[derive(Clone, Copy)] -pub struct CanAddr(sockaddr_can); - -impl CanAddr { - /// Creates a new CAN socket address for the specified interface by index. - /// An index of zero can be used to read from all interfaces. - pub fn new(ifindex: u32) -> Self { - let mut addr = Self::default(); - addr.0.can_ifindex = ifindex as c_int; - addr - } - - /// Try to create an address from an interface name. - pub fn from_iface(ifname: &str) -> io::Result { - let ifindex = if_nametoindex(ifname)?; - Ok(Self::new(ifindex)) - } - - /// Gets the address of the structure as a `sockaddr_can` pointer. - pub fn as_ptr(&self) -> *const sockaddr_can { - &self.0 - } - - /// Gets the address of the structure as a `sockaddr` pointer. - pub fn as_sockaddr_ptr(&self) -> *const sockaddr { - self.as_ptr().cast() - } - - /// Gets the size of the address structure. - pub fn len() -> usize { - mem::size_of::() - } - - /// Converts the address into a `sockaddr_storage` type. - /// This is a generic socket address container with enough space to hold - /// any address type in the system. - pub fn into_storage(self) -> (sockaddr_storage, socklen_t) { - let can_addr = crate::as_bytes(&self.0); - let len = can_addr.len(); - - let mut storage: sockaddr_storage = unsafe { mem::zeroed() }; - let sock_addr = crate::as_bytes_mut(&mut storage); - - sock_addr[0..len].copy_from_slice(can_addr); - (storage, len as socklen_t) - } - - /// Converts the address into a `socket2::SockAddr` - pub fn into_sock_addr(self) -> SockAddr { - SockAddr::from(self) - } -} - -impl Default for CanAddr { - fn default() -> Self { - let mut addr: sockaddr_can = unsafe { mem::zeroed() }; - addr.can_family = AF_CAN as sa_family_t; - Self(addr) - } -} - -impl fmt::Debug for CanAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "CanAddr {{ can_family: {}, can_ifindex: {} }}", - self.0.can_family, self.0.can_ifindex - ) - } -} - -impl From for CanAddr { - fn from(addr: sockaddr_can) -> Self { - Self(addr) - } -} - -impl From for SockAddr { - fn from(addr: CanAddr) -> Self { - let (storage, len) = addr.into_storage(); - unsafe { SockAddr::new(storage, len) } - } -} - -impl AsRef for CanAddr { - fn as_ref(&self) -> &sockaddr_can { - &self.0 - } -} - // ===== Private local helper functions ===== fn c_timeval_new(t: Duration) -> timeval { @@ -776,30 +672,3 @@ impl AsRef for CanFilter { &self.0 } } - -///////////////////////////////////////////////////////////////////////////// - -#[cfg(test)] -mod tests { - use super::*; - use crate::as_bytes; - - const IDX: u32 = 42; - - #[test] - fn test_addr() { - let _addr = CanAddr::new(IDX); - - assert_eq!(mem::size_of::(), CanAddr::len()); - } - - #[test] - fn test_addr_to_sock_addr() { - let addr = CanAddr::new(IDX); - - let (sock_addr, len) = addr.clone().into_storage(); - - assert_eq!(CanAddr::len() as socklen_t, len); - assert_eq!(as_bytes(&addr), &as_bytes(&sock_addr)[0..len as usize]); - } -} diff --git a/src/tokio.rs b/src/tokio.rs index 558ca7de..dbe6c30c 100644 --- a/src/tokio.rs +++ b/src/tokio.rs @@ -31,7 +31,7 @@ use std::{ future::Future, io, os::unix::{ - io::{AsRawFd, FromRawFd}, + io::{AsRawFd, FromRawFd, OwnedFd}, prelude::RawFd, }, pin::Pin, @@ -109,7 +109,7 @@ impl event::Source for EventedCanSocket { #[derive(Debug)] pub struct AsyncCanSocket(AsyncFd>); -impl AsyncCanSocket { +impl> AsyncCanSocket { /// Open a named CAN device such as "can0, "vcan0", etc pub fn open(ifname: &str) -> io::Result { let sock = T::open(ifname)?; @@ -143,8 +143,8 @@ impl AsyncCanSocket { // the kernel worry about keeping track of references; // as long as one of the duplicated file descriptors is open // the socket as a whole isn't going to be closed. - let new_fd = libc::dup(fd); - let new = T::from_raw_fd(new_fd); + let new_fd = OwnedFd::from_raw_fd(libc::dup(fd)); + let new = T::from(new_fd); Ok(Self(AsyncFd::new(EventedCanSocket(new))?)) } }