Skip to content

Commit

Permalink
fix(lib): Ensure libcoap is initialized before calling coap_* functions
Browse files Browse the repository at this point in the history
  • Loading branch information
pulsastrix committed Aug 16, 2024
1 parent ac689a4 commit 25db012
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 7 deletions.
17 changes: 10 additions & 7 deletions libcoap/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use libcoap_sys::{
coap_context_set_keepalive, coap_context_set_max_handshake_sessions, coap_context_set_max_idle_sessions, coap_context_set_psk2,
coap_context_set_session_timeout, coap_context_t, coap_dtls_spsk_info_t, COAP_DTLS_SPSK_SETUP_VERSION, coap_dtls_spsk_t, coap_event_t,
coap_free_context, coap_get_app_data, coap_io_process, COAP_IO_WAIT, coap_new_context,
coap_proto_t, coap_register_event_handler, coap_register_response_handler, coap_set_app_data, coap_startup,
coap_proto_t, coap_register_event_handler, coap_register_response_handler, coap_set_app_data,
coap_startup_with_feature_checks,
};

#[cfg(feature = "dtls")]
Expand All @@ -46,6 +47,13 @@ use crate::transport::CoapEndpoint;

static COAP_STARTUP_ONCE: Once = Once::new();

#[inline(always)]
pub(crate) fn ensure_coap_started() {
COAP_STARTUP_ONCE.call_once(|| unsafe {

Check warning on line 52 in libcoap/src/context.rs

View workflow job for this annotation

GitHub Actions / clippy (libcoap-rs)

[clippy (libcoap-rs)] libcoap/src/context.rs#L52

warning: unnecessary `unsafe` block --> libcoap/src/context.rs:52:36 | 52 | COAP_STARTUP_ONCE.call_once(|| unsafe { | ^^^^^^ unnecessary `unsafe` block | = note: `#[warn(unused_unsafe)]` on by default
Raw output
libcoap/src/context.rs:52:36:w:warning: unnecessary `unsafe` block
  --> libcoap/src/context.rs:52:36
   |
52 |     COAP_STARTUP_ONCE.call_once(|| unsafe {
   |                                    ^^^^^^ unnecessary `unsafe` block
   |
   = note: `#[warn(unused_unsafe)]` on by default


__END__
coap_startup_with_feature_checks();
});
}

#[derive(Debug)]
struct CoapContextInner<'a> {
/// Reference to the raw context this context wraps around.
Expand Down Expand Up @@ -96,12 +104,7 @@ impl<'a> CoapContext<'a> {
/// Returns an error if the underlying libcoap library was unable to create a new context
/// (probably an allocation error?).
pub fn new() -> Result<CoapContext<'a>, ContextCreationError> {
// TODO this should actually be done before calling _any_ libcoap function, not just the
// context initialization. Maybe we need to make sure to call this in other places too
// (e.g. if a resource is initialized before a context is created).
COAP_STARTUP_ONCE.call_once(|| unsafe {
coap_startup();
});
ensure_coap_started();
// SAFETY: Providing null here is fine, the context will just not be bound to an endpoint
// yet.
let raw_context = unsafe { coap_new_context(std::ptr::null()) };
Expand Down
3 changes: 3 additions & 0 deletions libcoap/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use crate::{
session::CoapSessionCommon,
types::CoapMessageId,
};
use crate::context::ensure_coap_started;
use crate::protocol::{Echo, Oscore, RequestTag};
use crate::types::{
decode_var_len_u16, decode_var_len_u32, decode_var_len_u8, encode_var_len_u16, encode_var_len_u32,
Expand Down Expand Up @@ -373,6 +374,7 @@ pub struct CoapMessage {
impl CoapMessage {
/// Creates a new CoAP message with the given type and code.
pub fn new(type_: CoapMessageType, code: CoapMessageCode) -> CoapMessage {
ensure_coap_started();
CoapMessage {
type_,
code,
Expand All @@ -388,6 +390,7 @@ impl CoapMessage {
/// # Safety
/// raw_pdu must point to a valid instance of coap_pdu_t.
pub unsafe fn from_raw_pdu(raw_pdu: *const coap_pdu_t) -> Result<CoapMessage, MessageConversionError> {
ensure_coap_started();
let mut option_iter = MaybeUninit::zeroed();
coap_option_iterator_init(raw_pdu, option_iter.as_mut_ptr(), std::ptr::null());
let mut option_iter = option_iter.assume_init();
Expand Down
4 changes: 4 additions & 0 deletions libcoap/src/prng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rand::{CryptoRng, RngCore};

use libcoap_sys::{coap_prng, coap_prng_init, coap_set_prng};

use crate::context::ensure_coap_started;
use crate::error::RngError;

// TODO If we can assert that libcoap's own thread-safety features are enabled at some point, we
Expand Down Expand Up @@ -53,6 +54,7 @@ static COAP_RNG_ACCESS_MUTEX: Mutex<()> = Mutex::new(());
/// # Result::<(), RngError>::Ok(())
/// ```
pub fn coap_prng_try_fill(dest: &mut [u8]) -> Result<(), RngError> {
ensure_coap_started();
let _acc_mutex = COAP_RNG_ACCESS_MUTEX.lock()?;
// SAFETY: Supplied pointer and length describe the provided slice.
match unsafe { coap_prng(dest.as_mut_ptr() as *mut c_void, dest.len()) } {
Expand Down Expand Up @@ -100,6 +102,7 @@ impl RngCore for CoapRng {
/// May return an error if the mutex for seeding the PRNG is poisoned, i.e. there was some panic
/// in a previous attempt of seeding the PRNG.
pub fn seed_coap_prng(seed: c_uint) -> Result<(), RngError> {
ensure_coap_started();
let guard = COAP_RNG_SEED_MUTEX.lock()?;
unsafe {
coap_prng_init(seed);
Expand Down Expand Up @@ -160,6 +163,7 @@ pub fn seed_coap_prng(seed: c_uint) -> Result<(), RngError> {
/// ```
#[cfg(feature = "rand")]
pub fn set_coap_prng<RNG: RngCore + CryptoRng + Send + Sync + 'static>(rng: RNG) -> Result<(), RngError> {
ensure_coap_started();
let mut guard = COAP_RNG_FN_MUTEX.lock()?;
*guard = Some(Box::new(rng));
// SAFETY: Pointer is valid and pointed to function does what libcoap expects.
Expand Down
3 changes: 3 additions & 0 deletions libcoap/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use libcoap_sys::{
};

use crate::{error::MessageConversionError, message::CoapMessage, protocol::CoapRequestCode};
use crate::context::ensure_coap_started;
use crate::mem::{CoapFfiRcCell, DropInnerExclusively};
use crate::message::CoapMessageCommon;
use crate::message::request::CoapRequest;
Expand Down Expand Up @@ -240,6 +241,7 @@ impl<D: Any + ?Sized + Debug> CoapResource<D> {
/// The `notify_con` parameter specifies whether observe notifications originating from this
/// resource are sent as confirmable or non-confirmable.
pub fn new<C: Into<Box<D>>>(uri_path: &str, user_data: C, notify_con: bool) -> CoapResource<D> {
ensure_coap_started();
let inner = unsafe {
let uri_path = coap_new_str_const(uri_path.as_ptr(), uri_path.len());
let raw_resource = coap_resource_init(
Expand Down Expand Up @@ -491,6 +493,7 @@ impl<D: 'static + ?Sized + Debug> CoapRequestHandler<D> {
response_pdu: *mut coap_pdu_t,
),
) -> CoapRequestHandler<D> {
ensure_coap_started();
let handler_fn: Option<Box<dyn FnMut(&CoapResource<D>, &mut CoapServerSession, &CoapRequest, CoapResponse)>> =
None;
CoapRequestHandler {
Expand Down
2 changes: 2 additions & 0 deletions libcoap/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use libcoap_sys::{
};
use libcoap_sys::coap_uri_scheme_t::{COAP_URI_SCHEME_COAP_WS, COAP_URI_SCHEME_COAPS_WS};

use crate::context::ensure_coap_started;
use crate::error::UriParsingError;
use crate::message::CoapOption;
use crate::protocol::UriPort;
Expand Down Expand Up @@ -736,6 +737,7 @@ impl CoapUri {
) -> Result<CoapUri, UriParsingError> {
let mut uri = Self::create_unparsed_uri(uri_str, is_proxy);

ensure_coap_started();
// SAFETY: The provided pointers to raw_uri and uri_str are valid.
// Because uri_str is pinned (and its type is not Unpin), the pointer locations are always
// valid while this object lives, therefore the resulting coap_uri_t remains valid for the
Expand Down

0 comments on commit 25db012

Please sign in to comment.