Skip to main content

kipuka/config/
coap.rs

1//! CoAP transport configuration (RFC 9483).
2//!
3//! The `[coap]` section enables EST over CoAP with DTLS for
4//! constrained device enrollment.  When enabled, the server
5//! listens on a UDP port (default 5684 for DTLS) in addition
6//! to the primary HTTP/TLS listener.
7
8use serde::Deserialize;
9
10/// `[coap]` section — CoAP transport for constrained devices.
11///
12/// ```toml
13/// [coap]
14/// enabled = true
15/// listen_addr = "0.0.0.0:5684"
16/// dtls_enabled = true
17/// block_size = 512
18/// max_payload = 65536
19/// session_timeout_secs = 300
20/// max_sessions = 1024
21/// ```
22#[derive(Debug, Clone, Deserialize)]
23#[serde(deny_unknown_fields)]
24pub struct CoapConfig {
25    /// Enable the CoAP transport listener.
26    #[serde(default)]
27    pub enabled: bool,
28
29    /// UDP listen address for CoAP/DTLS.
30    #[serde(default = "default_coap_listen_addr")]
31    pub listen_addr: String,
32
33    /// Enable DTLS for the CoAP listener.
34    #[serde(default = "default_true")]
35    pub dtls_enabled: bool,
36
37    /// CoAP block-wise transfer size in bytes (64, 128, 256, 512, 1024).
38    #[serde(default = "default_block_size")]
39    pub block_size: u16,
40
41    /// Maximum reassembled payload size in bytes.
42    #[serde(default = "default_max_payload")]
43    pub max_payload: usize,
44
45    /// DTLS session timeout for constrained device resumption.
46    #[serde(default = "default_session_timeout_secs")]
47    pub session_timeout_secs: u64,
48
49    /// Maximum number of concurrent DTLS sessions.
50    #[serde(default = "default_max_sessions")]
51    pub max_sessions: usize,
52}
53
54fn default_coap_listen_addr() -> String {
55    "0.0.0.0:5684".to_string()
56}
57
58fn default_true() -> bool {
59    true
60}
61
62fn default_block_size() -> u16 {
63    512
64}
65
66fn default_max_payload() -> usize {
67    65536
68}
69
70fn default_session_timeout_secs() -> u64 {
71    300
72}
73
74fn default_max_sessions() -> usize {
75    1024
76}
77
78impl Default for CoapConfig {
79    fn default() -> Self {
80        Self {
81            enabled: false,
82            listen_addr: default_coap_listen_addr(),
83            dtls_enabled: true,
84            block_size: default_block_size(),
85            max_payload: default_max_payload(),
86            session_timeout_secs: default_session_timeout_secs(),
87            max_sessions: default_max_sessions(),
88        }
89    }
90}
91
92impl CoapConfig {
93    /// Validate CoAP configuration constraints.
94    pub fn validate(&self) -> Result<(), String> {
95        const VALID_BLOCK_SIZES: &[u16] = &[16, 32, 64, 128, 256, 512, 1024];
96        if !VALID_BLOCK_SIZES.contains(&self.block_size) {
97            return Err(format!(
98                "[coap].block_size must be one of {:?}, got {}",
99                VALID_BLOCK_SIZES, self.block_size
100            ));
101        }
102
103        if self.max_payload == 0 {
104            return Err("[coap].max_payload must be greater than 0".into());
105        }
106
107        Ok(())
108    }
109}