1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
 * session/mod.rs - Types relating to generic CoAP sessions.
4
 * This file is part of the libcoap-rs crate, see the README and LICENSE files for
5
 * more information and terms of use.
6
 * Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved.
7
 * See the README as well as the LICENSE file for more information.
8
 */
9

            
10
use std::{
11
    any::Any,
12
    borrow::BorrowMut,
13
    cell::{Ref, RefMut},
14
    collections::{HashMap, VecDeque},
15
    marker::PhantomData,
16
    net::{SocketAddr, ToSocketAddrs},
17
    rc::Rc,
18
};
19

            
20
use libcoap_sys::{
21
    coap_context_t, coap_fixed_point_t, coap_mid_t, coap_new_message_id, coap_pdu_get_token, coap_pdu_t,
22
    coap_response_t, coap_send, coap_session_get_ack_random_factor, coap_session_get_ack_timeout,
23
    coap_session_get_addr_local, coap_session_get_addr_remote, coap_session_get_ifindex,
24
    coap_session_get_max_retransmit, coap_session_get_proto, coap_session_get_state, coap_session_get_type,
25
    coap_session_init_token, coap_session_max_pdu_size, coap_session_new_token, coap_session_send_ping,
26
    coap_session_set_ack_random_factor, coap_session_set_ack_timeout, coap_session_set_max_retransmit,
27
    coap_session_set_mtu, coap_session_state_t, coap_session_t, coap_session_type_t,
28
};
29
#[cfg(feature = "dtls-psk")]
30
use libcoap_sys::{coap_session_get_psk_hint, coap_session_get_psk_identity, coap_session_get_psk_key};
31

            
32
use self::sealed::{CoapSessionCommonInternal, CoapSessionInnerProvider};
33
pub use self::{client::CoapClientSession, server::CoapServerSession};
34
use crate::{
35
    error::{MessageConversionError, SessionGetAppDataError},
36
    message::{request::CoapRequest, response::CoapResponse, CoapMessage, CoapMessageCommon},
37
    protocol::CoapToken,
38
    types::{CoapAddress, CoapMessageId, CoapProtocol, IfIndex, MaxRetransmit},
39
};
40

            
41
pub mod client;
42

            
43
pub mod server;
44

            
45
/// Representation of the states that a session can be in.
46
#[repr(u32)]
47
pub enum CoapSessionState {
48
    None = coap_session_state_t::COAP_SESSION_STATE_NONE as u32,
49
    Connecting = coap_session_state_t::COAP_SESSION_STATE_CONNECTING as u32,
50
    Handshake = coap_session_state_t::COAP_SESSION_STATE_HANDSHAKE as u32,
51
    Csm = coap_session_state_t::COAP_SESSION_STATE_CSM as u32,
52
    Established = coap_session_state_t::COAP_SESSION_STATE_ESTABLISHED as u32,
53
}
54

            
55
impl From<coap_session_state_t> for CoapSessionState {
56
    fn from(raw_state: coap_session_state_t) -> Self {
57
        match raw_state {
58
            coap_session_state_t::COAP_SESSION_STATE_NONE => CoapSessionState::None,
59
            coap_session_state_t::COAP_SESSION_STATE_CONNECTING => CoapSessionState::Connecting,
60
            coap_session_state_t::COAP_SESSION_STATE_HANDSHAKE => CoapSessionState::Handshake,
61
            coap_session_state_t::COAP_SESSION_STATE_CSM => CoapSessionState::Csm,
62
            coap_session_state_t::COAP_SESSION_STATE_ESTABLISHED => CoapSessionState::Established,
63
            _ => unreachable!("unknown session state added"),
64
        }
65
    }
66
}
67

            
68
mod sealed {
69
    use super::*;
70

            
71
    /// Internal Trait for types that can provide a Ref(Mut) to CoapSessionInner instances.
72
    /// Implemented by the different session types ([CoapClientSession] and [CoapServerSession])
73
    pub trait CoapSessionInnerProvider<'a> {
74
        /// Provide a Ref to the instance of [CoapSessionInner] contained in this type.
75
        fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>>;
76

            
77
        /// Provide a RefMut to the instance of [CoapSessionInner] contained in this type.
78
        fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>>;
79
    }
