pub struct Message<PayloadBytes, Options> {
pub id: Id,
pub ty: Type,
pub ver: Version,
pub token: Token,
pub code: Code,
pub opts: Options,
pub payload: Payload<PayloadBytes>,
}
Expand description
CoAP Messages
This struct provides a high-level API for manipulating requests & responses, while still being cheaply serializable to & from the byte layout of CoAP messages on the wire.
Options
Options (the CoAP equivalent to HTTP headers) can be manipulated with methods
provided in the MessageOptions
trait. This includes getting & setting common
options known to this library.
Constructing
Message::new
is the most straightforward way to initialize messages.
Being one of the few structs in the toad-lib libraries with public fields, you may also initialize it with a struct literal.
use toad_msg::alloc::Message;
use toad_msg::{Code, Id, Payload, Token, Type, Version};
let a = Message { id: Id(1),
token: Token(Default::default()),
ver: Version::default(),
ty: Type::Con,
code: Code::GET,
payload: Payload(vec![]),
opts: Default::default() };
let b = Message::new(Type::Con, Code::GET, Id(1), Token(Default::default()));
assert_eq!(a, b);
Sending / Receiving
This crate (toad-msg
) explicitly does not know or care about how
the messages are sent and received, and is just concerned with the data
structures involved on the machines having a CoAP conversation.
For a runtime that uses this library, see toad
.
Further Reading from RFC7252
Messaging Model
generated from RFC7252 section 2.1
The CoAP messaging model is based on the exchange of messages over UDP between endpoints.
CoAP uses a short fixed-length binary header (4 bytes) that may be followed by compact binary options and a payload. This message format is shared by requests and responses. The CoAP message format is specified in Section 3. Each message contains a Message ID used to detect duplicates and for optional reliability. (The Message ID is compact; its 16-bit size enables up to about 250 messages per second from one endpoint to another with default protocol parameters.)
Reliability is provided by marking a message as Confirmable (CON). A Confirmable message is retransmitted using a default timeout and exponential back-off between retransmissions, until the recipient sends an Acknowledgement message (ACK) with the same Message ID (in this example, 0x7d34) from the corresponding endpoint; see Figure 2. When a recipient is not at all able to process a Confirmable message (i.e., not even able to provide a suitable error response), it replies with a Reset message (RST) instead of an Acknowledgement (ACK).
Client Server
| |
| CON [0x7d34] |
+----------------->|
| |
| ACK [0x7d34] |
|<-----------------+
| |
Figure 2: Reliable Message Transmission
A message that does not require reliable transmission (for example, each single measurement out of a stream of sensor data) can be sent as a Non-confirmable message (NON). These are not acknowledged, but still have a Message ID for duplicate detection (in this example, 0x01a0); see Figure 3. When a recipient is not able to process a Non-confirmable message, it may reply with a Reset message (RST).
Client Server
| |
| NON [0x01a0] |
+----------------->|
| |
Figure 3: Unreliable Message Transmission
See Section 4 for details of CoAP messages.
As CoAP runs over UDP, it also supports the use of multicast IP destination addresses, enabling multicast CoAP requests. Section 8 discusses the proper use of CoAP messages with multicast addresses and precautions for avoiding response congestion.
Several security modes are defined for CoAP in Section 9 ranging from no security to certificate-based security. This document specifies a binding to DTLS for securing the protocol; the use of IPsec with CoAP is discussed in [IPsec-CoAP].
Message Format
generated from RFC7252 section 3
CoAP is based on the exchange of compact messages that, by default, are transported over UDP (i.e., each CoAP message occupies the data section of one UDP datagram). CoAP may also be used over Datagram Transport Layer Security (DTLS) (see Section 9.1). It could also be used over other transports such as SMS, TCP, or SCTP, the specification of which is out of this document’s scope. (UDP-lite [RFC3828] and UDP zero checksum [RFC6936] are not supported by CoAP.)
CoAP messages are encoded in a simple binary format. The message format starts with a fixed-size 4-byte header. This is followed by a variable-length Token value, which can be between 0 and 8 bytes long.
Following the Token value comes a sequence of zero or more CoAP Options in Type-Length-Value (TLV) format, optionally followed by a payload that takes up the rest of the datagram.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver| T | TKL | Code | Message ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Token (if any, TKL bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 1 1 1 1 1 1 1| Payload (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 7: Message Format
The fields in the header are defined as follows:
Version (Ver): 2-bit unsigned integer. Indicates the CoAP version number. Implementations of this specification MUST set this field to 1 (01 binary). Other values are reserved for future versions. Messages with unknown version numbers MUST be silently ignored.
Type (T): 2-bit unsigned integer. Indicates if this message is of type Confirmable (0), Non-confirmable (1), Acknowledgement (2), or Reset (3). The semantics of these message types are defined in Section 4.
Token Length (TKL): 4-bit unsigned integer. Indicates the length of the variable-length Token field (0-8 bytes). Lengths 9-15 are reserved, MUST NOT be sent, and MUST be processed as a message format error.
Code: 8-bit unsigned integer, split into a 3-bit class (most significant bits) and a 5-bit detail (least significant bits), documented as “c.dd” where “c” is a digit from 0 to 7 for the 3-bit subfield and “dd” are two digits from 00 to 31 for the 5-bit subfield. The class can indicate a request (0), a success response (2), a client error response (4), or a server error response (5). (All other class values are reserved.) As a special case, Code 0.00 indicates an Empty message. In case of a request, the Code field indicates the Request Method; in case of a response, a Response Code. Possible values are maintained in the CoAP Code Registries (Section 12.1). The semantics of requests and responses are defined in Section 5.
Message ID: 16-bit unsigned integer in network byte order. Used to detect message duplication and to match messages of type Acknowledgement/Reset to messages of type Confirmable/Non- confirmable. The rules for generating a Message ID and matching messages are defined in Section 4.
The header is followed by the Token value, which may be 0 to 8 bytes, as given by the Token Length field. The Token value is used to correlate requests and responses. The rules for generating a Token and correlating requests and responses are defined in Section 5.3.1.
Header and Token are followed by zero or more Options (Section 3.1). An Option can be followed by the end of the message, by another Option, or by the Payload Marker and the payload.
Following the header, token, and options, if any, comes the optional payload. If present and of non-zero length, it is prefixed by a fixed, one-byte Payload Marker (0xFF), which indicates the end of options and the start of the payload. The payload data extends from after the marker to the end of the UDP datagram, i.e., the Payload Length is calculated from the datagram size. The absence of the Payload Marker denotes a zero-length payload. The presence of a marker followed by a zero-length payload MUST be processed as a message format error.
Implementation Note: The byte value 0xFF may also occur within an option length or value, so simple byte-wise scanning for 0xFF is not a viable technique for finding the payload marker. The byte 0xFF has the meaning of a payload marker only where the beginning of another option could occur.
Fields§
§id: Id
see Id
for details
ty: Type
see Type
for details
ver: Version
see Version
for details
token: Token
see Token
for details
code: Code
see Code
for details
opts: Options
see opt::Opt
for details
payload: Payload<PayloadBytes>
see Payload
Implementations§
source§impl<PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap> Message<PayloadBytes, Options>
impl<PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap> Message<PayloadBytes, Options>
sourcepub fn cache_key(&self) -> u64
pub fn cache_key(&self) -> u64
Using DefaultCacheKey
, get the cache key for
this request.
The cache key can be used to compare messages for representing the same action against the same resource; requests with different IDs but the same method and cache-key affecting options (ex. path, query parameters) will yield the same cache-key.
sourcepub fn set_payload(
&mut self,
p: Payload<PayloadBytes>
) -> Option<Payload<PayloadBytes>>
pub fn set_payload( &mut self, p: Payload<PayloadBytes> ) -> Option<Payload<PayloadBytes>>
Set the payload, returning the old payload if there was one
sourcepub fn ack(&self, id: Id) -> Self
pub fn ack(&self, id: Id) -> Self
Create a new message that ACKs this one.
This needs an Id
to assign to the newly created message.
// we are a server
use std::net::SocketAddr;
use toad_msg::alloc::Message;
use toad_msg::Id;
fn server_get_request() -> Option<(SocketAddr, Message)> {
// Servery sockety things...
}
fn server_send_msg(addr: SocketAddr, msg: Message) -> Result<(), ()> {
// Message sendy bits...
}
let (addr, req) = server_get_request().unwrap();
let ack_id = Id(req.id.0 + 1);
let ack = req.ack(ack_id);
server_send_msg(addr, ack).unwrap();
Trait Implementations§
source§impl<PayloadBytes: Array<Item = u8>, Options: OptionMap> Len for Message<PayloadBytes, Options>
impl<PayloadBytes: Array<Item = u8>, Options: OptionMap> Len for Message<PayloadBytes, Options>
source§impl<P, O> MessageOptions for Message<P, O>where
P: Array<Item = u8> + AppendCopy<u8>,
O: OptionMap,
impl<P, O> MessageOptions for Message<P, O>where P: Array<Item = u8> + AppendCopy<u8>, O: OptionMap,
§type OptValueBytes = <O as OptionMap>::OptValue
type OptValueBytes = <O as OptionMap>::OptValue
§type SetError = SetOptionError<OptValue<<Message<P, O> as MessageOptions>::OptValueBytes>, <Message<P, O> as MessageOptions>::OptValues>
type SetError = SetOptionError<OptValue<<Message<P, O> as MessageOptions>::OptValueBytes>, <Message<P, O> as MessageOptions>::OptValues>
source§fn add(
&mut self,
n: OptNumber,
v: OptValue<Self::OptValueBytes>
) -> Result<(), Self::SetError>
fn add( &mut self, n: OptNumber, v: OptValue<Self::OptValueBytes> ) -> Result<(), Self::SetError>
source§fn set(
&mut self,
n: OptNumber,
v: OptValue<Self::OptValueBytes>
) -> Result<Option<Self::OptValues>, Self::SetError>
fn set( &mut self, n: OptNumber, v: OptValue<Self::OptValueBytes> ) -> Result<Option<Self::OptValues>, Self::SetError>
source§fn get(&self, n: OptNumber) -> Option<&Self::OptValues>
fn get(&self, n: OptNumber) -> Option<&Self::OptValues>
source§fn get_first(&self, n: OptNumber) -> Option<&OptValue<Self::OptValueBytes>>
fn get_first(&self, n: OptNumber) -> Option<&OptValue<Self::OptValueBytes>>
source§fn get_str(&self, n: OptNumber) -> Result<Option<&str>, Utf8Error>
fn get_str(&self, n: OptNumber) -> Result<Option<&str>, Utf8Error>
source§fn get_strs<'a, F>(&'a self, n: OptNumber) -> Result<F, Utf8Error>where
F: FromIterator<&'a str>,
fn get_strs<'a, F>(&'a self, n: OptNumber) -> Result<F, Utf8Error>where F: FromIterator<&'a str>,
source§fn get_u8(&self, n: OptNumber) -> Option<u8>
fn get_u8(&self, n: OptNumber) -> Option<u8>
source§fn get_u16(&self, n: OptNumber) -> Option<u16>
fn get_u16(&self, n: OptNumber) -> Option<u16>
source§fn get_u32(&self, n: OptNumber) -> Option<u32>
fn get_u32(&self, n: OptNumber) -> Option<u32>
source§fn get_u64(&self, n: OptNumber) -> Option<u64>
fn get_u64(&self, n: OptNumber) -> Option<u64>
source§fn remove(&mut self, n: OptNumber) -> Option<Self::OptValues>
fn remove(&mut self, n: OptNumber) -> Option<Self::OptValues>
source§fn path<'a, F>(&'a self) -> Result<F, Utf8Error>where
F: FromIterator<&'a str>,
fn path<'a, F>(&'a self) -> Result<F, Utf8Error>where F: FromIterator<&'a str>,
source§fn path_string<'a>(&'a self) -> Result<String, Utf8Error>
fn path_string<'a>(&'a self) -> Result<String, Utf8Error>
source§fn add_query<S>(&mut self, query: S) -> Result<(), Self::SetError>where
S: AsRef<str>,
fn add_query<S>(&mut self, query: S) -> Result<(), Self::SetError>where S: AsRef<str>,
source§fn query<'a, F>(&'a self) -> Result<F, Utf8Error>where
F: FromIterator<&'a str>,
fn query<'a, F>(&'a self) -> Result<F, Utf8Error>where F: FromIterator<&'a str>,
source§fn set_content_format(
&mut self,
format: ContentFormat
) -> Result<(), Self::SetError>
fn set_content_format( &mut self, format: ContentFormat ) -> Result<(), Self::SetError>
source§fn content_format(&self) -> Option<ContentFormat>
fn content_format(&self) -> Option<ContentFormat>
source§fn set_observe(&mut self, a: Action) -> Result<(), Self::SetError>
fn set_observe(&mut self, a: Action) -> Result<(), Self::SetError>
source§fn set_accept(&mut self, format: ContentFormat) -> Result<(), Self::SetError>
fn set_accept(&mut self, format: ContentFormat) -> Result<(), Self::SetError>
source§fn set_size2(&mut self, size_bytes: u64) -> Result<(), Self::SetError>
fn set_size2(&mut self, size_bytes: u64) -> Result<(), Self::SetError>
source§fn if_exists_flag_enabled(&self) -> bool
fn if_exists_flag_enabled(&self) -> bool
Message::set_if_exists
appliessource§fn set_if_not_exists(&mut self) -> Result<(), Self::SetError>
fn set_if_not_exists(&mut self) -> Result<(), Self::SetError>
source§fn if_not_exists_flag_enabled(&self) -> bool
fn if_not_exists_flag_enabled(&self) -> bool
Message::set_if_not_exists
appliessource§fn set_proxy_scheme<S>(&mut self, scheme: S) -> Result<(), Self::SetError>where
S: AsRef<str>,
fn set_proxy_scheme<S>(&mut self, scheme: S) -> Result<(), Self::SetError>where S: AsRef<str>,
source§fn proxy_scheme(&self) -> Result<Option<&str>, Utf8Error>
fn proxy_scheme(&self) -> Result<Option<&str>, Utf8Error>
source§fn add_location_path<S>(&mut self, path: S) -> Result<(), Self::SetError>where
S: AsRef<str>,
fn add_location_path<S>(&mut self, path: S) -> Result<(), Self::SetError>where S: AsRef<str>,
source§fn location_path<'a, F>(&'a self) -> Result<F, Utf8Error>where
F: FromIterator<&'a str>,
fn location_path<'a, F>(&'a self) -> Result<F, Utf8Error>where F: FromIterator<&'a str>,
source§fn add_location_query<S>(&mut self, query: S) -> Result<(), Self::SetError>where
S: AsRef<str>,
fn add_location_query<S>(&mut self, query: S) -> Result<(), Self::SetError>where S: AsRef<str>,
source§fn location_query<'a, F>(&'a self) -> Result<F, Utf8Error>where
F: FromIterator<&'a str>,
fn location_query<'a, F>(&'a self) -> Result<F, Utf8Error>where F: FromIterator<&'a str>,
source§impl<C, O> Ord for Message<C, O>where
O: OptionMap + PartialOrd,
C: Array<Item = u8>,
impl<C, O> Ord for Message<C, O>where O: OptionMap + PartialOrd, C: Array<Item = u8>,
source§impl<C, O> PartialEq<Message<C, O>> for Message<C, O>where
O: OptionMap + PartialEq,
C: Array<Item = u8>,
impl<C, O> PartialEq<Message<C, O>> for Message<C, O>where O: OptionMap + PartialEq, C: Array<Item = u8>,
source§impl<C, O> PartialOrd<Message<C, O>> for Message<C, O>where
O: OptionMap + PartialOrd,
C: Array<Item = u8>,
impl<C, O> PartialOrd<Message<C, O>> for Message<C, O>where O: OptionMap + PartialOrd, C: Array<Item = u8>,
1.0.0 · source§fn le(&self, other: &Rhs) -> bool
fn le(&self, other: &Rhs) -> bool
self
and other
) and is used by the <=
operator. Read moresource§impl<Bytes: AsRef<[u8]>, PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap> TryFromBytes<Bytes> for Message<PayloadBytes, Options>
impl<Bytes: AsRef<[u8]>, PayloadBytes: Array<Item = u8> + AppendCopy<u8>, Options: OptionMap> TryFromBytes<Bytes> for Message<PayloadBytes, Options>
§type Error = MessageParseError
type Error = MessageParseError
source§fn try_from_bytes(bytes: Bytes) -> Result<Self, Self::Error>
fn try_from_bytes(bytes: Bytes) -> Result<Self, Self::Error>
T
into Self