solana_udp_client/
lib.rs

1#![cfg_attr(
2    not(feature = "agave-unstable-api"),
3    deprecated(
4        since = "3.1.0",
5        note = "This crate has been marked for formal inclusion in the Agave Unstable API. From \
6                v4.0.0 onward, the `agave-unstable-api` crate feature must be specified to \
7                acknowledge use of an interface that may break without warning."
8    )
9)]
10#![allow(clippy::arithmetic_side_effects)]
11
12pub mod nonblocking;
13pub mod udp_client;
14
15use {
16    crate::{
17        nonblocking::udp_client::UdpClientConnection as NonblockingUdpConnection,
18        udp_client::UdpClientConnection as BlockingUdpConnection,
19    },
20    solana_connection_cache::{
21        connection_cache::{
22            BaseClientConnection, ClientError, ConnectionManager, ConnectionPool,
23            ConnectionPoolError, NewConnectionConfig, Protocol,
24        },
25        connection_cache_stats::ConnectionCacheStats,
26    },
27    solana_keypair::Keypair,
28    solana_net_utils::sockets::{self, SocketConfiguration},
29    std::{
30        net::{SocketAddr, UdpSocket},
31        sync::Arc,
32    },
33};
34
35pub struct UdpPool {
36    connections: Vec<Arc<Udp>>,
37}
38impl ConnectionPool for UdpPool {
39    type BaseClientConnection = Udp;
40    type NewConnectionConfig = UdpConfig;
41
42    fn add_connection(&mut self, config: &Self::NewConnectionConfig, addr: &SocketAddr) -> usize {
43        let connection = self.create_pool_entry(config, addr);
44        let idx = self.connections.len();
45        self.connections.push(connection);
46        idx
47    }
48
49    fn num_connections(&self) -> usize {
50        self.connections.len()
51    }
52
53    fn get(&self, index: usize) -> Result<Arc<Self::BaseClientConnection>, ConnectionPoolError> {
54        self.connections
55            .get(index)
56            .cloned()
57            .ok_or(ConnectionPoolError::IndexOutOfRange)
58    }
59
60    fn create_pool_entry(
61        &self,
62        config: &Self::NewConnectionConfig,
63        _addr: &SocketAddr,
64    ) -> Arc<Self::BaseClientConnection> {
65        Arc::new(Udp(config.udp_socket.clone()))
66    }
67}
68
69pub struct UdpConfig {
70    udp_socket: Arc<UdpSocket>,
71}
72
73impl NewConnectionConfig for UdpConfig {
74    fn new() -> Result<Self, ClientError> {
75        // Use UNSPECIFIED for production validators to bind to all interfaces
76        // Use LOCALHOST only in dev/test context to avoid port conflicts in CI
77        #[cfg(not(feature = "dev-context-only-utils"))]
78        let bind_ip = std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED);
79        #[cfg(feature = "dev-context-only-utils")]
80        let bind_ip = std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST);
81
82        // This will bind to random ports, but VALIDATOR_PORT_RANGE is outside
83        // of the range for CI tests when this is running in CI
84        let socket = sockets::bind_in_range_with_config(
85            bind_ip,
86            solana_net_utils::VALIDATOR_PORT_RANGE,
87            SocketConfiguration::default(),
88        )
89        .map_err(Into::<ClientError>::into)?;
90        Ok(Self {
91            udp_socket: Arc::new(socket.1),
92        })
93    }
94}
95
96pub struct Udp(Arc<UdpSocket>);
97impl BaseClientConnection for Udp {
98    type BlockingClientConnection = BlockingUdpConnection;
99    type NonblockingClientConnection = NonblockingUdpConnection;
100
101    fn new_blocking_connection(
102        &self,
103        addr: SocketAddr,
104        _stats: Arc<ConnectionCacheStats>,
105    ) -> Arc<Self::BlockingClientConnection> {
106        Arc::new(BlockingUdpConnection::new_from_addr(self.0.clone(), addr))
107    }
108
109    fn new_nonblocking_connection(
110        &self,
111        addr: SocketAddr,
112        _stats: Arc<ConnectionCacheStats>,
113    ) -> Arc<Self::NonblockingClientConnection> {
114        Arc::new(NonblockingUdpConnection::new_from_addr(
115            self.0.try_clone().unwrap(),
116            addr,
117        ))
118    }
119}
120
121#[derive(Default)]
122pub struct UdpConnectionManager {}
123
124impl ConnectionManager for UdpConnectionManager {
125    type ConnectionPool = UdpPool;
126    type NewConnectionConfig = UdpConfig;
127
128    const PROTOCOL: Protocol = Protocol::UDP;
129
130    fn new_connection_pool(&self) -> Self::ConnectionPool {
131        UdpPool {
132            connections: Vec::default(),
133        }
134    }
135
136    fn new_connection_config(&self) -> Self::NewConnectionConfig {
137        UdpConfig::new().unwrap()
138    }
139
140    fn update_key(&self, _key: &Keypair) -> Result<(), Box<dyn std::error::Error>> {
141        Ok(())
142    }
143}