diff --git a/src/lib.rs b/src/lib.rs index afeb655..0a7a397 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ use bitflags::bitflags; pub use embedded_can::{ExtendedId, Id, StandardId}; use libc::{ bind, c_int, c_short, c_void, close, fcntl, read, setsockopt, sockaddr, socket, write, F_GETFL, - F_SETFL, O_NONBLOCK, SOCK_DGRAM, + F_SETFL, O_NONBLOCK, SOCK_DGRAM, SOL_SOCKET, SO_RCVTIMEO, }; use nix::net::if_::if_nametoindex; use std::convert::TryFrom; @@ -424,6 +424,7 @@ impl IsoTpSocket { Some(IsoTpOptions::default()), Some(FlowControlOptions::default()), Some(LinkLayerOptions::default()), + None, ) } @@ -438,6 +439,7 @@ impl IsoTpSocket { isotp_options: Option, rx_flow_control_options: Option, link_layer_options: Option, + rx_timeout: Option, ) -> Result { let if_index = if_nametoindex(ifname)?; Self::open_if_with_opts( @@ -447,6 +449,7 @@ impl IsoTpSocket { isotp_options, rx_flow_control_options, link_layer_options, + rx_timeout, ) } @@ -465,6 +468,7 @@ impl IsoTpSocket { Some(IsoTpOptions::default()), Some(FlowControlOptions::default()), Some(LinkLayerOptions::default()), + None, ) } @@ -478,6 +482,7 @@ impl IsoTpSocket { isotp_options: Option, rx_flow_control_options: Option, link_layer_options: Option, + rx_timeout: Option, ) -> Result { let rx_id = match rx_id.into() { Id::Standard(standard_id) => standard_id.as_raw() as u32, @@ -523,6 +528,38 @@ impl IsoTpSocket { } } + // Set receive timeout + if let Some(timeout) = rx_timeout { + let seconds = timeout.as_secs().try_into().map_err(|_| { + Error::from(io::Error::new( + io::ErrorKind::InvalidInput, + "Provided timeout too large for nix::sys::time::TimeVal.", + )) + })?; + // This conversion needs to be fallable as for 32-bit targets the value may not fit. + #[allow(clippy::unnecessary_fallible_conversions)] + let microseconds = timeout.subsec_micros().try_into().map_err(|_| { + Error::from(io::Error::new( + io::ErrorKind::InvalidInput, + "Provided timeout too large for nix::sys::time::TimeVal.", + )) + })?; + let tv = nix::sys::time::TimeVal::new(seconds, microseconds); + + let err = unsafe { + setsockopt( + sock_fd, + SOL_SOCKET, + SO_RCVTIMEO, + &tv as *const _ as *const c_void, + size_of::().try_into().unwrap(), + ) + }; + if err == -1 { + return Err(Error::from(io::Error::last_os_error())); + } + } + // Set FlowControlOptions if let Some(rx_flow_control_options) = rx_flow_control_options { let rx_flow_control_options_ptr: *const c_void =