Skip to main content

alpine_protocol_sdk/
simulator.rs

1use std::io;
2use std::net::SocketAddr;
3
4use alpine::messages::{CapabilitySet, DiscoveryReply, MessageType};
5use serde_json::json;
6use tokio::net::UdpSocket;
7use tokio::task::JoinHandle;
8
9#[derive(Debug, Clone, Copy)]
10pub enum BadDeviceScenario {
11    DropPackets,
12    InvalidCbor,
13    VendorOnlyStatus,
14}
15
16#[derive(Debug)]
17pub struct BadDeviceSimulator {
18    local_addr: SocketAddr,
19    handle: JoinHandle<()>,
20}
21
22impl BadDeviceSimulator {
23    pub async fn start(
24        bind_addr: SocketAddr,
25        scenario: BadDeviceScenario,
26    ) -> Result<Self, io::Error> {
27        let socket = UdpSocket::bind(bind_addr).await?;
28        let local_addr = socket.local_addr()?;
29        let handle = tokio::spawn(async move {
30            let mut buf = vec![0u8; 2048];
31            loop {
32                let (len, peer) = match socket.recv_from(&mut buf).await {
33                    Ok(res) => res,
34                    Err(_) => continue,
35                };
36                if len == 0 {
37                    continue;
38                }
39                match scenario {
40                    BadDeviceScenario::DropPackets => {}
41                    BadDeviceScenario::InvalidCbor => {
42                        let _ = socket.send_to(&[0xff, 0x00, 0x01], peer).await;
43                    }
44                    BadDeviceScenario::VendorOnlyStatus => {
45                        let mut caps = CapabilitySet::default();
46                        caps.vendor_extensions = Some(
47                            json!({
48                                "vendor_only_status": true
49                            })
50                            .as_object()
51                            .unwrap()
52                            .iter()
53                            .map(|(k, v)| (k.clone(), v.clone()))
54                            .collect(),
55                        );
56                        let reply = DiscoveryReply {
57                            message_type: MessageType::AlpineDiscoverReply,
58                            alpine_version: alpine::messages::ALPINE_VERSION.to_string(),
59                            device_id: "bad-device".to_string(),
60                            manufacturer_id: "vendor-only".to_string(),
61                            model_id: "sim".to_string(),
62                            hardware_rev: "0".to_string(),
63                            firmware_rev: "0".to_string(),
64                            mac: "00:00:00:00:00:00".to_string(),
65                            server_nonce: vec![0u8; 32],
66                            capabilities: caps,
67                            signature: vec![0u8; 64],
68                            device_identity_pubkey: Vec::new(),
69                            device_identity_attestation: Vec::new(),
70                            device_identity_trusted: false,
71                        };
72                        if let Ok(payload) = serde_cbor::to_vec(&reply) {
73                            let _ = socket.send_to(&payload, peer).await;
74                        }
75                    }
76                }
77            }
78        });
79        Ok(Self { local_addr, handle })
80    }
81
82    pub fn local_addr(&self) -> SocketAddr {
83        self.local_addr
84    }
85
86    pub async fn stop(self) {
87        self.handle.abort();
88    }
89}