1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! A lightweight low-level CoAP message manipulation crate.
//!
//! Its goal is to be compliant with the CoAP standards and to provide a
//! building block for libraries (e.g.
//! [coap](https://github.com/Covertness/coap-rs)) and applications.
//!
//! `coap-lite` supports `#![no_std]` and embedded environments.
//!
//! It was originally based on the improved low-level message handling code
//! from the [coap] crate as well as [rust-async-coap], made to work in bare
//! metal environments.
//!
//! ## Supported RFCs
//!
//! - CoAP [RFC 7252](https://tools.ietf.org/html/rfc7252)
//! - CoAP Observe Option [RFC 7641](https://tools.ietf.org/html/rfc7641)
//! - Too Many Requests Response Code [RFC 8516](https://tools.ietf.org/html/rfc8516)
//! - Constrained RESTful Environments (CoRE) Link Format
//!   [RFC6690](https://tools.ietf.org/html/rfc6690#:~:text=well-known%2Fcore)
//!
//! ## Usage
//!
//! This crate provides several types that can be used to build, modify and
//! encode/decode CoAP messages to/from their byte representation.
//!
//! **Note for no_std users**: it does require allocation, so you might have to
//! set a global allocator depending on your target.
//!
//! ### Client
//!
//! The following example uses `std::net::UdpSocket` to send the UDP packet but
//! you can use anything, e.g. [smoltcp](https://github.com/smoltcp-rs/smoltcp)
//! for embedded.
//!
//! ```rust
//! use coap_lite::{
//!     CoapRequest, RequestType as Method
//! };
//! use std::net::{SocketAddr, UdpSocket};
//!
//! fn main() {
//!     let mut request: CoapRequest<SocketAddr> = CoapRequest::new();
//!
//!     request.set_method(Method::Get);
//!     request.set_path("/test");
//!
//!     let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
//!
//!     let packet = request.message.to_bytes().unwrap();
//!     socket.send_to(&packet[..], "127.0.0.1:5683").expect("Could not send the data");
//! }
//! ```
//!
//! ### Server
//!
//! ```rust
//! use coap_lite::{CoapRequest, Packet};
//! use std::net::{UdpSocket};
//!
//! fn main() {
//!     let socket = UdpSocket::bind("127.0.0.1:5683").unwrap();
//!     let mut buf = [0; 100];
//!     let (size, src) = socket.recv_from(&mut buf).expect("Didn't receive data");
//!
//!     println!("Payload {:x?}", &buf[..size]);
//!
//!     let packet = Packet::from_bytes(&buf[..size]).unwrap();
//!     let request = CoapRequest::from_packet(packet, src);
//!
//!     let method = request.get_method().clone();
//!     let path = request.get_path();
//!
//!     println!("Received CoAP request '{:?} {}' from {}", method, path, src);
//!
//!     let mut response = request.response.unwrap();
//!     response.message.payload = b"OK".to_vec();
//!
//!     let packet = response.message.to_bytes().unwrap();
//!     socket.send_to(&packet[..], &src).expect("Could not send the data");
//! }
//! ```
//!
//! ### Low-level binary conversion
//!
//! ```rust
//! use coap_lite::{
//!     CoapOption, MessageClass, MessageType,
//!     Packet, RequestType, ResponseType,
//! };
//!
//! let mut request = Packet::new();
//! request.header.message_id = 23839;
//! request.header.code = MessageClass::Request(RequestType::Get);
//! request.set_token(vec![0, 0, 57, 116]);
//! request.add_option(CoapOption::UriHost, b"localhost".to_vec());
//! request.add_option(CoapOption::UriPath, b"tv1".to_vec());
//! assert_eq!(
//!     [
//!         0x44, 0x01, 0x5D, 0x1F, 0x00, 0x00, 0x39, 0x74, 0x39, 0x6C, 0x6F,
//!         0x63, 0x61, 0x6C, 0x68, 0x6F, 0x73, 0x74, 0x83, 0x74, 0x76, 0x31,
//!     ],
//!     request.to_bytes().unwrap()[..]
//! );
//!
//! let response = Packet::from_bytes(&[
//!     0x64, 0x45, 0x5D, 0x1F, 0x00, 0x00, 0x39, 0x74, 0xFF, 0x48, 0x65,
//!     0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21,
//! ])
//! .unwrap();
//! assert_eq!(23839, response.header.message_id);
//! assert_eq!(
//!     MessageClass::Response(ResponseType::Content),
//!     response.header.code
//! );
//! assert_eq!(MessageType::Acknowledgement, response.header.get_type());
//! assert_eq!([0, 0, 57, 116], response.get_token()[..]);
//! assert_eq!(b"Hello World!", &response.payload[..]);
//! ```
//!
//! [coap]: https://github.com/covertness/coap-rs
//! [rust-async-coap]: https://github.com/google/rust-async-coap

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::needless_doctest_main)]

#[macro_use]
extern crate alloc;

#[cfg_attr(tarpaulin, skip)]
pub mod error;

mod header;
pub mod link_format;
mod observe;
mod packet;
mod request;
mod response;

pub use header::{
    Header, HeaderRaw, MessageClass, MessageType, RequestType, ResponseType,
};
pub use observe::Subject;
pub use packet::{CoapOption, ContentFormat, ObserveOption, Packet};
pub use request::CoapRequest;
pub use response::CoapResponse;