Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions libcoap/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@
//! Module containing context-internal types and traits.

use core::ffi::c_uint;
#[cfg(feature = "dtls-pki")]
use std::ffi::CString;
#[cfg(feature = "dtls")]
use std::ptr::NonNull;
use std::{any::Any, ffi::c_void, fmt::Debug, net::SocketAddr, ops::Sub, sync::Once, time::Duration};
#[cfg(all(feature = "dtls-pki", unix))]
use std::{os::unix::ffi::OsStrExt, path::Path};

#[cfg(feature = "dtls-pki")]
use libcoap_sys::coap_context_set_pki_root_cas;
use libcoap_sys::{
Expand All @@ -43,20 +35,31 @@ use libcoap_sys::{
coap_register_response_handler, coap_set_app_data, coap_startup_with_feature_checks, COAP_BLOCK_SINGLE_BODY,
COAP_BLOCK_USE_LIBCOAP, COAP_IO_WAIT,
};
use std::ffi::CStr;
#[cfg(feature = "dtls-pki")]
use std::ffi::CString;
#[cfg(feature = "dtls")]
use std::ptr::NonNull;
use std::{any::Any, ffi::c_void, fmt::Debug, net::SocketAddr, ops::Sub, sync::Once, time::Duration};
#[cfg(all(feature = "dtls-pki", unix))]
use std::{os::unix::ffi::OsStrExt, path::Path};

#[cfg(any(feature = "dtls-rpk", feature = "dtls-pki"))]
use crate::crypto::pki_rpk::ServerPkiRpkCryptoContext;
#[cfg(feature = "dtls-psk")]
use crate::crypto::psk::ServerPskContext;
use crate::{
error::{ContextConfigurationError, EndpointCreationError, IoProcessError},
error::{ContextConfigurationError, EndpointCreationError, IoProcessError, MulticastGroupJoinError},
event::{event_handler_callback, CoapEventHandler},
mem::{CoapLendableFfiRcCell, CoapLendableFfiWeakCell, DropInnerExclusively},
resource::{CoapResource, UntypedCoapResource},
session::{session_response_handler, CoapServerSession, CoapSession},
transport::CoapEndpoint,
};

//TODO: New feature?
use libcoap_sys::coap_join_mcast_group_intf;

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

#[inline(always)]
Expand Down Expand Up @@ -407,6 +410,28 @@ impl CoapContext<'_> {
self.add_endpoint(addr, coap_proto_t_COAP_PROTO_DTLS)
}

/// Joins a multicast group.
///
/// `groupname` is usually a multicast IP address, while `ifname` is the used interface.
/// If `ifname` is set to `None`, the first appropriate interface will be chosen by the operating system.
pub fn join_mcast_group_intf(
&mut self,
groupname: impl AsRef<CStr>,
ifname: Option<&CStr>,
) -> Result<(), MulticastGroupJoinError> {
let inner_ref = self.inner.borrow();
let mcast_groupname = groupname.as_ref().as_ptr();
let mcast_ifname = ifname.map(|v| v.as_ptr()).unwrap_or(std::ptr::null());
// SAFETY: `inner_ref.raw_context` is always valid by construction of this type, group and interface name are pointers to valid C strings.
unsafe {
let ret = coap_join_mcast_group_intf(inner_ref.raw_context, mcast_groupname, mcast_ifname);
if ret != 0 {
return Err(MulticastGroupJoinError::Unknown);
}
};
Ok(())
}

// /// TODO
// #[cfg(all(feature = "tcp", dtls))]
// pub fn add_endpoint_tls(&mut self, _addr: SocketAddr) -> Result<(), EndpointCreationError> {
Expand Down
7 changes: 7 additions & 0 deletions libcoap/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ use thiserror::Error;

use crate::protocol::{CoapMessageType, CoapOptionType};

#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum MulticastGroupJoinError {
/// Unknown error inside of libcoap
#[error("CoAP join multicast group error: unknown error in call to libcoap")]
Unknown,
}

#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum EndpointCreationError {
/// Unknown error inside of libcoap
Expand Down
30 changes: 27 additions & 3 deletions libcoap/src/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ use std::{
};

use libcoap_sys::{
coap_delete_resource, coap_new_str_const, coap_pdu_t, coap_register_request_handler, coap_resource_get_uri_path,
coap_resource_get_userdata, coap_resource_init, coap_resource_notify_observers, coap_resource_set_get_observable,
coap_resource_set_mode, coap_resource_set_userdata, coap_resource_t, coap_send_rst, coap_session_t, coap_string_t,
coap_add_attr, coap_delete_resource, coap_new_str_const, coap_pdu_t, coap_register_request_handler,
coap_resource_get_uri_path, coap_resource_get_userdata, coap_resource_init, coap_resource_notify_observers,
coap_resource_set_get_observable, coap_resource_set_mode, coap_resource_set_userdata, coap_resource_t,
coap_send_rst, coap_session_t, coap_string_t, COAP_ATTR_FLAGS_RELEASE_NAME, COAP_ATTR_FLAGS_RELEASE_VALUE,
COAP_RESOURCE_FLAGS_NOTIFY_CON, COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RESOURCE_FLAGS_RELEASE_URI,
};

Expand Down Expand Up @@ -314,6 +315,29 @@ impl<D: Any + ?Sized + Debug> CoapResource<D> {
}
}

/// Adds an attribute with a name and an optional value to a CoAP resource object.
pub fn add_attr(&self, name: &str, val: Option<&str>) {
let mut inner = self.inner.borrow_mut();
// SAFETY: libcoap uses the passed pointers "attr_name" and "attr_val" here.
// Because of the passed flags, libcoap takes ownership of these pointers.
// Passing NULL for the value is safe, since libcoap only frees the value, if it's not NULL.
unsafe {
let attr_name = coap_new_str_const(name.as_ptr(), name.len());
let attr_val = match val {
Some(val_str) => coap_new_str_const(val_str.as_ptr(), val_str.len()),
None => std::ptr::null_mut(),
};
// coap_new_str_const allocates memory, which should be freed when
// the resource is deleted. Freeing a null pointer is a no-op here
coap_add_attr(
inner.raw_resource,
attr_name,
attr_val,
(COAP_ATTR_FLAGS_RELEASE_NAME | COAP_ATTR_FLAGS_RELEASE_VALUE) as i32,
);
}
}

fn call_dynamic_handler(
&self,
session: &mut CoapServerSession,
Expand Down