80

            
81
    /// Functions common between all sessions that should not be public.
82
    ///
83
    /// This trait does not have any mandatory functions and will be automatically implemented for
84
    /// all types that implement [CoapSessionInnerProvider].
85
    pub trait CoapSessionCommonInternal<'a>: CoapSessionInnerProvider<'a> {
86
233
        fn add_response(&self, pdu: CoapResponse) {
87
233
            let token = pdu.token();
88
233
            if let Some(token) = token {
89
233
                if self.inner_ref().received_responses.contains_key(token) {
90
233
                    self.inner_mut()
91
233
                        .received_responses
92
233
                        .get_mut(token)
93
233
                        .unwrap()
94
233
                        .push_back(pdu);
95
233
                }
96
            }
97
233
        }
98
    }
99

            
100
    impl<'a, T: CoapSessionInnerProvider<'a>> CoapSessionCommonInternal<'a> for T {}
101
}
102

            
103
/// Trait for functions that are common between client and server sessions.
104
pub trait CoapSessionCommon<'a>: CoapSessionCommonInternal<'a> {
105
    /// Returns the application specific data stored alongside this session.
106
    fn app_data<T: Any>(&self) -> Result<Option<Rc<T>>, SessionGetAppDataError> {
107
        self.inner_ref()
108
            .app_data
109
            .as_ref()
110
            .map(|v| v.clone().downcast().map_err(|_v| SessionGetAppDataError::WrongType))
111
            .transpose()
112
    }
113

            
114
    /// Sets the application-specific data stored alongside this session.
115
    fn set_app_data<T: 'static+Any>(&self, value: Option<T>) {
116
        let mut inner = self.inner_mut();
117
        let new_box: Option<Rc<dyn Any>> = value.map(|v| Rc::new(v) as Rc<dyn Any>);
118
        inner.app_data = new_box;
119
    }
120

            
121
    /// Clears the application-specific data stored alongside this session.
122
    fn clear_app_data(&self) {
123
        let mut inner = self.inner_mut();
124
        inner.app_data = None;
125
    }
126

            
127
    /// Returns the Ack-Random-Factor used by libcoap.
128
    ///
129
    /// The returned value is a tuple consisting of an integer and a fractional part, where the
130
    /// fractional part is a value from 0-999 and represents the first three digits after the comma.
131
    fn ack_random_factor(&self) -> (u16, u16) {
132
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
133
        let random_factor = unsafe { coap_session_get_ack_random_factor(self.inner_ref().raw_session) };
134
        (random_factor.integer_part, random_factor.fractional_part)
135
    }
136

            
137
    /// Sets the Ack-Random-Factor used by libcoap.
138
    fn set_ack_random_factor(&self, integer_part: u16, fractional_part: u16) {
139
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
140
        unsafe {
141
            coap_session_set_ack_random_factor(
142
                self.inner_mut().raw_session,
143
                coap_fixed_point_t {
144
                    integer_part,
145
                    fractional_part,
146
                },
147
            )
148
        };
149
    }
150

            
151
    /// Returns the current value of the Acknowledgement Timeout for this session (in seconds).
152
    ///
153
    /// The returned value is a tuple consisting of an integer and a fractional part, where the
154
    /// fractional part is a value from 0-999 and represents the first three digits after the comma.
155
    fn ack_timeout(&self) -> (u16, u16) {
156
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
157
        let random_factor = unsafe { coap_session_get_ack_timeout(self.inner_ref().raw_session) };
158
        (random_factor.integer_part, random_factor.fractional_part)
159
    }
160

            
161
    /// Sets the value of the Acknowledgement Timeout for this session.
162
    fn set_ack_timeout(&self, integer_part: u16, fractional_part: u16) {
163
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
164
        unsafe {
165
            coap_session_set_ack_timeout(
166
                self.inner_ref().raw_session,
167
                coap_fixed_point_t {
168
                    integer_part,
169
                    fractional_part,
170
                },
171
            )
172
        };
173
    }
174

            
175
    /// Returns the local address for this session.
