libcoap_rs/session/
server.rs

1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * session/server.rs - Types relating to client-side 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
10use std::cell::{Ref, RefMut};
11
12use libcoap_sys::{
13    coap_session_get_app_data, coap_session_get_type, coap_session_reference, coap_session_release,
14    coap_session_set_app_data, coap_session_t, coap_session_type_t,
15};
16
17use crate::mem::CoapFfiRcCell;
18use crate::mem::DropInnerExclusively;
19
20use super::{CoapSessionCommon, CoapSessionInner, CoapSessionInnerProvider};
21
22impl DropInnerExclusively for CoapServerSession<'_> {
23    fn drop_exclusively(self) {
24        let sess_ref = self.inner.clone();
25        std::mem::drop(self);
26        sess_ref.drop_exclusively();
27    }
28}
29
30/// Representation of a server-side CoAP session.
31#[derive(Debug, Clone)]
32pub struct CoapServerSession<'a> {
33    /// Inner part of this server-side session
34    /// A weak version of this reference is stored inside of the user/app data pointer in the
35    /// raw session struct so that it can be passed through the FFI barrier.
36    inner: CoapFfiRcCell<CoapServerSessionInner<'a>>,
37}
38
39#[derive(Debug)]
40/// Inner part of a server-side CoAP session.
41struct CoapServerSessionInner<'a> {
42    inner: CoapSessionInner<'a>,
43}
44
45impl CoapServerSession<'_> {
46    /// Creates a CoapServerSession from a raw session.
47    ///
48    /// This function will increment the libcoap-internal reference counter for the session by one.
49    /// Dropping the CoapServerSession will then decrement it again.
50    ///
51    /// # Panics
52    /// Panics if the given pointer is a null pointer or the raw session is not a server-side
53    /// session.
54    ///
55    /// # Safety
56    /// The provided pointer must be valid for the entire (here arbitrarily chosen) lifetime of the
57    /// CoapServerSession<'a>, most notably the program will abort if the [CoapContext] is dropped
58    /// before this session is.
59    /// The existing value in the `app_data` field of the raw session will be overridden.
60    /// Make sure that this is actually okay to do so — most importantly, no other [CoapSession] may
61    /// already be stored there.
62    ///
63    /// If you wish to restore an existing [CoapSession] from its raw counterpart, use
64    /// [from_raw()](CoapServerSession::from_raw) instead.
65    pub(crate) unsafe fn initialize_raw<'a>(raw_session: *mut coap_session_t) -> CoapServerSession<'a> {
66        assert!(!raw_session.is_null(), "provided raw session was null");
67        let raw_session_type = coap_session_get_type(raw_session);
68        let inner = CoapSessionInner::new(raw_session);
69        let session_inner = match raw_session_type {
70            coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
71            coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
72                panic!("attempted to create server session from raw client session")
73            },
74            coap_session_type_t::COAP_SESSION_TYPE_SERVER => CoapServerSessionInner { inner },
75            coap_session_type_t::COAP_SESSION_TYPE_HELLO => CoapServerSessionInner { inner },
76            _ => unreachable!("unknown session type"),
77        };
78        let session_ref = CoapFfiRcCell::new(session_inner);
79        coap_session_set_app_data(raw_session, session_ref.create_raw_weak());
80        // Increase libcoap-internal reference counter for raw session so that it doesn't get freed
81        // as long as this CoapServerSession instance exists.
82        coap_session_reference(raw_session);
83        CoapServerSession { inner: session_ref }
84    }
85
86    /// Restores a [CoapServerSession] from its raw counterpart.
87    ///
88    /// Make sure that this struct cannot outlive the [CoapContext] its session originates from, as
89    /// the lifetime cannot be inferred by the compiler and dropping the context will panic/abort if
90    /// the inner session is still referenced anywhere else.
91    ///
92    /// This function will increment the libcoap-internal reference counter for the session by one.
93    /// Dropping the CoapServerSession will then decrement it again.
94    ///
95    /// # Panics
96    /// Panics if the provided raw session pointer or its app_data field is null or the raw session
97    /// is not a server-side session.
98    ///
99    /// # Safety
100    /// The provided pointer must be valid for the entire lifetime of this struct.
101    pub(crate) unsafe fn from_raw<'a>(raw_session: *mut coap_session_t) -> CoapServerSession<'a> {
102        assert!(!raw_session.is_null(), "provided raw session was null");
103        let raw_session_type = coap_session_get_type(raw_session);
104        match raw_session_type {
105            coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
106            coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
107                let raw_app_data_ptr = coap_session_get_app_data(raw_session);
108                assert!(!raw_app_data_ptr.is_null(), "provided raw session has no app data");
109                // Increase libcoap-internal reference counter for raw session so that it doesn't get freed
110                // as long as this CoapServerSession instance exists.
111                coap_session_reference(raw_session);
112                CoapServerSession {
113                    inner: CoapFfiRcCell::clone_raw_rc(raw_app_data_ptr),
114                }
115            },
116            coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
117                panic!("attempted to create CoapServerSession from raw client session")
118            },
119            _ => unreachable!("unknown session type"),
120        }
121    }
122}
123
124impl<'a> Drop for CoapServerSession<'a> {
125    fn drop(&mut self) {
126        let raw_session = self.inner.borrow_mut().inner.raw_session;
127        // Decrease libcoap-internal reference counter for raw session so that we don't leak memory.
128        unsafe {
129            coap_session_release(raw_session);
130        }
131    }
132}
133
134impl<'a> CoapSessionInnerProvider<'a> for CoapServerSession<'a> {
135    fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
136        Ref::map(self.inner.borrow(), |v| &v.inner)
137    }
138    fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
139        RefMut::map(self.inner.borrow_mut(), |v| &mut v.inner)
140    }
141}
142
143impl<'a, T: CoapSessionCommon<'a>> PartialEq<T> for CoapServerSession<'_> {
144    fn eq(&self, other: &T) -> bool {
145        // SAFETY: Pointers are only compared, never accessed.
146        self.if_index() == other.if_index()
147            && unsafe { self.raw_session() == other.raw_session() }
148            && self.addr_local() == other.addr_local()
149            && self.addr_remote() == other.addr_remote()
150    }
151}
152
153impl Eq for CoapServerSession<'_> {}
154
155impl Drop for CoapServerSessionInner<'_> {
156    fn drop(&mut self) {
157        unsafe {
158            let app_data = coap_session_get_app_data(self.inner.raw_session);
159            assert!(!app_data.is_null());
160            std::mem::drop(CoapFfiRcCell::<CoapServerSessionInner>::raw_ptr_to_weak(app_data));
161        }
162    }
163}