Skip to main content

xds_server/
utils.rs

1//! Shared utilities for xds-server.
2
3use std::sync::atomic::{AtomicU64, Ordering};
4use std::time::{SystemTime, UNIX_EPOCH};
5
6/// Global counter for generating unique nonces.
7static NONCE_COUNTER: AtomicU64 = AtomicU64::new(0);
8
9/// Generate a unique nonce for xDS responses.
10///
11/// Nonces are used to correlate requests and responses in xDS protocol.
12/// They combine a timestamp with an atomic counter to ensure uniqueness
13/// even under high concurrency.
14///
15/// # Format
16///
17/// The nonce format is `{timestamp_hex}-{counter_hex}` for SotW protocol
18/// or `d{timestamp_hex}-{counter_hex}` for Delta protocol.
19///
20/// # Example
21///
22/// ```
23/// use xds_server::utils::{generate_nonce, NoncePrefix};
24///
25/// let nonce = generate_nonce(NoncePrefix::SotW);
26/// // e.g., "18c5a3b2f1-0"
27///
28/// let delta_nonce = generate_nonce(NoncePrefix::Delta);
29/// // e.g., "d18c5a3b2f1-1"
30/// # assert!(nonce.contains('-'));
31/// # assert!(delta_nonce.starts_with('d'));
32/// ```
33pub fn generate_nonce(prefix: NoncePrefix) -> String {
34    let timestamp = SystemTime::now()
35        .duration_since(UNIX_EPOCH)
36        .unwrap_or_default()
37        .as_nanos() as u64;
38
39    let count = NONCE_COUNTER.fetch_add(1, Ordering::Relaxed);
40
41    match prefix {
42        NoncePrefix::SotW => format!("{:x}-{:x}", timestamp, count),
43        NoncePrefix::Delta => format!("d{:x}-{:x}", timestamp, count),
44    }
45}
46
47/// Prefix for nonce generation.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum NoncePrefix {
50    /// State-of-the-World protocol (no prefix).
51    SotW,
52    /// Delta protocol (prefixed with 'd').
53    Delta,
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn nonce_unique() {
62        let n1 = generate_nonce(NoncePrefix::SotW);
63        let n2 = generate_nonce(NoncePrefix::SotW);
64        assert_ne!(n1, n2, "nonces should be unique");
65    }
66
67    #[test]
68    fn nonce_format_sotw() {
69        let nonce = generate_nonce(NoncePrefix::SotW);
70        assert!(nonce.contains('-'), "nonce should contain separator");
71        assert!(!nonce.starts_with('d'), "SotW nonce should not start with 'd'");
72    }
73
74    #[test]
75    fn nonce_format_delta() {
76        let nonce = generate_nonce(NoncePrefix::Delta);
77        assert!(nonce.starts_with('d'), "Delta nonce should start with 'd'");
78        assert!(nonce.contains('-'), "nonce should contain separator");
79    }
80}