Skip to content

Commit

Permalink
coap: Update to coap-message-0.3
Browse files Browse the repository at this point in the history
Merges: #72
  • Loading branch information
chrysn authored Jan 20, 2024
2 parents 15341d0 + 26a6fe2 commit 452e6e5
Show file tree
Hide file tree
Showing 8 changed files with 373 additions and 76 deletions.
16 changes: 7 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ rand_core_06 = { package = "rand_core", version = "^0.6" }
# For nimble UUID parsing and some debug implementations
hex = { version = "^0.4.3", default-features = false }

coap-numbers = { version = "^0.2.0", optional = true }
coap-numbers = "^0.2.0"

embedded-graphics = "0.6"

# Originally disabled by default because they were not published yet; now
# disabled by default we're moving toward opt-in modules anyway.
coap-message = { version = "^0.2.3", optional = true }
coap-handler = { version = "^0.1.4", optional = true }
coap-message-0-2 = { package = "coap-message", version = "^0.2.3" }
coap-message-0-3 = { package = "coap-message", version = "^0.3.0" }
coap-handler-0-1 = { package = "coap-handler", version = "^0.1.4" }
coap-handler-0-2 = { package = "coap-handler", version = "^0.2.0" }
embedded-nal = { version = "0.6.0", optional = true }
embedded-nal-tcpextensions = { version = "0.1", optional = true }
pin-utils = "0.1"
Expand All @@ -69,10 +69,8 @@ panic_handler_format = []
# only affects that single thread.
panic_handler_crash = []

# If these are present, traits for the respective optional dependencies will be
# implemented.
with_coap_message = ["coap-message" ]
with_coap_handler = ["coap-handler", "coap-numbers", "with_coap_message"]
with_coap_message = []
with_coap_handler = []
with_embedded_nal = ["embedded-nal", "embedded-nal-tcpextensions"]

# See msg::v2 documentation. Enabling this exposes components not under semver
Expand Down
8 changes: 8 additions & 0 deletions src/coap_handler/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! This module provides a wrappers around a coap_handler::Handler in different versions, all of
//! which can be registered at a RIOT GcoapHandler.
pub mod v0_1;
pub mod v0_2;

#[deprecated(note = "Use through the v0_1 module.")]
pub use v0_1::*;
22 changes: 12 additions & 10 deletions src/coap_handler.rs → src/coap_handler/v0_1.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/// This module provides a wrapper around a coap_handler::Handler that can be registered at a RIOT
/// GcoapHandler.
//! This module provides a wrapper around a coap_handler::Handler that can be registered at a RIOT
//! GcoapHandler.
use core::convert::TryInto;

use coap_message::{MutableWritableMessage, ReadableMessage};
use coap_handler_0_1::{Attribute, Handler, Record, Reporting};

use coap_message_0_2::{MutableWritableMessage, ReadableMessage};

use crate::coap_message::ResponseMessage;
use crate::gcoap::PacketBuffer;
Expand All @@ -11,11 +14,11 @@ use crate::gcoap::PacketBuffer;
/// to register it through a [crate::gcoap::SingleHandlerListener].
pub struct GcoapHandler<H>(pub H)
where
H: coap_handler::Handler;
H: Handler;

