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

            
11
use 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

            
21
use 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")]
36
use libcoap_sys::{coap_session_get_psk_hint, coap_session_get_psk_identity, coap_session_get_psk_key};
37

            
38
use self::sealed::{CoapSessionCommonInternal, CoapSessionInnerProvider};
39
pub use self::{client::CoapClientSession, server::CoapServerSession};
40
use 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

            
47
pub mod client;
48

            
49
pub mod server;
50

            
51
/// Representation of the states that a session can be in.
52
#[repr(u32)]
53
pub 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

            
61
impl 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

            
77
mod 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
233
        fn add_response(&self, pdu: CoapResponse) {
96
233
            let token = pdu.token();
97
233
            if let Some(token) = token {
98
233
                if self.inner_ref().received_responses.contains_key(token) {
99
233
                    self.inner_mut()
100
233
                        .received_responses
101
233
                        .get_mut(token)
102
233
                        .unwrap()
103
233
                        .push_back(pdu);
104
233
                }
105
            }
106
233
        }
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.
113
pub 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
25
    fn proto(&self) -> CoapProtocol {
234
25
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
235
25
        unsafe { coap_session_get_proto(self.inner_ref().raw_session) }.into()
236
25
    }
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
50
    fn max_pdu_size(&self) -> usize {
289
50
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
290
50
        unsafe { coap_session_max_pdu_size(self.inner_ref().raw_session) }
291
50
    }
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
25
    fn next_message_id(&self) -> CoapMessageId {
301
25
        // SAFETY: Provided session pointer being valid is an invariant of CoapSessionInner
302
25
        unsafe { coap_new_message_id(self.inner_mut().raw_session) as CoapMessageId }
303
25
    }
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
50
    fn send<P: Into<CoapMessage>>(&self, pdu: P) -> Result<CoapMessageId, MessageConversionError> {
324
50
        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
50
        let mid = unsafe { coap_send(self.inner_mut().raw_session, raw_pdu) };
328
50
        Ok(mid)
329
50
    }
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
25
    fn send_request(&self, mut req: CoapRequest) -> Result<CoapRequestHandle, MessageConversionError> {
338
25
        if req.token().is_none() {
339
25
            let mut token_len = libcoap_sys::COAP_TOKEN_DEFAULT_MAX as usize;
340
25
            let mut token_tmp: Vec<u8> = vec![0; token_len];
341
25
            // SAFETY: Provided pointer is valid, length matches.
342
25
            unsafe {
343
25
                coap_session_new_token(self.inner_mut().raw_session, &mut token_len, token_tmp.as_mut_ptr());
344
25
            }
345
25
            req.set_token(Some(Vec::from(&token_tmp[0..token_len])))
346
        }
347
25
        let token: Box<[u8]> = Box::from(req.token().unwrap());
348
25
        if req.mid().is_none() {
349
25
            req.set_mid(Some(self.next_message_id()))
350
        }
351
25
        self.inner_mut()
352
25
            .received_responses
353
25
            .insert(token.clone(), VecDeque::new());
354
25
        self.send(req.into_message()).map(|v| CoapRequestHandle::new(v, token))
355
25
    }
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
110
    fn poll_handle(&self, handle: &CoapRequestHandle) -> std::collections::vec_deque::IntoIter<CoapResponse> {
366
110
        self.inner_mut()
367
110
            .received_responses
368
110
            .insert(handle.token.clone(), VecDeque::new())
369
110
            .expect("Attempted to poll handle that does not refer to a valid token")
370
110
            .into_iter()
371
110
    }
372

            
373
    /// Returns whether this session waits for the provided token.
374
233
    fn is_waiting_for_token(&self, token: &CoapToken) -> bool {
375
233
        self.inner_ref().received_responses.contains_key(token)
376
233
    }
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

            
405
impl<'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.
413
pub enum CoapSession<'a> {
414
    Client(CoapClientSession<'a>),
415

            
416
    Server(CoapServerSession<'a>),
417
}
418

            
419
impl<'a> CoapSessionInnerProvider<'a> for CoapSession<'a> {
420
466
    fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
421
466
        match self {
422
466
            CoapSession::Client(sess) => sess.inner_ref(),
423

            
424
            CoapSession::Server(sess) => sess.inner_ref(),
425
        }
426
466
    }
