-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(server): Don't send a copy of the PDU instead of applying the response to the original response PDU #36
base: main
Are you sure you want to change the base?
Conversation
Workflow Status ReportGenerated for commit 1fa997b on Thu Nov 28 15:25:15 UTC 2024. Linting ReportClippy check result: success Refer to the "Files Changed" tab for identified issues. Code Coverage Report
Diff against main
Results for commit: 8586afb Coverage target is |
8db7082
to
42f78f0
Compare
…ponse to the original response PDU This will require application-side modifications to server-side request handlers. Namely, the resource handler must no longer call coap_send for the response PDU. This change was made to conform to libcoap's API contract and to enable CoAP Observe support. Additionally, a small workaround for proper CoAP Observe support was added that prevents duplicate addition of the Observe option in server-side resource handlers. This workaround should be removed once #21 has been tackled and the API for message handling was reworked.
Explicitly freeing the endpoints before calling coap_free_context() may cause a SIGABRT if sessions are still referenced somewhere (e.g., due to the session still being observed). This change decomposes the CoapEndpoint instances into their raw variant without calling coap_free_endpoint() on dropping the context so that libcoap can perform its own cleanup before freeing the endpoints itself in coap_free_context().
…anics in callbacks
42f78f0
to
8586afb
Compare
// Send remaining packets until we can cleanly shutdown. | ||
// SAFETY: Provided context is always valid as an invariant of this struct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this comment be moved above the while loop?
pub fn into_raw_pdu<'a, S: CoapSessionCommon<'a>+?Sized>( | ||
mut self, | ||
session: &S, | ||
) -> Result<*mut coap_pdu_t, MessageConversionError> { | ||
let message = self.as_message_mut(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If cargo fmt
allows it, I would probably rather keep the formatting here.
@@ -466,7 +462,7 @@ impl CoapMessage { | |||
/// | |||
/// # Safety | |||
/// raw_pdu must point to a valid mutable instance of coap_pdu_t. | |||
pub(crate) unsafe fn apply_to_raw_pdu<'a, S: CoapSessionCommon<'a> + ?Sized>( | |||
pub(crate) unsafe fn apply_to_raw_pdu<'a, S: CoapSessionCommon<'a>+?Sized>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
// TODO this is a really ugly workaround, remove this as soon as we have builder-like | ||
// interfaces for PDUs. | ||
// Do not duplicate Observe option as reapplying to the same PDU would cause the option | ||
// to be added twice otherwise. | ||
if let CoapOption::Observe(option) = option { | ||
// Check if Observe has already been set. | ||
let mut scratch: MaybeUninit<coap_opt_iterator_t> = MaybeUninit::uninit(); | ||
let cur_option = unsafe { coap_check_option(raw_pdu, optnum, scratch.as_mut_ptr()) }; | ||
if !cur_option.is_null() { | ||
// Observe has already been set, get value and compare with the one set for this message. | ||
let cur_value = unsafe { | ||
core::slice::from_raw_parts(coap_opt_value(cur_option), coap_opt_length(cur_option) as usize) | ||
}; | ||
let cur_value = decode_var_len_u32(cur_value); | ||
// If Observe option values differ, return an appropriate error. | ||
if option != cur_value { | ||
return Err(MessageConversionError::NonRepeatableOptionRepeated( | ||
CoapOptionType::Observe, | ||
)); | ||
} | ||
// Otherwise, skip adding the option value to the optlist to avoid a duplicate. | ||
continue; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this (or at least parts of it) be factored out into its own function, maybe?
@@ -50,7 +46,7 @@ use crate::session::CoapSessionCommon; | |||
macro_rules! resource_handler { | |||
($f:ident, $t:path) => {{ | |||
#[allow(clippy::unnecessary_mut_passed)] // We don't know whether the function needs a mutable reference or not. | |||
unsafe extern "C" fn _coap_method_handler_wrapper<D: Any + ?Sized + Debug>( | |||
unsafe extern "C" fn _coap_method_handler_wrapper<D: Any+?Sized+Debug>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
@@ -101,7 +101,7 @@ pub unsafe fn prepare_resource_handler_data<'a, D: Any + ?Sized + Debug>( | |||
} | |||
|
|||
/// Trait with functions relating to [CoapResource]s with an unknown data type. | |||
pub trait UntypedCoapResource: Any + Debug { | |||
pub trait UntypedCoapResource: Any+Debug { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
/// Decomposes this endpoint into its raw version. | ||
/// | ||
/// Note that the caller is now responsible for freeing the endpoint (either by calling | ||
/// coap_free_endpoint() or calling coap_free_context() on the associated context). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the documentation use [coap_free_endpoint()
] here?
* dtls_client_server_test.rs - Tests for UDP clients+servers. | ||
* This file is part of the libcoap-rs crate, see the README and LICENSE files for | ||
* more information and terms of use. | ||
* Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be 2024?
// Update token if necessary. | ||
if message.token.is_some() && cur_token != message.token.as_deref() { | ||
let token = message.token.as_ref().unwrap(); | ||
if coap_add_token(raw_pdu, token.len(), token.as_ptr()) == 0 { | ||
return Err(MessageConversionError::Unknown); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering here if you could just write the token regardless of the comparison result, as you would need to iterate over the buffers twice when they do not match.
use crate::{ | ||
error::{MessageConversionError, MessageTypeError, OptionValueError}, | ||
message::{construct_path_string, construct_query_string, CoapMessage, CoapMessageCommon, CoapOption}, | ||
protocol::{ | ||
CoapMessageCode, CoapMessageType, CoapOptionType, CoapResponseCode, ContentFormat, ETag, Echo, MaxAge, Observe, | ||
}, | ||
types::CoapUri, | ||
}; | ||
use crate::types::CoapUri; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the (unrelated) reformatting could be factored out of this PR in general to keep the diff a bit cleaner. But that is not strictly necessary.
This change will require application-side modifications to server-side request handlers. Namely, the resource handler must no longer call coap_send for the response PDU.
This change was made to conform to libcoap's API contract and to enable CoAP Observe support.
Additionally, a small workaround for proper CoAP Observe support was added that prevents duplicate addition of the Observe option in server-side resource handlers.
This workaround should be removed once #21 has been tackled and the API for message handling was reworked.
Lastly, there was an issue when calling
CoapContext::drop
on a server while a resource was observed by at least one client because libcoap keeps the server session referenced in this case.As we tried to explicitly free the endpoints before calling
coap_free_context()
, this caused a SIGABRT as the sessions prevent freeing the associated endpoint.Closes #14