Fixing parse socket address function (#1990)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Aditya Pandey
2023-03-27 17:31:45 +05:30
committed by GitHub
parent 96b48e9c2f
commit 889fa89d5e
2 changed files with 59 additions and 13 deletions

View File

@ -623,6 +623,7 @@ async fn run_network_until_shutdown<C>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::net::IpAddr;
#[test] #[test]
fn parse_help_node_command() { fn parse_help_node_command() {
@ -651,4 +652,16 @@ mod tests {
assert_eq!(cmd.network.discovery.port, Some(300)); assert_eq!(cmd.network.discovery.port, Some(300));
assert_eq!(cmd.network.port, Some(99)); assert_eq!(cmd.network.port, Some(99));
} }
#[test]
fn parse_metrics_port() {
let cmd = Command::try_parse_from(["reth", "--metrics", "9000"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9000)));
let cmd = Command::try_parse_from(["reth", "--metrics", ":9000"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9000)));
let cmd = Command::try_parse_from(["reth", "--metrics", "localhost:9000"]).unwrap();
assert_eq!(cmd.metrics, Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 9000)));
}
} }

View File

@ -2,7 +2,7 @@
use reth_primitives::{BlockHashOrNumber, H256}; use reth_primitives::{BlockHashOrNumber, H256};
use std::{ use std::{
env::VarError, env::VarError,
net::{SocketAddr, ToSocketAddrs}, net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs},
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr, str::FromStr,
}; };
@ -38,6 +38,23 @@ pub fn hash_or_num_value_parser(value: &str) -> Result<BlockHashOrNumber, eyre::
} }
} }
/// Error thrown while parsing a socket address.
#[derive(thiserror::Error, Debug)]
pub enum SocketAddressParsingError {
/// Failed to convert the string into a socket addr
#[error("Cannot parse socket address: {0}")]
Io(#[from] std::io::Error),
/// Input must not be empty
#[error("Cannot parse socket address from empty string")]
Empty,
/// Failed to parse the address
#[error("Could not parse socket address from {0}")]
Parse(String),
/// Failed to parse port
#[error("Could not parse port: {0}")]
Port(#[from] std::num::ParseIntError),
}
/// Parse a [SocketAddr] from a `str`. /// Parse a [SocketAddr] from a `str`.
/// ///
/// The following formats are checked: /// The following formats are checked:
@ -48,29 +65,32 @@ pub fn hash_or_num_value_parser(value: &str) -> Result<BlockHashOrNumber, eyre::
/// - Otherwise it is assumed to be a hostname /// - Otherwise it is assumed to be a hostname
/// ///
/// An error is returned if the value is empty. /// An error is returned if the value is empty.
pub fn parse_socket_address(value: &str) -> Result<SocketAddr, eyre::Error> { pub fn parse_socket_address(value: &str) -> Result<SocketAddr, SocketAddressParsingError> {
if value.is_empty() { if value.is_empty() {
eyre::bail!("Cannot parse socket address from an empty string"); return Err(SocketAddressParsingError::Empty)
} }
if value.starts_with(':') || value.parse::<u16>().is_ok() { if let Some(port) = value.strip_prefix(':').or_else(|| value.strip_prefix("localhost:")) {
("localhost", 9000).to_socket_addrs() let port: u16 = port.parse()?;
} else if value.contains(':') { return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port))
value.to_socket_addrs() }
} else { if let Ok(port) = value.parse::<u16>() {
(value, 9000).to_socket_addrs() return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port))
}? }
.next() value
.ok_or_else(|| eyre::eyre!("Could not parse socket address from {}", value)) .to_socket_addrs()?
.next()
.ok_or_else(|| SocketAddressParsingError::Parse(value.to_string()))
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use rand::{thread_rng, Rng};
#[test] #[test]
fn parse_socket_addresses() { fn parse_socket_addresses() {
for value in ["localhost:9000", ":9000", "9000", "localhost"] { for value in ["localhost:9000", ":9000", "9000"] {
let socket_addr = parse_socket_address(value) let socket_addr = parse_socket_address(value)
.unwrap_or_else(|_| panic!("could not parse socket address: {value}")); .unwrap_or_else(|_| panic!("could not parse socket address: {value}"));
@ -78,4 +98,17 @@ mod tests {
assert_eq!(socket_addr.port(), 9000); assert_eq!(socket_addr.port(), 9000);
} }
} }
#[test]
fn parse_socket_address_random() {
let port: u16 = thread_rng().gen();
for value in [format!("localhost:{port}"), format!(":{port}"), port.to_string()] {
let socket_addr = parse_socket_address(&value)
.unwrap_or_else(|_| panic!("could not parse socket address: {value}"));
assert!(socket_addr.ip().is_loopback());
assert_eq!(socket_addr.port(), port);
}
}
} }