1#![warn(if_let_rescope)]
5#![warn(keyword_idents_2024)]
6#![warn(missing_unsafe_on_extern)]
7#![warn(rust_2024_guarded_string_incompatible_syntax)]
8#![warn(rust_2024_incompatible_pat)]
9#![warn(tail_expr_drop_order)]
10#![warn(unsafe_attr_outside_unsafe)]
11#![warn(unsafe_op_in_unsafe_fn)]
12
13mod ip_echo_client;
14mod ip_echo_server;
15pub mod multihomed_sockets;
16pub mod sockets;
17
18#[cfg(feature = "dev-context-only-utils")]
19pub mod tooling_for_tests;
20
21pub use ip_echo_server::{
22 ip_echo_server, IpEchoServer, DEFAULT_IP_ECHO_SERVER_THREADS, MAX_PORT_COUNT_PER_MESSAGE,
23 MINIMUM_IP_ECHO_SERVER_THREADS,
24};
25use {
26 crate::sockets::{udp_socket_with_config, PLATFORM_SUPPORTS_SOCKET_CONFIGS},
27 ip_echo_client::{ip_echo_server_request, ip_echo_server_request_with_binding},
28 ip_echo_server::IpEchoServerMessage,
29 log::*,
30 rand::{thread_rng, Rng},
31 socket2::SockAddr,
32 std::{
33 io::{self},
34 net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, ToSocketAddrs, UdpSocket},
35 },
36 url::Url,
37};
38
39pub struct UdpSocketPair {
41 pub addr: SocketAddr, pub receiver: UdpSocket, pub sender: UdpSocket, }
45
46pub type PortRange = (u16, u16);
47
48#[cfg(not(debug_assertions))]
49pub const VALIDATOR_PORT_RANGE: PortRange = (8000, 10_000);
51
52#[cfg(debug_assertions)]
55pub const VALIDATOR_PORT_RANGE: PortRange = (
56 crate::sockets::UNIQUE_ALLOC_BASE_PORT - 512,
57 crate::sockets::UNIQUE_ALLOC_BASE_PORT,
58);
59
60pub const MINIMUM_VALIDATOR_PORT_RANGE_WIDTH: u16 = 25; pub(crate) const HEADER_LENGTH: usize = 4;
63pub(crate) const IP_ECHO_SERVER_RESPONSE_LENGTH: usize = HEADER_LENGTH + 23;
64
65#[deprecated(
68 since = "3.0.0",
69 note = "Use `get_public_ip_addr_with_binding` instead"
70)]
71pub fn get_public_ip_addr(ip_echo_server_addr: &SocketAddr) -> Result<IpAddr, String> {
72 let fut = ip_echo_server_request(*ip_echo_server_addr, IpEchoServerMessage::default());
73 let rt = tokio::runtime::Builder::new_current_thread()
74 .enable_all()
75 .build()
76 .map_err(|e| e.to_string())?;
77 let resp = rt.block_on(fut).map_err(|e| e.to_string())?;
78 Ok(resp.address)
79}
80
81pub fn get_public_ip_addr_with_binding(
84 ip_echo_server_addr: &SocketAddr,
85 bind_address: IpAddr,
86) -> anyhow::Result<IpAddr> {
87 let fut = ip_echo_server_request_with_binding(
88 *ip_echo_server_addr,
89 IpEchoServerMessage::default(),
90 bind_address,
91 );
92 let rt = tokio::runtime::Builder::new_current_thread()
93 .enable_all()
94 .build()?;
95 let resp = rt.block_on(fut)?;
96 Ok(resp.address)
97}
98
99pub fn get_cluster_shred_version(ip_echo_server_addr: &SocketAddr) -> Result<u16, String> {
101 let fut = ip_echo_server_request(*ip_echo_server_addr, IpEchoServerMessage::default());
102 let rt = tokio::runtime::Builder::new_current_thread()
103 .enable_all()
104 .build()
105 .map_err(|e| e.to_string())?;
106 let resp = rt.block_on(fut).map_err(|e| e.to_string())?;
107 resp.shred_version
108 .ok_or_else(|| "IP echo server does not return a shred-version".to_owned())
109}
110
111pub fn get_cluster_shred_version_with_binding(
114 ip_echo_server_addr: &SocketAddr,
115 bind_address: IpAddr,
116) -> anyhow::Result<u16> {
117 let fut = ip_echo_server_request_with_binding(
118 *ip_echo_server_addr,
119 IpEchoServerMessage::default(),
120 bind_address,
121 );
122 let rt = tokio::runtime::Builder::new_current_thread()
123 .enable_all()
124 .build()?;
125 let resp = rt.block_on(fut)?;
126 resp.shred_version
127 .ok_or_else(|| anyhow::anyhow!("IP echo server does not return a shred-version"))
128}
129
130const MAX_PORT_VERIFY_THREADS: usize = 64;
133
134pub fn verify_all_reachable_udp(
139 ip_echo_server_addr: &SocketAddr,
140 udp_sockets: &[&UdpSocket],
141) -> bool {
142 let rt = tokio::runtime::Builder::new_current_thread()
143 .enable_all()
144 .max_blocking_threads(MAX_PORT_VERIFY_THREADS)
145 .build()
146 .expect("Tokio builder should be able to reliably create a current thread runtime");
147 let fut = ip_echo_client::verify_all_reachable_udp(
148 *ip_echo_server_addr,
149 udp_sockets,
150 ip_echo_client::TIMEOUT,
151 ip_echo_client::DEFAULT_RETRY_COUNT,
152 );
153 rt.block_on(fut)
154}
155
156pub fn verify_all_reachable_tcp(
161 ip_echo_server_addr: &SocketAddr,
162 tcp_listeners: Vec<TcpListener>,
163) -> bool {
164 let rt = tokio::runtime::Builder::new_current_thread()
165 .enable_all()
166 .max_blocking_threads(MAX_PORT_VERIFY_THREADS)
167 .build()
168 .expect("Tokio builder should be able to reliably create a current thread runtime");
169 let fut = ip_echo_client::verify_all_reachable_tcp(
170 *ip_echo_server_addr,
171 tcp_listeners,
172 ip_echo_client::TIMEOUT,
173 );
174 rt.block_on(fut)
175}
176
177pub fn parse_port_or_addr(optstr: Option<&str>, default_addr: SocketAddr) -> SocketAddr {
178 if let Some(addrstr) = optstr {
179 if let Ok(port) = addrstr.parse() {
180 let mut addr = default_addr;
181 addr.set_port(port);
182 addr
183 } else if let Ok(addr) = addrstr.parse() {
184 addr
185 } else {
186 default_addr
187 }
188 } else {
189 default_addr
190 }
191}
192
193pub fn parse_port_range(port_range: &str) -> Option<PortRange> {
194 let ports: Vec<&str> = port_range.split('-').collect();
195 if ports.len() != 2 {
196 return None;
197 }
198
199 let start_port = ports[0].parse();
200 let end_port = ports[1].parse();
201
202 if start_port.is_err() || end_port.is_err() {
203 return None;
204 }
205 let start_port = start_port.unwrap();
206 let end_port = end_port.unwrap();
207 if end_port < start_port {
208 return None;
209 }
210 Some((start_port, end_port))
211}
212
213pub fn parse_host(host: &str) -> Result<IpAddr, String> {
214 let parsed_url = Url::parse(&format!("http://{host}")).map_err(|e| e.to_string())?;
217 if parsed_url.port().is_some() {
218 return Err(format!("Expected port in URL: {host}"));
219 }
220
221 let ips: Vec<_> = (host, 0)
223 .to_socket_addrs()
224 .map_err(|err| err.to_string())?
225 .map(|socket_address| socket_address.ip())
226 .collect();
227 if ips.is_empty() {
228 Err(format!("Unable to resolve host: {host}"))
229 } else {
230 Ok(ips[0])
231 }
232}
233
234pub fn is_host(string: String) -> Result<(), String> {
235 parse_host(&string).map(|_| ())
236}
237
238pub fn parse_host_port(host_port: &str) -> Result<SocketAddr, String> {
239 let addrs: Vec<_> = host_port
240 .to_socket_addrs()
241 .map_err(|err| format!("Unable to resolve host {host_port}: {err}"))?
242 .collect();
243 if addrs.is_empty() {
244 Err(format!("Unable to resolve host: {host_port}"))
245 } else {
246 Ok(addrs[0])
247 }
248}
249
250pub fn is_host_port(string: String) -> Result<(), String> {
251 parse_host_port(&string).map(|_| ())
252}
253
254#[deprecated(
255 since = "3.0.0",
256 note = "Please use the equivalent struct from solana-net-utils::sockets"
257)]
258#[derive(Clone, Copy, Debug, Default)]
259pub struct SocketConfig {
260 reuseport: bool,
261 recv_buffer_size: Option<usize>,
262 send_buffer_size: Option<usize>,
263}
264
265#[allow(deprecated)]
266impl SocketConfig {
267 pub fn reuseport(mut self, reuseport: bool) -> Self {
268 self.reuseport = reuseport;
269 self
270 }
271
272 pub fn recv_buffer_size(mut self, size: usize) -> Self {
279 self.recv_buffer_size = Some(size);
280 self
281 }
282
283 pub fn send_buffer_size(mut self, size: usize) -> Self {
290 self.send_buffer_size = Some(size);
291 self
292 }
293}
294
295#[deprecated(
296 since = "3.0.0",
297 note = "Please use the equivalent from solana-net-utils::sockets"
298)]
299#[allow(deprecated)]
300pub fn bind_common_in_range_with_config(
302 ip_addr: IpAddr,
303 range: PortRange,
304 config: SocketConfig,
305) -> io::Result<(u16, (UdpSocket, TcpListener))> {
306 for port in range.0..range.1 {
307 if let Ok((sock, listener)) = bind_common_with_config(ip_addr, port, config) {
308 return Result::Ok((sock.local_addr().unwrap().port(), (sock, listener)));
309 }
310 }
311
312 Err(io::Error::other(format!(
313 "No available TCP/UDP ports in {range:?}"
314 )))
315}
316
317pub fn bind_in_range(ip_addr: IpAddr, range: PortRange) -> io::Result<(u16, UdpSocket)> {
318 let config = sockets::SocketConfiguration::default();
319 sockets::bind_in_range_with_config(ip_addr, range, config)
320}
321
322#[deprecated(
323 since = "3.0.0",
324 note = "Please use the equivalent from solana-net-utils::sockets"
325)]
326#[allow(deprecated)]
327pub fn bind_in_range_with_config(
328 ip_addr: IpAddr,
329 range: PortRange,
330 config: SocketConfig,
331) -> io::Result<(u16, UdpSocket)> {
332 let socket = udp_socket_with_config(config.into())?;
333
334 for port in range.0..range.1 {
335 let addr = SocketAddr::new(ip_addr, port);
336
337 if socket.bind(&SockAddr::from(addr)).is_ok() {
338 let udp_socket: UdpSocket = socket.into();
339 return Result::Ok((udp_socket.local_addr().unwrap().port(), udp_socket));
340 }
341 }
342
343 Err(io::Error::other(format!(
344 "No available UDP ports in {range:?}"
345 )))
346}
347
348#[deprecated(
349 since = "3.0.0",
350 note = "Please use the equivalent from solana-net-utils::sockets"
351)]
352#[allow(deprecated)]
353pub fn bind_with_any_port_with_config(
354 ip_addr: IpAddr,
355 config: SocketConfig,
356) -> io::Result<UdpSocket> {
357 let sock = udp_socket_with_config(config.into())?;
358 let addr = SocketAddr::new(ip_addr, 0);
359 let bind = sock.bind(&SockAddr::from(addr));
360 match bind {
361 Ok(_) => Result::Ok(sock.into()),
362 Err(err) => Err(io::Error::other(format!("No available UDP port: {err}"))),
363 }
364}
365
366#[deprecated(
367 since = "3.0.0",
368 note = "Please use the equivalent from solana-net-utils::sockets"
369)]
370#[allow(deprecated)]
371pub fn multi_bind_in_range_with_config(
373 ip_addr: IpAddr,
374 range: PortRange,
375 config: SocketConfig,
376 mut num: usize,
377) -> io::Result<(u16, Vec<UdpSocket>)> {
378 if !PLATFORM_SUPPORTS_SOCKET_CONFIGS && num != 1 {
379 warn!(
381 "multi_bind_in_range_with_config() only supports 1 socket on this platform ({num} \
382 requested)"
383 );
384 num = 1;
385 }
386 let (port, socket) = bind_in_range_with_config(ip_addr, range, config)?;
387 let sockets = bind_more_with_config(socket, num, config)?;
388 Ok((port, sockets))
389}
390
391#[deprecated(
392 since = "3.0.0",
393 note = "Please use the eqiuvalent from solana-net-utils::sockets"
394)]
395#[allow(deprecated)]
396pub fn bind_to(ip_addr: IpAddr, port: u16, reuseport: bool) -> io::Result<UdpSocket> {
397 let config = SocketConfig {
398 reuseport,
399 ..Default::default()
400 };
401 bind_to_with_config(ip_addr, port, config)
402}
403
404pub fn bind_to_localhost() -> io::Result<UdpSocket> {
405 let config = sockets::SocketConfiguration::default();
406 sockets::bind_to_with_config(IpAddr::V4(Ipv4Addr::LOCALHOST), 0, config)
407}
408
409pub fn bind_to_unspecified() -> io::Result<UdpSocket> {
410 let config = sockets::SocketConfiguration::default();
411 sockets::bind_to_with_config(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0, config)
412}
413
414#[deprecated(
415 since = "3.0.0",
416 note = "Please avoid this function in favor of sockets::bind_to_with_config"
417)]
418#[allow(deprecated)]
419pub fn bind_to_with_config(
420 ip_addr: IpAddr,
421 port: u16,
422 config: SocketConfig,
423) -> io::Result<UdpSocket> {
424 let sock = udp_socket_with_config(config.into())?;
425 let addr = SocketAddr::new(ip_addr, port);
426 sock.bind(&SockAddr::from(addr)).map(|_| sock.into())
427}
428
429#[deprecated(
430 since = "3.0.0",
431 note = "Please avoid this function, it is easy to misuse"
432)]
433#[allow(deprecated)]
434pub fn bind_to_with_config_non_blocking(
435 ip_addr: IpAddr,
436 port: u16,
437 config: SocketConfig,
438) -> io::Result<UdpSocket> {
439 let sock = udp_socket_with_config(config.into())?;
440
441 let addr = SocketAddr::new(ip_addr, port);
442
443 sock.bind(&SockAddr::from(addr))?;
444 sock.set_nonblocking(true)?;
445 Ok(sock.into())
446}
447
448#[deprecated(
449 since = "3.0.0",
450 note = "Please avoid this function in favor of sockets::bind_common_with_config"
451)]
452pub fn bind_common(ip_addr: IpAddr, port: u16) -> io::Result<(UdpSocket, TcpListener)> {
454 let config = sockets::SocketConfiguration::default();
455 sockets::bind_common_with_config(ip_addr, port, config)
456}
457
458#[deprecated(
459 since = "3.0.0",
460 note = "Please avoid this function in favor of sockets::bind_common_with_config"
461)]
462#[allow(deprecated)]
463pub fn bind_common_with_config(
465 ip_addr: IpAddr,
466 port: u16,
467 config: SocketConfig,
468) -> io::Result<(UdpSocket, TcpListener)> {
469 let sock = udp_socket_with_config(config.into())?;
470
471 let addr = SocketAddr::new(ip_addr, port);
472 let sock_addr = SockAddr::from(addr);
473 sock.bind(&sock_addr)
474 .and_then(|_| TcpListener::bind(addr).map(|listener| (sock.into(), listener)))
475}
476
477#[deprecated(
478 since = "3.0.0",
479 note = "Please avoid this function, in favor of \
480 sockets::bind_two_in_range_with_offset_and_config"
481)]
482#[allow(deprecated)]
483pub fn bind_two_in_range_with_offset(
484 ip_addr: IpAddr,
485 range: PortRange,
486 offset: u16,
487) -> io::Result<((u16, UdpSocket), (u16, UdpSocket))> {
488 let sock_config = sockets::SocketConfiguration::default();
489 sockets::bind_two_in_range_with_offset_and_config(
490 ip_addr,
491 range,
492 offset,
493 sock_config,
494 sock_config,
495 )
496}
497
498#[deprecated(
499 since = "3.0.0",
500 note = "Please avoid this function, in favor of \
501 sockets::bind_two_in_range_with_offset_and_config"
502)]
503#[allow(deprecated)]
504pub fn bind_two_in_range_with_offset_and_config(
505 ip_addr: IpAddr,
506 range: PortRange,
507 offset: u16,
508 sock1_config: SocketConfig,
509 sock2_config: SocketConfig,
510) -> io::Result<((u16, UdpSocket), (u16, UdpSocket))> {
511 if range.1.saturating_sub(range.0) < offset {
512 return Err(io::Error::other(
513 "range too small to find two ports with the correct offset".to_string(),
514 ));
515 }
516
517 for port in range.0..range.1 {
518 let first_bind = bind_to_with_config(ip_addr, port, sock1_config);
519 if let Ok(first_bind) = first_bind {
520 if range.1.saturating_sub(port) >= offset {
521 let second_bind =
522 bind_to_with_config(ip_addr, port.saturating_add(offset), sock2_config);
523 if let Ok(second_bind) = second_bind {
524 return Ok((
525 (first_bind.local_addr().unwrap().port(), first_bind),
526 (second_bind.local_addr().unwrap().port(), second_bind),
527 ));
528 }
529 } else {
530 break;
531 }
532 }
533 }
534 Err(io::Error::other(
535 "couldn't find two ports with the correct offset in range".to_string(),
536 ))
537}
538
539pub fn find_available_port_in_range(ip_addr: IpAddr, range: PortRange) -> io::Result<u16> {
546 let [port] = find_available_ports_in_range(ip_addr, range)?;
547 Ok(port)
548}
549
550pub fn find_available_ports_in_range<const N: usize>(
555 ip_addr: IpAddr,
556 range: PortRange,
557) -> io::Result<[u16; N]> {
558 let mut result = [0u16; N];
559 let range = range.0..range.1;
560 let mut next_port_to_try = range
561 .clone()
562 .cycle() .skip(thread_rng().gen_range(range.clone()) as usize) .take(range.len()) .peekable();
566 let mut num = 0;
567 let config = sockets::SocketConfiguration::default();
568 while num < N {
569 let port_to_try = next_port_to_try.next().unwrap(); let bind = sockets::bind_common_with_config(ip_addr, port_to_try, config);
571 match bind {
572 Ok(_) => {
573 result[num] = port_to_try;
574 num = num.saturating_add(1);
575 }
576 Err(err) => {
577 if next_port_to_try.peek().is_none() {
578 return Err(err);
579 }
580 }
581 }
582 }
583 Ok(result)
584}
585
586#[deprecated(
587 since = "3.0.0",
588 note = "Please avoid this function, in favor of sockets::bind_more_with_config"
589)]
590#[allow(deprecated)]
591pub fn bind_more_with_config(
592 socket: UdpSocket,
593 num: usize,
594 config: SocketConfig,
595) -> io::Result<Vec<UdpSocket>> {
596 if !PLATFORM_SUPPORTS_SOCKET_CONFIGS {
597 if num > 1 {
598 warn!(
599 "bind_more_with_config() only supports 1 socket on this platform ({num} requested)"
600 );
601 }
602 Ok(vec![socket])
603 } else {
604 let addr = socket.local_addr().unwrap();
605 let ip = addr.ip();
606 let port = addr.port();
607 std::iter::once(Ok(socket))
608 .chain((1..num).map(|_| bind_to_with_config(ip, port, config)))
609 .collect()
610 }
611}
612
613#[cfg(test)]
614#[allow(deprecated)]
615mod tests {
616 use {
617 super::*,
618 crate::sockets::unique_port_range_for_tests,
619 ip_echo_server::IpEchoServerResponse,
620 itertools::Itertools,
621 std::{net::Ipv4Addr, time::Duration},
622 tokio::runtime::Runtime,
623 };
624
625 fn runtime() -> Runtime {
626 tokio::runtime::Builder::new_current_thread()
627 .enable_all()
628 .build()
629 .expect("Can not create a runtime")
630 }
631 #[test]
632 fn test_response_length() {
633 let resp = IpEchoServerResponse {
634 address: IpAddr::from([u16::MAX; 8]), shred_version: Some(u16::MAX),
636 };
637 let resp_size = bincode::serialized_size(&resp).unwrap();
638 assert_eq!(
639 IP_ECHO_SERVER_RESPONSE_LENGTH,
640 HEADER_LENGTH + resp_size as usize
641 );
642 }
643
644 #[test]
646 fn test_backward_compat() {
647 let address = IpAddr::from([
648 525u16, 524u16, 523u16, 522u16, 521u16, 520u16, 519u16, 518u16,
649 ]);
650 let response = IpEchoServerResponse {
651 address,
652 shred_version: Some(42),
653 };
654 let mut data = vec![0u8; IP_ECHO_SERVER_RESPONSE_LENGTH];
655 bincode::serialize_into(&mut data[HEADER_LENGTH..], &response).unwrap();
656 data.truncate(HEADER_LENGTH + 20);
657 assert_eq!(
658 bincode::deserialize::<IpAddr>(&data[HEADER_LENGTH..]).unwrap(),
659 address
660 );
661 }
662
663 #[test]
665 fn test_forward_compat() {
666 let address = IpAddr::from([
667 525u16, 524u16, 523u16, 522u16, 521u16, 520u16, 519u16, 518u16,
668 ]);
669 let mut data = [0u8; IP_ECHO_SERVER_RESPONSE_LENGTH];
670 bincode::serialize_into(&mut data[HEADER_LENGTH..], &address).unwrap();
671 let response: Result<IpEchoServerResponse, _> =
672 bincode::deserialize(&data[HEADER_LENGTH..]);
673 assert_eq!(
674 response.unwrap(),
675 IpEchoServerResponse {
676 address,
677 shred_version: None,
678 }
679 );
680 }
681
682 #[test]
683 fn test_parse_port_or_addr() {
684 let p1 = parse_port_or_addr(Some("9000"), SocketAddr::from(([1, 2, 3, 4], 1)));
685 assert_eq!(p1.port(), 9000);
686 let p2 = parse_port_or_addr(Some("127.0.0.1:7000"), SocketAddr::from(([1, 2, 3, 4], 1)));
687 assert_eq!(p2.port(), 7000);
688 let p2 = parse_port_or_addr(Some("hi there"), SocketAddr::from(([1, 2, 3, 4], 1)));
689 assert_eq!(p2.port(), 1);
690 let p3 = parse_port_or_addr(None, SocketAddr::from(([1, 2, 3, 4], 1)));
691 assert_eq!(p3.port(), 1);
692 }
693
694 #[test]
695 fn test_parse_port_range() {
696 assert_eq!(parse_port_range("garbage"), None);
697 assert_eq!(parse_port_range("1-"), None);
698 assert_eq!(parse_port_range("1-2"), Some((1, 2)));
699 assert_eq!(parse_port_range("1-2-3"), None);
700 assert_eq!(parse_port_range("2-1"), None);
701 }
702
703 #[test]
704 fn test_parse_host() {
705 parse_host("localhost:1234").unwrap_err();
706 parse_host("localhost").unwrap();
707 parse_host("127.0.0.0:1234").unwrap_err();
708 parse_host("127.0.0.0").unwrap();
709 }
710
711 #[test]
712 fn test_parse_host_port() {
713 parse_host_port("localhost:1234").unwrap();
714 parse_host_port("localhost").unwrap_err();
715 parse_host_port("127.0.0.0:1234").unwrap();
716 parse_host_port("127.0.0.0").unwrap_err();
717 }
718
719 #[test]
720 fn test_is_host_port() {
721 assert!(is_host_port("localhost:1234".to_string()).is_ok());
722 assert!(is_host_port("localhost".to_string()).is_err());
723 }
724
725 #[test]
726 fn test_bind() {
727 let (pr_s, pr_e) = sockets::localhost_port_range_for_tests();
728 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
729 let s = bind_in_range(ip_addr, (pr_s, pr_e)).unwrap();
730 assert_eq!(s.0, pr_s, "bind_in_range should use first available port");
731 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
732 let config = SocketConfig::default().reuseport(true);
733 let x = bind_to_with_config(ip_addr, pr_s + 1, config).unwrap();
734 let y = bind_to_with_config(ip_addr, pr_s + 1, config).unwrap();
735 assert_eq!(
736 x.local_addr().unwrap().port(),
737 y.local_addr().unwrap().port()
738 );
739 bind_to(ip_addr, pr_s, false).unwrap_err();
740 bind_in_range(ip_addr, (pr_s, pr_s + 2)).unwrap_err();
741
742 let (port, v) =
743 multi_bind_in_range_with_config(ip_addr, (pr_s + 5, pr_e), config, 10).unwrap();
744 for sock in &v {
745 assert_eq!(port, sock.local_addr().unwrap().port());
746 }
747 }
748
749 #[test]
750 fn test_bind_with_any_port() {
751 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
752 let config = SocketConfig::default();
753 let x = bind_with_any_port_with_config(ip_addr, config).unwrap();
754 let y = bind_with_any_port_with_config(ip_addr, config).unwrap();
755 assert_ne!(
756 x.local_addr().unwrap().port(),
757 y.local_addr().unwrap().port()
758 );
759 }
760
761 #[test]
762 fn test_bind_in_range_nil() {
763 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
764 let range = sockets::unique_port_range_for_tests(2);
765 bind_in_range(ip_addr, (range.end, range.end)).unwrap_err();
766 bind_in_range(ip_addr, (range.end, range.start)).unwrap_err();
767 }
768
769 #[test]
770 fn test_find_available_port_in_range() {
771 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
772 let range = sockets::unique_port_range_for_tests(4);
773 let (pr_s, pr_e) = (range.start, range.end);
774 assert_eq!(
775 find_available_port_in_range(ip_addr, (pr_s, pr_s + 1)).unwrap(),
776 pr_s
777 );
778 let port = find_available_port_in_range(ip_addr, (pr_s, pr_e)).unwrap();
779 assert!((pr_s..pr_e).contains(&port));
780
781 let _socket = bind_to(ip_addr, port, false).unwrap();
782 find_available_port_in_range(ip_addr, (port, port + 1)).unwrap_err();
783 }
784
785 #[test]
786 fn test_find_available_ports_in_range() {
787 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
788 let port_range = sockets::localhost_port_range_for_tests();
789 assert!(port_range.1 - port_range.0 > 16);
790 let sock = bind_to_with_config(ip_addr, port_range.0 + 2, SocketConfig::default()).unwrap();
792 let ports: [u16; 15] = find_available_ports_in_range(ip_addr, port_range).unwrap();
793 let mut ports_vec = Vec::from(ports);
794 ports_vec.push(sock.local_addr().unwrap().port());
795 let res: Vec<_> = ports_vec.into_iter().unique().collect();
796 assert_eq!(res.len(), 16, "Should reserve 16 unique ports");
797 }
798
799 #[test]
800 fn test_bind_common_in_range() {
801 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
802 let range = sockets::unique_port_range_for_tests(5);
803 let config = SocketConfig::default();
804 let (port, _sockets) =
805 bind_common_in_range_with_config(ip_addr, (range.start, range.end), config).unwrap();
806 assert!(range.contains(&port));
807 bind_common_in_range_with_config(ip_addr, (port, port + 1), config).unwrap_err();
808 }
809
810 #[test]
811 fn test_get_public_ip_addr_none() {
812 solana_logger::setup();
813 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
814 let (pr_s, pr_e) = sockets::localhost_port_range_for_tests();
815 let config = SocketConfig::default();
816 let (_server_port, (server_udp_socket, server_tcp_listener)) =
817 bind_common_in_range_with_config(ip_addr, (pr_s, pr_e), config).unwrap();
818
819 let _runtime = ip_echo_server(
820 server_tcp_listener,
821 DEFAULT_IP_ECHO_SERVER_THREADS,
822 Some(42),
823 );
824
825 let server_ip_echo_addr = server_udp_socket.local_addr().unwrap();
826 assert_eq!(
827 get_public_ip_addr_with_binding(
828 &server_ip_echo_addr,
829 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
830 )
831 .unwrap(),
832 parse_host("127.0.0.1").unwrap(),
833 );
834 assert_eq!(get_cluster_shred_version(&server_ip_echo_addr).unwrap(), 42);
835 assert!(verify_all_reachable_tcp(&server_ip_echo_addr, vec![],));
836 assert!(verify_all_reachable_udp(&server_ip_echo_addr, &[],));
837 }
838
839 #[test]
840 fn test_get_public_ip_addr_reachable() {
841 solana_logger::setup();
842 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
843 let port_range = sockets::localhost_port_range_for_tests();
844 let config = SocketConfig::default();
845 let (_server_port, (server_udp_socket, server_tcp_listener)) =
846 bind_common_in_range_with_config(ip_addr, port_range, config).unwrap();
847 let (_client_port, (client_udp_socket, client_tcp_listener)) =
848 bind_common_in_range_with_config(ip_addr, port_range, config).unwrap();
849
850 let _runtime = ip_echo_server(
851 server_tcp_listener,
852 DEFAULT_IP_ECHO_SERVER_THREADS,
853 Some(65535),
854 );
855
856 let ip_echo_server_addr = server_udp_socket.local_addr().unwrap();
857 assert_eq!(
858 get_public_ip_addr_with_binding(
859 &ip_echo_server_addr,
860 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
861 )
862 .unwrap(),
863 parse_host("127.0.0.1").unwrap(),
864 );
865 assert_eq!(
866 get_cluster_shred_version(&ip_echo_server_addr).unwrap(),
867 65535
868 );
869 assert!(verify_all_reachable_tcp(
870 &ip_echo_server_addr,
871 vec![client_tcp_listener],
872 ));
873 assert!(verify_all_reachable_udp(
874 &ip_echo_server_addr,
875 &[&client_udp_socket],
876 ));
877 }
878
879 #[test]
880 fn test_verify_ports_tcp_unreachable() {
881 solana_logger::setup();
882 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
883 let port_range = sockets::localhost_port_range_for_tests();
884 let config = SocketConfig::default();
885 let (_server_port, (server_udp_socket, _server_tcp_listener)) =
886 bind_common_in_range_with_config(ip_addr, port_range, config).unwrap();
887
888 let server_ip_echo_addr = server_udp_socket.local_addr().unwrap();
890
891 let (_, (_client_udp_socket, client_tcp_listener)) =
892 bind_common_in_range_with_config(ip_addr, port_range, config).unwrap();
893
894 let rt = runtime();
895 assert!(!rt.block_on(ip_echo_client::verify_all_reachable_tcp(
896 server_ip_echo_addr,
897 vec![client_tcp_listener],
898 Duration::from_secs(2),
899 )));
900 }
901
902 #[test]
903 fn test_verify_ports_udp_unreachable() {
904 solana_logger::setup();
905 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
906 let port_range = unique_port_range_for_tests(2);
907 let config = SocketConfig::default();
908 let (_server_port, (server_udp_socket, _server_tcp_listener)) =
909 bind_common_in_range_with_config(ip_addr, (port_range.start, port_range.end), config)
910 .unwrap();
911
912 let server_ip_echo_addr = server_udp_socket.local_addr().unwrap();
914
915 let (_correct_client_port, (client_udp_socket, _client_tcp_listener)) =
916 bind_common_in_range_with_config(ip_addr, (port_range.start, port_range.end), config)
917 .unwrap();
918
919 let rt = runtime();
920 assert!(!rt.block_on(ip_echo_client::verify_all_reachable_udp(
921 server_ip_echo_addr,
922 &[&client_udp_socket],
923 Duration::from_secs(2),
924 3,
925 )));
926 }
927
928 #[test]
929 fn test_verify_many_ports_reachable() {
930 solana_logger::setup();
931 let ip_addr = IpAddr::V4(Ipv4Addr::LOCALHOST);
932 let config = SocketConfig::default();
933 let mut tcp_listeners = vec![];
934 let mut udp_sockets = vec![];
935
936 let port_range = unique_port_range_for_tests(1);
937 let (_server_port, (_, server_tcp_listener)) =
938 bind_common_in_range_with_config(ip_addr, (port_range.start, port_range.end), config)
939 .unwrap();
940 for _ in 0..MAX_PORT_VERIFY_THREADS * 2 {
941 let port_range = unique_port_range_for_tests(1);
942 let (_client_port, (client_udp_socket, client_tcp_listener)) =
943 bind_common_in_range_with_config(
944 ip_addr,
945 (port_range.start, port_range.end),
946 config,
947 )
948 .unwrap();
949 tcp_listeners.push(client_tcp_listener);
950 udp_sockets.push(client_udp_socket);
951 }
952
953 let ip_echo_server_addr = server_tcp_listener.local_addr().unwrap();
954
955 let _runtime = ip_echo_server(
956 server_tcp_listener,
957 DEFAULT_IP_ECHO_SERVER_THREADS,
958 Some(65535),
959 );
960
961 assert_eq!(
962 get_public_ip_addr_with_binding(
963 &ip_echo_server_addr,
964 IpAddr::V4(Ipv4Addr::UNSPECIFIED)
965 )
966 .unwrap(),
967 parse_host("127.0.0.1").unwrap(),
968 );
969
970 let socket_refs = udp_sockets.iter().collect_vec();
971 assert!(verify_all_reachable_tcp(
972 &ip_echo_server_addr,
973 tcp_listeners,
974 ));
975 assert!(verify_all_reachable_udp(&ip_echo_server_addr, &socket_refs));
976 }
977
978 #[test]
979 fn test_bind_two_in_range_with_offset() {
980 solana_logger::setup();
981 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
982 let offset = 6;
983 let port_range = unique_port_range_for_tests(10);
984 if let Ok(((port1, _), (port2, _))) =
985 bind_two_in_range_with_offset(ip_addr, (port_range.start, port_range.end), offset)
986 {
987 assert!(port2 == port1 + offset);
988 }
989 let offset = 7;
990 if let Ok(((port1, _), (port2, _))) =
991 bind_two_in_range_with_offset(ip_addr, (port_range.start, port_range.end), offset)
992 {
993 assert!(port2 == port1 + offset);
994 }
995 assert!(bind_two_in_range_with_offset(
996 ip_addr,
997 (port_range.start, port_range.start + 5),
998 offset
999 )
1000 .is_err());
1001 }
1002
1003 #[test]
1004 fn test_multi_bind_in_range_with_config_reuseport_disabled() {
1005 let ip_addr: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
1006 let config = SocketConfig::default(); let port_range = unique_port_range_for_tests(3);
1009 let result =
1010 multi_bind_in_range_with_config(ip_addr, (port_range.start, port_range.end), config, 2);
1011
1012 assert!(
1013 result.is_err(),
1014 "Expected an error when reuseport is not set to true"
1015 );
1016 }
1017
1018 #[test]
1019 fn test_verify_udp_multiple_ips_reachable() {
1020 solana_logger::setup();
1021 let config = SocketConfig::default();
1022 let ip_a = IpAddr::V4(Ipv4Addr::LOCALHOST);
1023 let ip_b = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2));
1024
1025 let port_range = sockets::localhost_port_range_for_tests();
1026
1027 let (_srv_udp_port, (srv_udp_sock, srv_tcp_listener)) =
1028 bind_common_in_range_with_config(ip_a, port_range, config).unwrap();
1029
1030 let ip_echo_server_addr = srv_udp_sock.local_addr().unwrap();
1031 let _runtime = ip_echo_server(
1032 srv_tcp_listener,
1033 DEFAULT_IP_ECHO_SERVER_THREADS,
1034 Some(42),
1035 );
1036
1037 let mut udp_sockets = Vec::new();
1038 let (_p1, (sock_a, _tl_a)) =
1039 bind_common_in_range_with_config(ip_a, port_range, config).unwrap();
1040 let (_p2, (sock_b, _tl_b)) =
1041 bind_common_in_range_with_config(ip_b, port_range, config).unwrap();
1042
1043 udp_sockets.push(sock_a);
1044 udp_sockets.push(sock_b);
1045
1046 let socket_refs: Vec<&UdpSocket> = udp_sockets.iter().collect();
1047
1048 assert!(
1049 verify_all_reachable_udp(&ip_echo_server_addr, &socket_refs),
1050 "all UDP ports on both 127.0.0.1 and 127.0.0.2 should be reachable"
1051 );
1052 }
1053}