start of refactoring veilid_api

This commit is contained in:
John Smith 2021-12-20 19:12:30 -05:00
parent 971fa94751
commit c0a42ac90c
8 changed files with 647 additions and 565 deletions

View File

@ -60,16 +60,12 @@ struct Address {
union { union {
ipv4 @0 :AddressIPV4; ipv4 @0 :AddressIPV4;
ipv6 @1 :AddressIPV6; ipv6 @1 :AddressIPV6;
hostname @2 :Text;
} }
} }
struct SocketAddress { struct SocketAddress {
union { address @0 :Address;
ipv4 @0 :AddressIPV4; port @1 :UInt16;
ipv6 @1 :AddressIPV6;
}
port @2 :UInt16;
} }
enum ProtocolKind { enum ProtocolKind {
@ -80,25 +76,21 @@ enum ProtocolKind {
} }
struct DialInfoUDP { struct DialInfoUDP {
address @0 :Address; socketAddress @0 :SocketAddress;
port @1 :UInt16;
} }
struct DialInfoTCP { struct DialInfoTCP {
address @0 :Address; socketAddress @0 :SocketAddress;
port @1 :UInt16;
} }
struct DialInfoWS { struct DialInfoWS {
host @0 :Text; socketAddress @0 :SocketAddress;
port @1 :UInt16; request @1 :Text;
path @2 :Text;
} }
struct DialInfoWSS { struct DialInfoWSS {
host @0 :Text; socketAddress @0 :SocketAddress;
port @1 :UInt16; request @1 :Text;
path @2 :Text;
} }
struct DialInfo { struct DialInfo {

View File

@ -5,6 +5,7 @@ use crate::network_manager::*;
use crate::xx::*; use crate::xx::*;
use crate::*; use crate::*;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt;
state_machine! { state_machine! {
derive(Debug, PartialEq, Eq, Clone, Copy) derive(Debug, PartialEq, Eq, Clone, Copy)
@ -65,9 +66,9 @@ state_machine! {
}, },
} }
impl ToString for AttachmentState { impl fmt::Display for AttachmentState {
fn to_string(&self) -> String { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self { let out = match self {
AttachmentState::Attaching => "attaching".to_owned(), AttachmentState::Attaching => "attaching".to_owned(),
AttachmentState::AttachedWeak => "attached_weak".to_owned(), AttachmentState::AttachedWeak => "attached_weak".to_owned(),
AttachmentState::AttachedGood => "attached_good".to_owned(), AttachmentState::AttachedGood => "attached_good".to_owned(),
@ -76,7 +77,8 @@ impl ToString for AttachmentState {
AttachmentState::OverAttached => "over_attached".to_owned(), AttachmentState::OverAttached => "over_attached".to_owned(),
AttachmentState::Detaching => "detaching".to_owned(), AttachmentState::Detaching => "detaching".to_owned(),
AttachmentState::Detached => "detached".to_owned(), AttachmentState::Detached => "detached".to_owned(),
} };
write!(f, "{}", out)
} }
} }

View File

@ -51,6 +51,15 @@ struct NetworkInner {
listener_states: BTreeMap<SocketAddr, Arc<RwLock<ListenerState>>>, listener_states: BTreeMap<SocketAddr, Arc<RwLock<ListenerState>>>,
udp_protocol_handlers: BTreeMap<SocketAddr, RawUdpProtocolHandler>, udp_protocol_handlers: BTreeMap<SocketAddr, RawUdpProtocolHandler>,
tls_acceptor: Option<TlsAcceptor>, tls_acceptor: Option<TlsAcceptor>,
udp_port: u16,
tcp_port: u16,
ws_port: u16,
wss_port: u16,
outbound_udpv4_protocol_handler: Option<RawUdpProtocolHandler>,
outbound_udpv6_protocol_handler: Option<RawUdpProtocolHandler>,
outbound_tcp_protocol_handler: Option<RawTcpProtocolHandler>,
outbound_ws_protocol_handler: Option<WebsocketProtocolHandler>,
outbound_wss_protocol_handler: Option<WebsocketProtocolHandler>,
interfaces: NetworkInterfaces, interfaces: NetworkInterfaces,
} }
@ -84,6 +93,15 @@ impl Network {
listener_states: BTreeMap::new(), listener_states: BTreeMap::new(),
udp_protocol_handlers: BTreeMap::new(), udp_protocol_handlers: BTreeMap::new(),
tls_acceptor: None, tls_acceptor: None,
udp_port: 0u16,
tcp_port: 0u16,
ws_port: 0u16,
wss_port: 0u16,
outbound_udpv4_protocol_handler: None,
outbound_udpv6_protocol_handler: None,
outbound_tcp_protocol_handler: None,
outbound_ws_protocol_handler: None,
outbound_wss_protocol_handler: None,
interfaces: NetworkInterfaces::new(), interfaces: NetworkInterfaces::new(),
} }
} }
@ -267,34 +285,9 @@ impl Network {
c.network.tls.connection_initial_timeout, c.network.tls.connection_initial_timeout,
) )
}; };
// Create a reusable socket with no linger time, and no delay // Create a reusable socket with no linger time, and no delay
let domain = Domain::for_address(addr); let socket = new_shared_tcp_socket(addr)?;
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))
.map_err(|e| format!("Couldn't create TCP socket: {}", e))?;
if let Err(e) = socket.set_linger(None) {
warn!("Couldn't set TCP linger: {}", e);
}
if let Err(e) = socket.set_nodelay(true) {
warn!("Couldn't set TCP nodelay: {}", e);
}
if let Err(e) = socket.set_reuse_address(true) {
warn!("Couldn't set reuse address: {}", e);
}
cfg_if! {
if #[cfg(unix)] {
if let Err(e) = socket.set_reuse_port(true) {
warn!("Couldn't set reuse port: {}", e);
}
}
}
// Bind a listener and stash it with the sockaddr in a table
trace!("spawn_socket_listener: binding to {}", addr);
let socket2_addr = socket2::SockAddr::from(addr);
socket
.bind(&socket2_addr)
.map_err(|e| format!("failed to bind TCP socket: {}", e))?;
// Listen on the socket // Listen on the socket
socket socket
.listen(128) .listen(128)
@ -461,30 +454,59 @@ impl Network {
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
async fn spawn_udp_socket(&self, addr: SocketAddr) -> Result<(), String> { async fn create_udp_outbound_sockets(&self) -> Result<(), String> {
trace!("spawn_udp_socket on {:?}", &addr); let mut inner = self.inner.lock();
let mut port = inner.udp_port;
// v4
let socket_addr_v4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port);
if let Ok(socket) = new_shared_udp_socket(socket_addr_v4) {
log_net!("created udpv4 outbound socket on {:?}", &socket_addr_v4);
// Pull the port if we randomly bound, so v6 can be on the same port
port = socket
.local_addr()
.map_err(map_to_string)?
.as_socket_ipv4()
.ok_or("expected ipv4 address type".to_owned())?
.port();
// Make an async UdpSocket from the socket2 socket
let std_udp_socket: std::net::UdpSocket = socket.into();
let udp_socket = UdpSocket::from(std_udp_socket);
let socket_arc = Arc::new(udp_socket);
// Create protocol handler
let udpv4_handler =
RawUdpProtocolHandler::new(inner.network_manager.clone(), socket_arc.clone());
inner.outbound_udpv4_protocol_handler = Some(udpv4_handler);
}
//v6
let socket_addr_v6 =
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), port);
if let Ok(socket) = new_shared_udp_socket(socket_addr_v6) {
log_net!("created udpv6 outbound socket on {:?}", &socket_addr_v6);
// Make an async UdpSocket from the socket2 socket
let std_udp_socket: std::net::UdpSocket = socket.into();
let udp_socket = UdpSocket::from(std_udp_socket);
let socket_arc = Arc::new(udp_socket);
// Create protocol handler
let udpv6_handler =
RawUdpProtocolHandler::new(inner.network_manager.clone(), socket_arc.clone());
inner.outbound_udpv6_protocol_handler = Some(udpv6_handler);
}
Ok(())
}
async fn spawn_udp_inbound_socket(&self, addr: SocketAddr) -> Result<(), String> {
log_net!("spawn_udp_inbound_socket on {:?}", &addr);
// Create a reusable socket // Create a reusable socket
let domain = Domain::for_address(addr); let socket = new_shared_udp_socket(addr)?;
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP))
.map_err(|e| format!("Couldn't create UDP socket: {}", e))?;
if let Err(e) = socket.set_reuse_address(true) {
warn!("Couldn't set reuse address: {}", e);
}
cfg_if! {
if #[cfg(unix)] {
if let Err(e) = socket.set_reuse_port(true) {
warn!("Couldn't set reuse port: {}", e);
}
}
}
// Bind a listener and stash it with the sockaddr in a table
trace!("spawn_udp_socket: binding to {}", addr);
let socket2_addr = socket2::SockAddr::from(addr);
socket
.bind(&socket2_addr)
.map_err(|e| format!("failed to bind UDP socket: {}", e))?;
// Make an async UdpSocket from the socket2 socket // Make an async UdpSocket from the socket2 socket
let std_udp_socket: std::net::UdpSocket = socket.into(); let std_udp_socket: std::net::UdpSocket = socket.into();
@ -582,7 +604,7 @@ impl Network {
if !self.inner.lock().udp_protocol_handlers.contains_key(&addr) { if !self.inner.lock().udp_protocol_handlers.contains_key(&addr) {
let ldi_addrs = Self::translate_unspecified_address(&*self.inner.lock(), &addr); let ldi_addrs = Self::translate_unspecified_address(&*self.inner.lock(), &addr);
self.clone().spawn_udp_socket(addr).await?; self.clone().spawn_udp_inbound_socket(addr).await?;
// Return local dial infos we listen on // Return local dial infos we listen on
for ldi_addr in ldi_addrs { for ldi_addr in ldi_addrs {
@ -627,30 +649,29 @@ impl Network {
return Some(ph.clone()); return Some(ph.clone());
} }
} }
// otherwise find the first udp protocol handler that matches the ip protocol version of the peer addr
// otherwise find the outbound udp protocol handler that matches the ip protocol version of the peer addr
let inner = self.inner.lock(); let inner = self.inner.lock();
for (local_addr, ph) in &inner.udp_protocol_handlers { match peer_socket_addr {
if Self::match_socket_addr(&*inner, local_addr, peer_socket_addr) { SocketAddr::V4(_) => inner.outbound_udpv4_protocol_handler.clone(),
return Some(ph.clone()); SocketAddr::V6(_) => inner.outbound_udpv6_protocol_handler.clone(),
} }
} }
None
}
fn find_best_tcp_local_address(&self, peer_socket_addr: &SocketAddr) -> Option<SocketAddr> { fn get_preferred_local_address(
// Find a matching listening local tcp socket address if we can &self,
let routing_table = self.routing_table(); local_port: u16,
let dids = routing_table.local_dial_info_for_protocol(ProtocolType::TCP); peer_socket_addr: &SocketAddr,
) -> SocketAddr {
let inner = self.inner.lock(); let inner = self.inner.lock();
for did in dids { match peer_socket_addr {
if let Ok(local_addr) = did.dial_info.to_socket_addr() { SocketAddr::V4(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), local_port),
if Self::match_socket_addr(&*inner, &local_addr, peer_socket_addr) { SocketAddr::V6(_) => SocketAddr::new(
return Some(local_addr); IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
local_port,
),
} }
} }
}
None
}
async fn send_data_to_existing_connection( async fn send_data_to_existing_connection(
&self, &self,
@ -744,17 +765,30 @@ impl Network {
} }
DialInfo::TCP(_) => { DialInfo::TCP(_) => {
let peer_socket_addr = dial_info.to_socket_addr().map_err(logthru_net!())?; let peer_socket_addr = dial_info.to_socket_addr().map_err(logthru_net!())?;
let some_local_addr = self.find_best_tcp_local_address(&peer_socket_addr); let local_addr =
RawTcpProtocolHandler::connect(network_manager, some_local_addr, peer_socket_addr) self.get_preferred_local_address(self.inner.lock().tcp_port, &peer_socket_addr);
RawTcpProtocolHandler::connect(network_manager, local_addr, peer_socket_addr)
.await .await
.map_err(logthru_net!())? .map_err(logthru_net!())?
} }
DialInfo::WS(_) => WebsocketProtocolHandler::connect(network_manager, dial_info) DialInfo::WS(_) => {
.await let remote_ip_addr = dial_info.resolve()?;
.map_err(logthru_net!(error))?,
DialInfo::WSS(_) => WebsocketProtocolHandler::connect(network_manager, dial_info) let local_addr =
self.get_preferred_local_address(self.inner.lock().ws_port, &peer_socket_addr);
WebsocketProtocolHandler::connect(network_manager, local_addr, dial_info)
.await
.map_err(logthru_net!(error))?
}
DialInfo::WSS(_) => {
let local_addr =
self.get_preferred_local_address(self.inner.lock().ws_port, &peer_socket_addr);
WebsocketProtocolHandler::connect(network_manager, dial_info)
.await .await
.map_err(logthru_net!(error))?, .map_err(logthru_net!(error))?,
}
}; };
conn.send(data).await.map_err(logthru_net!(error)) conn.send(data).await.map_err(logthru_net!(error))
@ -801,11 +835,12 @@ impl Network {
c.network.protocol.udp.public_address.clone(), c.network.protocol.udp.public_address.clone(),
) )
}; };
trace!("UDP: starting listener at {:?}", listen_address); info!("UDP: starting listener at {:?}", listen_address);
let dial_infos = self.start_udp_handler(listen_address.clone()).await?; let dial_infos = self.start_udp_handler(listen_address.clone()).await?;
trace!("UDP: listener started");
for x in &dial_infos { for x in &dial_infos {
// Pick out UDP port for outbound connections (they will all be the same)
self.inner.lock().udp_port = x.port();
// Register local dial info
routing_table.register_local_dial_info(x.clone(), DialInfoOrigin::Static); routing_table.register_local_dial_info(x.clone(), DialInfoOrigin::Static);
} }
@ -867,6 +902,9 @@ impl Network {
let mut dial_infos: Vec<DialInfo> = Vec::new(); let mut dial_infos: Vec<DialInfo> = Vec::new();
for (a, p) in addresses { for (a, p) in addresses {
// Pick out WS port for outbound connections (they will all be the same)
self.inner.lock().ws_port = p;
let di = DialInfo::ws(a.address_string(), p, path.clone()); let di = DialInfo::ws(a.address_string(), p, path.clone());
dial_infos.push(di.clone()); dial_infos.push(di.clone());
routing_table.register_local_dial_info(di, DialInfoOrigin::Static); routing_table.register_local_dial_info(di, DialInfoOrigin::Static);
@ -906,7 +944,7 @@ impl Network {
) )
}; };
trace!("WSS: starting listener at {}", listen_address); trace!("WSS: starting listener at {}", listen_address);
let _ = self let addresses = self
.start_tcp_listener( .start_tcp_listener(
listen_address.clone(), listen_address.clone(),
true, true,
@ -921,11 +959,14 @@ impl Network {
// This is not the case with unencrypted websockets, which can be specified solely by an IP address // This is not the case with unencrypted websockets, which can be specified solely by an IP address
// //
// let mut dial_infos: Vec<DialInfo> = Vec::new(); // let mut dial_infos: Vec<DialInfo> = Vec::new();
// for (a, p) in addresses { for (_, p) in addresses {
// Pick out WS port for outbound connections (they will all be the same)
self.inner.lock().wss_port = p;
// let di = DialInfo::wss(a.address_string(), p, path.clone()); // let di = DialInfo::wss(a.address_string(), p, path.clone());
// dial_infos.push(di.clone()); // dial_infos.push(di.clone());
// routing_table.register_local_dial_info(di, DialInfoOrigin::Static); // routing_table.register_local_dial_info(di, DialInfoOrigin::Static);
// } }
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
if let Some(url) = url.as_ref() { if let Some(url) = url.as_ref() {
@ -974,6 +1015,9 @@ impl Network {
let mut dial_infos: Vec<DialInfo> = Vec::new(); let mut dial_infos: Vec<DialInfo> = Vec::new();
for (a, p) in addresses { for (a, p) in addresses {
// Pick out TCP port for outbound connections (they will all be the same)
self.inner.lock().tcp_port = p;
let di = DialInfo::tcp(a.to_canonical(), p); let di = DialInfo::tcp(a.to_canonical(), p);
dial_infos.push(di.clone()); dial_infos.push(di.clone());
routing_table.register_local_dial_info(di, DialInfoOrigin::Static); routing_table.register_local_dial_info(di, DialInfoOrigin::Static);
@ -1019,24 +1063,29 @@ impl Network {
pub async fn startup(&self) -> Result<(), String> { pub async fn startup(&self) -> Result<(), String> {
info!("starting network"); info!("starting network");
let network_manager = self.inner.lock().network_manager.clone();
// initialize interfaces // initialize interfaces
self.inner.lock().interfaces.refresh()?; self.inner.lock().interfaces.refresh()?;
// get listen config // get network config
let (listen_udp, listen_tcp, listen_ws, listen_wss) = { let (enabled_udp, connect_tcp, listen_tcp, connect_ws, listen_ws, connect_wss, listen_wss) = {
let c = self.config.get(); let c = self.config.get();
( (
c.network.protocol.udp.enabled && c.capabilities.protocol_udp, c.network.protocol.udp.enabled && c.capabilities.protocol_udp,
c.network.protocol.tcp.connect && c.capabilities.protocol_connect_tcp,
c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp, c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp,
c.network.protocol.ws.connect && c.capabilities.protocol_connect_ws,
c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws, c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws,
c.network.protocol.wss.connect && c.capabilities.protocol_connect_wss,
c.network.protocol.wss.listen && c.capabilities.protocol_accept_wss, c.network.protocol.wss.listen && c.capabilities.protocol_accept_wss,
) )
}; };
// start listeners // start listeners
if listen_udp { if enabled_udp {
self.start_udp_listeners().await?; self.start_udp_listeners().await?;
self.create_udp_outbound_sockets().await?;
} }
if listen_ws { if listen_ws {
self.start_ws_listeners().await?; self.start_ws_listeners().await?;

View File

@ -6,6 +6,7 @@ pub mod ws;
use super::listener_state::*; use super::listener_state::*;
use crate::veilid_api::ProtocolType; use crate::veilid_api::ProtocolType;
use crate::xx::*; use crate::xx::*;
use socket2::{Domain, Protocol, Socket, Type};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct DummyNetworkConnection {} pub struct DummyNetworkConnection {}
@ -61,3 +62,57 @@ impl NetworkConnection {
} }
} }
} }
pub fn new_shared_udp_socket(local_address: SocketAddr) -> Result<socket2::Socket, String> {
let domain = Domain::for_address(local_address);
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP))
.map_err(|e| format!("Couldn't create UDP socket: {}", e))?;
if let Err(e) = socket.set_reuse_address(true) {
log_net!(error "Couldn't set reuse address: {}", e);
}
cfg_if! {
if #[cfg(unix)] {
if let Err(e) = socket.set_reuse_port(true) {
log_net!(error "Couldn't set reuse port: {}", e);
}
}
}
let socket2_addr = socket2::SockAddr::from(local_address);
socket
.bind(&socket2_addr)
.map_err(|e| format!("failed to bind UDP socket: {}", e))?;
Ok(socket)
}
pub fn new_shared_tcp_socket(local_address: SocketAddr) -> Result<socket2::Socket, String> {
let domain = Domain::for_address(local_address);
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))
.map_err(map_to_string)
.map_err(logthru_net!())?;
if let Err(e) = socket.set_linger(None) {
log_net!(error "Couldn't set TCP linger: {}", e);
}
if let Err(e) = socket.set_nodelay(true) {
log_net!(error "Couldn't set TCP nodelay: {}", e);
}
if let Err(e) = socket.set_reuse_address(true) {
log_net!(error "Couldn't set reuse address: {}", e);
}
cfg_if! {
if #[cfg(unix)] {
if let Err(e) = socket.set_reuse_port(true) {
log_net!(error "Couldn't set reuse port: {}", e);
}
}
}
let socket2_addr = socket2::SockAddr::from(local_address);
if let Err(e) = socket.bind(&socket2_addr) {
log_net!(error "failed to bind TCP socket: {}", e);
}
Ok(socket)
}

View File

@ -6,7 +6,6 @@ use crate::*;
use async_std::net::*; use async_std::net::*;
use async_std::prelude::*; use async_std::prelude::*;
use async_std::sync::Mutex as AsyncMutex; use async_std::sync::Mutex as AsyncMutex;
use socket2::{Domain, Protocol, Socket, Type};
use std::fmt; use std::fmt;
struct RawTcpNetworkConnectionInner { struct RawTcpNetworkConnectionInner {
@ -170,40 +169,11 @@ impl RawTcpProtocolHandler {
pub async fn connect( pub async fn connect(
network_manager: NetworkManager, network_manager: NetworkManager,
preferred_local_address: Option<SocketAddr>, local_address: SocketAddr,
remote_socket_addr: SocketAddr, remote_socket_addr: SocketAddr,
) -> Result<NetworkConnection, String> { ) -> Result<NetworkConnection, String> {
// Make a low level socket that can connect to the remote socket address // Make a shared socket
// and attempt to reuse the local address that our listening socket uses let socket = new_shared_tcp_socket(local_address)?;
// for hole-punch compatibility
let domain = Domain::for_address(remote_socket_addr);
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))
.map_err(map_to_string)
.map_err(logthru_net!())?;
if let Err(e) = socket.set_linger(None) {
log_net!("Couldn't set TCP linger: {}", e);
}
if let Err(e) = socket.set_nodelay(true) {
log_net!("Couldn't set TCP nodelay: {}", e);
}
if let Err(e) = socket.set_reuse_address(true) {
log_net!("Couldn't set reuse address: {}", e);
}
cfg_if! {
if #[cfg(unix)] {
if let Err(e) = socket.set_reuse_port(true) {
log_net!("Couldn't set reuse port: {}", e);
}
}
}
// Try to bind it to the preferred local address
if let Some(some_local_addr) = preferred_local_address {
let socket2_addr = socket2::SockAddr::from(some_local_addr);
if let Err(e) = socket.bind(&socket2_addr) {
log_net!(error "failed to bind TCP socket: {}", e);
}
}
// Connect to the remote address // Connect to the remote address
let remote_socket2_addr = socket2::SockAddr::from(remote_socket_addr); let remote_socket2_addr = socket2::SockAddr::from(remote_socket_addr);

View File

@ -244,19 +244,21 @@ impl WebsocketProtocolHandler {
pub async fn connect( pub async fn connect(
network_manager: NetworkManager, network_manager: NetworkManager,
local_address: SocketAddr,
dial_info: &DialInfo, dial_info: &DialInfo,
) -> Result<NetworkConnection, String> { ) -> Result<NetworkConnection, String> {
// Split dial info up
let (tls, request, domain, port, protocol_type) = match &dial_info { let (tls, request, domain, port, protocol_type) = match &dial_info {
DialInfo::WS(di) => ( DialInfo::WS(di) => (
false, false,
di.path.clone(), format!("ws://{}:{}/{}", di.host, di.port, di.path),
di.host.clone(), di.host.clone(),
di.port, di.port,
ProtocolType::WS, ProtocolType::WS,
), ),
DialInfo::WSS(di) => ( DialInfo::WSS(di) => (
true, true,
di.path.clone(), format!("wss://{}:{}/{}", di.host, di.port, di.path),
di.host.clone(), di.host.clone(),
di.port, di.port,
ProtocolType::WSS, ProtocolType::WSS,
@ -264,24 +266,29 @@ impl WebsocketProtocolHandler {
_ => panic!("invalid dialinfo for WS/WSS protocol"), _ => panic!("invalid dialinfo for WS/WSS protocol"),
}; };
let tcp_stream = TcpStream::connect(format!("{}:{}", &domain, &port)) // Resolve remote address
.await let remote_ip_addr = dial_info.resolve()?;
let remote_socket_addr = SocketAddr::new(remote_ip_addr, port);
// Make a shared socket
let socket = new_shared_tcp_socket(local_address)?;
// Connect to the remote address
let remote_socket2_addr = socket2::SockAddr::from(remote_socket_addr);
socket
.connect(&remote_socket2_addr)
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error "addr={}", remote_socket_addr))?;
let local_addr = tcp_stream let std_stream: std::net::TcpStream = socket.into();
let tcp_stream = TcpStream::from(std_stream);
// See what local address we ended up with
let actual_local_addr = tcp_stream
.local_addr() .local_addr()
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?; .map_err(logthru_net!())?;
let peer_socket_addr = tcp_stream
.peer_addr()
.map_err(map_to_string)
.map_err(logthru_net!(error))?;
let peer_addr = PeerAddress::new(
Address::from_socket_addr(peer_socket_addr),
peer_socket_addr.port(),
protocol_type,
);
// Negotiate TLS if this is WSS
if tls { if tls {
let connector = TlsConnector::default(); let connector = TlsConnector::default();
let tls_stream = connector let tls_stream = connector
@ -294,9 +301,18 @@ impl WebsocketProtocolHandler {
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error))?;
let conn = NetworkConnection::Wss(WebsocketNetworkConnection::new(tls, ws_stream)); let conn = NetworkConnection::Wss(WebsocketNetworkConnection::new(tls, ws_stream));
// Make the connection descriptor peer address
let peer_addr = PeerAddress::new(
Address::from_socket_addr(remote_socket_addr),
port,
ProtocolType::WSS,
);
// Register the WSS connection
network_manager network_manager
.on_new_connection( .on_new_connection(
ConnectionDescriptor::new(peer_addr, local_addr), ConnectionDescriptor::new(peer_addr, actual_local_addr),
conn.clone(), conn.clone(),
) )
.await?; .await?;
@ -307,9 +323,18 @@ impl WebsocketProtocolHandler {
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error))?;
let conn = NetworkConnection::Ws(WebsocketNetworkConnection::new(tls, ws_stream)); let conn = NetworkConnection::Ws(WebsocketNetworkConnection::new(tls, ws_stream));
// Make the connection descriptor peer address
let peer_addr = PeerAddress::new(
Address::from_socket_addr(remote_socket_addr),
port,
ProtocolType::WS,
);
// Register the WS connection
network_manager network_manager
.on_new_connection( .on_new_connection(
ConnectionDescriptor::new(peer_addr, local_addr), ConnectionDescriptor::new(peer_addr, actual_local_addr),
conn.clone(), conn.clone(),
) )
.await?; .await?;

View File

@ -25,7 +25,7 @@ impl DialInfoEntry {
self.resolved_address self.resolved_address
} }
pub fn resolve(&mut self) -> Result<IpAddr, String> { pub fn resolve(&mut self) -> Result<Vec<IpAddr, String> {
let addr = match self.dial_info.resolve() { let addr = match self.dial_info.resolve() {
Ok(a) => a, Ok(a) => a,
Err(_) => return Err("failed to resolve address".to_owned()), Err(_) => return Err("failed to resolve address".to_owned()),

View File

@ -20,15 +20,105 @@ pub use core::str::FromStr;
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
pub enum VeilidAPIError {
Timeout,
Shutdown,
NodeNotFound(NodeId),
NoDialInfo(NodeId),
Internal(String),
Unimplemented(String),
ParseError {
message: String,
value: String,
},
InvalidArgument {
context: String,
argument: String,
value: String,
},
MissingArgument {
context: String,
argument: String,
},
}
impl fmt::Display for VeilidAPIError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"),
VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"),
VeilidAPIError::NodeNotFound(ni) => write!(f, "VeilidAPIError::NodeNotFound({})", ni),
VeilidAPIError::NoDialInfo(ni) => write!(f, "VeilidAPIError::NoDialInfo({})", ni),
VeilidAPIError::Internal(e) => write!(f, "VeilidAPIError::Internal({})", e),
VeilidAPIError::Unimplemented(e) => write!(f, "VeilidAPIError::Unimplemented({})", e),
VeilidAPIError::ParseError { message, value } => {
write!(f, "VeilidAPIError::ParseError({}: {})", message, value)
}
VeilidAPIError::InvalidArgument {
context,
argument,
value,
} => {
write!(
f,
"VeilidAPIError::InvalidArgument({}: {} = {})",
context, argument, value
)
}
VeilidAPIError::MissingArgument { context, argument } => {
write!(
f,
"VeilidAPIError::MissingArgument({}: {})",
context, argument
)
}
}
}
}
fn convert_rpc_error(x: RPCError) -> VeilidAPIError {
match x {
RPCError::Timeout => VeilidAPIError::Timeout,
RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented(s),
RPCError::Internal(s) => VeilidAPIError::Internal(s),
RPCError::Protocol(s) => VeilidAPIError::Internal(s),
RPCError::InvalidFormat => VeilidAPIError::Internal("Invalid packet format".to_owned()),
}
}
macro_rules! map_rpc_error {
() => {
|x| convert_rpc_error(x)
};
}
macro_rules! parse_error {
($msg:expr, $val:expr) => {
VeilidAPIError::ParseError {
message: $msg.to_string(),
value: $val.to_string(),
}
};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)]
pub struct NodeId { pub struct NodeId {
pub key: DHTKey, pub key: DHTKey,
} }
impl NodeId { impl NodeId {
pub fn new(key: DHTKey) -> Self { pub fn new(key: DHTKey) -> Self {
assert!(key.valid);
Self { key } Self { key }
} }
} }
impl fmt::Display for NodeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}", self.key.encode())
}
}
#[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)]
pub struct ValueKey { pub struct ValueKey {
@ -91,33 +181,26 @@ pub enum ProtocolType {
} }
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum ProtocolAddressType { pub enum ProtocolNetworkType {
UDPv4, UDPv4,
UDPv6, UDPv6,
TCPv4, TCPv4,
TCPv6, TCPv6,
WS,
WSS,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum Address { pub enum Address {
IPV4(Ipv4Addr), IPV4(Ipv4Addr),
IPV6(Ipv6Addr), IPV6(Ipv6Addr),
Hostname(String), }
impl Default for Address {
fn default() -> Self {
Address::IPV4(Ipv4Addr::new(0, 0, 0, 0))
}
} }
impl Address { impl Address {
pub fn to_canonical(&self) -> Address {
match self {
Address::IPV4(v4) => Address::IPV4(*v4),
Address::IPV6(v6) => match v6.to_ipv4() {
Some(v4) => Address::IPV4(v4),
None => Address::IPV6(*v6),
},
Address::Hostname(h) => Address::Hostname(h.clone()),
}
}
pub fn from_socket_addr(sa: SocketAddr) -> Address { pub fn from_socket_addr(sa: SocketAddr) -> Address {
match sa { match sa {
SocketAddr::V4(v4) => Address::IPV4(*v4.ip()), SocketAddr::V4(v4) => Address::IPV4(*v4.ip()),
@ -128,77 +211,138 @@ impl Address {
match self { match self {
Address::IPV4(v4) => v4.to_string(), Address::IPV4(v4) => v4.to_string(),
Address::IPV6(v6) => v6.to_string(), Address::IPV6(v6) => v6.to_string(),
Address::Hostname(h) => h.clone(),
} }
} }
pub fn address_string_with_port(&self, port: u16) -> String { pub fn address_string_with_port(&self, port: u16) -> String {
match self { match self {
Address::IPV4(v4) => format!("{}:{}", v4.to_string(), port), Address::IPV4(v4) => format!("{}:{}", v4.to_string(), port),
Address::IPV6(v6) => format!("[{}]:{}", v6.to_string(), port), Address::IPV6(v6) => format!("[{}]:{}", v6.to_string(), port),
Address::Hostname(h) => format!("{}:{}", h.clone(), port),
} }
} }
pub fn resolve(&self) -> Result<IpAddr, String> { pub fn is_public(&self) -> bool {
match self { match self {
Self::IPV4(a) => Ok(IpAddr::V4(*a)), Address::IPV4(v4) => ipv4addr_is_global(&v4),
Self::IPV6(a) => Ok(IpAddr::V6(*a)), Address::IPV6(v6) => ipv6addr_is_global(&v6),
Self::Hostname(h) => h
.parse()
.map_err(|e| format!("Failed to parse hostname: {}", e)),
} }
} }
pub fn address(&self) -> Result<IpAddr, String> { pub fn is_private(&self) -> bool {
match self { match self {
Self::IPV4(a) => Ok(IpAddr::V4(*a)), Address::IPV4(v4) => ipv4addr_is_private(&v4),
Self::IPV6(a) => Ok(IpAddr::V6(*a)), Address::IPV6(v6) => ipv6addr_is_unicast_site_local(&v6),
Self::Hostname(h) => Err(format!("Address not available for hostname: {}", h)),
} }
} }
pub fn to_socket_addr(&self, port: u16) -> Result<SocketAddr, String> { pub fn to_ip_addr(&self) -> IpAddr {
let addr = self.address()?; match self {
Ok(SocketAddr::new(addr, port)) Self::IPV4(a) => IpAddr::V4(*a),
Self::IPV6(a) => IpAddr::V6(*a),
}
}
pub fn to_socket_addr(&self, port: u16) -> SocketAddr {
SocketAddr::new(self.to_ip_addr(), port)
}
pub fn to_canonical(&self) -> Address {
match self {
Address::IPV4(v4) => Address::IPV4(*v4),
Address::IPV6(v6) => match v6.to_ipv4() {
Some(v4) => Address::IPV4(v4),
None => Address::IPV6(*v6),
},
}
} }
} }
impl core::str::FromStr for Address { impl FromStr for Address {
type Err = String; type Err = VeilidAPIError;
fn from_str(host: &str) -> Result<Address, String> { fn from_str(host: &str) -> Result<Address, VeilidAPIError> {
if let Ok(addr) = Ipv4Addr::from_str(host) { if let Ok(addr) = Ipv4Addr::from_str(host) {
Ok(Address::IPV4(addr)) Ok(Address::IPV4(addr))
} else if let Ok(addr) = Ipv6Addr::from_str(host) { } else if let Ok(addr) = Ipv6Addr::from_str(host) {
Ok(Address::IPV6(addr)) Ok(Address::IPV6(addr))
} else if !host.is_empty() {
Ok(Address::Hostname(host.to_string()))
} else { } else {
Err("unable to convert address to string".to_owned()) Err(parse_error!("Address::from_str failed", host))
} }
} }
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Copy, Default, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct SocketAddress {
address: Address,
port: u16,
}
impl SocketAddress {
pub fn new(address: Address, port: u16) -> Self {
Self { address, port }
}
pub fn from_socket_addr(sa: SocketAddr) -> SocketAddress {
Self {
address: Address::from_socket_addr(sa),
port: sa.port(),
}
}
pub fn address(&self) -> Address {
self.address
}
pub fn port(&self) -> u16 {
self.port
}
pub fn to_canonical(&self) -> SocketAddress {
SocketAddress {
address: self.address.to_canonical(),
port: self.port,
}
}
pub fn to_ip_addr(&self) -> IpAddr {
self.address.to_ip_addr()
}
pub fn to_socket_addr(&self) -> SocketAddr {
self.address.to_socket_addr(self.port)
}
}
impl fmt::Display for SocketAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}:{}", self.to_ip_addr(), self.port)
}
}
impl FromStr for SocketAddress {
type Err = VeilidAPIError;
fn from_str(s: &str) -> Result<SocketAddress, VeilidAPIError> {
let split = s.rsplit_once(':').ok_or_else(|| {
parse_error!("SocketAddress::from_str missing colon port separator", s)
})?;
let address = Address::from_str(split.0)?;
let port = u16::from_str(split.1).map_err(|e| {
parse_error!(
format!("SocketAddress::from_str failed parting port: {}", e),
s
)
})?;
Ok(SocketAddress { address, port })
}
}
#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct DialInfoUDP { pub struct DialInfoUDP {
pub address: Address, pub socket_address: SocketAddress,
pub port: u16,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct DialInfoTCP { pub struct DialInfoTCP {
pub address: Address, pub socket_address: SocketAddress,
pub port: u16,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct DialInfoWS { pub struct DialInfoWS {
pub host: String, pub socket_address: SocketAddress,
pub port: u16, pub request: String,
pub path: String,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct DialInfoWSS { pub struct DialInfoWSS {
pub host: String, pub socket_address: SocketAddress,
pub port: u16, pub request: String,
pub path: String,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
@ -208,39 +352,124 @@ pub enum DialInfo {
WS(DialInfoWS), WS(DialInfoWS),
WSS(DialInfoWSS), WSS(DialInfoWSS),
} }
impl Default for DialInfo {
fn default() -> Self {
DialInfo::UDP(DialInfoUDP::default())
}
}
impl fmt::Display for DialInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
DialInfo::UDP(di) => write!(f, "udp|{}", di.socket_address),
DialInfo::TCP(di) => write!(f, "tcp|{}", di.socket_address),
DialInfo::WS(di) => write!(f, "ws|{}|{}", di.socket_address, di.request),
DialInfo::WSS(di) => write!(f, "wss|{}|{}", di.socket_address, di.request),
}
}
}
impl FromStr for DialInfo {
type Err = VeilidAPIError;
fn from_str(s: &str) -> Result<DialInfo, VeilidAPIError> {
let (proto, rest) = s.split_once('|').ok_or_else(|| {
parse_error!("SocketAddress::from_str missing protocol '|' separator", s)
})?;
match proto {
"udp" => {
let socket_address = SocketAddress::from_str(rest)?;
Ok(DialInfo::udp(socket_address))
}
"tcp" => {
let socket_address = SocketAddress::from_str(rest)?;
Ok(DialInfo::tcp(socket_address))
}
"ws" => {
let (sa, rest) = s.split_once('|').ok_or_else(|| {
parse_error!(
"SocketAddress::from_str missing socket address '|' separator",
s
)
})?;
let socket_address = SocketAddress::from_str(sa)?;
DialInfo::try_ws(socket_address, rest.to_string())
}
"wss" => {
let (sa, rest) = s.split_once('|').ok_or_else(|| {
parse_error!(
"SocketAddress::from_str missing socket address '|' separator",
s
)
})?;
let socket_address = SocketAddress::from_str(sa)?;
DialInfo::try_wss(socket_address, rest.to_string())
}
}
}
}
impl DialInfo { impl DialInfo {
pub fn udp_from_socketaddr(socketaddr: SocketAddr) -> Self { pub fn udp_from_socketaddr(socket_addr: SocketAddr) -> Self {
Self::UDP(DialInfoUDP { Self::UDP(DialInfoUDP {
address: Address::from_socket_addr(socketaddr).to_canonical(), socket_address: SocketAddress::from_socket_addr(socket_addr).to_canonical(),
port: socketaddr.port(),
}) })
} }
pub fn tcp_from_socketaddr(socketaddr: SocketAddr) -> Self { pub fn tcp_from_socketaddr(socket_addr: SocketAddr) -> Self {
Self::TCP(DialInfoTCP { Self::TCP(DialInfoTCP {
address: Address::from_socket_addr(socketaddr).to_canonical(), socket_address: SocketAddress::from_socket_addr(socket_addr).to_canonical(),
port: socketaddr.port(),
}) })
} }
pub fn udp(address: Address, port: u16) -> Self { pub fn udp(socket_address: SocketAddress) -> Self {
let address = address.to_canonical(); Self::UDP(DialInfoUDP {
if let Address::Hostname(_) = address { socket_address: socket_address.to_canonical(),
panic!("invalid address type for protocol") })
} }
Self::UDP(DialInfoUDP { address, port }) pub fn tcp(socket_address: SocketAddress) -> Self {
Self::TCP(DialInfoTCP {
socket_address: socket_address.to_canonical(),
})
} }
pub fn tcp(address: Address, port: u16) -> Self { pub fn try_ws(socket_address: SocketAddress, url: String) -> Result<Self, VeilidAPIError> {
let address = address.to_canonical(); let split_url = SplitUrl::from_str(&url)
if let Address::Hostname(_) = address { .map_err(|e| parse_error!(format!("unable to split WS url: {}", e), url))?;
panic!("invalid address type for protocol") if split_url.scheme != "ws" || !url.starts_with("ws://") {
return Err(parse_error!("incorrect scheme for WS dialinfo", url));
} }
Self::TCP(DialInfoTCP { address, port }) let url_port = split_url.port.unwrap_or(80u16);
if url_port != socket_address.port() {
return Err(parse_error!(
"socket address port doesn't match url port",
url
));
} }
pub fn ws(host: String, port: u16, path: String) -> Self { Ok(Self::WS(DialInfoWS {
Self::WS(DialInfoWS { host, port, path }) socket_address: socket_address.to_canonical(),
request: url[5..].to_string(),
}))
} }
pub fn wss(host: String, port: u16, path: String) -> Self { pub fn try_wss(socket_address: SocketAddress, url: String) -> Result<Self, VeilidAPIError> {
Self::WSS(DialInfoWSS { host, port, path }) let split_url = SplitUrl::from_str(&url)
.map_err(|e| parse_error!(format!("unable to split WSS url: {}", e), url))?;
if split_url.scheme != "wss" || !url.starts_with("wss://") {
return Err(parse_error!("incorrect scheme for WSS dialinfo", url));
}
let url_port = split_url.port.unwrap_or(443u16);
if url_port != socket_address.port() {
return Err(parse_error!(
"socket address port doesn't match url port",
url
));
}
if !Address::from_str(&split_url.host).is_err() {
return Err(parse_error!(
"WSS url can not use address format, only hostname format",
url
));
}
Ok(Self::WSS(DialInfoWSS {
socket_address: socket_address.to_canonical(),
request: url[6..].to_string(),
}))
} }
pub fn protocol_type(&self) -> ProtocolType { pub fn protocol_type(&self) -> ProtocolType {
match self { match self {
@ -250,234 +479,79 @@ impl DialInfo {
Self::WSS(_) => ProtocolType::WSS, Self::WSS(_) => ProtocolType::WSS,
} }
} }
pub fn protocol_network_type(&self) -> ProtocolNetworkType {
pub fn protocol_address_type(&self) -> ProtocolAddressType {
match self { match self {
Self::UDP(di) => match di.address { Self::UDP(di) => match di.socket_address.address() {
Address::IPV4(_) => ProtocolAddressType::UDPv4, Address::IPV4(_) => ProtocolNetworkType::UDPv4,
Address::IPV6(_) => ProtocolAddressType::UDPv6, Address::IPV6(_) => ProtocolNetworkType::UDPv6,
Address::Hostname(_) => panic!("invalid address type for protocol"),
}, },
Self::TCP(di) => match di.address { Self::TCP(di) => match di.socket_address.address() {
Address::IPV4(_) => ProtocolAddressType::TCPv4, Address::IPV4(_) => ProtocolNetworkType::TCPv4,
Address::IPV6(_) => ProtocolAddressType::TCPv6, Address::IPV6(_) => ProtocolNetworkType::TCPv6,
Address::Hostname(_) => panic!("invalid address type for protocol"),
}, },
Self::WS(_) => ProtocolAddressType::WS, Self::WS(di) => match di.socket_address.address() {
Self::WSS(_) => ProtocolAddressType::WSS, Address::IPV4(_) => ProtocolNetworkType::TCPv4,
} Address::IPV6(_) => ProtocolNetworkType::TCPv6,
}
pub fn try_udp_v4(&self) -> Option<SocketAddrV4> {
match self {
Self::UDP(v) => match v.address.to_socket_addr(v.port).ok() {
Some(SocketAddr::V4(v4)) => Some(v4),
_ => None,
}, },
_ => None, Self::WSS(di) => match di.socket_address.address() {
} Address::IPV4(_) => ProtocolNetworkType::TCPv4,
} Address::IPV6(_) => ProtocolNetworkType::TCPv6,
pub fn try_udp_v6(&self) -> Option<SocketAddrV6> {
match self {
Self::UDP(v) => match v.address.to_socket_addr(v.port).ok() {
Some(SocketAddr::V6(v6)) => Some(v6),
_ => None,
}, },
_ => None,
} }
} }
pub fn socket_address(&self) -> SocketAddress {
pub fn try_tcp_v4(&self) -> Option<SocketAddrV4> {
match self { match self {
Self::TCP(v) => match v.address.to_socket_addr(v.port).ok() { Self::UDP(di) => di.socket_address,
Some(SocketAddr::V4(v4)) => Some(v4), Self::TCP(di) => di.socket_address,
_ => None, Self::WS(di) => di.socket_address,
}, Self::WSS(di) => di.socket_address,
_ => None,
} }
} }
pub fn to_ip_addr(&self) -> IpAddr {
pub fn try_tcp_v6(&self) -> Option<SocketAddrV6> {
match self { match self {
Self::TCP(v) => match v.address.to_socket_addr(v.port).ok() { Self::UDP(di) => di.socket_address.to_ip_addr(),
Some(SocketAddr::V6(v6)) => Some(v6), Self::TCP(di) => di.socket_address.to_ip_addr(),
_ => None, Self::WS(di) => di.socket_address.to_ip_addr(),
}, Self::WSS(di) => di.socket_address.to_ip_addr(),
_ => None,
}
}
pub fn try_ws(&self) -> Option<String> {
match self {
Self::WS(v) => Some(v.host.clone()),
_ => None,
}
}
pub fn try_wss(&self) -> Option<String> {
match self {
Self::WSS(v) => Some(v.host.clone()),
_ => None,
}
}
pub fn address_string(&self) -> String {
match self {
Self::UDP(di) => di.address.address_string(),
Self::TCP(di) => di.address.address_string(),
Self::WS(di) => di.host.clone(),
Self::WSS(di) => di.host.clone(),
}
}
pub fn address_string_with_port(&self) -> String {
match self {
Self::UDP(di) => di.address.address_string_with_port(di.port),
Self::TCP(di) => di.address.address_string_with_port(di.port),
Self::WS(di) => format!("{}:{}", di.host.clone(), di.port),
Self::WSS(di) => format!("{}:{}", di.host.clone(), di.port),
}
}
pub fn all_but_path(&self) -> String {
match self {
Self::UDP(di) => format!("udp://{}", di.address.address_string_with_port(di.port)),
Self::TCP(di) => format!("tcp://{}", di.address.address_string_with_port(di.port)),
Self::WS(di) => format!("ws://{}:{}", di.host.clone(), di.port),
Self::WSS(di) => format!("wss://{}:{}", di.host.clone(), di.port),
}
}
pub fn to_url_string(&self, user: Option<String>) -> String {
let user_string = match user {
Some(u) => format!("{}@", u),
None => "".to_owned(),
};
match self {
Self::UDP(di) => format!(
"udp://{}{}",
user_string,
di.address.address_string_with_port(di.port)
),
Self::TCP(di) => format!(
"tcp://{}{}",
user_string,
di.address.address_string_with_port(di.port)
),
Self::WS(di) => format!(
"ws://{}{}:{}{}",
user_string,
di.host.clone(),
di.port,
prepend_slash(di.path.clone())
),
Self::WSS(di) => format!(
"wss://{}{}:{}{}",
user_string,
di.host.clone(),
di.port,
prepend_slash(di.path.clone())
),
}
}
pub fn resolve(&self) -> Result<IpAddr, String> {
match self {
Self::UDP(di) => {
let addr = di.address.resolve()?;
Ok(addr)
}
Self::TCP(di) => {
let addr = di.address.resolve()?;
Ok(addr)
}
Self::WS(di) => {
let addr: IpAddr = di
.host
.parse()
.map_err(|e| format!("Failed to parse WS host '{}': {}", di.host, e))?;
Ok(addr)
}
Self::WSS(di) => {
let addr: IpAddr = di
.host
.parse()
.map_err(|e| format!("Failed to parse WSS host '{}': {}", di.host, e))?;
Ok(addr)
}
}
}
pub fn address(&self) -> Result<IpAddr, String> {
match self {
Self::UDP(di) => di.address.address(),
Self::TCP(di) => di.address.address(),
Self::WS(_) => Err("Address not available for WS protocol".to_owned()),
Self::WSS(_) => Err("Address not available for WSS protocol".to_owned()),
} }
} }
pub fn port(&self) -> u16 { pub fn port(&self) -> u16 {
match self { match self {
Self::UDP(di) => di.port, Self::UDP(di) => di.socket_address.port,
Self::TCP(di) => di.port, Self::TCP(di) => di.socket_address.port,
Self::WS(di) => di.port, Self::WS(di) => di.socket_address.port,
Self::WSS(di) => di.port, Self::WSS(di) => di.socket_address.port,
} }
} }
pub fn path(&self) -> Result<String, String> { pub fn to_socket_addr(&self) -> SocketAddr {
match self { match self {
Self::UDP(_) => Err("path not available for udp protocol".to_owned()), Self::UDP(di) => di.socket_address.to_socket_addr(),
Self::TCP(_) => Err("path not available for tcp protocol".to_owned()), Self::TCP(di) => di.socket_address.to_socket_addr(),
Self::WS(di) => Ok(di.path.clone()), Self::WS(di) => di.socket_address.to_socket_addr(),
Self::WSS(di) => Ok(di.path.clone()), Self::WSS(di) => di.socket_address.to_socket_addr(),
} }
} }
pub fn to_socket_addr(&self) -> Result<SocketAddr, String> { pub fn request(&self) -> Option<String> {
match self { match self {
Self::UDP(di) => Ok(SocketAddr::new(di.address.address()?, di.port)), Self::UDP(_) => None,
Self::TCP(di) => Ok(SocketAddr::new(di.address.address()?, di.port)), Self::TCP(_) => None,
Self::WS(_) => Err("Can not directly convert WS hostname to socket addr".to_owned()), Self::WS(di) => Some(format!("ws://{}", di.request)),
Self::WSS(_) => Err("Can not directly convert WSS hostname to socket addr".to_owned()), Self::WSS(di) => Some(format!("wss://{}", di.request)),
} }
} }
pub fn is_public(&self) -> bool {
self.socket_address().address().is_public()
}
pub fn is_public(&self) -> Result<bool, String> { pub fn is_private(&self) -> bool {
let addr = self self.socket_address().address().is_private()
.resolve()
.map_err(|_| "failed to resolve address".to_owned())?;
Ok(ipaddr_is_global(&addr))
} }
pub fn is_private(&self) -> Result<bool, String> { pub fn is_valid(&self) -> bool {
let addr = self let socket_address = self.socket_address();
.resolve() let address = socket_address.address();
.map_err(|_| "failed to resolve address".to_owned())?; let port = socket_address.port();
Ok(match addr { (address.is_public() || address.is_private()) && port > 0
IpAddr::V4(a) => ipv4addr_is_private(&a),
IpAddr::V6(a) => ipv6addr_is_unicast_site_local(&a),
})
}
pub fn is_valid(&self) -> Result<bool, String> {
Ok(self.is_public()? || self.is_private()?)
}
pub fn is_loopback(&self) -> Result<bool, String> {
let addr = self
.resolve()
.map_err(|_| "failed to resolve address".to_owned())?;
Ok(ipaddr_is_loopback(&addr))
}
}
impl ToString for DialInfo {
fn to_string(&self) -> String {
self.to_url_string(None)
}
}
impl Default for DialInfo {
fn default() -> Self {
Self::UDP(DialInfoUDP {
address: Address::IPV4(Ipv4Addr::new(0, 0, 0, 0)),
port: 0u16,
})
} }
} }
@ -498,37 +572,40 @@ pub struct PeerInfo {
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] #[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct PeerAddress { pub struct PeerAddress {
pub address: Address, pub socket_address: SocketAddress,
pub port: u16,
pub protocol_type: ProtocolType, pub protocol_type: ProtocolType,
} }
impl PeerAddress { impl PeerAddress {
pub fn new(address: Address, port: u16, protocol_type: ProtocolType) -> Self { pub fn new(socket_address: SocketAddress, protocol_type: ProtocolType) -> Self {
Self { Self {
address, socket_address,
port,
protocol_type, protocol_type,
} }
} }
pub fn to_socket_addr(&self) -> Result<SocketAddr, String> { pub fn to_socket_addr(&self) -> SocketAddr {
self.address.to_socket_addr(self.port) self.socket_address.to_socket_addr()
} }
pub fn protocol_address_type(&self) -> ProtocolAddressType {
pub fn protocol_network_type(&self) -> ProtocolNetworkType {
match self.protocol_type { match self.protocol_type {
ProtocolType::UDP => match self.address { ProtocolType::UDP => match self.socket_address.address() {
Address::IPV4(_) => ProtocolAddressType::UDPv4, Address::IPV4(_) => ProtocolNetworkType::UDPv4,
Address::IPV6(_) => ProtocolAddressType::UDPv6, Address::IPV6(_) => ProtocolNetworkType::UDPv6,
Address::Hostname(_) => panic!("invalid address type for protocol"),
}, },
ProtocolType::TCP => match self.address { ProtocolType::TCP => match self.socket_address.address() {
Address::IPV4(_) => ProtocolAddressType::TCPv4, Address::IPV4(_) => ProtocolNetworkType::TCPv4,
Address::IPV6(_) => ProtocolAddressType::TCPv6, Address::IPV6(_) => ProtocolNetworkType::TCPv6,
Address::Hostname(_) => panic!("invalid address type for protocol"), },
ProtocolType::WS => match self.socket_address.address() {
Address::IPV4(_) => ProtocolNetworkType::TCPv4,
Address::IPV6(_) => ProtocolNetworkType::TCPv6,
},
ProtocolType::WSS => match self.socket_address.address() {
Address::IPV4(_) => ProtocolNetworkType::TCPv4,
Address::IPV6(_) => ProtocolNetworkType::TCPv6,
}, },
ProtocolType::WS => ProtocolAddressType::WS,
ProtocolType::WSS => ProtocolAddressType::WSS,
} }
} }
} }
@ -555,101 +632,48 @@ impl ConnectionDescriptor {
pub fn protocol_type(&self) -> ProtocolType { pub fn protocol_type(&self) -> ProtocolType {
self.remote.protocol_type self.remote.protocol_type
} }
pub fn protocol_address_type(&self) -> ProtocolAddressType { pub fn protocol_network_type(&self) -> ProtocolNetworkType {
self.remote.protocol_address_type() self.remote.protocol_network_type()
} }
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct NodeDialInfoSingle { pub struct NodeDialInfoSingle {
pub node_id: NodeId, pub node_id: NodeId,
pub dial_info: DialInfo, pub dial_info: DialInfo,
} }
impl core::str::FromStr for NodeDialInfoSingle { impl fmt::Display for NodeDialInfoSingle {
type Err = String; fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fn from_str(url: &str) -> Result<NodeDialInfoSingle, String> { write!(f, "{}@{}", self.node_id, self.dial_info)
let mut cur_url = url;
let proto;
if url.starts_with("udp://") {
cur_url = &cur_url[6..];
proto = ProtocolType::UDP;
} else if url.starts_with("tcp://") {
cur_url = &cur_url[6..];
proto = ProtocolType::TCP;
} else if url.starts_with("ws://") {
cur_url = &cur_url[5..];
proto = ProtocolType::WS;
} else if url.starts_with("wss://") {
cur_url = &cur_url[6..];
proto = ProtocolType::WSS;
} else {
return Err(format!("unknown protocol: {}", url));
}
// parse out node id if we have one
let node_id = match cur_url.find('@') {
Some(x) => {
let n = NodeId::new(DHTKey::try_decode(&cur_url[0..x])?);
cur_url = &cur_url[x + 1..];
n
}
None => {
return Err("NodeDialInfoSingle is missing the node id".to_owned());
}
};
// parse out address
let address = match cur_url.rfind(':') {
Some(x) => {
let mut h = &cur_url[0..x];
cur_url = &cur_url[x + 1..];
match proto {
ProtocolType::WS | ProtocolType::WSS => Address::Hostname(h.to_string()),
_ => {
// peel off square brackets on ipv6 address
if x >= 2 && &h[0..1] == "[" && &h[(h.len() - 1)..] == "]" {
h = &h[1..(h.len() - 1)];
}
Address::from_str(h)?
}
}
}
None => {
return Err("NodeDialInfoSingle is missing the port".to_owned());
}
};
// parse out port
let pathstart = cur_url.find('/').unwrap_or(cur_url.len());
let port =
u16::from_str(&cur_url[0..pathstart]).map_err(|e| format!("port is invalid: {}", e))?;
cur_url = &cur_url[pathstart..];
// build NodeDialInfoSingle
Ok(NodeDialInfoSingle {
node_id,
dial_info: match proto {
ProtocolType::UDP => DialInfo::udp(address, port),
ProtocolType::TCP => DialInfo::tcp(address, port),
ProtocolType::WS => {
DialInfo::ws(address.address_string(), port, cur_url.to_string())
}
ProtocolType::WSS => {
DialInfo::wss(address.address_string(), port, cur_url.to_string())
}
},
})
} }
} }
impl ToString for NodeDialInfoSingle { impl FromStr for NodeDialInfoSingle {
fn to_string(&self) -> String { type Err = VeilidAPIError;
self.dial_info fn from_str(s: &str) -> Result<NodeDialInfoSingle, VeilidAPIError> {
.to_url_string(Some(self.node_id.key.encode())) // split out node id from the dial info
let (node_id_str, rest) = s.split_once('@').ok_or_else(|| {
parse_error!(
"NodeDialInfoSingle::from_str missing @ node id separator",
s
)
})?;
// parse out node id
let node_id = NodeId::new(DHTKey::try_decode(node_id_str).map_err(|e| {
parse_error!(
format!("NodeDialInfoSingle::from_str couldn't parse node id: {}", e),
s
)
})?);
// parse out dial info
let dial_info = DialInfo::from_str(rest)?;
// return completed NodeDialInfoSingle
Ok(NodeDialInfoSingle { node_id, dial_info })
} }
} }
@ -705,41 +729,6 @@ cfg_if! {
} }
} }
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
pub enum VeilidAPIError {
Timeout,
Shutdown,
NodeNotFound(NodeId),
NoDialInfo(NodeId),
Internal(String),
Unimplemented(String),
InvalidArgument {
context: String,
argument: String,
value: String,
},
MissingArgument {
context: String,
argument: String,
},
}
fn convert_rpc_error(x: RPCError) -> VeilidAPIError {
match x {
RPCError::Timeout => VeilidAPIError::Timeout,
RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented(s),
RPCError::Internal(s) => VeilidAPIError::Internal(s),
RPCError::Protocol(s) => VeilidAPIError::Internal(s),
RPCError::InvalidFormat => VeilidAPIError::Internal("Invalid packet format".to_owned()),
}
}
macro_rules! map_rpc_error {
() => {
|x| convert_rpc_error(x)
};
}
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)]
pub enum TunnelMode { pub enum TunnelMode {
Raw, Raw,