Skip to content

Commit

Permalink
Split out CanAddr into new addr module.
Browse files Browse the repository at this point in the history
  • Loading branch information
fpagliughi committed Oct 27, 2023
1 parent 1dc9b49 commit c69cd8d
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 141 deletions.
154 changes: 154 additions & 0 deletions src/addr.rs
Original file line number Diff line number Diff line change
@@ -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:
// <LICENSE or http://opensource.org/licenses/MIT>
// 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<Self> {
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::<sockaddr_can>()
}

/// 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<sockaddr_can> for CanAddr {
fn from(addr: sockaddr_can) -> Self {
Self(addr)
}
}

impl From<CanAddr> for SockAddr {
fn from(addr: CanAddr) -> Self {
let (storage, len) = addr.into_storage();
unsafe { SockAddr::new(storage, len) }
}
}

impl AsRef<sockaddr_can> 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::<sockaddr_can>(), 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]);
}
}
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
141 changes: 5 additions & 136 deletions src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
};

Expand Down Expand Up @@ -77,109 +76,6 @@ impl<E: fmt::Debug> ShouldRetry for io::Result<E> {
}
}

// ===== 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<Self> {
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::<sockaddr_can>()
}

/// 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<sockaddr_can> for CanAddr {
fn from(addr: sockaddr_can) -> Self {
Self(addr)
}
}

impl From<CanAddr> for SockAddr {
fn from(addr: CanAddr) -> Self {
let (storage, len) = addr.into_storage();
unsafe { SockAddr::new(storage, len) }
}
}

impl AsRef<sockaddr_can> for CanAddr {
fn as_ref(&self) -> &sockaddr_can {
&self.0
}
}

// ===== Private local helper functions =====

fn c_timeval_new(t: Duration) -> timeval {
Expand Down Expand Up @@ -776,30 +672,3 @@ impl AsRef<libc::can_filter> 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::<sockaddr_can>(), 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]);
}
}
8 changes: 4 additions & 4 deletions src/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use std::{
future::Future,
io,
os::unix::{
io::{AsRawFd, FromRawFd},
io::{AsRawFd, FromRawFd, OwnedFd},
prelude::RawFd,
},
pin::Pin,
Expand Down Expand Up @@ -109,7 +109,7 @@ impl<T: Socket> event::Source for EventedCanSocket<T> {
#[derive(Debug)]
pub struct AsyncCanSocket<T: Socket>(AsyncFd<EventedCanSocket<T>>);

impl<T: Socket + FromRawFd> AsyncCanSocket<T> {
impl<T: Socket + From<OwnedFd>> AsyncCanSocket<T> {
/// Open a named CAN device such as "can0, "vcan0", etc
pub fn open(ifname: &str) -> io::Result<Self> {
let sock = T::open(ifname)?;
Expand Down Expand Up @@ -143,8 +143,8 @@ impl<T: Socket + FromRawFd> AsyncCanSocket<T> {
// 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))?))
}
}
Expand Down

0 comments on commit c69cd8d

Please sign in to comment.