176
    fn addr_local(&self) -> SocketAddr {
177
        CoapAddress::from(unsafe {
178
            // This is infallible as long as the raw session is valid (which it always should be
179
            // as long as the invariants are kept).
180
            coap_session_get_addr_local(self.inner_ref().raw_session)
181
                .as_ref()
182
                .unwrap()
183
        })
184
        .to_socket_addrs()
185
        .unwrap()
186
        .next()
187
        .unwrap()
188
    }
189

            
190
    /// Returns the remote address for this session.
191
    fn addr_remote(&self) -> SocketAddr {
192
        CoapAddress::from(unsafe {
193
            // This is infallible as long as the raw session is valid (which it always should be
194
            // as long as the invariants are kept).
195
            coap_session_get_addr_remote(self.inner_ref().raw_session)
196
                .as_ref()
197
                .unwrap()
198
        })
199
        .to_socket_addrs()
200
        .unwrap()
201
        .next()
202
        .unwrap()
203
    }
204

            
205
    /// Returns the interface index for this session.
206
    fn if_index(&self) -> IfIndex {
207
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
208
        unsafe { coap_session_get_ifindex(self.inner_ref().raw_session) }
209
    }
210

            
211
    /// Returns the maximum number of retransmissions for this session.
212
    fn max_retransmit(&self) -> MaxRetransmit {
213
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
214
        unsafe { coap_session_get_max_retransmit(self.inner_ref().raw_session) }
215
    }
216

            
217
    /// Sets the maximum number of retransmissions for this session.
218
    fn set_max_retransmit(&mut self, value: MaxRetransmit) {
219
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
220
        unsafe { coap_session_set_max_retransmit(self.inner_ref().raw_session, value) }
221
    }
222

            
223
    /// Returns the underlying transport protocol used for this session.
224
25
    fn proto(&self) -> CoapProtocol {
225
25
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
226
25
        unsafe { coap_session_get_proto(self.inner_ref().raw_session) }.into()
227
25
    }
228

            
229
    /// Returns the current PSK hint for this session.
230
    #[cfg(feature = "dtls-psk")]
231
    fn psk_hint(&self) -> Option<Box<[u8]>> {
232
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
233
        unsafe {
234
            coap_session_get_psk_hint(self.inner_ref().raw_session)
235
                .as_ref()
236
                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
237
        }
238
    }
239

            
240
    /// Returns the current PSK identity for this session.
241
    #[cfg(feature = "dtls-psk")]
242
    fn psk_identity(&self) -> Option<Box<[u8]>> {
243
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
244
        unsafe {
245
            coap_session_get_psk_identity(self.inner_ref().raw_session)
246
                .as_ref()
247
                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
248
        }
249
    }
250

            
251
    /// Returns the current PSK key for this session.
252
    #[cfg(feature = "dtls-psk")]
253
    fn psk_key(&self) -> Option<Box<[u8]>> {
254
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
255
        unsafe {
256
            coap_session_get_psk_key(self.inner_ref().raw_session)
257
                .as_ref()
258
                .map(|raw_hint| Box::from(std::slice::from_raw_parts(raw_hint.s, raw_hint.length)))
259
        }
260
    }
261

            
262
    /// Returns the current state of this session.
263
    #[must_use = "getting the current session state without using it is a no-op"]
264
    fn state(&self) -> CoapSessionState {
265
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
266
        unsafe { coap_session_get_state(self.inner_ref().raw_session).into() }
267
    }
268

            
269
    /// Initializes the initial token value used by libcoap for this session.
270
    ///
271
    /// This value will be used as the token and incremented for each message sent through this
272
    /// session that does not already have a token set.
273
    fn init_token(&self, token: &[u8; 8]) {
274
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
275
        unsafe { coap_session_init_token(self.inner_mut().raw_session, token.len(), token.as_ptr()) }
276
    }
277

            
278
    /// Returns the maximum size of a PDU for this session.
279
50
    fn max_pdu_size(&self) -> usize {
280
50
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
281
50
        unsafe { coap_session_max_pdu_size(self.inner_ref().raw_session) }
282
50
    }
283

            
284
    /// Sets the maximum size of a PDU for this session.
