Skip to content
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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

pulsastrix
Copy link
Member

@pulsastrix pulsastrix commented Nov 27, 2024

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

@pulsastrix pulsastrix added bug Something isn't working libcoap-parity Features that libcoap offers, but libcoap-rs currently does not labels Nov 27, 2024
@pulsastrix pulsastrix added this to the v0.3.0 milestone Nov 27, 2024
@pulsastrix pulsastrix self-assigned this Nov 27, 2024
Copy link

github-actions bot commented Nov 27, 2024

Workflow Status Report

Generated for commit 1fa997b on Thu Nov 28 15:25:15 UTC 2024.

CI Status

Linting Report

Clippy check result: success

Refer to the "Files Changed" tab for identified issues.

Code Coverage Report

Filename                             Stmts    Miss  Cover    Missing
---------------------------------  -------  ------  -------  ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
libcoap/src/crypto/psk/client.rs        61      42  31.15%   70-73, 82, 103-187, 231-237, 267, 274, 308-334
libcoap/src/crypto/psk/key.rs           43      18  58.14%   42-48, 163-204
libcoap/src/crypto/psk/server.rs        82      66  19.51%   67-85, 94, 97-114, 142, 149, 156, 185-228, 251-391
libcoap/src/session/client.rs           76      16  78.95%   56, 150, 156, 177, 183, 212-213, 219-229, 276-281
libcoap/src/session/mod.rs             154      89  42.21%   56-62, 91-92, 106-220, 231-275, 285-287, 297-307, 343, 358, 373-374, 391-392, 415, 423, 451, 455, 476-480, 558, 564
libcoap/src/session/server.rs           48      14  70.83%   69-71, 143-144, 152-153, 179-190
libcoap/src/crypto/pki_rpk/key.rs       51      31  39.22%   150-204, 234-242, 244-254
libcoap/src/crypto/pki_rpk/mod.rs      120      88  26.67%   449-480, 502-599, 608, 611-661, 674, 681, 688, 723, 725, 729, 750-897
libcoap/src/crypto/pki_rpk/pki.rs       54      20  62.96%   77-135, 258-300, 309-311
libcoap/src/crypto/pki_rpk/rpk.rs       23      10  56.52%   61-90, 159-162
libcoap/src/message/mod.rs             260     120  53.85%   104-107, 109-123, 125-130, 138-144, 146-160, 162-167, 171, 173, 207, 209, 212-221, 224-238, 241-242, 244-248, 264-273, 294-300, 397, 439, 445, 479, 485, 499, 509-514, 519, 521-523, 539, 544-545, 550-552, 554-557, 562, 582-589
libcoap/src/message/request.rs         220     144  34.55%   52, 69-186, 201-202, 229-257, 265-354, 359-360, 366-375, 381, 384-386, 390, 397-401, 412, 416, 431-432, 437, 440-441, 445-446, 450, 453, 456, 459, 473-477
libcoap/src/message/response.rs        143     106  25.87%   35-158, 164, 167, 170, 173, 195-221, 225-226, 232-324, 328-332, 358-359
libcoap/src/context.rs                 191      92  51.83%   50, 89, 94-99, 105-106, 111, 116, 118, 152-195, 204-212, 228, 236, 257, 265, 304-307, 341, 428, 433, 449, 457-618
libcoap/src/error.rs                     4       4  0.00%    91-170
libcoap/src/event.rs                     9       0  100.00%
libcoap/src/mem.rs                     118      40  66.10%   145-159, 193-194, 207-208, 277, 293-294, 316-320, 350-351, 364-366, 378-389, 449-450, 470, 478-485, 504, 523-524, 527-528
libcoap/src/prng.rs                     18      14  22.22%   67-179
libcoap/src/protocol.rs                150     102  32.00%   145-146, 152-157, 159-171, 173-174, 176-177, 184-189, 191-203, 205-206, 208-209, 266-267, 289, 347-348, 350-352, 361-362, 364-380, 437-441, 443-482, 517
libcoap/src/resource.rs                141      63  55.32%   62, 96-98, 173-174, 176-208, 216-217, 219-221, 248, 254, 257, 282-289, 302-304, 329-331, 338-339, 348-350, 356-358, 364-372, 494, 496-508
libcoap/src/transport.rs                13       4  69.23%   28-33, 54, 73
libcoap/src/types.rs                   236     127  46.19%   76-121, 128-157, 200-232, 243-275, 285, 411-451, 504-578, 636, 662-663, 687, 699, 784, 799, 829-838, 871-892, 905-911, 918, 946-989
libcoap/tests/common/dtls.rs            24       4  83.33%   36, 48, 54-56
libcoap/tests/common/mod.rs             46       6  86.96%   78, 109-112, 115
libcoap-sys/src/lib.rs                  97      35  63.92%   115-151, 183, 188, 193, 198, 208, 213, 223, 228, 233, 238, 243, 248, 253, 258, 263, 268, 278, 320-337, 459-460
TOTAL                                 2382    1255  47.31%

Diff against main

Filename                           Stmts    Miss  Cover
-------------------------------  -------  ------  -------
libcoap/src/session/mod.rs             0      -2  +1.30%
libcoap/src/session/server.rs          0      +2  -4.17%
libcoap/src/message/mod.rs           +15      -4  +4.46%
libcoap/src/message/request.rs         0      -6  +2.73%
libcoap/src/message/response.rs        0      -5  +3.50%
libcoap/src/context.rs                +3      -1  +1.30%
libcoap/src/mem.rs                     0      -1  +0.85%
libcoap/src/protocol.rs                0      -8  +5.33%
libcoap/src/resource.rs               +2      -6  +4.96%
libcoap/src/transport.rs              +3      +1  -0.77%
libcoap/src/types.rs                   0     -39  +16.53%
libcoap/tests/common/dtls.rs          +1      +1  -3.62%
libcoap/tests/common/mod.rs           -1      +1  -2.41%
TOTAL                                +23     -67  +3.35%

badge

Results for commit: 8586afb

Coverage target is 80%

…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().
@pulsastrix pulsastrix changed the title WIP: fix(server): Don't send a copy of the PDU instead of applying the response to the original response PDU fix(server): Don't send a copy of the PDU instead of applying the response to the original response PDU Nov 28, 2024
@pulsastrix pulsastrix marked this pull request as ready for review November 28, 2024 15:26
@pulsastrix pulsastrix requested a review from JKRhb November 28, 2024 15:26
Comment on lines 353 to 354
// Send remaining packets until we can cleanly shutdown.
// SAFETY: Provided context is always valid as an invariant of this struct.
Copy link
Member

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?

Comment on lines +424 to -432
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();

Copy link
Member

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>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Comment on lines +493 to +516
// 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;
}
}
Copy link
Member

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>(
Copy link
Member

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 {
Copy link
Member

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).
Copy link
Member

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be 2024?

Comment on lines +481 to +487
// 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);
}
}
Copy link
Member

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.

Comment on lines +10 to -15
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;
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working libcoap-parity Features that libcoap offers, but libcoap-rs currently does not
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Help with using server observable notifications
2 participants