async_coap/
lib.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16//! An experimental, asynchronous implementation of the Constrained Application Protocol (CoAP).
17//!
18//! This library provides a flexible, [asynchronous](https://rust-lang-nursery.github.io/futures-rs/)
19//! interface for using and serving CoAP resources. You can either use the [included datagram-based
20//! back-end](datagram) or you can write your own back-end by implementing [`LocalEndpoint`].
21//!
22//! By implementing [datagram::AsyncDatagramSocket], you can use the [provided datagram-based
23//! back-end](datagram) with whatever datagram-based network layer you might want, be it UDP,
24//! DTLS, or even SMS. An implementation for Rust's standard [`std::net::UdpSocket`]
25//! ([`AllowStdUdpSocket`]) is included. A [Tokio](https://tokio.rs)-based implementation is
26//! forthcoming.
27//!
28//! ## Design
29//!
30//! Async-coap works differently than other CoAP libraries, making heavy use of combinators and
31//! [Futures v0.3].
32//!
33//! [Futures v0.3]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/
34//!
35//! ### Simple Unicast
36//!
37//! For the most part, CoAP was designed for the typical [RESTful] paradigm of sending requests and
38//! receiving responses.
39//! In typical CoAP libraries, you have a message type that you would create, populate with your request,
40//! and then pass to a method to send that request somewhere. Once the response had been received, the result
41//! would be returned as a single message. Simple. Straightforward.
42//!
43//! [RESTful]: https://en.wikipedia.org/wiki/Representational_state_transfer
44//!
45//! This similarly straightforward to do with *async-coap*:
46//!
47//! ```
48//! # #![feature(async_await)]
49//! # use std::sync::Arc;
50//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
51//! # use async_coap::prelude::*;
52//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
53//! # use async_coap::null::NullLocalEndpoint;
54//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
55//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
56//! # let mut pool = LocalPool::new();
57//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
58//! # let future = async move {
59//! // Create a `remote_endpoint` instance representing the destination
60//! // identified by the URI "coap://coap.me/test". This tends to be
61//! // more convenient than using `local_endpoint` directly.
62//! let mut remote_endpoint = local_endpoint
63//!     .remote_endpoint_from_uri(uri!("coap://coap.me/test"))
64//!     .expect("Remote endpoint lookup failed");
65//!
66//! // Create a future representing for our request.
67//! let future = remote_endpoint.send(CoapRequest::get().emit_any_response());
68//!
69//! // Send the request and await the response.
70//! let response = future.await.expect("CoAP request failed");
71//!
72//! // Print out the response message to standard output.
73//! println!("Got response: {}", response);
74//! # };
75//! # pool.run_until(future);
76//! ```
77//!
78//! ### Block2 Reconstruction
79//!
80//! However, there are cases where a single request can result in multiple
81//! responses (i.e. [Multicast] and [Observing]), as well as cases where a single "logical"
82//! request/response can be spread out across many smaller requests and responses
83//! (i.e. [Block transfer]).
84//!
85//! [Multicast]: https://tools.ietf.org/html/rfc7252#section-8
86//! [Observing]: https://tools.ietf.org/html/rfc7641
87//! [Block transfer]: https://tools.ietf.org/html/rfc7959
88//!
89//! Let's take Block2 transfers, for example. Many libraries support Block2 transfers,
90//! often by implementing message reconstruction under-the-hood, which can be very
91//! convenient. The *async-coap* way to do it is similarly convenient:
92//!
93//! ```
94//! # #![feature(async_await)]
95//! # use std::sync::Arc;
96//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
97//! # use async_coap::prelude::*;
98//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
99//! # use async_coap::null::NullLocalEndpoint;
100//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
101//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
102//! # let mut pool = LocalPool::new();
103//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
104//! # let future = async move {
105//! # let mut remote_endpoint = local_endpoint
106//! #    .remote_endpoint_from_uri(uri!("coap://coap.me/test"))
107//! #    .expect("Remote endpoint lookup failed");
108//! // We can change the path on the above remote_endpoint using
109//! // the `clone_using_rel_ref` method:
110//! let mut remote_endpoint = remote_endpoint.clone_using_rel_ref(rel_ref!("/large"));
111//!
112//! // Create a send descriptor that will reconstruct the block2 parts
113//! // and return the reconstituted message.
114//! let send_descriptor = CoapRequest::get()
115//!     .block2(None)
116//!     .emit_successful_collected_response();
117//!
118//! let response = remote_endpoint
119//!     .send(send_descriptor)
120//!     .await
121//!     .expect("CoAP request failed");
122//!
123//! // Print out the response message to standard output.
124//! println!("Reconstructed response: {}", response);
125//! # };
126//! # pool.run_until(future);
127//! ```
128//!
129//! ### Inspection
130//!
131//! The problem with how this is implemented by other CoAP libraries is that it is difficult
132//! or impossible to implement things like progress meters. However, with *async-coap*, we
133//! can add some feedback to the above example very easily using [`inspect`]:
134//!
135//! [`inspect`]: send_desc::SendDescExt::inspect
136//!
137//! ```
138//! # #![feature(async_await)]
139//! # use std::sync::Arc;
140//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
141//! # use async_coap::prelude::*;
142//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
143//! # use async_coap::null::NullLocalEndpoint;
144//! # use async_coap::message::MessageDisplay;
145//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
146//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
147//! # let mut pool = LocalPool::new();
148//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
149//! # let future = async move {
150//! # let mut remote_endpoint = local_endpoint
151//! #    .remote_endpoint_from_uri(uri!("coap://coap.me/test"))
152//! #    .expect("Remote endpoint lookup failed");
153//! # let mut remote_endpoint = remote_endpoint.clone_using_rel_ref(rel_ref!("/large"));
154//! // Create a send descriptor that will reconstruct the block2 parts
155//! // and return the reconstituted message, printing out each individual
156//! // message as we go.
157//! let send_descriptor = CoapRequest::get()
158//!     .block2(None)
159//!     .emit_successful_collected_response()
160//!     .inspect(|context| {
161//!         println!("inspect: Got {}", MessageDisplay(context.message()));
162//!     });
163//!
164//! let response = remote_endpoint
165//!     .send(send_descriptor)
166//!     .await
167//!     .expect("CoAP request failed");
168//!
169//! // Print out the response message to standard output.
170//! println!("Reconstructed response: {}", response);
171//! # };
172//! # pool.run_until(future);
173//! ```
174//!
175//! ### Multiple Responses
176//!
177//! That's all good and well, but what about requests that generate multiple responses, like
178//! multicast requests? For that we use a different
179//! send method: [`send_as_stream`]. Instead of returning a [`Future`], it returns a [`Stream`].
180//! This allows us to collect all of the responses:
181//!
182//! ```no_run
183//! # #![feature(async_await)]
184//! # use std::sync::Arc;
185//! # use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
186//! # use async_coap::prelude::*;
187//! # use async_coap::datagram::{DatagramLocalEndpoint, AllowStdUdpSocket, LoopbackSocket};
188//! # use async_coap::null::NullLocalEndpoint;
189//! # use async_coap::message::MessageDisplay;
190//! # use async_coap::Error;
191//! # use futures_timer::TryFutureExt;
192//! # use std::time::Duration;
193//! # let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
194//! # let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
195//! # let mut pool = LocalPool::new();
196//! # pool.spawner().spawn_local(local_endpoint.clone().receive_loop_arc(null_receiver!()).map(|_|unreachable!()));
197//! # let future = async move {
198//! let mut remote_endpoint = local_endpoint
199//!     .remote_endpoint_from_uri(uri!("coap://[FF02::FD]/.well-known/core"))
200//!     .expect("Remote endpoint lookup failed");
201//!
202//! // Don't let the remote_endpoint include
203//! // a `Uri-Host` host option.
204//! remote_endpoint.remove_host_option();
205//!
206//! let send_descriptor = CoapRequest::get()
207//!     .multicast()
208//!     .accept(ContentFormat::APPLICATION_LINK_FORMAT)
209//!     .emit_successful_response()
210//!     .include_socket_addr();
211//!
212//! let mut stream = remote_endpoint.send_as_stream(send_descriptor);
213//!
214//! while let Some((msg, socket_addr))
215//!     = stream.next().await.transpose().expect("Error on get")
216//! {
217//!     println!("From {} got {}", socket_addr, msg);
218//! }
219//! # };
220//! # pool.run_until(future);
221//! ```
222//!
223//! [`send_as_stream`]: RemoteEndpointExt::send_as_stream
224//! [`Future`]: std::future::Future
225//! [`Stream`]: futures-preview::stream::Stream
226//!
227//! ## Future Work
228//!
229//! This library is currently in the experimental stage, so there are a lot of additional features
230//! and mechanisms that aren't yet implemented. Here is a short list:
231//!
232//! * Support for "effortless" serving of [observable resources][Observing]
233//! * Support for [Block1][Block transfer] transfers.
234//! * Improved support for [observing][Observing] remote resources.
235//! * Make serving resources easier-to-use.
236//! * [OSCORE](https://tools.ietf.org/html/draft-ietf-core-object-security) support.
237//! * Support for supplying alternate [transmission parameters](https://tools.ietf.org/html/rfc7252#section-4.8).
238//! * Support for burst transmissions for nonconfirmable and multicast requests.
239//! * Make sending asynchronous responses easier.
240//!
241//! ### Support for deeply embedded devices
242//!
243//! To the extent possible, the API is designed
244//! to minimize the amount of memory allocation. While it does currently require the `alloc` crate,
245//! that requirement will (hopefully) become optional once the [Generic Associated Types][GAT]
246//! feature lands, without significantly influencing how the API works. This will allow for the
247//! same API to be used for deeply embedded, resource-constrained devices as would be used for
248//! other types of non-resource-constrained devices.
249//!
250//! [GAT]: https://github.com/rust-lang/rust/issues/44265
251//! [`AllowStdUdpSocket`]: crate::datagram::AllowStdUdpSocket
252//!
253//! ## Full Example
254//!
255//! ```
256//! # #![feature(async_await)]
257//! #
258//! use std::sync::Arc;
259//! use futures::{prelude::*,executor::LocalPool,task::LocalSpawnExt};
260//! use async_coap::prelude::*;
261//! use async_coap::datagram::{DatagramLocalEndpoint,AllowStdUdpSocket};
262//!
263//! // Create our asynchronous socket. In this case, it is just an
264//! // (inefficient) wrapper around the standard rust `UdpSocket`,
265//! // but that is quite adequate in this case.
266//! let socket = AllowStdUdpSocket::bind("[::]:0").expect("UDP bind failed");
267//!
268//! // Create a new local endpoint from the socket we just created,
269//! // wrapping it in a `Arc<>` to ensure it can live long enough.
270//! let local_endpoint = Arc::new(DatagramLocalEndpoint::new(socket));
271//!
272//! // Create a local execution pool for running our local endpoint.
273//! let mut pool = LocalPool::new();
274//!
275//! // Quick aside: The `Local` in `LocalPool` is completely unrelated
276//! // to the `Local` in `LocalEndpoint`: a `LocalEndpoint` refers to
277//! // the local side of a CoAP connection. A `LocalPool` is just a
278//! // single-threaded execution pool. A `LocalEndpoint` will run
279//! // just fine on a `ThreadedPool`.
280//!
281//! // Add our local endpoint to the pool, so that it
282//! // can receive packets.
283//! pool.spawner().spawn_local(local_endpoint
284//!     .clone()
285//!     .receive_loop_arc(null_receiver!())
286//!     .map(|err| panic!("Receive loop terminated: {}", err))
287//! );
288//!
289//! // Create a remote endpoint instance to represent the
290//! // device we wish to interact with.
291//! let remote_endpoint = local_endpoint
292//!     .remote_endpoint_from_uri(uri!("coap://coap.me"))
293//!     .unwrap(); // Will only fail if the URI scheme or authority is unrecognizable
294//!
295//! // Create a future that sends a request to a specific path
296//! // on the remote endpoint, collecting any blocks in the response
297//! // and returning `Ok(OwnedImmutableMessage)` upon success.
298//! let future_result = remote_endpoint.send_to(
299//!     rel_ref!("large"),
300//!     CoapRequest::get()                          // This is a CoAP GET request
301//!         .accept(ContentFormat::TEXT_PLAIN_UTF8) // We only want plaintext
302//!         .block2(Some(Default::default()))       // Enable block2 processing
303//!         .emit_successful_collected_response()   // Collect all blocks into a single message
304//! );
305//!
306//! // Wait until we get the result of our request.
307//! let result = pool.run_until(future_result);
308//!
309//! println!("result: {:?}", result);
310//! ```
311//!
312//! Additional examples can be found in the [module documentation for send descriptors][send-desc]
313//! and the [documentation for `LocalEndpoint`][LocalEndpoint].
314//!
315//! [send-desc]: send_desc/index.html
316
317#![feature(async_await)]
318#![cfg_attr(not(feature = "std"), no_std)]
319#![warn(rust_2018_idioms)]
320#![warn(missing_debug_implementations)]
321#![warn(clippy::all)]
322#![warn(missing_docs)]
323
324#[macro_use]
325extern crate log;
326
327pub mod arc_guard;
328use arc_guard::*;
329
330#[doc(hidden)]
331pub use async_coap_uri;
332
333pub mod uri {
334    //! A limited subset of items from the URI-handling [`async-coap-uri`] crate.
335    //!
336    //! See the [`async-coap-uri` crate documentation][`async-coap-uri`] for more details.
337    //!
338    //! [`async-coap-uri`]: ../async_coap_uri/index.html
339    pub use async_coap_uri::escape;
340
341    pub use async_coap_uri::{rel_ref, uri, uri_ref};
342    pub use async_coap_uri::{RelRef, Uri, UriRef};
343    pub use async_coap_uri::{RelRefBuf, UriBuf, UriRefBuf};
344
345    pub use async_coap_uri::{AnyUriRef, UriDisplay, UriType};
346
347    pub use async_coap_uri::{ParseError, ResolveError};
348
349    pub use async_coap_uri::UriRawComponents;
350
351    #[doc(hidden)]
352    pub(super) use async_coap_uri::prelude;
353
354    #[doc(hidden)]
355    pub use async_coap_uri::{assert_rel_ref_literal, assert_uri_literal, assert_uri_ref_literal};
356}
357
358pub mod message;
359pub mod option;
360
361pub mod send_desc;
362use send_desc::*;
363
364mod response_status;
365pub use response_status::ResponseStatus;
366
367mod content_format;
368pub use content_format::ContentFormat;
369
370mod socketaddr;
371pub use socketaddr::SocketAddrExt;
372pub use socketaddr::ToSocketAddrs;
373
374mod block;
375pub use block::*;
376
377mod trans_params;
378pub use trans_params::*;
379
380mod local_endpoint;
381pub use local_endpoint::*;
382
383mod remote_endpoint;
384pub use remote_endpoint::*;
385
386mod send_as_stream;
387pub use send_as_stream::*;
388
389mod receive_as_stream;
390pub use receive_as_stream::*;
391
392mod inbound_context;
393pub use inbound_context::*;
394
395pub mod consts;
396#[doc(hidden)]
397pub use consts::*;
398
399mod error;
400pub use error::*;
401
402mod util;
403use util::*;
404
405pub mod link_format;
406#[doc(hidden)]
407pub use link_format::*;
408
409pub mod datagram;
410pub mod null;
411
412mod etag;
413pub use etag::ETag;
414
415use futures::future::BoxFuture;
416use message::MessageRead;
417use message::MessageWrite;
418
419#[doc(hidden)]
420pub mod prelude {
421    pub use super::uri::prelude::*;
422
423    pub use super::LocalEndpoint;
424    pub use super::LocalEndpointExt;
425
426    pub use super::null_receiver;
427
428    pub use super::RemoteEndpoint;
429    pub use super::RemoteEndpointExt;
430
431    pub use super::send_desc::CoapRequest;
432    pub use super::send_desc::SendDescExt;
433    pub use super::send_desc::SendDescMulticast;
434    pub use super::send_desc::SendDescUnicast;
435
436    pub use super::ContentFormat;
437    pub use super::ResponseStatus;
438
439    pub use super::message::MsgCode;
440    pub use super::message::MsgCodeClass;
441    pub use super::message::MsgId;
442    pub use super::message::MsgToken;
443    pub use super::message::MsgType;
444
445    pub use super::option;
446    pub use option::OptionInsert;
447    pub use option::OptionInsertExt;
448    pub use option::OptionIterator;
449    pub use option::OptionIteratorExt;
450    pub use option::OptionKey;
451    pub use option::OptionNumber;
452
453    pub use super::SocketAddrExt;
454}
455
456use futures::prelude::*;
457use prelude::*;