285
    fn set_mtu(&self, mtu: u32) {
286
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
287
        unsafe { coap_session_set_mtu(self.inner_mut().raw_session, mtu) }
288
    }
289

            
290
    /// Returns the next message ID that should be used for this session.
291
25
    fn next_message_id(&self) -> CoapMessageId {
292
25
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
293
25
        unsafe { coap_new_message_id(self.inner_mut().raw_session) as CoapMessageId }
294
25
    }
295

            
296
    /// Returns the next token that should be used for requests.
297
    fn new_token(&mut self, token: &mut [u8; 8]) -> usize {
298
        let mut length = 8;
299
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
300
        unsafe { coap_session_new_token(self.inner_mut().raw_session, &mut length, token.as_mut_ptr()) }
301
        length
302
    }
303

            
304
    /// Send a ping message to the remote peer.
305
    fn send_ping(&mut self) -> CoapMessageId {
306
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
307
        unsafe { coap_session_send_ping(self.inner_mut().raw_session) }
308
    }
309

            
310
    /// Send the given message-like object to the peer.
311
    ///
312
    /// # Errors
313
    /// Returns a [MessageConversionError] if the supplied object cannot be converted to a message.
314
50
    fn send<P: Into<CoapMessage>>(&self, pdu: P) -> Result<CoapMessageId, MessageConversionError> {
315
50
        let raw_pdu = pdu.into().into_raw_pdu(self)?;
316
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner,
317
        // raw pdu should be valid as we got it from `into_raw_pdu()`.
318
50
        let mid = unsafe { coap_send(self.inner_mut().raw_session, raw_pdu) };
319
50
        Ok(mid)
320
50
    }
321

            
322
    /// Sends the given CoapRequest, returning a CoapRequestHandle that can be used to poll the
323
    /// request for completion.
324
    ///
325
    /// # Errors
326
    /// Returns a [MessageConversionError] if the given Request could not be converted into a raw
327
    /// message.
328
25
    fn send_request(&self, mut req: CoapRequest) -> Result<CoapRequestHandle, MessageConversionError> {
329
25
        if req.token().is_none() {
330
25
            let mut token_len = libcoap_sys::COAP_TOKEN_DEFAULT_MAX as usize;
331
25
            let mut token_tmp: Vec<u8> = vec![0; token_len];
332
25
            // SAFETY: Provided pointer is valid, length matches.
333
25
            unsafe {
334
25
                coap_session_new_token(self.inner_mut().raw_session, &mut token_len, token_tmp.as_mut_ptr());
335
25
            }
336
25
            req.set_token(Some(Vec::from(&token_tmp[0..token_len])))
337
        }
338
25
        let token: Box<[u8]> = Box::from(req.token().unwrap());
339
25
        if req.mid().is_none() {
340
25
            req.set_mid(Some(self.next_message_id()))
341
        }
342
25
        self.inner_mut()
343
25
            .received_responses
344
25
            .insert(token.clone(), VecDeque::new());
345
25
        self.send(req.into_message()).map(|v| CoapRequestHandle::new(v, token))
346
25
    }
347

            
348
    /// Polls whether the request for the given handle already has pending responses.
349
    ///
350
    /// Returns an iterator over all responses associated with the request.
351
    ///
352
    /// # Panics
353
    ///
354
    /// Panics if the provided handle does not refer to a valid token, i.e., because it belongs to
355
    /// a different session.
356
110
    fn poll_handle(&self, handle: &CoapRequestHandle) -> std::collections::vec_deque::IntoIter<CoapResponse> {
357
110
        self.inner_mut()
358
110
            .received_responses
359
110
            .insert(handle.token.clone(), VecDeque::new())
360
110
            .expect("Attempted to poll handle that does not refer to a valid token")
361
110
            .into_iter()
362
110
    }
363

            
364
    /// Returns whether this session waits for the provided token.
365
233
    fn is_waiting_for_token(&self, token: &CoapToken) -> bool {
366
233
        self.inner_ref().received_responses.contains_key(token)
367
233
    }
368

            
369
    /// Stops listening for responses to this request handle.
370
    ///
