1use super::connection::{ConnectionConfig, ConnectionEvent, ConstrainedConnection};
15use super::header::ConstrainedPacket;
16use super::state::ConnectionState;
17use super::types::{ConnectionId, ConstrainedError};
18use std::collections::HashMap;
19use std::net::SocketAddr;
20use std::time::{Duration, Instant};
21
22#[derive(Debug, Clone)]
24pub struct EngineConfig {
25 pub max_connections: usize,
27 pub connection_config: ConnectionConfig,
29 pub poll_interval: Duration,
31 pub enable_connection_reuse: bool,
33}
34
35impl Default for EngineConfig {
36 fn default() -> Self {
37 Self {
38 max_connections: 8,
39 connection_config: ConnectionConfig::default(),
40 poll_interval: Duration::from_millis(100),
41 enable_connection_reuse: true,
42 }
43 }
44}
45
46impl EngineConfig {
47 pub fn for_ble() -> Self {
49 Self {
50 max_connections: 4,
51 connection_config: ConnectionConfig::for_ble(),
52 poll_interval: Duration::from_millis(50),
53 enable_connection_reuse: true,
54 }
55 }
56
57 pub fn for_lora() -> Self {
59 Self {
60 max_connections: 2,
61 connection_config: ConnectionConfig::for_lora(),
62 poll_interval: Duration::from_millis(500),
63 enable_connection_reuse: true,
64 }
65 }
66}
67
68#[derive(Debug, Clone)]
70pub enum EngineEvent {
71 ConnectionAccepted {
73 connection_id: ConnectionId,
75 remote_addr: SocketAddr,
77 },
78 ConnectionEstablished {
80 connection_id: ConnectionId,
82 },
83 DataReceived {
85 connection_id: ConnectionId,
87 data: Vec<u8>,
89 },
90 ConnectionClosed {
92 connection_id: ConnectionId,
94 },
95 ConnectionError {
97 connection_id: ConnectionId,
99 error: String,
101 },
102 Transmit {
104 remote_addr: SocketAddr,
106 packet: Vec<u8>,
108 },
109}
110
111#[derive(Debug)]
115pub struct ConstrainedEngine {
116 config: EngineConfig,
118 connections: HashMap<ConnectionId, ConstrainedConnection>,
120 addr_to_conn: HashMap<SocketAddr, ConnectionId>,
122 events: Vec<EngineEvent>,
124 next_conn_id: u16,
126 last_poll: Instant,
128}
129
130impl ConstrainedEngine {
131 pub fn new(config: EngineConfig) -> Self {
133 Self {
134 config,
135 connections: HashMap::new(),
136 addr_to_conn: HashMap::new(),
137 events: Vec::new(),
138 next_conn_id: 1,
139 last_poll: Instant::now(),
140 }
141 }
142
143 pub fn with_defaults() -> Self {
145 Self::new(EngineConfig::default())
146 }
147
148 pub fn connection_count(&self) -> usize {
150 self.connections.len()
151 }
152
153 pub fn can_accept_connection(&self) -> bool {
155 self.connections.len() < self.config.max_connections
156 }
157
158 fn generate_conn_id(&mut self) -> ConnectionId {
160 let id = ConnectionId::new(self.next_conn_id);
161 self.next_conn_id = self.next_conn_id.wrapping_add(1);
162 if self.next_conn_id == 0 {
163 self.next_conn_id = 1;
164 }
165 id
166 }
167
168 pub fn connect(
172 &mut self,
173 remote_addr: SocketAddr,
174 ) -> Result<(ConnectionId, Vec<u8>), ConstrainedError> {
175 if !self.can_accept_connection() {
176 return Err(ConstrainedError::SendBufferFull);
177 }
178
179 if self.addr_to_conn.contains_key(&remote_addr) {
181 return Err(ConstrainedError::ConnectionExists(
182 *self
183 .addr_to_conn
184 .get(&remote_addr)
185 .unwrap_or(&ConnectionId::new(0)),
186 ));
187 }
188
189 let conn_id = self.generate_conn_id();
190 let mut conn = ConstrainedConnection::new_outbound_with_config(
191 conn_id,
192 remote_addr,
193 self.config.connection_config.clone(),
194 );
195
196 let syn_packet = conn.initiate()?;
197 let packet_bytes = syn_packet.to_bytes();
198
199 self.connections.insert(conn_id, conn);
200 self.addr_to_conn.insert(remote_addr, conn_id);
201
202 Ok((conn_id, packet_bytes))
203 }
204
205 pub fn process_incoming(
209 &mut self,
210 remote_addr: SocketAddr,
211 data: &[u8],
212 ) -> Result<Vec<(SocketAddr, Vec<u8>)>, ConstrainedError> {
213 let packet = ConstrainedPacket::from_bytes(data)?;
214 let header = &packet.header;
215 let mut responses = Vec::new();
216
217 if let Some(conn) = self.connections.get_mut(&header.connection_id) {
219 conn.process_packet(&packet)?;
220
221 while let Some(event) = conn.next_event() {
223 match event {
224 ConnectionEvent::Connected => {
225 self.events.push(EngineEvent::ConnectionEstablished {
226 connection_id: header.connection_id,
227 });
228 }
229 ConnectionEvent::DataReceived(_) => {
230 }
232 ConnectionEvent::Closed => {
233 self.events.push(EngineEvent::ConnectionClosed {
234 connection_id: header.connection_id,
235 });
236 }
237 ConnectionEvent::Reset => {
238 self.events.push(EngineEvent::ConnectionClosed {
239 connection_id: header.connection_id,
240 });
241 }
242 ConnectionEvent::Error(err) => {
243 self.events.push(EngineEvent::ConnectionError {
244 connection_id: header.connection_id,
245 error: err,
246 });
247 }
248 ConnectionEvent::Transmit(data) => {
249 responses.push((remote_addr, data));
250 }
251 }
252 }
253
254 let packets = conn.poll();
256 for pkt in packets {
257 responses.push((remote_addr, pkt.to_bytes()));
258 }
259 } else if header.is_syn() && !header.is_ack() {
260 if !self.can_accept_connection() {
262 let rst = super::header::ConstrainedHeader::reset(header.connection_id);
264 responses.push((
265 remote_addr,
266 super::header::ConstrainedPacket::control(rst).to_bytes(),
267 ));
268 return Ok(responses);
269 }
270
271 let mut conn = ConstrainedConnection::new_inbound_with_config(
272 header.connection_id,
273 remote_addr,
274 self.config.connection_config.clone(),
275 );
276
277 let syn_ack = conn.accept(header.seq)?;
278 responses.push((remote_addr, syn_ack.to_bytes()));
279
280 self.connections.insert(header.connection_id, conn);
281 self.addr_to_conn.insert(remote_addr, header.connection_id);
282
283 self.events.push(EngineEvent::ConnectionAccepted {
284 connection_id: header.connection_id,
285 remote_addr,
286 });
287 }
288 Ok(responses)
291 }
292
293 pub fn send(
295 &mut self,
296 connection_id: ConnectionId,
297 data: &[u8],
298 ) -> Result<Vec<(SocketAddr, Vec<u8>)>, ConstrainedError> {
299 let conn = self
300 .connections
301 .get_mut(&connection_id)
302 .ok_or(ConstrainedError::ConnectionNotFound(connection_id))?;
303
304 conn.send(data)?;
305
306 let remote_addr = conn.remote_addr();
307 let packets = conn.poll();
308
309 Ok(packets
310 .into_iter()
311 .map(|p| (remote_addr, p.to_bytes()))
312 .collect())
313 }
314
315 pub fn recv(&mut self, connection_id: ConnectionId) -> Option<Vec<u8>> {
317 self.connections.get_mut(&connection_id)?.recv()
318 }
319
320 pub fn close(
322 &mut self,
323 connection_id: ConnectionId,
324 ) -> Result<Vec<(SocketAddr, Vec<u8>)>, ConstrainedError> {
325 let conn = self
326 .connections
327 .get_mut(&connection_id)
328 .ok_or(ConstrainedError::ConnectionNotFound(connection_id))?;
329
330 let fin = conn.close()?;
331 let remote_addr = conn.remote_addr();
332
333 Ok(vec![(remote_addr, fin.to_bytes())])
334 }
335
336 pub fn reset(
338 &mut self,
339 connection_id: ConnectionId,
340 ) -> Result<Vec<(SocketAddr, Vec<u8>)>, ConstrainedError> {
341 let conn = self
342 .connections
343 .get_mut(&connection_id)
344 .ok_or(ConstrainedError::ConnectionNotFound(connection_id))?;
345
346 let rst = conn.reset();
347 let remote_addr = conn.remote_addr();
348
349 self.connections.remove(&connection_id);
351 self.addr_to_conn.retain(|_, id| *id != connection_id);
352
353 Ok(vec![(remote_addr, rst.to_bytes())])
354 }
355
356 pub fn poll(&mut self) -> Vec<(SocketAddr, Vec<u8>)> {
360 let now = Instant::now();
361 if now.duration_since(self.last_poll) < self.config.poll_interval {
362 return Vec::new();
363 }
364 self.last_poll = now;
365
366 let mut responses = Vec::new();
367 let mut to_remove = Vec::new();
368
369 for (conn_id, conn) in &mut self.connections {
370 let packets = conn.poll();
372 let remote_addr = conn.remote_addr();
373
374 for pkt in packets {
375 responses.push((remote_addr, pkt.to_bytes()));
376 }
377
378 while let Some(event) = conn.next_event() {
380 match event {
381 ConnectionEvent::Closed | ConnectionEvent::Reset => {
382 to_remove.push(*conn_id);
383 self.events.push(EngineEvent::ConnectionClosed {
384 connection_id: *conn_id,
385 });
386 }
387 ConnectionEvent::Error(err) => {
388 to_remove.push(*conn_id);
389 self.events.push(EngineEvent::ConnectionError {
390 connection_id: *conn_id,
391 error: err,
392 });
393 }
394 _ => {}
395 }
396 }
397
398 if conn.is_closed() {
400 to_remove.push(*conn_id);
401 }
402 }
403
404 for conn_id in to_remove {
406 if let Some(conn) = self.connections.remove(&conn_id) {
407 self.addr_to_conn.remove(&conn.remote_addr());
408 }
409 }
410
411 responses
412 }
413
414 pub fn next_event(&mut self) -> Option<EngineEvent> {
416 if self.events.is_empty() {
417 None
418 } else {
419 Some(self.events.remove(0))
420 }
421 }
422
423 pub fn has_connection(&self, connection_id: ConnectionId) -> bool {
425 self.connections.contains_key(&connection_id)
426 }
427
428 pub fn connection_for_addr(&self, addr: &SocketAddr) -> Option<ConnectionId> {
430 self.addr_to_conn.get(addr).copied()
431 }
432
433 pub fn active_connections(&self) -> Vec<ConnectionId> {
435 self.connections.keys().copied().collect()
436 }
437
438 pub fn connection_state(&self, connection_id: ConnectionId) -> Option<ConnectionState> {
440 self.connections.get(&connection_id).map(|c| c.state())
441 }
442}
443
444#[cfg(test)]
445mod tests {
446 use super::*;
447 use std::net::{IpAddr, Ipv4Addr};
448
449 fn test_addr(port: u16) -> SocketAddr {
450 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port)
451 }
452
453 #[test]
454 fn test_engine_new() {
455 let engine = ConstrainedEngine::with_defaults();
456 assert_eq!(engine.connection_count(), 0);
457 assert!(engine.can_accept_connection());
458 }
459
460 #[test]
461 fn test_engine_connect() {
462 let mut engine = ConstrainedEngine::with_defaults();
463 let (conn_id, packet) = engine.connect(test_addr(8080)).expect("connect");
464
465 assert_eq!(engine.connection_count(), 1);
466 assert!(engine.has_connection(conn_id));
467 assert!(!packet.is_empty());
468
469 let pkt = ConstrainedPacket::from_bytes(&packet).expect("parse");
471 assert!(pkt.header.is_syn());
472 assert!(!pkt.header.is_ack());
473 }
474
475 #[test]
476 fn test_engine_connect_duplicate() {
477 let mut engine = ConstrainedEngine::with_defaults();
478 let addr = test_addr(8080);
479
480 engine.connect(addr).expect("first connect");
481 let result = engine.connect(addr);
482
483 assert!(result.is_err());
484 }
485
486 #[test]
487 fn test_engine_max_connections() {
488 let config = EngineConfig {
489 max_connections: 2,
490 ..Default::default()
491 };
492 let mut engine = ConstrainedEngine::new(config);
493
494 engine.connect(test_addr(8080)).expect("connect 1");
495 engine.connect(test_addr(8081)).expect("connect 2");
496
497 let result = engine.connect(test_addr(8082));
499 assert!(result.is_err());
500 }
501
502 #[test]
503 fn test_engine_accept_connection() {
504 let mut engine = ConstrainedEngine::with_defaults();
505
506 let syn = ConstrainedPacket::control(super::super::header::ConstrainedHeader::syn(
508 ConnectionId::new(0x1234),
509 ));
510
511 let responses = engine
512 .process_incoming(test_addr(8080), &syn.to_bytes())
513 .expect("process SYN");
514
515 assert_eq!(responses.len(), 1);
517 let syn_ack = ConstrainedPacket::from_bytes(&responses[0].1).expect("parse");
518 assert!(syn_ack.header.is_syn_ack());
519
520 let event = engine.next_event();
522 assert!(matches!(
523 event,
524 Some(EngineEvent::ConnectionAccepted { .. })
525 ));
526 }
527
528 #[test]
529 fn test_engine_handshake() {
530 let mut initiator = ConstrainedEngine::with_defaults();
531 let mut responder = ConstrainedEngine::with_defaults();
532
533 let initiator_addr = test_addr(8080);
534 let responder_addr = test_addr(9090);
535
536 let (conn_id, syn_packet) = initiator.connect(responder_addr).expect("connect");
538
539 let responses = responder
541 .process_incoming(initiator_addr, &syn_packet)
542 .expect("process SYN");
543 assert_eq!(responses.len(), 1);
544
545 let responses = initiator
547 .process_incoming(responder_addr, &responses[0].1)
548 .expect("process SYN-ACK");
549
550 assert!(!responses.is_empty());
552
553 let event = initiator.next_event();
555 assert!(
556 matches!(event, Some(EngineEvent::ConnectionEstablished { connection_id }) if connection_id == conn_id)
557 );
558 }
559
560 #[test]
561 fn test_engine_config_for_ble() {
562 let config = EngineConfig::for_ble();
563 assert_eq!(config.max_connections, 4);
564 assert_eq!(config.connection_config.mss, 235);
565 }
566
567 #[test]
568 fn test_engine_config_for_lora() {
569 let config = EngineConfig::for_lora();
570 assert_eq!(config.max_connections, 2);
571 assert_eq!(config.connection_config.mss, 50);
572 }
573
574 #[test]
575 fn test_engine_close_not_found() {
576 let mut engine = ConstrainedEngine::with_defaults();
577
578 let result = engine.close(ConnectionId::new(0x9999));
580 assert!(result.is_err());
581 assert!(matches!(
582 result,
583 Err(ConstrainedError::ConnectionNotFound(_))
584 ));
585 }
586
587 #[test]
588 fn test_engine_reset() {
589 let mut engine = ConstrainedEngine::with_defaults();
590 let (conn_id, _) = engine.connect(test_addr(8080)).expect("connect");
591
592 let responses = engine.reset(conn_id).expect("reset");
593
594 assert_eq!(responses.len(), 1);
595 let rst = ConstrainedPacket::from_bytes(&responses[0].1).expect("parse");
596 assert!(rst.header.is_rst());
597
598 assert!(!engine.has_connection(conn_id));
600 }
601
602 #[test]
603 fn test_engine_poll() {
604 let mut engine = ConstrainedEngine::with_defaults();
605 engine.connect(test_addr(8080)).expect("connect");
606
607 let _ = engine.poll();
609 }
610
611 #[test]
612 fn test_engine_active_connections() {
613 let mut engine = ConstrainedEngine::with_defaults();
614 let (id1, _) = engine.connect(test_addr(8080)).expect("connect 1");
615 let (id2, _) = engine.connect(test_addr(8081)).expect("connect 2");
616
617 let active = engine.active_connections();
618 assert_eq!(active.len(), 2);
619 assert!(active.contains(&id1));
620 assert!(active.contains(&id2));
621 }
622}