libcoap_rs/session/
mod.rs

1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * Copyright © The libcoap-rs Contributors, all rights reserved.
4 * This file is part of the libcoap-rs project, see the README file for
5 * general information on this project and the NOTICE.md and LICENSE files
6 * for information regarding copyright ownership and terms of use.
7 *
8 * session/mod.rs - Types relating to generic CoAP sessions.
9 */
10
11use std::{
12    any::Any,
13    borrow::BorrowMut,
14    cell::{Ref, RefMut},
15    collections::{HashMap, VecDeque},
16    marker::PhantomData,
17    net::{SocketAddr, ToSocketAddrs},
18    rc::Rc,
19};
20
21use libcoap_sys::{
22    coap_context_t, coap_fixed_point_t, coap_mid_t, coap_new_message_id, coap_pdu_get_token, coap_pdu_t,
23    coap_response_t, coap_response_t_COAP_RESPONSE_FAIL, coap_response_t_COAP_RESPONSE_OK, coap_send,
24    coap_session_get_ack_random_factor, coap_session_get_ack_timeout, coap_session_get_addr_local,
25    coap_session_get_addr_remote, coap_session_get_ifindex, coap_session_get_max_retransmit, coap_session_get_proto,
26    coap_session_get_state, coap_session_get_type, coap_session_init_token, coap_session_max_pdu_size,
27    coap_session_new_token, coap_session_send_ping, coap_session_set_ack_random_factor, coap_session_set_ack_timeout,
28    coap_session_set_max_retransmit, coap_session_set_mtu, coap_session_state_t,
29    coap_session_state_t_COAP_SESSION_STATE_CONNECTING, coap_session_state_t_COAP_SESSION_STATE_CSM,
30    coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED, coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE,
31    coap_session_state_t_COAP_SESSION_STATE_NONE, coap_session_t, coap_session_type_t_COAP_SESSION_TYPE_CLIENT,
32    coap_session_type_t_COAP_SESSION_TYPE_HELLO, coap_session_type_t_COAP_SESSION_TYPE_NONE,
33    coap_session_type_t_COAP_SESSION_TYPE_SERVER,
34};
35#[cfg(feature = "dtls-psk")]
36use libcoap_sys::{coap_session_get_psk_hint, coap_session_get_psk_identity, coap_session_get_psk_key};
37
38use self::sealed::{CoapSessionCommonInternal, CoapSessionInnerProvider};
39pub use self::{client::CoapClientSession, server::CoapServerSession};
40use crate::{
41    error::{MessageConversionError, SessionGetAppDataError},
42    message::{request::CoapRequest, response::CoapResponse, CoapMessage, CoapMessageCommon},
43    protocol::CoapToken,
44    types::{CoapAddress, CoapMessageId, CoapProtocol, IfIndex, MaxRetransmit},
45};
46
47pub mod client;
48
49pub mod server;
50
51/// Representation of the states that a session can be in.
52#[repr(u32)]
53pub enum CoapSessionState {
54    None = coap_session_state_t_COAP_SESSION_STATE_NONE as u32,
55    Connecting = coap_session_state_t_COAP_SESSION_STATE_CONNECTING as u32,
56    Handshake = coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE as u32,
57    Csm = coap_session_state_t_COAP_SESSION_STATE_CSM as u32,
58    Established = coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED as u32,
59}
60
61impl From<coap_session_state_t> for CoapSessionState {
62    fn from(raw_state: coap_session_state_t) -> Self {
63        // Variant names are named by bindgen, we have no influence on this.
64        // Ref: https://github.com/rust-lang/rust/issues/39371
65        #[allow(non_upper_case_globals)]
66        match raw_state {
67            coap_session_state_t_COAP_SESSION_STATE_NONE => CoapSessionState::None,
68            coap_session_state_t_COAP_SESSION_STATE_CONNECTING => CoapSessionState::Connecting,
69            coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE => CoapSessionState::Handshake,
70            coap_session_state_t_COAP_SESSION_STATE_CSM => CoapSessionState::Csm,
71            coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED => CoapSessionState::Established,
72            _ => unreachable!("unknown session state added"),
73        }
74    }
75}
76
77mod sealed {
78    use super::*;
79
80    /// Internal Trait for types that can provide a Ref(Mut) to CoapSessionInner instances.
81    /// Implemented by the different session types ([CoapClientSession] and [CoapServerSession])
82    pub trait CoapSessionInnerProvider<'a> {
83        /// Provide a Ref to the instance of [CoapSessionInner] contained in this type.
84        fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>>;
85
86        /// Provide a RefMut to the instance of [CoapSessionInner] contained in this type.
87        fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>>;
88    }
89
90    /// Functions common between all sessions that should not be public.
91    ///
92    /// This trait does not have any mandatory functions and will be automatically implemented for
93    /// all types that implement [CoapSessionInnerProvider].
94    pub trait CoapSessionCommonInternal<'a>: CoapSessionInnerProvider<'a> {
95        fn add_response(&self, pdu: CoapResponse) {
96            let token = pdu.token();
97            if let Some(token) = token {
98                if self.inner_ref().received_responses.contains_key(token) {
99                    self.inner_mut()
100                        .received_responses
101                        .get_mut(token)
102                        .unwrap()
103                        .push_back(pdu);
104                }
105            }
106        }
107    }
108
109    impl<'a, T: CoapSessionInnerProvider<'a>> CoapSessionCommonInternal<'a> for T {}
110}
111
112/// Trait for functions that are common between client and server sessions.
113pub trait CoapSessionCommon<'a>: CoapSessionCommonInternal<'a> {
114    /// Returns the application specific data stored alongside this session.
115    fn app_data<T: Any>(&self) -> Result<Option<Rc<T>>, SessionGetAppDataError> {
116        self.inner_ref()
117            .app_data
118            .as_ref()
119            .map(|v| v.clone().downcast().map_err(|_v| SessionGetAppDataError::WrongType))
120            .transpose()
121    }
122
123    /// Sets the application-specific data stored alongside this session.
124    fn set_app_data<T: 'static + Any>(&self, value: Option<T>) {
125        let mut inner = self.inner_mut();
126        let new_box: Option<Rc<dyn Any>> = value.map(|v| Rc::new(v) as Rc<dyn Any>);
127        inner.app_data = new_box;
128    }
129
130    /// Clears the application-specific data stored alongside this session.
131    fn clear_app_data(&self) {
132        let mut inner = self.inner_mut();
133        inner.app_data = None;
134    }
135
136    /// Returns the Ack-Random-Factor used by libcoap.
137    ///
138    /// The returned value is a tuple consisting of an integer and a fractional part, where the
139    /// fractional part is a value from 0-999 and represents the first three digits after the comma.
140    fn ack_random_factor(&self) -> (u16, u16) {
141        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
142        let random_factor = unsafe { coap_session_get_ack_random_factor(self.inner_ref().raw_session) };
143        (random_factor.integer_part, random_factor.fractional_part)
144    }
145
146    /// Sets the Ack-Random-Factor used by libcoap.
147    fn set_ack_random_factor(&self, integer_part: u16, fractional_part: u16) {
148        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
149        unsafe {
150            coap_session_set_ack_random_factor(
151                self.inner_mut().raw_session,
152                coap_fixed_point_t {
153                    integer_part,
154                    fractional_part,
155                },
156            )
157        };
158    }
159
160    /// Returns the current value of the Acknowledgement Timeout for this session (in seconds).
161    ///
162    /// The returned value is a tuple consisting of an integer and a fractional part, where the
163    /// fractional part is a value from 0-999 and represents the first three digits after the comma.
164    fn ack_timeout(&self) -> (u16, u16) {
165        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
166        let random_factor = unsafe { coap_session_get_ack_timeout(self.inner_ref().raw_session) };
167        (random_factor.integer_part, random_factor.fractional_part)
168    }
169
170    /// Sets the value of the Acknowledgement Timeout for this session.
171    fn set_ack_timeout(&self, integer_part: u16, fractional_part: u16) {
172        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
173        unsafe {
174            coap_session_set_ack_timeout(
175                self.inner_ref().raw_session,
176                coap_fixed_point_t {
177                    integer_part,
178                    fractional_part,
179                },
180            )
181        };
182    }
183
184    /// Returns the local address for this session.
185    fn addr_local(&self) -> SocketAddr {
186        CoapAddress::from(unsafe {
187            // This is infallible as long as the raw session is valid (which it always should be
188            // as long as the invariants are kept).
189            coap_session_get_addr_local(self.inner_ref().raw_session)
190                .as_ref()
191                .unwrap()
192        })
193        .to_socket_addrs()
194        .unwrap()
195        .next()
196        .unwrap()
197    }
198
199    /// Returns the remote address for this session.
200    fn addr_remote(&self) -> SocketAddr {
201        CoapAddress::from(unsafe {
202            // This is infallible as long as the raw session is valid (which it always should be
203            // as long as the invariants are kept).
204            coap_session_get_addr_remote(self.inner_ref().raw_session)
205                .as_ref()
206                .unwrap()
207        })
208        .to_socket_addrs()
209        .unwrap()
210        .next()
211        .unwrap()
212    }
213
214    /// Returns the interface index for this session.
215    fn if_index(&self) -> IfIndex {
216        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
217        unsafe { coap_session_get_ifindex(self.inner_ref().raw_session) }
218    }
219
220    /// Returns the maximum number of retransmissions for this session.
221    fn max_retransmit(&self) -> MaxRetransmit {
222        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
223        unsafe { coap_session_get_max_retransmit(self.inner_ref().raw_session) }
224    }
225
226    /// Sets the maximum number of retransmissions for this session.
227    fn set_max_retransmit(&mut self, value: MaxRetransmit) {
228        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
229        unsafe { coap_session_set_max_retransmit(self.inner_ref().raw_session, value) }
230    }
231
232    /// Returns the underlying transport protocol used for this session.
233    fn proto(&self) -> CoapProtocol {
234        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
235        unsafe { coap_session_get_proto(self.inner_ref().raw_session) }.into()
236    }
237
238    /// Returns the current PSK hint for this session.
239    #[cfg(feature = "dtls-psk")]
240    fn psk_hint(&self) -> Option<Box<[u8]>> {
241        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
242        unsafe {
243            coap_session_get_psk_hint(self.inner_ref().raw_session)
244                .as_ref()
245                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
246        }
247    }
248
249    /// Returns the current PSK identity for this session.
250    #[cfg(feature = "dtls-psk")]
251    fn psk_identity(&self) -> Option<Box<[u8]>> {
252        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
253        unsafe {
254            coap_session_get_psk_identity(self.inner_ref().raw_session)
255                .as_ref()
256                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
257        }
258    }
259
260    /// Returns the current PSK key for this session.
261    #[cfg(feature = "dtls-psk")]
262    fn psk_key(&self) -> Option<Box<[u8]>> {
263        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
264        unsafe {
265            coap_session_get_psk_key(self.inner_ref().raw_session)
266                .as_ref()
267                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
268        }
269    }
270
271    /// Returns the current state of this session.
272    #[must_use = "getting the current session state without using it is a no-op"]
273    fn state(&self) -> CoapSessionState {
274        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
275        unsafe { coap_session_get_state(self.inner_ref().raw_session).into() }
276    }
277
278    /// Initializes the initial token value used by libcoap for this session.
279    ///
280    /// This value will be used as the token and incremented for each message sent through this
281    /// session that does not already have a token set.
282    fn init_token(&self, token: &[u8; 8]) {
283        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
284        unsafe { coap_session_init_token(self.inner_mut().raw_session, token.len(), token.as_ptr()) }
285    }
286
287    /// Returns the maximum size of a PDU for this session.
288    fn max_pdu_size(&self) -> usize {
289        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
290        unsafe { coap_session_max_pdu_size(self.inner_ref().raw_session) }
291    }
292
293    /// Sets the maximum size of a PDU for this session.
294    fn set_mtu(&self, mtu: u32) {
295        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
296        unsafe { coap_session_set_mtu(self.inner_mut().raw_session, mtu) }
297    }
298
299    /// Returns the next message ID that should be used for this session.
300    fn next_message_id(&self) -> CoapMessageId {
301        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
302        unsafe { coap_new_message_id(self.inner_mut().raw_session) as CoapMessageId }
303    }
304
305    /// Returns the next token that should be used for requests.
306    fn new_token(&mut self, token: &mut [u8; 8]) -> usize {
307        let mut length = 8;
308        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
309        unsafe { coap_session_new_token(self.inner_mut().raw_session, &mut length, token.as_mut_ptr()) }
310        length
311    }
312
313    /// Send a ping message to the remote peer.
314    fn send_ping(&mut self) -> CoapMessageId {
315        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
316        unsafe { coap_session_send_ping(self.inner_mut().raw_session) }
317    }
318
319    /// Send the given message-like object to the peer.
320    ///
321    /// # Errors
322    /// Returns a [MessageConversionError] if the supplied object cannot be converted to a message.
323    fn send<P: Into<CoapMessage>>(&self, pdu: P) -> Result<CoapMessageId, MessageConversionError> {
324        let raw_pdu = pdu.into().into_raw_pdu(self)?;
325        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner,
326        // raw pdu should be valid as we got it from `into_raw_pdu()`.
327        let mid = unsafe { coap_send(self.inner_mut().raw_session, raw_pdu) };
328        Ok(mid)
329    }
330
331    /// Sends the given CoapRequest, returning a CoapRequestHandle that can be used to poll the
332    /// request for completion.
333    ///
334    /// # Errors
335    /// Returns a [MessageConversionError] if the given Request could not be converted into a raw
336    /// message.
337    fn send_request(&self, mut req: CoapRequest) -> Result<CoapRequestHandle, MessageConversionError> {
338        if req.token().is_none() {
339            let mut token_len = libcoap_sys::COAP_TOKEN_DEFAULT_MAX as usize;
340            let mut token_tmp: Vec<u8> = vec![0; token_len];
341            // SAFETY: Provided pointer is valid, length matches.
342            unsafe {
343                coap_session_new_token(self.inner_mut().raw_session, &mut token_len, token_tmp.as_mut_ptr());
344            }
345            req.set_token(Some(Vec::from(&token_tmp[0..token_len])))
346        }
347        let token: Box<[u8]> = Box::from(req.token().unwrap());
348        if req.mid().is_none() {
349            req.set_mid(Some(self.next_message_id()))
350        }
351        self.inner_mut()
352            .received_responses
353            .insert(token.clone(), VecDeque::new());
354        self.send(req.into_message()).map(|v| CoapRequestHandle::new(v, token))
355    }
356
357    /// Polls whether the request for the given handle already has pending responses.
358    ///
359    /// Returns an iterator over all responses associated with the request.
360    ///
361    /// # Panics
362    ///
363    /// Panics if the provided handle does not refer to a valid token, i.e., because it belongs to
364    /// a different session.
365    fn poll_handle(&self, handle: &CoapRequestHandle) -> std::collections::vec_deque::IntoIter<CoapResponse> {
366        self.inner_mut()
367            .received_responses
368            .insert(handle.token.clone(), VecDeque::new())
369            .expect("Attempted to poll handle that does not refer to a valid token")
370            .into_iter()
371    }
372
373    /// Returns whether this session waits for the provided token.
374    fn is_waiting_for_token(&self, token: &CoapToken) -> bool {
375        self.inner_ref().received_responses.contains_key(token)
376    }
377
378    /// Stops listening for responses to this request handle.
379    ///
380    /// Any future responses to the request associated with this handle will be responded to with an
381    /// RST message.
382    fn remove_handle(&self, handle: CoapRequestHandle) {
383        self.inner_mut().received_responses.remove(&handle.token);
384    }
385
386    /// Returns a mutable reference to the underlying raw session.
387    ///
388    /// # Safety
389    /// Do not do anything that would interfere with the functionality of this wrapper.
390    /// Most importantly, *do not* free the session yourself.
391    unsafe fn raw_session_mut(&self) -> *mut coap_session_t {
392        self.inner_mut().raw_session
393    }
394
395    /// Returns a reference to the underlying raw session.
396    ///
397    /// # Safety
398    /// Do not do anything that would interfere with the functionality of this wrapper.
399    /// Most importantly, *do not* free the session yourself.
400    unsafe fn raw_session(&self) -> *const coap_session_t {
401        self.inner_ref().raw_session
402    }
403}
404
405impl<'a, T: CoapSessionCommonInternal<'a>> CoapSessionCommon<'a> for T {}
406
407#[derive(Debug)]
408/// The representation of a CoAP session.
409///
410/// This enum only provides functionality that is common between clients and servers (by
411/// implementing [CoapSessionCommon]). If you require functionality specific to client- or
412/// server-side sessions, match this enum on the required session type.
413pub enum CoapSession<'a> {
414    Client(CoapClientSession<'a>),
415
416    Server(CoapServerSession<'a>),
417}
418
419impl<'a> CoapSessionInnerProvider<'a> for CoapSession<'a> {
420    fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
421        match self {
422            CoapSession::Client(sess) => sess.inner_ref(),
423
424            CoapSession::Server(sess) => sess.inner_ref(),
425        }
426    }
427
428    fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
429        match self {
430            CoapSession::Client(sess) => sess.inner_mut(),
431
432            CoapSession::Server(sess) => sess.inner_mut(),
433        }
434    }
435}
436
437impl<'a> CoapSession<'a> {
438    /// Restores a CoapSession from its raw counterpart.
439    ///
440    /// Note that it is not possible to statically infer the lifetime of the created session from
441    /// the raw pointer, i.e., the session will be created with an arbitrary lifetime.
442    /// Therefore, callers of this function should ensure that the created session instance does not
443    /// outlive the context it is bound to.
444    /// Failing to do so will result in a panic/abort in the context destructor as it is unable to
445    /// claim exclusive ownership of the session.
446    ///
447    /// # Panics
448    ///
449    /// Panics if the given pointer is a null pointer.
450    ///
451    /// # Safety
452    /// The provided pointer must be valid, the provided session's app data must be a valid argument
453    /// to [`CoapFfiRcCell<CoapClientSessionInner>::clone_raw_rc`](crate::mem::CoapFfiRcCell::clone_raw_rc)
454    /// or [`CoapFfiRcCell<CoapServerSessionInner>::clone_raw_rc`](crate::mem::CoapFfiRcCell::clone_raw_rc)
455    /// (depending on the session type).
456    pub(crate) unsafe fn from_raw(raw_session: *mut coap_session_t) -> CoapSession<'a> {
457        assert!(!raw_session.is_null(), "provided raw session was null");
458        let raw_session_type = coap_session_get_type(raw_session);
459
460        // Variant names are named by bindgen, we have no influence on this.
461        // Ref: https://github.com/rust-lang/rust/issues/39371
462        #[allow(non_upper_case_globals)]
463        match raw_session_type {
464            coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
465
466            coap_session_type_t_COAP_SESSION_TYPE_CLIENT => CoapClientSession::from_raw(raw_session).into(),
467
468            coap_session_type_t_COAP_SESSION_TYPE_SERVER | coap_session_type_t_COAP_SESSION_TYPE_HELLO => {
469                CoapServerSession::from_raw(raw_session).into()
470            },
471            _ => unreachable!("unknown session type"),
472        }
473    }
474}
475
476impl<'a> From<CoapClientSession<'a>> for CoapSession<'a> {
477    fn from(session: CoapClientSession<'a>) -> Self {
478        CoapSession::Client(session)
479    }
480}
481
482impl<'a> From<CoapServerSession<'a>> for CoapSession<'a> {
483    fn from(session: CoapServerSession<'a>) -> Self {
484        CoapSession::Server(session)
485    }
486}
487
488impl PartialEq for CoapSession<'_> {
489    fn eq(&self, other: &Self) -> bool {
490        match self {
491            CoapSession::Client(cli_sess) => cli_sess.eq(other),
492
493            CoapSession::Server(srv_sess) => srv_sess.eq(other),
494        }
495    }
496}
497
498impl Eq for CoapSession<'_> {}
499
500/// Inner part of the representation of a CoapSession.
501///
502/// For internal use only, this is only public because of some limitations in Rusts type system
503/// (as we would leak a private type).
504#[derive(Debug)]
505#[doc(hidden)]
506pub struct CoapSessionInner<'a> {
507    raw_session: *mut coap_session_t,
508    app_data: Option<Rc<dyn Any>>,
509    received_responses: HashMap<CoapToken, VecDeque<CoapResponse>>,
510    _context_lifetime_marker: PhantomData<&'a coap_context_t>,
511}
512
513impl CoapSessionInner<'_> {
514    /// Initializes a new session from its raw counterpart.
515    ///
516    /// Callers of this function should probably also insert themselves into the `app_data` pointer
517    /// of the raw session to allow later retrieval (as is done for `CoapClientSession` and
518    /// `CoapServerSession`.
519    ///
520    /// # Safety
521    /// Provided pointer must point to a valid raw_session.
522    ///
523    /// Note that the chosen lifetime for the inner session is arbitrarily, so you should ensure
524    /// that the CoapSessionInner instance does not outlive the underlying session.
525    /// To do so, you probably want to increase the reference counter of the session by one and
526    /// never provide values of this session with a lifetime that exceeds the one of the
527    /// [CoapContext] this session is bound to.
528    pub(crate) unsafe fn new<'a>(raw_session: *mut coap_session_t) -> CoapSessionInner<'a> {
529        CoapSessionInner {
530            raw_session,
531            app_data: None,
532            received_responses: HashMap::new(),
533            _context_lifetime_marker: Default::default(),
534        }
535    }
536}
537
538/// A handle returned by CoAP sessions upon sending a request.
539///
540/// Can be used in calls to [CoapSessionCommon::poll_handle()] to check for responses to the sent
541/// request.
542#[derive(Debug, Clone, PartialEq, Eq, Hash)]
543pub struct CoapRequestHandle {
544    _mid: CoapMessageId,
545    token: CoapToken,
546}
547
548impl CoapRequestHandle {
549    fn new<T: Into<Box<[u8]>>>(mid: CoapMessageId, token: T) -> CoapRequestHandle {
550        CoapRequestHandle {
551            _mid: mid,
552            token: token.into(),
553        }
554    }
555}
556
557// This is fine, we don't read the C-type struct, we return it.
558pub(crate) unsafe extern "C" fn session_response_handler(
559    session: *mut coap_session_t,
560    _sent: *const coap_pdu_t,
561    received: *const coap_pdu_t,
562    _id: coap_mid_t,
563) -> coap_response_t {
564    let mut session = CoapSession::from_raw(session);
565    let client = session.borrow_mut();
566    // First check if the token is actually one we are currently waiting for.
567    let raw_token = coap_pdu_get_token(received);
568    let token: CoapToken = CoapToken::from(std::slice::from_raw_parts(raw_token.s, raw_token.length));
569    if !client.is_waiting_for_token(&token) {
570        return coap_response_t_COAP_RESPONSE_FAIL;
571    }
572    if let Ok(message) = CoapMessage::from_raw_pdu(received).and_then(CoapResponse::from_message) {
573        client.add_response(message);
574        coap_response_t_COAP_RESPONSE_OK
575    } else {
576        coap_response_t_COAP_RESPONSE_FAIL
577    }
578}