371
    /// Any future responses to the request associated with this handle will be responded to with an
372
    /// RST message.
373
    fn remove_handle(&self, handle: CoapRequestHandle) {
374
        self.inner_mut().received_responses.remove(&handle.token);
375
    }
376

            
377
    /// Returns a mutable reference to the underlying raw session.
378
    ///
379
    /// # Safety
380
    /// Do not do anything that would interfere with the functionality of this wrapper.
381
    /// Most importantly, *do not* free the session yourself.
382
    unsafe fn raw_session_mut(&self) -> *mut coap_session_t {
383
        self.inner_mut().raw_session
384
    }
385

            
386
    /// Returns a 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(&self) -> *const coap_session_t {
392
        self.inner_ref().raw_session
393
    }
394
}
395

            
396
impl<'a, T: CoapSessionCommonInternal<'a>> CoapSessionCommon<'a> for T {}
397

            
398
#[derive(Debug)]
399
/// The representation of a CoAP session.
400
///
401
/// This enum only provides functionality that is common between clients and servers (by
402
/// implementing [CoapSessionCommon]). If you require functionality specific to client- or
403
/// server-side sessions, match this enum on the required session type.
404
pub enum CoapSession<'a> {
405
    Client(CoapClientSession<'a>),
406

            
407
    Server(CoapServerSession<'a>),
408
}
409

            
410
impl<'a> CoapSessionInnerProvider<'a> for CoapSession<'a> {
411
466
    fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
412
466
        match self {
413
466
            CoapSession::Client(sess) => sess.inner_ref(),
414

            
415
            CoapSession::Server(sess) => sess.inner_ref(),
416
        }
417
466
    }
418

            
419
233
    fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
420
233
        match self {
421
233
            CoapSession::Client(sess) => sess.inner_mut(),
422

            
423
            CoapSession::Server(sess) => sess.inner_mut(),
424
        }
425
233
    }
426
}
427

            
428
impl<'a> CoapSession<'a> {
429
    /// Restores a CoapSession from its raw counterpart.
430
    ///
431
    /// Note that it is not possible to statically infer the lifetime of the created session from
432
    /// the raw pointer, i.e., the session will be created with an arbitrary lifetime.
433
    /// Therefore, callers of this function should ensure that the created session instance does not
434
    /// outlive the context it is bound to.
435
    /// Failing to do so will result in a panic/abort in the context destructor as it is unable to
436
    /// claim exclusive ownership of the session.
437
    ///
438
    /// # Panics
439
    ///
440
    /// Panics if the given pointer is a null pointer.
441
    ///
442
    /// # Safety
443
    /// The provided pointer must be valid, the provided session's app data must be a valid argument
444
    /// to [`CoapFfiRcCell<CoapClientSessionInner>::clone_raw_rc`](crate::mem::CoapFfiRcCell::clone_raw_rc)
445
    /// or [`CoapFfiRcCell<CoapServerSessionInner>::clone_raw_rc`](crate::mem::CoapFfiRcCell::clone_raw_rc)
446
    /// (depending on the session type).
447
524
    pub(crate) unsafe fn from_raw(raw_session: *mut coap_session_t) -> CoapSession<'a> {
448
524
        assert!(!raw_session.is_null(), "provided raw session was null");
449
524
        let raw_session_type = coap_session_get_type(raw_session);
450
524
        match raw_session_type {
451
            coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
452

            
453
396
            coap_session_type_t::COAP_SESSION_TYPE_CLIENT => CoapClientSession::from_raw(raw_session).into(),
454

            
455
            coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
456
128
                CoapServerSession::from_raw(raw_session).into()
457
            },
458
            _ => unreachable!("unknown session type"),
459
        }
460
524
    }
461
}
462

            
463
impl<'a> From<CoapClientSession<'a>> for CoapSession<'a> {
464
396
    fn from(session: CoapClientSession<'a>) -> Self {
465
396
        CoapSession::Client(session)
466
396
    }
467
}
468

            
469
impl<'a> From<CoapServerSession<'a>> for CoapSession<'a> {
470
396
    fn from(session: CoapServerSession<'a>) -> Self {
471
396
        CoapSession::Server(session)
472
396
    }
