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