diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml
index 874b34ce..0d7e42da 100644
--- a/.github/workflows/report.yml
+++ b/.github/workflows/report.yml
@@ -59,7 +59,7 @@ jobs:
pattern: docs
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- path: coverage-data
+ path: ./doc
- name: 'Get artifact ID'
id: get-artifact-id
uses: actions/github-script@v7
@@ -79,7 +79,7 @@ jobs:
- if: ${{ (github.event.workflow_run.head_repository.owner.login == github.event.workflow_run.repository.owner.login) && (vars.DOCS_AND_COV_REPO != '') }}
uses: peaceiris/actions-gh-pages@v4
with:
- publish_dir: ./target/doc
+ publish_dir: ./doc
publish_branch: main
external_repository: ${{ vars.DOCS_AND_COV_REPO }}
personal_token: ${{ secrets.DOCS_AND_COV_REPO_TOKEN }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f3e05a6e..2cb36940 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -30,18 +30,20 @@ jobs:
RUSTDOCFLAGS: "${{ matrix.rust_version == 'nightly' && '-C instrument-coverage -Cpanic=abort -Zpanic_abort_tests -Z unstable-options --persist-doctests target/debug/doctests' || ' ' }}"
LIBRARY_FEATURES: |
${{ (matrix.crate == 'libcoap-rs' && 'tcp,vendored,rand')
- || (matrix.crate == 'libcoap-sys' && 'default')
+ || (matrix.crate == 'libcoap-sys' && 'default,vendored')
|| 'vendored'
}}
+ LIBCOAP_RS_DTLS_BACKEND: ${{ matrix.dtls_backend }}
+ LIBCOAP_RS_BUILD_SYSTEM: "vendored"
DTLS_LIBRARY_FEATURES: |
- ${{ (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'tinydtls' && 'tcp,dtls-psk,dtls-rpk,dtls_tinydtls_vendored')
- || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'mbedtls' && 'tcp,dtls-psk,dtls-pki,dtls_mbedtls_vendored')
- || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'openssl' && 'tcp,dtls-psk,dtls-pki,dtls_openssl_vendored')
- || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'gnutls' && 'tcp,dtls-psk,dtls-pki,dtls-rpk,dtls_gnutls')
- || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'tinydtls' && 'dtls,dtls_backend_tinydtls,dtls_backend_tinydtls_vendored')
- || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'mbedtls' && 'dtls,dtls_backend_mbedtls,dtls_backend_mbedtls_vendored')
- || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'openssl' && 'dtls,dtls_backend_openssl,dtls_backend_openssl_vendored')
- || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'gnutls' && 'dtls,dtls_backend_gnutls')
+ ${{ (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'tinydtls' && 'tcp,dtls-psk,dtls-rpk,dtls-tinydtls-sys-vendored')
+ || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'mbedtls' && 'tcp,dtls-psk,dtls-pki,dtls-mbedtls-sys')
+ || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'openssl' && 'tcp,dtls-psk,dtls-pki,dtls-openssl-sys-vendored')
+ || (matrix.crate == 'libcoap-rs' && matrix.dtls_backend == 'gnutls' && 'tcp,dtls-psk,dtls-pki,dtls-rpk')
+ || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'tinydtls' && 'dtls,dtls-tinydtls-sys-vendored')
+ || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'mbedtls' && 'dtls,dtls-mbedtls-sys')
+ || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'openssl' && 'dtls,dtls-openssl-sys-vendored')
+ || (matrix.crate == 'libcoap-sys' && matrix.dtls_backend == 'gnutls' && 'dtls')
|| 'vendored'
}}
steps:
@@ -51,9 +53,9 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
components: rust-src, rustc, rust-std, cargo, llvm-tools, llvm-tools-preview
- toolchain: ${{ matrix.rust_version == 'msrv' && '1.81' || matrix.rust_version }}
+ toolchain: ${{ matrix.rust_version == 'msrv' && '1.82' || matrix.rust_version }}
- if: matrix.dtls_backend == 'gnutls'
- uses: awalsh128/cache-apt-pkgs-action@latest
+ uses: awalsh128/cache-apt-pkgs-action@v1.4.3
with:
packages: libgnutls28-dev libgnutls30
version: 1.0
@@ -105,7 +107,7 @@ jobs:
submodules: true
ref: ${{ env.HEAD_REF }}
# --all-features uses GNUTLS as backend, must provide it.
- - uses: awalsh128/cache-apt-pkgs-action@latest
+ - uses: awalsh128/cache-apt-pkgs-action@v1.4.3
with:
packages: libgnutls28-dev libgnutls30
version: 1.0
diff --git a/.idea/libcoap-rs.iml b/.idea/libcoap-rs.iml
index 84e5d2c4..e82ac0ec 100644
--- a/.idea/libcoap-rs.iml
+++ b/.idea/libcoap-rs.iml
@@ -5,7 +5,15 @@
+
+
+
+
+
+
+
+
diff --git a/libcoap-sys/Cargo.toml b/libcoap-sys/Cargo.toml
index 769576b4..08faf2ee 100644
--- a/libcoap-sys/Cargo.toml
+++ b/libcoap-sys/Cargo.toml
@@ -18,54 +18,56 @@ categories = ["external-ffi-bindings", "network-programming", "embedded"]
keywords = ["coap", "libcoap"]
exclude = ["src/libcoap/ext/"]
resolver = "2"
-# Current reason for MSRV (please update when increasing MSRV): Transient dependency "home" requires Rust 1.81.
-rust-version = "1.81.0"
+build = "build/main.rs"
+# Current reason for MSRV (please update when increasing MSRV): bindgen generates unsafe extern "C" blocks, which are
+# not supported on Rust < 1.82.
+# See also: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html
+rust-version = "1.82.0"
[features]
-# The default features match those of libcoaps configure script, except for dtls, which is disabled here because it
-# requires a backend to be set manually.
-default = ["oscore", "ipv4", "ipv6", "af-unix", "tcp", "websockets", "async", "observe-persist", "q-block", "thread-safe", "thread-recursive-lock-detection", "server", "client", "epoll", "vendored", "static"]
-# While not specified here due to limitations in Cargo's syntax, the DTLS feature depends on one of the DTLS backends
-# being enabled.
-# If you are developing a library based on libcoap-sys and do not care about the DTLS backend, enable the dtls feature
-# and let the user decide on the backend to use, either by re-exporting these features (see
-# https://doc.rust-lang.org/cargo/reference/features.html#dependency-features) or by assuming that the user will use
-# libcoap-sys as a dependency and enable the corresponding backend feature themselves, relying on Cargo's feature
-# unification to enable it for your crate as well.
-# Also note that the backends are **mutually exclusive** due to the C library having these backends as mutually
-# exclusive features. If multiple backends are enabled (e.g. because multiple dependencies use libcoap-sys and use
-# different backends), we select one based on the auto-detection order specified in
-# https://github.com/obgm/libcoap/blob/develop/configure.ac#L494 (gnutls > openssl > mbedtls > tinydtls).
+# The default features match those of libcoap's configure script for
+# the minimum supported version.
+default = [
+ "dtls",
+ "oscore",
+ "ipv4",
+ "ipv6",
+ "af-unix",
+ "tcp",
+ "websockets",
+ "async",
+ "observe-persist",
+ "q-block",
+ "thread-safe",
+ "thread-recursive-lock-detection",
+ "server",
+ "client",
+ "epoll",
+ # TODO add proxy
+]
+# Allows using the version of OpenSSL provided by openssl-sys instead of a system-provided one.
+# Note that this does not enforce the use of OpenSSL in libcoap, see the crate-level documentation for more info.
+dtls-openssl-sys = ["dep:openssl-sys"]
+# Tell the openssl-sys version that is possibly used by libcoap-sys to use the vendored version of its library.
+dtls-openssl-sys-vendored = ["dtls-openssl-sys", "openssl-sys/vendored"]
+# Allows using the version of MbedTLS provided by mbedtls-sys-auto instead of a system-provided one.
+# Note that this does not enforce the use of MbedTLS in libcoap, see the crate-level documentation for more info.
+dtls-mbedtls-sys = ["dep:mbedtls-sys-auto"]
+# Allows using the version of TinyDTLS provided by tinydtls-sys instead of a system-provided one.
+# Note that this does not enforce the use of TinyDTLS in libcoap, see the crate-level documentation for more info.
+dtls-tinydtls-sys = ["dep:tinydtls-sys", "tinydtls-sys/ecc", "tinydtls-sys/psk"]
+# Tell the tinydtls-sys version that is possibly used by libcoap-sys to use the vendored version of its library.
+dtls-tinydtls-sys-vendored = ["dtls-tinydtls-sys", "tinydtls-sys/vendored"]
-# Corresponding libcoap configure flag: --with-openssl
-dtls_backend_openssl = ["dtls", "dep:openssl-sys"]
-dtls_backend_openssl_vendored = ["dtls_backend_openssl", "openssl-sys/vendored"]
-# Corresponding libcoap configure flag: --with-gnutls
-dtls_backend_gnutls = ["dtls"]
-# Corresponding libcoap configure flag: --with-mbedtls
-dtls_backend_mbedtls = ["dtls"] # can't use mbedtls-sys-auto to generate linker flags here, as the crate doesn't support mbedtls >= 3.0.0
-dtls_backend_mbedtls_vendored = ["dep:mbedtls-sys-auto", "dtls_backend_mbedtls"]
-# Corresponding libcoap configure flags: --with-tinydtls --without-submodule-tinydtls
-dtls_backend_tinydtls = ["dtls", "dep:tinydtls-sys", "tinydtls-sys/ecc", "tinydtls-sys/psk"]
-dtls_backend_tinydtls_vendored = ["dtls_backend_tinydtls", "tinydtls-sys/vendored"]
-# Enabling this feature will force libcoap-sys to be built with and statically linked to a vendored version of libcoap,
-# which will be built by the build-script before building libcoap-sys.
+# Enabling this feature will allow libcoap-sys to be built with and statically linked to a vendored version of libcoap,
# This way, it is no longer required to have libcoap installed to use this crate.
-vendored = ["static"]
-# Enable this feature to use static linking to libcoap instead of dynamic linking.
-static = []
+vendored = []
# --- FEATURE FLAGS ---
-# Note that setting the feature flags currently has no effect on the generated Rust code, because the libcoap headers do
-# not use these feature flags. They only affect the features built into the vendored C library (if enabled).
-
# Enable this feature to enable/require CoAP over DTLS support in the C library.
-# Important: also read the section on DTLS backends before enabling this feature.
# Corresponding libcoap configure flag: --enable-dtls
dtls = []
# Enable this feature to enable/require TLS support in addition to DTLS support.
-# Note: Will also enable the TCP and DTLS features, so consider the above section regarding DTLS backends before +
-# enabling this.
tls = ["dtls", "tcp"]
# Enable this feature to enable/require OSCORE functionality in the C library.
# Corresponding libcoap configure flag: --enable-oscore
@@ -137,24 +139,28 @@ dtls-rpk = ["dtls"]
[dependencies]
openssl-sys = { version = "^0.9.74", optional = true }
mbedtls-sys-auto = { version = "^2.26", optional = true }
-libc = "^0.2.126"
tinydtls-sys = { version = "^0.2.0", default-features = false, optional = true }
[target.'cfg(target_os="espidf")'.dependencies]
-esp-idf-sys = { version = "0.35.0" }
+esp-idf-sys = { version = "0.36.1" }
+
+[target.'cfg(not(target_os="espidf"))'.dependencies]
+libc = "0.2.126"
[build-dependencies]
-bindgen = "0.69.4"
+bindgen = { version = "0.71.1" }
autotools = "^0.2.3"
fs_extra = "^1.2"
pkg-config = "^0.3.24"
-regex = "1.10.5"
-embuild = { version = "0.32.0", features = ["bindgen", "espidf", "cmake"] }
version-compare = "0.2.0"
+anyhow = { version = "1.0.94", features = ["backtrace"] }
+enumset = "1.1.5"
+syn = { version = "2.0.96" }
+embuild = { version = "0.33.0", features = ["espidf"] }
[package.metadata.docs.rs]
features = ["dtls", "dtls_backend_openssl", "vendored"]
[[package.metadata.esp-idf-sys.extra_components]]
-remote_component = { name = "espressif/coap", version = "4.3.4~3" }
+remote_component = { name = "espressif/coap", version = "4.3.5~3" }
bindings_header = "src/wrapper.h"
diff --git a/libcoap-sys/build.rs b/libcoap-sys/build.rs
deleted file mode 100644
index 476c0e3f..00000000
--- a/libcoap-sys/build.rs
+++ /dev/null
@@ -1,804 +0,0 @@
-// SPDX-License-Identifier: BSD-2-CLAUSE
-/*
- * build.rs - build script for libcoap Rust bindings.
- * This file is part of the libcoap-sys crate, see the README and LICENSE files for
- * more information and terms of use.
- * Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved.
- * See the README as well as the LICENSE file for more information.
- */
-
-use std::{
- cell::RefCell,
- collections::BTreeSet,
- default::Default,
- env,
- ffi::{OsStr, OsString},
- fmt::{Debug, Display},
- io::ErrorKind,
- path::{Path, PathBuf},
- process::Command,
- rc::Rc,
-};
-
-use bindgen::{
- callbacks::{IntKind, ParseCallbacks},
- EnumVariation,
-};
-use pkg_config::probe_library;
-use version_compare::{Cmp, Version};
-
-/// Features whose availability can be checked during compile time based on `#define` directives.
-const COMPILE_TIME_FEATURE_CHECKS: [&str; 16] = [
- "af-unix",
- "async",
- "client",
- "small-stack",
- "tcp",
- "epoll",
- "ipv4",
- "ipv6",
- "oscore",
- "q-block",
- "server",
- "thread-recursive-lock-detection",
- "thread-safe",
- "dtls",
- "observe-persist",
- "websockets",
-];
-
-/// Data structure describing meta-information about the used version of libcoap.
-#[derive(Debug)]
-struct LibcoapMetadata {
- package_version: String,
- version: i64,
- feature_defines_available: bool,
- feature_defines: BTreeSet,
- dtls_backend: Option,
-}
-
-impl Default for LibcoapMetadata {
- fn default() -> Self {
- Self {
- package_version: Default::default(),
- version: 0,
- feature_defines_available: false,
- // By default, TCP is assumed to be supported if COAP_DISABLE_TCP is unset.
- feature_defines: BTreeSet::from(["tcp".to_string()]),
- dtls_backend: None,
- }
- }
-}
-
-/// Implementation of bindgen's [ParseCallbacks] that allow reading some meta-information about the
-/// used libcoap version from its defines (package version, supported features, ...)
-#[derive(Debug, Default)]
-struct CoapDefineParser {
- defines: Rc>,
-}
-
-impl ParseCallbacks for CoapDefineParser {
- fn int_macro(&self, name: &str, value: i64) -> Option {
- match name {
- "LIBCOAP_VERSION" => {
- self.defines.borrow_mut().version = value;
- },
- "COAP_AF_UNIX_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("af-unix".to_string());
- },
- "COAP_ASYNC_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("async".to_string());
- },
- "COAP_CLIENT_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("client".to_string());
- },
- "COAP_CONSTRAINED_STACK" => {
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("small-stack".to_string());
- },
- "COAP_DISABLE_TCP" => {
- if value == 1 {
- self.defines.borrow_mut().feature_defines.remove("tcp");
- }
- },
- "COAP_EPOLL_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("epoll".to_string());
- },
- "COAP_IPV4_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("ipv4".to_string());
- },
- "COAP_IPV6_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("ipv6".to_string());
- },
- "COAP_OSCORE_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("oscore".to_string());
- },
- "COAP_Q_BLOCK_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("q-block".to_string());
- },
- "COAP_SERVER_SUPPORT" => {
- self.defines.borrow_mut().feature_defines.insert("server".to_string());
- },
- "COAP_THREAD_RECURSIVE_CHECK" => {
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("thread-recursive-lock-detection".to_string());
- },
- "COAP_THREAD_SAFE" => {
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("thread-safe".to_string());
- },
- "COAP_WITH_LIBGNUTLS" => {
- self.defines.borrow_mut().dtls_backend = Some(DtlsBackend::GnuTls);
- self.defines.borrow_mut().feature_defines.insert("dtls".to_string());
- },
- "COAP_WITH_LIBMBEDTLS" => {
- self.defines.borrow_mut().dtls_backend = Some(DtlsBackend::MbedTls);
- self.defines.borrow_mut().feature_defines.insert("dtls".to_string());
- },
- "COAP_WITH_LIBOPENSSL" => {
- self.defines.borrow_mut().dtls_backend = Some(DtlsBackend::OpenSsl);
- self.defines.borrow_mut().feature_defines.insert("dtls".to_string());
- },
- "COAP_WITH_LIBTINYDTLS" => {
- self.defines.borrow_mut().dtls_backend = Some(DtlsBackend::TinyDtls);
- self.defines.borrow_mut().feature_defines.insert("dtls".to_string());
- },
- // TODO(#29): as soon as we have wolfSSL support in libcoap-sys
- /*"COAP_WITH_LIBWOLFSSL" => {
- self.defines.borrow_mut().dtls_backend = Some(DtlsBackend::WolfSsl);
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("dtls".to_string());
- },*/
- "COAP_WITH_OBSERVE_PERSIST" => {
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("observe-persist".to_string());
- },
- "COAP_WS_SUPPORT" => {
- self.defines
- .borrow_mut()
- .feature_defines
- .insert("websockets".to_string());
- },
- _ => {},
- }
- None
- }
-
- fn str_macro(&self, name: &str, value: &[u8]) {
- // Will allow this here, as we might want to add additional cfg flags later on.
- #[allow(clippy::single_match)]
- match name {
- "LIBCOAP_PACKAGE_VERSION" => {
- let version_str = String::from_utf8_lossy(value);
- println!("cargo:rustc-cfg=libcoap_version=\"{}\"", version_str.as_ref());
- println!("cargo:libcoap_version={}", version_str.as_ref());
- let version = Version::from(version_str.as_ref()).expect("invalid libcoap version");
- match version.compare(Version::from("4.3.4").unwrap()) {
- Cmp::Gt => println!("cargo:rustc-cfg=non_inlined_coap_send_rst"),
- _ => {},
- }
- self.defines.borrow_mut().package_version = version.to_string();
- },
- _ => {},
- }
- }
-
- fn include_file(&self, filename: &str) {
- let header_path = Path::new(filename);
- if header_path.file_name().eq(&Some(OsStr::new("coap_defines.h"))) {
- self.defines.borrow_mut().feature_defines_available = true;
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum DtlsBackend {
- GnuTls,
- OpenSsl,
- MbedTls,
- TinyDtls,
-}
-impl Display for DtlsBackend {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let str = match self {
- DtlsBackend::GnuTls => "gnutls",
- DtlsBackend::OpenSsl => "openssl",
- DtlsBackend::MbedTls => "mbedtls",
- DtlsBackend::TinyDtls => "tinydtls",
- }
- .to_string();
- write!(f, "{}", str)
- }
-}
-
-fn get_target_mcu() -> &'static str {
- let cfg_flags = embuild::espidf::sysenv::cfg_args().expect("missing cfg flags from IDF");
- let mcus = [
- "esp32", "esp32s2", "esp32s3", "esp32c3", "esp32c2", "esp32h2", "esp32c5", "esp32c6", "esp32p4",
- ];
- for mcu in mcus {
- if cfg_flags.get(mcu).is_some() {
- return mcu;
- }
- }
- panic!("unknown ESP target MCU, please add target to libcoap-sys build.rs file!")
-}
-
-fn get_builder_espidf() -> bindgen::Builder {
- embuild::espidf::sysenv::output();
- let esp_idf_path = embuild::espidf::sysenv::idf_path().expect("missing IDF path");
- let esp_idf_buildroot = env::var("DEP_ESP_IDF_ROOT").expect("DEP_ESP_IDF_ROOT is not set");
- let esp_include_path = embuild::espidf::sysenv::cincl_args().expect("missing IDF cincl args");
- let embuild_env = embuild::espidf::sysenv::env_path().expect("missing IDF env path");
- let esp_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH is not set");
-
- // Determine compiler path
- // SAFETY: Always safe to call in a single-threaded environment (see docs of env::set_var).
- unsafe { env::set_var("PATH", embuild_env) };
- let cmake_info = embuild::cmake::Query::new(
- &Path::new(&esp_idf_buildroot).join("build"),
- "cargo",
- &[
- embuild::cmake::file_api::ObjKind::Codemodel,
- embuild::cmake::file_api::ObjKind::Toolchains,
- embuild::cmake::file_api::ObjKind::Cache,
- ],
- )
- .expect("unable to query cmake API for compiler path")
- .get_replies()
- .expect("unable to get cmake query replies for compiler path");
- let compiler = cmake_info
- .get_toolchains()
- .map_err(|_e| "Can't get toolchains")
- .and_then(|mut t| {
- t.take(embuild::cmake::file_api::codemodel::Language::C)
- .ok_or("No C toolchain")
- })
- .and_then(|t| t.compiler.path.ok_or("No compiler path set"))
- .expect("unable to determine compiler path");
-
- // Parse include arguments
- // Regexes are correct and never change, therefore it is ok to unwrap here.
- let arg_splitter = regex::Regex::new(r##"(?:[^\\]"[^"]*[^\\]")?(\s)"##).unwrap();
- let apostrophe_remover = regex::Regex::new(r##"^"(?.*)"$"##).unwrap();
- let esp_clang_args = arg_splitter
- .split(esp_include_path.args.as_str())
- .map(|x| apostrophe_remover.replace(x.trim(), "$content").to_string())
- .collect::>();
- let bindgen_builder = embuild::bindgen::Factory {
- clang_args: esp_clang_args.clone(),
- linker: Some(compiler),
- mcu: None,
- force_cpp: false,
- sysroot: None,
- }
- .builder()
- .expect("unable to create bindgen builder for libcoap bindings from ESP-IDF");
-
- let clang_target = if esp_arch.starts_with("riscv32") {
- "riscv32"
- } else {
- esp_arch.as_str()
- };
- let short_target = if esp_arch.starts_with("riscv32") {
- "riscv"
- } else {
- esp_arch.as_str()
- };
- let target_mcu = get_target_mcu();
-
- bindgen_builder
- .clang_args(&esp_clang_args)
- .clang_arg("-target")
- .clang_arg(clang_target)
- .clang_arg("-DESP_PLATFORM")
- .clang_arg("-DLWIP_IPV4=1")
- .clang_arg("-DLWIP_IPV6=1")
- .clang_arg("-DconfigUSE_PASSIVE_IDLE_HOOK=1")
- .clang_arg(format!("-I{}/components/newlib/platform_include", esp_idf_path))
- .clang_arg(format!("-I{}/components/lwip/port/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/lwip/port/esp32xx/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/lwip/lwip/src/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/lwip/port/freertos/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/esp_system/include", esp_idf_path))
- .clang_arg(format!(
- "-I{}/components/freertos/config/include/freertos",
- esp_idf_path
- ))
- .clang_arg(format!("-I{}/components/freertos/esp_additions/include", esp_idf_path))
- .clang_arg(format!(
- "-I{}/components/freertos/esp_additions/include/freertos",
- esp_idf_path
- ))
- .clang_arg(format!(
- "-I{}/components/freertos/esp_additions/arch/{}/include",
- esp_idf_path, short_target
- )) // for older espidf
- .clang_arg(format!(
- "-I{}/components/freertos/config/{}/include",
- esp_idf_path, short_target
- )) // for newer espidf
- .clang_arg(format!("-I{}/components/{}/include", esp_idf_path, short_target))
- .clang_arg(format!(
- "-I{}/components/{}/{}/include",
- esp_idf_path, short_target, target_mcu
- ))
- .clang_arg(format!("-I{}/components/esp_hw_support/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/esp_common/include", esp_idf_path))
- .clang_arg(format!(
- "-I{}/components/freertos/FreeRTOS-Kernel-SMP/include",
- esp_idf_path
- ))
- .clang_arg(format!(
- "-I{}/components/freertos/FreeRTOS-Kernel-SMP/portable/{}/include/freertos",
- esp_idf_path, short_target
- ))
- .clang_arg(format!("-I{}/components/soc/{}/include", esp_idf_path, target_mcu))
- .clang_arg(format!("-I{}/components/heap/include", esp_idf_path))
- .clang_arg(format!("-I{}/components/esp_rom/include", esp_idf_path))
- .clang_arg(format!(
- "-I{}/managed_components/espressif__coap/port/include",
- esp_idf_buildroot
- ))
- .clang_arg(format!(
- "-I{}/managed_components/espressif__coap/libcoap/include",
- esp_idf_buildroot
- ))
- .clang_arg(format!("-I{}/build/config/", esp_idf_buildroot))
- .allowlist_type("epoll_event")
-}
-
-fn get_builder() -> bindgen::Builder {
- bindgen::Builder::default().blocklist_type("epoll_event")
-}
-
-fn build_vendored_library(
- out_dir: &OsString,
- dtls_backend: Option<&DtlsBackend>,
- mut builder: bindgen::Builder,
-) -> bindgen::Builder {
- let libcoap_src_dir = Path::new(&out_dir).join("libcoap");
-
- // Even though libcoap supports out-of-source builds, autogen.sh (or the corresponding
- // autotools) modify files in the source tree, which causes verification problems when
- // running cargo package.
- // Therefore, we copy the libcoap source over to the output directory and build from there.
- let copy_options = fs_extra::dir::CopyOptions {
- overwrite: true,
- ..Default::default()
- };
- match std::fs::remove_dir_all(&libcoap_src_dir) {
- Ok(_) => {},
- Err(e) if e.kind() == ErrorKind::NotFound => {},
- e => e.expect("unable to clear libcoap build directory"),
- }
- fs_extra::dir::copy(
- Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("libcoap"),
- Path::new(&out_dir),
- ©_options,
- )
- .expect("unable to prepare libcoap build source directory");
- let current_dir_backup = env::current_dir().expect("unable to get current directory");
- env::set_current_dir(&libcoap_src_dir).expect("unable to change to libcoap build dir");
- Command::new(libcoap_src_dir.join("autogen.sh"))
- .status()
- .expect("unable to execute autogen.sh");
- let mut build_config = autotools::Config::new(&libcoap_src_dir);
- build_config.out_dir(out_dir);
- if let Some(dtls_backend) = dtls_backend {
- build_config
- .enable("dtls", None)
- .with(dtls_backend.to_string().as_str(), None);
-
- // If DTLS is vendored we need to tell libcoap about the vendored version
- match dtls_backend {
- DtlsBackend::TinyDtls => {
- // We do not ship tinydtls with our source distribution. Instead, we use tinydtls-sys.
- build_config.without("submodule-tinydtls", None);
-
- // If tinydtls-sys is built with the vendored feature, the library is built alongside
- // the Rust crate. To use the version built by the tinydtls-sys build script, we use the
- // environment variables set by the build script.
- if let Some(tinydtls_include) = env::var_os("DEP_TINYDTLS_INCLUDE") {
- build_config.env(
- "TinyDTLS_CFLAGS",
- format!(
- "-I{} -I{}",
- tinydtls_include
- .to_str()
- .expect("DEP_TINYDTLS_INCLUDE is not a valid string"),
- Path::new(&tinydtls_include)
- .join("tinydtls")
- .to_str()
- .expect("DEP_TINYDTLS_INCLUDE is not a valid string")
- ),
- );
- };
-
- if let Some(tinydtls_libs) = env::var_os("DEP_TINYDTLS_LIBS") {
- build_config.env(
- "TinyDTLS_LIBS",
- format!(
- "-L{}",
- tinydtls_libs.to_str().expect("DEP_TINYDTLS_LIBS is invalid string")
- ),
- );
-
- build_config.env(
- "PKG_CONFIG_PATH",
- Path::new(tinydtls_libs.as_os_str())
- .join("lib")
- .join("pkgconfig")
- .into_os_string(),
- );
- }
- },
- DtlsBackend::OpenSsl => {
- // Set include path according to the path provided by openssl-sys (relevant if
- // openssl-sys is vendored)
- if let Some(openssl_include) = env::var_os("DEP_OPENSSL_INCLUDE") {
- build_config.env(
- "OpenSSL_CFLAGS",
- format!(
- "-I{}",
- openssl_include.to_str().expect("DEP_OPENSSL_INCLUDE is invalid path")
- ),
- );
- build_config.env(
- "PKG_CONFIG_PATH",
- Path::new(openssl_include.as_os_str())
- .parent()
- .expect("DEP_OPENSSL_INCLUDE has no parent directory")
- .join("lib")
- .join("pkgconfig")
- .into_os_string(),
- );
- }
- },
- DtlsBackend::MbedTls => {
- // Set include path according to the path provided by mbedtls-sys (relevant if
- // mbedtls-sys is vendored).
- // libcoap doesn't support overriding the MbedTLS CFLAGS, but doesn't set those
- // either, so we just set CFLAGS and hope they propagate.
- if let Some(mbedtls_include) = env::var_os("DEP_MBEDTLS_INCLUDE") {
- // the config.h of mbedtls-sys-auto is generated separately from all other
- // includes in the root of mbedtls-sys-auto's OUT_DIR.
- // In order to let libcoap read use the correct config file, we need to copy
- // this file into our own OUT_DIR under include/mbedtls/config.h, so that we
- // can then set OUT_DIR/include as an additional include path.
- let config_h = env::var_os("DEP_MBEDTLS_CONFIG_H")
- .expect("DEP_MBEDTLS_INCLUDE is set but DEP_MBEDTLS_CONFIG_H is not");
- let config_path = Path::new(&config_h);
- let out_include = Path::new(&out_dir).join("include");
- std::fs::create_dir_all(out_include.join("mbedtls"))
- .expect("unable to prepare include directory for mbedtls config.h");
- std::fs::copy(config_path, out_include.join("mbedtls").join("config.h"))
- .expect("unable to copy mbedtls config.h to include directory");
- let mbedtls_library_path = config_path
- .parent()
- .expect("DEP_MBEDTLS_CONFIG_H has no parent directory")
- .join("build")
- .join("library");
- build_config.env(
- "MbedTLS_CFLAGS",
- format!(
- "-I{} -I{}",
- out_include.to_str().expect("OUT_DIR is not a valid string"),
- mbedtls_include
- .to_str()
- .expect("DEP_MBEDTLS_INCLUDE is not a valid string")
- ),
- );
- build_config.env(
- "MbedTLS_LIBS",
- format!(
- "-L{0} -l:libmbedtls.a -l:libmbedcrypto.a -l:libmbedx509.a",
- mbedtls_library_path
- .to_str()
- .expect("DEP_MBEDTLS_CONFIG_H is not a valid string"),
- ),
- );
- }
- },
- DtlsBackend::GnuTls => {
- // Vendoring not supported
- },
- }
- } else {
- build_config.disable("dtls", None);
- }
- build_config
- // Disable shared library compilation because the vendored library will always be
- // statically linked
- .disable("shared", None)
- // Disable any documentation for vendored C library
- .disable("documentation", None)
- .disable("doxygen", None)
- .disable("manpages", None)
- // This would install the license into the documentation directory, but we don't use the
- // generated documentation anywhere.
- .disable("license-install", None)
- // Disable tests and examples as well as test coverage
- .disable("tests", None)
- .disable("examples", None)
- .disable("gcov", None);
-
- // Enable debug symbols if enabled in Rust
- match env::var_os("DEBUG")
- .expect("env variable DEBUG that should have been set by cargo is not set")
- .to_str()
- .expect("env variable DEBUG is not valid")
- {
- "0" | "false" => {},
- _ => {
- build_config.with("debug", None);
- },
- }
- // Enable dependency features based on selected cargo features.
- build_config
- .enable("oscore", Some(if cfg!(feature = "oscore") { "yes" } else { "no" }))
- .enable("ipv4-support", Some(if cfg!(feature = "ipv4") { "yes" } else { "no" }))
- .enable("ipv6-support", Some(if cfg!(feature = "ipv6") { "yes" } else { "no" }))
- .enable(
- "af-unix-support",
- Some(if cfg!(feature = "af-unix") { "yes" } else { "no" }),
- )
- .enable("tcp", Some(if cfg!(feature = "tcp") { "yes" } else { "no" }))
- .enable(
- "websockets",
- Some(if cfg!(feature = "websockets") { "yes" } else { "no" }),
- )
- .enable("async", Some(if cfg!(feature = "async") { "yes" } else { "no" }))
- .enable(
- "observe-persist",
- Some(if cfg!(feature = "observe-persist") { "yes" } else { "no" }),
- )
- .enable("q-block", Some(if cfg!(feature = "q-block") { "yes" } else { "no" }))
- .enable(
- "thread-safe",
- Some(if cfg!(feature = "thread-safe") { "yes" } else { "no" }),
- )
- .enable(
- "thread-recursive-lock-detection",
- Some(if cfg!(feature = "thread-recursive-lock-detection") {
- "yes"
- } else {
- "no"
- }),
- )
- .enable(
- "small-stack",
- Some(if cfg!(feature = "small-stack") { "yes" } else { "no" }),
- )
- .enable("server-mode", Some(if cfg!(feature = "server") { "yes" } else { "no" }))
- .enable("client-mode", Some(if cfg!(feature = "client") { "yes" } else { "no" }))
- .with("epoll", Some(if cfg!(feature = "epoll") { "yes" } else { "no" }));
-
- // Run build
- let dst = build_config.build();
-
- // Add the built library to the search path
- println!(
- "cargo:rustc-link-search=native={}",
- dst.join("lib")
- .to_str()
- .expect("libcoap build output dir is not a valid string")
- );
- println!(
- "cargo:include={}",
- dst.join("include")
- .to_str()
- .expect("libcoap build output dir is not a valid string")
- );
- builder = builder
- .clang_arg(format!(
- "-I{}",
- dst.join("include")
- .to_str()
- .expect("libcoap build output dir is not a valid string")
- ))
- .clang_arg(format!(
- "-L{}",
- dst.join("lib")
- .to_str()
- .expect("libcoap build output dir is not a valid string")
- ));
- env::set_current_dir(current_dir_backup).expect("unable to switch back to source dir");
- builder
-}
-
-fn main() {
- println!("cargo::rustc-check-cfg=cfg(feature_checks_available)");
- println!("cargo::rustc-check-cfg=cfg(non_inlined_coap_send_rst)");
- println!("cargo:rerun-if-changed=src/libcoap/");
- println!("cargo:rerun-if-changed=src/wrapper.h");
- // Read required environment variables.
- let out_dir = env::var_os("OUT_DIR").expect("unsupported OUT_DIR");
- let target_os = env::var("CARGO_CFG_TARGET_OS").expect("invalid TARGET_OS environment variable");
-
- let mut bindgen_builder = match target_os.as_str() {
- "espidf" => get_builder_espidf(),
- _ => get_builder(),
- };
-
- let mut dtls_backend = Option::None;
- if cfg!(feature = "dtls") {
- // We can only select one TLS backend at a time for libcoap, but cargo does not support mutually
- // exclusive features, and it would be really bad if a project that uses multiple dependencies
- // which depend on different TLS backends would not compile.
- // Therefore, if multiple TLS backend features are enabled, we choose one based on the following
- // priority order: gnutls > openssl > mbedtls > tinydtls, matching the order specified in
- // https://github.com/obgm/libcoap/blob/develop/configure.ac#L494
- let mut multiple_backends = false;
- if cfg!(feature = "dtls_backend_tinydtls") {
- dtls_backend = Some(DtlsBackend::TinyDtls);
- }
- if cfg!(feature = "dtls_backend_mbedtls") {
- if dtls_backend.is_some() {
- multiple_backends = true;
- }
- println!("cargo:rerun-if-env-changed=MBEDTLS_LIBRARY_PATH");
- dtls_backend = Some(DtlsBackend::MbedTls);
- }
- if cfg!(feature = "dtls_backend_openssl") {
- if dtls_backend.is_some() {
- multiple_backends = true;
- }
- dtls_backend = Some(DtlsBackend::OpenSsl);
- }
- if cfg!(feature = "dtls_backend_gnutls") {
- if dtls_backend.is_some() {
- multiple_backends = true;
- }
- dtls_backend = Some(DtlsBackend::GnuTls);
- }
- if multiple_backends {
- // more than one backend was set, so unwrapping is ok here.
- println!("cargo:warning=Multiple DTLS backends enabled for libcoap-sys. Only one can be enabled, choosing {:?} as the backend to use. This may cause problems.", dtls_backend.as_ref().unwrap());
- }
- if dtls_backend.is_none() {
- println!("cargo:warning=No DTLS backend selected for libcoap-sys, aborting build.");
- panic!("No DTLS backend selected for libcoap-sys, aborting build")
- }
- }
-
- // Build vendored library if feature was set.
- if cfg!(feature = "vendored") && target_os.as_str() != "espidf" {
- bindgen_builder = build_vendored_library(&out_dir, dtls_backend.as_ref(), bindgen_builder);
- };
-
- if target_os.as_str() != "espidf" {
- // Tell cargo to link libcoap.
- println!(
- "cargo:rustc-link-lib={}{}",
- cfg!(feature = "static").then(|| "static=").unwrap_or("dylib="),
- format!(
- "coap-3-{}",
- &dtls_backend
- .as_ref()
- .map(|v| v.to_string())
- .unwrap_or_else(|| "notls".to_string())
- )
- .as_str()
- );
-
- // For the DTLS libraries, we need to tell cargo which external libraries to link.
- // Note that these linker instructions have to be added *after* the linker instruction
- // for libcoap itself, as some linkers require dependencies to be in reverse order.
- if let Some(dtls_backend) = dtls_backend {
- match dtls_backend {
- DtlsBackend::TinyDtls => {
- // Handled by tinydtls-sys
- },
- DtlsBackend::OpenSsl => {
- // Handled by openssl-sys
- },
- DtlsBackend::MbedTls => {
- // If mbedtls is vendored, mbedtls-sys-auto already takes care of linking.
- if env::var_os("DEP_MBEDTLS_INCLUDE").is_none() {
- // We aren't using mbedtls-sys-auto if we aren't vendoring (as it doesn't support
- // mbedtls >= 3.0.0), so we need to tell cargo to link to mbedtls ourselves.
-
- // Try to find mbedtls using pkg-config, will emit cargo link statements if successful
- if pkg_config::Config::new()
- .statik(cfg!(feature = "static"))
- .probe("mbedtls")
- .is_err()
- {
- // couldn't find using pkg-config, just try linking with given library
- // search path.
- println!("cargo:rustc-link-lib=mbedtls",);
- println!("cargo:rustc-link-lib=mbedx509",);
- println!("cargo:rustc-link-lib=mbedcrypto",);
- }
- }
- },
- DtlsBackend::GnuTls => {
- // gnutls-sys is unmaintained, so we need to link to gnutls ourselves.
-
- // try pkg-config
- if probe_library("gnutls").is_err() {
- // if that doesn't work, try using the standard library search path.
- println!("cargo:rustc-link-lib=gnutls")
- }
- },
- }
- }
- }
-
- let libcoap_defines = Rc::new(RefCell::new(LibcoapMetadata::default()));
-
- let cfg_info = Box::new(CoapDefineParser {
- defines: Rc::clone(&libcoap_defines),
- });
-
- bindgen_builder = bindgen_builder
- .header("src/wrapper.h")
- .default_enum_style(EnumVariation::Rust { non_exhaustive: true })
- // Causes invalid syntax for some reason, so we have to disable it.
- .generate_comments(false)
- .dynamic_link_require_all(true)
- .allowlist_function("(oscore|coap)_.*")
- .allowlist_type("(oscore|coap)_.*")
- .allowlist_var("(oscore|coap)_.*")
- .allowlist_function("(OSCORE|COAP)_.*")
- .allowlist_type("(OSCORE|COAP)_.*")
- .allowlist_var("(OSCORE|COAP|LIBCOAP)_.*")
- // We use the definitions made by the libc crate instead
- .blocklist_type("sockaddr(_in|_in6)?")
- .blocklist_type("in6?_(addr|port)(_t)?")
- .blocklist_type("in6_addr__bindgen_ty_1")
- .blocklist_type("(__)?socklen_t")
- .blocklist_type("fd_set")
- .blocklist_type("sa_family_t")
- .blocklist_type("(__)?time_t")
- .blocklist_type("__fd_mask")
- // Are generated because they are typedef-ed inside of the C headers, blocklisting them
- // will instead replace them with the appropriate rust types.
- // See https://github.com/rust-lang/rust-bindgen/issues/1215 for an open issue concerning
- // this problem.
- .blocklist_type("__(u)?int(8|16|32|64|128)_t")
- .size_t_is_usize(true)
- .parse_callbacks(cfg_info);
- if !cfg!(feature = "vendored") {
- // Triggers a rebuild on every cargo build invocation if used for the vendored version, as
- // the included headers seem to come from our built version.
- // Should be fine though, as we already printed `cargo:rerun-if-changed=src/libcoap/` at the
- // start of the file.
- bindgen_builder = bindgen_builder.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
- }
- let bindings = bindgen_builder.generate().expect("unable to generate bindings");
-
- // Check if required features are available in libcoap.
- let libcoap_defines = libcoap_defines.take();
- if libcoap_defines.feature_defines_available {
- println!("cargo:rustc-cfg=feature_checks_available");
- for feature in COMPILE_TIME_FEATURE_CHECKS {
- let feature_env_var_name = "CARGO_FEATURE_".to_string() + &feature.replace('-', "_").to_uppercase();
- if env::var(&feature_env_var_name).is_ok() && !libcoap_defines.feature_defines.contains(feature) {
- panic!("Required feature {feature} is not available in the used version of libcoap!");
- }
- }
- if dtls_backend != libcoap_defines.dtls_backend {
- // Should be fine, as applications should expect that the DTLS library could differ.
- println!("cargo:warning=DTLS library used by libcoap does not match chosen one. This might lead to issues.")
- }
- } else {
- println!("cargo:warning=The used version of libcoap does not provide a coap_defines.h file, either because it is too old (<4.3.5) or because this file is somehow not included. Compile-time feature checks are not available, and the availability of some features (small-stack, IPv4/IPv6,) cannot be asserted at all!");
- }
-
- let out_path = PathBuf::from(out_dir);
- bindings
- .write_to_file(out_path.join("bindings.rs"))
- .expect("unable to write generated bindings to file");
-}
diff --git a/libcoap-sys/build/bindings.rs b/libcoap-sys/build/bindings.rs
new file mode 100644
index 00000000..c8f95868
--- /dev/null
+++ b/libcoap-sys/build/bindings.rs
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/bindings.rs - Binding generation tools for the libcoap-sys build script.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{cell::RefCell, fmt::Debug, path::PathBuf, rc::Rc};
+
+use anyhow::{Context, Result};
+use bindgen::callbacks::{DeriveTrait, ImplementsTrait, IntKind, ParseCallbacks};
+
+use crate::metadata::{DtlsBackend, LibcoapDefineInfo, LibcoapFeature};
+
+/// Implementation of bindgen's [ParseCallbacks] that allow reading some meta-information about the
+/// used libcoap version from its defines (package version, supported features, ...)
+#[derive(Debug, Default)]
+pub struct LibcoapDefineParser {
+ defines: Rc>,
+}
+
+impl LibcoapDefineParser {
+ pub fn new() -> (Rc>, Self) {
+ let target = std::env::var_os("TARGET").unwrap_or_default();
+ let host = std::env::var_os("HOST").unwrap_or_default();
+
+ if target != host {
+ println!(concat!(
+ "cargo:warning=libcoap-rs compile-time feature checks may be inaccurate when cross",
+ " compiling, see https://libcoap.net/doc/reference/4.3.5/man_coap_supported.html",
+ " for more information."
+ ));
+ }
+
+ let value: LibcoapDefineParser = Default::default();
+ (Rc::clone(&value.defines), value)
+ }
+}
+
+impl ParseCallbacks for LibcoapDefineParser {
+ fn int_macro(&self, name: &str, value: i64) -> Option {
+ let mut defines = self.defines.borrow_mut();
+ defines.supported_features |= LibcoapFeature::features_from_define(name, value);
+ if let Some(dtls_backend) = DtlsBackend::library_from_define(name, value) {
+ if let Some(old_backend) = defines.dtls_backend.replace(dtls_backend) {
+ println!("cargo:warning=The libcoap header files indicate that more than one DTLS library is active at the same time ({dtls_backend} and {old_backend}), which should not be possible. Are the header paths misconfigured?");
+ }
+ }
+ None
+ }
+
+ fn str_macro(&self, name: &str, value: &[u8]) {
+ if name == "LIBCOAP_PACKAGE_VERSION" {
+ let version_str = String::from_utf8_lossy(value);
+ self.defines.borrow_mut().version = Some(version_str.to_string())
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+struct LibcoapBindingHelper;
+
+impl ParseCallbacks for LibcoapBindingHelper {
+ // Even if we don't use CargoCallbacks, we want to rebuild if relevant environment variables
+ // change.
+ fn read_env_var(&self, key: &str) {
+ println!("cargo:rerun-if-env-changed={key}")
+ }
+
+ fn blocklisted_type_implements_trait(&self, name: &str, derive_trait: DeriveTrait) -> Option {
+ // This is based on what libc reports for Unix-based OSes
+ #[cfg(unix)]
+ match (name, derive_trait) {
+ (
+ "struct epoll_event" | "fd_set" | "struct sockaddr_in" | "struct sockaddr_in6" | "struct sockaddr",
+ DeriveTrait::Debug | DeriveTrait::Hash | DeriveTrait::PartialEqOrPartialOrd | DeriveTrait::Copy,
+ ) => Some(ImplementsTrait::Yes),
+ (
+ "struct epoll_event" | "fd_set" | "struct sockaddr_in" | "struct sockaddr_in6" | "struct sockaddr",
+ DeriveTrait::Default,
+ ) => Some(ImplementsTrait::No),
+ (
+ "time_t" | "socklen_t" | "sa_family_t",
+ DeriveTrait::Debug
+ | DeriveTrait::Hash
+ | DeriveTrait::PartialEqOrPartialOrd
+ | DeriveTrait::Copy
+ | DeriveTrait::Default,
+ ) => Some(ImplementsTrait::Yes),
+ (_, _) => None,
+ }
+ #[cfg(not(unix))]
+ // Let's just assume that bindgen's default behavior is fine.
+ None
+ }
+}
+
+pub fn generate_libcoap_bindings(
+ bindgen_builder_configurator: impl FnOnce(bindgen::Builder) -> Result,
+ rerun_on_header_file_changes: bool,
+) -> Result {
+ let source_root = PathBuf::from(
+ std::env::var_os("CARGO_MANIFEST_DIR")
+ .expect("CARGO_MANIFEST_DIR is not set (are we not running as a cargo build script?)"),
+ );
+ let mut builder = bindgen::Builder::default()
+ .header(
+ source_root
+ .join("src")
+ .join("wrapper.h")
+ .to_str()
+ .context("unable to convert header path to &str")?
+ .to_string(),
+ )
+ .parse_callbacks(Box::new(LibcoapBindingHelper))
+ .generate_comments(true)
+ .generate_cstr(true)
+ .allowlist_function("(oscore|coap)_.*")
+ .allowlist_type("(oscore|coap)_.*")
+ .allowlist_var("(oscore|coap)_.*")
+ .allowlist_function("(OSCORE|COAP)_.*")
+ .allowlist_type("(OSCORE|COAP)_.*")
+ .allowlist_var("(OSCORE|COAP|LIBCOAP)_.*")
+ // We use the definitions made by the libc crate instead
+ .blocklist_type("sockaddr(_in|_in6)?")
+ .blocklist_type("in6?_(addr|port)(_t)?")
+ .blocklist_type("in6_addr__bindgen_ty_1")
+ .blocklist_type("(__)?socklen_t")
+ .blocklist_type("fd_set")
+ .blocklist_type("sa_family_t")
+ .blocklist_type("(__)?time_t")
+ .blocklist_type("__fd_mask")
+ .blocklist_type("epoll_event")
+ // Are generated because they are typedef-ed inside of the C headers, blocklisting them
+ // will instead replace them with the appropriate rust types.
+ // See https://github.com/rust-lang/rust-bindgen/issues/1215 for an open issue concerning
+ // this problem.
+ .blocklist_type("__(u)?int(8|16|32|64|128)_t")
+ .size_t_is_usize(true);
+
+ // The `rerun_on_header_files()` method only applies to the top level header (in our case
+ // src/wrapper.h, so we must not add CargoCallbacks at all if we want to get our desired
+ // effect).
+ // To still handle environment variable changes properly, LibcoapBindingHeader already includes
+ // the relevant parts of CargoCallbacks.
+ if rerun_on_header_file_changes {
+ builder = builder.parse_callbacks(Box::new(
+ bindgen::CargoCallbacks::new().rerun_on_header_files(rerun_on_header_file_changes),
+ ))
+ }
+ builder = bindgen_builder_configurator(builder)?;
+
+ builder.generate().context("unable to generate bindings")
+}
diff --git a/libcoap-sys/build/build_system/esp_idf.rs b/libcoap-sys/build/build_system/esp_idf.rs
new file mode 100644
index 00000000..02379a47
--- /dev/null
+++ b/libcoap-sys/build/build_system/esp_idf.rs
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/build_system/esp_idf.rs - ESP-IDF build system for libcoap-sys.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+use std::{env, fs::File, io::Write, iter::once, path::PathBuf};
+
+use anyhow::{anyhow, Context, Result};
+use enumset::EnumSet;
+use syn::{ForeignItem, Ident, Item};
+use version_compare::Version;
+
+use crate::{
+ build_system::BuildSystem,
+ metadata::{DtlsBackend, LibcoapFeature},
+};
+
+pub struct EspIdfBuildSystem {
+ out_dir: PathBuf,
+ esp_idf_bindings_file: PathBuf,
+ requested_features: EnumSet,
+ bypass_compile_time_feature_checks: bool,
+}
+
+impl EspIdfBuildSystem {
+ pub fn new(
+ out_dir: PathBuf,
+ requested_features: EnumSet,
+ requested_dtls_backend: Option,
+ bypass_compile_time_feature_checks: bool,
+ ) -> Result {
+ embuild::espidf::sysenv::output();
+ let esp_idf_bindings_file = env::var_os("DEP_ESP_IDF_ROOT")
+ .map(PathBuf::from)
+ .expect("Environment variable DEP_ESP_IDF_ROOT has not been set by esp-idf-sys")
+ .join("bindings.rs");
+
+ if let Some(backend) = requested_dtls_backend {
+ if backend != DtlsBackend::MbedTls {
+ return Err(anyhow!("libcoap only supports the MbedTLS DTLS backend when compiling for ESP-IDF, but you have requested the {backend} backend."));
+ }
+ }
+
+ Ok(Self {
+ out_dir,
+ esp_idf_bindings_file,
+ requested_features,
+ bypass_compile_time_feature_checks,
+ })
+ }
+}
+
+impl BuildSystem for EspIdfBuildSystem {
+ fn detected_features(&self) -> Option> {
+ // We ensure the availability of some requested features by generating checks for the
+ // cfg values set by esp-idf-sys based on the used sdkconfig.
+ // Therefore, we can tell the build script feature checker that all requested features are
+ // available (to mute the warning about there being no feature check).
+
+ // However, do warn the user if features are requested that cannot be checked this way, but
+ // would be checkable if the defines-based checker was used.
+ let uncheckable_features: EnumSet = self
+ .requested_features
+ .iter()
+ .filter(|v| v.define_name().is_some() && v.sdkconfig_flag_name().is_none())
+ .collect();
+ if !uncheckable_features.is_empty() {
+ println!(
+ concat!(
+ "cargo:warning=When building for ESP-IDF, the availability of the following ",
+ "requested features that usually can be checked during compile time can only",
+ "be checked during runtime instead: {}"
+ ),
+ uncheckable_features
+ .iter()
+ .map(|v| v.as_str())
+ .collect::>()
+ .join(", ")
+ )
+ }
+
+ Some(self.requested_features)
+ }
+
+ fn detected_dtls_backend(&self) -> Option {
+ // If DTLS is a requested feature, we check during compile time whether MbedTLS is
+ // supposed to be enabled.
+ self.requested_features
+ .contains(LibcoapFeature::Dtls)
+ .then_some(DtlsBackend::MbedTls)
+ }
+
+ fn version(&self) -> Option {
+ None
+ }
+
+ fn generate_bindings(&mut self) -> Result {
+ // Find, read and parse the Rust bindings generated by esp-idf-sys.
+ let esp_bindings_file =
+ std::fs::read_to_string(&self.esp_idf_bindings_file).context("unable to read ESP-IDF bindings file")?;
+ let parsed_esp_bindings_file =
+ syn::parse_file(&esp_bindings_file).context("unable to parse ESP-IDF bindings file")?;
+
+ // Create file for our own bindings.
+ let bindings_file_path = self.out_dir.join("bindings.rs");
+ let mut libcoap_bindings_file = File::create(&bindings_file_path).context("unable to create bindings file")?;
+
+ // Iterate over all items in the esp-idf-sys bindings file.
+ for item in parsed_esp_bindings_file.items {
+ // Find the list of identifiers provided by this item.
+ let ident: Box> = match item {
+ Item::Const(v) => Box::new(once(v.ident)),
+ Item::Enum(v) => Box::new(once(v.ident)),
+ Item::ExternCrate(v) => Box::new(once(v.ident)),
+ Item::Fn(v) => Box::new(once(v.sig.ident)),
+ Item::Macro(v) => Box::new(v.ident.into_iter()),
+ Item::Mod(v) => Box::new(once(v.ident)),
+ Item::Static(v) => Box::new(once(v.ident)),
+ Item::Struct(v) => Box::new(once(v.ident)),
+ Item::Trait(v) => Box::new(once(v.ident)),
+ Item::TraitAlias(v) => Box::new(once(v.ident)),
+ Item::Type(v) => Box::new(once(v.ident)),
+ Item::Union(v) => Box::new(once(v.ident)),
+ Item::ForeignMod(v) => Box::new(v.items.into_iter().filter_map(|fe| match fe {
+ ForeignItem::Fn(fi) => Some(fi.sig.ident),
+ ForeignItem::Static(fi) => Some(fi.ident),
+ ForeignItem::Type(fi) => Some(fi.ident),
+ _ => None,
+ })),
+ _ => Box::new(std::iter::empty()),
+ };
+
+ for ident in ident.map(|i| i.to_string()) {
+ let lowercase_ident = ident.to_lowercase();
+ // If the item belongs to the libcoap crate (starts with coap or oscore), re-export it in our bindings.
+ if lowercase_ident.starts_with("coap") || lowercase_ident.starts_with("oscore") {
+ writeln!(&mut libcoap_bindings_file, "pub use esp_idf_sys::{};", ident)
+ .context("unable to write to bindings file")?;
+ }
+ }
+ }
+
+ if !self.bypass_compile_time_feature_checks {
+ for (feature_name, feature_flag) in self
+ .requested_features
+ .iter()
+ .filter_map(|v| v.sdkconfig_flag_name().map(|flag| (v.as_str(), flag)))
+ {
+ let feature_flag_lowercase = feature_flag.to_lowercase();
+ // For some reason, embuild adds expected cfg flags for some, but not all
+ // feature-related sdkconfig flags, causing warnings if we don't do this.
+ println!("cargo::rustc-check-cfg=cfg(esp_idf_{})", feature_flag_lowercase);
+
+ writeln!(
+ &mut libcoap_bindings_file,
+ // Only show these errors if the coap component is enabled at all (in order to
+ // only show the relevant compilation error).
+ "#[cfg(all(esp_idf_comp_espressif__coap_enabled, not(esp_idf_{})))]",
+ feature_flag_lowercase
+ )
+ .context("unable to write to bindings file")?;
+ writeln!(
+ &mut libcoap_bindings_file,
+ concat!(
+ "compile_error!(\"Requested feature \\\"{}\\\" is not enabled\n",
+ "in ESP-IDF sdkconfig.defaults (set `CONFIG_{}=y` to fix this)\");"
+ ),
+ feature_flag, feature_name
+ )
+ .context("unable to write to bindings file")?;
+ }
+ }
+
+ Ok(bindings_file_path)
+ }
+}
diff --git a/libcoap-sys/build/build_system/manual.rs b/libcoap-sys/build/build_system/manual.rs
new file mode 100644
index 00000000..fc18437c
--- /dev/null
+++ b/libcoap-sys/build/build_system/manual.rs
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/build_system/manual.rs - Manual build system for libcoap-sys.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{cell::RefCell, env, env::VarError, path::PathBuf};
+
+use anyhow::{Context, Result};
+use enumset::EnumSet;
+use version_compare::Version;
+
+use crate::{
+ bindings::{generate_libcoap_bindings, LibcoapDefineParser},
+ build_system::BuildSystem,
+ metadata::{DtlsBackend, LibcoapDefineInfo, LibcoapFeature},
+};
+pub struct ManualBuildSystem {
+ out_dir: PathBuf,
+ include_dirs: Vec,
+ define_info: Option,
+}
+
+impl ManualBuildSystem {
+ pub fn link_with_libcoap(out_dir: PathBuf, requested_dtls_backend: Option) -> Result {
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_INCLUDE_DIRS");
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_LIB_DIRS");
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_STATIC");
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_ADDITIONAL_LIBRARIES");
+
+ // Parse environment variables.
+ let include_dirs: Vec = env::var("LIBCOAP_RS_INCLUDE_DIRS")
+ .context("LIBCOAP_RS_INCLUDE_DIRS has not been set or is not valid unicode")?
+ .split(":")
+ .map(PathBuf::from)
+ .collect();
+ let lib_dirs: Vec = env::var("LIBCOAP_RS_LIB_DIRS")
+ .context("LIBCOAP_RS_LIB_DIRS has not been set or is not valid unicode")?
+ .split(":")
+ .map(PathBuf::from)
+ .collect();
+ let additional_libraries: Vec = match env::var("LIBCOAP_RS_ADDITIONAL_LIBRARIES") {
+ Ok(v) => v.split(":").map(ToString::to_string).collect(),
+ Err(VarError::NotPresent) => vec![],
+ Err(e) => return Err(e).context("Unable to parse LIBCOAP_RS_ADDITIONAL_LIBRARIES environment variable."),
+ };
+ let use_static = match env::var("LIBCOAP_RS_STATIC") {
+ Ok(v) => !(v == "0" || v.is_empty()),
+ Err(VarError::NotPresent) => false,
+ Err(e) => return Err(e).context("Unable to parse LIBCOAP_RS_STATIC environment variable."),
+ };
+
+ // Determine name of libcoap library.
+ let library_name = if let Some(backend) = requested_dtls_backend {
+ format!("coap-3-{}", backend.library_suffix())
+ } else {
+ "coap-3".to_string()
+ };
+
+ // Add given library paths to search path.
+ for lib_dir in lib_dirs {
+ println!("cargo:rustc-link-search={}", lib_dir.display());
+ }
+ // Instruct rustc to link with the desired version of libcoap.
+ println!(
+ "cargo:rustc-link-lib={}{}",
+ if use_static { "static=" } else { "" },
+ library_name
+ );
+
+ // Instruct rustc to link with additional libraries (note that this *must* happen *after*
+ // linking with libcoap, at least with some linkers).
+ for additional_library in additional_libraries {
+ println!("cargo:rustc-link-lib={}", additional_library);
+ }
+
+ Ok(Self {
+ out_dir,
+ include_dirs,
+ define_info: None,
+ })
+ }
+}
+
+impl BuildSystem for ManualBuildSystem {
+ fn detected_features(&self) -> Option> {
+ self.define_info.as_ref().map(|v| v.supported_features)
+ }
+
+ fn detected_dtls_backend(&self) -> Option {
+ self.define_info.as_ref().and_then(|v| v.dtls_backend)
+ }
+
+ fn version(&self) -> Option {
+ self.define_info
+ .as_ref()
+ .and_then(|i| i.version.as_ref().map(|v| Version::from(v.as_str())))
+ .expect("unable to parse version string obtained from coap_defines.h")
+ }
+
+ fn generate_bindings(&mut self) -> anyhow::Result {
+ let (define_info, define_parser) = LibcoapDefineParser::new();
+ let bindings = generate_libcoap_bindings(
+ |builder| {
+ Ok(builder
+ .parse_callbacks(Box::new(define_parser))
+ // If the pkg-config provided include path coincides with a system include directory,
+ // setting the "-I{}" command line argument will not do anything, potentially resulting
+ // in clang using different CoAP headers than provided by pkg-config, e.g., if there
+ // is an old libcoap in /usr/local/include, but the desired one has its headers in /usr/include.
+ // Therefore, we use `-isystem` instead.
+ // See also: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-I-dir
+ .clang_args(self.include_dirs.iter().map(|v| format!("-isystem{}", v.display()))))
+ },
+ true,
+ )?;
+
+ self.define_info = Some(RefCell::take(&define_info));
+
+ let out_path = self.out_dir.join("bindings.rs");
+ bindings
+ .write_to_file(&out_path)
+ .context("unable to write bindings to file")?;
+ Ok(out_path)
+ }
+}
diff --git a/libcoap-sys/build/build_system/mod.rs b/libcoap-sys/build/build_system/mod.rs
new file mode 100644
index 00000000..ebc12399
--- /dev/null
+++ b/libcoap-sys/build/build_system/mod.rs
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/build_system/mod.rs - Basic definitions for libcoap-sys build systems.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+use std::path::PathBuf;
+
+use anyhow::Result;
+use enumset::EnumSet;
+use version_compare::Version;
+
+use crate::metadata::{DtlsBackend, LibcoapFeature};
+
+pub mod esp_idf;
+pub mod manual;
+pub mod pkgconfig;
+pub mod vendored;
+
+/// Trait that is implemented by build systems for libcoap.
+///
+/// It is assumed that the constructor structs implementing this trait already perform all
+/// necessary steps to link against libcoap, and that only binding generation and compile-time
+/// checks remain.
+///
+/// If you want to implement your own build system, you may want to use the `manual` build system
+/// as a basis.
+///
+/// In order to implement the compile-time checks, you may want to use
+/// [`LibcoapDefineParser`](crate::bindings::LibcoapDefineParser), at least in cases where you have
+/// the corresponding `coap_defines.h` header file available.
+pub trait BuildSystem {
+ /// Returns the set of features that are supported by the linked version of libcoap, or `None`
+ /// if this detection is not possible or has not been performed yet.
+ ///
+ /// It is assumed that after `generate_bindings()` is called, a `None` return value indicates
+ /// that compile-time feature detection is unsupported.
+ fn detected_features(&self) -> Option>;
+
+ /// Returns the DTLS backend that has been used in the `libcoap` version this build
+ /// system built against, or `None` if this detection is not possible or has not been performed
+ /// yet.
+ ///
+ /// It is assumed that after `generate_bindings()` is called, a `None` return value indicates
+ /// that compile-time DTLS library detection is unsupported.
+ fn detected_dtls_backend(&self) -> Option;
+
+ /// Returns the `libcoap` library version this build system built against, or `None` if this
+ /// detection is not possible or has not been performed yet.
+ ///
+ /// It is assumed that after `generate_bindings()` is called, a `None` return value indicates
+ /// that compile-time DTLS library detection is unsupported.
+ fn version(&self) -> Option;
+
+ /// Generate Rust bindings to the `libcoap` C library that we linked against and return a
+ /// `PathBuf` to the generated bindings file to use.
+ fn generate_bindings(&mut self) -> Result;
+}
diff --git a/libcoap-sys/build/build_system/pkgconfig.rs b/libcoap-sys/build/build_system/pkgconfig.rs
new file mode 100644
index 00000000..3d972930
--- /dev/null
+++ b/libcoap-sys/build/build_system/pkgconfig.rs
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/build_system/pkgconfig.rs - pkg-config build system for libcoap-sys.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{cell::RefCell, path::PathBuf};
+
+use anyhow::{anyhow, Context};
+use enumset::EnumSet;
+use pkg_config::Library;
+use version_compare::Version;
+
+use crate::{
+ bindings::{generate_libcoap_bindings, LibcoapDefineParser},
+ build_system::BuildSystem,
+ metadata::{DtlsBackend, LibcoapDefineInfo, LibcoapFeature, MINIMUM_LIBCOAP_VERSION},
+};
+
+pub struct PkgConfigBuildSystem {
+ define_info: Option,
+ out_dir: PathBuf,
+ library: Library,
+}
+
+impl PkgConfigBuildSystem {
+ /// Obtain some built version of libcoap and set the appropriate linker flags to link with it
+ /// (and its dependencies, if any).
+ pub fn link_with_libcoap(out_dir: PathBuf, requested_dtls_backend: Option) -> anyhow::Result {
+ let mut prober = pkg_config::Config::new();
+ let prober = prober
+ .atleast_version(MINIMUM_LIBCOAP_VERSION)
+ .cargo_metadata(true)
+ .env_metadata(true);
+ let library = if let Some(requested_dtls_backend) = requested_dtls_backend {
+ // Use the libcoap version corresponding to the requested DTLS library, if one has been set.
+ prober.probe(&format!("libcoap-3-{}", requested_dtls_backend.library_suffix()))
+ } else {
+ // Otherwise, use the "default" version.
+ prober.probe("libcoap-3")
+ };
+
+ library
+ .map(|lib| Self {
+ out_dir,
+ define_info: None,
+ library: lib,
+ })
+ .context("unable to probe library using pkg-config")
+ }
+}
+
+impl BuildSystem for PkgConfigBuildSystem {
+ fn detected_features(&self) -> Option> {
+ self.define_info.as_ref().map(|v| v.supported_features)
+ }
+
+ fn detected_dtls_backend(&self) -> Option {
+ self.define_info.as_ref().and_then(|v| v.dtls_backend)
+ }
+
+ fn version(&self) -> Option {
+ Version::from(&self.library.version)
+ .map(Some)
+ .expect("unable to parse version string obtained from pkg-config")
+ }
+
+ fn generate_bindings(&mut self) -> anyhow::Result {
+ let (define_info, define_parser) = LibcoapDefineParser::new();
+ let bindings = generate_libcoap_bindings(
+ |builder| {
+ Ok(builder
+ .parse_callbacks(Box::new(define_parser))
+ // If the pkg-config provided include path coincides with a system include directory,
+ // setting the "-I{}" command line argument will not do anything, potentially resulting
+ // in clang using different CoAP headers than provided by pkg-config, e.g., if there
+ // is an old libcoap in /usr/local/include, but the desired one has its headers in /usr/include.
+ // Therefore, we use `-isystem` instead.
+ // See also: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-I-dir
+ .clang_args(
+ self.library
+ .include_paths
+ .iter()
+ .map(|v| format!("-isystem{}", v.display())),
+ ))
+ },
+ true,
+ )?;
+
+ self.define_info = Some(RefCell::take(&define_info));
+
+ if let Some(version) = &self.define_info.as_ref().unwrap().version {
+ if Version::from(&self.library.version) != Version::from(version) {
+ return Err(anyhow!("The library version indicated by pkg-config does not match the one indicated by the headers. Are the include paths misconfigured?"));
+ }
+ }
+
+ let out_path = self.out_dir.join("bindings.rs");
+ bindings
+ .write_to_file(&out_path)
+ .context("unable to write bindings to file")?;
+ Ok(out_path)
+ }
+}
diff --git a/libcoap-sys/build/build_system/vendored.rs b/libcoap-sys/build/build_system/vendored.rs
new file mode 100644
index 00000000..58d2d891
--- /dev/null
+++ b/libcoap-sys/build/build_system/vendored.rs
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/build_system/vendored.rs - Vendored build system for libcoap-sys.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{
+ cell::RefCell,
+ env,
+ env::VarError,
+ path::{Path, PathBuf},
+ process::Command,
+};
+
+use anyhow::{anyhow, ensure, Context, Result};
+use enumset::EnumSet;
+use version_compare::Version;
+
+use crate::{
+ bindings::{generate_libcoap_bindings, LibcoapDefineParser},
+ build_system::BuildSystem,
+ metadata::{DtlsBackend, LibcoapDefineInfo, LibcoapFeature},
+};
+
+const VENDORED_LIBCOAP_VERSION: &str = "4.3.5";
+
+pub struct VendoredBuildSystem {
+ out_dir: PathBuf,
+ define_info: Option,
+ include_paths: Vec,
+}
+
+impl VendoredBuildSystem {
+ /// Obtain some built version of libcoap and set the appropriate linker flags to link with it
+ /// (and its dependencies, if any).
+ pub fn build_libcoap(
+ out_dir: PathBuf,
+ requested_features: EnumSet,
+ requested_dtls_backend: Option,
+ ) -> Result {
+ println!("cargo:rerun-if-changed=src/libcoap");
+
+ let libcoap_src_dir = out_dir.join("libcoap");
+ let libcoap_build_prefix = out_dir.join("build");
+
+ // Even though libcoap supports out-of-source builds, autogen.sh (or the corresponding
+ // autotools) modify files in the source tree, which causes verification problems when
+ // running cargo package.
+ // Therefore, we copy the libcoap source over to the output directory and build from there.
+ let copy_options = fs_extra::dir::CopyOptions {
+ overwrite: true,
+ ..Default::default()
+ };
+ std::fs::create_dir_all(&libcoap_src_dir)?;
+ std::fs::create_dir_all(&libcoap_build_prefix)?;
+ std::fs::remove_dir_all(&libcoap_src_dir).context("unable to clear libcoap build directory")?;
+ std::fs::remove_dir_all(&libcoap_build_prefix).context("unable to clear libcoap build directory")?;
+ std::fs::create_dir_all(&libcoap_build_prefix)?;
+ std::fs::create_dir_all(&libcoap_src_dir)?;
+ fs_extra::dir::copy(
+ Path::new(env!("CARGO_MANIFEST_DIR")).join("src").join("libcoap"),
+ &out_dir,
+ ©_options,
+ )
+ .context("unable to prepare libcoap build source directory")?;
+
+ env::set_current_dir(&libcoap_src_dir).expect("unable to change to libcoap build dir");
+ ensure!(
+ Command::new(libcoap_src_dir.join("autogen.sh"))
+ .status()
+ .context("unable to execute autogen.sh")?
+ .success(),
+ "autogen.sh returned an error code"
+ );
+
+ let mut build_config = autotools::Config::new(&libcoap_src_dir);
+
+ let mut build_config = build_config
+ // Disable shared library compilation because the vendored library will always be
+ // statically linked
+ .out_dir(&libcoap_build_prefix)
+ .disable("shared", None)
+ .enable("static", None)
+ // Disable any documentation for vendored C library
+ .disable("documentation", None)
+ .disable("doxygen", None)
+ .disable("manpages", None)
+ // This would install the license into the documentation directory, but we don't use the
+ // generated documentation anywhere.
+ .disable("license-install", None)
+ // Disable tests and examples as well as test coverage
+ .disable("tests", None)
+ .disable("examples", None)
+ .disable("gcov", None)
+ // We do not include the TinyDTLS submodule in our source distribution, make sure that
+ // libcoap doesn't try to use it.
+ // This will generate a warning message if TinyDTLS isn't explicitly enabled, but this
+ // has no negative consequences.
+ .without("submodule-tinydtls", None);
+
+ for feature in requested_features {
+ if let Some(feature_flag) = feature.configure_flag_name() {
+ build_config = build_config.enable(feature_flag, None);
+ }
+ }
+ for feature in EnumSet::::all().difference(requested_features) {
+ if let Some(feature_flag) = feature.configure_flag_name() {
+ build_config = build_config.disable(feature_flag, None);
+ }
+ }
+ let pkg_config_path_bak = env::var_os("PKG_CONFIG_PATH");
+
+ let link_using_pkgconfig = if requested_features.contains(LibcoapFeature::Dtls) {
+ // Check if we have any DTLS libraries already added as a Rust dependency.
+ // For each one, set the appropriate PKG_CONFIG_PATHs, CFLAGS and/or LIBS to use them
+ // instead of system versions if they are going to be used.
+ let mut additional_pkg_config_paths: Vec = vec![];
+ // May be unused if none of the DTLS crate features has been enabled.
+ #[allow(unused_mut)]
+ let mut dtls_libraries_linked_by_other_crates = EnumSet::::empty();
+ #[cfg(feature = "dtls-tinydtls-sys")]
+ {
+ let (pkg_config_path, linked) = Self::configure_tinydtls_sys(build_config)?;
+ if let Some(pkg_config_path) = pkg_config_path {
+ additional_pkg_config_paths.push(pkg_config_path)
+ }
+ if linked {
+ dtls_libraries_linked_by_other_crates |= DtlsBackend::TinyDtls
+ }
+ }
+ #[cfg(feature = "dtls-openssl-sys")]
+ {
+ let (pkg_config_path, linked) = Self::configure_openssl_sys(build_config)?;
+ if let Some(pkg_config_path) = pkg_config_path {
+ additional_pkg_config_paths.push(pkg_config_path)
+ }
+ if linked {
+ dtls_libraries_linked_by_other_crates |= DtlsBackend::OpenSsl
+ }
+ }
+ #[cfg(feature = "dtls-mbedtls-sys")]
+ {
+ let (pkg_config_path, linked) = Self::configure_mbedtls_sys(&out_dir, build_config)?;
+ if let Some(pkg_config_path) = pkg_config_path {
+ additional_pkg_config_paths.push(pkg_config_path)
+ }
+ if linked {
+ dtls_libraries_linked_by_other_crates |= DtlsBackend::MbedTls
+ }
+ }
+
+ // Add libcoap's own build directory to the PKG_CONFIG_PATH (might be used later on to
+ // find the generated .pc file to link against libcoap).
+ additional_pkg_config_paths.push(libcoap_build_prefix.join("lib").join("pkgconfig"));
+
+ let pkg_config_path = match env::var("PKG_CONFIG_PATH") {
+ Ok(v) => {
+ format!(
+ "{}:{}",
+ additional_pkg_config_paths
+ .iter()
+ .map(|v| v
+ .to_str()
+ .ok_or(anyhow!("unable to convert PKG_CONFIG_PATH value to UTF-8")))
+ .collect::>>()?
+ .join(":"),
+ v
+ )
+ },
+ Err(VarError::NotPresent) => additional_pkg_config_paths
+ .iter()
+ .map(|v| {
+ v.to_str()
+ .ok_or(anyhow!("unable to convert PKG_CONFIG_PATH value to UTF-8"))
+ })
+ .collect::>>()?
+ .join(":"),
+ Err(e) => Err(e).context("PKG_CONFIG_PATH is not a valid UTF-8 string")?,
+ };
+ build_config.env("PKG_CONFIG_PATH", &pkg_config_path);
+
+ // SAFETY: We are single-threaded here.
+ unsafe { env::set_var("PKG_CONFIG_PATH", pkg_config_path) }
+
+ // Choose a DTLS backend.
+ let selected_dtls_backend = if let Some(requested_dtls_backend) = requested_dtls_backend {
+ // If one has been explicitly requested by the user, use that one.
+ Some(requested_dtls_backend)
+ } else if cfg!(feature = "dtls-openssl-sys") {
+ // If we do have a library already linked via a rust dependency, prefer those, but
+ // maintain the order also used in libcoap itself.
+ Some(DtlsBackend::OpenSsl)
+ } else if cfg!(feature = "dtls-mbedtls-sys") {
+ Some(DtlsBackend::MbedTls)
+ } else if cfg!(feature = "dtls-tinydtls-sys") {
+ Some(DtlsBackend::TinyDtls)
+ } else {
+ // Otherwise, we will rely on libcoap to find us a suitable DTLS library.
+ None
+ };
+
+ // If we are not using one of the DTLS libraries already linked by another rust crate,
+ // we need to link the DTLS library as well. Set a boolean variable to keep track of this.
+ let dtls_library_already_linked = if let Some(selected_dtls_backend) = selected_dtls_backend {
+ build_config = build_config.with(selected_dtls_backend.as_str(), None);
+ if dtls_libraries_linked_by_other_crates.contains(selected_dtls_backend) {
+ println!("cargo:rustc-cfg=used_dtls_crate=\"{}\"", selected_dtls_backend.as_str())
+ }
+ dtls_libraries_linked_by_other_crates.contains(selected_dtls_backend)
+ } else {
+ false
+ };
+
+ !dtls_library_already_linked
+ } else {
+ false
+ };
+
+ build_config.build();
+
+ if link_using_pkgconfig {
+ // We need to link both libcoap and its DTLS library. Use the generated pkg-config
+ // file to determine how to do this.
+ let library = pkg_config::Config::new().statik(true).exactly_version(VENDORED_LIBCOAP_VERSION).probe("libcoap-3").context("unable to link against build version of libcoap using pkg-config (which is necessary if you're not using a Rust dependency to link the DTLS library)")?;
+
+ // SAFETY: We are still single-threaded here.
+ unsafe { env::set_var("PKG_CONFIG_PATH", pkg_config_path_bak.unwrap_or_default()) }
+ Ok(Self {
+ out_dir,
+ define_info: None,
+ include_paths: library.include_paths,
+ })
+ } else {
+ // SAFETY: We are still single-threaded here.
+ unsafe { env::set_var("PKG_CONFIG_PATH", pkg_config_path_bak.unwrap_or_default()) }
+ println!(
+ "cargo:rustc-link-search={}",
+ libcoap_build_prefix
+ .join("lib")
+ .to_str()
+ .context("unable to convert OUT_DIR to a valid UTF-8 string.")?
+ );
+ println!("cargo:rustc-link-lib=static=coap-3");
+ Ok(Self {
+ out_dir,
+ define_info: None,
+ include_paths: vec![libcoap_build_prefix.join("include")],
+ })
+ }
+ }
+
+ #[cfg(feature = "dtls-tinydtls-sys")]
+ fn configure_tinydtls_sys(build_config: &mut autotools::Config) -> Result<(Option, bool)> {
+ if env::var_os("TinyDTLS_CFLAGS").is_some() || env::var_os("TinyDTLS_LIBS").is_some() {
+ // Do not use tinydtls-sys if the user manually set either the corresponding LIBS or
+ // CFLAGS variable.
+ // However, do warn the user that this might cause issues.
+ println!("cargo:warning=You have enabled the tinydtls-sys dependency, but have overridden either the TinyDTLS_CFLAGS or TinyDTLS_LIBS environment variable used by libcoap to find TinyDTLS.");
+ println!("cargo:warning=Note that attempting to link more than one version of the same library at once may cause unexpected issues and/or cryptic compilation errors, especially if both versions are statically linked.");
+ Ok((None, false))
+ } else {
+ let tinydtls_include = env::var_os("DEP_TINYDTLS_INCLUDE")
+ .expect("tinydtls-sys dependency has been added, but DEP_TINYDTLS_INCLUDE has not been set");
+ let tinydtls_libs = env::var_os("DEP_TINYDTLS_LIBS")
+ .expect("tinydtls-sys dependency has been added, but DEP_TINYDTLS_LIBS has not been set");
+ build_config.env(
+ "TinyDTLS_CFLAGS",
+ format!(
+ "-I{} -I{}",
+ tinydtls_include
+ .to_str()
+ .context("DEP_TINYDTLS_INCLUDE path is not a valid UTF-8 string")?,
+ Path::new(&tinydtls_include)
+ .join("tinydtls")
+ .to_str()
+ .context("DEP_TINYDTLS_INCLUDE path is not a valid UTF-8 string")?
+ ),
+ );
+
+ // Need to set TinyDTLS_LIBS explicitly to force static linking (TinyDTLS also builds a shared version of the library).
+ build_config.env(
+ "TinyDTLS_LIBS",
+ format!(
+ "-L{} -l:libtinydtls.a",
+ tinydtls_libs
+ .to_str()
+ .context("DEP_TINYDTLS_LIBS path is not a valid UTF-8 string")?
+ ),
+ );
+
+ // Add TinyDTLS's pkg-config directory to the path for version checking.
+ Ok((Some(PathBuf::from(tinydtls_libs).join("lib").join("pkgconfig")), true))
+ }
+ }
+
+ #[cfg(feature = "dtls-openssl-sys")]
+ fn configure_openssl_sys(_build_config: &mut autotools::Config) -> Result<(Option, bool)> {
+ if env::var_os("OpenSSL_CFLAGS").is_some() || env::var_os("OpenSSL_LIBS").is_some() {
+ // Do not use tinydtls-sys if the user manually set either the corresponding LIBS or
+ // CFLAGS variable.
+ // However, do warn the user that this might cause issues.
+ println!("cargo:warning=You have enabled the openssl-sys dependency, but have overridden either the OpenSSL_CFLAGS or OpenSSL_LIBS environment variable used by libcoap to find OpenSSL.");
+ println!("cargo:warning=Note that attempting to link more than one version of the same library at once may cause unexpected issues and/or cryptic compilation errors, especially if both versions are statically linked.");
+ Ok((None, false))
+ } else {
+ let openssl_include = env::var_os("DEP_OPENSSL_INCLUDE")
+ .expect("openssl-sys dependency has been added, but DEP_OPENSSL_INCLUDE has not been set");
+ let openssl_libs = Path::new(openssl_include.as_os_str())
+ .parent()
+ .context("DEP_OPENSSL_INCLUDE has no parent directory")?
+ .join("lib");
+
+ // Just add the OpenSSL directory to the PKG_CONFIG_PATH, that way libcoap will find it.
+ Ok((Some(openssl_libs.join("pkgconfig")), true))
+ }
+ }
+
+ #[cfg(feature = "dtls-mbedtls-sys")]
+ fn configure_mbedtls_sys(out_dir: &Path, build_config: &mut autotools::Config) -> Result<(Option, bool)> {
+ if env::var_os("MbedTLS_CFLAGS").is_some() || env::var_os("MbedTLS_LIBS").is_some() {
+ // Do not use tinydtls-sys if the user manually set either the corresponding LIBS or
+ // CFLAGS variable.
+ // However, do warn the user that this might cause issues.
+ println!("cargo:warning=You have enabled the mbedtls-sys dependency, but have overridden either the MbedTLS_CFLAGS or MbedTLS_LIBS environment variable used by libcoap to find MbedTLS.");
+ println!("cargo:warning=Note that attempting to link more than one version of the same library at once may cause unexpected issues and/or cryptic compilation errors, especially if both versions are statically linked.");
+ Ok((None, false))
+ } else {
+ let mbedtls_include = env::var_os("DEP_MBEDTLS_INCLUDE")
+ .expect("mbedtls-sys dependency has been added, but DEP_MBEDTLS_INCLUDE has not been set");
+
+ // Can't use pkg-config here, as pkg-config was only added to MbedTLS recently.
+
+ // the config.h of mbedtls-sys-auto is generated separately from all other
+ // includes in the root of mbedtls-sys-auto's OUT_DIR.
+ // In order to let libcoap read use the correct config file, we need to copy
+ // this file into our own OUT_DIR under include/mbedtls/config.h, so that we
+ // can then set OUT_DIR/include as an additional include path.
+ let config_h = env::var_os("DEP_MBEDTLS_CONFIG_H")
+ .expect("DEP_MBEDTLS_INCLUDE is set but DEP_MBEDTLS_CONFIG_H is not");
+
+ let config_path = Path::new(&config_h);
+ let out_include = Path::new(&out_dir).join("include");
+ std::fs::create_dir_all(out_include.join("mbedtls"))
+ .context("unable to prepare include directory for mbedtls config.h")?;
+ std::fs::copy(config_path, out_include.join("mbedtls").join("config.h"))
+ .context("unable to copy mbedtls config.h to include directory")?;
+ let mbedtls_library_path = config_path
+ .parent()
+ .context("DEP_MBEDTLS_CONFIG_H has no parent directory")?
+ .join("build")
+ .join("library");
+
+ build_config.env(
+ "MbedTLS_CFLAGS",
+ format!(
+ "-I{} -I{}",
+ out_include.to_str().expect("OUT_DIR is not a valid UTF-8 string"),
+ mbedtls_include
+ .to_str()
+ .expect("DEP_MBEDTLS_INCLUDE is not a valid UTF-8 string")
+ ),
+ );
+ build_config.env(
+ "MbedTLS_LIBS",
+ format!(
+ "-L{0} -l:libmbedtls.a -l:libmbedcrypto.a -l:libmbedx509.a",
+ mbedtls_library_path
+ .to_str()
+ .expect("DEP_MBEDTLS_CONFIG_H is not a valid string"),
+ ),
+ );
+
+ // If MbedTLS_CFLAGS and MbedTLS_LIBS are both set, libcoap will fall back to
+ // determining the library version using other methods. No need to add to pkg-config
+ // path here (as of now).
+ Ok((None, true))
+ }
+ }
+}
+
+impl BuildSystem for VendoredBuildSystem {
+ fn detected_features(&self) -> Option> {
+ self.define_info.as_ref().map(|v| v.supported_features)
+ }
+
+ fn detected_dtls_backend(&self) -> Option {
+ self.define_info.as_ref().and_then(|v| v.dtls_backend)
+ }
+
+ fn version(&self) -> Option {
+ Version::from(VENDORED_LIBCOAP_VERSION)
+ }
+
+ fn generate_bindings(&mut self) -> anyhow::Result {
+ let (define_info, define_parser) = LibcoapDefineParser::new();
+ let bindings = generate_libcoap_bindings(
+ |builder| {
+ Ok(builder
+ .parse_callbacks(Box::new(define_parser))
+ // If the pkg-config provided include path coincides with a system include directory,
+ // setting the "-I{}" command line argument will not do anything, potentially resulting
+ // in clang using different CoAP headers than provided by pkg-config, e.g., if there
+ // is an old libcoap in /usr/local/include, but the desired one has its headers in /usr/include.
+ // Therefore, we use `-isystem` instead.
+ // See also: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-I-dir
+ .clang_args(self.include_paths.iter().map(|v| format!("-isystem{}", v.display()))))
+ },
+ // Do not run on header file changes, as this will cause cargo to __always__ rebuild,
+ // no matter what.
+ // This is probably related to the fact that the headers are only generated during
+ // build.
+ // Without changes to the actual source code in src, crate features or environment
+ // variables that influence this build script (which are already covered by
+ // cargo:rerun-if-env-changed), the headers will never change and necessitate a rebuild,
+ // so this should be fine.
+ false,
+ )?;
+ // Just to make sure we do actually run if the libcoap source code changed.
+ println!("cargo:rerun-if-changed=src/libcoap");
+
+ self.define_info = Some(RefCell::take(&define_info));
+
+ if let Some(version) = &self.define_info.as_ref().unwrap().version {
+ if Version::from(VENDORED_LIBCOAP_VERSION) != Version::from(version) {
+ return Err(anyhow!("The library version indicated by the headers does not match the vendored version that should be in use. Are the include paths misconfigured?"));
+ }
+ }
+
+ let out_path = self.out_dir.join("bindings.rs");
+ bindings
+ .write_to_file(&out_path)
+ .context("unable to write bindings to file")?;
+ Ok(out_path)
+ }
+}
diff --git a/libcoap-sys/build/main.rs b/libcoap-sys/build/main.rs
new file mode 100644
index 00000000..96c7baae
--- /dev/null
+++ b/libcoap-sys/build/main.rs
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/main.rs - Build script entrypoint for libcoap-sys.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{env, env::VarError, path::PathBuf};
+
+use anyhow::{anyhow, bail, Context, Result};
+use enumset::EnumSet;
+use version_compare::Version;
+
+use crate::{
+ build_system::{
+ esp_idf::EspIdfBuildSystem, manual::ManualBuildSystem, pkgconfig::PkgConfigBuildSystem,
+ vendored::VendoredBuildSystem, BuildSystem,
+ },
+ metadata::{DtlsBackend, LibcoapFeature, MINIMUM_LIBCOAP_VERSION},
+};
+
+mod bindings;
+mod build_system;
+mod metadata;
+
+fn main() -> Result<()> {
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_DTLS_BACKEND");
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_BUILD_SYSTEM");
+ println!("cargo:rerun-if-env-changed=LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS");
+ // On ESP-IDF builds, this indicates whether the libcoap component has been enabled.
+ println!("cargo::rustc-check-cfg=cfg(esp_idf_comp_espressif__coap_enabled)");
+ // Indicates the DTLS library crate that was linked against, if a library version vendored by
+ // another crate was used.
+ println!("cargo:rustc-check-cfg=cfg(used_dtls_crate, values(\"mbedtls\", \"tinydtls\", \"openssl\"))");
+ // Indicates the DTLS backend used, if any.
+ println!("cargo:rustc-check-cfg=cfg(dtls_backend, values(\"mbedtls\", \"tinydtls\", \"openssl\", \"gnutls\", \"wolfssl\"))");
+ // The detected libcoap version, if any.
+ println!("cargo::rustc-check-cfg=cfg(libcoap_version, values(any()))");
+
+ let out_dir = PathBuf::from(
+ env::var_os("OUT_DIR").expect("no OUT_DIR was provided (are we not running as a cargo build script?)"),
+ );
+
+ let target_os = env::var("CARGO_CFG_TARGET_OS").expect("unable to parse CARGO_CFG_TARGET_OS env variable");
+
+ let requested_features: EnumSet = EnumSet::::all()
+ .iter()
+ .filter(|feat| env::var_os(format!("CARGO_FEATURE_{}", feat.cargo_feature_var_suffix())).is_some())
+ .collect();
+
+ let requested_dtls_backend: Option = match env::var("LIBCOAP_RS_DTLS_BACKEND") {
+ Ok(v) => v.parse().map(Some),
+ Err(VarError::NotPresent) => Ok(None),
+ Err(e) => Err(anyhow!(e)),
+ }
+ .context("unable to parse environment variable LIBCOAP_RS_DTLS_BACKEND")?;
+
+ let chosen_build_system = match env::var("LIBCOAP_RS_BUILD_SYSTEM") {
+ Ok(v) => Ok(Some(v)),
+ Err(VarError::NotPresent) => Ok(None),
+ Err(e) => Err(e).context("unable to parse environment variable LIBCOAP_BUILD_SYSTEM"),
+ }?;
+
+ let bypass_compile_time_feature_checks = match env::var("LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS") {
+ Ok(v) if v == "0" => Ok(false),
+ Ok(_v) => Ok(true),
+ Err(VarError::NotPresent) => Ok(false),
+ Err(e) => Err(e).context("unable to parse environment variable LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS"),
+ }?;
+
+ let mut build_system: Box = match chosen_build_system.as_deref() {
+ Some(requested_build_system) => link_libcoap_explicit(
+ requested_build_system,
+ &target_os,
+ out_dir,
+ requested_features,
+ requested_dtls_backend,
+ bypass_compile_time_feature_checks,
+ ),
+ None => link_libcoap_auto(
+ &target_os,
+ out_dir,
+ requested_features,
+ requested_dtls_backend,
+ bypass_compile_time_feature_checks,
+ ),
+ }?;
+
+ let bindings_file = build_system.generate_bindings()?;
+ println!(
+ "cargo:rustc-env=BINDINGS_FILE={}",
+ bindings_file.canonicalize()?.display()
+ );
+
+ if let Some(version) = build_system.version() {
+ if version < Version::from(MINIMUM_LIBCOAP_VERSION).unwrap() {
+ println!("cargo:warning=The linked version of libcoap is lower than the minimal version required for libcoap-sys ({}), this will most likely cause errors.", MINIMUM_LIBCOAP_VERSION);
+ }
+ println!("cargo::metadata=libcoap_version={}", version.as_str());
+ println!("cargo::rustc-cfg=libcoap_version=\"{}\"", version.as_str());
+ } else {
+ println!("cargo:warning=Unable to automatically detect the linked version of libcoap, please manually ensure that the used version is at least {} for libcoap-sys to work as expected.", MINIMUM_LIBCOAP_VERSION);
+ }
+
+ if let Some(dtls_backend) = build_system.detected_dtls_backend() {
+ println!("cargo::metadata=dtls_backend={}", dtls_backend.as_str());
+ println!("cargo::rustc-cfg=dtls_backend=\"{}\"", dtls_backend.as_str());
+
+ if !bypass_compile_time_feature_checks {
+ if let Some(req_backend) = requested_dtls_backend {
+ assert_eq!(req_backend, dtls_backend,
+ concat!(
+ "The libcoap-rs compile-time check has determined that the DTLS library\n",
+ "the used version of libcoap linked against ({}) does not match the one set in LIBCOAP_RS_DTLS_BACKEND ({}).\n",
+ "If you are certain that this check is mistaken (e.g., because you are cross-compiling), you\n",
+ "may bypass it by setting the `LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS` environment\n",
+ "variable to any non-zero value.\n",
+ "Be aware, however, that this might lead to more cryptic errors if the requested features are\n",
+ "not available after all.\n",
+ "Refer to the libcoap-sys crate-level documentation for more information: https://docs.rs/libcoap-sys."
+ ), dtls_backend.as_str(), req_backend.as_str())
+ } else if bypass_compile_time_feature_checks {
+ println!("cargo:warning=You have bypassed the libcoap-sys compile-time DTLS library check.")
+ }
+ }
+ }
+
+ match build_system.detected_features() {
+ Some(detected_features) => {
+ let compile_time_checkable_features: EnumSet = requested_features
+ .iter()
+ .filter(|feat| feat.define_name().is_some())
+ .collect();
+ if !bypass_compile_time_feature_checks && !compile_time_checkable_features.is_subset(detected_features) {
+ let missing_features = requested_features.difference(detected_features);
+ bail!(
+ concat!(
+ "the libcoap-rs compile-time feature check has determined that the following enabled features\n",
+ "are not supported by the used C library: {}.\n",
+ "If you are certain that this check is mistaken (e.g., because you are cross-compiling), you\n",
+ "may bypass this check by setting the `LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS` environment\n",
+ "variable to any non-zero value.\n",
+ "Be aware, however, that this might lead to more cryptic errors if the requested features are\n",
+ "not available after all.\n",
+ "Refer to the libcoap-sys crate-level documentation for more information: https://docs.rs/libcoap-sys."
+ ),
+ missing_features
+ .iter()
+ .map(|v| v.as_str())
+ .collect::>()
+ .join(", ")
+ );
+ } else if bypass_compile_time_feature_checks {
+ println!("cargo:warning=You have bypassed the libcoap-sys compile-time feature check.")
+ }
+ },
+ None => {
+ println!("cargo:warning=The used build system for libcoap-sys does not support compile-time feature checks. Missing features may therefore only be detected during runtime.");
+ },
+ }
+
+ Ok(())
+}
+
+fn link_libcoap_explicit(
+ requested_build_system: &str,
+ target_os: &str,
+ out_dir: PathBuf,
+ requested_features: EnumSet,
+ requested_dtls_backend: Option,
+ bypass_compile_time_feature_checks: bool,
+) -> Result> {
+ match requested_build_system {
+ "vendored" if target_os == "espidf" => {
+ EspIdfBuildSystem::new(out_dir, requested_features, requested_dtls_backend, bypass_compile_time_feature_checks).map(|v| Box::::from(Box::new(v)))
+ },
+ "vendored" if cfg!(not(feature = "vendored")) => Err(anyhow!("LIBCOAP_RS_BUILD_SYSTEM has been set to \"vendored\", but the corresponding crate feature \"vendored\" has not been enabled.")),
+ "vendored" => VendoredBuildSystem::build_libcoap(out_dir, requested_features, requested_dtls_backend)
+ .map(|v| Box::::from(Box::new(v))),
+ "pkgconfig" if target_os != "espidf" => {
+ PkgConfigBuildSystem::link_with_libcoap(out_dir, requested_dtls_backend)
+ .map(|v| Box::::from(Box::new(v)))
+ },
+ "manual" => ManualBuildSystem::link_with_libcoap(out_dir, requested_dtls_backend).map(|v| Box::::from(Box::new(v))),
+ v => Err(anyhow!("build system {v} is unknown or unsupported for this target")),
+ }
+ .context(format!(
+ "unable to link libcoap using force-configured build system {requested_build_system}"
+ ))
+}
+
+fn vendored_libcoap_build(
+ target_os: &str,
+ out_dir: PathBuf,
+ requested_features: EnumSet,
+ requested_dtls_backend: Option,
+ bypass_compile_time_feature_checks: bool,
+) -> Result> {
+ // TODO: Later on, we'll probably want to use the CMake based build system for any host+target
+ // combination that the libcoap build documentation recommends CMake for (most notably:
+ // Windows).
+ // See: https://github.com/obgm/libcoap/blob/develop/BUILDING
+ match target_os {
+ "espidf" => EspIdfBuildSystem::new(
+ out_dir,
+ requested_features,
+ requested_dtls_backend,
+ bypass_compile_time_feature_checks,
+ )
+ .map(|v| Box::::from(Box::new(v))),
+ _ => VendoredBuildSystem::build_libcoap(out_dir, requested_features, requested_dtls_backend)
+ .map(|v| Box::::from(Box::new(v))),
+ }
+}
+
+fn link_libcoap_auto(
+ target_os: &str,
+ out_dir: PathBuf,
+ requested_features: EnumSet,
+ requested_dtls_backend: Option,
+ bypass_compile_time_feature_checks: bool,
+) -> Result> {
+ let mut errors = Vec::<(&'static str, anyhow::Error)>::new();
+ // Try vendored build first if the feature is enabled and supported by the host.
+ // If the vendored build fails on a supported target, do not try anything else (we assume that
+ // the user wanted to use the vendored library for a reason).
+ if cfg!(feature = "vendored") || target_os == "espidf" {
+ return vendored_libcoap_build(
+ target_os,
+ out_dir,
+ requested_features,
+ requested_dtls_backend,
+ bypass_compile_time_feature_checks,
+ );
+ }
+ PkgConfigBuildSystem::link_with_libcoap(out_dir.clone(), requested_dtls_backend)
+ .map(|v| Box::::from(Box::new(v)))
+ .or_else(|e| {
+ errors.push(("pkgconfig", e));
+ ManualBuildSystem::link_with_libcoap(out_dir, requested_dtls_backend)
+ .map(|v| Box::::from(Box::new(v)))
+ })
+ .map_err(|e| {
+ errors.push(("manual", e));
+ anyhow!(
+ "unable to find a version of libcoap to link with:\n{}",
+ errors
+ .iter()
+ .map(|(k, v)| format!("Build system {k} failed with error: {v:?}"))
+ .collect::>()
+ .join("\n")
+ )
+ })
+}
diff --git a/libcoap-sys/build/metadata.rs b/libcoap-sys/build/metadata.rs
new file mode 100644
index 00000000..b7e63bbf
--- /dev/null
+++ b/libcoap-sys/build/metadata.rs
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * build/metadata.rs - Type definitions for metadata in the libcoap-sys build script.
+ * This file is part of the libcoap-sys crate, see the README and LICENSE files for
+ * more information and terms of use.
+ * Copyright © 2021-2025 The NAMIB Project Developers, all rights reserved.
+ * See the README as well as the LICENSE file for more information.
+ */
+
+use std::{
+ fmt::{Display, Formatter},
+ str::FromStr,
+};
+
+use anyhow::anyhow;
+use enumset::{EnumSet, EnumSetType};
+
+/// Minimum required version of libcoap in order to build the bindgen-generated bindings.
+///
+/// Note that this is *not* the minimum supported version of the safe wrapper, and should only be
+/// increased if building on older versions causes issues with libcoap-sys specifically.
+pub const MINIMUM_LIBCOAP_VERSION: &str = "4.3.5";
+
+/// Information about a version of libcoap that was parsed by
+/// [`LibcoapDefineParser`](crate::bindings::LibcoapDefineParser).
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
+pub struct LibcoapDefineInfo {
+ pub version: Option,
+ pub dtls_backend: Option,
+ pub supported_features: EnumSet,
+}
+
+/// An optional feature that may or may not be supported by a version of `libcoap`.
+#[derive(EnumSetType, Debug)]
+pub enum LibcoapFeature {
+ AfUnix,
+ Async,
+ Client,
+ SmallStack,
+ Tcp,
+ Epoll,
+ Ipv4,
+ Ipv6,
+ Oscore,
+ QBlock,
+ Server,
+ ThreadRecursiveLockDetection,
+ ThreadSafe,
+ Dtls,
+ ObservePersist,
+ WebSockets,
+ SecureWebSockets,
+ DtlsCid,
+ DtlsPsk,
+ DtlsPki,
+ DtlsPkcs11,
+ DtlsRpk,
+ Tls,
+}
+
+impl LibcoapFeature {
+ /// Returns the name of the #define in `coap_defines.h` that corresponds to the given feature,
+ /// or None if there is no direct correspondence to such a #define.
+ pub fn define_name(&self) -> Option<&'static str> {
+ match self {
+ LibcoapFeature::AfUnix => Some("COAP_AF_UNIX_SUPPORT"),
+ LibcoapFeature::Async => Some("COAP_ASYNC_SUPPORT"),
+ LibcoapFeature::Client => Some("COAP_CLIENT_SUPPORT"),
+ LibcoapFeature::SmallStack => Some("COAP_CONSTRAINED_STACK"),
+ LibcoapFeature::Tcp => Some("COAP_DISABLE_TCP"),
+ LibcoapFeature::Epoll => Some("COAP_EPOLL_SUPPORT"),
+ LibcoapFeature::Ipv4 => Some("COAP_IPV4_SUPPORT"),
+ LibcoapFeature::Ipv6 => Some("COAP_IPV6_SUPPORT"),
+ LibcoapFeature::Oscore => Some("COAP_OSCORE_SUPPORT"),
+ LibcoapFeature::QBlock => Some("COAP_Q_BLOCK_SUPPORT"),
+ LibcoapFeature::Server => Some("COAP_SERVER_SUPPORT"),
+ LibcoapFeature::ThreadRecursiveLockDetection => Some("COAP_THREAD_RECURSIVE_CHECK"),
+ LibcoapFeature::ThreadSafe => Some("COAP_THREAD_SAFE"),
+ LibcoapFeature::ObservePersist => Some("COAP_WITH_OBSERVE_PERSIST"),
+ LibcoapFeature::WebSockets => Some("COAP_WS_SUPPORT"),
+ _ => None,
+ }
+ }
+
+ /// Returns the set of features that are supposedly enabled if the #define with the name
+ /// `define_name` is set to `define_value` in `coap_defines.h`, or an empty set if the provided
+ /// define does not correspond to such a feature.
+ pub fn features_from_define(define_name: &str, define_value: i64) -> EnumSet {
+ // Only consider values != 0.
+ if define_name != "COAP_DISABLE_TCP" && define_value == 0 {
+ return EnumSet::empty();
+ }
+ match define_name {
+ "COAP_AF_UNIX_SUPPORT" => EnumSet::from(LibcoapFeature::AfUnix),
+ "COAP_ASYNC_SUPPORT" => EnumSet::from(LibcoapFeature::Async),
+ "COAP_CLIENT_SUPPORT" => EnumSet::from(LibcoapFeature::Client),
+ "COAP_CONSTRAINED_STACK" => EnumSet::from(LibcoapFeature::SmallStack),
+ "COAP_EPOLL_SUPPORT" => EnumSet::from(LibcoapFeature::Epoll),
+ "COAP_IPV4_SUPPORT" => EnumSet::from(LibcoapFeature::Ipv4),
+ "COAP_IPV6_SUPPORT" => EnumSet::from(LibcoapFeature::Ipv6),
+ "COAP_OSCORE_SUPPORT" => EnumSet::from(LibcoapFeature::Oscore),
+ "COAP_Q_BLOCK_SUPPORT" => EnumSet::from(LibcoapFeature::QBlock),
+ "COAP_SERVER_SUPPORT" => EnumSet::from(LibcoapFeature::Server),
+ "COAP_THREAD_RECURSIVE_CHECK" => EnumSet::from(LibcoapFeature::ThreadRecursiveLockDetection),
+ "COAP_THREAD_SAFE" => EnumSet::from(LibcoapFeature::ThreadSafe),
+ "COAP_WITH_OBSERVE_PERSIST" => EnumSet::from(LibcoapFeature::ObservePersist),
+ "COAP_WS_SUPPORT" => EnumSet::from(LibcoapFeature::WebSockets),
+ "COAP_DISABLE_TCP" => {
+ if define_value == 0 {
+ EnumSet::from(LibcoapFeature::Tcp)
+ } else {
+ EnumSet::empty()
+ }
+ },
+ "COAP_WITH_LIBGNUTLS"
+ | "COAP_WITH_LIBMBEDTLS"
+ | "COAP_WITH_LIBOPENSSL"
+ | "COAP_WITH_LIBTINYDTLS"
+ | "COAP_WITH_LIBWOLFSSL" => EnumSet::from(LibcoapFeature::Dtls),
+ _ => EnumSet::empty(),
+ }
+ }
+
+ /// Return the configure argument name (--enable-) that can be provided to libcoap's
+ /// configure-script to enable the given feature (or None if no such flag is available).
+ pub fn configure_flag_name(&self) -> Option<&'static str> {
+ match self {
+ LibcoapFeature::AfUnix => Some("af-unix"),
+ LibcoapFeature::Async => Some("async"),
+ LibcoapFeature::Client => Some("client-mode"),
+ LibcoapFeature::SmallStack => Some("small-stack"),
+ LibcoapFeature::Tcp => Some("tcp"),
+ LibcoapFeature::Epoll => Some("epoll"),
+ LibcoapFeature::Ipv4 => Some("ipv4"),
+ LibcoapFeature::Ipv6 => Some("ipv6"),
+ LibcoapFeature::Oscore => Some("oscore"),
+ LibcoapFeature::QBlock => Some("q-block"),
+ LibcoapFeature::Server => Some("server-mode"),
+ LibcoapFeature::ThreadRecursiveLockDetection => Some("thread-recursive-lock-detection"),
+ LibcoapFeature::ThreadSafe => Some("thread-safe"),
+ LibcoapFeature::Dtls => Some("dtls"),
+ LibcoapFeature::ObservePersist => Some("observe-persist"),
+ LibcoapFeature::WebSockets => Some("websockets"),
+ _ => None,
+ }
+ }
+
+ /// Return the ESP-IDF sdkconfig option name that must be set to enable this feature, or None
+ /// if no configuration option is available.
+ /// Reference: https://github.com/espressif/idf-extra-components/blob/master/coap/Kconfig
+ pub fn sdkconfig_flag_name(&self) -> Option<&'static str> {
+ match self {
+ LibcoapFeature::DtlsPsk => Some("COAP_MBEDTLS_PSK"),
+ LibcoapFeature::DtlsPki => Some("COAP_MBEDTLS_PKI"),
+ // Should be implied by mbedtls being enabled.
+ LibcoapFeature::DtlsCid => Some("COAP_MBEDTLS_PSK"),
+ LibcoapFeature::Tcp => Some("COAP_TCP_SUPPORT"),
+ LibcoapFeature::Oscore => Some("COAP_OSCORE_SUPPORT"),
+ LibcoapFeature::ObservePersist => Some("COAP_OBSERVE_PERSIST"),
+ LibcoapFeature::QBlock => Some("COAP_Q_BLOCK"),
+ LibcoapFeature::Async => Some("COAP_ASYNC_SUPPORT"),
+ LibcoapFeature::ThreadSafe => Some("COAP_THREAD_SAFE"),
+ LibcoapFeature::ThreadRecursiveLockDetection => Some("COAP_THREAD_RECURSIVE_CHECK"),
+ LibcoapFeature::WebSockets => Some("COAP_WEBSOCKETS"),
+ LibcoapFeature::Client => Some("COAP_CLIENT_SUPPORT"),
+ LibcoapFeature::Server => Some("COAP_SERVER_SUPPORT"),
+ _ => None,
+ }
+ }
+
+ /// Returns the suffix of the CARGO_FEATURE_ environment variable that must be set
+ /// during build script execution if the feature has been enabled.
+ pub fn cargo_feature_var_suffix(&self) -> String {
+ self.as_str().to_uppercase().replace('-', "_")
+ }
+
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ LibcoapFeature::AfUnix => "af-unix",
+ LibcoapFeature::Async => "async",
+ LibcoapFeature::Client => "client",
+ LibcoapFeature::SmallStack => "small-stack",
+ LibcoapFeature::Tcp => "tcp",
+ LibcoapFeature::Epoll => "epoll",
+ LibcoapFeature::Ipv4 => "ipv4",
+ LibcoapFeature::Ipv6 => "ipv6",
+ LibcoapFeature::Oscore => "oscore",
+ LibcoapFeature::QBlock => "q-block",
+ LibcoapFeature::Server => "server",
+ LibcoapFeature::ThreadRecursiveLockDetection => "thread-recursive-lock-detection",
+ LibcoapFeature::ThreadSafe => "thread-safe",
+ LibcoapFeature::Dtls => "dtls",
+ LibcoapFeature::ObservePersist => "observe-persist",
+ LibcoapFeature::WebSockets => "websockets",
+ LibcoapFeature::SecureWebSockets => "secure-websockets",
+ LibcoapFeature::DtlsCid => "dtls-cid",
+ LibcoapFeature::DtlsPsk => "dtls-psk",
+ LibcoapFeature::DtlsPki => "dtls-pki",
+ LibcoapFeature::DtlsPkcs11 => "dtls-pkcs11",
+ LibcoapFeature::DtlsRpk => "dtls-rpk",
+ LibcoapFeature::Tls => "tls",
+ }
+ }
+}
+
+/// A DLTS library that can be used by `libcoap` for encryption support.
+#[derive(Debug, EnumSetType, Hash)]
+pub enum DtlsBackend {
+ GnuTls,
+ OpenSsl,
+ MbedTls,
+ TinyDtls,
+ WolfSsl,
+}
+
+impl FromStr for DtlsBackend {
+ type Err = anyhow::Error;
+
+ fn from_str(s: &str) -> Result {
+ match s {
+ "gnutls" => Ok(DtlsBackend::GnuTls),
+ "openssl" => Ok(DtlsBackend::OpenSsl),
+ "mbedtls" => Ok(DtlsBackend::MbedTls),
+ "tinydtls" => Ok(DtlsBackend::TinyDtls),
+ "wolfssl" => Ok(DtlsBackend::WolfSsl),
+ v => Err(anyhow!("unknown DTLS backend {v}")),
+ }
+ }
+}
+
+impl Display for DtlsBackend {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
+impl DtlsBackend {
+ /// Returns the suffix that has to be appended to libcoap-3- to find a library
+ /// version linked against the right DTLS library.
+ pub fn library_suffix(&self) -> &'static str {
+ // just keeping this here in case we ever need to change this definition to something
+ // different than self.as_str() for some libraries.
+ self.as_str()
+ }
+
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ DtlsBackend::GnuTls => "gnutls",
+ DtlsBackend::OpenSsl => "openssl",
+ DtlsBackend::MbedTls => "mbedtls",
+ DtlsBackend::TinyDtls => "tinydtls",
+ DtlsBackend::WolfSsl => "wolfssl",
+ }
+ }
+
+ /// Returns the DTLS library that is supposedly enabled if the #define with the name
+ /// `define_name` is set to `define_value` in `coap_defines.h`, or None if the provided
+ /// define does not correspond to a DTLS library.
+ pub fn library_from_define(define_name: &str, define_value: i64) -> Option {
+ if define_value == 0 {
+ return None;
+ }
+ match define_name {
+ "COAP_WITH_LIBGNUTLS" => Some(DtlsBackend::GnuTls),
+ "COAP_WITH_LIBMBEDTLS" => Some(DtlsBackend::MbedTls),
+ "COAP_WITH_LIBOPENSSL" => Some(DtlsBackend::OpenSsl),
+ "COAP_WITH_LIBTINYDTLS" => Some(DtlsBackend::TinyDtls),
+ "COAP_WITH_LIBWOLFSSL" => Some(DtlsBackend::WolfSsl),
+ _ => None,
+ }
+ }
+}
diff --git a/libcoap-sys/examples/esp-idf/.cargo/config.toml b/libcoap-sys/examples/esp-idf/.cargo/config.toml
new file mode 100644
index 00000000..11494290
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/.cargo/config.toml
@@ -0,0 +1,16 @@
+[build]
+target = "riscv32imc-esp-espidf"
+
+[target.riscv32imc-esp-espidf]
+linker = "ldproxy"
+runner = "espflash flash --monitor"
+rustflags = [ "--cfg", "espidf_time64"]
+
+[unstable]
+build-std = ["std", "panic_abort"]
+
+[env]
+MCU="esp32c3"
+# Note: this variable is not used by the pio builder (`cargo build --features pio`)
+ESP_IDF_VERSION = "v5.2.3"
+
diff --git a/libcoap-sys/examples/esp-idf/.github/workflows/rust_ci.yml b/libcoap-sys/examples/esp-idf/.github/workflows/rust_ci.yml
new file mode 100644
index 00000000..e7e9b1ec
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/.github/workflows/rust_ci.yml
@@ -0,0 +1,41 @@
+name: Continuous Integration
+
+on:
+ push:
+ paths-ignore:
+ - "**/README.md"
+ pull_request:
+ workflow_dispatch:
+
+env:
+ CARGO_TERM_COLOR: always
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+jobs:
+ rust-checks:
+ name: Rust Checks
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ action:
+ - command: build
+ args: --release
+ - command: fmt
+ args: --all -- --check --color always
+ - command: clippy
+ args: --all-targets --all-features --workspace -- -D warnings
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Setup Rust
+ uses: dtolnay/rust-toolchain@v1
+ with:
+ toolchain: nightly
+ components: rust-src rustfmt clippy
+ - name: Enable caching
+ uses: Swatinem/rust-cache@v2
+ - name: Install ldproxy
+ run: cargo install ldproxy
+ - name: Run command
+ run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}
diff --git a/libcoap-sys/examples/esp-idf/.gitignore b/libcoap-sys/examples/esp-idf/.gitignore
new file mode 100644
index 00000000..aa1d4bf7
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/.gitignore
@@ -0,0 +1,5 @@
+/.vscode
+/.embuild
+/target
+/Cargo.lock
+/vars.log
\ No newline at end of file
diff --git a/libcoap-sys/examples/esp-idf/Cargo.toml b/libcoap-sys/examples/esp-idf/Cargo.toml
new file mode 100644
index 00000000..8f1b550c
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/Cargo.toml
@@ -0,0 +1,34 @@
+[package]
+name = "libcoap-sys-esp-idf-example"
+version = "0.1.0"
+authors = ["Hugo Hakim Damer "]
+edition = "2021"
+resolver = "2"
+rust-version = "1.77"
+
+[[bin]]
+name = "libcoap-sys-esp-idf-example"
+harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors
+
+[profile.release]
+opt-level = "s"
+
+[profile.dev]
+debug = true # Symbols are nice and they don't increase the size on Flash
+opt-level = "z"
+
+[features]
+default = []
+
+experimental = ["esp-idf-svc/experimental"]
+
+[dependencies]
+log = "0.4"
+esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] }
+esp-idf-sys = { version = "0.36.1" }
+libcoap-sys = { version = "*", path = "../../" }
+
+[build-dependencies]
+embuild = "0.33"
+
+[workspace]
diff --git a/libcoap-sys/examples/esp-idf/README.md b/libcoap-sys/examples/esp-idf/README.md
new file mode 100644
index 00000000..25f49b59
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/README.md
@@ -0,0 +1,6 @@
+This folder contains a slightly modified version of the ESP-IDF Rust project template that can be found
+[here](https://github.com/esp-rs/esp-idf-template/tree/master/cargo), with slight modifications to
+`sdkconfig.defaults`, `Cargo.toml` and `main.rs` to add support for `libcoap-sys`.
+
+It is mainly used to test the compilation and binding generation process for ESP-IDF builds of `libcoap-sys`,
+but you may also use it as a reference for your own projects.
\ No newline at end of file
diff --git a/libcoap-sys/examples/esp-idf/build.rs b/libcoap-sys/examples/esp-idf/build.rs
new file mode 100644
index 00000000..112ec3f7
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ embuild::espidf::sysenv::output();
+}
diff --git a/libcoap-sys/examples/esp-idf/components_esp32c3.lock b/libcoap-sys/examples/esp-idf/components_esp32c3.lock
new file mode 100644
index 00000000..b6391610
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/components_esp32c3.lock
@@ -0,0 +1,20 @@
+dependencies:
+ espressif/coap:
+ component_hash: a5d1b781b15980d9af136b5e63315dd5f5ec00215cc755f395ad2fb4977c7668
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.4'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 4.3.5~3
+ idf:
+ source:
+ type: idf
+ version: 5.2.3
+direct_dependencies:
+- espressif/coap
+manifest_hash: 13fcf89b865b0f073a765a0dfdcf062a0063b4af7a631d3d37ef94c920538a25
+target: esp32c3
+version: 2.0.0
diff --git a/libcoap-sys/examples/esp-idf/rust-toolchain.toml b/libcoap-sys/examples/esp-idf/rust-toolchain.toml
new file mode 100644
index 00000000..f70d2254
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/rust-toolchain.toml
@@ -0,0 +1,3 @@
+[toolchain]
+channel = "nightly"
+components = ["rust-src"]
diff --git a/libcoap-sys/examples/esp-idf/sdkconfig.defaults b/libcoap-sys/examples/esp-idf/sdkconfig.defaults
new file mode 100644
index 00000000..1c2bfab4
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/sdkconfig.defaults
@@ -0,0 +1,21 @@
+# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
+
+# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
+# This allows to use 1 ms granularity for thread sleeps (10 ms by default).
+#CONFIG_FREERTOS_HZ=1000
+
+# Workaround for https://github.com/espressif/esp-idf/issues/7631
+#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
+#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
+
+CONFIG_COAP_CLIENT_SUPPORT=y
+CONFIG_COAP_SERVER_SUPPORT=y
+CONFIG_COAP_TCP_SUPPORT=y
+CONFIG_COAP_OSCORE_SUPPORT=y
+CONFIG_COAP_Q_BLOCK=y
+CONFIG_COAP_SERVER_SUPPORT=y
+CONFIG_COAP_THREAD_RECURSIVE_CHECK=y
+CONFIG_COAP_THREAD_SAFE=y
+CONFIG_COAP_OBSERVE_PERSIST=y
+CONFIG_COAP_WEBSOCKETS=y
diff --git a/libcoap-sys/examples/esp-idf/src/main.rs b/libcoap-sys/examples/esp-idf/src/main.rs
new file mode 100644
index 00000000..42fa7063
--- /dev/null
+++ b/libcoap-sys/examples/esp-idf/src/main.rs
@@ -0,0 +1,12 @@
+use libcoap_sys as _;
+
+fn main() {
+ // It is necessary to call this function once. Otherwise some patches to the runtime
+ // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
+ esp_idf_svc::sys::link_patches();
+
+ // Bind the log crate to the ESP Logging facilities
+ esp_idf_svc::log::EspLogger::initialize_default();
+
+ log::info!("Hello, world!");
+}
diff --git a/libcoap-sys/examples/esp-idf/vars.log b/libcoap-sys/examples/esp-idf/vars.log
new file mode 100644
index 00000000..e69de29b
diff --git a/libcoap-sys/src/lib.rs b/libcoap-sys/src/lib.rs
index 1444fdf8..1add89fc 100644
--- a/libcoap-sys/src/lib.rs
+++ b/libcoap-sys/src/lib.rs
@@ -14,107 +14,334 @@
//! made in this library are generated automatically using bindgen, for further documentation on how
//! to use them, refer to the [libcoap documentation](https://libcoap.net/documentation.html).
//!
-//! In most cases you probably want to use the safe wrapper provided by the libcoap crate (or
-//! another coap library written in pure rust such as [coap-rs](https://github.com/covertness/coap-rs))
+//! In most cases you probably want to use the safe wrapper provided by the libcoap-rs crate or
+//! another coap library written in pure Rust such as [coap-rs](https://github.com/covertness/coap-rs)
//! instead.
//!
-//! Cargo Features
+//! The TLDR for building libcoap-sys (and resolving the most common Build Issues)
+//! ------------------------------------------------------------------------------
+//! It is strongly recommended that you read the remainder of this page in order to fully understand
+//! the build process and possible causes of errors, especially if you're cross-compiling or
+//! building for embedded targets.
+//!
+//! However, if you lack the time to do so, the following instructions should work in most cases:
+//!
+//! 1. Add a dependency to this crate and add all features you need for your crate to work.
+//! Call [`coap_startup_with_feature_checks()`] instead of [`coap_startup()`] during
+//! initialization to ensure that all of these features are actually available in the linked
+//! version of `libcoap`.
+//!
+//! 2. If you require DTLS support and run into `Required feature "dtls-(psk|pki|rpk|...)" is not
+//! supported by libcoap` errors, manually select a DTLS library that supports all of your
+//! required DTLS features by setting the `LIBCOAP_RS_DTLS_BACKEND` environment variable to your
+//! desired choice (the library name in all-lowercase should work).
+//!
+//! 3. If you're building a binary crate (or tests, examples, ...) and are getting non-DTLS-related
+//! `Required feature "" is not supported by libcoap` errors, enable the `vendored`
+//! feature to build and statically link a version of libcoap that supports exactly the features
+//! you requested.
+//!
+//! 4. Inspect your dependency tree to determine whether you already have a DTLS library's sys-crate
+//! (`openssl-sys`, `tinydtls-sys` or `mbedtls-sys-auto`) in your dependency tree.
+//! If this is the case, enable the `dtls--sys` feature for all of them.
+//! This may resolve issues related to linking multiple versions of the same library at once, and
+//! could also help in reducing binary size.
+//!
+//! If you're still unable to compile `libcoap-sys`, refer to the documentation below.
+//! If the documentation below does not solve your issue, feel free to open an issue
+//! [on GitHub](https://github.com/namib-project/libcoap-rs/) and ask for help.
+//!
+//! Optional Features
//! --------------
-//! We currently define a number of features that affect the functionality provided by this wrapper
-//! and required by the linked libcoap library.
-//!
-//! Features affecting functionality:
-//! - `dtls`: Enable usage of DTLS for transport security. Supports a number of different backends.
-//!
-//! Note that while not specified here due to limitations in Cargo's syntax, the DTLS feature
-//! depends on one of the DTLS backends being enabled, and failing to enable a DTLS backend will
-//! result in a build failure.
-//!
-//! If you are developing a library based on libcoap-sys and do not care about the DTLS backend,
-//! enable the dtls feature and let the user decide on the backend to use, either by
-//! re-exporting these features (see [the Cargo Book](https://doc.rust-lang.org/cargo/reference/features.html#dependency-features))
-//! or by assuming that the user will use libcoap-sys as a dependency and enable the
-//! corresponding backend feature themselves, relying on Cargo's feature unification to enable
-//! it for your crate as well.
-//!
-//! Also note that the backends are **mutually exclusive** due to the C library having these
-//! backends as mutually exclusive features. If multiple backends are enabled (e.g. because
-//! multiple dependencies use libcoap-sys and use different backends), we select one based on
-//! the auto-detection order specified in [the libcoap configure script](https://github.com/obgm/libcoap/blob/develop/configure.ac#L494)
-//! (gnutls > openssl > mbedtls > tinydtls).
-//! - `dtls_backend_(openssl|gnutls|mbedtls|tinydtls)`: Enable the corresponding DTLS backend.
-//!
-//! Note that enabling the OpenSSL, GnuTLS, TinyDTLS or MbedTLS backend will also require the
-//! appropriate library to be available (hence the dependency on the corresponding sys-crate).
-//! The TinyDTLS backend is built using a vendored (and statically linked) version of TinyDTLS
-//! by default, see the tinydtls-sys crate for more info.
-//! Choosing a DTLS backend also means that the license terms of these libraries may apply to
-//! you. See the relevant parts of the [libcoap license file](https://github.com/obgm/libcoap/blob/develop/LICENSE)
-//! for more information.
-//! - `tcp` (default): Enable CoAP over TCP support
-//! - `async` (default): Enable async functionality.
-//!
-//! Note that this async functionality is not translated to Rust's async language functionality,
-//! but instead adds functionality to the underlying C library to allow for making asynchronous
-//! requests (i.e. function calls that return before the response has arrived).
-//!
-//! Integrating libcoap into Rusts async language features is out of scope for this crate, but
-//! might be implemented later on in the libcoap (safe abstraction) crate.
-//! - `server` (default): Enable code related to server functionality
-//! - `client` (default): Enable code related to client functionality
-//! - `epoll` (default): Allow the underlying C library to perform IO operations using epoll.
-//!
-//! Other features:
-//! - `vendored` (default): Use a vendored version of libcoap instead of the system-provided one.
-//! Note that `vendored` implies `static`.
-//! - `static` (default): Perform static linking to the libcoap C library.
-//!
-//! ### Note on features affecting functionality
-//! The features that add or remove functionality do not change the generated bindings as libcoap's
-//! headers (unlike the source files themselves) are not affected by the corresponding `#define`s.
-//!
-//! For library users that link to a shared version of libcoap, this means that the feature flags
-//! do not have any effect and the supported features will correspond directly to the features
-//! enabled during the build of the shared libcoap instance (using the configure-script).
-//!
-//! For users of the vendored version of libcoap (see the `vendored` feature), the supported
-//! features of the vendored libcoap will be set to match the cargo features during build.
+//! Most features specified in this crate's Cargo.toml directly correspond to a feature that can be
+//! enabled or disabled in libcoap's configure-script and/or CMake configuration, refer to the
+//! libcoap documentation for more details on these features.
+//!
+//! The `default` feature should match the default features enabled in the configure script of the
+//! minimum supported version of libcoap.
+//!
+//! Depending on the build system and linked version of libcoap, the features actually provided may
+//! differ from the ones indicated by the crate features.
+//! If you want to ensure that all features that are enabled for this crate are actually supported
+//! by the linked version of libcoap, you may call [`coap_startup_with_feature_checks()`].
+//!
+//! Aside from the features relating to libcoap functionality, the following features may also be
+//! enabled for this crate:
+//! - `vendored`: Build and statically link against a version of libcoap bundled with this crate
+//! instead of using a system-provided one[^1].
+//! - `dtls--sys`: Allows the [vendored](#vendored-build-system) libcoap version to link against the
+//! same version of a DTLS library that is used by the corresponding -sys
+//! crate[^2].
+//! Note, however, that this does not imply that this DTLS library *will* be used, refer to
+//! the [documentation below](#dtls-library-selection) for more information.
+//!
+//! If a different build system than `vendored` is used, this feature is effectively a no-op.
+//! - `dtls--sys-vendored` instructs the sys-crate of the DTLS library corresponding
+//! to the feature name to use a vendored version of the underlying library (implies
+//! `dtls--sys`).
+//! - `dtls-(cid|psk|pki|pkcs11|rpk)`: Require support for specific DTLS features in `libcoap`.
+//! These features can not be enabled explicitly while building `libcoap`, support for them is
+//! automatically made available based on the used DTLS library (see
+//! [the corresponding section below](#dtls-library-selection)).
+//!
+//! Enabling these features will add appropriate checks during compile- and/or runtime
+//! initialization to ensure these features are available in the used DTLS library (or panic
+//! otherwise).
+//!
+//! [^1]: Note that when building for the ESP-IDF, this feature will be a no-op, as the version
+//! provided by the ESP-IDF will always be used.
+//! [^2]: In the case of `mbedtls`, `mbedtls-sys-auto` is used instead, as `mbedtls-sys` is
+//! unmaintained.
+//!
+//! Build Process
+//! -------------
+//! In general, `libcoap-sys` supports four different build systems, which will be explained in more
+//! detail in the following sections:
+//! - `vendored`: Build libcoap from source using a bundled version of the library (requires the
+//! `vendored` feature to be enabled.
+//! - `pkgconfig`: Link against a system-provided version of libcoap, obtaining the library and
+//! include paths using the `pkg-config` utility.
+//! - `manual`: Provide include and library directories+compiler/linker flags via environment
+//! variables.
+//! - `espidf`: Build for the ESP family of microcontrollers using the ESP-IDF framework (used
+//! instead of the regular `vendored` build if the build system is set to `vendored` and
+//! building for an ESP-IDF Rust target).
+//!
+//! The build system that should be used can be specified manually by setting the
+//! `LIBCOAP_RS_BUILD_SYSTEM` environment variable to the corresponding value.
+//!
+//! If you have explicitly specified a build system and building using that system fails, no other
+//! system will be tried.
+//!
+//! If you do not explicitly provide a build system to use, the build script will follow these
+//! steps to determine a suitable build system:
+//!
+//! 1. If the `vendored` crate feature is enabled, or we are building for the ESP-IDF, act as if the
+//! build system is set to `vendored`. If a vendored build is attempted and fails, return with an
+//! error and do not try anything else.
+//! 2. Otherwise, try `pkgconfig` first.
+//! 3. If `pkgconfig` doesn't work, fall back to `manual` (which will fail if the environment
+//! variables aren't set).
+//! 4. If `manual` doesn't work, return an error indicating the issues with all previously attempted
+//! build systems.
+//!
+//! ## Generic Information (applies to all build systems)
+//! The following information applies to all build systems (although some specifics may be detailed
+//! in the respective build system's section).
+//!
+//! ### C Standard Library Functions
+//! Some `libcoap` functions utilize types from the C standard library (e.g., `sockaddr_in` in
+//! `coap_address_t`).
+//!
+//! For most targets, the data types defined in the [`libc`](https://docs.rs/libc/latest/libc/)
+//! crate will be used to provide those data types.
+//! However, some targets (especially embedded ones such as `espidf`) will use a different library
+//! instead, which may cause compilation issues in code that assumes `libc` data types to be
+//! compatible.
+//!
+//! For your convenience, this crate re-exports the used standard library crate as the `c_stdlib`
+//! module. For best interoperability, you should `use` this module instead of using the actual
+//! crates directly to import the required data types.
+//!
+//! ### DTLS Library Selection
+//!
+//! In order to provide DTLS support, `libcoap` must be combined with a DTLS library/backend.
+//! DTLS libraries are mutually exclusive, and multiple versions of `libcoap` linked against
+//! different DTLS libraries may be installed in a system simultaneously, so `libcoap-sys` must
+//! decide on a variant of `libcoap` to link against during build.
+//!
+//! While the default mechanism for determining a DTLS library differs between build systems, you
+//! may select a DTLS library explicitly by setting the `LIBCOAP_RS_DTLS_BACKEND` environment
+//! variable to any of the supported values (`gnutls`, `openssl`, `mbedtls`, `tinydtls`, or
+//! `wolfssl`). Refer to the build-system-specific documentation for information about supported
+//! DTLS libraries and specifics.
+//!
+//! Note that some DTLS-related features (such as `dtls-(cid|psk|pki|pkcs11|rpk)`) are dependent on
+//! the used DTLS backend, refer to [the `coap_encryption(3)` man page](https://libcoap.net/doc/reference/4.3.5/man_coap_encryption.html)
+//! for information on supported features for each DTLS library.
+//!
+//! ### Feature Support and Compile-Time/Initialization Checks
+//! During compilation, each build system will attempt to ensure that the used version of `libcoap`
+//! does in fact support all [features](#optional-features) that were enabled in `Cargo.toml`.
+//! The exact method differs based on each build system, but most will attempt to parse the
+//! `coap3/coap_defines.h` header file in order to determine missing features (with `espidf` being a
+//! notable exception).
+//!
+//! If a build system detects that a requested feature is missing, an appropriate error message will
+//! be returned. In most cases, these errors must be resolved by linking to a different version of
+//! `libcoap`.
+//!
+//! Unfortunately, for various reasons, this compile-time feature check may produce false
+//! positive and/or false negative results (especially when cross compiling[^3])
+//! is not available for all features (especially ones dependent on the DTLS library) and may not
+//! even be available at all on some platforms.
+//!
+//! Therefore, library users should assume that the compile-time checks may not provide accurate
+//! results, and should call [`coap_startup_with_feature_checks()`] during initialization to perform
+//! run-time checks for all requested features. This run-time check will always work and be
+//! accurate.
+//!
+//! Lastly, if you encounter a false positive error (i.e., a compile time error that indicates that
+//! some feature is missing, even though you are 100% certain that it is available), you may bypass
+//! the compile-time checks by setting `LIBCOAP_RS_BYPASS_COMPILE_FEATURE_CHECKS` to any non-zero
+//! value.
+//! Note, however, that this might lead to cryptic errors if your assumption was wrong and the
+//! feature is not available after all.
+//!
+//! In most cases, a false positive might be caused by the include paths/header files used for
+//! binding generation refering to a different version of `libcoap` than the one that is linked
+//! against, which could also cause difficult-to-debug issues and indicates a more severe problem
+//! with the build process.
+//!
+//! [^3]: For this reason, using this method [is noted to be unsafe in `libcoap`'s documentation](https://libcoap.net/doc/reference/4.3.5/man_coap_supported.html).
+//!
+//! ## Vendored Build System
+//!
+//! The vendored build system uses a bundled version of libcoap (usually the latest stable version
+//! at the time of release) to build and statically link against.
+//! Under the hood, it uses the [`autotools`](https://docs.rs/autotools/latest/autotools/) crate to
+//! configure and run the build process, and you may therefore customize the build's compiler and
+//! linker flags by setting the environment variables used in `libcoap`'s `configure` script.
+//!
+//! This build system will enable only those features in `libcoap` that are requested as
+//! `Cargo.toml` features, and will explicitly disable all other ones.
+//!
+//! If a DTLS library is explicitly selected by the user, it will instruct libcoap to link against
+//! that library by setting the corresponding `--with-` configure flag.
+//!
+//! If you enable the `dtls--sys` features and do not set the `_CFLAGS`
+//! or `_LIBS` environment variables, this build system will set these environment
+//! variables to ensure that if this DTLS library is the one that libcoap uses, we link against
+//! exactly the same version as used in the `-sys` crate.
+//! This is especially relevant if those crates also provide a `vendored` version in order to avoid
+//! multiple versions of the same library being in use.
+//! If a different DTLS library is used, this feature should have no effect (it will set the
+//! environment variable, but `libcoap` will ignore it).
+//!
+//! If you do not specify a DTLS library, this build system will follow the same default order that
+//! libcoap does (gnutls > openssl > wolfssl > mbedtls > tinydtls), unless you enabled one of the
+//! `dtls--sys` features, in which case those will have priority.
+//! If multiple of these features are enabled, they are prioritized in the same order as used by
+//! `libcoap` (openssl > mbedtls > tinydtls).
+//!
+//! ## `pkg-config` Build System
+//!
+//! The `pkg-config` build system utilizes the `pkg-config` utility available on most Unix-like
+//! systems to link against a system-provided version of `libcoap`.
+//! To do so, it uses the [`pkg_config`](https://docs.rs/pkg-config/latest/pkg_config/) crate, and
+//! you may therefore customize the build process by setting the environment variables described in
+//! that library's documentation (which may be of special relevance if you try to cross compile).
+//!
+//! By default, it will probe `pkg-config` for a library with the name `libcoap-3`, which will
+//! usually symlink to the DTLS library variant of libcoap that was installed most recently.
+//! If you have explicitly requested use of a specific DTLS library, this build system will attempt
+//! to find the `libcoap-3-` library instead.
+//!
+//! However, library selection does not take into account any other requested features (i.e., it
+//! will not check for feature support before generating the bindings), but will use header-based
+//! compile-time feature checks (see the general section) to ensure support for all required
+//! features after binding generation.
+//!
+//! The `dtls--sys` features have no effect on this build system, but note that static
+//! linking against a system-provided version of `libcoap` may cause issues if it causes multiple
+//! versions of the same DTLS library to be statically linked into the same Rust binary.
+//!
+//! ## `manual` Build System
+//!
+//! This build system is intended as a fallback solution if all other options fail. It will attempt
+//! to generate bindings and link against the version of `libcoap` that is described by the
+//! following environment variables:
+//!
+//! - `LIBCOAP_RS_INCLUDE_DIRS`: Paths that should be added to `clang`'s include path to search for
+//! header files (e.g., `/usr/local/include`, _not_
+//! `/usr/local/include/coap3`). Multiple values are separated by
+//! colons (`:`).
+//! - `LIBCOAP_RS_LIB_DIRS`: Paths that should be added to `rustc`'s library path to search for
+//! object files to link against. Multiple values are separated by
+//! colons (`:`).
+//! - `LIBCOAP_RS_STATIC`: Set to any non-zero and non-empty value to instruct `rustc` to use
+//! static linking instead of dynamic linking for `libcoap`.
+//! - `LIBCOAP_RS_ADDITIONAL_LIBRARIES`: Additional libraries (such as DTLS libraries) that should
+//! be linked against, separated by colons (`:`).
+//! Note that these will be added after `libcoap`, and that the order
+//! in which they are specified matters for most linkers.
+//! You may also request static linking by prepending `static=` to the
+//! library name.
+//!
+//! ## `espidf` Build System
+//!
+//! This build system will be used instead of the regular `vendored` build if you are building for
+//! targets that are based on the `ESP-IDF`.
+//!
+//! If `libcoap-sys` is a direct dependency, it will automatically enable the
+//! [`espressif/coap`](https://components.espressif.com/components/espressif/coap) component in
+//! order to instruct `esp-idf-sys` to compile and link `libcoap` and generate bindings for it.
+//!
+//! If you encounter errors that indicate that the `espressif/coap` component may not be enabled in
+//! the ESP-IDF, this could have the following reasons:
+//! - You may have to run `cargo clean`, as the `esp-idf-sys` build script does not always detect
+//! changes in requested extra components properly.
+//! - `libcoap-sys` is a transient dependency: the `esp-idf-sys` build script
+//! [only considers metadata from the root crate and its direct dependencies](https://docs.esp-rs.org/esp-idf-sys/esp_idf_sys/#extra-esp-idf-components)
+//! to determine which components to install.
+//! In order to solve this, you can either add `libcoap-sys` as a direct dependency, or copy
+//! this crate's `src/wrapper.h` file and add the following snippet to your own `Cargo.toml`.
+//! ```cargo
+//! [[package.metadata.esp-idf-sys.extra_components]]
+//! remote_component = { name = "espressif/coap", version = "4.3.5~3" }
+//! bindings_header = "src/wrapper.h"
+//! ```
+//! Afterward, run `cargo clean` (see the issue mentioned above) and try again.
+//!
+//! It will then parse the generated bindings file and re-export all symbols in `esp-idf-sys` that
+//! are related to `libcoap`.
+//!
+//! Note that `esp-idf-sys` may use a different version of `bindgen` than the other build systems
+//! and that bindings might differ slightly as a result.
+//!
+//! Unlike most other targets, this one will use `esp-idf-sys` instead of `libc` to provide its
+//! standard library types (see the generic information section above).
// Bindgen translates the C headers, clippy's and rustfmt's recommendations are not applicable here.
#![allow(clippy::all)]
#![allow(non_camel_case_types)]
#![allow(deref_nullptr)]
#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
-use std::ffi::c_void;
+use core::ffi::c_void;
-#[allow(unused_imports)]
-use libc::{fd_set, memcmp, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, socklen_t, time_t};
-#[allow(unused_imports)]
+use c_stdlib::{epoll_event, fd_set, memcmp, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, socklen_t, time_t};
+/// Re-export of the crate that provides libc data types used by libcoap.
+///
+/// In most cases, this will be libc, but on the ESP-IDF, it will be esp_idf_sys.
+#[cfg(target_os = "espidf")]
+pub use esp_idf_sys as c_stdlib;
+/// Re-export of the crate that provides libc data types used by libcoap.
+///
+/// In most cases, this will be libc, but on the ESP-IDF, it will be esp_idf_sys.
#[cfg(not(target_os = "espidf"))]
-use libc::epoll_event;
-// use dtls backend libraries in cases where they set our linker flags, otherwise cargo will
-// optimize them out.
+pub use libc as c_stdlib;
+// use dtls backend libraries in cases where they set our linker flags, otherwise rustc will
+// optimize them out, resulting in missing symbols.
#[allow(unused_imports)]
-#[cfg(feature = "dtls_backend_mbedtls_vendored")]
+#[cfg(used_dtls_crate = "mbedtls")]
use mbedtls_sys as _;
#[allow(unused_imports)]
-#[cfg(feature = "dtls_backend_openssl")]
+#[cfg(used_dtls_crate = "openssl")]
use openssl_sys as _;
#[allow(unused_imports)]
-#[cfg(feature = "dtls_backend_tinydtls")]
+#[cfg(used_dtls_crate = "tinydtls")]
use tinydtls_sys as _;
-#[cfg(target_family = "windows")]
-include!(concat!(env!("OUT_DIR"), "\\bindings.rs"));
-#[cfg(not(target_family = "windows"))]
-include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+// Add check whether the libcoap component is enabled when building for the ESP-IDF.
+#[cfg(all(target_os = "espidf", not(esp_idf_comp_espressif__coap_enabled)))]
+compile_error!(concat!(
+ "You are building libcoap-sys for an ESP-IDF target, but have not added the\n",
+ "espressif/coap remote component (see the libcoap-sys documentation for more information)"
+));
-#[inline]
-#[cfg(not(non_inlined_coap_send_rst))]
-pub unsafe fn coap_send_rst(session: *mut coap_session_t, request: *const coap_pdu_t) -> coap_mid_t {
- coap_send_message_type(session, request, crate::coap_pdu_type_t::COAP_MESSAGE_RST)
-}
+include!(env!("BINDINGS_FILE"));
/// Compares instances of coap_str_const_t and/or coap_string_t.
///
@@ -148,145 +375,130 @@ pub unsafe fn coap_string_equal_internal(
&& (str1_len == 0
|| !str1_ptr.is_null()
&& !str2_ptr.is_null()
- && memcmp(str1_ptr as *const c_void, str2_ptr as *const c_void, str1_len) == 0)
+ && memcmp(str1_ptr as *const c_void, str2_ptr as *const c_void, str1_len as _) == 0)
+}
+
+/// Execute feature check function and panic with an error message if the feature is not supported.
+///
+/// SAFETY: check_fn will be called, make sure to wrap this macro in unsafe if the function is
+/// unsafe.
+#[cfg(any(not(target_os = "espidf"), esp_idf_comp_espressif__coap_enabled))]
+macro_rules! feature_check {
+ ($feature:literal, $check_fn:ident) => {
+ #[cfg(feature = $feature)]
+ // SAFETY: Function is always safe to call.
+ if $check_fn() != 1 {
+ panic!("Required feature \"{}\" is not supported by libcoap", $feature)
+ }
+ };
+ ( $(($feature:literal, $check_fn:ident)),* ) => {
+ $(
+ feature_check!($feature, $check_fn);
+ )*
+ }
+}
+
+#[cfg(any(not(target_os = "espidf"), esp_idf_comp_espressif__coap_enabled))]
+macro_rules! dtls_backend_string {
+ ($backend:ident) => {
+ match $backend {
+ coap_tls_library_t_COAP_TLS_LIBRARY_OPENSSL => "openssl",
+ coap_tls_library_t_COAP_TLS_LIBRARY_GNUTLS => "gnutls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_MBEDTLS => "mbedtls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_TINYDTLS => "tinydtls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_WOLFSSL => "wolfssl",
+ coap_tls_library_t_COAP_TLS_LIBRARY_NOTLS => "notls",
+ _ => "unknown",
+ }
+ };
+}
+
+#[cfg(any(not(target_os = "espidf"), esp_idf_comp_espressif__coap_enabled))]
+macro_rules! panic_wrong_dtls {
+ ($presumed_backend:ident, $detected_backend:ident) => {
+ panic!(
+ concat!(
+ "compile-time detected DTLS backend \"{}\" does not match run-time detected DTLS backend \"{}\".\n",
+ "This almost certainly means that libcoap-sys was linked against a different version of \n",
+ "libcoap than the one whose headers were used for binding generation."
+ ),
+ dtls_backend_string!($presumed_backend),
+ dtls_backend_string!($detected_backend)
+ )
+ };
}
/// Initialize the CoAP library and additionally perform runtime checks to ensure that required
-/// features (as enabled in `Cargo.toml`) are available.
+/// features (as enabled in `Cargo.toml`) are available and that the used DTLS library matches the
+/// one that was determined during compile-time.
///
-/// You *should* prefer using this function over [coap_startup], as without calling this function
+/// You *should* prefer using this function over [`coap_startup()`], as without calling this function
/// some of the features enabled using the Cargo features may not actually be available.
-/// (NOTE: However, see the below section on safety).
///
-/// Either this function or [coap_startup] must be run once before any libcoap function is called.
+/// Either this function or [`coap_startup()`] must be run once before any libcoap function is called.
///
/// If you are absolutely 100% certain that all features you require are always available (or are
/// prepared to deal with error return values/different behavior on your own if they aren't), you
-/// may use [coap_startup] instead.
-///
-/// # SAFETY WARNING
-/// In order to preserve backwards compatibility, this method may (for now) skip the feature checks
-/// altogether if they aren't provided by libcoap (which may be the case for libcoap < 4.3.5rc3).
-///
-/// If you want to be absolutely certain that a given feature is available, you *must* also check
-/// the libcoap version to ensure that it is at least 4.3.5rc3.
-///
-/// This behavior will be changed as soon as libcoap 4.3.5 is released, after which libcoap 4.3.5
-/// will become the minimum supported version and these checks will be mandatory.
+/// may use [`coap_startup()`] instead.
+// Make sure that if we're compiling for the ESP-IDF, this function is only compiled if the
+// libcoap component is installed in the ESP-IDF.
+// This way, these function calls will not cause missing function or struct definition errors that
+// clutter up the error log, and the only error message will be the way more descriptive
+// compile_error macro invocation at the start of this file.
+#[cfg(any(not(target_os = "espidf"), esp_idf_comp_espressif__coap_enabled))]
pub fn coap_startup_with_feature_checks() {
- // only compile checks if they are available for the given libcoap version.
- #[cfg(feature_checks_available)]
- {
- #[cfg(feature = "af-unix")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_af_unix_is_supported() != 1 } {
- panic!("Required feature \"af-unix\" is not supported by libcoap")
- }
- #[cfg(feature = "async")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_async_is_supported() != 1 } {
- panic!("Required feature \"async\" is not supported by libcoap")
- }
- #[cfg(feature = "client")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_client_is_supported() != 1 } {
- panic!("Required feature \"ipv4\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_dtls_is_supported() != 1 } {
- panic!("Required feature \"dtls\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls-cid")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_dtls_cid_is_supported() != 1 } {
- panic!("Required feature \"dtls-cid\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls-psk")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_dtls_psk_is_supported() != 1 } {
- panic!("Required feature \"dtls-psk\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls-pki")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_dtls_pki_is_supported() != 1 } {
- panic!("Required feature \"dtls-pki\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls-pkcs11")]
- // SAFETY: Function is always safe to call.
- if !unsafe { coap_dtls_pkcs11_is_supported() == 1 } {
- panic!("Required feature \"dtls-pkcs11\" is not supported by libcoap")
- }
- #[cfg(feature = "dtls-rpk")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_dtls_rpk_is_supported() != 1 } {
- panic!("Required feature \"dtls-rpk\" is not supported by libcoap")
- }
- #[cfg(feature = "epoll")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_epoll_is_supported() != 1 } {
- panic!("Required feature \"epoll\" is not supported by libcoap")
- }
- #[cfg(feature = "ipv4")]
- // SAFETY: Function is always safe to call.
- if !unsafe { coap_ipv4_is_supported() == 1 } {
- panic!("Required feature \"ipv4\" is not supported by libcoap")
- }
- #[cfg(feature = "ipv6")]
- // SAFETY: Function is always safe to call.
- if !unsafe { coap_ipv6_is_supported() == 1 } {
- panic!("Required feature \"ipv6\" is not supported by libcoap")
- }
- #[cfg(feature = "observe-persist")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_observe_persist_is_supported() != 1 } {
- panic!("Required feature \"ipv4\" is not supported by libcoap")
- }
- #[cfg(feature = "oscore")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_oscore_is_supported() != 1 } {
- panic!("Required feature \"oscore\" is not supported by libcoap")
- }
- #[cfg(feature = "q-block")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_q_block_is_supported() != 1 } {
- panic!("Required feature \"q-block\" is not supported by libcoap")
- }
- #[cfg(feature = "server")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_server_is_supported() != 1 } {
- panic!("Required feature \"ipv4\" is not supported by libcoap")
- }
- #[cfg(feature = "tcp")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_tcp_is_supported() != 1 } {
- panic!("Required feature \"tcp\" is not supported by libcoap")
- }
- #[cfg(feature = "thread-safe")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_threadsafe_is_supported() != 1 } {
- panic!("Required feature \"thread-safe\" is not supported by libcoap")
- }
- #[cfg(feature = "tls")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_tls_is_supported() != 1 } {
- panic!("Required feature \"tls\" is not supported by libcoap")
- }
- #[cfg(feature = "websockets")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_ws_is_supported() != 1 } {
- panic!("Required feature \"websockets\" is not supported by libcoap")
- }
- #[cfg(feature = "secure-websockets")]
- // SAFETY: Function is always safe to call.
- if unsafe { coap_wss_is_supported() != 1 } {
- panic!("Required feature \"websockets\" is not supported by libcoap")
- }
+ unsafe {
+ feature_check!(
+ ("af-unix", coap_af_unix_is_supported),
+ ("async", coap_async_is_supported),
+ ("client", coap_client_is_supported),
+ ("dtls", coap_dtls_is_supported),
+ ("dtls-cid", coap_dtls_cid_is_supported),
+ ("dtls-psk", coap_dtls_psk_is_supported),
+ ("dtls-pki", coap_dtls_pki_is_supported),
+ ("dtls-pkcs11", coap_dtls_pkcs11_is_supported),
+ ("dtls-rpk", coap_dtls_rpk_is_supported),
+ ("epoll", coap_epoll_is_supported),
+ ("ipv4", coap_ipv4_is_supported),
+ ("ipv6", coap_ipv6_is_supported),
+ ("observe-persist", coap_observe_persist_is_supported),
+ ("oscore", coap_oscore_is_supported),
+ ("q-block", coap_q_block_is_supported),
+ ("server", coap_server_is_supported),
+ ("tcp", coap_tcp_is_supported),
+ ("thread-safe", coap_threadsafe_is_supported),
+ ("tls", coap_tls_is_supported),
+ ("websockets", coap_ws_is_supported),
+ ("secure-websockets", coap_wss_is_supported)
+ );
}
- #[cfg(not(feature_checks_available))]
+
+ // ESP-IDF is missing the coap_tls_library_t type.
+ #[cfg(not(target_os = "espidf"))]
{
- println!("WARNING: coap_startup_with_feature_checks() could not assert the availability of features because the linked version of libcoap is too old (< 4.3.5rc3)!")
+ let presumed_dtls_backend = if cfg!(dtls_backend = "openssl") {
+ coap_tls_library_t_COAP_TLS_LIBRARY_OPENSSL
+ } else if cfg!(dtls_backend = "gnutls") {
+ coap_tls_library_t_COAP_TLS_LIBRARY_GNUTLS
+ } else if cfg!(dtls_backend = "mbedtls") {
+ coap_tls_library_t_COAP_TLS_LIBRARY_MBEDTLS
+ } else if cfg!(dtls_backend = "tinydtls") {
+ coap_tls_library_t_COAP_TLS_LIBRARY_TINYDTLS
+ } else if cfg!(dtls_backend = "wolfssl") {
+ coap_tls_library_t_COAP_TLS_LIBRARY_WOLFSSL
+ } else {
+ coap_tls_library_t_COAP_TLS_LIBRARY_NOTLS
+ };
+
+ let actual_dtls_backend = unsafe { *coap_get_tls_library_version() }.type_;
+
+ if presumed_dtls_backend != coap_tls_library_t_COAP_TLS_LIBRARY_NOTLS
+ && actual_dtls_backend != presumed_dtls_backend
+ {
+ panic_wrong_dtls!(presumed_dtls_backend, actual_dtls_backend);
+ }
}
+
// SAFETY: Function is always safe to call.
unsafe { coap_startup() }
}
@@ -300,14 +512,7 @@ mod tests {
sync::{Arc, Barrier},
};
- use libc::{AF_INET, AF_INET6, in6_addr, in_addr, sa_family_t, size_t};
-
- use crate::{
- coap_pdu_code_t::{COAP_REQUEST_CODE_GET, COAP_RESPONSE_CODE_CONTENT},
- coap_proto_t::COAP_PROTO_UDP,
- coap_request_t::COAP_REQUEST_GET,
- coap_response_t::COAP_RESPONSE_OK,
- };
+ use libc::{in6_addr, in_addr, sa_family_t, size_t, AF_INET, AF_INET6};
use super::*;
@@ -326,7 +531,7 @@ mod tests {
size: std::mem::size_of::() as socklen_t,
addr: std::mem::zeroed(),
};
- *coap_addr.addr.sin.as_mut() = sockaddr_in {
+ coap_addr.addr.sin = sockaddr_in {
sin_family: AF_INET as sa_family_t,
sin_port: addr.port().to_be(),
sin_addr: in_addr {
@@ -346,7 +551,7 @@ mod tests {
size: std::mem::size_of::() as socklen_t,
addr: std::mem::zeroed(),
};
- *coap_addr.addr.sin6.as_mut() = sockaddr_in6 {
+ coap_addr.addr.sin6 = sockaddr_in6 {
sin6_family: AF_INET6 as sa_family_t,
sin6_port: addr.port().to_be(),
sin6_addr: in6_addr {
@@ -388,7 +593,7 @@ mod tests {
COAP_TEST_RESOURCE_RESPONSE.as_ptr(),
);
coap_set_app_data(coap_session_get_context(session), (&true) as *const bool as *mut c_void);
- coap_pdu_set_code(response_pdu, COAP_RESPONSE_CODE_CONTENT);
+ coap_pdu_set_code(response_pdu, coap_pdu_code_t_COAP_RESPONSE_CODE_CONTENT);
}
/// Response handler for the CoAP client/server test (client-side)
@@ -404,7 +609,7 @@ mod tests {
received: *const coap_pdu_t,
_mid: coap_mid_t,
) -> coap_response_t {
- assert_eq!(coap_pdu_get_code(received), COAP_RESPONSE_CODE_CONTENT);
+ assert_eq!(coap_pdu_get_code(received), coap_pdu_code_t_COAP_RESPONSE_CODE_CONTENT);
let mut len: size_t = 0;
let mut data: *const u8 = std::ptr::null();
assert_ne!(coap_get_data(received, &mut len, &mut data), 0);
@@ -412,7 +617,7 @@ mod tests {
assert_eq!(data, COAP_TEST_RESOURCE_RESPONSE.as_bytes());
coap_set_app_data(coap_session_get_context(session), (&true) as *const bool as *mut c_void);
- return COAP_RESPONSE_OK;
+ return coap_response_t_COAP_RESPONSE_OK;
}
/// Creates a CoAP server that provides a single resource under COAP_TEST_RESOURCE_URI over the
@@ -425,7 +630,7 @@ mod tests {
let address: coap_address_t = coap_address_from_socketaddr(addr);
// SAFETY: We asserted that context != null, listen_addr is a reference and can therefore not be null.
- let endpoint = unsafe { coap_new_endpoint(context, &address, coap_proto_t::COAP_PROTO_UDP) };
+ let endpoint = unsafe { coap_new_endpoint(context, &address, coap_proto_t_COAP_PROTO_UDP) };
assert!(!endpoint.is_null());
// SAFETY: Since we use a string constant here, the arguments to the function are all valid.
@@ -442,7 +647,11 @@ mod tests {
// struct allows for mutable pointers to be set there, so that applications can use this to
// modify some application specific state.
unsafe {
- coap_register_request_handler(test_resource, COAP_REQUEST_GET, Some(test_resource_handler));
+ coap_register_request_handler(
+ test_resource,
+ coap_request_t_COAP_REQUEST_GET,
+ Some(test_resource_handler),
+ );
coap_add_resource(context, test_resource);
coap_set_app_data(context, (&false) as *const bool as *mut c_void);
}
@@ -471,6 +680,7 @@ mod tests {
/// Test case that creates a basic coap server and makes a request to it from a separate context
#[test]
fn test_coap_client_server_basic() {
+ coap_startup_with_feature_checks();
// This will give us a SocketAddress with a port in the local port range automatically
// assigned by the operating system.
// Because the UdpSocket goes out of scope, the Port will be free for usage by libcoap.
@@ -504,7 +714,7 @@ mod tests {
// SAFETY: null pointer is valid argument for local_if, server_address is guaranteed to be
// a correct value (conversion cannot fail), validity of context was asserted before.
let client_session =
- unsafe { coap_new_client_session(context, std::ptr::null(), &server_address, COAP_PROTO_UDP) };
+ unsafe { coap_new_client_session(context, std::ptr::null(), &server_address, coap_proto_t_COAP_PROTO_UDP) };
// SAFETY: context and client_session were asserted to be valid.
// Casting *const to *mut is fine because we don't mutate the value pointed to and the
@@ -515,8 +725,11 @@ mod tests {
unsafe {
coap_register_response_handler(context, Some(test_response_handler));
coap_set_app_data(context, (&false) as *const bool as *mut c_void);
- let coap_request_pdu =
- coap_new_pdu(coap_pdu_type_t::COAP_MESSAGE_NON, COAP_REQUEST_CODE_GET, client_session);
+ let coap_request_pdu = coap_new_pdu(
+ coap_pdu_type_t_COAP_MESSAGE_NON,
+ coap_pdu_code_t_COAP_REQUEST_CODE_GET,
+ client_session,
+ );
assert!(!coap_request_pdu.is_null());
assert_ne!(
coap_add_option(
diff --git a/libcoap/Cargo.toml b/libcoap/Cargo.toml
index 0949d459..189bfaa5 100644
--- a/libcoap/Cargo.toml
+++ b/libcoap/Cargo.toml
@@ -16,29 +16,30 @@ authors = ["Hugo Hakim Damer "]
categories = ["api-bindings", "network-programming", "embedded"]
keywords = ["coap", "libcoap"]
resolver = "2"
-# Current reason for MSRV (please update when increasing MSRV): Transient dependency "home" requires Rust 1.81.
-rust-version = "1.81.0"
+# Current reason for MSRV (please update when increasing MSRV): bindgen generates unsafe extern "C" blocks, which are
+# not supported on Rust < 1.82, and Rust < 1.84 is not MSRV aware, so we can't just increase libcoap-sys's MSRV.
+# See also: https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html
+rust-version = "1.82.0"
[features]
-default = ["dtls-psk", "tcp", "dtls_openssl", "vendored", "libcoap-sys/default"]
-dtls_tinydtls = ["libcoap-sys/dtls_backend_tinydtls"]
-dtls_tinydtls_vendored = ["dtls_tinydtls", "libcoap-sys/dtls_backend_tinydtls_vendored"]
-dtls_openssl = ["libcoap-sys/dtls_backend_openssl"]
-dtls_openssl_vendored = ["dtls_openssl", "libcoap-sys/dtls_backend_openssl_vendored"]
-dtls_gnutls = ["libcoap-sys/dtls_backend_gnutls"]
-dtls_mbedtls = ["libcoap-sys/dtls_backend_mbedtls"]
-dtls_mbedtls_vendored = ["dtls_mbedtls", "libcoap-sys/dtls_backend_mbedtls_vendored"]
-dtls-psk = ["libcoap-sys/dtls", "libcoap-sys/dtls-psk"]
-dtls-pki = ["libcoap-sys/dtls", "libcoap-sys/dtls-pki"]
-dtls-rpk = ["libcoap-sys/dtls", "libcoap-sys/dtls-rpk"]
+default = ["dtls-psk", "tcp"]
+dtls = ["libcoap-sys/dtls"]
+dtls-psk = ["dtls", "libcoap-sys/dtls-psk"]
+dtls-pki = ["dtls", "libcoap-sys/dtls-pki"]
+dtls-rpk = ["dtls", "libcoap-sys/dtls-rpk"]
+dtls-cid = ["dtls-psk", "libcoap-sys/dtls-cid"]
tcp = ["libcoap-sys/tcp"]
tls = ["libcoap-sys/tls"]
rand = ["dep:rand", "dep:rand_core"]
vendored = ["libcoap-sys/vendored"]
+dtls-openssl-sys = ["libcoap-sys/dtls-openssl-sys"]
+dtls-mbedtls-sys = ["libcoap-sys/dtls-mbedtls-sys"]
+dtls-tinydtls-sys = ["libcoap-sys/dtls-tinydtls-sys"]
+dtls-openssl-sys-vendored = ["libcoap-sys/dtls-openssl-sys-vendored"]
+dtls-tinydtls-sys-vendored = ["libcoap-sys/dtls-tinydtls-sys-vendored"]
[dependencies]
libcoap-sys = { version = "^0.2.2", path = "../libcoap-sys", default-features = false, features = ["client", "server"] }
-libc = { version = "^0.2.95" }
num-derive = { version = "^0.3.3" }
num-traits = { version = "^0.2.14" }
url = { version = "^2.2", optional = true }
@@ -48,6 +49,18 @@ thiserror = "^1.0"
[build-dependencies]
version-compare = "0.2.0"
+anyhow = "1.0.95"
[package.metadata.docs.rs]
features = ["dtls", "dtls_openssl", "vendored", "url"]
+
+[target.'cfg(target_os="espidf")'.dependencies]
+esp-idf-sys = { version = "0.36.1" }
+
+# For ESP-IDF builds, we need to add the espressif/coap component ourselves here,
+# as esp-idf-sys only inspects the metadata for direct dependencies.
+# Otherwise, users of this library would always also have to depend on libcoap-sys
+# or add this snippet themselves.
+[[package.metadata.esp-idf-sys.extra_components]]
+remote_component = { name = "espressif/coap", version = "4.3.5~3" }
+bindings_header = "src/wrapper.h"
diff --git a/libcoap/build.rs b/libcoap/build.rs
index 22c63928..0f883095 100644
--- a/libcoap/build.rs
+++ b/libcoap/build.rs
@@ -1,32 +1,69 @@
// SPDX-License-Identifier: BSD-2-CLAUSE
-use version_compare::{Cmp, Version};
-
-fn main() {
- println!("cargo::rustc-check-cfg=cfg(dtls_ec_jpake_support)");
- println!("cargo::rustc-check-cfg=cfg(dtls_cid_support)");
- println!("cargo::rustc-check-cfg=cfg(coap_uri_buf_unused)");
- println!("cargo::rustc-check-cfg=cfg(dtls)");
- if let Ok(libcoap_version) = std::env::var("DEP_COAP_3_LIBCOAP_VERSION") {
- let version = Version::from(libcoap_version.as_ref()).expect("invalid libcoap version");
- // libcoap >= 4.3.5rc2 no longer uses the buf and buflen parameters in
- // coap_uri_into_options(), so we can optimize them out and save some memory.
- match version.compare(Version::from("4.3.5rc2").unwrap()) {
- Cmp::Gt | Cmp::Eq => {
- println!("cargo:rustc-cfg=coap_uri_buf_unused");
- },
- _ => {},
- }
- // libcoap >= 4.3.5rc3 supports DTLS EC JPAKE and connection ID extensions, which adds
- // additional fields to some DTLS configuration structs.
- match version.compare(Version::from("4.3.5rc3").unwrap()) {
- Cmp::Gt | Cmp::Eq => {
- println!("cargo:rustc-cfg=dtls_ec_jpake_support");
- println!("cargo:rustc-cfg=dtls_cid_support");
- },
- _ => {},
- }
+use std::env::VarError;
+
+use anyhow::{bail, Result};
+use version_compare::Version;
+
+/// The minimal version of libcoap that is expected to work with libcoap-rs.
+///
+/// Does not necessarily match the minimum supported version of libcoap-sys, and should be increased
+/// whenever we make changes to the safe wrapper that can not feasibly be supported on older
+/// versions of libcoap.
+const MINIMUM_LIBCOAP_VERSION: &str = "4.3.5";
+
+fn main() -> Result<()> {
+ println!("cargo::rustc-check-cfg=cfg(dtls_backend, values(\"gnutls\", \"mbedtls\", \"tinydtls\", \"openssl\", \"wolfssl\"))");
+ println!("cargo::rustc-check-cfg=cfg(libcoap_version, values(any()))");
+
+ // If at all possible, you should not write code that is conditional on the DTLS backend (use
+ // cargo features instead).
+ // If there is no other way (e.g., if there is no way to determine feature support), you must
+ // at least write code that can also deal with the variable not being there.
+ match std::env::var("DEP_COAP_3_DTLS_BACKEND") {
+ Ok(dtls_backend) => {
+ println!("cargo::rustc-cfg=dtls_backend=\"{}\"", dtls_backend)
+ },
+ Err(VarError::NotUnicode(_)) => {
+ panic!("DEP_COAP_3_DTLS_BACKEND is not valid unicode")
+ },
+ Err(VarError::NotPresent) => {},
}
- #[cfg(any(feature = "dtls-pki", feature = "dtls-rpk", feature = "dtls-psk"))]
- println!("cargo:rustc-cfg=dtls")
+
+ match std::env::var("DEP_COAP_3_LIBCOAP_VERSION") {
+ Ok(libcoap_version) => {
+ let version = Version::from(libcoap_version.as_ref()).expect("invalid libcoap version");
+ println!("cargo::rustc-cfg=libcoap_version=\"{}\"", version.as_str());
+
+ if version < Version::from(MINIMUM_LIBCOAP_VERSION).unwrap() {
+ // Unlike libcoap-sys, we do return an error here and not just a warning, as
+ // unsupported libcoap versions might have semantic differences that break the
+ // safety guarantees this wrapper is supposed to provide.
+
+ bail!("The linked version of libcoap is lower than the minimal version required for libcoap-rs ({}), can not build.", MINIMUM_LIBCOAP_VERSION);
+ }
+
+ // Uncomment and adjust this in order to create version-dependent cfg-flags.
+ // When updating the minimum supported libcoap version, one should also remove all
+ // cfg-flags that are only relevant for versions lower than the new minimum
+ // supported one, and rewrite code gated on these flags to assume that the minimum
+ // version .
+ // Note: In most cases, you probably want to check for the presence of a given feature instead.
+ // Matching based on the libcoap version usually only makes sense in order to either
+ // enable optional optimizations possible with newer versions, or to add struct fields
+ // that were added into existing structs without breaking backward compatibility.
+
+ /*if version > Version::from("4.3.5").unwrap() {
+ println!("cargo:rustc-cfg=[INSERT FLAG NAME HERE]")
+ }*/
+ },
+ Err(VarError::NotUnicode(_)) => {
+ panic!("DEP_COAP_3_LIBCOAP_VERSION is not valid unicode")
+ },
+ Err(VarError::NotPresent) => {
+ println!("cargo:warning=Unable to automatically detect the linked version of libcoap, please manually ensure that the used version is at least {} for libcoap-rs to work as expected.", MINIMUM_LIBCOAP_VERSION);
+ },
+ }
+
+ Ok(())
}
diff --git a/libcoap/examples/esp-idf/.cargo/config.toml b/libcoap/examples/esp-idf/.cargo/config.toml
new file mode 100644
index 00000000..11494290
--- /dev/null
+++ b/libcoap/examples/esp-idf/.cargo/config.toml
@@ -0,0 +1,16 @@
+[build]
+target = "riscv32imc-esp-espidf"
+
+[target.riscv32imc-esp-espidf]
+linker = "ldproxy"
+runner = "espflash flash --monitor"
+rustflags = [ "--cfg", "espidf_time64"]
+
+[unstable]
+build-std = ["std", "panic_abort"]
+
+[env]
+MCU="esp32c3"
+# Note: this variable is not used by the pio builder (`cargo build --features pio`)
+ESP_IDF_VERSION = "v5.2.3"
+
diff --git a/libcoap/examples/esp-idf/.github/workflows/rust_ci.yml b/libcoap/examples/esp-idf/.github/workflows/rust_ci.yml
new file mode 100644
index 00000000..e7e9b1ec
--- /dev/null
+++ b/libcoap/examples/esp-idf/.github/workflows/rust_ci.yml
@@ -0,0 +1,41 @@
+name: Continuous Integration
+
+on:
+ push:
+ paths-ignore:
+ - "**/README.md"
+ pull_request:
+ workflow_dispatch:
+
+env:
+ CARGO_TERM_COLOR: always
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+jobs:
+ rust-checks:
+ name: Rust Checks
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ action:
+ - command: build
+ args: --release
+ - command: fmt
+ args: --all -- --check --color always
+ - command: clippy
+ args: --all-targets --all-features --workspace -- -D warnings
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Setup Rust
+ uses: dtolnay/rust-toolchain@v1
+ with:
+ toolchain: nightly
+ components: rust-src rustfmt clippy
+ - name: Enable caching
+ uses: Swatinem/rust-cache@v2
+ - name: Install ldproxy
+ run: cargo install ldproxy
+ - name: Run command
+ run: cargo ${{ matrix.action.command }} ${{ matrix.action.args }}
diff --git a/libcoap/examples/esp-idf/.gitignore b/libcoap/examples/esp-idf/.gitignore
new file mode 100644
index 00000000..aa1d4bf7
--- /dev/null
+++ b/libcoap/examples/esp-idf/.gitignore
@@ -0,0 +1,5 @@
+/.vscode
+/.embuild
+/target
+/Cargo.lock
+/vars.log
\ No newline at end of file
diff --git a/libcoap/examples/esp-idf/Cargo.toml b/libcoap/examples/esp-idf/Cargo.toml
new file mode 100644
index 00000000..92046ac0
--- /dev/null
+++ b/libcoap/examples/esp-idf/Cargo.toml
@@ -0,0 +1,34 @@
+[package]
+name = "libcoap-esp-idf-example"
+version = "0.1.0"
+authors = ["Hugo Hakim Damer "]
+edition = "2021"
+resolver = "2"
+rust-version = "1.77"
+
+[[bin]]
+name = "libcoap-esp-idf-example"
+harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors
+
+[profile.release]
+opt-level = "s"
+
+[profile.dev]
+debug = true # Symbols are nice and they don't increase the size on Flash
+opt-level = "z"
+
+[features]
+default = []
+
+experimental = ["esp-idf-svc/experimental"]
+
+[dependencies]
+log = "0.4"
+esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] }
+esp-idf-sys = { version = "0.36.1" }
+libcoap-rs = { version = "*", path = "../../" }
+
+[build-dependencies]
+embuild = "0.33"
+
+[workspace]
diff --git a/libcoap/examples/esp-idf/README.md b/libcoap/examples/esp-idf/README.md
new file mode 100644
index 00000000..ba3f678b
--- /dev/null
+++ b/libcoap/examples/esp-idf/README.md
@@ -0,0 +1,6 @@
+This folder contains a slightly modified version of the ESP-IDF Rust project template that can be found
+[here](https://github.com/esp-rs/esp-idf-template/tree/master/cargo), with slight modifications to
+`sdkconfig.defaults`, `Cargo.toml` and `main.rs` to add support for `libcoap-sys` and `libcoap-rs`.
+
+It is mainly used to test the compilation and binding generation process for ESP-IDF builds of `libcoap-rs`,
+but you may also use it as a reference for your own projects.
\ No newline at end of file
diff --git a/libcoap/examples/esp-idf/build.rs b/libcoap/examples/esp-idf/build.rs
new file mode 100644
index 00000000..112ec3f7
--- /dev/null
+++ b/libcoap/examples/esp-idf/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+ embuild::espidf::sysenv::output();
+}
diff --git a/libcoap/examples/esp-idf/components_esp32c3.lock b/libcoap/examples/esp-idf/components_esp32c3.lock
new file mode 100644
index 00000000..b6391610
--- /dev/null
+++ b/libcoap/examples/esp-idf/components_esp32c3.lock
@@ -0,0 +1,20 @@
+dependencies:
+ espressif/coap:
+ component_hash: a5d1b781b15980d9af136b5e63315dd5f5ec00215cc755f395ad2fb4977c7668
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.4'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 4.3.5~3
+ idf:
+ source:
+ type: idf
+ version: 5.2.3
+direct_dependencies:
+- espressif/coap
+manifest_hash: 13fcf89b865b0f073a765a0dfdcf062a0063b4af7a631d3d37ef94c920538a25
+target: esp32c3
+version: 2.0.0
diff --git a/libcoap/examples/esp-idf/rust-toolchain.toml b/libcoap/examples/esp-idf/rust-toolchain.toml
new file mode 100644
index 00000000..f70d2254
--- /dev/null
+++ b/libcoap/examples/esp-idf/rust-toolchain.toml
@@ -0,0 +1,3 @@
+[toolchain]
+channel = "nightly"
+components = ["rust-src"]
diff --git a/libcoap/examples/esp-idf/sdkconfig.defaults b/libcoap/examples/esp-idf/sdkconfig.defaults
new file mode 100644
index 00000000..1c2bfab4
--- /dev/null
+++ b/libcoap/examples/esp-idf/sdkconfig.defaults
@@ -0,0 +1,21 @@
+# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000
+
+# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
+# This allows to use 1 ms granularity for thread sleeps (10 ms by default).
+#CONFIG_FREERTOS_HZ=1000
+
+# Workaround for https://github.com/espressif/esp-idf/issues/7631
+#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
+#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
+
+CONFIG_COAP_CLIENT_SUPPORT=y
+CONFIG_COAP_SERVER_SUPPORT=y
+CONFIG_COAP_TCP_SUPPORT=y
+CONFIG_COAP_OSCORE_SUPPORT=y
+CONFIG_COAP_Q_BLOCK=y
+CONFIG_COAP_SERVER_SUPPORT=y
+CONFIG_COAP_THREAD_RECURSIVE_CHECK=y
+CONFIG_COAP_THREAD_SAFE=y
+CONFIG_COAP_OBSERVE_PERSIST=y
+CONFIG_COAP_WEBSOCKETS=y
diff --git a/libcoap/examples/esp-idf/src/main.rs b/libcoap/examples/esp-idf/src/main.rs
new file mode 100644
index 00000000..c5f1bcc6
--- /dev/null
+++ b/libcoap/examples/esp-idf/src/main.rs
@@ -0,0 +1,14 @@
+use libcoap_rs::CoapContext;
+
+fn main() {
+ // It is necessary to call this function once. Otherwise some patches to the runtime
+ // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
+ esp_idf_svc::sys::link_patches();
+
+ // Bind the log crate to the ESP Logging facilities
+ esp_idf_svc::log::EspLogger::initialize_default();
+
+ log::info!("Hello, world!");
+
+ let context = CoapContext::new().unwrap();
+}
diff --git a/libcoap/examples/esp-idf/vars.log b/libcoap/examples/esp-idf/vars.log
new file mode 100644
index 00000000..e69de29b
diff --git a/libcoap/src/context.rs b/libcoap/src/context.rs
index c8be5ec1..ee6e2c01 100644
--- a/libcoap/src/context.rs
+++ b/libcoap/src/context.rs
@@ -9,15 +9,15 @@
//! Module containing context-internal types and traits.
+use core::ffi::c_uint;
#[cfg(feature = "dtls-pki")]
use std::ffi::CString;
-#[cfg(dtls)]
+#[cfg(feature = "dtls")]
use std::ptr::NonNull;
use std::{any::Any, ffi::c_void, fmt::Debug, net::SocketAddr, ops::Sub, sync::Once, time::Duration};
#[cfg(all(feature = "dtls-pki", unix))]
use std::{os::unix::ffi::OsStrExt, path::Path};
-use libc::c_uint;
#[cfg(feature = "dtls-pki")]
use libcoap_sys::coap_context_set_pki_root_cas;
use libcoap_sys::{
@@ -25,9 +25,22 @@ use libcoap_sys::{
coap_context_get_max_handshake_sessions, coap_context_get_max_idle_sessions, coap_context_get_session_timeout,
coap_context_set_block_mode, coap_context_set_csm_max_message_size, coap_context_set_csm_timeout,
coap_context_set_keepalive, coap_context_set_max_handshake_sessions, coap_context_set_max_idle_sessions,
- coap_context_set_session_timeout, coap_context_t, coap_event_t, coap_free_context, coap_get_app_data,
- coap_io_process, coap_new_context, coap_proto_t, coap_register_event_handler, coap_register_response_handler,
- coap_set_app_data, coap_startup_with_feature_checks, COAP_BLOCK_SINGLE_BODY, COAP_BLOCK_USE_LIBCOAP, COAP_IO_WAIT,
+ coap_context_set_session_timeout, coap_context_t, coap_event_t, coap_event_t_COAP_EVENT_BAD_PACKET,
+ coap_event_t_COAP_EVENT_DTLS_CLOSED, coap_event_t_COAP_EVENT_DTLS_CONNECTED, coap_event_t_COAP_EVENT_DTLS_ERROR,
+ coap_event_t_COAP_EVENT_DTLS_RENEGOTIATE, coap_event_t_COAP_EVENT_KEEPALIVE_FAILURE,
+ coap_event_t_COAP_EVENT_MSG_RETRANSMITTED, coap_event_t_COAP_EVENT_OSCORE_DECODE_ERROR,
+ coap_event_t_COAP_EVENT_OSCORE_DECRYPTION_FAILURE, coap_event_t_COAP_EVENT_OSCORE_INTERNAL_ERROR,
+ coap_event_t_COAP_EVENT_OSCORE_NOT_ENABLED, coap_event_t_COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD,
+ coap_event_t_COAP_EVENT_OSCORE_NO_SECURITY, coap_event_t_COAP_EVENT_PARTIAL_BLOCK,
+ coap_event_t_COAP_EVENT_SERVER_SESSION_DEL, coap_event_t_COAP_EVENT_SERVER_SESSION_NEW,
+ coap_event_t_COAP_EVENT_SESSION_CLOSED, coap_event_t_COAP_EVENT_SESSION_CONNECTED,
+ coap_event_t_COAP_EVENT_SESSION_FAILED, coap_event_t_COAP_EVENT_TCP_CLOSED, coap_event_t_COAP_EVENT_TCP_CONNECTED,
+ coap_event_t_COAP_EVENT_TCP_FAILED, coap_event_t_COAP_EVENT_WS_CLOSED, coap_event_t_COAP_EVENT_WS_CONNECTED,
+ coap_event_t_COAP_EVENT_WS_PACKET_SIZE, coap_event_t_COAP_EVENT_XMIT_BLOCK_FAIL, coap_free_context,
+ coap_get_app_data, coap_io_process, coap_new_context, coap_proto_t, coap_proto_t_COAP_PROTO_DTLS,
+ coap_proto_t_COAP_PROTO_TCP, coap_proto_t_COAP_PROTO_UDP, coap_register_event_handler,
+ coap_register_response_handler, coap_set_app_data, coap_startup_with_feature_checks, COAP_BLOCK_SINGLE_BODY,
+ COAP_BLOCK_USE_LIBCOAP, COAP_IO_WAIT,
};
#[cfg(any(feature = "dtls-rpk", feature = "dtls-pki"))]
@@ -148,49 +161,52 @@ impl<'a> CoapContext<'a> {
let inner_ref = &mut *self.inner.borrow_mut();
// Call event handler for event.
if let Some(handler) = &mut inner_ref.event_handler {
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match event {
- coap_event_t::COAP_EVENT_DTLS_CLOSED => handler.handle_dtls_closed(&mut session),
- coap_event_t::COAP_EVENT_DTLS_CONNECTED => handler.handle_dtls_connected(&mut session),
- coap_event_t::COAP_EVENT_DTLS_RENEGOTIATE => handler.handle_dtls_renegotiate(&mut session),
- coap_event_t::COAP_EVENT_DTLS_ERROR => handler.handle_dtls_error(&mut session),
- coap_event_t::COAP_EVENT_TCP_CONNECTED => handler.handle_tcp_connected(&mut session),
- coap_event_t::COAP_EVENT_TCP_CLOSED => handler.handle_tcp_closed(&mut session),
- coap_event_t::COAP_EVENT_TCP_FAILED => handler.handle_tcp_failed(&mut session),
- coap_event_t::COAP_EVENT_SESSION_CONNECTED => handler.handle_session_connected(&mut session),
- coap_event_t::COAP_EVENT_SESSION_CLOSED => handler.handle_session_closed(&mut session),
- coap_event_t::COAP_EVENT_SESSION_FAILED => handler.handle_session_failed(&mut session),
- coap_event_t::COAP_EVENT_PARTIAL_BLOCK => handler.handle_partial_block(&mut session),
- coap_event_t::COAP_EVENT_SERVER_SESSION_NEW => {
+ coap_event_t_COAP_EVENT_DTLS_CLOSED => handler.handle_dtls_closed(&mut session),
+ coap_event_t_COAP_EVENT_DTLS_CONNECTED => handler.handle_dtls_connected(&mut session),
+ coap_event_t_COAP_EVENT_DTLS_RENEGOTIATE => handler.handle_dtls_renegotiate(&mut session),
+ coap_event_t_COAP_EVENT_DTLS_ERROR => handler.handle_dtls_error(&mut session),
+ coap_event_t_COAP_EVENT_TCP_CONNECTED => handler.handle_tcp_connected(&mut session),
+ coap_event_t_COAP_EVENT_TCP_CLOSED => handler.handle_tcp_closed(&mut session),
+ coap_event_t_COAP_EVENT_TCP_FAILED => handler.handle_tcp_failed(&mut session),
+ coap_event_t_COAP_EVENT_SESSION_CONNECTED => handler.handle_session_connected(&mut session),
+ coap_event_t_COAP_EVENT_SESSION_CLOSED => handler.handle_session_closed(&mut session),
+ coap_event_t_COAP_EVENT_SESSION_FAILED => handler.handle_session_failed(&mut session),
+ coap_event_t_COAP_EVENT_PARTIAL_BLOCK => handler.handle_partial_block(&mut session),
+ coap_event_t_COAP_EVENT_SERVER_SESSION_NEW => {
if let CoapSession::Server(server_session) = &mut session {
handler.handle_server_session_new(server_session)
} else {
panic!("server-side session event fired for non-server-side session");
}
},
- coap_event_t::COAP_EVENT_SERVER_SESSION_DEL => {
+ coap_event_t_COAP_EVENT_SERVER_SESSION_DEL => {
if let CoapSession::Server(server_session) = &mut session {
handler.handle_server_session_del(server_session)
} else {
panic!("server-side session event fired for non-server-side session");
}
},
- coap_event_t::COAP_EVENT_XMIT_BLOCK_FAIL => handler.handle_xmit_block_fail(&mut session),
- coap_event_t::COAP_EVENT_BAD_PACKET => handler.handle_bad_packet(&mut session),
- coap_event_t::COAP_EVENT_MSG_RETRANSMITTED => handler.handle_msg_retransmitted(&mut session),
- coap_event_t::COAP_EVENT_OSCORE_DECRYPTION_FAILURE => {
+ coap_event_t_COAP_EVENT_XMIT_BLOCK_FAIL => handler.handle_xmit_block_fail(&mut session),
+ coap_event_t_COAP_EVENT_BAD_PACKET => handler.handle_bad_packet(&mut session),
+ coap_event_t_COAP_EVENT_MSG_RETRANSMITTED => handler.handle_msg_retransmitted(&mut session),
+ coap_event_t_COAP_EVENT_OSCORE_DECRYPTION_FAILURE => {
handler.handle_oscore_decryption_failure(&mut session)
},
- coap_event_t::COAP_EVENT_OSCORE_NOT_ENABLED => handler.handle_oscore_not_enabled(&mut session),
- coap_event_t::COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD => {
+ coap_event_t_COAP_EVENT_OSCORE_NOT_ENABLED => handler.handle_oscore_not_enabled(&mut session),
+ coap_event_t_COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD => {
handler.handle_oscore_no_protected_payload(&mut session)
},
- coap_event_t::COAP_EVENT_OSCORE_NO_SECURITY => handler.handle_oscore_no_security(&mut session),
- coap_event_t::COAP_EVENT_OSCORE_INTERNAL_ERROR => handler.handle_oscore_internal_error(&mut session),
- coap_event_t::COAP_EVENT_OSCORE_DECODE_ERROR => handler.handle_oscore_decode_error(&mut session),
- coap_event_t::COAP_EVENT_WS_PACKET_SIZE => handler.handle_ws_packet_size(&mut session),
- coap_event_t::COAP_EVENT_WS_CONNECTED => handler.handle_ws_connected(&mut session),
- coap_event_t::COAP_EVENT_WS_CLOSED => handler.handle_ws_closed(&mut session),
- coap_event_t::COAP_EVENT_KEEPALIVE_FAILURE => handler.handle_keepalive_failure(&mut session),
+ coap_event_t_COAP_EVENT_OSCORE_NO_SECURITY => handler.handle_oscore_no_security(&mut session),
+ coap_event_t_COAP_EVENT_OSCORE_INTERNAL_ERROR => handler.handle_oscore_internal_error(&mut session),
+ coap_event_t_COAP_EVENT_OSCORE_DECODE_ERROR => handler.handle_oscore_decode_error(&mut session),
+ coap_event_t_COAP_EVENT_WS_PACKET_SIZE => handler.handle_ws_packet_size(&mut session),
+ coap_event_t_COAP_EVENT_WS_CONNECTED => handler.handle_ws_connected(&mut session),
+ coap_event_t_COAP_EVENT_WS_CLOSED => handler.handle_ws_closed(&mut session),
+ coap_event_t_COAP_EVENT_KEEPALIVE_FAILURE => handler.handle_keepalive_failure(&mut session),
_ => {
// TODO probably a log message is justified here.
},
@@ -198,9 +214,12 @@ impl<'a> CoapContext<'a> {
}
// For server-side sessions: Ensure that server-side session wrappers are either kept in memory or dropped when needed.
if let CoapSession::Server(serv_sess) = session {
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match event {
- coap_event_t::COAP_EVENT_SERVER_SESSION_NEW => inner_ref.server_sessions.push(serv_sess),
- coap_event_t::COAP_EVENT_SERVER_SESSION_DEL => {
+ coap_event_t_COAP_EVENT_SERVER_SESSION_NEW => inner_ref.server_sessions.push(serv_sess),
+ coap_event_t_COAP_EVENT_SERVER_SESSION_DEL => {
std::mem::drop(inner_ref.server_sessions.remove(
inner_ref.server_sessions.iter().position(|v| v.eq(&serv_sess)).expect(
"attempted to remove session wrapper from context that was never associated with it",
@@ -369,29 +388,29 @@ impl CoapContext<'_> {
/// Creates a new UDP endpoint that is bound to the given address.
pub fn add_endpoint_udp(&mut self, addr: SocketAddr) -> Result<(), EndpointCreationError> {
- self.add_endpoint(addr, coap_proto_t::COAP_PROTO_UDP)
+ self.add_endpoint(addr, coap_proto_t_COAP_PROTO_UDP)
}
/// Creates a new TCP endpoint that is bound to the given address.
#[cfg(feature = "tcp")]
pub fn add_endpoint_tcp(&mut self, addr: SocketAddr) -> Result<(), EndpointCreationError> {
- self.add_endpoint(addr, coap_proto_t::COAP_PROTO_TCP)
+ self.add_endpoint(addr, coap_proto_t_COAP_PROTO_TCP)
}
/// Creates a new DTLS endpoint that is bound to the given address.
///
/// Note that in order to actually connect to DTLS clients, you need to set a crypto provider
/// using [CoapContext::set_psk_context] and/or [CoapContext::set_pki_rpk_context].
- #[cfg(dtls)]
+ #[cfg(feature = "dtls")]
pub fn add_endpoint_dtls(&mut self, addr: SocketAddr) -> Result<(), EndpointCreationError> {
- self.add_endpoint(addr, coap_proto_t::COAP_PROTO_DTLS)
+ self.add_endpoint(addr, coap_proto_t_COAP_PROTO_DTLS)
}
// /// TODO
// #[cfg(all(feature = "tcp", dtls))]
// pub fn add_endpoint_tls(&mut self, _addr: SocketAddr) -> Result<(), EndpointCreationError> {
// todo!()
- // // TODO: self.add_endpoint(addr, coap_proto_t::COAP_PROTO_TLS)
+ // // TODO: self.add_endpoint(addr, coap_proto_t_COAP_PROTO_TLS)
// }
/// Adds the given resource to the resource pool of this context.
diff --git a/libcoap/src/crypto/pki_rpk/key.rs b/libcoap/src/crypto/pki_rpk/key.rs
index 036200d5..acdc20c0 100644
--- a/libcoap/src/crypto/pki_rpk/key.rs
+++ b/libcoap/src/crypto/pki_rpk/key.rs
@@ -7,16 +7,23 @@
* See the README as well as the LICENSE file for more information.
*/
+#[cfg(unix)]
+use std::os::unix::ffi::OsStrExt;
+use std::{ffi::CString, fmt::Debug, path::Path};
+
use libcoap_sys::{
- coap_asn1_privatekey_type_t, coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_pki_t, coap_pki_define_t,
+ coap_asn1_privatekey_type_t, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
+ coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2, coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
+ coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_pki_t, coap_pki_define_t,
};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
-use std::ffi::CString;
-use std::fmt::Debug;
-#[cfg(unix)]
-use std::os::unix::ffi::OsStrExt;
-use std::path::Path;
/// Trait for marker structs that describe different types of asymmetric DTLS keys (RPK or PKI).
#[allow(private_bounds)]
@@ -210,41 +217,41 @@ impl> From for EngineKeyComponent {
#[derive(Copy, Clone, FromPrimitive, Debug, PartialEq, Eq, Hash, Default)]
pub enum Asn1PrivateKeyType {
#[default]
- None = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_NONE as isize,
- Rsa = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA as isize,
- Rsa2 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA2 as isize,
- Dsa = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA as isize,
- Dsa1 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA1 as isize,
- Dsa2 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA2 as isize,
- Dsa3 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA3 as isize,
- Dsa4 = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA4 as isize,
- Dh = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DH as isize,
- Dhx = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DHX as isize,
- Ec = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_EC as isize,
- Hmac = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HMAC as isize,
- Cmac = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_CMAC as isize,
- Tls1Prf = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_TLS1_PRF as isize,
- Hkdf = coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HKDF as isize,
+ None = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE as isize,
+ Rsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA as isize,
+ Rsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2 as isize,
+ Dsa = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA as isize,
+ Dsa1 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1 as isize,
+ Dsa2 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2 as isize,
+ Dsa3 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3 as isize,
+ Dsa4 = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4 as isize,
+ Dh = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH as isize,
+ Dhx = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX as isize,
+ Ec = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC as isize,
+ Hmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC as isize,
+ Cmac = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC as isize,
+ Tls1Prf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF as isize,
+ Hkdf = coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF as isize,
}
impl From for coap_asn1_privatekey_type_t {
fn from(value: Asn1PrivateKeyType) -> Self {
match value {
- Asn1PrivateKeyType::None => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_NONE,
- Asn1PrivateKeyType::Rsa => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA,
- Asn1PrivateKeyType::Rsa2 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_RSA2,
- Asn1PrivateKeyType::Dsa => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA,
- Asn1PrivateKeyType::Dsa1 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA1,
- Asn1PrivateKeyType::Dsa2 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA2,
- Asn1PrivateKeyType::Dsa3 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA3,
- Asn1PrivateKeyType::Dsa4 => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DSA4,
- Asn1PrivateKeyType::Dh => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DH,
- Asn1PrivateKeyType::Dhx => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_DHX,
- Asn1PrivateKeyType::Ec => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_EC,
- Asn1PrivateKeyType::Hmac => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HMAC,
- Asn1PrivateKeyType::Cmac => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_CMAC,
- Asn1PrivateKeyType::Tls1Prf => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_TLS1_PRF,
- Asn1PrivateKeyType::Hkdf => coap_asn1_privatekey_type_t::COAP_ASN1_PKEY_HKDF,
+ Asn1PrivateKeyType::None => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_NONE,
+ Asn1PrivateKeyType::Rsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA,
+ Asn1PrivateKeyType::Rsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_RSA2,
+ Asn1PrivateKeyType::Dsa => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA,
+ Asn1PrivateKeyType::Dsa1 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA1,
+ Asn1PrivateKeyType::Dsa2 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA2,
+ Asn1PrivateKeyType::Dsa3 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA3,
+ Asn1PrivateKeyType::Dsa4 => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DSA4,
+ Asn1PrivateKeyType::Dh => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DH,
+ Asn1PrivateKeyType::Dhx => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_DHX,
+ Asn1PrivateKeyType::Ec => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_EC,
+ Asn1PrivateKeyType::Hmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HMAC,
+ Asn1PrivateKeyType::Cmac => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_CMAC,
+ Asn1PrivateKeyType::Tls1Prf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_TLS1_PRF,
+ Asn1PrivateKeyType::Hkdf => coap_asn1_privatekey_type_t_COAP_ASN1_PKEY_HKDF,
}
}
}
diff --git a/libcoap/src/crypto/pki_rpk/mod.rs b/libcoap/src/crypto/pki_rpk/mod.rs
index f35f8f57..5d0918b6 100644
--- a/libcoap/src/crypto/pki_rpk/mod.rs
+++ b/libcoap/src/crypto/pki_rpk/mod.rs
@@ -295,27 +295,31 @@ mod pki;
#[cfg(feature = "dtls-rpk")]
mod rpk;
-#[cfg(feature = "dtls-pki")]
-pub use pki::*;
-#[cfg(feature = "dtls-rpk")]
-pub use rpk::*;
+use std::{
+ cell::RefCell,
+ ffi::{c_char, c_int, c_uint, c_void, CStr, CString, NulError},
+ fmt::{Debug, Formatter},
+ marker::PhantomData,
+ ptr::NonNull,
+ rc::{Rc, Weak},
+};
pub use key::*;
-
-use crate::error::{ContextConfigurationError, SessionCreationError};
-use crate::session::CoapSession;
-use crate::types::CoapAddress;
-use crate::CoapContext;
use libcoap_sys::{
coap_context_set_pki, coap_context_t, coap_dtls_key_t, coap_dtls_pki_t, coap_new_client_session_pki, coap_proto_t,
coap_session_t, COAP_DTLS_PKI_SETUP_VERSION,
};
-use std::cell::RefCell;
-use std::ffi::{c_char, c_int, c_uint, c_void, CStr, CString, NulError};
-use std::fmt::{Debug, Formatter};
-use std::marker::PhantomData;
-use std::ptr::NonNull;
-use std::rc::{Rc, Weak};
+#[cfg(feature = "dtls-pki")]
+pub use pki::*;
+#[cfg(feature = "dtls-rpk")]
+pub use rpk::*;
+
+use crate::{
+ error::{ContextConfigurationError, SessionCreationError},
+ session::CoapSession,
+ types::CoapAddress,
+ CoapContext,
+};
/// A context configuration for server-side PKI or RPK based DTLS encryption.
#[derive(Clone, Debug)]
diff --git a/libcoap/src/crypto/pki_rpk/pki.rs b/libcoap/src/crypto/pki_rpk/pki.rs
index bebf05f7..4223db49 100644
--- a/libcoap/src/crypto/pki_rpk/pki.rs
+++ b/libcoap/src/crypto/pki_rpk/pki.rs
@@ -7,21 +7,33 @@
* See the README as well as the LICENSE file for more information.
*/
-use crate::crypto::pki_rpk;
-use crate::crypto::pki_rpk::key::{KeyComponentSealed, KeyTypeSealed};
-use crate::crypto::pki_rpk::{
- Asn1PrivateKeyType, CertVerificationMode, CertVerifying, CnCallback, DerFileKeyComponent, DerMemoryKeyComponent,
- EngineKeyComponent, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying, PemFileKeyComponent,
- PemMemoryKeyComponent, Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext,
+use std::{
+ ffi::{c_uint, CStr, CString},
+ fmt::Debug,
};
-use crate::crypto::ClientCryptoContext;
-use crate::session::CoapSession;
+
use libcoap_sys::{
coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_key_t__bindgen_ty_1, coap_dtls_pki_t, coap_pki_define_t,
- coap_pki_key_define_t, coap_pki_key_t,
+ coap_pki_define_t_COAP_PKI_KEY_DEF_DER, coap_pki_define_t_COAP_PKI_KEY_DEF_DER_BUF,
+ coap_pki_define_t_COAP_PKI_KEY_DEF_ENGINE, coap_pki_define_t_COAP_PKI_KEY_DEF_PEM,
+ coap_pki_define_t_COAP_PKI_KEY_DEF_PEM_BUF, coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11, coap_pki_key_define_t,
+ coap_pki_key_t_COAP_PKI_KEY_DEFINE,
+};
+
+use crate::{
+ crypto::{
+ pki_rpk,
+ pki_rpk::{
+ key::{KeyComponentSealed, KeyTypeSealed},
+ Asn1PrivateKeyType, CertVerificationMode, CertVerifying, CnCallback, DerFileKeyComponent,
+ DerMemoryKeyComponent, EngineKeyComponent, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying,
+ PemFileKeyComponent, PemMemoryKeyComponent, Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder,
+ ServerPkiRpkCryptoContext,
+ },
+ ClientCryptoContext,
+ },
+ session::CoapSession,
};
-use std::ffi::{c_uint, CStr, CString};
-use std::fmt::Debug;
/// (Marker) key type for keys with a certificate signed by a trusted CA.
#[derive(Debug, Clone, Copy)]
@@ -314,7 +326,7 @@ impl, PK: KeyComponent, SK: KeyComponent> KeyDef
let (private_key, private_key_len) = self.private_key.as_raw_key_component();
coap_dtls_key_t {
- key_type: coap_pki_key_t::COAP_PKI_KEY_DEFINE,
+ key_type: coap_pki_key_t_COAP_PKI_KEY_DEFINE,
key: coap_dtls_key_t__bindgen_ty_1 {
define: coap_pki_key_define_t {
ca,
@@ -339,25 +351,25 @@ impl, PK: KeyComponent, SK: KeyComponent> KeyDef
}
impl KeyComponentSealed for PemFileKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_PEM;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PEM;
}
impl KeyComponentSealed for PemMemoryKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_PEM_BUF;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PEM_BUF;
}
impl KeyComponentSealed for DerFileKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_DER;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_DER;
}
impl KeyComponentSealed for DerMemoryKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_DER_BUF;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_DER_BUF;
}
impl KeyComponentSealed for Pkcs11KeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_PKCS11;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11;
}
impl KeyComponentSealed for EngineKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_ENGINE;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_ENGINE;
}
diff --git a/libcoap/src/crypto/pki_rpk/rpk.rs b/libcoap/src/crypto/pki_rpk/rpk.rs
index 1642bc75..486f6a9b 100644
--- a/libcoap/src/crypto/pki_rpk/rpk.rs
+++ b/libcoap/src/crypto/pki_rpk/rpk.rs
@@ -7,20 +7,27 @@
* See the README as well as the LICENSE file for more information.
*/
-use crate::crypto::pki_rpk;
-use crate::crypto::pki_rpk::key::{KeyComponentSealed, KeyTypeSealed};
-use crate::crypto::pki_rpk::{
- Asn1PrivateKeyType, CnCallback, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying, PemMemoryKeyComponent,
- Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext,
-};
-use crate::crypto::ClientCryptoContext;
-use crate::session::CoapSession;
+use std::{ffi::CString, fmt::Debug};
+
use libcoap_sys::{
coap_const_char_ptr_t, coap_dtls_key_t, coap_dtls_key_t__bindgen_ty_1, coap_dtls_pki_t, coap_pki_define_t,
- coap_pki_key_define_t, coap_pki_key_t,
+ coap_pki_define_t_COAP_PKI_KEY_DEF_PEM, coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11_RPK,
+ coap_pki_define_t_COAP_PKI_KEY_DEF_RPK_BUF, coap_pki_key_define_t, coap_pki_key_t,
+ coap_pki_key_t_COAP_PKI_KEY_DEFINE,
+};
+
+use crate::{
+ crypto::{
+ pki_rpk,
+ pki_rpk::{
+ key::{KeyComponentSealed, KeyTypeSealed},
+ Asn1PrivateKeyType, CnCallback, KeyComponent, KeyDef, KeyDefSealed, NonCertVerifying,
+ PemMemoryKeyComponent, Pkcs11KeyComponent, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext,
+ },
+ ClientCryptoContext,
+ },
+ session::CoapSession,
};
-use std::ffi::CString;
-use std::fmt::Debug;
/// (Marker) key type for asymmetric DTLS keys not signed by a CA (raw public keys).
#[derive(Debug, Clone, Copy)]
@@ -170,7 +177,7 @@ impl, SK: KeyComponent> KeyDefSealed for RpkKeyDef, SK: KeyComponent> KeyDefSealed for RpkKeyDef>::DEFINE_TYPE,
private_key_def: >::DEFINE_TYPE,
private_key_type: self.asn1_private_key_type.into(),
@@ -197,9 +204,9 @@ impl, SK: KeyComponent> KeyDef for RpkKeyDef
}
impl KeyComponentSealed for PemMemoryKeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_RPK_BUF;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_RPK_BUF;
}
impl KeyComponentSealed for Pkcs11KeyComponent {
- const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t::COAP_PKI_KEY_DEF_PKCS11_RPK;
+ const DEFINE_TYPE: coap_pki_define_t = coap_pki_define_t_COAP_PKI_KEY_DEF_PKCS11_RPK;
}
diff --git a/libcoap/src/crypto/psk/client.rs b/libcoap/src/crypto/psk/client.rs
index e8b09d1a..ec907be9 100644
--- a/libcoap/src/crypto/psk/client.rs
+++ b/libcoap/src/crypto/psk/client.rs
@@ -7,20 +7,22 @@
* See the README as well as the LICENSE file for more information.
*/
-use crate::crypto::psk::key::PskKey;
-use crate::error::SessionCreationError;
-use crate::session::CoapClientSession;
-use crate::types::CoapAddress;
-use crate::CoapContext;
+use std::{
+ cell::RefCell,
+ ffi::{c_char, c_void, CString, NulError},
+ fmt::Debug,
+ ptr::NonNull,
+ rc::{Rc, Weak},
+};
+
use libcoap_sys::{
coap_dtls_cpsk_info_t, coap_dtls_cpsk_t, coap_new_client_session_psk2, coap_proto_t, coap_session_t,
coap_str_const_t, COAP_DTLS_CPSK_SETUP_VERSION,
};
-use std::cell::RefCell;
-use std::ffi::{c_char, c_void, CString, NulError};
-use std::fmt::Debug;
-use std::ptr::NonNull;
-use std::rc::{Rc, Weak};
+
+use crate::{
+ crypto::psk::key::PskKey, error::SessionCreationError, session::CoapClientSession, types::CoapAddress, CoapContext,
+};
/// Builder for a client-side DTLS encryption context for use with pre-shared keys (PSK).
#[derive(Debug)]
@@ -41,9 +43,7 @@ impl<'a> ClientPskContextBuilder<'a> {
raw_cfg: Box::new(coap_dtls_cpsk_t {
version: COAP_DTLS_CPSK_SETUP_VERSION as u8,
reserved: Default::default(),
- #[cfg(dtls_ec_jpake_support)]
ec_jpake: 0,
- #[cfg(dtls_cid_support)]
use_cid: 0,
validate_ih_call_back: None,
ih_call_back_arg: std::ptr::null_mut(),
@@ -96,10 +96,12 @@ impl ClientPskContextBuilder<'_> {
/// Enables or disables support for EC JPAKE ([RFC 8236](https://datatracker.ietf.org/doc/html/rfc8236))
/// key exchanges in (D)TLS.
///
+ /// Note: At the time of writing (based on libcoap 4.3.5), this is only supported on MbedTLS,
+ /// enabling EC JPAKE on other DTLS backends has no effect.
+ ///
/// # Implementation details (informative, not covered by semver guarantees)
///
/// Equivalent to setting `ec_jpake` in the underlying [`coap_dtls_cpsk_t`] structure.
- #[cfg(dtls_ec_jpake_support)]
pub fn ec_jpake(mut self, ec_jpake: bool) -> Self {
self.ctx.raw_cfg.ec_jpake = ec_jpake.into();
self
@@ -110,7 +112,7 @@ impl ClientPskContextBuilder<'_> {
/// # Implementation details (informative, not covered by semver guarantees)
///
/// Equivalent to setting `use_cid` in the underlying [`coap_dtls_cpsk_t`] structure.
- #[cfg(dtls_cid_support)]
+ #[cfg(feature = "dtls-cid")]
pub fn use_cid(mut self, use_cid: bool) -> Self {
self.ctx.raw_cfg.use_cid = use_cid.into();
self
diff --git a/libcoap/src/crypto/psk/key.rs b/libcoap/src/crypto/psk/key.rs
index eebf94de..11503451 100644
--- a/libcoap/src/crypto/psk/key.rs
+++ b/libcoap/src/crypto/psk/key.rs
@@ -7,10 +7,9 @@
* See the README as well as the LICENSE file for more information.
*/
+use std::{borrow::Cow, marker::PhantomData, ptr::NonNull};
+
use libcoap_sys::{coap_bin_const_t, coap_dtls_cpsk_info_t, coap_dtls_spsk_info_t};
-use std::borrow::Cow;
-use std::marker::PhantomData;
-use std::ptr::NonNull;
/// A pre-shared DTLS key.
#[derive(Debug, Clone)]
diff --git a/libcoap/src/crypto/psk/server.rs b/libcoap/src/crypto/psk/server.rs
index eeb61bb7..5f281e83 100644
--- a/libcoap/src/crypto/psk/server.rs
+++ b/libcoap/src/crypto/psk/server.rs
@@ -7,22 +7,24 @@
* See the README as well as the LICENSE file for more information.
*/
-use crate::crypto::psk::key::PskKey;
-use crate::error::ContextConfigurationError;
-use crate::session::CoapServerSession;
+use std::{
+ borrow::Borrow,
+ cell::RefCell,
+ collections::{BTreeMap, HashMap},
+ ffi::{c_void, CStr},
+ fmt::Debug,
+ hash::Hash,
+ os::raw::c_char,
+ ptr::NonNull,
+ rc::{Rc, Weak},
+};
+
use libcoap_sys::{
coap_bin_const_t, coap_context_set_psk2, coap_context_t, coap_dtls_spsk_info_t, coap_dtls_spsk_t, coap_session_t,
COAP_DTLS_SPSK_SETUP_VERSION,
};
-use std::borrow::Borrow;
-use std::cell::RefCell;
-use std::collections::{BTreeMap, HashMap};
-use std::ffi::{c_void, CStr};
-use std::fmt::Debug;
-use std::hash::Hash;
-use std::os::raw::c_char;
-use std::ptr::NonNull;
-use std::rc::{Rc, Weak};
+
+use crate::{crypto::psk::key::PskKey, error::ContextConfigurationError, session::CoapServerSession};
/// Builder for a server-side DTLS encryption context for use with pre-shared keys (PSK).
#[derive(Debug)]
@@ -46,7 +48,6 @@ impl<'a> ServerPskContextBuilder<'a> {
raw_cfg: Box::new(coap_dtls_spsk_t {
version: COAP_DTLS_SPSK_SETUP_VERSION as u8,
reserved: Default::default(),
- #[cfg(dtls_ec_jpake_support)]
ec_jpake: 0,
validate_id_call_back: None,
id_call_back_arg: std::ptr::null_mut(),
@@ -105,10 +106,12 @@ impl ServerPskContextBuilder<'_> {
/// Enables or disables support for EC JPAKE ([RFC 8236](https://datatracker.ietf.org/doc/html/rfc8236))
/// key exchanges in (D)TLS.
///
+ /// Note: At the time of writing (based on libcoap 4.3.5), this is only supported on MbedTLS,
+ /// enabling EC JPAKE on other DTLS backends has no effect.
+ ///
/// # Implementation details (informative, not covered by semver guarantees)
///
/// Equivalent to setting `ec_jpake` in the underlying [`coap_dtls_spsk_t`] structure.
- #[cfg(dtls_ec_jpake_support)]
pub fn ec_jpake(mut self, ec_jpake: bool) -> Self {
self.ctx.raw_cfg.ec_jpake = ec_jpake.into();
self
diff --git a/libcoap/src/error.rs b/libcoap/src/error.rs
index 14fcf6f5..6c1630dd 100644
--- a/libcoap/src/error.rs
+++ b/libcoap/src/error.rs
@@ -9,9 +9,7 @@
//! Error types
-use std::ffi::NulError;
-use std::string::FromUtf8Error;
-use std::sync::PoisonError;
+use std::{ffi::NulError, string::FromUtf8Error, sync::PoisonError};
use thiserror::Error;
diff --git a/libcoap/src/event.rs b/libcoap/src/event.rs
index 07573119..fb716763 100644
--- a/libcoap/src/event.rs
+++ b/libcoap/src/event.rs
@@ -11,13 +11,15 @@
use std::fmt::Debug;
-use libcoap_sys::{coap_event_t, coap_session_get_context, coap_session_t};
-use libcoap_sys::{coap_session_get_type, coap_session_type_t};
+use libcoap_sys::{
+ coap_event_t, coap_event_t_COAP_EVENT_SERVER_SESSION_NEW, coap_event_t_COAP_EVENT_TCP_CONNECTED,
+ coap_session_get_context, coap_session_get_type, coap_session_t, coap_session_type_t_COAP_SESSION_TYPE_SERVER,
+};
-use crate::context::CoapContext;
-use crate::session::CoapSession;
-
-use crate::session::CoapServerSession;
+use crate::{
+ context::CoapContext,
+ session::{CoapServerSession, CoapSession},
+};
/// Trait for CoAP event handlers.
///
@@ -147,7 +149,6 @@ pub trait CoapEventHandler: Debug {
#[allow(unused_variables)]
fn handle_oscore_decode_error(&mut self, session: &mut CoapSession) {}
-
/// Handle an oversized WebSocket packet event.
#[allow(unused_variables)]
fn handle_ws_packet_size(&mut self, session: &mut CoapSession) {}
@@ -171,9 +172,9 @@ pub trait CoapEventHandler: Debug {
pub(crate) unsafe extern "C" fn event_handler_callback(raw_session: *mut coap_session_t, event: coap_event_t) -> i32 {
let raw_session_type = coap_session_get_type(raw_session);
- let session: CoapSession = if event == coap_event_t::COAP_EVENT_SERVER_SESSION_NEW
- || (event == coap_event_t::COAP_EVENT_TCP_CONNECTED
- && raw_session_type == coap_session_type_t::COAP_SESSION_TYPE_SERVER)
+ let session: CoapSession = if event == coap_event_t_COAP_EVENT_SERVER_SESSION_NEW
+ || (event == coap_event_t_COAP_EVENT_TCP_CONNECTED
+ && raw_session_type == coap_session_type_t_COAP_SESSION_TYPE_SERVER)
{
CoapServerSession::initialize_raw(raw_session).into()
} else {
diff --git a/libcoap/src/lib.rs b/libcoap/src/lib.rs
index 9dcda7ab..bad62a8a 100644
--- a/libcoap/src/lib.rs
+++ b/libcoap/src/lib.rs
@@ -36,16 +36,20 @@
//! - [x] Notifying observers as a server
//!
//! # Building
-//! libcoap-rs can be linked to either an included version of libcoap or to a version provided by
-//! the environment.
-//! By default, it will use the vendored version, which can be disabled by disabling the default
-//! feature `vendored`.
+//! libcoap-rs is based on libcoap-sys, which provide many different ways to obtain and link against
+//! a system-provided or vendored version of the libcoap C library.
//!
-//! In order to use DTLS, a DTLS library must be chosen, see the later section on using
-//! cryptography for more information.
+//! Refer to [its documentation](https://docs.rs/libcoap-sys) for detailed instructions on how to
+//! build libcoap-sys as well as this library.
//!
-//! Some (but not all) of the available DTLS libraries may also be vendored using the
-//! `dtls_[LIBRARY]_vendored` feature.
+//! Most of these instructions can be applied to libcoap-rs directly, although libcoap-rs does
+//! abstract away some of the features.
+//!
+//! For your convenience, libcoap-rs "re-exports" some features that do not have any influence on
+//! the safe wrapper, but may have to be set in libcoap-sys to enable building (e.g., the
+//! `dtls--sys` features).
+//! This way, you don't need to add libcoap-sys as a dependency yourself, and may just enable the
+//! feature in this crate instead.
//!
//! ## Building on the ESP32
//!
@@ -207,7 +211,7 @@ pub use event::CoapEventHandler;
pub use resource::{CoapRequestHandler, CoapResource};
mod context;
-#[cfg(dtls)]
+#[cfg(feature = "dtls")]
pub mod crypto;
pub mod error;
mod event;
diff --git a/libcoap/src/mem.rs b/libcoap/src/mem.rs
index 64097377..5fb078d4 100644
--- a/libcoap/src/mem.rs
+++ b/libcoap/src/mem.rs
@@ -9,11 +9,13 @@
//! Code related to memory handling, especially for passing objects through FFI
-use std::cell::{Ref, RefCell, RefMut};
-use std::ffi::c_void;
-use std::fmt::{Debug, Formatter};
-use std::ops::{Deref, DerefMut};
-use std::rc::{Rc, Weak};
+use std::{
+ cell::{Ref, RefCell, RefMut},
+ ffi::c_void,
+ fmt::{Debug, Formatter},
+ ops::{Deref, DerefMut},
+ rc::{Rc, Weak},
+};
/// Trait implemented by libcoap wrapper structs that contain an inner value that may be dropped
/// exclusively, i.e., that can be dropped with the additional check that there are no further
diff --git a/libcoap/src/message/mod.rs b/libcoap/src/message/mod.rs
index fd31b57c..2c294f48 100644
--- a/libcoap/src/message/mod.rs
+++ b/libcoap/src/message/mod.rs
@@ -15,10 +15,7 @@
//! process of creating requests and responses and setting the appropriate options ([CoapRequest]
//! and [CoapResponse]).
-use std::{ffi::c_void, mem::MaybeUninit, slice::Iter};
-use std::fmt::Write;
-
-use num_traits::FromPrimitive;
+use std::{ffi::c_void, fmt::Write, mem::MaybeUninit, slice::Iter};
use libcoap_sys::{
coap_add_data, coap_add_data_large_request, coap_add_optlist_pdu, coap_add_token, coap_delete_optlist,
@@ -27,23 +24,23 @@ use libcoap_sys::{
coap_pdu_get_mid, coap_pdu_get_token, coap_pdu_get_type, coap_pdu_init, coap_pdu_set_code, coap_pdu_set_type,
coap_pdu_t, coap_session_t,
};
+use num_traits::FromPrimitive;
pub use request::CoapRequest;
pub use response::CoapResponse;
use crate::{
+ context::ensure_coap_started,
error::{MessageConversionError, OptionValueError},
protocol::{
- Block, CoapMatch, CoapMessageCode, CoapMessageType, CoapOptionNum, CoapOptionType, ContentFormat, ETag,
- HopLimit, MaxAge, NoResponse, Observe, ProxyScheme, ProxyUri, Size, UriHost, UriPath, UriPort, UriQuery,
+ Block, CoapMatch, CoapMessageCode, CoapMessageType, CoapOptionNum, CoapOptionType, ContentFormat, ETag, Echo,
+ HopLimit, MaxAge, NoResponse, Observe, Oscore, ProxyScheme, ProxyUri, RequestTag, Size, UriHost, UriPath,
+ UriPort, UriQuery,
},
session::CoapSessionCommon,
- types::CoapMessageId,
-};
-use crate::context::ensure_coap_started;
-use crate::protocol::{Echo, Oscore, RequestTag};
-use crate::types::{
- decode_var_len_u16, decode_var_len_u32, decode_var_len_u8, encode_var_len_u16, encode_var_len_u32,
- encode_var_len_u8,
+ types::{
+ decode_var_len_u16, decode_var_len_u32, decode_var_len_u8, encode_var_len_u16, encode_var_len_u32,
+ encode_var_len_u8, CoapMessageId,
+ },
};
pub mod request;
diff --git a/libcoap/src/message/request.rs b/libcoap/src/message/request.rs
index 862984f8..85854872 100644
--- a/libcoap/src/message/request.rs
+++ b/libcoap/src/message/request.rs
@@ -10,17 +10,15 @@
use std::str::FromStr;
use crate::{
- error::{MessageConversionError, MessageTypeError},
- message::{CoapMessage, CoapMessageCommon, CoapOption},
+ error::{MessageConversionError, MessageTypeError, OptionValueError},
+ message::{construct_path_string, construct_query_string, CoapMessage, CoapMessageCommon, CoapOption},
protocol::{
CoapMatch, CoapMessageCode, CoapMessageType, CoapOptionType, CoapRequestCode, ContentFormat, ETag, HopLimit,
NoResponse, Observe,
},
+ session::CoapSessionCommon,
types::{CoapUri, CoapUriScheme},
};
-use crate::error::OptionValueError;
-use crate::message::{construct_path_string, construct_query_string};
-use crate::session::CoapSessionCommon;
/// Representation of a CoAP request message.
///
diff --git a/libcoap/src/message/response.rs b/libcoap/src/message/response.rs
index c3a0cc9a..844c3dc5 100644
--- a/libcoap/src/message/response.rs
+++ b/libcoap/src/message/response.rs
@@ -7,12 +7,14 @@
* See the README as well as the LICENSE file for more information.
*/
-use crate::error::{MessageConversionError, MessageTypeError, OptionValueError};
-use crate::message::{CoapMessage, CoapMessageCommon, CoapOption, construct_path_string, construct_query_string};
-use crate::protocol::{
- CoapMessageCode, CoapMessageType, CoapOptionType, CoapResponseCode, ContentFormat, Echo, ETag, MaxAge, Observe,
+use crate::{
+ error::{MessageConversionError, MessageTypeError, OptionValueError},
+ message::{construct_path_string, construct_query_string, CoapMessage, CoapMessageCommon, CoapOption},
+ protocol::{
+ CoapMessageCode, CoapMessageType, CoapOptionType, CoapResponseCode, ContentFormat, ETag, Echo, MaxAge, Observe,
+ },
+ types::CoapUri,
};
-use crate::types::CoapUri;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CoapResponse {
diff --git a/libcoap/src/prng.rs b/libcoap/src/prng.rs
index 65f3f54e..53aa2354 100644
--- a/libcoap/src/prng.rs
+++ b/libcoap/src/prng.rs
@@ -15,22 +15,20 @@
//! [rand] crate that allow using the libcoap PRNG as a [rand::Rng] or setting the libcoap PRNG to
//! an existing [rand::Rng].
-use std::ffi::{c_uint, c_void};
#[cfg(feature = "rand")]
use std::ffi::c_int;
-use std::sync::Mutex;
+use std::{
+ ffi::{c_uint, c_void},
+ sync::Mutex,
+};
#[cfg(feature = "rand")]
-use libc::size_t;
-#[cfg(feature = "rand")]
-use rand::{CryptoRng, RngCore};
-
+use libcoap_sys::coap_set_prng;
use libcoap_sys::{coap_prng, coap_prng_init};
#[cfg(feature = "rand")]
-use libcoap_sys::coap_set_prng;
+use rand::{CryptoRng, RngCore};
-use crate::context::ensure_coap_started;
-use crate::error::RngError;
+use crate::{context::ensure_coap_started, error::RngError};
// TODO If we can assert that libcoap's own thread-safety features are enabled at some point, we
// don't need these mutexes.
@@ -186,7 +184,7 @@ pub fn set_coap_prng(rng: RNG)
/// This function is intended as a [libcoap_sys::coap_rand_func_t], therefore `out` should be valid
/// and point to the start of an area of memory that can be filled with `len` bytes.
#[cfg(feature = "rand")]
-unsafe extern "C" fn prng_callback(out: *mut c_void, len: size_t) -> c_int {
+unsafe extern "C" fn prng_callback(out: *mut c_void, len: usize) -> c_int {
let out_slice = std::slice::from_raw_parts_mut(out as *mut u8, len);
match COAP_RNG_FN_MUTEX.lock() {
Ok(mut rng_fn) => rng_fn
diff --git a/libcoap/src/protocol.rs b/libcoap/src/protocol.rs
index 6bb8f926..7b9b27d0 100644
--- a/libcoap/src/protocol.rs
+++ b/libcoap/src/protocol.rs
@@ -14,31 +14,49 @@ use std::{
fmt::{Display, Formatter},
};
-use num_derive::FromPrimitive;
-use num_traits::FromPrimitive;
-
use libcoap_sys::{
+ coap_option_num_t, coap_pdu_code_t, coap_pdu_code_t_COAP_EMPTY_CODE, coap_pdu_code_t_COAP_REQUEST_CODE_DELETE,
+ coap_pdu_code_t_COAP_REQUEST_CODE_FETCH, coap_pdu_code_t_COAP_REQUEST_CODE_GET,
+ coap_pdu_code_t_COAP_REQUEST_CODE_IPATCH, coap_pdu_code_t_COAP_REQUEST_CODE_PATCH,
+ coap_pdu_code_t_COAP_REQUEST_CODE_POST, coap_pdu_code_t_COAP_REQUEST_CODE_PUT,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_GATEWAY, coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_OPTION,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_REQUEST, coap_pdu_code_t_COAP_RESPONSE_CODE_CHANGED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_CONFLICT, coap_pdu_code_t_COAP_RESPONSE_CODE_CONTENT,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_CONTINUE, coap_pdu_code_t_COAP_RESPONSE_CODE_CREATED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_DELETED, coap_pdu_code_t_COAP_RESPONSE_CODE_FORBIDDEN,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_GATEWAY_TIMEOUT, coap_pdu_code_t_COAP_RESPONSE_CODE_HOP_LIMIT_REACHED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_INCOMPLETE, coap_pdu_code_t_COAP_RESPONSE_CODE_INTERNAL_ERROR,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ACCEPTABLE, coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ALLOWED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_FOUND, coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_IMPLEMENTED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_PRECONDITION_FAILED, coap_pdu_code_t_COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_REQUEST_TOO_LARGE, coap_pdu_code_t_COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_TOO_MANY_REQUESTS, coap_pdu_code_t_COAP_RESPONSE_CODE_UNAUTHORIZED,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_UNPROCESSABLE, coap_pdu_code_t_COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT,
+ coap_pdu_code_t_COAP_RESPONSE_CODE_VALID, coap_pdu_type_t, coap_pdu_type_t_COAP_MESSAGE_ACK,
+ coap_pdu_type_t_COAP_MESSAGE_CON, coap_pdu_type_t_COAP_MESSAGE_NON, coap_pdu_type_t_COAP_MESSAGE_RST,
+ coap_request_t, coap_request_t_COAP_REQUEST_DELETE, coap_request_t_COAP_REQUEST_FETCH,
+ coap_request_t_COAP_REQUEST_GET, coap_request_t_COAP_REQUEST_IPATCH, coap_request_t_COAP_REQUEST_PATCH,
+ coap_request_t_COAP_REQUEST_POST, coap_request_t_COAP_REQUEST_PUT, coap_response_phrase,
COAP_MEDIATYPE_APPLICATION_ACE_CBOR, COAP_MEDIATYPE_APPLICATION_CBOR, COAP_MEDIATYPE_APPLICATION_COAP_GROUP_JSON,
- COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT,
- COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, COAP_MEDIATYPE_APPLICATION_COSE_KEY, COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, COAP_MEDIATYPE_APPLICATION_COSE_MAC,
- COAP_MEDIATYPE_APPLICATION_COSE_MAC0, COAP_MEDIATYPE_APPLICATION_COSE_SIGN,
- COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, COAP_MEDIATYPE_APPLICATION_CWT,
- COAP_MEDIATYPE_APPLICATION_DOTS_CBOR, COAP_MEDIATYPE_APPLICATION_EXI, COAP_MEDIATYPE_APPLICATION_JSON,
- COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ, COAP_MEDIATYPE_APPLICATION_OCTET_STREAM,
- COAP_MEDIATYPE_APPLICATION_OSCORE, COAP_MEDIATYPE_APPLICATION_RDF_XML, COAP_MEDIATYPE_APPLICATION_SENML_CBOR,
- COAP_MEDIATYPE_APPLICATION_SENML_EXI, COAP_MEDIATYPE_APPLICATION_SENML_JSON,
- COAP_MEDIATYPE_APPLICATION_SENML_XML, COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, COAP_MEDIATYPE_APPLICATION_SENSML_EXI,
- COAP_MEDIATYPE_APPLICATION_SENSML_JSON, COAP_MEDIATYPE_APPLICATION_SENSML_XML, COAP_MEDIATYPE_APPLICATION_XML,
- COAP_MEDIATYPE_TEXT_PLAIN, COAP_OPTION_ACCEPT,
- COAP_OPTION_BLOCK1, COAP_OPTION_BLOCK2,
- COAP_OPTION_CONTENT_FORMAT, COAP_OPTION_ECHO, COAP_OPTION_ETAG,
- COAP_OPTION_HOP_LIMIT, COAP_OPTION_IF_MATCH, COAP_OPTION_IF_NONE_MATCH, COAP_OPTION_LOCATION_PATH, COAP_OPTION_LOCATION_QUERY,
- COAP_OPTION_MAXAGE, COAP_OPTION_NORESPONSE, coap_option_num_t, COAP_OPTION_OBSERVE,
- COAP_OPTION_OSCORE, COAP_OPTION_PROXY_SCHEME, COAP_OPTION_PROXY_URI, COAP_OPTION_Q_BLOCK1,
+ COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0,
+ COAP_MEDIATYPE_APPLICATION_COSE_KEY, COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, COAP_MEDIATYPE_APPLICATION_COSE_MAC,
+ COAP_MEDIATYPE_APPLICATION_COSE_MAC0, COAP_MEDIATYPE_APPLICATION_COSE_SIGN, COAP_MEDIATYPE_APPLICATION_COSE_SIGN1,
+ COAP_MEDIATYPE_APPLICATION_CWT, COAP_MEDIATYPE_APPLICATION_DOTS_CBOR, COAP_MEDIATYPE_APPLICATION_EXI,
+ COAP_MEDIATYPE_APPLICATION_JSON, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ,
+ COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, COAP_MEDIATYPE_APPLICATION_OSCORE, COAP_MEDIATYPE_APPLICATION_RDF_XML,
+ COAP_MEDIATYPE_APPLICATION_SENML_CBOR, COAP_MEDIATYPE_APPLICATION_SENML_EXI, COAP_MEDIATYPE_APPLICATION_SENML_JSON,
+ COAP_MEDIATYPE_APPLICATION_SENML_XML, COAP_MEDIATYPE_APPLICATION_SENSML_CBOR,
+ COAP_MEDIATYPE_APPLICATION_SENSML_EXI, COAP_MEDIATYPE_APPLICATION_SENSML_JSON,
+ COAP_MEDIATYPE_APPLICATION_SENSML_XML, COAP_MEDIATYPE_APPLICATION_XML, COAP_MEDIATYPE_TEXT_PLAIN,
+ COAP_OPTION_ACCEPT, COAP_OPTION_BLOCK1, COAP_OPTION_BLOCK2, COAP_OPTION_CONTENT_FORMAT, COAP_OPTION_ECHO,
+ COAP_OPTION_ETAG, COAP_OPTION_HOP_LIMIT, COAP_OPTION_IF_MATCH, COAP_OPTION_IF_NONE_MATCH,
+ COAP_OPTION_LOCATION_PATH, COAP_OPTION_LOCATION_QUERY, COAP_OPTION_MAXAGE, COAP_OPTION_NORESPONSE,
+ COAP_OPTION_OBSERVE, COAP_OPTION_OSCORE, COAP_OPTION_PROXY_SCHEME, COAP_OPTION_PROXY_URI, COAP_OPTION_Q_BLOCK1,
COAP_OPTION_Q_BLOCK2, COAP_OPTION_RTAG, COAP_OPTION_SIZE1, COAP_OPTION_SIZE2, COAP_OPTION_URI_HOST,
- COAP_OPTION_URI_PATH, COAP_OPTION_URI_PORT, COAP_OPTION_URI_QUERY, coap_pdu_code_t, coap_pdu_type_t,
- coap_pdu_type_t::{COAP_MESSAGE_ACK, COAP_MESSAGE_CON, COAP_MESSAGE_NON, COAP_MESSAGE_RST}, coap_request_t, coap_response_phrase,
+ COAP_OPTION_URI_PATH, COAP_OPTION_URI_PORT, COAP_OPTION_URI_QUERY,
};
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
use crate::error::{MessageCodeError, UnknownOptionError};
@@ -286,7 +304,7 @@ impl CoapMessageCode {
/// [coap_pdu_t](libcoap_sys::coap_pdu_t).
pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
match self {
- CoapMessageCode::Empty => coap_pdu_code_t::COAP_EMPTY_CODE,
+ CoapMessageCode::Empty => coap_pdu_code_t_COAP_EMPTY_CODE,
CoapMessageCode::Request(req) => req.to_raw_pdu_code(),
CoapMessageCode::Response(rsp) => rsp.to_raw_pdu_code(),
}
@@ -309,8 +327,11 @@ impl TryFrom for CoapMessageCode {
type Error = MessageCodeError;
fn try_from(code: coap_pdu_code_t) -> Result {
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match code {
- coap_pdu_code_t::COAP_EMPTY_CODE => Ok(CoapMessageCode::Empty),
+ coap_pdu_code_t_COAP_EMPTY_CODE => Ok(CoapMessageCode::Empty),
code => CoapRequestCode::try_from(code)
.map(CoapMessageCode::Request)
.or_else(|_| CoapResponseCode::try_from(code).map(CoapMessageCode::Response)),
@@ -326,30 +347,30 @@ impl TryFrom for CoapMessageCode {
#[non_exhaustive]
#[derive(FromPrimitive, Clone, Copy, Eq, PartialEq, Hash, Debug)]
pub enum CoapRequestCode {
- Get = coap_pdu_code_t::COAP_REQUEST_CODE_GET as u8,
- Put = coap_pdu_code_t::COAP_REQUEST_CODE_PUT as u8,
- Delete = coap_pdu_code_t::COAP_REQUEST_CODE_DELETE as u8,
- Post = coap_pdu_code_t::COAP_REQUEST_CODE_POST as u8,
- Fetch = coap_pdu_code_t::COAP_REQUEST_CODE_FETCH as u8,
- IPatch = coap_pdu_code_t::COAP_REQUEST_CODE_IPATCH as u8,
- Patch = coap_pdu_code_t::COAP_REQUEST_CODE_PATCH as u8,
+ Get = coap_pdu_code_t_COAP_REQUEST_CODE_GET as u8,
+ Put = coap_pdu_code_t_COAP_REQUEST_CODE_PUT as u8,
+ Delete = coap_pdu_code_t_COAP_REQUEST_CODE_DELETE as u8,
+ Post = coap_pdu_code_t_COAP_REQUEST_CODE_POST as u8,
+ Fetch = coap_pdu_code_t_COAP_REQUEST_CODE_FETCH as u8,
+ IPatch = coap_pdu_code_t_COAP_REQUEST_CODE_IPATCH as u8,
+ Patch = coap_pdu_code_t_COAP_REQUEST_CODE_PATCH as u8,
}
impl CoapRequestCode {
/// Returns the [coap_request_t](coap_request_t) corresponding to this request code.
///
- /// Note that this is *not* the code that should be set inside of a [coap_pdu_t](libcoap_sys::coap_pdu_t),
+ /// Note that this is *not* the code that should be set inside a [coap_pdu_t](libcoap_sys::coap_pdu_t),
/// but a value used internally by the libcoap C library. See [to_raw_pdu_code()](CoapRequestCode::to_raw_pdu_code())
/// for the standardized value used in messages.
pub fn to_raw_request(self) -> coap_request_t {
match self {
- CoapRequestCode::Get => coap_request_t::COAP_REQUEST_GET,
- CoapRequestCode::Put => coap_request_t::COAP_REQUEST_PUT,
- CoapRequestCode::Delete => coap_request_t::COAP_REQUEST_FETCH,
- CoapRequestCode::Post => coap_request_t::COAP_REQUEST_POST,
- CoapRequestCode::Fetch => coap_request_t::COAP_REQUEST_FETCH,
- CoapRequestCode::IPatch => coap_request_t::COAP_REQUEST_IPATCH,
- CoapRequestCode::Patch => coap_request_t::COAP_REQUEST_PATCH,
+ CoapRequestCode::Get => coap_request_t_COAP_REQUEST_GET,
+ CoapRequestCode::Put => coap_request_t_COAP_REQUEST_PUT,
+ CoapRequestCode::Delete => coap_request_t_COAP_REQUEST_DELETE,
+ CoapRequestCode::Post => coap_request_t_COAP_REQUEST_POST,
+ CoapRequestCode::Fetch => coap_request_t_COAP_REQUEST_FETCH,
+ CoapRequestCode::IPatch => coap_request_t_COAP_REQUEST_IPATCH,
+ CoapRequestCode::Patch => coap_request_t_COAP_REQUEST_PATCH,
}
}
@@ -357,28 +378,13 @@ impl CoapRequestCode {
/// request code.
pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
match self {
- CoapRequestCode::Get => coap_pdu_code_t::COAP_REQUEST_CODE_GET,
- CoapRequestCode::Put => coap_pdu_code_t::COAP_REQUEST_CODE_PUT,
- CoapRequestCode::Delete => coap_pdu_code_t::COAP_REQUEST_CODE_FETCH,
- CoapRequestCode::Post => coap_pdu_code_t::COAP_REQUEST_CODE_POST,
- CoapRequestCode::Fetch => coap_pdu_code_t::COAP_REQUEST_CODE_FETCH,
- CoapRequestCode::IPatch => coap_pdu_code_t::COAP_REQUEST_CODE_IPATCH,
- CoapRequestCode::Patch => coap_pdu_code_t::COAP_REQUEST_CODE_PATCH,
- }
- }
-}
-
-impl From for CoapRequestCode {
- fn from(req: coap_request_t) -> Self {
- match req {
- coap_request_t::COAP_REQUEST_GET => CoapRequestCode::Get,
- coap_request_t::COAP_REQUEST_POST => CoapRequestCode::Post,
- coap_request_t::COAP_REQUEST_PUT => CoapRequestCode::Put,
- coap_request_t::COAP_REQUEST_DELETE => CoapRequestCode::Delete,
- coap_request_t::COAP_REQUEST_FETCH => CoapRequestCode::Fetch,
- coap_request_t::COAP_REQUEST_PATCH => CoapRequestCode::Patch,
- coap_request_t::COAP_REQUEST_IPATCH => CoapRequestCode::IPatch,
- _ => panic!("unknown request type"),
+ CoapRequestCode::Get => coap_pdu_code_t_COAP_REQUEST_CODE_GET,
+ CoapRequestCode::Put => coap_pdu_code_t_COAP_REQUEST_CODE_PUT,
+ CoapRequestCode::Delete => coap_pdu_code_t_COAP_REQUEST_CODE_FETCH,
+ CoapRequestCode::Post => coap_pdu_code_t_COAP_REQUEST_CODE_POST,
+ CoapRequestCode::Fetch => coap_pdu_code_t_COAP_REQUEST_CODE_FETCH,
+ CoapRequestCode::IPatch => coap_pdu_code_t_COAP_REQUEST_CODE_IPATCH,
+ CoapRequestCode::Patch => coap_pdu_code_t_COAP_REQUEST_CODE_PATCH,
}
}
}
@@ -386,8 +392,8 @@ impl From for CoapRequestCode {
impl TryFrom for CoapRequestCode {
type Error = MessageCodeError;
- fn try_from(req: coap_pdu_code_t) -> Result {
- ::from_u32(req as u32).ok_or(MessageCodeError::NotARequestCode)
+ fn try_from(value: coap_pdu_code_t) -> Result {
+ ::from_u32(value as u32).ok_or(MessageCodeError::NotARequestCode)
}
}
@@ -399,33 +405,33 @@ impl TryFrom for CoapRequestCode {
#[non_exhaustive]
#[derive(Clone, Copy, FromPrimitive, Debug, Eq, PartialEq, Hash)]
pub enum CoapResponseCode {
- Content = coap_pdu_code_t::COAP_RESPONSE_CODE_CONTENT as u8,
- BadGateway = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_GATEWAY as u8,
- Continue = coap_pdu_code_t::COAP_RESPONSE_CODE_CONTINUE as u8,
- Conflict = coap_pdu_code_t::COAP_RESPONSE_CODE_CONFLICT as u8,
- BadRequest = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_REQUEST as u8,
- BadOption = coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_OPTION as u8,
- Changed = coap_pdu_code_t::COAP_RESPONSE_CODE_CHANGED as u8,
- Created = coap_pdu_code_t::COAP_RESPONSE_CODE_CREATED as u8,
- Deleted = coap_pdu_code_t::COAP_RESPONSE_CODE_DELETED as u8,
- Forbidden = coap_pdu_code_t::COAP_RESPONSE_CODE_FORBIDDEN as u8,
- GatewayTimeout = coap_pdu_code_t::COAP_RESPONSE_CODE_GATEWAY_TIMEOUT as u8,
- HopLimitReached = coap_pdu_code_t::COAP_RESPONSE_CODE_HOP_LIMIT_REACHED as u8,
- Incomplete = coap_pdu_code_t::COAP_RESPONSE_CODE_INCOMPLETE as u8,
- InternalError = coap_pdu_code_t::COAP_RESPONSE_CODE_INTERNAL_ERROR as u8,
- NotAcceptable = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ACCEPTABLE as u8,
- NotAllowed = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ALLOWED as u8,
- NotFound = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_FOUND as u8,
- NotImplemented = coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_IMPLEMENTED as u8,
- PreconditionFailed = coap_pdu_code_t::COAP_RESPONSE_CODE_PRECONDITION_FAILED as u8,
- ProxyingNotSupported = coap_pdu_code_t::COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED as u8,
- RequestTooLarge = coap_pdu_code_t::COAP_RESPONSE_CODE_REQUEST_TOO_LARGE as u8,
- ServiceUnavailable = coap_pdu_code_t::COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE as u8,
- TooManyRequests = coap_pdu_code_t::COAP_RESPONSE_CODE_TOO_MANY_REQUESTS as u8,
- Unauthorized = coap_pdu_code_t::COAP_RESPONSE_CODE_UNAUTHORIZED as u8,
- Unprocessable = coap_pdu_code_t::COAP_RESPONSE_CODE_UNPROCESSABLE as u8,
- UnsupportedContentFormat = coap_pdu_code_t::COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT as u8,
- Valid = coap_pdu_code_t::COAP_RESPONSE_CODE_VALID as u8,
+ Content = coap_pdu_code_t_COAP_RESPONSE_CODE_CONTENT as u8,
+ BadGateway = coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_GATEWAY as u8,
+ Continue = coap_pdu_code_t_COAP_RESPONSE_CODE_CONTINUE as u8,
+ Conflict = coap_pdu_code_t_COAP_RESPONSE_CODE_CONFLICT as u8,
+ BadRequest = coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_REQUEST as u8,
+ BadOption = coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_OPTION as u8,
+ Changed = coap_pdu_code_t_COAP_RESPONSE_CODE_CHANGED as u8,
+ Created = coap_pdu_code_t_COAP_RESPONSE_CODE_CREATED as u8,
+ Deleted = coap_pdu_code_t_COAP_RESPONSE_CODE_DELETED as u8,
+ Forbidden = coap_pdu_code_t_COAP_RESPONSE_CODE_FORBIDDEN as u8,
+ GatewayTimeout = coap_pdu_code_t_COAP_RESPONSE_CODE_GATEWAY_TIMEOUT as u8,
+ HopLimitReached = coap_pdu_code_t_COAP_RESPONSE_CODE_HOP_LIMIT_REACHED as u8,
+ Incomplete = coap_pdu_code_t_COAP_RESPONSE_CODE_INCOMPLETE as u8,
+ InternalError = coap_pdu_code_t_COAP_RESPONSE_CODE_INTERNAL_ERROR as u8,
+ NotAcceptable = coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ACCEPTABLE as u8,
+ NotAllowed = coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ALLOWED as u8,
+ NotFound = coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_FOUND as u8,
+ NotImplemented = coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_IMPLEMENTED as u8,
+ PreconditionFailed = coap_pdu_code_t_COAP_RESPONSE_CODE_PRECONDITION_FAILED as u8,
+ ProxyingNotSupported = coap_pdu_code_t_COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED as u8,
+ RequestTooLarge = coap_pdu_code_t_COAP_RESPONSE_CODE_REQUEST_TOO_LARGE as u8,
+ ServiceUnavailable = coap_pdu_code_t_COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE as u8,
+ TooManyRequests = coap_pdu_code_t_COAP_RESPONSE_CODE_TOO_MANY_REQUESTS as u8,
+ Unauthorized = coap_pdu_code_t_COAP_RESPONSE_CODE_UNAUTHORIZED as u8,
+ Unprocessable = coap_pdu_code_t_COAP_RESPONSE_CODE_UNPROCESSABLE as u8,
+ UnsupportedContentFormat = coap_pdu_code_t_COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT as u8,
+ Valid = coap_pdu_code_t_COAP_RESPONSE_CODE_VALID as u8,
}
impl CoapResponseCode {
@@ -433,35 +439,33 @@ impl CoapResponseCode {
/// request code.
pub fn to_raw_pdu_code(self) -> coap_pdu_code_t {
match self {
- CoapResponseCode::Content => coap_pdu_code_t::COAP_RESPONSE_CODE_CONTENT,
- CoapResponseCode::BadGateway => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_GATEWAY,
- CoapResponseCode::Continue => coap_pdu_code_t::COAP_RESPONSE_CODE_CONTINUE,
- CoapResponseCode::Conflict => coap_pdu_code_t::COAP_RESPONSE_CODE_CONFLICT,
- CoapResponseCode::BadRequest => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_REQUEST,
- CoapResponseCode::BadOption => coap_pdu_code_t::COAP_RESPONSE_CODE_BAD_OPTION,
- CoapResponseCode::Changed => coap_pdu_code_t::COAP_RESPONSE_CODE_CHANGED,
- CoapResponseCode::Created => coap_pdu_code_t::COAP_RESPONSE_CODE_CREATED,
- CoapResponseCode::Deleted => coap_pdu_code_t::COAP_RESPONSE_CODE_DELETED,
- CoapResponseCode::Forbidden => coap_pdu_code_t::COAP_RESPONSE_CODE_FORBIDDEN,
- CoapResponseCode::GatewayTimeout => coap_pdu_code_t::COAP_RESPONSE_CODE_GATEWAY_TIMEOUT,
- CoapResponseCode::HopLimitReached => coap_pdu_code_t::COAP_RESPONSE_CODE_HOP_LIMIT_REACHED,
- CoapResponseCode::Incomplete => coap_pdu_code_t::COAP_RESPONSE_CODE_INCOMPLETE,
- CoapResponseCode::InternalError => coap_pdu_code_t::COAP_RESPONSE_CODE_INTERNAL_ERROR,
- CoapResponseCode::NotAcceptable => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ACCEPTABLE,
- CoapResponseCode::NotAllowed => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_ALLOWED,
- CoapResponseCode::NotFound => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_FOUND,
- CoapResponseCode::NotImplemented => coap_pdu_code_t::COAP_RESPONSE_CODE_NOT_IMPLEMENTED,
- CoapResponseCode::PreconditionFailed => coap_pdu_code_t::COAP_RESPONSE_CODE_PRECONDITION_FAILED,
- CoapResponseCode::ProxyingNotSupported => coap_pdu_code_t::COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
- CoapResponseCode::RequestTooLarge => coap_pdu_code_t::COAP_RESPONSE_CODE_REQUEST_TOO_LARGE,
- CoapResponseCode::ServiceUnavailable => coap_pdu_code_t::COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE,
- CoapResponseCode::TooManyRequests => coap_pdu_code_t::COAP_RESPONSE_CODE_TOO_MANY_REQUESTS,
- CoapResponseCode::Unauthorized => coap_pdu_code_t::COAP_RESPONSE_CODE_UNAUTHORIZED,
- CoapResponseCode::Unprocessable => coap_pdu_code_t::COAP_RESPONSE_CODE_UNPROCESSABLE,
- CoapResponseCode::UnsupportedContentFormat => {
- coap_pdu_code_t::COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT
- },
- CoapResponseCode::Valid => coap_pdu_code_t::COAP_RESPONSE_CODE_VALID,
+ CoapResponseCode::Content => coap_pdu_code_t_COAP_RESPONSE_CODE_CONTENT,
+ CoapResponseCode::BadGateway => coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_GATEWAY,
+ CoapResponseCode::Continue => coap_pdu_code_t_COAP_RESPONSE_CODE_CONTINUE,
+ CoapResponseCode::Conflict => coap_pdu_code_t_COAP_RESPONSE_CODE_CONFLICT,
+ CoapResponseCode::BadRequest => coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_REQUEST,
+ CoapResponseCode::BadOption => coap_pdu_code_t_COAP_RESPONSE_CODE_BAD_OPTION,
+ CoapResponseCode::Changed => coap_pdu_code_t_COAP_RESPONSE_CODE_CHANGED,
+ CoapResponseCode::Created => coap_pdu_code_t_COAP_RESPONSE_CODE_CREATED,
+ CoapResponseCode::Deleted => coap_pdu_code_t_COAP_RESPONSE_CODE_DELETED,
+ CoapResponseCode::Forbidden => coap_pdu_code_t_COAP_RESPONSE_CODE_FORBIDDEN,
+ CoapResponseCode::GatewayTimeout => coap_pdu_code_t_COAP_RESPONSE_CODE_GATEWAY_TIMEOUT,
+ CoapResponseCode::HopLimitReached => coap_pdu_code_t_COAP_RESPONSE_CODE_HOP_LIMIT_REACHED,
+ CoapResponseCode::Incomplete => coap_pdu_code_t_COAP_RESPONSE_CODE_INCOMPLETE,
+ CoapResponseCode::InternalError => coap_pdu_code_t_COAP_RESPONSE_CODE_INTERNAL_ERROR,
+ CoapResponseCode::NotAcceptable => coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ACCEPTABLE,
+ CoapResponseCode::NotAllowed => coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_ALLOWED,
+ CoapResponseCode::NotFound => coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_FOUND,
+ CoapResponseCode::NotImplemented => coap_pdu_code_t_COAP_RESPONSE_CODE_NOT_IMPLEMENTED,
+ CoapResponseCode::PreconditionFailed => coap_pdu_code_t_COAP_RESPONSE_CODE_PRECONDITION_FAILED,
+ CoapResponseCode::ProxyingNotSupported => coap_pdu_code_t_COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED,
+ CoapResponseCode::RequestTooLarge => coap_pdu_code_t_COAP_RESPONSE_CODE_REQUEST_TOO_LARGE,
+ CoapResponseCode::ServiceUnavailable => coap_pdu_code_t_COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE,
+ CoapResponseCode::TooManyRequests => coap_pdu_code_t_COAP_RESPONSE_CODE_TOO_MANY_REQUESTS,
+ CoapResponseCode::Unauthorized => coap_pdu_code_t_COAP_RESPONSE_CODE_UNAUTHORIZED,
+ CoapResponseCode::Unprocessable => coap_pdu_code_t_COAP_RESPONSE_CODE_UNPROCESSABLE,
+ CoapResponseCode::UnsupportedContentFormat => coap_pdu_code_t_COAP_RESPONSE_CODE_UNSUPPORTED_CONTENT_FORMAT,
+ CoapResponseCode::Valid => coap_pdu_code_t_COAP_RESPONSE_CODE_VALID,
}
}
}
@@ -497,13 +501,13 @@ impl TryFrom for CoapResponseCode {
#[derive(Copy, Clone, Hash, Eq, PartialEq, FromPrimitive, Debug)]
pub enum CoapMessageType {
/// Confirmable message, i.e. a message whose reception should be confirmed by the peer.
- Con = COAP_MESSAGE_CON as u8,
+ Con = coap_pdu_type_t_COAP_MESSAGE_CON as u8,
/// Non-confirmable message, i.e. a message whose reception should not be confirmed by the peer.
- Non = COAP_MESSAGE_NON as u8,
+ Non = coap_pdu_type_t_COAP_MESSAGE_NON as u8,
/// Acknowledgement for a previous message.
- Ack = COAP_MESSAGE_ACK as u8,
+ Ack = coap_pdu_type_t_COAP_MESSAGE_ACK as u8,
/// Non-acknowledgement for a previous message.
- Rst = COAP_MESSAGE_RST as u8,
+ Rst = coap_pdu_type_t_COAP_MESSAGE_RST as u8,
}
impl CoapMessageType {
@@ -511,10 +515,10 @@ impl CoapMessageType {
/// this message type.
pub fn to_raw_pdu_type(&self) -> coap_pdu_type_t {
match self {
- CoapMessageType::Con => COAP_MESSAGE_CON,
- CoapMessageType::Non => COAP_MESSAGE_NON,
- CoapMessageType::Ack => COAP_MESSAGE_ACK,
- CoapMessageType::Rst => COAP_MESSAGE_RST,
+ CoapMessageType::Con => coap_pdu_type_t_COAP_MESSAGE_CON,
+ CoapMessageType::Non => coap_pdu_type_t_COAP_MESSAGE_NON,
+ CoapMessageType::Ack => coap_pdu_type_t_COAP_MESSAGE_ACK,
+ CoapMessageType::Rst => coap_pdu_type_t_COAP_MESSAGE_RST,
}
}
}
diff --git a/libcoap/src/resource.rs b/libcoap/src/resource.rs
index 6a752b9f..8c01f67f 100644
--- a/libcoap/src/resource.rs
+++ b/libcoap/src/resource.rs
@@ -9,33 +9,29 @@
//! Resource and resource handler descriptions
+use core::ffi::c_int;
use std::{
any::Any,
- cell::Ref,
- cell::RefMut,
+ cell::{Ref, RefMut},
fmt::{Debug, Formatter},
marker::PhantomData,
};
-use libc::c_int;
-
use libcoap_sys::{
- coap_delete_resource, coap_new_str_const, coap_pdu_t, coap_register_request_handler, COAP_RESOURCE_FLAGS_NOTIFY_CON,
- COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RESOURCE_FLAGS_RELEASE_URI, coap_resource_get_uri_path, coap_resource_get_userdata,
- coap_resource_init, coap_resource_notify_observers, coap_resource_set_get_observable, coap_resource_set_mode, coap_resource_set_userdata, coap_resource_t,
- coap_send_rst, coap_session_t, coap_string_t,
+ coap_delete_resource, coap_new_str_const, coap_pdu_t, coap_register_request_handler, coap_resource_get_uri_path,
+ coap_resource_get_userdata, coap_resource_init, coap_resource_notify_observers, coap_resource_set_get_observable,
+ coap_resource_set_mode, coap_resource_set_userdata, coap_resource_t, coap_send_rst, coap_session_t, coap_string_t,
+ COAP_RESOURCE_FLAGS_NOTIFY_CON, COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RESOURCE_FLAGS_RELEASE_URI,
};
-use crate::{error::MessageConversionError, message::CoapMessage, protocol::CoapRequestCode};
-use crate::context::ensure_coap_started;
-use crate::mem::{CoapFfiRcCell, DropInnerExclusively};
-use crate::message::CoapMessageCommon;
-use crate::message::request::CoapRequest;
-use crate::message::response::CoapResponse;
-use crate::protocol::CoapMessageCode;
-use crate::protocol::CoapMessageType;
-use crate::session::CoapServerSession;
-use crate::session::CoapSessionCommon;
+use crate::{
+ context::ensure_coap_started,
+ error::MessageConversionError,
+ mem::{CoapFfiRcCell, DropInnerExclusively},
+ message::{request::CoapRequest, response::CoapResponse, CoapMessage, CoapMessageCommon},
+ protocol::{CoapMessageCode, CoapMessageType, CoapRequestCode},
+ session::{CoapServerSession, CoapSessionCommon},
+};
// Trait aliases are experimental
//trait CoapMethodHandlerFn = FnMut(&D, &mut CoapSession, &CoapRequestMessage, &mut CoapResponseMessage);
diff --git a/libcoap/src/session/client.rs b/libcoap/src/session/client.rs
index 47f241c2..6da6fffc 100644
--- a/libcoap/src/session/client.rs
+++ b/libcoap/src/session/client.rs
@@ -7,28 +7,35 @@
* See the README as well as the LICENSE file for more information.
*/
-use std::cell::{Ref, RefMut};
-use std::net::SocketAddr;
+use std::{
+ cell::{Ref, RefMut},
+ net::SocketAddr,
+};
use libcoap_sys::{
- coap_new_client_session, coap_proto_t, coap_register_event_handler, coap_session_get_app_data,
- coap_session_get_context, coap_session_get_type, coap_session_init_token, coap_session_release,
- coap_session_set_app_data, coap_session_t, coap_session_type_t, COAP_TOKEN_DEFAULT_MAX,
+ coap_new_client_session, coap_proto_t_COAP_PROTO_DTLS, coap_proto_t_COAP_PROTO_TCP, coap_proto_t_COAP_PROTO_UDP,
+ coap_register_event_handler, coap_session_get_app_data, coap_session_get_context, coap_session_get_type,
+ coap_session_init_token, coap_session_release, coap_session_set_app_data, coap_session_t,
+ coap_session_type_t_COAP_SESSION_TYPE_CLIENT, coap_session_type_t_COAP_SESSION_TYPE_HELLO,
+ coap_session_type_t_COAP_SESSION_TYPE_NONE, coap_session_type_t_COAP_SESSION_TYPE_SERVER, COAP_TOKEN_DEFAULT_MAX,
};
use super::{CoapSessionCommon, CoapSessionInner, CoapSessionInnerProvider};
-use crate::event::event_handler_callback;
-use crate::mem::{CoapFfiRcCell, DropInnerExclusively};
-use crate::prng::coap_prng_try_fill;
-use crate::{context::CoapContext, error::SessionCreationError, types::CoapAddress};
-
-#[cfg(dtls)]
+#[cfg(feature = "dtls")]
use crate::crypto::ClientCryptoContext;
+use crate::{
+ context::CoapContext,
+ error::SessionCreationError,
+ event::event_handler_callback,
+ mem::{CoapFfiRcCell, DropInnerExclusively},
+ prng::coap_prng_try_fill,
+ types::CoapAddress,
+};
#[derive(Debug)]
struct CoapClientSessionInner<'a> {
inner: CoapSessionInner<'a>,
- #[cfg(dtls)]
+ #[cfg(feature = "dtls")]
// This field is actually referred to be libcoap, so it isn't actually unused.
#[allow(unused)]
crypto_ctx: Option>,
@@ -53,7 +60,7 @@ impl<'a> CoapClientSessionInner<'a> {
let inner_session = CoapFfiRcCell::new(CoapClientSessionInner {
inner: CoapSessionInner::new(raw_session),
- #[cfg(dtls)]
+ #[cfg(feature = "dtls")]
crypto_ctx: None,
});
@@ -70,7 +77,7 @@ impl<'a> CoapClientSessionInner<'a> {
/// # Safety
/// The provided pointer for `raw_session` must be valid and point to the newly constructed raw
/// session.
- #[cfg(dtls)]
+ #[cfg(feature = "dtls")]
unsafe fn new_with_crypto_ctx(
raw_session: *mut coap_session_t,
crypto_ctx: ClientCryptoContext<'a>,
@@ -100,7 +107,7 @@ impl CoapClientSession<'_> {
/// # Errors
/// Will return a [SessionCreationError] if libcoap was unable to create a session (most likely
/// because it was not possible to bind to a port).
- #[cfg(dtls)]
+ #[cfg(feature = "dtls")]
pub fn connect_dtls<'a>(
ctx: &mut CoapContext<'a>,
addr: SocketAddr,
@@ -115,15 +122,15 @@ impl CoapClientSession<'_> {
match &crypto_ctx {
#[cfg(feature = "dtls-psk")]
ClientCryptoContext::Psk(psk_ctx) => {
- psk_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t::COAP_PROTO_DTLS)?
+ psk_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t_COAP_PROTO_DTLS)?
},
#[cfg(feature = "dtls-pki")]
ClientCryptoContext::Pki(pki_ctx) => {
- pki_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t::COAP_PROTO_DTLS)?
+ pki_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t_COAP_PROTO_DTLS)?
},
#[cfg(feature = "dtls-rpk")]
ClientCryptoContext::Rpk(rpk_ctx) => {
- rpk_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t::COAP_PROTO_DTLS)?
+ rpk_ctx.create_raw_session(ctx, &addr.into(), coap_proto_t_COAP_PROTO_DTLS)?
},
}
};
@@ -149,7 +156,7 @@ impl CoapClientSession<'_> {
ctx.as_mut_raw_context(),
std::ptr::null(),
CoapAddress::from(addr).as_raw_address(),
- coap_proto_t::COAP_PROTO_UDP,
+ coap_proto_t_COAP_PROTO_UDP,
)
};
if session.is_null() {
@@ -176,7 +183,7 @@ impl CoapClientSession<'_> {
ctx.as_mut_raw_context(),
std::ptr::null(),
CoapAddress::from(addr).as_raw_address(),
- coap_proto_t::COAP_PROTO_TCP,
+ coap_proto_t_COAP_PROTO_TCP,
)
};
if session.is_null() {
@@ -208,15 +215,18 @@ impl CoapClientSession<'_> {
pub(crate) unsafe fn from_raw<'a>(raw_session: *mut coap_session_t) -> CoapClientSession<'a> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match raw_session_type {
- coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
- coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
+ coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
+ coap_session_type_t_COAP_SESSION_TYPE_CLIENT => {
let raw_app_data_ptr = coap_session_get_app_data(raw_session);
assert!(!raw_app_data_ptr.is_null(), "provided raw session has no app data");
let inner = CoapFfiRcCell::clone_raw_rc(raw_app_data_ptr);
CoapClientSession { inner }
},
- coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER | coap_session_type_t_COAP_SESSION_TYPE_HELLO => {
panic!("attempted to create CoapClientSession from raw server session")
},
_ => unreachable!("unknown session type"),
@@ -267,6 +277,7 @@ impl<'a> CoapSessionInnerProvider<'a> for CoapClientSession<'a> {
fn inner_ref<'b>(&'b self) -> Ref<'b, CoapSessionInner<'a>> {
Ref::map(self.inner.borrow(), |v| &v.inner)
}
+
fn inner_mut<'b>(&'b self) -> RefMut<'b, CoapSessionInner<'a>> {
RefMut::map(self.inner.borrow_mut(), |v| &mut v.inner)
}
diff --git a/libcoap/src/session/mod.rs b/libcoap/src/session/mod.rs
index 13016e3d..ffb0ac3f 100644
--- a/libcoap/src/session/mod.rs
+++ b/libcoap/src/session/mod.rs
@@ -19,12 +19,17 @@ use std::{
use libcoap_sys::{
coap_context_t, coap_fixed_point_t, coap_mid_t, coap_new_message_id, coap_pdu_get_token, coap_pdu_t,
- coap_response_t, coap_send, coap_session_get_ack_random_factor, coap_session_get_ack_timeout,
- coap_session_get_addr_local, coap_session_get_addr_remote, coap_session_get_ifindex,
- coap_session_get_max_retransmit, coap_session_get_proto, coap_session_get_state, coap_session_get_type,
- coap_session_init_token, coap_session_max_pdu_size, coap_session_new_token, coap_session_send_ping,
- coap_session_set_ack_random_factor, coap_session_set_ack_timeout, coap_session_set_max_retransmit,
- coap_session_set_mtu, coap_session_state_t, coap_session_t, coap_session_type_t,
+ coap_response_t, coap_response_t_COAP_RESPONSE_FAIL, coap_response_t_COAP_RESPONSE_OK, coap_send,
+ coap_session_get_ack_random_factor, coap_session_get_ack_timeout, coap_session_get_addr_local,
+ coap_session_get_addr_remote, coap_session_get_ifindex, coap_session_get_max_retransmit, coap_session_get_proto,
+ coap_session_get_state, coap_session_get_type, coap_session_init_token, coap_session_max_pdu_size,
+ coap_session_new_token, coap_session_send_ping, coap_session_set_ack_random_factor, coap_session_set_ack_timeout,
+ coap_session_set_max_retransmit, coap_session_set_mtu, coap_session_state_t,
+ coap_session_state_t_COAP_SESSION_STATE_CONNECTING, coap_session_state_t_COAP_SESSION_STATE_CSM,
+ coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED, coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE,
+ coap_session_state_t_COAP_SESSION_STATE_NONE, coap_session_t, coap_session_type_t_COAP_SESSION_TYPE_CLIENT,
+ coap_session_type_t_COAP_SESSION_TYPE_HELLO, coap_session_type_t_COAP_SESSION_TYPE_NONE,
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER,
};
#[cfg(feature = "dtls-psk")]
use libcoap_sys::{coap_session_get_psk_hint, coap_session_get_psk_identity, coap_session_get_psk_key};
@@ -45,21 +50,24 @@ pub mod server;
/// Representation of the states that a session can be in.
#[repr(u32)]
pub enum CoapSessionState {
- None = coap_session_state_t::COAP_SESSION_STATE_NONE as u32,
- Connecting = coap_session_state_t::COAP_SESSION_STATE_CONNECTING as u32,
- Handshake = coap_session_state_t::COAP_SESSION_STATE_HANDSHAKE as u32,
- Csm = coap_session_state_t::COAP_SESSION_STATE_CSM as u32,
- Established = coap_session_state_t::COAP_SESSION_STATE_ESTABLISHED as u32,
+ None = coap_session_state_t_COAP_SESSION_STATE_NONE as u32,
+ Connecting = coap_session_state_t_COAP_SESSION_STATE_CONNECTING as u32,
+ Handshake = coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE as u32,
+ Csm = coap_session_state_t_COAP_SESSION_STATE_CSM as u32,
+ Established = coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED as u32,
}
impl From for CoapSessionState {
fn from(raw_state: coap_session_state_t) -> Self {
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match raw_state {
- coap_session_state_t::COAP_SESSION_STATE_NONE => CoapSessionState::None,
- coap_session_state_t::COAP_SESSION_STATE_CONNECTING => CoapSessionState::Connecting,
- coap_session_state_t::COAP_SESSION_STATE_HANDSHAKE => CoapSessionState::Handshake,
- coap_session_state_t::COAP_SESSION_STATE_CSM => CoapSessionState::Csm,
- coap_session_state_t::COAP_SESSION_STATE_ESTABLISHED => CoapSessionState::Established,
+ coap_session_state_t_COAP_SESSION_STATE_NONE => CoapSessionState::None,
+ coap_session_state_t_COAP_SESSION_STATE_CONNECTING => CoapSessionState::Connecting,
+ coap_session_state_t_COAP_SESSION_STATE_HANDSHAKE => CoapSessionState::Handshake,
+ coap_session_state_t_COAP_SESSION_STATE_CSM => CoapSessionState::Csm,
+ coap_session_state_t_COAP_SESSION_STATE_ESTABLISHED => CoapSessionState::Established,
_ => unreachable!("unknown session state added"),
}
}
@@ -112,7 +120,7 @@ pub trait CoapSessionCommon<'a>: CoapSessionCommonInternal<'a> {
}
/// Sets the application-specific data stored alongside this session.
- fn set_app_data(&self, value: Option) {
+ fn set_app_data(&self, value: Option) {
let mut inner = self.inner_mut();
let new_box: Option> = value.map(|v| Rc::new(v) as Rc);
inner.app_data = new_box;
@@ -447,12 +455,16 @@ impl<'a> CoapSession<'a> {
pub(crate) unsafe fn from_raw(raw_session: *mut coap_session_t) -> CoapSession<'a> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
+
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match raw_session_type {
- coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
+ coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
- coap_session_type_t::COAP_SESSION_TYPE_CLIENT => CoapClientSession::from_raw(raw_session).into(),
+ coap_session_type_t_COAP_SESSION_TYPE_CLIENT => CoapClientSession::from_raw(raw_session).into(),
- coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER | coap_session_type_t_COAP_SESSION_TYPE_HELLO => {
CoapServerSession::from_raw(raw_session).into()
},
_ => unreachable!("unknown session type"),
@@ -542,7 +554,6 @@ impl CoapRequestHandle {
}
// This is fine, we don't read the C-type struct, we return it.
-#[allow(improper_ctypes_definitions)]
pub(crate) unsafe extern "C" fn session_response_handler(
session: *mut coap_session_t,
_sent: *const coap_pdu_t,
@@ -555,12 +566,12 @@ pub(crate) unsafe extern "C" fn session_response_handler(
let raw_token = coap_pdu_get_token(received);
let token: CoapToken = CoapToken::from(std::slice::from_raw_parts(raw_token.s, raw_token.length));
if !client.is_waiting_for_token(&token) {
- return coap_response_t::COAP_RESPONSE_FAIL;
+ return coap_response_t_COAP_RESPONSE_FAIL;
}
if let Ok(message) = CoapMessage::from_raw_pdu(received).and_then(CoapResponse::from_message) {
client.add_response(message);
- coap_response_t::COAP_RESPONSE_OK
+ coap_response_t_COAP_RESPONSE_OK
} else {
- coap_response_t::COAP_RESPONSE_FAIL
+ coap_response_t_COAP_RESPONSE_FAIL
}
}
diff --git a/libcoap/src/session/server.rs b/libcoap/src/session/server.rs
index 29335e58..9177648a 100644
--- a/libcoap/src/session/server.rs
+++ b/libcoap/src/session/server.rs
@@ -11,7 +11,9 @@ use std::cell::{Ref, RefMut};
use libcoap_sys::{
coap_session_get_app_data, coap_session_get_type, coap_session_reference, coap_session_release,
- coap_session_set_app_data, coap_session_t, coap_session_type_t,
+ coap_session_set_app_data, coap_session_t, coap_session_type_t_COAP_SESSION_TYPE_CLIENT,
+ coap_session_type_t_COAP_SESSION_TYPE_HELLO, coap_session_type_t_COAP_SESSION_TYPE_NONE,
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER,
};
use super::{CoapSessionCommon, CoapSessionInner, CoapSessionInnerProvider};
@@ -65,13 +67,16 @@ impl CoapServerSession<'_> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
let inner = CoapSessionInner::new(raw_session);
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
let session_inner = match raw_session_type {
- coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
- coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
+ coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
+ coap_session_type_t_COAP_SESSION_TYPE_CLIENT => {
panic!("attempted to create server session from raw client session")
},
- coap_session_type_t::COAP_SESSION_TYPE_SERVER => CoapServerSessionInner { inner },
- coap_session_type_t::COAP_SESSION_TYPE_HELLO => CoapServerSessionInner { inner },
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER => CoapServerSessionInner { inner },
+ coap_session_type_t_COAP_SESSION_TYPE_HELLO => CoapServerSessionInner { inner },
_ => unreachable!("unknown session type"),
};
let session_ref = CoapFfiRcCell::new(session_inner);
@@ -139,9 +144,12 @@ impl CoapServerSession<'_> {
pub(crate) unsafe fn from_raw_without_refcount<'a>(raw_session: *mut coap_session_t) -> CoapServerSession<'a> {
assert!(!raw_session.is_null(), "provided raw session was null");
let raw_session_type = coap_session_get_type(raw_session);
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
match raw_session_type {
- coap_session_type_t::COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
- coap_session_type_t::COAP_SESSION_TYPE_SERVER | coap_session_type_t::COAP_SESSION_TYPE_HELLO => {
+ coap_session_type_t_COAP_SESSION_TYPE_NONE => panic!("provided session has no type"),
+ coap_session_type_t_COAP_SESSION_TYPE_SERVER | coap_session_type_t_COAP_SESSION_TYPE_HELLO => {
let raw_app_data_ptr = coap_session_get_app_data(raw_session);
assert!(!raw_app_data_ptr.is_null(), "provided raw session has no app data");
CoapServerSession {
@@ -149,7 +157,7 @@ impl CoapServerSession<'_> {
ref_counted: false,
}
},
- coap_session_type_t::COAP_SESSION_TYPE_CLIENT => {
+ coap_session_type_t_COAP_SESSION_TYPE_CLIENT => {
panic!("attempted to create CoapServerSession from raw client session")
},
_ => unreachable!("unknown session type"),
diff --git a/libcoap/src/types.rs b/libcoap/src/types.rs
index 9967c799..4ac83f27 100644
--- a/libcoap/src/types.rs
+++ b/libcoap/src/types.rs
@@ -9,41 +9,35 @@
//! Types required for conversion between libcoap C library abstractions and Rust types.
-use std::ffi::CString;
-use std::fmt::{Display, Formatter};
-use std::marker::PhantomPinned;
-use std::pin::Pin;
+use core::ffi::c_ushort;
use std::{
- fmt::Debug,
+ ffi::{CStr, CString},
+ fmt::{Debug, Display, Formatter},
+ marker::PhantomPinned,
mem::MaybeUninit,
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs},
os::raw::c_int,
+ pin::Pin,
str::FromStr,
};
-use libc::{c_ushort, in6_addr, in_addr, sa_family_t, sockaddr_in, sockaddr_in6, socklen_t, AF_INET, AF_INET6};
+use libcoap_sys::{
+ c_stdlib::{in6_addr, in_addr, sa_family_t, sockaddr_in, sockaddr_in6, socklen_t, AF_INET, AF_INET6},
+ coap_address_t, coap_delete_optlist, coap_mid_t, coap_proto_t, coap_proto_t_COAP_PROTO_DTLS,
+ coap_proto_t_COAP_PROTO_NONE, coap_proto_t_COAP_PROTO_TCP, coap_proto_t_COAP_PROTO_TLS,
+ coap_proto_t_COAP_PROTO_UDP, coap_split_proxy_uri, coap_split_uri, coap_str_const_t, coap_string_equal,
+ coap_uri_into_optlist, coap_uri_scheme_t, coap_uri_scheme_t_COAP_URI_SCHEME_COAP,
+ coap_uri_scheme_t_COAP_URI_SCHEME_COAPS, coap_uri_scheme_t_COAP_URI_SCHEME_COAPS_TCP,
+ coap_uri_scheme_t_COAP_URI_SCHEME_COAPS_WS, coap_uri_scheme_t_COAP_URI_SCHEME_COAP_TCP,
+ coap_uri_scheme_t_COAP_URI_SCHEME_COAP_WS, coap_uri_scheme_t_COAP_URI_SCHEME_HTTP,
+ coap_uri_scheme_t_COAP_URI_SCHEME_HTTPS, coap_uri_t, COAP_URI_SCHEME_SECURE_MASK,
+};
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
#[cfg(feature = "url")]
use url::Url;
-use libcoap_sys::coap_uri_scheme_t::{COAP_URI_SCHEME_COAPS_WS, COAP_URI_SCHEME_COAP_WS};
-use libcoap_sys::{
- coap_address_t, coap_delete_optlist, coap_mid_t, coap_proto_t,
- coap_proto_t::{COAP_PROTO_DTLS, COAP_PROTO_NONE, COAP_PROTO_TCP, COAP_PROTO_TLS, COAP_PROTO_UDP},
- coap_split_proxy_uri, coap_split_uri, coap_str_const_t, coap_string_equal, coap_uri_into_options,
- coap_uri_scheme_t,
- coap_uri_scheme_t::{
- COAP_URI_SCHEME_COAP, COAP_URI_SCHEME_COAPS, COAP_URI_SCHEME_COAPS_TCP, COAP_URI_SCHEME_COAP_TCP,
- COAP_URI_SCHEME_HTTP, COAP_URI_SCHEME_HTTPS,
- },
- coap_uri_t, COAP_URI_SCHEME_SECURE_MASK,
-};
-
-use crate::context::ensure_coap_started;
-use crate::error::UriParsingError;
-use crate::message::CoapOption;
-use crate::protocol::UriPort;
+use crate::{context::ensure_coap_started, error::UriParsingError, message::CoapOption, protocol::UriPort};
/// Interface index used internally by libcoap to refer to an endpoint.
pub type IfIndex = c_int;
@@ -92,11 +86,11 @@ impl ToSocketAddrs for CoapAddress {
// SAFETY: That the underlying value of addr is a valid sockaddr is an invariant, the only
// way the value could be invalid is if as_mut_coap_address_t() (an unsafe function) is used
// incorrectly.
- let socketaddr = match unsafe { self.0.addr.sa.as_ref().sa_family } as i32 {
+ let socketaddr = match unsafe { self.0.addr.sa.sa_family as _ } {
AF_INET => {
// SAFETY: Validity of addr is an invariant, and we checked that the type of the
// underlying sockaddr is actually sockaddr_in.
- let raw_addr = unsafe { self.0.addr.sin.as_ref() };
+ let raw_addr = unsafe { self.0.addr.sin };
SocketAddrV4::new(
Ipv4Addr::from(raw_addr.sin_addr.s_addr.to_ne_bytes()),
u16::from_be(raw_addr.sin_port),
@@ -106,9 +100,17 @@ impl ToSocketAddrs for CoapAddress {
AF_INET6 => {
// SAFETY: Validity of addr is an invariant, and we checked that the type of the
// underlying sockaddr is actually sockaddr_in6.
- let raw_addr = unsafe { self.0.addr.sin6.as_ref() };
+ let raw_addr = unsafe { self.0.addr.sin6 };
+
+ // The esp_idf_sys definition of sockaddr_in6 differs slightly.
+ #[cfg(not(target_os = "espidf"))]
+ let raw_addr_bytes = raw_addr.sin6_addr.s6_addr;
+ #[cfg(target_os = "espidf")]
+ // SAFETY: Both representations are valid.
+ let raw_addr_bytes = unsafe { raw_addr.sin6_addr.un.u8_addr };
+
SocketAddrV6::new(
- Ipv6Addr::from(raw_addr.sin6_addr.s6_addr),
+ Ipv6Addr::from(raw_addr_bytes),
u16::from_be(raw_addr.sin6_port),
raw_addr.sin6_flowinfo,
raw_addr.sin6_scope_id,
@@ -135,7 +137,7 @@ impl From for CoapAddress {
addr: std::mem::zeroed(),
};
- *coap_addr.addr.sin.as_mut() = sockaddr_in {
+ coap_addr.addr.sin = sockaddr_in {
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
@@ -167,7 +169,9 @@ impl From for CoapAddress {
addr: std::mem::zeroed(),
};
- *coap_addr.addr.sin6.as_mut() = sockaddr_in6 {
+ // Representation of sockaddr_in6 differs depending on the used OS, therefore
+ // some fields are a bit different.
+ coap_addr.addr.sin6 = sockaddr_in6 {
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
@@ -182,7 +186,12 @@ impl From for CoapAddress {
sin6_family: AF_INET6 as sa_family_t,
sin6_port: addr.port().to_be(),
sin6_addr: in6_addr {
+ #[cfg(not(target_os = "espidf"))]
s6_addr: addr.ip().octets(),
+ #[cfg(target_os = "espidf")]
+ un: libcoap_sys::c_stdlib::in6_addr__bindgen_ty_1 {
+ u8_addr: addr.ip().octets(),
+ },
},
sin6_flowinfo: addr.flowinfo(),
sin6_scope_id: addr.scope_id(),
@@ -217,14 +226,14 @@ impl From<&coap_address_t> for CoapAddress {
#[repr(u32)]
#[derive(Copy, Clone, FromPrimitive, Debug, PartialEq, Eq, Hash)]
pub enum CoapUriScheme {
- Coap = COAP_URI_SCHEME_COAP as u32,
- Coaps = COAP_URI_SCHEME_COAPS as u32,
- CoapTcp = COAP_URI_SCHEME_COAP_TCP as u32,
- CoapsTcp = COAP_URI_SCHEME_COAPS_TCP as u32,
- Http = COAP_URI_SCHEME_HTTP as u32,
- Https = COAP_URI_SCHEME_HTTPS as u32,
- CoapWs = COAP_URI_SCHEME_COAP_WS as u32,
- CoapsWs = COAP_URI_SCHEME_COAPS_WS as u32,
+ Coap = coap_uri_scheme_t_COAP_URI_SCHEME_COAP as u32,
+ Coaps = coap_uri_scheme_t_COAP_URI_SCHEME_COAPS as u32,
+ CoapTcp = coap_uri_scheme_t_COAP_URI_SCHEME_COAP_TCP as u32,
+ CoapsTcp = coap_uri_scheme_t_COAP_URI_SCHEME_COAPS_TCP as u32,
+ Http = coap_uri_scheme_t_COAP_URI_SCHEME_HTTP as u32,
+ Https = coap_uri_scheme_t_COAP_URI_SCHEME_HTTPS as u32,
+ CoapWs = coap_uri_scheme_t_COAP_URI_SCHEME_COAP_WS as u32,
+ CoapsWs = coap_uri_scheme_t_COAP_URI_SCHEME_COAPS_WS as u32,
}
impl CoapUriScheme {
@@ -589,48 +598,12 @@ impl CoapUri {
// TODO this is a lot of copying around, however, fixing that would require an entire
// rewrite of the option handling code, so it's better kept for a separate PR.
- // Set size of temporary buffer for option storage.
- // TODO remove when updating minimum libcoap version to 4.3.5, as this buffer is no longer
- // used there.
- #[cfg(coap_uri_buf_unused)]
- let mut buf = [];
- #[cfg(not(coap_uri_buf_unused))]
- let mut buf = {
- let buf_len =
- // Length of UriHost option (length of host + max. 5 bytes of option header)
- self.host().map(|v| v.len()+5).unwrap_or(0)
- // Length of UriPort option (max. 2 bytes for the port number + max. 5 bytes of
- // option header)
- + self.port().map(|v| 7).unwrap_or(0)
- // Length of path segment
- + self.path().map(|v| v.len()).unwrap_or(0)
- // Length of option headers for path segments.
- // Each path segment has its own header, which can be up to 5 bytes in size.
- + self.path().map(|v| (v.iter().filter(|c| **c as char == '/').count()+1)*5).unwrap_or(0)
- // Length of query segment
- + self.query().map(|v| v.len()).unwrap_or(0)
- // Length of option headers for query segments.
- // Each query segment has its own header, which can be up to 5 bytes in size.
- + self.query().map(|v| (v.iter().filter(|c| **c as char == '?' || **c as char == '&').count()+1)*5).unwrap_or(0);
- vec![0u8; buf_len]
- };
-
let mut optlist = std::ptr::null_mut();
// SAFETY: self.raw_uri is always valid after construction. The destination may be a null
// pointer, optlist may be a null pointer at the start (it will be set to a valid
// pointer by this call). Buf and create_port_host_opt are set according to the
// libcoap documentation.
- if unsafe {
- coap_uri_into_options(
- &self.raw_uri,
- std::ptr::null(),
- &mut optlist,
- 1,
- buf.as_mut_ptr(),
- buf.len(),
- )
- } < 0
- {
+ if unsafe { coap_uri_into_optlist(&self.raw_uri, std::ptr::null(), &mut optlist, 1) } < 0 {
// We have already parsed this URI. If converting it into options fails, something went
// terribly wrong.
panic!("could not convert valid coap URI into options");
@@ -749,7 +722,7 @@ impl CoapUri {
length: 0,
s: std::ptr::null(),
},
- scheme: coap_uri_scheme_t::COAP_URI_SCHEME_COAP,
+ scheme: coap_uri_scheme_t_COAP_URI_SCHEME_COAP,
},
uri_str,
is_proxy,
@@ -776,7 +749,7 @@ impl CoapUri {
if unsafe {
parsing_fn(
uri.uri_str.0.as_ptr() as *const u8,
- libc::strlen(uri.uri_str.0.as_ptr()),
+ CStr::from_ptr(uri.uri_str.0.as_ptr()).count_bytes(),
std::ptr::from_mut(&mut uri.raw_uri),
)
} < 0
@@ -833,10 +806,10 @@ impl PartialEq for CoapUri {
// corresponding parts of the underlying string, which is pinned. Therefore, the
// pointer and length are valid for the lifetime of this struct.
&& unsafe {
- coap_string_equal!(&self.raw_uri.host, &other.raw_uri.host)
- && coap_string_equal!(&self.raw_uri.path, &other.raw_uri.path)
- && coap_string_equal!(&self.raw_uri.query, &other.raw_uri.query)
- }
+ coap_string_equal!(&self.raw_uri.host, &other.raw_uri.host)
+ && coap_string_equal!(&self.raw_uri.path, &other.raw_uri.path)
+ && coap_string_equal!(&self.raw_uri.query, &other.raw_uri.query)
+ }
}
}
@@ -878,11 +851,11 @@ impl Display for CoapUri {
#[non_exhaustive]
#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq, Hash)]
pub enum CoapProtocol {
- None = COAP_PROTO_NONE as u32,
- Udp = COAP_PROTO_UDP as u32,
- Dtls = COAP_PROTO_DTLS as u32,
- Tcp = COAP_PROTO_TCP as u32,
- Tls = COAP_PROTO_TLS as u32,
+ None = coap_proto_t_COAP_PROTO_NONE as u32,
+ Udp = coap_proto_t_COAP_PROTO_UDP as u32,
+ Dtls = coap_proto_t_COAP_PROTO_DTLS as u32,
+ Tcp = coap_proto_t_COAP_PROTO_TCP as u32,
+ Tls = coap_proto_t_COAP_PROTO_TLS as u32,
}
impl CoapProtocol {
diff --git a/libcoap/src/wrapper.h b/libcoap/src/wrapper.h
new file mode 120000
index 00000000..762e29fb
--- /dev/null
+++ b/libcoap/src/wrapper.h
@@ -0,0 +1 @@
+../../libcoap-sys/src/wrapper.h
\ No newline at end of file
diff --git a/libcoap/tests/common/dtls.rs b/libcoap/tests/common/dtls.rs
index 138ab58f..b572df40 100644
--- a/libcoap/tests/common/dtls.rs
+++ b/libcoap/tests/common/dtls.rs
@@ -1,14 +1,23 @@
-use crate::common;
-use libcoap_rs::crypto::pki_rpk::{
- KeyDef, KeyType, NonCertVerifying, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext,
+use std::{ffi::CStr, path::PathBuf, time::Duration};
+
+use libcoap_rs::{
+ crypto::{
+ pki_rpk::{KeyDef, KeyType, NonCertVerifying, PkiRpkContext, PkiRpkContextBuilder, ServerPkiRpkCryptoContext},
+ ClientCryptoContext,
+ },
+ message::CoapMessageCommon,
+ protocol::{CoapMessageCode, CoapResponseCode},
+ session::{CoapClientSession, CoapSessionCommon},
+ CoapContext,
+};
+use libcoap_sys::{
+ coap_get_tls_library_version, coap_package_version, coap_tls_library_t_COAP_TLS_LIBRARY_GNUTLS,
+ coap_tls_library_t_COAP_TLS_LIBRARY_MBEDTLS, coap_tls_library_t_COAP_TLS_LIBRARY_NOTLS,
+ coap_tls_library_t_COAP_TLS_LIBRARY_OPENSSL, coap_tls_library_t_COAP_TLS_LIBRARY_TINYDTLS,
+ coap_tls_library_t_COAP_TLS_LIBRARY_WOLFSSL,
};
-use libcoap_rs::crypto::ClientCryptoContext;
-use libcoap_rs::message::CoapMessageCommon;
-use libcoap_rs::protocol::{CoapMessageCode, CoapResponseCode};
-use libcoap_rs::session::{CoapClientSession, CoapSessionCommon};
-use libcoap_rs::CoapContext;
-use std::path::PathBuf;
-use std::time::Duration;
+
+use crate::common;
// Is used in some test cases, but not in others (causing a compiler warning)
#[allow(unused)]
@@ -23,6 +32,24 @@ pub fn dtls_client_server_request_common(
ServerPkiRpkCryptoContext<'static>: From>,
ClientCryptoContext<'static>: From>,
{
+ // Variant names are named by bindgen, we have no influence on this.
+ // Ref: https://github.com/rust-lang/rust/issues/39371
+ #[allow(non_upper_case_globals)]
+ let tls_library = match unsafe { *coap_get_tls_library_version() }.type_ {
+ coap_tls_library_t_COAP_TLS_LIBRARY_NOTLS => "notls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_TINYDTLS => "tinydtls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_OPENSSL => "openssl",
+ coap_tls_library_t_COAP_TLS_LIBRARY_GNUTLS => "gnutls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_MBEDTLS => "mbedtls",
+ coap_tls_library_t_COAP_TLS_LIBRARY_WOLFSSL => "wolfssl",
+ _ => "unknown",
+ };
+ println!(
+ "Libcoap-Version: {}, DTLS library: {}",
+ unsafe { CStr::from_ptr(coap_package_version()) }.to_string_lossy(),
+ tls_library
+ );
+
let server_address = common::get_unused_server_addr();
let client_crypto_ctx = client_ctx_setup(PkiRpkContextBuilder::<'static, KTY, NonCertVerifying>::new(client_key));
let server_handle = common::spawn_test_server(move |mut context: CoapContext| {
diff --git a/libcoap/tests/common/mod.rs b/libcoap/tests/common/mod.rs
index af109b34..02934c35 100644
--- a/libcoap/tests/common/mod.rs
+++ b/libcoap/tests/common/mod.rs
@@ -10,18 +10,24 @@
#[cfg(any(feature = "dtls-pki", feature = "dtls-rpk"))]
pub mod dtls;
-use std::net::{SocketAddr, UdpSocket};
-use std::rc::Rc;
-use std::sync::{Arc, Condvar, Mutex};
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::thread::JoinHandle;
-use std::time::Duration;
+use std::{
+ net::{SocketAddr, UdpSocket},
+ rc::Rc,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc, Condvar, Mutex,
+ },
+ thread::JoinHandle,
+ time::Duration,
+};
-use libcoap_rs::{CoapContext, CoapRequestHandler, CoapResource};
-use libcoap_rs::message::{CoapMessageCommon, CoapRequest, CoapResponse};
-use libcoap_rs::protocol::{CoapMessageCode, CoapMessageType, CoapRequestCode, CoapResponseCode};
-use libcoap_rs::session::CoapSessionCommon;
-use libcoap_sys::{coap_dtls_set_log_level, coap_log_t, coap_set_log_level};
+use libcoap_rs::{
+ message::{CoapMessageCommon, CoapRequest, CoapResponse},
+ protocol::{CoapMessageCode, CoapMessageType, CoapRequestCode, CoapResponseCode},
+ session::CoapSessionCommon,
+ CoapContext, CoapRequestHandler, CoapResource,
+};
+use libcoap_sys::{coap_dtls_set_log_level, coap_log_t_COAP_LOG_DEBUG, coap_set_log_level};
pub(crate) fn get_unused_server_addr() -> SocketAddr {
// This will give us a SocketAddress with a port in the local port range automatically
@@ -51,25 +57,40 @@ pub(crate) fn spawn_test_server) -> CoapContext<'
let ready_condition = Arc::new((Mutex::new(false), Condvar::new()));
let ready_condition2 = Arc::clone(&ready_condition);
- let server_handle = std::thread::spawn(move || {
- let (ready_var, ready_cond) = &*ready_condition2;
- run_test_server(|context| {
- let context = context_configurator(context);
- let mut ready_var = ready_var.lock().expect("ready condition mutex is poisoned");
- *ready_var = true;
- ready_cond.notify_all();
- context
- });
- });
+ let server_handle = std::thread::Builder::new()
+ .name(String::from("test server"))
+ .spawn(move || {
+ let (ready_var, ready_cond) = &*ready_condition2;
+ run_test_server(|context| {
+ let context = context_configurator(context);
+ let mut ready_var = ready_var.lock().expect("ready condition mutex is poisoned");
+ *ready_var = true;
+ ready_cond.notify_all();
+ context
+ });
+ })
+ .expect("unable to spawn test server thread");
let (ready_var, ready_cond) = &*ready_condition;
- drop(
- ready_cond
- .wait_while(ready_var.lock().expect("ready condition mutex is poisoned"), |ready| {
- !*ready
- })
- .expect("ready condition mutex is poisoned"),
- );
+ {
+ let (_guard, timeout_result) = ready_cond
+ .wait_timeout_while(
+ ready_var.lock().expect("ready condition mutex is poisoned"),
+ Duration::from_secs(10),
+ |ready| !*ready,
+ )
+ .expect("ready condition mutex is poisoned");
+ if timeout_result.timed_out() && server_handle.is_finished() {
+ if let Err(e) = server_handle.join() {
+ std::panic::resume_unwind(e);
+ }
+ panic!("Test server thread is dead and has not reported readiness after 10 seconds, but has also not panicked.")
+ }
+
+ if timeout_result.timed_out() {
+ panic!("Test server thread has not reported readiness after 10 seconds, but has also not died (deadlock?).")
+ }
+ }
server_handle
}
@@ -77,8 +98,8 @@ pub(crate) fn spawn_test_server) -> CoapContext<'
pub(crate) fn run_test_server) -> CoapContext<'static>>(context_configurator: F) {
unsafe {
libcoap_sys::coap_startup_with_feature_checks();
- coap_dtls_set_log_level(coap_log_t::COAP_LOG_DEBUG);
- coap_set_log_level(coap_log_t::COAP_LOG_DEBUG);
+ coap_dtls_set_log_level(coap_log_t_COAP_LOG_DEBUG);
+ coap_set_log_level(coap_log_t_COAP_LOG_DEBUG);
}
let mut context = CoapContext::new().unwrap();
context = context_configurator(context);
diff --git a/libcoap/tests/dtls_pki_client_server_test.rs b/libcoap/tests/dtls_pki_client_server_test.rs
index bc97761f..3f834e1e 100644
--- a/libcoap/tests/dtls_pki_client_server_test.rs
+++ b/libcoap/tests/dtls_pki_client_server_test.rs
@@ -9,11 +9,14 @@
#![cfg(feature = "dtls-pki")]
-use crate::common::dtls::dtls_client_server_request_common;
-use libcoap_rs::crypto::pki_rpk::{Asn1PrivateKeyType, DerFileKeyComponent, NonCertVerifying, PkiRpkContextBuilder};
-use libcoap_rs::crypto::pki_rpk::{Pki, PkiKeyDef};
use std::path::PathBuf;
+use libcoap_rs::crypto::pki_rpk::{
+ Asn1PrivateKeyType, DerFileKeyComponent, NonCertVerifying, Pki, PkiKeyDef, PkiRpkContextBuilder,
+};
+
+use crate::common::dtls::dtls_client_server_request_common;
+
mod common;
#[test]
@@ -75,9 +78,9 @@ pub fn dtls_pki_asn1_file_client_server_request() {
// For some inexplicable reason, setting the CA cert fails _only_ with ASN1 files using the
// OpenSSL library.
// I'm pretty sure this is a libcoap issue, so we'll not set the CA cert there for now.
- #[cfg(not(feature = "dtls_openssl"))]
+ #[cfg(not(dtls_backend = "openssl"))]
Some(key_storage.join("./ca/ca.crt.der")),
- #[cfg(feature = "dtls_openssl")]
+ #[cfg(dtls_backend = "openssl")]
None::,
key_storage.join("./server/server.crt.der"),
key_storage.join("./server/server.key.der"),
@@ -93,7 +96,7 @@ pub fn dtls_pki_asn1_file_client_server_request() {
#[test]
// GnuTLS does not like DER-encoded EC keys from memory (for some reason. Loading them from files as
// done in the test above works fine).
-#[cfg(not(feature = "dtls_gnutls"))]
+#[cfg_attr(dtls_backend = "gnutls", ignore)]
pub fn dtls_pki_asn1_memory_client_server_request() {
const DER_CA_CERT: &[u8] = include_bytes!("../resources/test-keys/ca/ca.crt.der");
const DER_CLIENT_PUBLIC_CERT: &[u8] = include_bytes!("../resources/test-keys/client/client.crt.der");
diff --git a/libcoap/tests/dtls_psk_client_server_test.rs b/libcoap/tests/dtls_psk_client_server_test.rs
index 757e9612..a19dcacf 100644
--- a/libcoap/tests/dtls_psk_client_server_test.rs
+++ b/libcoap/tests/dtls_psk_client_server_test.rs
@@ -10,13 +10,11 @@
#![cfg(feature = "dtls-psk")]
use std::time::Duration;
-use libcoap_rs::crypto::psk::PskKey;
-use libcoap_rs::crypto::psk::{ClientPskContextBuilder, ServerPskContextBuilder};
-use libcoap_rs::session::CoapClientSession;
use libcoap_rs::{
+ crypto::psk::{ClientPskContextBuilder, PskKey, ServerPskContextBuilder},
message::CoapMessageCommon,
protocol::{CoapMessageCode, CoapResponseCode},
- session::CoapSessionCommon,
+ session::{CoapClientSession, CoapSessionCommon},
CoapContext,
};
diff --git a/libcoap/tests/dtls_rpk_client_server_test.rs b/libcoap/tests/dtls_rpk_client_server_test.rs
index 5ed48495..7ca64b04 100644
--- a/libcoap/tests/dtls_rpk_client_server_test.rs
+++ b/libcoap/tests/dtls_rpk_client_server_test.rs
@@ -9,9 +9,9 @@
#![cfg(feature = "dtls-rpk")]
+use libcoap_rs::crypto::pki_rpk::{NonCertVerifying, PkiRpkContextBuilder, Rpk, RpkKeyDef};
+
use crate::common::dtls::dtls_client_server_request_common;
-use libcoap_rs::crypto::pki_rpk::{NonCertVerifying, PkiRpkContextBuilder};
-use libcoap_rs::crypto::pki_rpk::{Rpk, RpkKeyDef};
mod common;
diff --git a/libcoap/tests/tcp_client_server_test.rs b/libcoap/tests/tcp_client_server_test.rs
index e5a64258..fe9b8a5b 100644
--- a/libcoap/tests/tcp_client_server_test.rs
+++ b/libcoap/tests/tcp_client_server_test.rs
@@ -6,16 +6,16 @@
* Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved.
* See the README as well as the LICENSE file for more information.
*/
- #![cfg(feature = "tcp")]
+#![cfg(feature = "tcp")]
+
+use std::time::Duration;
-use libcoap_rs::session::CoapClientSession;
use libcoap_rs::{
message::CoapMessageCommon,
protocol::{CoapMessageCode, CoapResponseCode},
- session::CoapSessionCommon,
+ session::{CoapClientSession, CoapSessionCommon},
CoapContext,
};
-use std::time::Duration;
mod common;
diff --git a/libcoap/tests/udp_client_server_test.rs b/libcoap/tests/udp_client_server_test.rs
index c3d9d27e..21226193 100644
--- a/libcoap/tests/udp_client_server_test.rs
+++ b/libcoap/tests/udp_client_server_test.rs
@@ -7,14 +7,14 @@
* See the README as well as the LICENSE file for more information.
*/
-use libcoap_rs::session::CoapClientSession;
+use std::time::Duration;
+
use libcoap_rs::{
message::CoapMessageCommon,
protocol::{CoapMessageCode, CoapResponseCode},
- session::CoapSessionCommon,
+ session::{CoapClientSession, CoapSessionCommon},
CoapContext,
};
-use std::time::Duration;
mod common;