473
}
474

            
475
impl PartialEq for CoapSession<'_> {
476
    fn eq(&self, other: &Self) -> bool {
477
        match self {
478
            CoapSession::Client(cli_sess) => cli_sess.eq(other),
479

            
480
            CoapSession::Server(srv_sess) => srv_sess.eq(other),
481
        }
482
    }
483
}
484

            
485
impl Eq for CoapSession<'_> {}
486

            
487
/// Inner part of the representation of a CoapSession.
488
///
489
/// For internal use only, this is only public because of some limitations in Rusts type system
490
/// (as we would leak a private type).
491
#[derive(Debug)]
492
#[doc(hidden)]
493
pub struct CoapSessionInner<'a> {
494
    raw_session: *mut coap_session_t,
495
    app_data: Option<Rc<dyn Any>>,
496
    received_responses: HashMap<CoapToken, VecDeque<CoapResponse>>,
497
    _context_lifetime_marker: PhantomData<&'a coap_context_t>,
498
}
499

            
500
impl CoapSessionInner<'_> {
501
    /// Initializes a new session from its raw counterpart.
502
    ///
503
    /// Callers of this function should probably also insert themselves into the `app_data` pointer
504
    /// of the raw session to allow later retrieval (as is done for `CoapClientSession` and
505
    /// `CoapServerSession`.
506
    ///
507
    /// # Safety
508
    /// Provided pointer must point to a valid raw_session.
509
    ///
510
    /// Note that the chosen lifetime for the inner session is arbitrarily, so you should ensure
511
    /// that the CoapSessionInner instance does not outlive the underlying session.
512
    /// To do so, you probably want to increase the reference counter of the session by one and
513
    /// never provide values of this session with a lifetime that exceeds the one of the
514
    /// [CoapContext] this session is bound to.
515
501
    pub(crate) unsafe fn new<'a>(raw_session: *mut coap_session_t) -> CoapSessionInner<'a> {
516
501
        CoapSessionInner {
517
501
            raw_session,
518
501
            app_data: None,
519
501
            received_responses: HashMap::new(),
520
501
            _context_lifetime_marker: Default::default(),
521
501
        }
522
501
    }
523
}
524

            
525
/// A handle returned by CoAP sessions upon sending a request.
526
///
527
/// Can be used in calls to [CoapSessionCommon::poll_handle()] to check for responses to the sent
528
/// request.
529
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
530
pub struct CoapRequestHandle {
531
    _mid: CoapMessageId,
532
    token: CoapToken,
533
}
534

            
535
impl CoapRequestHandle {
536
25
    fn new<T: Into<Box<[u8]>>>(mid: CoapMessageId, token: T) -> CoapRequestHandle {
537
25
        CoapRequestHandle {
538
25
            _mid: mid,
539
25
            token: token.into(),
540
25
        }
541
25
    }
542
}
543

            
544
// This is fine, we don't read the C-type struct, we return it.
545
#[allow(improper_ctypes_definitions)]
546
233
pub(crate) unsafe extern "C" fn session_response_handler(
547
233
    session: *mut coap_session_t,
548
233
    _sent: *const coap_pdu_t,
549
233
    received: *const coap_pdu_t,
550
233
    _id: coap_mid_t,
551
233
) -> coap_response_t {
552
233
    let mut session = CoapSession::from_raw(session);
553
233
    let client = session.borrow_mut();
554
233
    // First check if the token is actually one we are currently waiting for.
555
233
    let raw_token = coap_pdu_get_token(received);
556
233
    let token: CoapToken = CoapToken::from(std::slice::from_raw_parts(raw_token.s, raw_token.length));
557
233
    if !client.is_waiting_for_token(&token) {
558
        return coap_response_t::COAP_RESPONSE_FAIL;
559
233
    }
560
233
    if let Ok(message) = CoapMessage::from_raw_pdu(received).and_then(CoapResponse::from_message) {
561
233
        client.add_response(message);
562
233
        coap_response_t::COAP_RESPONSE_OK
563
    } else {
564
        coap_response_t::COAP_RESPONSE_FAIL
565
    }
566
233
}