Thanks to visit codestin.com
Credit goes to docs.rs

socketcan/
addr.rs

1// socketcan/src/lib.rs
2//
3// The main lib file for the Rust SocketCAN library.
4//
5// This file is part of the Rust 'socketcan-rs' library.
6//
7// Licensed under the MIT license:
8//   <LICENSE or http://opensource.org/licenses/MIT>
9// This file may not be copied, modified, or distributed except according
10// to those terms.
11
12//! SocketCAN address type.
13
14use crate::id::id_to_canid_t;
15use embedded_can::Id;
16use libc::{sa_family_t, sockaddr, sockaddr_can, sockaddr_storage, socklen_t};
17use nix::net::if_::if_nametoindex;
18use socket2::SockAddr;
19use std::{fmt, io, mem, mem::size_of, os::raw::c_int};
20
21pub use libc::{AF_CAN, CAN_RAW, PF_CAN};
22
23/// CAN socket address.
24///
25/// This is the address for use with CAN sockets. It is simply an address to
26/// the SocketCAN host interface. It can be created by looking up the name
27/// of the interface, like "can0", "vcan0", etc, or an interface index can
28/// be specified directly, if known. An index of zero can be used to read
29/// frames from all interfaces.
30///
31/// This is based on, and compatible with, the `sockaddr_can` struct from
32/// libc.
33/// [ref](https://docs.rs/libc/latest/libc/struct.sockaddr_can.html)
34#[derive(Clone, Copy)]
35pub struct CanAddr(sockaddr_can);
36
37impl CanAddr {
38    /// Creates a new CAN socket address for the specified interface by index.
39    /// An index of zero can be used to read from all interfaces.
40    pub fn new(ifindex: u32) -> Self {
41        let mut addr = Self::default();
42        addr.0.can_ifindex = ifindex as c_int;
43        addr
44    }
45
46    /// Creates a new CAN J1939 socket address for the specified interface
47    /// by index.
48    pub fn new_j1939(ifindex: u32, name: u64, pgn: u32, jaddr: u8) -> Self {
49        let mut addr = Self::new(ifindex);
50        addr.0.can_addr.j1939.name = name;
51        addr.0.can_addr.j1939.pgn = pgn;
52        addr.0.can_addr.j1939.addr = jaddr;
53        addr
54    }
55
56    /// Creates a new CAN ISO-TP socket address for the specified interface
57    /// by index.
58    pub fn new_isotp<R, T>(ifindex: u32, rx_id: R, tx_id: T) -> Self
59    where
60        R: Into<Id>,
61        T: Into<Id>,
62    {
63        let mut addr = Self::new(ifindex);
64        addr.0.can_addr.tp.rx_id = id_to_canid_t(rx_id);
65        addr.0.can_addr.tp.tx_id = id_to_canid_t(tx_id);
66        addr
67    }
68
69    /// Try to create an address from an interface name.
70    pub fn from_iface(ifname: &str) -> io::Result<Self> {
71        let ifindex = if_nametoindex(ifname)?;
72        Ok(Self::new(ifindex))
73    }
74
75    /// Try to create a J1939 address from an interface name.
76    pub fn from_iface_j1939(ifname: &str, name: u64, pgn: u32, jaddr: u8) -> io::Result<Self> {
77        let mut addr = Self::from_iface(ifname)?;
78        addr.0.can_addr.j1939.name = name;
79        addr.0.can_addr.j1939.pgn = pgn;
80        addr.0.can_addr.j1939.addr = jaddr;
81        Ok(addr)
82    }
83
84    /// Try to create a ISO-TP address from an interface name.
85    pub fn from_iface_isotp<R, T>(ifname: &str, rx_id: R, tx_id: T) -> io::Result<Self>
86    where
87        R: Into<Id>,
88        T: Into<Id>,
89    {
90        let mut addr = Self::from_iface(ifname)?;
91        addr.0.can_addr.tp.rx_id = id_to_canid_t(rx_id);
92        addr.0.can_addr.tp.tx_id = id_to_canid_t(tx_id);
93        Ok(addr)
94    }
95
96    /// Gets the address of the structure as a `sockaddr_can` pointer.
97    pub fn as_ptr(&self) -> *const sockaddr_can {
98        &self.0
99    }
100
101    /// Gets the address of the structure as a `sockaddr` pointer.
102    pub fn as_sockaddr_ptr(&self) -> *const sockaddr {
103        self.as_ptr().cast()
104    }
105
106    /// Gets the size of the address structure.
107    pub fn len() -> usize {
108        size_of::<sockaddr_can>()
109    }
110
111    /// Gets the underlying address as a byte slice
112    pub fn as_bytes(&self) -> &[u8] {
113        crate::as_bytes(&self.0)
114    }
115
116    /// Converts the address into a `sockaddr_storage` type.
117    /// The storage type is a generic socket address container with enough
118    /// space to hold any address in the system (not just CAN addresses).
119    pub fn into_storage(self) -> (sockaddr_storage, socklen_t) {
120        let can_addr = self.as_bytes();
121        let len = can_addr.len();
122
123        let mut storage: sockaddr_storage = unsafe { mem::zeroed() };
124        let sock_addr = crate::as_bytes_mut(&mut storage);
125
126        sock_addr[..len].copy_from_slice(can_addr);
127        (storage, len as socklen_t)
128    }
129
130    /// Converts the address into a `socket2::SockAddr`
131    pub fn into_sock_addr(self) -> SockAddr {
132        SockAddr::from(self)
133    }
134}
135
136impl Default for CanAddr {
137    fn default() -> Self {
138        let mut addr: sockaddr_can = unsafe { mem::zeroed() };
139        addr.can_family = AF_CAN as sa_family_t;
140        Self(addr)
141    }
142}
143
144impl fmt::Debug for CanAddr {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        write!(
147            f,
148            "CanAddr {{ can_family: {}, can_ifindex: {} }}",
149            self.0.can_family, self.0.can_ifindex
150        )
151    }
152}
153
154impl From<sockaddr_can> for CanAddr {
155    fn from(addr: sockaddr_can) -> Self {
156        Self(addr)
157    }
158}
159
160impl From<CanAddr> for SockAddr {
161    fn from(addr: CanAddr) -> Self {
162        let (storage, len) = addr.into_storage();
163        unsafe { SockAddr::new(storage, len) }
164    }
165}
166
167impl AsRef<sockaddr_can> for CanAddr {
168    fn as_ref(&self) -> &sockaddr_can {
169        &self.0
170    }
171}
172
173/////////////////////////////////////////////////////////////////////////////
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178    use crate::as_bytes;
179
180    const IDX: u32 = 42;
181
182    #[test]
183    fn test_addr() {
184        let _addr = CanAddr::new(IDX);
185
186        assert_eq!(size_of::<sockaddr_can>(), CanAddr::len());
187    }
188
189    #[test]
190    fn test_addr_to_sock_addr() {
191        let addr = CanAddr::new(IDX);
192
193        let (sock_addr, len) = addr.clone().into_storage();
194
195        assert_eq!(CanAddr::len() as socklen_t, len);
196        assert_eq!(as_bytes(&addr), &as_bytes(&sock_addr)[0..len as usize]);
197    }
198}