torrust_tracker/servers/udp/server/
bound_socket.rs

1use std::fmt::Debug;
2use std::net::SocketAddr;
3use std::ops::Deref;
4
5use url::Url;
6
7use crate::servers::udp::UDP_TRACKER_LOG_TARGET;
8
9/// Wrapper for Tokio [`UdpSocket`][`tokio::net::UdpSocket`] that is bound to a particular socket.
10pub struct BoundSocket {
11    socket: tokio::net::UdpSocket,
12}
13
14impl BoundSocket {
15    /// # Errors
16    ///
17    /// Will return an error if the socket can't be bound the the provided address.
18    pub async fn new(addr: SocketAddr) -> Result<Self, Box<std::io::Error>> {
19        let bind_addr = format!("udp://{addr}");
20        tracing::debug!(target: UDP_TRACKER_LOG_TARGET, bind_addr, "UdpSocket::new (binding)");
21
22        let socket = tokio::net::UdpSocket::bind(addr).await;
23
24        let socket = match socket {
25            Ok(socket) => socket,
26            Err(e) => Err(e)?,
27        };
28
29        let local_addr = format!("udp://{}", socket.local_addr()?);
30        tracing::debug!(target: UDP_TRACKER_LOG_TARGET, local_addr, "UdpSocket::new (bound)");
31
32        Ok(Self { socket })
33    }
34
35    /// # Panics
36    ///
37    /// Will panic if the socket can't get the address it was bound to.
38    #[must_use]
39    pub fn address(&self) -> SocketAddr {
40        self.socket.local_addr().expect("it should get local address")
41    }
42
43    /// # Panics
44    ///
45    /// Will panic if the address the socket was bound to is not a valid address
46    /// to be used in a URL.
47    #[must_use]
48    pub fn url(&self) -> Url {
49        Url::parse(&format!("udp://{}", self.address())).expect("UDP socket address should be valid")
50    }
51}
52
53impl Deref for BoundSocket {
54    type Target = tokio::net::UdpSocket;
55
56    fn deref(&self) -> &Self::Target {
57        &self.socket
58    }
59}
60
61impl Debug for BoundSocket {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        let local_addr = match self.socket.local_addr() {
64            Ok(socket) => format!("Receiving From: {socket}"),
65            Err(err) => format!("Socket Broken: {err}"),
66        };
67
68        f.debug_struct("UdpSocket").field("addr", &local_addr).finish_non_exhaustive()
69    }
70}