Skip to content

Commit c6076ba

Browse files
committed
Get rid of the Epoch for most use cases
1 parent 7934ffe commit c6076ba

10 files changed

Lines changed: 120 additions & 161 deletions

File tree

rs-matter/src/dm.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use core::future::Future;
1919
use core::num::NonZeroU8;
2020
use core::pin::pin;
21-
use core::time::Duration;
2221

2322
use embassy_futures::select::select3;
2423
use embassy_time::{Instant, Timer};
@@ -375,7 +374,7 @@ where
375374
async fn write(
376375
&self,
377376
exchange: &mut Exchange<'_>,
378-
timeout_instant: Option<Duration>,
377+
timeout_instant: Option<Instant>,
379378
is_groupcast: bool,
380379
) -> Result<(), Error> {
381380
while exchange.rx().is_ok() {
@@ -418,7 +417,7 @@ where
418417
async fn invoke(
419418
&self,
420419
exchange: &mut Exchange<'_>,
421-
timeout_instant: Option<Duration>,
420+
timeout_instant: Option<Instant>,
422421
is_groupcast: bool,
423422
) -> Result<(), Error> {
424423
let Some((mut tx, rx)) = self.buffers(exchange).await? else {
@@ -725,11 +724,11 @@ where
725724
}
726725

727726
/// Process a `TimedReq` request, which is used to set a timeout for the following Write/Invoke request.
728-
async fn timed(&self, exchange: &mut Exchange<'_>) -> Result<Duration, Error> {
727+
async fn timed(&self, exchange: &mut Exchange<'_>) -> Result<Instant, Error> {
729728
let req = TimedReq::from_tlv(&get_root_node_struct(exchange.rx()?.payload())?)?;
730729
debug!("IM: Timed request: {:?}", req);
731730

732-
let timeout_instant = req.timeout_instant(exchange.matter().epoch());
731+
let timeout_instant = req.timeout_instant();
733732

734733
Self::send_status(exchange, IMStatusCode::Success).await?;
735734

@@ -740,14 +739,14 @@ where
740739
async fn timed_out(
741740
&self,
742741
exchange: &mut Exchange<'_>,
743-
timeout_instant: Option<Duration>,
742+
timeout_instant: Option<Instant>,
744743
timed_req: bool,
745744
) -> Result<bool, Error> {
746745
let status = {
747746
if timed_req != timeout_instant.is_some() {
748747
Some(IMStatusCode::TimedRequestMisMatch)
749748
} else if timeout_instant
750-
.map(|timeout_instant| (exchange.matter().epoch())() > timeout_instant)
749+
.map(|timeout_instant| Instant::now() > timeout_instant)
751750
.unwrap_or(false)
752751
{
753752
Some(IMStatusCode::Timeout)

rs-matter/src/failsafe.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
*/
1717

1818
use core::num::NonZeroU8;
19-
use core::time::Duration;
19+
20+
use embassy_time::{Duration, Instant};
2021

2122
use crate::cert::{CertRef, MAX_CERT_TLV_LEN};
2223
use crate::crypto::{
@@ -34,7 +35,6 @@ use crate::sc::pase::Pase;
3435
use crate::tlv::TLVElement;
3536
use crate::transport::session::SessionMode;
3637
use crate::utils::bitflags::bitflags;
37-
use crate::utils::epoch::Epoch;
3838
use crate::utils::init::{init, Init};
3939
use crate::utils::storage::Vec;
4040

@@ -53,7 +53,7 @@ bitflags! {
5353

5454
#[derive(PartialEq)]
5555
pub struct ArmedCtx {
56-
armed_at: Duration,
56+
armed_at: Instant,
5757
timeout_secs: u16,
5858
fab_idx: u8,
5959
flags: NocFlags,
@@ -91,28 +91,25 @@ pub struct FailSafe {
9191
state: State,
9292
secret_key: CanonPkcSecretKey,
9393
root_ca: Vec<u8, { MAX_CERT_TLV_LEN }>,
94-
epoch: Epoch,
9594
breadcrumb: u64,
9695
}
9796

9897
impl FailSafe {
9998
#[inline(always)]
100-
pub const fn new(epoch: Epoch) -> Self {
99+
pub const fn new() -> Self {
101100
Self {
102101
state: State::Idle,
103102
secret_key: PKC_SECRET_KEY_ZEROED,
104103
root_ca: Vec::new(),
105-
epoch,
106104
breadcrumb: 0,
107105
}
108106
}
109107

110-
pub fn init(epoch: Epoch) -> impl Init<Self> {
108+
pub fn init() -> impl Init<Self> {
111109
init!(Self {
112110
state: State::Idle,
113111
secret_key <- CanonPkcSecretKey::init(),
114112
root_ca <- Vec::init(),
115-
epoch,
116113
breadcrumb: 0
117114
})
118115
}
@@ -136,8 +133,12 @@ impl FailSafe {
136133
N: NetworksAccess,
137134
{
138135
if let State::Armed(ctx) = &self.state {
139-
let now = (self.epoch)();
140-
if now >= ctx.armed_at + Duration::from_secs(ctx.timeout_secs as u64) {
136+
let now = Instant::now();
137+
if now
138+
>= ctx
139+
.armed_at
140+
.saturating_add(Duration::from_secs(ctx.timeout_secs as u64))
141+
{
141142
// Timeout path: no caller exchange to preserve, so wipe
142143
// every PASE session along with the fabric / networks
143144
// rollback.
@@ -270,7 +271,7 @@ impl FailSafe {
270271
// }
271272

272273
self.state = State::Armed(ArmedCtx {
273-
armed_at: (self.epoch)(),
274+
armed_at: Instant::now(),
274275
timeout_secs,
275276
fab_idx: session_mode.fab_idx(),
276277
flags: NocFlags::empty(),
@@ -295,7 +296,7 @@ impl FailSafe {
295296
};
296297

297298
if timeout_secs > 0 {
298-
ctx.armed_at = (self.epoch)();
299+
ctx.armed_at = Instant::now();
299300
ctx.timeout_secs = timeout_secs;
300301
self.breadcrumb = breadcrumb;
301302
} else {
@@ -802,3 +803,9 @@ impl FailSafe {
802803
}
803804
}
804805
}
806+
807+
impl Default for FailSafe {
808+
fn default() -> Self {
809+
Self::new()
810+
}
811+
}

rs-matter/src/im/timed.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@
1717

1818
//! This module contains types related to the Timed Request feature in the Matter Interaction Model.
1919
20-
use core::time::Duration;
20+
use embassy_time::{Duration, Instant};
2121

2222
use crate::dm::GlobalElements;
2323
use crate::im::IM_REVISION;
2424
use crate::tlv::{FromTLV, ToTLV};
25-
use crate::utils::epoch::Epoch;
2625

2726
/// A structure representing a timed request in the Interaction Model.
2827
///
@@ -48,9 +47,11 @@ impl TimedReq {
4847
}
4948
}
5049

51-
/// Returns the moment in time - since the system epoch - when the request
52-
/// following this timed request should be considered expired.
53-
pub fn timeout_instant(&self, epoch: Epoch) -> Duration {
54-
unwrap!(epoch().checked_add(Duration::from_millis(self.timeout as _)))
50+
/// Returns the monotonic [`Instant`] at which the request following this
51+
/// timed request should be considered expired.
52+
///
53+
/// Saturates to [`Instant::MAX`] if the addition would overflow.
54+
pub fn timeout_instant(&self) -> Instant {
55+
Instant::now().saturating_add(Duration::from_millis(self.timeout as _))
5556
}
5657
}

rs-matter/src/lib.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl<'a> Matter<'a> {
204204
port: u16,
205205
) -> Self {
206206
Self {
207-
state: Mutex::new(RefCell::new(MatterState::new(epoch))),
207+
state: Mutex::new(RefCell::new(MatterState::new())),
208208
transport: Transport::new(dev_det),
209209
mdns_changed: Notification::new(),
210210
session_removed: Notification::new(),
@@ -261,7 +261,7 @@ impl<'a> Matter<'a> {
261261
) -> impl Init<Self> {
262262
init!(
263263
Self {
264-
state <- Mutex::init(RefCell::init(MatterState::init(epoch))),
264+
state <- Mutex::init(RefCell::init(MatterState::init())),
265265
transport <- Transport::init(dev_det),
266266
mdns_changed: Notification::new(),
267267
session_removed: Notification::new(),
@@ -704,23 +704,23 @@ pub struct MatterState {
704704
impl MatterState {
705705
/// Create a new instance of MatterState
706706
#[inline(always)]
707-
const fn new(epoch: Epoch) -> Self {
707+
const fn new() -> Self {
708708
Self {
709709
fabrics: Fabrics::new(),
710-
sessions: Sessions::new(epoch),
711-
pase: Pase::new(epoch),
712-
failsafe: FailSafe::new(epoch),
710+
sessions: Sessions::new(),
711+
pase: Pase::new(),
712+
failsafe: FailSafe::new(),
713713
basic_info_settings: BasicInfoSettings::new(),
714714
}
715715
}
716716

717717
/// Return an in-place initializer for MatterState
718-
fn init(epoch: Epoch) -> impl Init<Self> {
718+
fn init() -> impl Init<Self> {
719719
init!(Self {
720720
fabrics <- Fabrics::init(),
721-
sessions <- Sessions::init(epoch),
722-
pase <- Pase::init(epoch),
723-
failsafe <- FailSafe::init(epoch),
721+
sessions <- Sessions::init(),
722+
pase <- Pase::init(),
723+
failsafe <- FailSafe::init(),
724724
basic_info_settings <- BasicInfoSettings::init(),
725725
})
726726
}

rs-matter/src/sc/pase.rs

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
//! of the PASE protocol for establishing secure sessions using a shared passcode.
2222
2323
use core::num::NonZeroU8;
24-
use core::ops::Add;
25-
use core::time::Duration;
24+
25+
use embassy_time::{Duration, Instant};
2626

2727
use crate::dm::clusters::adm_comm::{self};
2828
use crate::dm::endpoints::ROOT_ENDPOINT_ID;
@@ -34,7 +34,6 @@ use crate::sc::pase::spake2p::{
3434
use crate::sc::SessionParameters;
3535
use crate::tlv::{FromTLV, OctetStr, ToTLV};
3636
use crate::transport::exchange::{Exchange, ExchangeId};
37-
use crate::utils::epoch::Epoch;
3837
use crate::utils::init::{init, Init};
3938
use crate::utils::maybe::Maybe;
4039
use crate::MatterService;
@@ -95,7 +94,7 @@ pub struct CommWindow {
9594
/// The opener info
9695
opener: Option<CommWindowOpener>,
9796
/// The window expiry instant
98-
window_expiry: Duration,
97+
window_expiry: Instant,
9998
/// Number of failed PAKE handshake attempts within this window.
10099
/// Per Matter Core spec section 11.18.6.1.5, the window SHALL be
101100
/// revoked after 20 unsuccessful handshakes.
@@ -118,7 +117,7 @@ impl CommWindow {
118117
salt: Spake2pVerifierSaltRef<'a>,
119118
discriminator: u16,
120119
opener: Option<CommWindowOpener>,
121-
window_expiry: Duration,
120+
window_expiry: Instant,
122121
) -> impl Init<Self> + 'a {
123122
init!(Self {
124123
mdns_id,
@@ -146,7 +145,7 @@ impl CommWindow {
146145
count: u32,
147146
discriminator: u16,
148147
opener: Option<CommWindowOpener>,
149-
window_expiry: Duration,
148+
window_expiry: Instant,
150149
) -> impl Init<Self> + 'a {
151150
init!(Self {
152151
mdns_id,
@@ -189,34 +188,23 @@ pub struct Pase {
189188
/// The (one and only) PASE session timeout tracker
190189
/// If there is no active PASE session, this is `None`
191190
pub(crate) session_timeout: Option<SessionEstTimeout>,
192-
/// The epoch function
193-
pub(crate) epoch: Epoch,
194191
}
195192

196193
impl Pase {
197194
/// Create a new PASE state
198-
///
199-
/// # Arguments
200-
/// - `epoch` - The epoch function
201195
#[inline(always)]
202-
pub const fn new(epoch: Epoch) -> Self {
196+
pub const fn new() -> Self {
203197
Self {
204198
comm_window: Maybe::none(),
205199
session_timeout: None,
206-
epoch,
207200
}
208201
}
209202

210203
/// Return an in-place initializer for the PASE manager
211-
///
212-
/// # Arguments
213-
/// - `epoch` - The epoch function
214-
/// - `rand` - The random number generator
215-
pub fn init(epoch: Epoch) -> impl Init<Self> {
204+
pub fn init() -> impl Init<Self> {
216205
init!(Self {
217206
comm_window <- Maybe::init_none(),
218207
session_timeout: None,
219-
epoch,
220208
})
221209
}
222210

@@ -232,7 +220,7 @@ impl Pase {
232220
let expired = self
233221
.comm_window
234222
.as_opt_ref()
235-
.map(|comm_window| (self.epoch)() > comm_window.window_expiry)
223+
.map(|comm_window| Instant::now() > comm_window.window_expiry)
236224
.unwrap_or(false);
237225

238226
if expired {
@@ -285,7 +273,7 @@ impl Pase {
285273
Err(ErrorCode::InvalidCommand)?;
286274
}
287275

288-
let window_expiry = (self.epoch)().add(Duration::from_secs(timeout_secs as _));
276+
let window_expiry = Instant::now().saturating_add(Duration::from_secs(timeout_secs as _));
289277

290278
self.comm_window
291279
.reinit(Maybe::init_some(CommWindow::init_with_pw(
@@ -342,7 +330,7 @@ impl Pase {
342330
Err(ErrorCode::InvalidCommand)?;
343331
}
344332

345-
let window_expiry = (self.epoch)().add(Duration::from_secs(timeout_secs as _));
333+
let window_expiry = Instant::now().saturating_add(Duration::from_secs(timeout_secs as _));
346334

347335
self.comm_window.reinit(Maybe::init_some(CommWindow::init(
348336
mdns_id,
@@ -433,6 +421,12 @@ impl Pase {
433421
}
434422
}
435423

424+
impl Default for Pase {
425+
fn default() -> Self {
426+
Self::new()
427+
}
428+
}
429+
436430
/// The timeout tracker for a PASE session establishment
437431
const PASE_SESSION_EST_TIMEOUT_SECS: Duration = Duration::from_secs(60);
438432

@@ -442,30 +436,23 @@ pub(crate) const SPAKE2_SESSION_KEYS_INFO: &[u8] = b"SessionKeys";
442436
/// The PASE session establishment timeout tracker
443437
pub(crate) struct SessionEstTimeout {
444438
/// The session expiry instant
445-
session_est_expiry: Duration,
439+
session_est_expiry: Instant,
446440
/// The exchange identifier
447441
pub(crate) exch_id: ExchangeId,
448442
}
449443

450444
impl SessionEstTimeout {
451-
/// Create a new session establishment timeout tracker
452-
///
453-
/// # Arguments
454-
/// - `exchange` - The exchange
455-
/// - `epoch` - The epoch function
456-
pub(crate) fn new(exchange: &Exchange, epoch: Epoch) -> Self {
445+
/// Create a new session establishment timeout tracker.
446+
pub(crate) fn new(exchange: &Exchange) -> Self {
457447
Self {
458-
session_est_expiry: epoch().add(PASE_SESSION_EST_TIMEOUT_SECS),
448+
session_est_expiry: Instant::now().saturating_add(PASE_SESSION_EST_TIMEOUT_SECS),
459449
exch_id: exchange.id(),
460450
}
461451
}
462452

463-
/// Check if the session establishment has expired
464-
///
465-
/// # Arguments
466-
/// - `epoch` - The current epoch
467-
pub(crate) fn is_sess_expired(&self, epoch: Epoch) -> bool {
468-
epoch() > self.session_est_expiry
453+
/// Check if the session establishment has expired.
454+
pub(crate) fn is_sess_expired(&self) -> bool {
455+
Instant::now() > self.session_est_expiry
469456
}
470457
}
471458

0 commit comments

Comments
 (0)