Skip to main content

twopoint/
peer.rs

1use std::io;
2use std::net::{ToSocketAddrs, SocketAddr, UdpSocket};
3use std::time::Duration;
4
5use crate::util::*;
6use crate::key::Key;
7use crate::crypto::Crypto;
8
9/// A UDP peer that can send and receive encrypted messages.
10///
11/// Each peer maintains a UDP socket and can connect to at most one remote endpoint
12/// at a time. All messages are encrypted using AES-128-GCM before transmission.
13pub struct Peer {
14  socket: UdpSocket,
15  crypto: Crypto,
16}
17
18impl Peer {
19
20  /// Creates a new peer with the given socket and encryption key.
21  pub fn new(socket: UdpSocket, key: Key) -> Self {
22    Self { socket, crypto: Crypto::new(key) }
23  }
24
25  /// Creates a new peer, binds to `bind_addr`, and connects to `connect_addr`.
26  ///
27  /// This is a convenience method that combines socket creation, binding, and connection.
28  /// Use `"0.0.0.0:0"` or `"[::]:0"` for `connect_addr` to create an unconnected peer.
29  pub fn setup<A1, A2>(bind_addr: A1, connect_addr: A2, key: Key) -> io::Result<Self>
30  where
31    A1: ToSocketAddrs,
32    A2: ToSocketAddrs,
33  {
34    let socket = UdpSocket::bind(bind_addr)?;
35    let peer = Self::new(socket, key);
36    peer.connect(connect_addr)?;
37    Ok(peer)
38  }
39
40  /// Returns a reference to the underlying UDP socket.
41  pub fn socket(&self) -> &UdpSocket {
42    &self.socket
43  }
44
45  /// Returns the local socket address.
46  pub fn local_addr(&self) -> SocketAddr {
47    self.socket.local_addr().expect("couldn't get local address")
48  }
49
50  /// Returns the remote socket address if connected, otherwise `None`.
51  pub fn remote_addr_optional(&self) -> Option<SocketAddr> {
52    match self.socket.peer_addr() {
53      Ok(addr) => {
54        if !is_unspecified(addr) {
55          Some(addr)
56        } else {
57          None
58        }
59      }
60      Err(_) => None
61    }
62  }
63
64  /// Returns the remote socket address, or an unspecified address if not connected.
65  pub fn remote_addr(&self) -> SocketAddr {
66    self.remote_addr_optional()
67      .unwrap_or_else(|| to_unspecified(self.local_addr()))
68  }
69
70  /// Connects to the specified remote address.
71  ///
72  /// This establishes the peer's target for communication. Both `send()` and
73  /// `recv()` operations require the peer to be connected to function.
74  pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
75    self.socket.connect(addr)
76  }
77
78  /// Disconnects from the current remote address.
79  ///
80  /// After disconnecting, both `send()` and `recv()` calls will fail until
81  /// the peer is reconnected to a remote address.
82  pub fn disconnect(&self) -> io::Result<()> {
83    self.socket.connect(to_unspecified(self.local_addr()))
84  }
85
86  /// Sets the read timeout for receive operations.
87  pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
88    self.socket.set_read_timeout(timeout)
89  }
90
91  /// Sets the write timeout for send operations.
92  pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
93    self.socket.set_write_timeout(timeout)
94  }
95
96  /// Encrypts and sends the contents of the buffer to the connected peer.
97  ///
98  /// The buffer is modified in-place during encryption - a 28-byte overhead
99  /// (16-byte authentication tag + 12-byte nonce) is appended to the end.
100  ///
101  /// Returns an error if not connected to a peer, if encryption fails, or on network errors.
102  pub fn send(&mut self, buffer: &mut Vec<u8>) -> io::Result<()> {
103    self.crypto.encrypt(buffer)?;
104    self.socket.send(buffer)?;
105    Ok(())
106  }
107
108  /// Receives and decrypts a message into the buffer.
109  ///
110  /// The buffer must be large enough to hold the entire encrypted message.
111  /// After receiving, the buffer is truncated to the message length, then
112  /// the 28-byte crypto overhead is removed from the end during decryption.
113  /// The buffer is resized to match the original message length.
114  ///
115  /// Returns an error if not connected to a peer, if decryption fails, or on network errors.
116  pub fn recv(&mut self, buffer: &mut Vec<u8>) -> io::Result<()> {
117    let len = self.socket.recv(buffer)?;
118    buffer.truncate(len);
119    self.crypto.decrypt(buffer)?;
120    Ok(())
121  }
122
123}
124
125impl Clone for Peer {
126  /// Clones the peer, including its socket and encryption state.
127  ///
128  /// This allows for multiple mutable references to the same peer.
129  /// The socket is cloned using `try_clone()`, which may fail in
130  /// extreme cases if the underlying system resources are not available.
131  ///
132  /// Returns a new peer with the same configuration.
133  fn clone(&self) -> Self {
134    let socket = self.socket.try_clone().expect("couldn't clone socket");
135    let crypto = self.crypto.clone();
136    Self { socket, crypto }
137  }
138}
139