libcoap_rs/lib.rs
1// SPDX-License-Identifier: BSD-2-Clause
2/*
3 * lib.rs - Main library entry point for safe libcoap bindings.
4 * This file is part of the libcoap-rs crate, see the README and LICENSE files for
5 * more information and terms of use.
6 * Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved.
7 * See the README as well as the LICENSE file for more information.
8 */
9
10#![cfg_attr(feature = "nightly", feature(trait_upcasting))]
11
12//! A safe wrapper around the libcoap C library.
13//!
14//! This wrapper allows for safe and idiomatic usage of the libcoap C library in Rust.
15//!
16//! # Protocol support
17//! libcoap-rs currently supports the following subset of the libcoap feature set:
18//! - [x] Basic CoAP client
19//! - [x] Basic CoAP server
20//! - [ ] Transports:
21//! - [x] UDP
22//! - [-] DTLS
23//! - [x] DTLS using PSK
24//! - [ ] DTLS using PKI/RPK
25//! - [ ] TCP
26//! - [ ] TLS
27//! - [ ] Blockwise Transfer
28//! - [x] Receiving large messages
29//! - Note: Handled by libcoap by setting `COAP_BLOCK_USE_LIBCOAP|COAP_BLOCK_SINGLE_BODY`
30//! - [x] sending client-side large messages
31//! - [ ] sending server-side large messages
32//! - [ ] Resource observation
33//! - [ ] Observing resources as a client
34//! - [x] Notifying observers as a server
35//!
36//! # Examples
37//!
38//! ## Client
39//! This example runs a simple CoAP client which makes a request to `coap://[::1]:5683/hello_world`
40//! and checks whether the result has the code 2.00 (Content) and the paylaod `Hello World!`.
41//!
42//! ```no_run
43//! use std::{
44//! net::{SocketAddr, UdpSocket},
45//! time::Duration,
46//! };
47//!
48//! use libcoap_rs::{
49//! CoapContext,
50//! message::{CoapMessageCommon, CoapResponse, CoapRequest},
51//! protocol::{CoapRequestCode, CoapResponseCode, CoapMessageCode, CoapMessageType},
52//! CoapRequestHandler, CoapResource,
53//! session::{CoapSessionCommon, CoapClientSession},
54//! types::{CoapUriScheme, CoapUri}
55//! };
56//!
57//! use url::Url;
58//!
59//! let server_address : SocketAddr = "[::1]:5683".parse().unwrap();
60//!
61//! // Create a new context.
62//! let mut context = CoapContext::new().expect("Failed to create CoAP context");
63//!
64//! // Connect to the server at the specified address over UDP (plaintext CoAP)//!
65//! let session = CoapClientSession::connect_udp(&mut context, server_address)
66//! .expect("Failed to create client-side session");
67//!
68//! // Create a new CoAP URI to request from.
69//! let uri = CoapUri::try_from_url(Url::parse("coap://[::1]:5683/hello_world").unwrap()).unwrap();
70//!
71//! // Create a new request of type get with the specified URI.
72//! let mut request = CoapRequest::new(CoapMessageType::Con, CoapRequestCode::Get).unwrap();
73//! request.set_uri(Some(uri)).unwrap();
74//!
75//! // Send the request and wait for a response.
76//! let req_handle = session.send_request(request).expect("Unable to send request");
77//! loop {
78//! context.do_io(Some(Duration::from_secs(10))).expect("error during IO");
79//! // Poll for responses to a request using the request handle.
80//! for response in session.poll_handle(&req_handle) {
81//! assert_eq!(response.code(), CoapMessageCode::Response(CoapResponseCode::Content));
82//! assert_eq!(response.data().unwrap().as_ref(), "Hello World!".as_bytes());
83//! return;
84//! }
85//! }
86//! ```
87//!
88//! ## Server
89//! This example runs a simple CoAP server that provides a resource under the URI path
90//! `/hello_world` with `Hello World!` as the response payload.
91//!
92//! ```no_run
93//! use std::{
94//! net::{SocketAddr, UdpSocket},
95//! time::Duration,
96//! };
97//!
98//! use libcoap_rs::{
99//! CoapContext,
100//! message::{CoapMessageCommon, CoapResponse, CoapRequest},
101//! protocol::{CoapRequestCode, CoapResponseCode},
102//! CoapRequestHandler, CoapResource,
103//! session::{CoapSessionCommon, CoapServerSession},
104//! };
105//!
106//! // This will give us a SocketAddress with a port in the local port range automatically
107//! // assigned by the operating system.
108//! // Because the UdpSocket goes out of scope, the Port will be free for usage by libcoap.
109//! // This seems to be the only portable way to get a port number assigned from the operating
110//! // system.
111//! // It is assumed here that after unbinding the temporary socket, the OS will not reassign
112//! // this port until we bind it again. This should work in most cases (unless we run on a
113//! // system with very few free ports), because at least Linux will not reuse port numbers
114//! // unless necessary, see https://unix.stackexchange.com/a/132524.
115//! let server_address = UdpSocket::bind("localhost:0")
116//! .expect("Failed to bind server socket")
117//! .local_addr()
118//! .expect("Failed to get server socket address");
119//!
120//! // a new CoAP context and bind to the generated SocketAddr.
121//! let mut context = CoapContext::new().expect("Failed to create CoAP context");
122//! context.add_endpoint_udp(server_address).expect("Unable to add/bind to endpoint");
123//!
124//! // Create a new resource that is available at the URI path `hello_world`
125//! // The second argument can be used to provide any kind of user-specific data, which will
126//! // then be passed to the handler function.
127//! let resource = CoapResource::new("hello_world", (), false);
128//! // Set a method handler for the GET method.
129//! resource.set_method_handler(
130//! CoapRequestCode::Get,
131//! Some(CoapRequestHandler::new(
132//! // The handler can be a lambda or some other kind of function.
133//! // Using methods is also possible by setting the resource's user data to an instance
134//! // of the struct, as the first argument will then be a mutable reference to the
135//! // user data. Methods will then use this user data as the `&mut self` reference.
136//! //
137//! // The provided CoapResponse is already filled with the correct token to be
138//! // interpreted as a response to the correct request by the client.
139//! |completed: &mut (), session: &mut CoapServerSession, request: &CoapRequest, mut response: CoapResponse| {
140//! // Set content of the response message to "Hello World!"
141//! let data = Vec::<u8>::from("Hello World!".as_bytes());
142//! response.set_data(Some(data));
143//! // Set the response code to 2.00 "Content"
144//! response.set_code(CoapResponseCode::Content);
145//! // Send the response message.
146//! session.send(response).expect("Unable to send response");
147//! },
148//! )),
149//! );
150//!
151//! // Add the resource to the context.
152//! context.add_resource(resource);
153//! loop {
154//! // process IO in a loop...
155//! if let Err(e) = context.do_io(Some(Duration::from_secs(1))) {
156//! break;
157//! }
158//! // ...until we want to shut down.
159//! }
160//! // Properly shut down, completing outstanding IO requests and properly closing sessions.
161//! context.shutdown(Some(Duration::from_secs(0))).unwrap();
162//! ```
163//!
164//! # Using cryptography
165//! If you wish to use CoAP over DTLS, you have to provide credential and key information to
166//! libcoap. To do so, you need to provide an instance of [crypto::CoapClientCryptoProvider]
167//! to [session::CoapClientSession::connect_dtls()] (for client sessions) and/or an instance of
168//! [crypto::CoapServerCryptoProvider] to [CoapContext::set_server_crypto_provider()] (for server
169//! sessions).
170//!
171//! libcoap requires a DTLS library to be selected for DTLS functionality. By default, libcoap-rs
172//! will use `openssl` for this purpose. If you wish to use one of the other supported DTLS
173//! libraries (GnuTLS, MBedTLS, TinyDTLS), disable the `dtls_openssl` feature and replace it with
174//! the feature for the library of your choice.
175//!
176//! Note that enabling multiple backends is not possible and doing so will result in a single
177//! backend being chosen based on the priority order (gnutls > openssl > mbedtls > tinydtls).
178
179mod context;
180#[cfg(feature = "dtls")]
181pub mod crypto;
182pub mod error;
183mod event;
184mod mem;
185pub mod message;
186pub mod protocol;
187mod resource;
188pub mod session;
189pub mod transport;
190pub mod types;
191
192pub use context::CoapContext;
193pub use event::CoapEventHandler;
194pub use resource::{CoapRequestHandler, CoapResource};