use std::net::{IpAddr, SocketAddr};
use tor_linkspec::{BridgeAddr, ChannelMethod, HasRelayIds, RelayIdRef, RelayIdType, RelayIds};
#[cfg(feature = "pt-client")]
use tor_linkspec::{PtTarget, PtTargetAddr};
#[derive(Clone, Debug, derive_more::Display, Eq, PartialEq)]
#[non_exhaustive]
pub enum PeerAddr {
Direct(SocketAddr),
#[cfg(feature = "pt-client")]
Pt(PtTarget),
}
impl PeerAddr {
#[cfg(any(test, feature = "testing"))]
pub(crate) const UNSPECIFIED: Self = Self::Direct(SocketAddr::new(
IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED),
0,
));
pub fn netinfo_addr(&self) -> Option<IpAddr> {
self.socket_addr().map(|sa| sa.ip())
}
pub fn socket_addr(&self) -> Option<SocketAddr> {
match self {
PeerAddr::Direct(sa) => Some(*sa),
#[cfg(feature = "pt-client")]
PeerAddr::Pt(t) => match t.addr() {
PtTargetAddr::IpPort(sa) => Some(*sa),
_ => None,
},
}
}
}
impl From<SocketAddr> for PeerAddr {
fn from(sa: SocketAddr) -> Self {
Self::Direct(sa)
}
}
#[cfg(feature = "pt-client")]
impl From<PtTarget> for PeerAddr {
fn from(t: PtTarget) -> Self {
Self::Pt(t)
}
}
impl From<&PeerAddr> for Option<BridgeAddr> {
fn from(t: &PeerAddr) -> Self {
match t {
PeerAddr::Direct(sa) => Some(BridgeAddr::new_addr_from_sockaddr(*sa)),
#[cfg(feature = "pt-client")]
PeerAddr::Pt(target) => target.addr().clone().into(),
}
}
}
#[derive(Clone, Debug)]
pub struct PeerInfo {
addr: PeerAddr,
ids: RelayIds,
}
impl PeerInfo {
#[cfg(any(test, feature = "testing"))]
pub(crate) const EMPTY: Self = Self {
addr: PeerAddr::UNSPECIFIED,
ids: RelayIds::empty(),
};
pub(crate) fn new(addr: PeerAddr, ids: RelayIds) -> Self {
Self { addr, ids }
}
pub(crate) fn addr(&self) -> &PeerAddr {
&self.addr
}
pub(crate) fn ids(&self) -> &RelayIds {
&self.ids
}
pub fn matches_chan_method(&self, method: &ChannelMethod) -> bool {
match (method, self.addr()) {
(ChannelMethod::Direct(addrs), PeerAddr::Direct(our_addr)) => addrs.contains(our_addr),
#[cfg(feature = "pt-client")]
(ChannelMethod::Pluggable(target), PeerAddr::Pt(our_target)) => our_target == target,
_ => false,
}
}
}
impl std::fmt::Display for PeerInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} [{}]", self.addr, self.ids)
}
}
impl HasRelayIds for PeerInfo {
fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
self.ids().identity(key_type)
}
}