impl<H> crate::gcoap::Handler for GcoapHandler<H>
where
H: coap_handler::Handler,
H: Handler,
{
fn handle(&mut self, pkt: &mut PacketBuffer) -> isize {
let request_data = self.0.extract_request_data(pkt);
Expand All @@ -27,10 +30,9 @@ where

impl<H> crate::gcoap::WithLinkEncoder for GcoapHandler<H>
where
H: coap_handler::Handler + coap_handler::Reporting,
H: Handler + Reporting,
{
fn encode(&self, writer: &mut crate::gcoap::LinkEncoder) {
use coap_handler::Record;
for record in self.0.report() {
writer.write_comma_maybe();
writer.write(b"<");
Expand All @@ -46,7 +48,7 @@ where
writer.write(b"\"");
}
for attr in record.attributes() {
use coap_handler::Attribute::*;
use Attribute::*;
match attr {
Observable => writer.write(b";obs"),
Interface(i) => {
Expand All @@ -71,9 +73,9 @@ where
/// Blanket implementation for mutex wrapped resources
///
/// This is useful in combination with the defauilt implementation for Option as well.
impl<'b, H> coap_handler::Handler for &'b crate::mutex::Mutex<H>
impl<'b, H> Handler for &'b crate::mutex::Mutex<H>
where
H: coap_handler::Handler,
H: Handler,
{
type RequestData = Option<H::RequestData>;

Expand Down
146 changes: 146 additions & 0 deletions src/coap_handler/v0_2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//! This module provides a wrapper around a coap_handler::Handler that can be registered at a RIOT
//! GcoapHandler.
use core::convert::TryInto;

use coap_handler_0_2::{Attribute, Handler, Record, Reporting};

use coap_message_0_3::{
error::RenderableOnMinimal,
MinimalWritableMessage,
MutableWritableMessage,
ReadableMessage,
};

use crate::coap_message::ResponseMessage;
use crate::gcoap::PacketBuffer;

/// Adapter to get a [crate::gcoap::Handler] from a more generic [coap_handler::Handler], typically
/// to register it through a [crate::gcoap::SingleHandlerListener].
pub struct GcoapHandler<H>(pub H)
where
H: Handler;

impl<H> crate::gcoap::Handler for GcoapHandler<H>
where
H: Handler,
{
fn handle(&mut self, pkt: &mut PacketBuffer) -> isize {
let request_data = self.0.extract_request_data(pkt);
let mut lengthwrapped = ResponseMessage::new(pkt);
match request_data {
Ok(r) => {
if let Err(e) = self.0.build_response(&mut lengthwrapped, r) {
lengthwrapped.rewind();
if let Err(_e2) = e.render(&mut lengthwrapped) {
// Render double fault
lengthwrapped.rewind();
lengthwrapped.set_code(coap_numbers::code::INTERNAL_SERVER_ERROR);
}
}
}
Err(e) => {
if let Err(_e2) = e.render(&mut lengthwrapped) {
// Render double fault
lengthwrapped.rewind();
lengthwrapped.set_code(coap_numbers::code::INTERNAL_SERVER_ERROR);
}
}
}
lengthwrapped.finish()
}
}

impl<H> crate::gcoap::WithLinkEncoder for GcoapHandler<H>
where
H: Handler + Reporting,
{
fn encode(&self, writer: &mut crate::gcoap::LinkEncoder) {
for record in self.0.report() {
writer.write_comma_maybe();
writer.write(b"<");
for pathelement in record.path() {
writer.write(b"/");
writer.write(pathelement.as_ref().as_bytes());
}
writer.write(b">");
if let Some(rel) = record.rel() {
// Not trying to be smart about whether or not we need the quotes
writer.write(b";rel=\"");
writer.write(rel.as_bytes());
writer.write(b"\"");
}
for attr in record.attributes() {
use Attribute::*;
match attr {
Observable => writer.write(b";obs"),
Interface(i) => {
writer.write(b";if=\"");
writer.write(i.as_bytes());
writer.write(b"\"");
}
ResourceType(r) => {
writer.write(b";rt=\"");
writer.write(r.as_bytes());
writer.write(b"\"");
}
// FIXME: deduplicate with what's somewhere in coap-handler-implementations;
// implement remaining items
_ => (),
}
}
}
}
}

/// Blanket implementation for mutex wrapped resources
///
/// This is useful in combination with the defauilt implementation for Option as well.
impl<'b, H> Handler for &'b crate::mutex::Mutex<H>
where
H: Handler,
{
type RequestData = Option<H::RequestData>;

type ExtractRequestError = H::ExtractRequestError;
type BuildResponseError<M: MinimalWritableMessage> = H::BuildResponseError<M>;

fn extract_request_data<M: ReadableMessage>(
&mut self,
request: &M,
) -> Result<Self::RequestData, Self::ExtractRequestError> {
self.try_lock()
.map(|mut h| h.extract_request_data(request))
.transpose()
}

fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
if let Some(r) = request {
if let Some(mut s) = self.try_lock() {
return s.estimate_length(r);
}
}

1
}

fn build_response<M: MutableWritableMessage>(
&mut self,
response: &mut M,
request: Self::RequestData,
) -> Result<(), Self::BuildResponseError<M>> {
if let Some(r) = request {
if let Some(mut s) = self.try_lock() {
return s.build_response(response, r);
}
}

response.set_code(
coap_numbers::code::SERVICE_UNAVAILABLE
.try_into()
.map_err(|_| "Message type can't even exprss Service Unavailable")
.unwrap(),
);
Ok(())
}
}
64 changes: 10 additions & 54 deletions src/coap_message.rs → src/coap_message/impl_0_2.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
/// This module implements coap_message::ReadableMessage for, and a wrapper that provides
/// coap_message::WritableMessage around RIOT's coap_pkt_t.
use crate::gcoap::{PacketBuffer, PacketBufferOptIter};
use coap_message::{
use coap_message_0_2::{
MessageOption,
MinimalWritableMessage,
MutableWritableMessage,
ReadableMessage,
WithSortedOptions,
};

pub struct MessageOption<'a> {
number: u16,
value: &'a [u8],
}

impl<'a> coap_message::MessageOption for MessageOption<'a> {
impl<'a> MessageOption for super::MessageOption<'a> {
fn number(&self) -> u16 {
self.number
}
Expand All @@ -23,27 +16,14 @@ impl<'a> coap_message::MessageOption for MessageOption<'a> {
}
}

pub struct OptionsIterator<'a>(PacketBufferOptIter<'a>);
impl<'a> Iterator for OptionsIterator<'a> {
type Item = MessageOption<'a>;

fn next(&mut self) -> Option<Self::Item> {
let (opt_num, slice) = self.0.next()?;
Some(MessageOption {
number: opt_num,
value: slice,
})
}
}

impl WithSortedOptions for PacketBuffer {
impl WithSortedOptions for super::PacketBuffer {
// valid because gcoap just reads options from the message where they are stored in sequence
}

impl ReadableMessage for PacketBuffer {
impl ReadableMessage for super::PacketBuffer {
type Code = u8;
type OptionsIter<'a> = OptionsIterator<'a>;
type MessageOption<'a> = MessageOption<'a>;
type OptionsIter<'a> = super::OptionsIterator<'a>;
type MessageOption<'a> = super::MessageOption<'a>;

fn code(&self) -> Self::Code {
self.get_code_raw()
Expand All @@ -54,35 +34,11 @@ impl ReadableMessage for PacketBuffer {
}

fn options(&self) -> Self::OptionsIter<'_> {
OptionsIterator(self.opt_iter())
}
}

pub struct ResponseMessage<'a> {
message: &'a mut PacketBuffer,
payload_written: Option<usize>,
}

impl<'a> ResponseMessage<'a> {
pub fn new(buf: &'a mut PacketBuffer) -> Self {
// Can't really err; FIXME ensure that such a check won't affect ROM too much
buf.resp_init(5 << 5).unwrap();

ResponseMessage {
message: buf,
payload_written: None,
}
}

pub fn finish(&self) -> isize {
self.message.get_length(match self.payload_written {
None => 0,
Some(x) => x + 1,
}) as isize
super::OptionsIterator(self.opt_iter())
}
}

impl<'a> MinimalWritableMessage for ResponseMessage<'a> {
impl<'a> MinimalWritableMessage for super::ResponseMessage<'a> {
type Code = u8;
type OptionNumber = u16;

Expand All @@ -105,7 +61,7 @@ impl<'a> MinimalWritableMessage for ResponseMessage<'a> {
}
}

impl<'a> MutableWritableMessage for ResponseMessage<'a> {
impl<'a> MutableWritableMessage for super::ResponseMessage<'a> {
fn available_space(&self) -> usize {
self.message.payload().len()
}
Expand Down
Loading

0 comments on commit 452e6e5

Please sign in to comment.