Skip to main content

ant_quic/constrained/
adapter.rs

1// Copyright 2024 Saorsa Labs Ltd.
2//
3// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
4// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
5//
6// Full details available at https://saorsalabs.com/licenses
7
8//! Engine Adapter for Transport Integration
9//!
10//! This module provides the adapter layer that connects the constrained protocol engine
11//! to transport providers. It abstracts the engine interface for easy integration.
12
13use super::engine::{ConstrainedEngine, EngineConfig, EngineEvent};
14use super::state::ConnectionState;
15use super::types::{ConnectionId, ConstrainedAddr, ConstrainedError};
16use crate::transport::TransportAddr;
17use std::net::SocketAddr;
18
19/// Output from the engine to be transmitted
20#[derive(Debug, Clone)]
21pub struct EngineOutput {
22    /// Destination address
23    pub destination: TransportAddr,
24    /// Packet data to send
25    pub data: Vec<u8>,
26}
27
28impl EngineOutput {
29    /// Create a new engine output
30    pub fn new(destination: TransportAddr, data: Vec<u8>) -> Self {
31        Self { destination, data }
32    }
33}
34
35/// Adapter that wraps ConstrainedEngine for transport integration
36///
37/// This provides a transport-agnostic interface for the constrained engine,
38/// handling address translation between `TransportAddr` and `SocketAddr`.
39#[derive(Debug)]
40pub struct ConstrainedEngineAdapter {
41    /// The underlying engine
42    engine: ConstrainedEngine,
43    /// Mapping from TransportAddr to internal SocketAddr
44    /// (for non-UDP transports that need a synthetic address)
45    addr_map: std::collections::HashMap<TransportAddr, SocketAddr>,
46    /// Reverse mapping from SocketAddr to TransportAddr
47    reverse_map: std::collections::HashMap<SocketAddr, TransportAddr>,
48    /// Next synthetic address counter (for BLE/LoRa)
49    next_synthetic: u32,
50}
51
52impl ConstrainedEngineAdapter {
53    /// Create a new adapter with the given configuration
54    pub fn new(config: EngineConfig) -> Self {
55        Self {
56            engine: ConstrainedEngine::new(config),
57            addr_map: std::collections::HashMap::new(),
58            reverse_map: std::collections::HashMap::new(),
59            next_synthetic: 1,
60        }
61    }
62
63    /// Create adapter with BLE configuration
64    pub fn for_ble() -> Self {
65        Self::new(EngineConfig::for_ble())
66    }
67
68    /// Create adapter with LoRa configuration
69    pub fn for_lora() -> Self {
70        Self::new(EngineConfig::for_lora())
71    }
72
73    /// Get or create a synthetic SocketAddr for a TransportAddr
74    ///
75    /// For non-UDP transports (BLE, LoRa, etc.), we create a synthetic
76    /// SocketAddr that maps to the real transport address.
77    fn get_or_create_socket_addr(&mut self, addr: &TransportAddr) -> SocketAddr {
78        if let TransportAddr::Udp(socket_addr) = addr {
79            // UDP addresses can be used directly
80            return *socket_addr;
81        }
82
83        // For other transports, use existing mapping or create new synthetic address
84        if let Some(socket_addr) = self.addr_map.get(addr) {
85            return *socket_addr;
86        }
87
88        // Create synthetic address in the 127.x.x.x range
89        let ip = std::net::Ipv4Addr::new(
90            127,
91            ((self.next_synthetic >> 16) & 0xFF) as u8,
92            ((self.next_synthetic >> 8) & 0xFF) as u8,
93            (self.next_synthetic & 0xFF) as u8,
94        );
95        let socket_addr = SocketAddr::new(
96            std::net::IpAddr::V4(ip),
97            (self.next_synthetic % 65535) as u16,
98        );
99        self.next_synthetic += 1;
100
101        self.addr_map.insert(addr.clone(), socket_addr);
102        self.reverse_map.insert(socket_addr, addr.clone());
103
104        socket_addr
105    }
106
107    /// Convert a SocketAddr back to TransportAddr
108    fn socket_to_transport(&self, socket_addr: &SocketAddr) -> TransportAddr {
109        self.reverse_map
110            .get(socket_addr)
111            .cloned()
112            .unwrap_or(TransportAddr::Udp(*socket_addr))
113    }
114
115    /// Initiate a connection to a remote address
116    pub fn connect(
117        &mut self,
118        remote: &TransportAddr,
119    ) -> Result<(ConnectionId, Vec<EngineOutput>), ConstrainedError> {
120        let socket_addr = self.get_or_create_socket_addr(remote);
121        let (conn_id, packet) = self.engine.connect(socket_addr)?;
122        let output = EngineOutput::new(remote.clone(), packet);
123        Ok((conn_id, vec![output]))
124    }
125
126    /// Process an incoming packet from a transport
127    pub fn process_incoming(
128        &mut self,
129        source: &TransportAddr,
130        data: &[u8],
131    ) -> Result<Vec<EngineOutput>, ConstrainedError> {
132        let socket_addr = self.get_or_create_socket_addr(source);
133        let responses = self.engine.process_incoming(socket_addr, data)?;
134
135        Ok(responses
136            .into_iter()
137            .map(|(addr, packet)| {
138                let dest = self.socket_to_transport(&addr);
139                EngineOutput::new(dest, packet)
140            })
141            .collect())
142    }
143
144    /// Send data on an established connection
145    pub fn send(
146        &mut self,
147        connection_id: ConnectionId,
148        data: &[u8],
149    ) -> Result<Vec<EngineOutput>, ConstrainedError> {
150        let responses = self.engine.send(connection_id, data)?;
151
152        Ok(responses
153            .into_iter()
154            .map(|(addr, packet)| {
155                let dest = self.socket_to_transport(&addr);
156                EngineOutput::new(dest, packet)
157            })
158            .collect())
159    }
160
161    /// Receive data from a connection (if available)
162    pub fn recv(&mut self, connection_id: ConnectionId) -> Option<Vec<u8>> {
163        self.engine.recv(connection_id)
164    }
165
166    /// Close a connection
167    pub fn close(
168        &mut self,
169        connection_id: ConnectionId,
170    ) -> Result<Vec<EngineOutput>, ConstrainedError> {
171        let responses = self.engine.close(connection_id)?;
172
173        Ok(responses
174            .into_iter()
175            .map(|(addr, packet)| {
176                let dest = self.socket_to_transport(&addr);
177                EngineOutput::new(dest, packet)
178            })
179            .collect())
180    }
181
182    /// Poll for timeouts and retransmissions
183    pub fn poll(&mut self) -> Vec<EngineOutput> {
184        let responses = self.engine.poll();
185
186        responses
187            .into_iter()
188            .map(|(addr, packet)| {
189                let dest = self.socket_to_transport(&addr);
190                EngineOutput::new(dest, packet)
191            })
192            .collect()
193    }
194
195    /// Get the next event from the engine
196    pub fn next_event(&mut self) -> Option<AdapterEvent> {
197        self.engine.next_event().map(|event| match event {
198            EngineEvent::ConnectionAccepted {
199                connection_id,
200                remote_addr,
201            } => {
202                let addr = self.socket_to_transport(&remote_addr);
203                AdapterEvent::ConnectionAccepted {
204                    connection_id,
205                    remote_addr: ConstrainedAddr::new(addr),
206                }
207            }
208            EngineEvent::ConnectionEstablished { connection_id } => {
209                AdapterEvent::ConnectionEstablished { connection_id }
210            }
211            EngineEvent::DataReceived {
212                connection_id,
213                data,
214            } => AdapterEvent::DataReceived {
215                connection_id,
216                data,
217            },
218            EngineEvent::ConnectionClosed { connection_id } => {
219                AdapterEvent::ConnectionClosed { connection_id }
220            }
221            EngineEvent::ConnectionError {
222                connection_id,
223                error,
224            } => AdapterEvent::ConnectionError {
225                connection_id,
226                error,
227            },
228            EngineEvent::Transmit {
229                remote_addr,
230                packet,
231            } => {
232                let addr = self.socket_to_transport(&remote_addr);
233                AdapterEvent::Transmit {
234                    destination: addr,
235                    packet,
236                }
237            }
238        })
239    }
240
241    /// Get the number of active connections
242    pub fn connection_count(&self) -> usize {
243        self.engine.connection_count()
244    }
245
246    /// Get the underlying engine (for advanced use)
247    pub fn engine(&self) -> &ConstrainedEngine {
248        &self.engine
249    }
250
251    /// Get mutable access to the underlying engine
252    pub fn engine_mut(&mut self) -> &mut ConstrainedEngine {
253        &mut self.engine
254    }
255
256    /// Get the state of a specific connection
257    pub fn connection_state(&self, connection_id: ConnectionId) -> Option<ConnectionState> {
258        self.engine.connection_state(connection_id)
259    }
260
261    /// Get all active connection IDs
262    pub fn active_connections(&self) -> Vec<ConnectionId> {
263        self.engine.active_connections()
264    }
265}
266
267/// Events from the adapter (transport-agnostic)
268#[derive(Debug, Clone)]
269pub enum AdapterEvent {
270    /// New incoming connection accepted
271    ConnectionAccepted {
272        /// Connection ID
273        connection_id: ConnectionId,
274        /// Remote address
275        remote_addr: ConstrainedAddr,
276    },
277    /// Outbound connection established
278    ConnectionEstablished {
279        /// Connection ID
280        connection_id: ConnectionId,
281    },
282    /// Data received on a connection
283    DataReceived {
284        /// Connection ID
285        connection_id: ConnectionId,
286        /// The data
287        data: Vec<u8>,
288    },
289    /// Connection closed
290    ConnectionClosed {
291        /// Connection ID
292        connection_id: ConnectionId,
293    },
294    /// Connection error
295    ConnectionError {
296        /// Connection ID
297        connection_id: ConnectionId,
298        /// Error message
299        error: String,
300    },
301    /// Packet ready to transmit
302    Transmit {
303        /// Destination address
304        destination: TransportAddr,
305        /// Packet data
306        packet: Vec<u8>,
307    },
308}
309
310#[cfg(test)]
311mod tests {
312    use super::*;
313
314    #[test]
315    fn test_adapter_creation() {
316        let adapter = ConstrainedEngineAdapter::for_ble();
317        assert_eq!(adapter.connection_count(), 0);
318    }
319
320    #[test]
321    fn test_adapter_connect_udp() {
322        let mut adapter = ConstrainedEngineAdapter::for_ble();
323        let addr = TransportAddr::Udp("192.168.1.100:8080".parse().unwrap());
324
325        let result = adapter.connect(&addr);
326        assert!(result.is_ok());
327
328        let (_conn_id, outputs) = result.unwrap();
329        assert_eq!(outputs.len(), 1);
330        assert_eq!(outputs[0].destination, addr);
331        assert!(!outputs[0].data.is_empty());
332        assert_eq!(adapter.connection_count(), 1);
333    }
334
335    #[test]
336    fn test_adapter_connect_ble() {
337        let mut adapter = ConstrainedEngineAdapter::for_ble();
338        let addr = TransportAddr::Ble {
339            device_id: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
340            service_uuid: None,
341        };
342
343        let result = adapter.connect(&addr);
344        assert!(result.is_ok());
345
346        let (_conn_id, outputs) = result.unwrap();
347        assert_eq!(outputs.len(), 1);
348        // For BLE, the destination should be preserved
349        assert_eq!(outputs[0].destination, addr);
350        assert!(!outputs[0].data.is_empty());
351    }
352
353    #[test]
354    fn test_adapter_synthetic_address_reuse() {
355        let mut adapter = ConstrainedEngineAdapter::for_ble();
356        let addr = TransportAddr::Ble {
357            device_id: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
358            service_uuid: None,
359        };
360
361        // Get synthetic address twice - should be the same
362        let socket1 = adapter.get_or_create_socket_addr(&addr);
363        let socket2 = adapter.get_or_create_socket_addr(&addr);
364        assert_eq!(socket1, socket2);
365    }
366
367    #[test]
368    fn test_adapter_different_addresses() {
369        let mut adapter = ConstrainedEngineAdapter::for_ble();
370
371        let addr1 = TransportAddr::Ble {
372            device_id: [0x11, 0x22, 0x33, 0x44, 0x55, 0x66],
373            service_uuid: None,
374        };
375        let addr2 = TransportAddr::Ble {
376            device_id: [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF],
377            service_uuid: None,
378        };
379
380        let socket1 = adapter.get_or_create_socket_addr(&addr1);
381        let socket2 = adapter.get_or_create_socket_addr(&addr2);
382
383        // Different BLE devices should get different synthetic addresses
384        assert_ne!(socket1, socket2);
385    }
386
387    #[test]
388    fn test_adapter_poll() {
389        let mut adapter = ConstrainedEngineAdapter::for_ble();
390
391        // Poll should return empty when no connections
392        let outputs = adapter.poll();
393        assert!(outputs.is_empty());
394    }
395}