427

            
428
233
    fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
429
233
        match self {
430
233
            CoapSession::Client(sess) => sess.inner_mut(),
431

            
432
            CoapSession::Server(sess) => sess.inner_mut(),
433
        }
434
233
    }
435
}
436

            
437
impl<'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
534
    pub(crate) unsafe fn from_raw(raw_session: *mut coap_session_t) -> CoapSession<'a> {
457
534
        assert!(!raw_session.is_null(), "provided raw session was null");
458
534
        let raw_session_type = coap_session_get_type(raw_session);
459
534

            
460
534
        // Variant names are named by bindgen, we have no influence on this.
461
534
        // Ref: https://github.com/rust-lang/rust/issues/39371
462
534
        #[allow(non_upper_case_globals)]
463
534
        match raw_session_type {
464
            coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
465

            
466
401
            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
133
                CoapServerSession::from_raw(raw_session).into()
470
            },
471
            _ => unreachable!("unknown session type"),
472
        }
473
534
    }
474
}
475

            
476
impl<'a> From<CoapClientSession<'a>> for CoapSession<'a> {
477
401
    fn from(session: CoapClientSession<'a>) -> Self {
478
401
        CoapSession::Client(session)
479
401
    }
480
}
481

            
482
impl<'a> From<CoapServerSession<'a>> for CoapSession<'a> {
483
401
    fn from(session: CoapServerSession<'a>) -> Self {
484
401
        CoapSession::Server(session)
485
401
    }
486
}
487

            
488
impl 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

            
498
impl 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)]
506
pub 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

            
513
impl 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
501
    pub(crate) unsafe fn new<'a>(raw_session: *mut coap_session_t) -> CoapSessionInner<'a> {
529
501
        CoapSessionInner {
530
501
            raw_session,
531
501
            app_data: None,
532
501
            received_responses: HashMap::new(),
533
501
            _context_lifetime_marker: Default::default(),
534
501
        }
535
501
    }
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)]
543
pub struct CoapRequestHandle {
544
    _mid: CoapMessageId,
545
    token: CoapToken,
546
}
547

            
548
impl CoapRequestHandle {
549
25
    fn new<T: Into<Box<[u8]>>>(mid: CoapMessageId, token: T) -> CoapRequestHandle {
550
25
        CoapRequestHandle {
551
25
            _mid: mid,
552
25
            token: token.into(),
553
25
        }
554
25
    }
555
}
556

            
557
// This is fine, we don't read the C-type struct, we return it.
558
233
pub(crate) unsafe extern "C" fn session_response_handler(
559
233
    session: *mut coap_session_t,
560
233
    _sent: *const coap_pdu_t,
561
233
    received: *const coap_pdu_t,
562
233
    _id: coap_mid_t,
563
233
) -> coap_response_t {
564
233
    let mut session = CoapSession::from_raw(session);
565
233
    let client = session.borrow_mut();
566
233
    // First check if the token is actually one we are currently waiting for.
567
233
    let raw_token = coap_pdu_get_token(received);
568
233
    let token: CoapToken = CoapToken::from(std::slice::from_raw_parts(raw_token.s, raw_token.length));
569
233
    if !client.is_waiting_for_token(&token) {
570
        return coap_response_t_COAP_RESPONSE_FAIL;
571
233
    }
572
233
    if let Ok(message) = CoapMessage::from_raw_pdu(received).and_then(CoapResponse::from_message) {
573
233
        client.add_response(message);
574
233
        coap_response_t_COAP_RESPONSE_OK
575
    } else {
576
        coap_response_t_COAP_RESPONSE_FAIL
577
    }
578
233
}