1use std::collections::HashMap;
5use std::net::SocketAddr;
6use std::sync::{Arc, Mutex};
7use std::time::{Duration, Instant};
8
9use coap_lite::{CoapOption, MessageClass, MessageType, Packet, RequestType, ResponseType};
10use pamoja_core::{topic_matches, Error, Message, Receive, Result, Transport};
11use tokio::net::UdpSocket;
12use tokio::sync::mpsc;
13use tokio::task::JoinHandle;
14
15use crate::{observe_value, path_from_packet, random};
16
17const EXCHANGE_LIFETIME: Duration = Duration::from_secs(247);
21
22const DATAGRAM: usize = 1500;
25
26pub struct CoapServer {
55 bind: String,
56 shared: Arc<Shared>,
57 incoming: Option<mpsc::UnboundedReceiver<Message>>,
58 pump: Option<JoinHandle<()>>,
59}
60
61#[derive(Clone)]
67pub struct CoapPublisher {
68 shared: Arc<Shared>,
69}
70
71struct Shared {
73 socket: Mutex<Option<Arc<UdpSocket>>>,
75 state: Mutex<State>,
77}
78
79struct State {
81 filters: Vec<String>,
83 resources: HashMap<String, Vec<u8>>,
85 observers: HashMap<String, Vec<Observer>>,
87 answered: HashMap<(SocketAddr, u16), (Instant, Vec<u8>)>,
89 next_id: u16,
91 sequence: u32,
94}
95
96struct Observer {
98 peer: SocketAddr,
100 token: Vec<u8>,
102 last_id: u16,
104}
105
106impl CoapServer {
107 pub fn new(bind: impl Into<String>) -> Self {
118 Self {
119 bind: bind.into(),
120 shared: Arc::new(Shared {
121 socket: Mutex::new(None),
122 state: Mutex::new(State {
123 filters: Vec::new(),
124 resources: HashMap::new(),
125 observers: HashMap::new(),
126 answered: HashMap::new(),
127 next_id: random() as u16,
128 sequence: 0,
129 }),
130 }),
131 incoming: None,
132 pump: None,
133 }
134 }
135
136 pub fn publisher(&self) -> CoapPublisher {
142 CoapPublisher {
143 shared: Arc::clone(&self.shared),
144 }
145 }
146
147 pub fn is_connected(&self) -> bool {
154 self.shared.socket().is_some()
155 }
156
157 pub fn local_addr(&self) -> Option<SocketAddr> {
164 self.shared.socket()?.local_addr().ok()
165 }
166
167 pub fn observers(&self, path: &str) -> usize {
177 self.shared.observers(path)
178 }
179
180 pub async fn disconnect(&mut self) -> Result<()> {
194 if let Some(pump) = self.pump.take() {
195 pump.abort();
196 }
197 *self.shared.socket.lock().expect("socket lock") = None;
198 self.incoming = None;
199 self.shared.state().observers.clear();
200 Ok(())
201 }
202}
203
204impl CoapPublisher {
205 pub async fn publish(&self, path: &str, payload: &[u8]) -> Result<()> {
223 let socket = self.shared.socket().ok_or(Error::Closed)?;
224 let out = {
225 let mut state = self.shared.state();
226 let path = path.trim_matches('/').to_owned();
227 state.resources.insert(path.clone(), payload.to_vec());
228 state.notify(&path, payload)
229 };
230 let mut failure = None;
231 for (to, bytes) in out {
232 if let Err(error) = socket.send_to(&bytes, to).await {
233 if !crate::refused(&error) {
234 failure.get_or_insert(Error::Transport(error.to_string()));
235 }
236 }
237 }
238 failure.map_or(Ok(()), Err)
239 }
240
241 pub fn observers(&self, path: &str) -> usize {
251 self.shared.observers(path)
252 }
253
254 pub fn is_connected(&self) -> bool {
260 self.shared.socket().is_some()
261 }
262
263 pub fn local_addr(&self) -> Option<SocketAddr> {
269 self.shared.socket()?.local_addr().ok()
270 }
271}
272
273impl Shared {
274 fn socket(&self) -> Option<Arc<UdpSocket>> {
276 self.socket.lock().expect("socket lock").clone()
277 }
278
279 fn state(&self) -> std::sync::MutexGuard<'_, State> {
281 self.state.lock().expect("server lock")
282 }
283
284 fn observers(&self, path: &str) -> usize {
286 self.state()
287 .observers
288 .get(path.trim_matches('/'))
289 .map_or(0, Vec::len)
290 }
291}
292
293impl Transport for CoapServer {
294 async fn connect(&mut self) -> Result<()> {
305 self.disconnect().await?;
306 let socket = Arc::new(
307 UdpSocket::bind(&self.bind)
308 .await
309 .map_err(|err| Error::Transport(format!("could not bind {}: {err}", self.bind)))?,
310 );
311 let (tx, rx) = mpsc::unbounded_channel();
312 let shared = Arc::clone(&self.shared);
313 let pump_socket = Arc::clone(&socket);
314 let pump = tokio::spawn(async move {
315 let mut buf = vec![0u8; DATAGRAM];
316 loop {
317 let (len, peer) = match pump_socket.recv_from(&mut buf).await {
318 Ok(received) => received,
319 Err(error) if crate::refused(&error) => continue,
320 Err(_) => break,
321 };
322 let Ok(packet) = Packet::from_bytes(&buf[..len]) else {
323 continue;
324 };
325 let out = handle(&packet, peer, &shared.state, &tx);
326 for (to, bytes) in out {
327 let _ = pump_socket.send_to(&bytes, to).await;
328 }
329 }
330 });
331 *self.shared.socket.lock().expect("socket lock") = Some(socket);
332 self.incoming = Some(rx);
333 self.pump = Some(pump);
334 Ok(())
335 }
336
337 async fn send(&mut self, topic: &str, payload: &[u8]) -> Result<()> {
353 self.publisher().publish(topic, payload).await
354 }
355
356 async fn subscribe(&mut self, topic: &str) -> Result<()> {
368 self.shared
369 .state()
370 .filters
371 .push(topic.trim_matches('/').to_owned());
372 Ok(())
373 }
374}
375
376impl Receive for CoapServer {
377 async fn recv(&mut self) -> Result<Option<Message>> {
387 let incoming = self.incoming.as_mut().ok_or(Error::Closed)?;
388 Ok(incoming.recv().await)
389 }
390}
391
392impl State {
393 fn message_id(&mut self) -> u16 {
395 let id = self.next_id;
396 self.next_id = self.next_id.wrapping_add(1);
397 id
398 }
399
400 fn next_sequence(&mut self) -> u32 {
402 self.sequence = (self.sequence + 1) & 0x00FF_FFFF;
403 self.sequence
404 }
405
406 fn notify(&mut self, path: &str, payload: &[u8]) -> Vec<(SocketAddr, Vec<u8>)> {
408 let sequence = self.next_sequence();
409 let count = self.observers.get(path).map_or(0, Vec::len);
410 let ids: Vec<u16> = (0..count).map(|_| self.message_id()).collect();
411 let Some(observers) = self.observers.get_mut(path) else {
412 return Vec::new();
413 };
414 observers
415 .iter_mut()
416 .zip(ids)
417 .filter_map(|(observer, id)| {
418 observer.last_id = id;
419 let mut packet = response(ResponseType::Content, payload);
420 packet.header.set_type(MessageType::NonConfirmable);
421 packet.header.message_id = id;
422 packet.set_token(observer.token.clone());
423 packet.add_option(CoapOption::Observe, observe_bytes(sequence));
424 Some((observer.peer, packet.to_bytes().ok()?))
425 })
426 .collect()
427 }
428}
429
430fn handle(
432 packet: &Packet,
433 peer: SocketAddr,
434 state: &Mutex<State>,
435 tx: &mpsc::UnboundedSender<Message>,
436) -> Vec<(SocketAddr, Vec<u8>)> {
437 let mut state = state.lock().expect("server lock");
438 let id = packet.header.message_id;
439 match (packet.header.get_type(), packet.header.code) {
440 (MessageType::Reset, _) => {
441 for observers in state.observers.values_mut() {
442 observers.retain(|observer| !(observer.peer == peer && observer.last_id == id));
443 }
444 Vec::new()
445 }
446 (MessageType::Confirmable, MessageClass::Empty) => {
447 vec![(peer, empty(MessageType::Reset, id))]
448 }
449 (
450 kind @ (MessageType::Confirmable | MessageType::NonConfirmable),
451 MessageClass::Request(method),
452 ) => {
453 let confirmable = kind == MessageType::Confirmable;
454 if confirmable {
455 let now = Instant::now();
456 state
457 .answered
458 .retain(|_, (at, _)| now.duration_since(*at) < EXCHANGE_LIFETIME);
459 if let Some((_, bytes)) = state.answered.get(&(peer, id)) {
460 return vec![(peer, bytes.clone())];
461 }
462 }
463 let (mut answer, mut out) = request(&mut state, packet, method, peer, tx);
464 answer.set_token(packet.get_token().to_vec());
465 if confirmable {
466 answer.header.set_type(MessageType::Acknowledgement);
467 answer.header.message_id = id;
468 } else {
469 answer.header.set_type(MessageType::NonConfirmable);
470 answer.header.message_id = state.message_id();
471 }
472 if let Ok(bytes) = answer.to_bytes() {
473 if confirmable {
474 state
475 .answered
476 .insert((peer, id), (Instant::now(), bytes.clone()));
477 }
478 out.insert(0, (peer, bytes));
479 }
480 out
481 }
482 (MessageType::Confirmable, _) => vec![(peer, empty(MessageType::Reset, id))],
483 _ => Vec::new(),
484 }
485}
486
487fn request(
489 state: &mut State,
490 packet: &Packet,
491 method: RequestType,
492 peer: SocketAddr,
493 tx: &mpsc::UnboundedSender<Message>,
494) -> (Packet, Vec<(SocketAddr, Vec<u8>)>) {
495 let path = path_from_packet(packet);
496 match method {
497 RequestType::Get => {
498 let Some(current) = state.resources.get(&path).cloned() else {
499 return (response(ResponseType::NotFound, &[]), Vec::new());
500 };
501 let token = packet.get_token().to_vec();
502 let mut answer = response(ResponseType::Content, ¤t);
503 match observe_value(packet) {
504 Some(0) => {
505 let observers = state.observers.entry(path).or_default();
506 observers
507 .retain(|observer| !(observer.peer == peer && observer.token == token));
508 observers.push(Observer {
509 peer,
510 token,
511 last_id: 0,
512 });
513 answer.add_option(CoapOption::Observe, observe_bytes(state.sequence));
514 }
515 Some(1) => {
516 if let Some(observers) = state.observers.get_mut(&path) {
517 observers
518 .retain(|observer| !(observer.peer == peer && observer.token == token));
519 }
520 }
521 _ => {}
522 }
523 (answer, Vec::new())
524 }
525 RequestType::Put | RequestType::Post => {
526 if !state
527 .filters
528 .iter()
529 .any(|filter| topic_matches(filter, &path))
530 {
531 return (response(ResponseType::NotFound, &[]), Vec::new());
532 }
533 let _ = tx.send(Message::new(path.clone(), packet.payload.clone()));
534 state.resources.insert(path.clone(), packet.payload.clone());
535 let notifications = state.notify(&path, &packet.payload);
536 (response(ResponseType::Changed, &[]), notifications)
537 }
538 _ => (response(ResponseType::MethodNotAllowed, &[]), Vec::new()),
539 }
540}
541
542fn response(code: ResponseType, payload: &[u8]) -> Packet {
544 let mut packet = Packet::new();
545 packet.header.set_version(1);
546 packet.header.code = MessageClass::Response(code);
547 packet.payload = payload.to_vec();
548 packet
549}
550
551fn empty(kind: MessageType, message_id: u16) -> Vec<u8> {
553 let mut packet = Packet::new();
554 packet.header.set_version(1);
555 packet.header.set_type(kind);
556 packet.header.code = MessageClass::Empty;
557 packet.header.message_id = message_id;
558 packet.to_bytes().unwrap_or_default()
559}
560
561fn observe_bytes(value: u32) -> Vec<u8> {
564 let bytes = value.to_be_bytes();
565 let first = bytes
566 .iter()
567 .position(|byte| *byte != 0)
568 .unwrap_or(bytes.len());
569 bytes[first..].to_vec()
570}
571
572#[cfg(test)]
573mod tests {
574 use super::*;
575
576 #[test]
577 fn an_observe_value_takes_the_fewest_bytes_that_hold_it() {
578 assert_eq!(observe_bytes(0), Vec::<u8>::new());
579 assert_eq!(observe_bytes(1), vec![1]);
580 assert_eq!(observe_bytes(0x0100), vec![1, 0]);
581 assert_eq!(observe_bytes(0x00FF_FFFF), vec![0xFF, 0xFF, 0xFF]);
582 }
583
584 #[test]
585 fn the_notification_number_wraps_at_24_bits() {
586 let mut state = State {
587 filters: Vec::new(),
588 resources: HashMap::new(),
589 observers: HashMap::new(),
590 answered: HashMap::new(),
591 next_id: 0,
592 sequence: 0x00FF_FFFF,
593 };
594 assert_eq!(state.next_sequence(), 0);
595 assert_eq!(state.next_sequence(), 1);
596 }
597}