use std::cmp::Ordering;
#[cfg(feature = "tor")]
use std::convert::TryFrom;
use std::fmt;
use std::net::{
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6,
};
use std::num::ParseIntError;
use std::str::FromStr;
#[cfg(feature = "tor")]
use torut::onion::{OnionAddressV3, TorPublicKeyV3};
#[derive(
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, Error
)]
#[display(doc_comments)]
pub struct NoOnionSupportError;
#[derive(Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum AddrParseError {
#[from(ParseIntError)]
WrongPortNumber,
WrongAddrFormat(String),
WrongSocketFormat(String),
WrongSocketExtFormat(String),
UnknownProtocolError(String),
#[cfg(feature = "tor")]
#[display(inner)]
#[from]
OnionAddressError(torut::onion::OnionAddressParseError),
#[from(NoOnionSupportError)]
NeedsTorFeature,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, From, Display)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(inner)]
#[non_exhaustive] pub enum InetAddr {
#[from]
IPv4(Ipv4Addr),
#[from]
IPv6(Ipv6Addr),
#[cfg(feature = "tor")]
#[from]
Tor(TorPublicKeyV3),
}
impl PartialOrd for InetAddr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(InetAddr::IPv4(addr1), InetAddr::IPv4(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetAddr::IPv6(addr1), InetAddr::IPv6(addr2)) => {
addr1.partial_cmp(addr2)
}
#[cfg(feature = "tor")]
(InetAddr::Tor(addr1), InetAddr::Tor(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetAddr::IPv4(_), _) => Some(Ordering::Greater),
(_, InetAddr::IPv4(_)) => Some(Ordering::Less),
#[cfg(feature = "tor")]
(InetAddr::IPv6(_), _) => Some(Ordering::Greater),
#[cfg(feature = "tor")]
(_, InetAddr::IPv6(_)) => Some(Ordering::Less),
}
}
}
impl Ord for InetAddr {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_or(Ordering::Equal)
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for InetAddr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
InetAddr::IPv4(ipv4) => ipv4.hash(state),
InetAddr::IPv6(ipv6) => ipv6.hash(state),
#[cfg(feature = "tor")]
InetAddr::Tor(torv3) => torv3.as_bytes().hash(state),
}
}
}
impl InetAddr {
#[inline]
pub fn ipv6_addr(self) -> Option<Ipv6Addr> {
match self {
InetAddr::IPv4(ipv4_addr) => Some(ipv4_addr.to_ipv6_mapped()),
InetAddr::IPv6(ipv6_addr) => Some(ipv6_addr),
#[cfg(feature = "tor")]
_ => None,
}
}
#[inline]
pub fn ipv4_addr(self) -> Option<Ipv4Addr> {
match self {
InetAddr::IPv4(ipv4_addr) => Some(ipv4_addr),
InetAddr::IPv6(ipv6_addr) => ipv6_addr.to_ipv4(),
#[cfg(feature = "tor")]
_ => None,
}
}
#[cfg(not(feature = "tor"))]
#[inline]
pub fn is_tor(self) -> bool { false }
#[cfg(not(feature = "tor"))]
#[inline]
pub fn onion_address(self) -> Option<()> { None }
#[cfg(feature = "tor")]
#[inline]
pub fn is_tor(self) -> bool { matches!(self, InetAddr::Tor(_)) }
#[cfg(feature = "tor")]
#[inline]
pub fn onion_address(self) -> Option<OnionAddressV3> {
match self {
InetAddr::IPv4(_) | InetAddr::IPv6(_) => None,
InetAddr::Tor(key) => Some(OnionAddressV3::from(&key)),
}
}
}
impl Default for InetAddr {
#[inline]
fn default() -> Self { InetAddr::IPv4(Ipv4Addr::from(0)) }
}
#[cfg(feature = "tor")]
impl TryFrom<InetAddr> for IpAddr {
type Error = NoOnionSupportError;
#[inline]
fn try_from(addr: InetAddr) -> Result<Self, Self::Error> {
Ok(match addr {
InetAddr::IPv4(addr) => IpAddr::V4(addr),
InetAddr::IPv6(addr) => IpAddr::V6(addr),
#[cfg(feature = "tor")]
InetAddr::Tor(_) => return Err(NoOnionSupportError),
})
}
}
#[cfg(not(feature = "tor"))]
impl From<InetAddr> for IpAddr {
#[inline]
fn from(addr: InetAddr) -> Self {
match addr {
InetAddr::IPv4(addr) => IpAddr::V4(addr),
InetAddr::IPv6(addr) => IpAddr::V6(addr),
}
}
}
impl From<IpAddr> for InetAddr {
#[inline]
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(v4) => InetAddr::from(v4),
IpAddr::V6(v6) => InetAddr::from(v6),
}
}
}
#[cfg(feature = "tor")]
impl From<OnionAddressV3> for InetAddr {
#[inline]
fn from(addr: OnionAddressV3) -> Self {
InetAddr::Tor(addr.get_public_key())
}
}
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetAddr);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetAddr);
impl FromStr for InetAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[cfg(feature = "tor")]
match (IpAddr::from_str(s), OnionAddressV3::from_str(s)) {
(Ok(_), Ok(_)) => {
Err(AddrParseError::WrongAddrFormat(s.to_owned()))
}
(Ok(ip_addr), _) => Ok(Self::from(ip_addr)),
(_, Ok(onionv3)) => Ok(Self::from(onionv3)),
_ => Err(AddrParseError::WrongAddrFormat(s.to_owned())),
}
#[cfg(not(feature = "tor"))]
match IpAddr::from_str(s) {
Ok(ip_addr) => Ok(InetAddr::from(ip_addr)),
_ => Err(AddrParseError::NeedsTorFeature),
}
}
}
#[cfg(feature = "parse_arg")]
impl parse_arg::ParseArgFromStr for InetAddr {
fn describe_type<W: std::fmt::Write>(mut writer: W) -> std::fmt::Result {
#[cfg(not(feature = "tor"))]
{
write!(writer, "IPv4 or IPv6 address")
}
#[cfg(feature = "tor")]
{
write!(writer, "IPv4, IPv6, or Tor (onion) address")
}
}
}
impl From<[u8; 4]> for InetAddr {
#[inline]
fn from(value: [u8; 4]) -> Self { InetAddr::from(Ipv4Addr::from(value)) }
}
impl From<[u8; 16]> for InetAddr {
#[inline]
fn from(value: [u8; 16]) -> Self { InetAddr::from(Ipv6Addr::from(value)) }
}
impl From<[u16; 8]> for InetAddr {
#[inline]
fn from(value: [u16; 8]) -> Self { InetAddr::from(Ipv6Addr::from(value)) }
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, From)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[non_exhaustive] pub enum PartialSocketAddr {
IPv4(Ipv4Addr, Option<u16>),
IPv6(Ipv6Addr, Option<u16>),
#[cfg(feature = "tor")]
#[from]
Tor(TorPublicKeyV3),
}
impl PartialOrd for PartialSocketAddr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(
PartialSocketAddr::IPv4(addr1, Some(port1)),
PartialSocketAddr::IPv4(addr2, Some(port2)),
) => SocketAddrV4::new(*addr1, *port1)
.partial_cmp(&SocketAddrV4::new(*addr2, *port2)),
(
PartialSocketAddr::IPv6(addr1, Some(port1)),
PartialSocketAddr::IPv6(addr2, Some(port2)),
) => SocketAddrV6::new(*addr1, *port1, 0, 0)
.partial_cmp(&SocketAddrV6::new(*addr2, *port2, 0, 0)),
(
PartialSocketAddr::IPv4(addr1, Some(port1)),
PartialSocketAddr::IPv4(addr2, None),
) => SocketAddrV4::new(*addr1, *port1)
.partial_cmp(&SocketAddrV4::new(*addr2, 0)),
(
PartialSocketAddr::IPv6(addr1, Some(port1)),
PartialSocketAddr::IPv6(addr2, None),
) => SocketAddrV6::new(*addr1, *port1, 0, 0)
.partial_cmp(&SocketAddrV6::new(*addr2, 0, 0, 0)),
(
PartialSocketAddr::IPv4(addr1, None),
PartialSocketAddr::IPv4(addr2, Some(port2)),
) => SocketAddrV4::new(*addr1, 0)
.partial_cmp(&SocketAddrV4::new(*addr2, *port2)),
(
PartialSocketAddr::IPv6(addr1, None),
PartialSocketAddr::IPv6(addr2, Some(port2)),
) => SocketAddrV6::new(*addr1, 0, 0, 0)
.partial_cmp(&SocketAddrV6::new(*addr2, *port2, 0, 0)),
(
PartialSocketAddr::IPv4(addr1, None),
PartialSocketAddr::IPv4(addr2, None),
) => addr1.partial_cmp(addr2),
(
PartialSocketAddr::IPv6(addr1, None),
PartialSocketAddr::IPv6(addr2, None),
) => addr1.partial_cmp(addr2),
#[cfg(feature = "tor")]
(PartialSocketAddr::Tor(addr1), PartialSocketAddr::Tor(addr2)) => {
addr1.partial_cmp(addr2)
}
(PartialSocketAddr::IPv4(_, _), _) => Some(Ordering::Greater),
(_, PartialSocketAddr::IPv4(_, _)) => Some(Ordering::Less),
#[cfg(feature = "tor")]
(PartialSocketAddr::IPv6(_, _), _) => Some(Ordering::Greater),
#[cfg(feature = "tor")]
(_, PartialSocketAddr::IPv6(_, _)) => Some(Ordering::Less),
}
}
}
impl Ord for PartialSocketAddr {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_or(Ordering::Equal)
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for PartialSocketAddr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
PartialSocketAddr::IPv4(ipv4, port) => {
ipv4.hash(state);
port.hash(state)
}
PartialSocketAddr::IPv6(ipv6, port) => {
ipv6.hash(state);
port.hash(state)
}
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(torv3) => torv3.as_bytes().hash(state),
}
}
}
impl PartialSocketAddr {
#[cfg(feature = "tor")]
#[inline]
pub fn tor3(tor: TorPublicKeyV3) -> Self { PartialSocketAddr::Tor(tor) }
#[inline]
pub fn socket(ip: IpAddr, port: Option<u16>) -> Self {
match ip {
IpAddr::V4(ipv4) => PartialSocketAddr::IPv4(ipv4, port),
IpAddr::V6(ipv6) => PartialSocketAddr::IPv6(ipv6, port),
}
}
#[cfg(not(feature = "tor"))]
#[inline]
pub fn is_tor(self) -> bool { false }
#[cfg(not(feature = "tor"))]
#[inline]
pub fn onion_address(self) -> Option<()> { None }
#[cfg(feature = "tor")]
#[inline]
pub fn is_tor(self) -> bool { matches!(self, PartialSocketAddr::Tor(_)) }
#[cfg(feature = "tor")]
#[inline]
pub fn onion_address(self) -> Option<OnionAddressV3> {
match self {
PartialSocketAddr::IPv4(_, _) | PartialSocketAddr::IPv6(_, _) => {
None
}
PartialSocketAddr::Tor(key) => Some(OnionAddressV3::from(&key)),
}
}
#[inline]
pub fn address(self) -> InetAddr {
match self {
PartialSocketAddr::IPv4(addr, _) => InetAddr::IPv4(addr),
PartialSocketAddr::IPv6(addr, _) => InetAddr::IPv6(addr),
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(tor) => InetAddr::Tor(tor),
}
}
#[inline]
pub fn port(self) -> Option<u16> {
match self {
PartialSocketAddr::IPv4(_, port)
| PartialSocketAddr::IPv6(_, port) => port,
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(_) => None,
}
}
pub fn inet_socket(self, default_port: u16) -> InetSocketAddr {
match self {
PartialSocketAddr::IPv4(addr, None) => {
InetSocketAddr::IPv4(SocketAddrV4::new(addr, default_port))
}
PartialSocketAddr::IPv6(addr, None) => InetSocketAddr::IPv6(
SocketAddrV6::new(addr, default_port, 0, 0),
),
PartialSocketAddr::IPv4(addr, Some(port)) => {
InetSocketAddr::IPv4(SocketAddrV4::new(addr, port))
}
PartialSocketAddr::IPv6(addr, Some(port)) => {
InetSocketAddr::IPv6(SocketAddrV6::new(addr, port, 0, 0))
}
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(addr) => InetSocketAddr::Tor(addr),
}
}
}
impl Default for PartialSocketAddr {
#[inline]
fn default() -> Self { PartialSocketAddr::IPv4(Ipv4Addr::from(0), None) }
}
#[cfg(feature = "tor")]
impl TryFrom<PartialSocketAddr> for IpAddr {
type Error = NoOnionSupportError;
#[inline]
fn try_from(addr: PartialSocketAddr) -> Result<Self, Self::Error> {
Ok(match addr {
PartialSocketAddr::IPv4(addr, _) => IpAddr::V4(addr),
PartialSocketAddr::IPv6(addr, _) => IpAddr::V6(addr),
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(_) => return Err(NoOnionSupportError),
})
}
}
impl From<IpAddr> for PartialSocketAddr {
#[inline]
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(v4) => PartialSocketAddr::from(v4),
IpAddr::V6(v6) => PartialSocketAddr::from(v6),
}
}
}
impl From<Ipv4Addr> for PartialSocketAddr {
#[inline]
fn from(value: Ipv4Addr) -> Self { PartialSocketAddr::IPv4(value, None) }
}
impl From<Ipv6Addr> for PartialSocketAddr {
#[inline]
fn from(value: Ipv6Addr) -> Self { PartialSocketAddr::IPv6(value, None) }
}
impl From<SocketAddr> for PartialSocketAddr {
#[inline]
fn from(value: SocketAddr) -> Self {
match value {
SocketAddr::V4(v4) => PartialSocketAddr::from(v4),
SocketAddr::V6(v6) => PartialSocketAddr::from(v6),
}
}
}
impl From<SocketAddrV4> for PartialSocketAddr {
#[inline]
fn from(value: SocketAddrV4) -> Self {
PartialSocketAddr::IPv4(*value.ip(), Some(value.port()))
}
}
impl From<SocketAddrV6> for PartialSocketAddr {
#[inline]
fn from(value: SocketAddrV6) -> Self {
PartialSocketAddr::IPv6(*value.ip(), Some(value.port()))
}
}
#[cfg(feature = "tor")]
impl From<OnionAddressV3> for PartialSocketAddr {
#[inline]
fn from(addr: OnionAddressV3) -> Self {
PartialSocketAddr::Tor(addr.get_public_key())
}
}
impl From<InetAddr> for PartialSocketAddr {
fn from(addr: InetAddr) -> Self {
match addr {
InetAddr::IPv4(addr) => PartialSocketAddr::IPv4(addr, None),
InetAddr::IPv6(addr) => PartialSocketAddr::IPv6(addr, None),
#[cfg(feature = "tor")]
InetAddr::Tor(addr) => PartialSocketAddr::Tor(addr),
}
}
}
impl From<InetSocketAddr> for PartialSocketAddr {
fn from(addr: InetSocketAddr) -> Self {
match addr {
InetSocketAddr::IPv4(socket) => {
PartialSocketAddr::IPv4(*socket.ip(), Some(socket.port()))
}
InetSocketAddr::IPv6(socket) => {
PartialSocketAddr::IPv6(*socket.ip(), Some(socket.port()))
}
#[cfg(feature = "tor")]
InetSocketAddr::Tor(addr) => PartialSocketAddr::Tor(addr),
}
}
}
impl fmt::Display for PartialSocketAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PartialSocketAddr::IPv4(addr, None) => fmt::Display::fmt(addr, f),
PartialSocketAddr::IPv6(addr, None) => fmt::Display::fmt(addr, f),
PartialSocketAddr::IPv4(addr, Some(port)) => {
fmt::Display::fmt(&SocketAddrV4::new(*addr, *port), f)
}
PartialSocketAddr::IPv6(addr, Some(port)) => {
fmt::Display::fmt(&SocketAddrV6::new(*addr, *port, 0, 0), f)
}
#[cfg(feature = "tor")]
PartialSocketAddr::Tor(addr) => fmt::Display::fmt(addr, f),
}
}
}
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(PartialSocketAddr);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(PartialSocketAddr);
impl FromStr for PartialSocketAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
#[cfg(not(feature = "tor"))]
struct OnionAddressV3;
#[cfg(not(feature = "tor"))]
impl OnionAddressV3 {
fn from_str(_: &str) -> Result<Self, AddrParseError> {
Err(AddrParseError::NeedsTorFeature)
}
}
match (
SocketAddr::from_str(s),
IpAddr::from_str(s),
OnionAddressV3::from_str(s),
) {
(Ok(_), _, Ok(_)) | (_, Ok(_), Ok(_)) => {
Err(AddrParseError::WrongAddrFormat(s.to_owned()))
}
(Ok(socket_addr), ..) => Ok(Self::from(socket_addr)),
(_, Ok(ip_addr), _) => Ok(Self::from(ip_addr)),
#[cfg(feature = "tor")]
(_, _, Ok(onionv3)) => Ok(Self::from(onionv3)),
(_, _, Err(err)) => Err(err.into()),
#[cfg(not(feature = "tor"))]
_ => Err(AddrParseError::WrongAddrFormat(s.to_owned())),
}
}
}
#[cfg(feature = "parse_arg")]
impl parse_arg::ParseArgFromStr for PartialSocketAddr {
fn describe_type<W: std::fmt::Write>(mut writer: W) -> std::fmt::Result {
#[cfg(not(feature = "tor"))]
{
write!(writer, "IPv4 or IPv6 address with optional port")
}
#[cfg(feature = "tor")]
{
write!(
writer,
"IPv4, IPv6, or Tor (onion) address with optional port"
)
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename = "lowercase")
)]
#[non_exhaustive]
#[repr(u8)]
pub enum Transport {
#[display("tcp")]
Tcp = 1,
#[display("udp")]
Udp = 2,
#[display("mtcp")]
Mtcp = 3,
#[display("quic")]
Quic = 4,
}
impl Default for Transport {
#[inline]
fn default() -> Self { Transport::Tcp }
}
impl FromStr for Transport {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s.to_lowercase().as_str() {
"tcp" => Transport::Tcp,
"udp" => Transport::Udp,
"mtcp" => Transport::Mtcp,
"quic" => Transport::Quic,
_ => {
return Err(AddrParseError::UnknownProtocolError(s.to_owned()))
}
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Display, From)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(inner)]
#[non_exhaustive] pub enum InetSocketAddr {
#[from]
IPv4(SocketAddrV4),
#[from]
IPv6(SocketAddrV6),
#[cfg(feature = "tor")]
#[from]
Tor(TorPublicKeyV3),
}
impl PartialOrd for InetSocketAddr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(InetSocketAddr::IPv4(addr1), InetSocketAddr::IPv4(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetSocketAddr::IPv6(addr1), InetSocketAddr::IPv6(addr2)) => {
addr1.partial_cmp(addr2)
}
#[cfg(feature = "tor")]
(InetSocketAddr::Tor(addr1), InetSocketAddr::Tor(addr2)) => {
addr1.partial_cmp(addr2)
}
(InetSocketAddr::IPv4(_), _) => Some(Ordering::Greater),
(_, InetSocketAddr::IPv4(_)) => Some(Ordering::Less),
#[cfg(feature = "tor")]
(InetSocketAddr::IPv6(_), _) => Some(Ordering::Greater),
#[cfg(feature = "tor")]
(_, InetSocketAddr::IPv6(_)) => Some(Ordering::Less),
}
}
}
impl Ord for InetSocketAddr {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_or(Ordering::Equal)
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl std::hash::Hash for InetSocketAddr {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
InetSocketAddr::IPv4(socketv4) => socketv4.hash(state),
InetSocketAddr::IPv6(socketv6) => socketv6.hash(state),
#[cfg(feature = "tor")]
InetSocketAddr::Tor(torv3) => torv3.as_bytes().hash(state),
}
}
}
impl Default for InetSocketAddr {
#[inline]
fn default() -> Self {
InetSocketAddr::IPv4(SocketAddrV4::new(Ipv4Addr::from(0), 0))
}
}
impl InetSocketAddr {
#[cfg(feature = "tor")]
#[inline]
pub fn tor3(tor: TorPublicKeyV3) -> Self { InetSocketAddr::Tor(tor) }
#[inline]
pub fn socket(ip: IpAddr, port: u16) -> Self {
match ip {
IpAddr::V4(ipv4) => {
InetSocketAddr::IPv4(SocketAddrV4::new(ipv4, port))
}
IpAddr::V6(ipv6) => {
InetSocketAddr::IPv6(SocketAddrV6::new(ipv6, port, 0, 0))
}
}
}
#[inline]
pub fn is_tor(&self) -> bool {
match self {
InetSocketAddr::IPv4(_) | InetSocketAddr::IPv6(_) => false,
#[cfg(feature = "tor")]
InetSocketAddr::Tor(_) => true,
}
}
#[inline]
pub fn address(self) -> InetAddr {
match self {
InetSocketAddr::IPv4(socket) => InetAddr::IPv4(*socket.ip()),
InetSocketAddr::IPv6(socket) => InetAddr::IPv6(*socket.ip()),
#[cfg(feature = "tor")]
InetSocketAddr::Tor(tor) => InetAddr::Tor(tor),
}
}
#[inline]
pub fn port(self) -> Option<u16> {
match self {
InetSocketAddr::IPv4(socket) => Some(socket.port()),
InetSocketAddr::IPv6(socket) => Some(socket.port()),
#[cfg(feature = "tor")]
InetSocketAddr::Tor(_) => None,
}
}
}
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetSocketAddr);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetSocketAddr);
impl FromStr for InetSocketAddr {
type Err = AddrParseError;
#[allow(unreachable_code)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(socket_addr) = SocketAddrV6::from_str(s) {
Ok(InetSocketAddr::IPv6(socket_addr))
} else if let Ok(socket_addr) = SocketAddrV4::from_str(s) {
Ok(InetSocketAddr::IPv4(socket_addr))
} else {
#[cfg(not(feature = "tor"))]
{
Err(AddrParseError::NeedsTorFeature)
}
#[cfg(feature = "tor")]
if let Ok(addr) = OnionAddressV3::from_str(s) {
Ok(InetSocketAddr::Tor(addr.get_public_key()))
} else {
Err(AddrParseError::WrongAddrFormat(s.to_owned()))
}
}
}
}
#[cfg(feature = "parse_arg")]
impl parse_arg::ParseArgFromStr for InetSocketAddr {
fn describe_type<W: std::fmt::Write>(mut writer: W) -> std::fmt::Result {
#[cfg(not(feature = "tor"))]
{
write!(writer, "IPv4 or IPv6 socket address")
}
#[cfg(feature = "tor")]
{
write!(writer, "IPv4, IPv6, or Tor (onion) socket address")
}
}
}
#[cfg(feature = "tor")]
impl TryFrom<InetSocketAddr> for SocketAddr {
type Error = NoOnionSupportError;
#[inline]
fn try_from(socket_addr: InetSocketAddr) -> Result<Self, Self::Error> {
match socket_addr {
InetSocketAddr::IPv4(socket) => Ok(SocketAddr::V4(socket)),
InetSocketAddr::IPv6(socket) => Ok(SocketAddr::V6(socket)),
InetSocketAddr::Tor(_) => Err(NoOnionSupportError),
}
}
}
#[cfg(not(feature = "tor"))]
impl From<InetSocketAddr> for SocketAddr {
#[inline]
fn from(socket_addr: InetSocketAddr) -> Self {
match socket_addr {
InetSocketAddr::IPv4(socket) => SocketAddr::V4(socket),
InetSocketAddr::IPv6(socket) => SocketAddr::V6(socket),
#[cfg(feature = "tor")]
InetSocketAddr::Tor(_) => unreachable!(),
}
}
}
impl From<SocketAddr> for InetSocketAddr {
#[inline]
fn from(socket: SocketAddr) -> Self {
match socket {
SocketAddr::V4(socket) => InetSocketAddr::IPv4(socket),
SocketAddr::V6(socket) => InetSocketAddr::IPv6(socket),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(
all(feature = "serde", feature = "serde_str_helpers"),
derive(Serialize, Deserialize),
serde(
try_from = "serde_str_helpers::DeserBorrowStr",
into = "String",
crate = "serde_crate"
)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "serde_str_helpers")),
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
pub struct InetSocketAddrExt(
)
pub Transport,
pub InetSocketAddr,
);
#[cfg(feature = "stringly_conversions")]
impl_try_from_stringly_standard!(InetSocketAddrExt);
#[cfg(feature = "stringly_conversions")]
impl_into_stringly_standard!(InetSocketAddrExt);
impl InetSocketAddrExt {
#[inline]
pub fn tcp(socket: SocketAddr) -> Self {
Self(Transport::Tcp, socket.into())
}
#[inline]
pub fn udp(address: IpAddr, port: u16) -> Self {
Self(Transport::Udp, SocketAddr::new(address, port).into())
}
}
impl fmt::Display for InetSocketAddrExt {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}://{}", self.0, self.1)
}
}
impl FromStr for InetSocketAddrExt {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut vals = s.split("://");
if let (Some(transport), Some(addr), None) =
(vals.next(), vals.next(), vals.next())
{
Ok(Self(transport.parse()?, addr.parse()?))
} else {
Err(AddrParseError::WrongSocketExtFormat(s.to_owned()))
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_inet_addr() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let ip4 = InetAddr::IPv4(ip4a);
let ip6 = InetAddr::IPv6(ip6a);
assert_eq!(
ip4.ipv6_addr().unwrap(),
Ipv6Addr::from_str("::ffff:127.0.0.1").unwrap()
);
assert_eq!(ip6.ipv6_addr().unwrap(), ip6a);
assert_eq!(InetAddr::from(IpAddr::V4(ip4a)), ip4);
assert_eq!(InetAddr::from(IpAddr::V6(ip6a)), ip6);
assert_eq!(InetAddr::from(ip4a), ip4);
assert_eq!(InetAddr::from(ip6a), ip6);
assert_eq!(InetAddr::default(), InetAddr::from_str("0.0.0.0").unwrap());
#[cfg(feature = "tor")]
assert_eq!(IpAddr::try_from(ip4).unwrap(), IpAddr::V4(ip4a));
#[cfg(feature = "tor")]
assert_eq!(IpAddr::try_from(ip6).unwrap(), IpAddr::V6(ip6a));
#[cfg(not(feature = "tor"))]
assert_eq!(IpAddr::from(ip4.clone()), IpAddr::V4(ip4a));
#[cfg(not(feature = "tor"))]
assert_eq!(IpAddr::from(ip6.clone()), IpAddr::V6(ip6a));
assert_eq!(InetAddr::from_str("127.0.0.1").unwrap(), ip4);
assert_eq!(InetAddr::from_str("::1").unwrap(), ip6);
assert_eq!(format!("{}", ip4), "127.0.0.1");
assert_eq!(format!("{}", ip6), "::1");
assert!(!ip4.is_tor());
assert!(!ip6.is_tor());
}
#[test]
fn test_transport() {
assert_eq!(format!("{}", Transport::Tcp), "tcp");
assert_eq!(format!("{}", Transport::Udp), "udp");
assert_eq!(format!("{}", Transport::Quic), "quic");
assert_eq!(format!("{}", Transport::Mtcp), "mtcp");
assert_eq!(Transport::from_str("tcp").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("Tcp").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("TCP").unwrap(), Transport::Tcp);
assert_eq!(Transport::from_str("udp").unwrap(), Transport::Udp);
assert_eq!(Transport::from_str("quic").unwrap(), Transport::Quic);
assert_eq!(Transport::from_str("mtcp").unwrap(), Transport::Mtcp);
assert!(Transport::from_str("xtp").is_err());
}
#[test]
fn test_inet_socket_addr() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let socket4a = "127.0.0.1:6865".parse().unwrap();
let socket6a = "[::1]:6865".parse().unwrap();
let ip4 = InetSocketAddr::socket(ip4a, 6865);
let ip6 = InetSocketAddr::socket(ip6a, 6865);
assert_eq!(InetSocketAddr::from(SocketAddr::V4(socket4a)), ip4);
assert_eq!(InetSocketAddr::from(SocketAddr::V6(socket6a)), ip6);
assert_eq!(InetSocketAddr::from(socket4a), ip4);
assert_eq!(InetSocketAddr::from(socket6a), ip6);
assert_eq!(
InetSocketAddr::default(),
InetSocketAddr::from_str("0.0.0.0:0").unwrap()
);
#[cfg(feature = "tor")]
assert_eq!(
SocketAddr::try_from(ip4).unwrap(),
SocketAddr::V4(socket4a)
);
#[cfg(feature = "tor")]
assert_eq!(
SocketAddr::try_from(ip6).unwrap(),
SocketAddr::V6(socket6a)
);
#[cfg(not(feature = "tor"))]
assert_eq!(SocketAddr::from(ip4.clone()), SocketAddr::V4(socket4a));
#[cfg(not(feature = "tor"))]
assert_eq!(SocketAddr::from(ip6.clone()), SocketAddr::V6(socket6a));
assert_eq!(InetSocketAddr::from_str("127.0.0.1:6865").unwrap(), ip4);
assert_eq!(InetSocketAddr::from_str("[::1]:6865").unwrap(), ip6);
assert_eq!(format!("{}", ip4), "127.0.0.1:6865");
assert_eq!(format!("{}", ip6), "[::1]:6865");
assert!(!ip4.is_tor());
assert!(!ip6.is_tor());
}
#[test]
fn test_inet_socket_addr_ext() {
let ip4a = "127.0.0.1".parse().unwrap();
let ip6a = "::1".parse().unwrap();
let ip4 = InetSocketAddrExt::tcp(SocketAddr::new(ip4a, 6865));
let ip6 = InetSocketAddrExt::udp(ip6a, 6865);
assert_eq!(
InetSocketAddrExt::default(),
InetSocketAddrExt::from_str("tcp://0.0.0.0:0").unwrap()
);
#[cfg(feature = "tor")]
assert_eq!(
InetSocketAddrExt::from_str("tcp://127.0.0.1:6865").unwrap(),
ip4
);
#[cfg(feature = "tor")]
assert_eq!(
InetSocketAddrExt::from_str("udp://[::1]:6865").unwrap(),
ip6
);
assert_eq!(format!("{}", ip4), "tcp://127.0.0.1:6865");
assert_eq!(format!("{}", ip6), "udp://[::1]:6865");
}
}