alpine_protocol_sdk/
simulator.rs1use 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}