1#![allow(clippy::arithmetic_side_effects)]
3use {
4 crossbeam_channel::unbounded,
5 log::*,
6 rand::{thread_rng, Rng},
7 socket2::{Domain, SockAddr, Socket, Type},
8 std::{
9 collections::{BTreeMap, HashSet},
10 io::{self, Read, Write},
11 net::{IpAddr, SocketAddr, TcpListener, TcpStream, ToSocketAddrs, UdpSocket},
12 sync::{Arc, RwLock},
13 time::{Duration, Instant},
14 },
15 url::Url,
16};
17
18mod ip_echo_server;
19pub use ip_echo_server::{
20 ip_echo_server, IpEchoServer, DEFAULT_IP_ECHO_SERVER_THREADS, MAX_PORT_COUNT_PER_MESSAGE,
21 MINIMUM_IP_ECHO_SERVER_THREADS,
22};
23use ip_echo_server::{IpEchoServerMessage, IpEchoServerResponse};
24
25pub struct UdpSocketPair {
27 pub addr: SocketAddr, pub receiver: UdpSocket, pub sender: UdpSocket, }
31
32pub type PortRange = (u16, u16);
33
34pub const VALIDATOR_PORT_RANGE: PortRange = (8000, 10_000);
35pub const MINIMUM_VALIDATOR_PORT_RANGE_WIDTH: u16 = 16; pub(crate) const HEADER_LENGTH: usize = 4;
38pub(crate) const IP_ECHO_SERVER_RESPONSE_LENGTH: usize = HEADER_LENGTH + 23;
39
40fn ip_echo_server_request(
41 ip_echo_server_addr: &SocketAddr,
42 msg: IpEchoServerMessage,
43) -> Result<IpEchoServerResponse, String> {
44 let timeout = Duration::new(5, 0);
45 TcpStream::connect_timeout(ip_echo_server_addr, timeout)
46 .and_then(|mut stream| {
47 let mut bytes = vec![0; HEADER_LENGTH];
49
50 bytes.append(&mut bincode::serialize(&msg).expect("serialize IpEchoServerMessage"));
51
52 bytes.push(b'\n');
55
56 stream.set_read_timeout(Some(Duration::new(10, 0)))?;
57 stream.write_all(&bytes)?;
58 stream.shutdown(std::net::Shutdown::Write)?;
59 let mut data = vec![0u8; IP_ECHO_SERVER_RESPONSE_LENGTH];
60 let _ = stream.read(&mut data[..])?;
61 Ok(data)
62 })
63 .and_then(|data| {
64 if data.len() < HEADER_LENGTH {
68 return Err(io::Error::new(
69 io::ErrorKind::Other,
70 format!("Response too short, received {} bytes", data.len()),
71 ));
72 }
73
74 let response_header: String =
75 data[0..HEADER_LENGTH].iter().map(|b| *b as char).collect();
76 if response_header != "\0\0\0\0" {
77 if response_header == "HTTP" {
78 let http_response = data.iter().map(|b| *b as char).collect::<String>();
79 return Err(io::Error::new(
80 io::ErrorKind::Other,
81 format!(
82 "Invalid gossip entrypoint. {ip_echo_server_addr} looks to be an HTTP port: {http_response}"
83 ),
84 ));
85 }
86 return Err(io::Error::new(
87 io::ErrorKind::Other,
88 format!(
89 "Invalid gossip entrypoint. {ip_echo_server_addr} provided an invalid response header: '{response_header}'"
90 ),
91 ));
92 }
93
94 bincode::deserialize(&data[HEADER_LENGTH..]).map_err(|err| {
95 io::Error::new(
96 io::ErrorKind::Other,
97 format!("Failed to deserialize: {err:?}"),
98 )
99 })
100 })
101 .map_err(|err| err.to_string())
102}
103
104pub fn get_public_ip_addr(ip_echo_server_addr: &SocketAddr) -> Result<IpAddr, String> {
107 let resp = ip_echo_server_request(ip_echo_server_addr, IpEchoServerMessage::default())?;
108 Ok(resp.address)
109}
110
111pub fn get_cluster_shred_version(ip_echo_server_addr: &SocketAddr) -> Result<u16, String> {
112 let resp = ip_echo_server_request(ip_echo_server_addr, IpEchoServerMessage::default())?;
113 resp.shred_version
114 .ok_or_else(|| String::from("IP echo server does not return a shred-version"))
115}
116
117const DEFAULT_TIMEOUT_SECS: u64 = 5;
120const DEFAULT_RETRY_COUNT: usize = 5;
121
122fn do_verify_reachable_ports(
123 ip_echo_server_addr: &SocketAddr,
124 tcp_listeners: Vec<(u16, TcpListener)>,
125 udp_sockets: &[&UdpSocket],
126 timeout: u64,
127 udp_retry_count: usize,
128) -> bool {
129 info!(
130 "Checking that tcp ports {:?} are reachable from {:?}",
131 tcp_listeners, ip_echo_server_addr
132 );
133
134 let tcp_ports: Vec<_> = tcp_listeners.iter().map(|(port, _)| *port).collect();
135 let _ = ip_echo_server_request(
136 ip_echo_server_addr,
137 IpEchoServerMessage::new(&tcp_ports, &[]),
138 )
139 .map_err(|err| warn!("ip_echo_server request failed: {}", err));
140
141 let mut ok = true;
142 let timeout = Duration::from_secs(timeout);
143
144 for (port, tcp_listener) in tcp_listeners {
146 let (sender, receiver) = unbounded();
147 let listening_addr = tcp_listener.local_addr().unwrap();
148 let thread_handle = std::thread::Builder::new()
149 .name(format!("solVrfyTcp{port:05}"))
150 .spawn(move || {
151 debug!("Waiting for incoming connection on tcp/{}", port);
152 match tcp_listener.incoming().next() {
153 Some(_) => sender
154 .send(())
155 .unwrap_or_else(|err| warn!("send failure: {}", err)),
156 None => warn!("tcp incoming failed"),
157 }
158 })
159 .unwrap();
160 match receiver.recv_timeout(timeout) {
161 Ok(_) => {
162 info!("tcp/{} is reachable", port);
163 }
164 Err(err) => {
165 error!(
166 "Received no response at tcp/{}, check your port configuration: {}",
167 port, err
168 );
169 TcpStream::connect_timeout(&listening_addr, timeout).unwrap();
174 ok = false;
175 }
176 }
177 thread_handle.join().unwrap();
179 }
180
181 if !ok {
182 return ok;
184 }
185
186 let mut udp_ports: BTreeMap<_, _> = BTreeMap::new();
187 udp_sockets.iter().for_each(|udp_socket| {
188 let port = udp_socket.local_addr().unwrap().port();
189 udp_ports
190 .entry(port)
191 .or_insert_with(Vec::new)
192 .push(udp_socket);
193 });
194 let udp_ports: Vec<_> = udp_ports.into_iter().collect();
195
196 info!(
197 "Checking that udp ports {:?} are reachable from {:?}",
198 udp_ports.iter().map(|(port, _)| port).collect::<Vec<_>>(),
199 ip_echo_server_addr
200 );
201
202 'outer: for checked_ports_and_sockets in udp_ports.chunks(MAX_PORT_COUNT_PER_MESSAGE) {
203 ok = false;
204
205 for udp_remaining_retry in (0_usize..udp_retry_count).rev() {
206 let (checked_ports, checked_socket_iter) = (
207 checked_ports_and_sockets
208 .iter()
209 .map(|(port, _)| *port)
210 .collect::<Vec<_>>(),
211 checked_ports_and_sockets
212 .iter()
213 .flat_map(|(_, sockets)| sockets),
214 );
215
216 let _ = ip_echo_server_request(
217 ip_echo_server_addr,
218 IpEchoServerMessage::new(&[], &checked_ports),
219 )
220 .map_err(|err| warn!("ip_echo_server request failed: {}", err));
221
222 let reachable_ports = Arc::new(RwLock::new(HashSet::new()));
224 let thread_handles: Vec<_> = checked_socket_iter
225 .map(|udp_socket| {
226 let port = udp_socket.local_addr().unwrap().port();
227 let udp_socket = udp_socket.try_clone().expect("Unable to clone udp socket");
228 let reachable_ports = reachable_ports.clone();
229
230 std::thread::Builder::new()
231 .name(format!("solVrfyUdp{port:05}"))
232 .spawn(move || {
233 let start = Instant::now();
234
235 let original_read_timeout = udp_socket.read_timeout().unwrap();
236 udp_socket
237 .set_read_timeout(Some(Duration::from_millis(250)))
238 .unwrap();
239 loop {
240 if reachable_ports.read().unwrap().contains(&port)
241 || Instant::now().duration_since(start) >= timeout
242 {
243 break;
244 }
245
246 let recv_result = udp_socket.recv(&mut [0; 1]);
247 debug!(
248 "Waited for incoming datagram on udp/{}: {:?}",
249 port, recv_result
250 );
251
252 if recv_result.is_ok() {
253 reachable_ports.write().unwrap().insert(port);
254 break;
255 }
256 }
257 udp_socket.set_read_timeout(original_read_timeout).unwrap();
258 })
259 .unwrap()
260 })
261 .collect();
262
263 for thread in thread_handles {
268 thread.join().unwrap();
269 }
270
271 let reachable_ports = reachable_ports.read().unwrap().clone();
272 if reachable_ports.len() == checked_ports.len() {
273 info!(
274 "checked udp ports: {:?}, reachable udp ports: {:?}",
275 checked_ports, reachable_ports
276 );
277 ok = true;
278 break;
279 } else if udp_remaining_retry > 0 {
280 error!(
282 "checked udp ports: {:?}, reachable udp ports: {:?}",
283 checked_ports, reachable_ports
284 );
285 error!("There are some udp ports with no response!! Retrying...");
286 } else {
287 error!("Maximum retry count is reached....");
288 break 'outer;
289 }
290 }
291 }
292
293 ok
294}
295
296pub fn verify_reachable_ports(
297 ip_echo_server_addr: &SocketAddr,
298 tcp_listeners: Vec<(u16, TcpListener)>,
299 udp_sockets: &[&UdpSocket],
300) -> bool {
301 do_verify_reachable_ports(
302 ip_echo_server_addr,
303 tcp_listeners,
304 udp_sockets,
305 DEFAULT_TIMEOUT_SECS,
306 DEFAULT_RETRY_COUNT,
307 )
308}
309
310pub fn parse_port_or_addr(optstr: Option<&str>, default_addr: SocketAddr) -> SocketAddr {
311 if let Some(addrstr) = optstr {
312 if let Ok(port) = addrstr.parse() {
313 let mut addr = default_addr;
314 addr.set_port(port);
315 addr
316 } else if let Ok(addr) = addrstr.parse() {
317 addr
318 } else {
319 default_addr
320 }
321 } else {
322 default_addr
323 }
324}
325
326pub fn parse_port_range(port_range: &str) -> Option<PortRange> {
327 let ports: Vec<&str> = port_range.split('-').collect();
328 if ports.len() != 2 {
329 return None;
330 }
331
332 let start_port = ports[0].parse();
333 let end_port = ports[1].parse();
334
335 if start_port.is_err() || end_port.is_err() {
336 return None;
337 }
338 let start_port = start_port.unwrap();
339 let end_port = end_port.unwrap();
340 if end_port < start_port {
341 return None;
342 }
343 Some((start_port, end_port))
344}
345
346pub fn parse_host(host: &str) -> Result<IpAddr, String> {
347 let parsed_url = Url::parse(&format!("http://{host}")).map_err(|e| e.to_string())?;
350 if parsed_url.port().is_some() {
351 return Err(format!("Expected port in URL: {host}"));
352 }
353
354 let ips: Vec<_> = (host, 0)
356 .to_socket_addrs()
357 .map_err(|err| err.to_string())?
358 .map(|socket_address| socket_address.ip())
359 .collect();
360 if ips.is_empty() {
361 Err(format!("Unable to resolve host: {host}"))
362 } else {
363 Ok(ips[0])
364 }
365}
366
367pub fn is_host(string: String) -> Result<(), String> {
368 parse_host(&string).map(|_| ())
369}
370
371pub fn parse_host_port(host_port: &str) -> Result<SocketAddr, String> {
372 let addrs: Vec<_> = host_port
373 .to_socket_addrs()
374 .map_err(|err| format!("Unable to resolve host {host_port}: {err}"))?
375 .collect();
376 if addrs.is_empty() {
377 Err(format!("Unable to resolve host: {host_port}"))
378 } else {
379 Ok(addrs[0])
380 }
381}
382
383pub fn is_host_port(string: String) -> Result<(), String> {
384 parse_host_port(&string).map(|_| ())
385}
386
387#[derive(Clone, Debug)]
388pub struct SocketConfig {
389 pub reuseport: bool,
390}
391
392impl Default for SocketConfig {
393 #[allow(clippy::derivable_impls)]
394 fn default() -> Self {
395 Self { reuseport: false }
396 }
397}
398
399#[cfg(any(windows, target_os = "ios"))]
400fn udp_socket(_reuseaddr: bool) -> io::Result<Socket> {
401 let sock = Socket::new(Domain::IPV4, Type::DGRAM, None)?;
402 Ok(sock)
403}
404
405#[cfg(any(windows, target_os = "ios"))]
406fn udp_socket_with_config(_config: SocketConfig) -> io::Result<Socket> {
407 let sock = Socket::new(Domain::IPV4, Type::DGRAM, None)?;
408 Ok(sock)
409}
410
411#[cfg(not(any(windows, target_os = "ios")))]
412fn udp_socket(reuseport: bool) -> io::Result<Socket> {
413 let config = SocketConfig { reuseport };
414 udp_socket_with_config(config)
415}
416
417#[cfg(not(any(windows, target_os = "ios")))]
418fn udp_socket_with_config(config: SocketConfig) -> io::Result<Socket> {
419 use nix::sys::socket::{setsockopt, sockopt::ReusePort};
420 let SocketConfig { reuseport } = config;
421
422 let sock = Socket::new(Domain::IPV4, Type::DGRAM, None)?;
423
424 if reuseport {
425 setsockopt(&sock, ReusePort, &true).ok();
426 }
427
428 Ok(sock)
429}
430
431pub fn bind_common_in_range(
433 ip_addr: IpAddr,
434 range: PortRange,
435) -> io::Result<(u16, (UdpSocket, TcpListener))> {
436 for port in range.0..range.1 {
437 if let Ok((sock, listener)) = bind_common(ip_addr, port) {
438 return Result::Ok((sock.local_addr().unwrap().port(), (sock, listener)));
439 }
440 }
441
442 Err(io::Error::new(
443 io::ErrorKind::Other,
444 format!("No available TCP/UDP ports in {range:?}"),
445 ))
446}
447
448pub fn bind_in_range(ip_addr: IpAddr, range: PortRange) -> io::Result<(u16, UdpSocket)> {
449 let config = SocketConfig::default();
450 bind_in_range_with_config(ip_addr, range, config)
451}
452
453pub fn bind_in_range_with_config(
454 ip_addr: IpAddr,
455 range: PortRange,
456 config: SocketConfig,
457) -> io::Result<(u16, UdpSocket)> {
458 let sock = udp_socket_with_config(config)?;
459
460 for port in range.0..range.1 {
461 let addr = SocketAddr::new(ip_addr, port);
462
463 if sock.bind(&SockAddr::from(addr)).is_ok() {
464 let sock: UdpSocket = sock.into();
465 return Result::Ok((sock.local_addr().unwrap().port(), sock));
466 }
467 }
468
469 Err(io::Error::new(
470 io::ErrorKind::Other,
471 format!("No available UDP ports in {range:?}"),
472 ))
473}
474
475pub fn bind_with_any_port(ip_addr: IpAddr) -> io::Result<UdpSocket> {
476 let sock = udp_socket(false)?;
477 let addr = SocketAddr::new(ip_addr, 0);
478 match sock.bind(&SockAddr::from(addr)) {
479 Ok(_) => Result::Ok(sock.into()),
480 Err(err) => Err(io::Error::new(
481 io::ErrorKind::Other,
482 format!("No available UDP port: {err}"),
483 )),
484 }
485}
486
487pub fn multi_bind_in_range(
489 ip_addr: IpAddr,
490 range: PortRange,
491 mut num: usize,
492) -> io::Result<(u16, Vec<UdpSocket>)> {
493 if cfg!(windows) && num != 1 {
494 warn!(
496 "multi_bind_in_range() only supports 1 socket in windows ({} requested)",
497 num
498 );
499 num = 1;
500 }
501 let mut sockets = Vec::with_capacity(num);
502
503 const NUM_TRIES: usize = 100;
504 let mut port = 0;
505 let mut error = None;
506 for _ in 0..NUM_TRIES {
507 port = {
508 let (port, _) = bind_in_range(ip_addr, range)?;
509 port
510 }; let config = SocketConfig { reuseport: true };
513 for _ in 0..num {
514 let sock = bind_to_with_config(ip_addr, port, config.clone());
515 if let Ok(sock) = sock {
516 sockets.push(sock);
517 } else {
518 error = Some(sock);
519 break;
520 }
521 }
522 if sockets.len() == num {
523 break;
524 } else {
525 sockets.clear();
526 }
527 }
528 if sockets.len() != num {
529 error.unwrap()?;
530 }
531 Ok((port, sockets))
532}
533
534pub fn bind_to(ip_addr: IpAddr, port: u16, reuseport: bool) -> io::Result<UdpSocket> {
535 let config = SocketConfig { reuseport };
536 bind_to_with_config(ip_addr, port, config)
537}
538
539pub fn bind_to_with_config(
540 ip_addr: IpAddr,
541 port: u16,
542 config: SocketConfig,
543) -> io::Result<UdpSocket> {
544 let sock = udp_socket_with_config(config)?;
545
546 let addr = SocketAddr::new(ip_addr, port);
547
548 sock.bind(&SockAddr::from(addr)).map(|_| sock.into())
549}
550
551pub fn bind_common(ip_addr: IpAddr, port: u16) -> io::Result<(UdpSocket, TcpListener)> {
553 let config = SocketConfig { reuseport: false };
554 bind_common_with_config(ip_addr, port, config)
555}
556
557pub fn bind_common_with_config(
559 ip_addr: IpAddr,
560 port: u16,
561 config: SocketConfig,
562) -> io::Result<(UdpSocket, TcpListener)> {
563 let sock = udp_socket_with_config(config)?;
564
565 let addr = SocketAddr::new(ip_addr, port);
566 let sock_addr = SockAddr::from(addr);
567 sock.bind(&sock_addr)
568 .and_then(|_| TcpListener::bind(addr).map(|listener| (sock.into(), listener)))
569}
570
571pub fn bind_two_in_range_with_offset(
572 ip_addr: IpAddr,
573 range: PortRange,
574 offset: u16,
575) -> io::Result<((u16, UdpSocket), (u16, UdpSocket))> {
576 let sock1_config = SocketConfig::default();
577 let sock2_config = SocketConfig::default();
578 bind_two_in_range_with_offset_and_config(ip_addr, range, offset, sock1_config, sock2_config)
579}
580
581pub fn bind_two_in_range_with_offset_and_config(
582 ip_addr: IpAddr,
583 range: PortRange,
584 offset: u16,
585 sock1_config: SocketConfig,
586 sock2_config: SocketConfig,
587) -> io::Result<((u16, UdpSocket), (u16, UdpSocket))> {
588 if range.1.saturating_sub(range.0) < offset {
589 return Err(io::Error::new(
590 io::ErrorKind::Other,
591 "range too small to find two ports with the correct offset".to_string(),
592 ));
593 }
594 for port in range.0..range.1 {
595 if let Ok(first_bind) = bind_to_with_config(ip_addr, port, sock1_config.clone()) {
596 if range.1.saturating_sub(port) >= offset {
597 if let Ok(second_bind) =
598 bind_to_with_config(ip_addr, port + offset, sock2_config.clone())
599 {
600 return Ok((
601 (first_bind.local_addr().unwrap().port(), first_bind),
602 (second_bind.local_addr().unwrap().port(), second_bind),
603 ));
604 }
605 } else {
606 break;
607 }
608 }
609 }
610 Err(io::Error::new(
611 io::ErrorKind::Other,
612 "couldn't find two ports with the correct offset in range".to_string(),
613 ))
614}
615
616pub fn find_available_port_in_range(ip_addr: IpAddr, range: PortRange) -> io::Result<u16> {
617 let (start, end) = range;
618 let mut tries_left = end - start;
619 let mut rand_port = thread_rng().gen_range(start..end);
620 loop {
621 match bind_common(ip_addr, rand_port) {
622 Ok(_) => {
623 break Ok(rand_port);
624 }
625 Err(err) => {
626 if tries_left == 0 {
627 return Err(err);
628 }
629 }
630 }
631 rand_port += 1;
632 if rand_port == end {
633 rand_port = start;
634 }
635 tries_left -= 1;
636 }
637}
638
639pub fn bind_more_with_config(
640 socket: UdpSocket,
641 num: usize,
642 config: SocketConfig,
643) -> io::Result<Vec<UdpSocket>> {
644 let addr = socket.local_addr().unwrap();
645 let ip = addr.ip();
646 let port = addr.port();
647 std::iter::once(Ok(socket))
648 .chain((1..num).map(|_| bind_to_with_config(ip, port, config.clone())))
649 .collect()
650}
651
652#[cfg(test)]
653mod tests {
654 use {super::*, std::net::Ipv4Addr};
655
656 #[test]
657 fn test_response_length() {
658 let resp = IpEchoServerResponse {
659 address: IpAddr::from([u16::MAX; 8]), shred_version: Some(u16::MAX),
661 };
662 let resp_size = bincode::serialized_size(&resp).unwrap();
663 assert_eq!(
664 IP_ECHO_SERVER_RESPONSE_LENGTH,
665 HEADER_LENGTH + resp_size as usize
666 );
667 }
668
669 #[test]
671 fn test_backward_compat() {
672 let address = IpAddr::from([
673 525u16, 524u16, 523u16, 522u16, 521u16, 520u16, 519u16, 518u16,
674 ]);
675 let response = IpEchoServerResponse {
676 address,
677 shred_version: Some(42),
678 };
679 let mut data = vec![0u8; IP_ECHO_SERVER_RESPONSE_LENGTH];
680 bincode::serialize_into(&mut data[HEADER_LENGTH..], &response).unwrap();
681 data.truncate(HEADER_LENGTH + 20);
682 assert_eq!(
683 bincode::deserialize::<IpAddr>(&data[HEADER_LENGTH..]).unwrap(),
684 address
685 );
686 }
687
688 #[test]
690 fn test_forward_compat() {
691 let address = IpAddr::from([
692 525u16, 524u16, 523u16, 522u16, 521u16, 520u16, 519u16, 518u16,
693 ]);
694 let mut data = [0u8; IP_ECHO_SERVER_RESPONSE_LENGTH];
695 bincode::serialize_into(&mut data[HEADER_LENGTH..], &address).unwrap();
696 let response: Result<IpEchoServerResponse, _> =
697 bincode::deserialize(&data[HEADER_LENGTH..]);
698 assert_eq!(
699 response.unwrap(),
700 IpEchoServerResponse {
701 address,
702 shred_version: None,
703 }
704 );
705 }
706
707 #[test]
708 fn test_parse_port_or_addr() {
709 let p1 = parse_port_or_addr(Some("9000"), SocketAddr::from(([1, 2, 3, 4], 1)));
710 assert_eq!(p1.port(), 9000);
711 let p2 = parse_port_or_addr(Some("127.0.0.1:7000"), SocketAddr::from(([1, 2, 3, 4], 1)));
712 assert_eq!(p2.port(), 7000);
713 let p2 = parse_port_or_addr(Some("hi there"), SocketAddr::from(([1, 2, 3, 4], 1)));
714 assert_eq!(p2.port(), 1);
715 let p3 = parse_port_or_addr(None, SocketAddr::from(([1, 2, 3, 4], 1)));
716 assert_eq!(p3.port(), 1);
717 }
718
719 #[test]
720 fn test_parse_port_range() {
721 assert_eq!(parse_port_range("garbage"), None);
722 assert_eq!(parse_port_range("1-"), None);
723 assert_eq!(parse_port_range("1-2"), Some((1, 2)));
724 assert_eq!(parse_port_range("1-2-3"), None);
725 assert_eq!(parse_port_range("2-1"), None);
726 }
727
728 #[test]
729 fn test_parse_host() {
730 parse_host("localhost:1234").unwrap_err();
731 parse_host("localhost").unwrap();
732 parse_host("127.0.0.0:1234").unwrap_err();
733 parse_host("127.0.0.0").unwrap();
734 }
735
736 #[test]
737 fn test_parse_host_port() {
738 parse_host_port("localhost:1234").unwrap();
739 parse_host_port("localhost").unwrap_err();
740 parse_host_port("127.0.0.0:1234").unwrap();
741 parse_host_port("127.0.0.0").unwrap_err();
742 }
743
744 #[test]
745 fn test_is_host_port() {
746 assert!(is_host_port("localhost:1234".to_string()).is_ok());
747 assert!(is_host_port("localhost".to_string()).is_err());
748 }
749
750 #[test]
751 fn test_bind() {
752 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
753 assert_eq!(bind_in_range(ip_addr, (2000, 2001)).unwrap().0, 2000);
754 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
755 let config = SocketConfig { reuseport: true };
756 let x = bind_to_with_config(ip_addr, 2002, config.clone()).unwrap();
757 let y = bind_to_with_config(ip_addr, 2002, config).unwrap();
758 assert_eq!(
759 x.local_addr().unwrap().port(),
760 y.local_addr().unwrap().port()
761 );
762 bind_to(ip_addr, 2002, false).unwrap_err();
763 bind_in_range(ip_addr, (2002, 2003)).unwrap_err();
764
765 let (port, v) = multi_bind_in_range(ip_addr, (2010, 2110), 10).unwrap();
766 for sock in &v {
767 assert_eq!(port, sock.local_addr().unwrap().port());
768 }
769 }
770
771 #[test]
772 fn test_bind_with_any_port() {
773 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
774 let x = bind_with_any_port(ip_addr).unwrap();
775 let y = bind_with_any_port(ip_addr).unwrap();
776 assert_ne!(
777 x.local_addr().unwrap().port(),
778 y.local_addr().unwrap().port()
779 );
780 }
781
782 #[test]
783 fn test_bind_in_range_nil() {
784 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
785 bind_in_range(ip_addr, (2000, 2000)).unwrap_err();
786 bind_in_range(ip_addr, (2000, 1999)).unwrap_err();
787 }
788
789 #[test]
790 fn test_find_available_port_in_range() {
791 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
792 assert_eq!(
793 find_available_port_in_range(ip_addr, (3000, 3001)).unwrap(),
794 3000
795 );
796 let port = find_available_port_in_range(ip_addr, (3000, 3050)).unwrap();
797 assert!((3000..3050).contains(&port));
798
799 let _socket = bind_to(ip_addr, port, false).unwrap();
800 find_available_port_in_range(ip_addr, (port, port + 1)).unwrap_err();
801 }
802
803 #[test]
804 fn test_bind_common_in_range() {
805 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
806 let (port, _sockets) = bind_common_in_range(ip_addr, (3100, 3150)).unwrap();
807 assert!((3100..3150).contains(&port));
808
809 bind_common_in_range(ip_addr, (port, port + 1)).unwrap_err();
810 }
811
812 #[test]
813 fn test_get_public_ip_addr_none() {
814 solana_logger::setup();
815 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
816 let (_server_port, (server_udp_socket, server_tcp_listener)) =
817 bind_common_in_range(ip_addr, (3200, 3250)).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(&server_ip_echo_addr),
828 parse_host("127.0.0.1"),
829 );
830 assert_eq!(get_cluster_shred_version(&server_ip_echo_addr), Ok(42));
831 assert!(verify_reachable_ports(&server_ip_echo_addr, vec![], &[],));
832 }
833
834 #[test]
835 fn test_get_public_ip_addr_reachable() {
836 solana_logger::setup();
837 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
838 let (_server_port, (server_udp_socket, server_tcp_listener)) =
839 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
840 let (client_port, (client_udp_socket, client_tcp_listener)) =
841 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
842
843 let _runtime = ip_echo_server(
844 server_tcp_listener,
845 DEFAULT_IP_ECHO_SERVER_THREADS,
846 Some(65535),
847 );
848
849 let ip_echo_server_addr = server_udp_socket.local_addr().unwrap();
850 assert_eq!(
851 get_public_ip_addr(&ip_echo_server_addr),
852 parse_host("127.0.0.1"),
853 );
854 assert_eq!(get_cluster_shred_version(&ip_echo_server_addr), Ok(65535));
855 assert!(verify_reachable_ports(
856 &ip_echo_server_addr,
857 vec![(client_port, client_tcp_listener)],
858 &[&client_udp_socket],
859 ));
860 }
861
862 #[test]
863 fn test_get_public_ip_addr_tcp_unreachable() {
864 solana_logger::setup();
865 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
866 let (_server_port, (server_udp_socket, _server_tcp_listener)) =
867 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
868
869 let server_ip_echo_addr = server_udp_socket.local_addr().unwrap();
872
873 let (correct_client_port, (_client_udp_socket, client_tcp_listener)) =
874 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
875
876 assert!(!do_verify_reachable_ports(
877 &server_ip_echo_addr,
878 vec![(correct_client_port, client_tcp_listener)],
879 &[],
880 2,
881 3,
882 ));
883 }
884
885 #[test]
886 fn test_get_public_ip_addr_udp_unreachable() {
887 solana_logger::setup();
888 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
889 let (_server_port, (server_udp_socket, _server_tcp_listener)) =
890 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
891
892 let server_ip_echo_addr = server_udp_socket.local_addr().unwrap();
895
896 let (_correct_client_port, (client_udp_socket, _client_tcp_listener)) =
897 bind_common_in_range(ip_addr, (3200, 3250)).unwrap();
898
899 assert!(!do_verify_reachable_ports(
900 &server_ip_echo_addr,
901 vec![],
902 &[&client_udp_socket],
903 2,
904 3,
905 ));
906 }
907
908 #[test]
909 fn test_bind_two_in_range_with_offset() {
910 solana_logger::setup();
911 let ip_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
912 let offset = 6;
913 if let Ok(((port1, _), (port2, _))) =
914 bind_two_in_range_with_offset(ip_addr, (1024, 65535), offset)
915 {
916 assert!(port2 == port1 + offset);
917 }
918 let offset = 42;
919 if let Ok(((port1, _), (port2, _))) =
920 bind_two_in_range_with_offset(ip_addr, (1024, 65535), offset)
921 {
922 assert!(port2 == port1 + offset);
923 }
924 assert!(bind_two_in_range_with_offset(ip_addr, (1024, 1044), offset).is_err());
925 }
926}