refactor checkpoint

This commit is contained in:
John Smith 2022-04-16 11:18:54 -04:00
parent ddb74d993f
commit 71f7017235
23 changed files with 977 additions and 615 deletions

View File

@ -50,16 +50,16 @@ def tee(prefix, infile, *files):
return t return t
def read_until_local_dial_info(proc, proto): def read_until_interface_dial_info(proc, proto):
local_dial_info_str = b"Local Dial Info: " interface_dial_info_str = b"Interface Dial Info: "
for ln in iter(proc.stdout.readline, ""): for ln in iter(proc.stdout.readline, ""):
sys.stdout.buffer.write(ln) sys.stdout.buffer.write(ln)
sys.stdout.flush() sys.stdout.flush()
idx = ln.find(local_dial_info_str) idx = ln.find(interface_dial_info_str)
if idx != -1: if idx != -1:
idx += len(local_dial_info_str) idx += len(interface_dial_info_str)
di = ln[idx:] di = ln[idx:]
if b"@"+bytes(proto)+b"|" in di: if b"@"+bytes(proto)+b"|" in di:
return di.decode("utf-8").strip() return di.decode("utf-8").strip()
@ -130,7 +130,7 @@ def main():
main_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) main_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(">>> MAIN NODE PID={}".format(main_proc.pid)) print(">>> MAIN NODE PID={}".format(main_proc.pid))
main_di = read_until_local_dial_info( main_di = read_until_interface_dial_info(
main_proc, bytes(args.protocol, 'utf-8')) main_proc, bytes(args.protocol, 'utf-8'))
print(">>> MAIN DIAL INFO={}".format(main_di)) print(">>> MAIN DIAL INFO={}".format(main_di))

View File

@ -107,6 +107,19 @@ struct NodeDialInfo {
dialInfo @1 :DialInfo; # how to get to the node dialInfo @1 :DialInfo; # how to get to the node
} }
# Signals
##############################
struct SignalInfoHolePunch {
receipt @0 :Data; # receipt to return with hole punch
nodeInfo @1 :NodeInfo; # node info of the signal sender for hole punch attempt
}
struct SignalInfoReverseConnect {
receipt @0 :Data; # receipt to return with reverse connect
nodeInfo @1 :NodeInfo; # node info of the signal sender for reverse connect attempt
}
# Private Routes # Private Routes
############################## ##############################
@ -186,10 +199,18 @@ struct NodeStatus {
willValidateDialInfo @4 :Bool; willValidateDialInfo @4 :Bool;
} }
struct ProtocolSet {
udp @0 :Bool;
tcp @1 :Bool;
ws @2 :Bool;
wss @3 :Bool;
}
struct NodeInfo { struct NodeInfo {
networkClass @0 :NetworkClass; # network class of this node networkClass @0 :NetworkClass; # network class of this node
dialInfoList @1 :List(DialInfo); # dial info for this node outboundProtocols @1 :ProtocolSet; # protocols that can go outbound
relayDialInfoList @2 :List(DialInfo); # relay dial info for this node dialInfoList @2 :List(DialInfo); # inbound dial info for this node
relayPeerInfo @3 :PeerInfo; # (optional) relay peer info for this node
} }
struct SenderInfo { struct SenderInfo {
@ -214,8 +235,7 @@ struct OperationReturnReceipt {
struct OperationFindNodeQ { struct OperationFindNodeQ {
nodeId @0 :NodeID; # node id to locate nodeId @0 :NodeID; # node id to locate
dialInfoList @1 :List(DialInfo); # dial info for the node asking the question senderNodeInfo @1 :NodeInfo; # dial info for the node asking the question
relayDialInfoList @2 :List(DialInfo); # relay dial info for the node asking the question
} }
struct PeerInfo { struct PeerInfo {
@ -297,12 +317,11 @@ struct OperationFindBlockA {
peers @2 :List(PeerInfo); # returned 'closer peer' information peers @2 :List(PeerInfo); # returned 'closer peer' information
} }
struct OperationSignalQ { struct OperationSignal {
data @0 :Data; # the signalling system request union {
} holePunch @0 :SignalInfoHolePunch;
reverseConnect @1 :SignalInfoReverseConnect;
struct OperationSignalA { }
data @0 :Data; # the signalling system response
} }
enum TunnelEndpointMode { enum TunnelEndpointMode {
@ -318,9 +337,8 @@ enum TunnelError {
} }
struct TunnelEndpoint { struct TunnelEndpoint {
nodeId @0 :NodeID; # node id mode @0 :TunnelEndpointMode; # what kind of endpoint this is
dialInfoList @1 :List(DialInfo); # how to reach the node peerInfo @1 :PeerInfo; # node id and dialinfo
mode @2 :TunnelEndpointMode; # what kind of endpoint this is
} }
struct FullTunnel { struct FullTunnel {
@ -406,17 +424,15 @@ struct Operation {
findBlockQ @19 :OperationFindBlockQ; findBlockQ @19 :OperationFindBlockQ;
findBlockA @20 :OperationFindBlockA; findBlockA @20 :OperationFindBlockA;
signalQ @21 :OperationSignalQ; signal @21 :OperationSignal;
signalA @22 :OperationSignalA; returnReceipt @22 :OperationReturnReceipt;
returnReceipt @23 :OperationReturnReceipt;
# Tunnel operations # Tunnel operations
startTunnelQ @24 :OperationStartTunnelQ; startTunnelQ @23 :OperationStartTunnelQ;
startTunnelA @25 :OperationStartTunnelA; startTunnelA @24 :OperationStartTunnelA;
completeTunnelQ @26 :OperationCompleteTunnelQ; completeTunnelQ @25 :OperationCompleteTunnelQ;
completeTunnelA @27 :OperationCompleteTunnelA; completeTunnelA @26 :OperationCompleteTunnelA;
cancelTunnelQ @28 :OperationCancelTunnelQ; cancelTunnelQ @27 :OperationCancelTunnelQ;
cancelTunnelA @29 :OperationCancelTunnelA; cancelTunnelA @28 :OperationCancelTunnelA;
} }
} }

View File

@ -66,6 +66,7 @@ struct NetworkUnlockedInner {
// Background processes // Background processes
update_udpv4_dialinfo_task: TickTask, update_udpv4_dialinfo_task: TickTask,
update_tcpv4_dialinfo_task: TickTask, update_tcpv4_dialinfo_task: TickTask,
update_wsv4_dialinfo_task: TickTask,
} }
#[derive(Clone)] #[derive(Clone)]
@ -107,6 +108,7 @@ impl Network {
NetworkUnlockedInner { NetworkUnlockedInner {
update_udpv4_dialinfo_task: TickTask::new(1), update_udpv4_dialinfo_task: TickTask::new(1),
update_tcpv4_dialinfo_task: TickTask::new(1), update_tcpv4_dialinfo_task: TickTask::new(1),
update_wsv4_dialinfo_task: TickTask::new(1),
} }
} }
@ -135,6 +137,15 @@ impl Network {
Box::pin(this2.clone().update_tcpv4_dialinfo_task_routine(l, t)) Box::pin(this2.clone().update_tcpv4_dialinfo_task_routine(l, t))
}); });
} }
// Set ws dialinfo tick task
{
let this2 = this.clone();
this.unlocked_inner
.update_wsv4_dialinfo_task
.set_routine(move |l, t| {
Box::pin(this2.clone().update_wsv4_dialinfo_task_routine(l, t))
});
}
this this
} }
@ -289,7 +300,7 @@ impl Network {
res res
} }
async fn send_data_to_existing_connection( pub async fn send_data_to_existing_connection(
&self, &self,
descriptor: ConnectionDescriptor, descriptor: ConnectionDescriptor,
data: Vec<u8>, data: Vec<u8>,
@ -380,41 +391,6 @@ impl Network {
res res
} }
// Send data to node
// We may not have dial info for a node, but have an existing connection for it
// because an inbound connection happened first, and no FindNodeQ has happened to that
// node yet to discover its dial info. The existing connection should be tried first
// in this case.
pub async fn send_data(&self, node_ref: NodeRef, data: Vec<u8>) -> Result<(), String> {
// First try to send data to the last socket we've seen this peer on
let data = if let Some(descriptor) = node_ref.last_connection() {
match self
.clone()
.send_data_to_existing_connection(descriptor, data)
.await
.map_err(logthru_net!())?
{
None => {
return Ok(());
}
Some(d) => d,
}
} else {
data
};
// If that fails, try to make a connection or reach out to the peer via its dial info
let node_info = node_ref
.best_node_info()
.ok_or_else(|| "couldn't send data, no dial info or peer address".to_owned())?;
xxx write logic to determine if a relay needs to be used first xxx
self.send_data_to_dial_info(dial_info, data)
.await
.map_err(logthru_net!())
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
pub fn get_protocol_config(&self) -> Option<ProtocolConfig> { pub fn get_protocol_config(&self) -> Option<ProtocolConfig> {
@ -433,28 +409,33 @@ impl Network {
let protocol_config = { let protocol_config = {
let c = self.config.get(); let c = self.config.get();
ProtocolConfig { ProtocolConfig {
udp_enabled: c.network.protocol.udp.enabled && c.capabilities.protocol_udp, inbound: ProtocolSet {
tcp_connect: c.network.protocol.tcp.connect && c.capabilities.protocol_connect_tcp, udp: c.network.protocol.udp.enabled && c.capabilities.protocol_udp,
tcp_listen: c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp, tcp: c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp,
ws_connect: c.network.protocol.ws.connect && c.capabilities.protocol_connect_ws, ws: c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws,
ws_listen: c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws, wss: c.network.protocol.wss.listen && c.capabilities.protocol_accept_wss,
wss_connect: c.network.protocol.wss.connect && c.capabilities.protocol_connect_wss, },
wss_listen: c.network.protocol.wss.listen && c.capabilities.protocol_accept_wss, outbound: ProtocolSet {
udp: c.network.protocol.udp.enabled && c.capabilities.protocol_udp,
tcp: c.network.protocol.tcp.connect && c.capabilities.protocol_connect_tcp,
ws: c.network.protocol.ws.connect && c.capabilities.protocol_connect_ws,
wss: c.network.protocol.wss.connect && c.capabilities.protocol_connect_wss,
},
} }
}; };
self.inner.lock().protocol_config = Some(protocol_config); self.inner.lock().protocol_config = Some(protocol_config);
// start listeners // start listeners
if protocol_config.udp_enabled { if protocol_config.inbound.udp {
self.start_udp_listeners().await?; self.start_udp_listeners().await?;
} }
if protocol_config.ws_listen { if protocol_config.inbound.ws {
self.start_ws_listeners().await?; self.start_ws_listeners().await?;
} }
if protocol_config.wss_listen { if protocol_config.inbound.wss {
self.start_wss_listeners().await?; self.start_wss_listeners().await?;
} }
if protocol_config.tcp_listen { if protocol_config.inbound.tcp {
self.start_tcp_listeners().await?; self.start_tcp_listeners().await?;
} }
@ -503,7 +484,7 @@ impl Network {
// Go through our global dialinfo and see what our best network class is // Go through our global dialinfo and see what our best network class is
let mut network_class = NetworkClass::Invalid; let mut network_class = NetworkClass::Invalid;
for did in inner.routing_table.global_dial_info_details() { for did in inner.routing_table.public_dial_info_details() {
if let Some(nc) = did.network_class { if let Some(nc) = did.network_class {
if nc < network_class { if nc < network_class {
network_class = nc; network_class = nc;
@ -521,6 +502,7 @@ impl Network {
protocol_config, protocol_config,
udp_static_public_dialinfo, udp_static_public_dialinfo,
tcp_static_public_dialinfo, tcp_static_public_dialinfo,
ws_static_public_dialinfo,
network_class, network_class,
) = { ) = {
let inner = self.inner.lock(); let inner = self.inner.lock();
@ -529,6 +511,7 @@ impl Network {
inner.protocol_config.unwrap_or_default(), inner.protocol_config.unwrap_or_default(),
inner.udp_static_public_dialinfo, inner.udp_static_public_dialinfo,
inner.tcp_static_public_dialinfo, inner.tcp_static_public_dialinfo,
inner.ws_static_public_dialinfo,
inner.network_class.unwrap_or(NetworkClass::Invalid), inner.network_class.unwrap_or(NetworkClass::Invalid),
) )
}; };
@ -538,15 +521,15 @@ impl Network {
// If we can have public dialinfo, or we haven't figured out our network class yet, // If we can have public dialinfo, or we haven't figured out our network class yet,
// and we're active for UDP, we should attempt to get our public dialinfo sorted out // and we're active for UDP, we should attempt to get our public dialinfo sorted out
// and assess our network class if we haven't already // and assess our network class if we haven't already
if protocol_config.udp_enabled if protocol_config.inbound.udp
&& !udp_static_public_dialinfo && !udp_static_public_dialinfo
&& (network_class.inbound_capable() || network_class == NetworkClass::Invalid) && (network_class.inbound_capable() || network_class == NetworkClass::Invalid)
{ {
let filter = DialInfoFilter::global() let filter = DialInfoFilter::all()
.with_protocol_type(ProtocolType::UDP) .with_protocol_type(ProtocolType::UDP)
.with_address_type(AddressType::IPV4); .with_address_type(AddressType::IPV4);
let need_udpv4_dialinfo = routing_table let need_udpv4_dialinfo = routing_table
.first_filtered_dial_info_detail(&filter) .first_public_filtered_dial_info_detail(&filter)
.is_none(); .is_none();
if need_udpv4_dialinfo { if need_udpv4_dialinfo {
// If we have no public UDPv4 dialinfo, then we need to run a NAT check // If we have no public UDPv4 dialinfo, then we need to run a NAT check
@ -559,15 +542,15 @@ impl Network {
} }
// Same but for TCPv4 // Same but for TCPv4
if protocol_config.tcp_listen if protocol_config.inbound.tcp
&& !tcp_static_public_dialinfo && !tcp_static_public_dialinfo
&& (network_class.inbound_capable() || network_class == NetworkClass::Invalid) && (network_class.inbound_capable() || network_class == NetworkClass::Invalid)
{ {
let filter = DialInfoFilter::global() let filter = DialInfoFilter::all()
.with_protocol_type(ProtocolType::TCP) .with_protocol_type(ProtocolType::TCP)
.with_address_type(AddressType::IPV4); .with_address_type(AddressType::IPV4);
let need_tcpv4_dialinfo = routing_table let need_tcpv4_dialinfo = routing_table
.first_filtered_dial_info_detail(&filter) .first_public_filtered_dial_info_detail(&filter)
.is_none(); .is_none();
if need_tcpv4_dialinfo { if need_tcpv4_dialinfo {
// If we have no public TCPv4 dialinfo, then we need to run a NAT check // If we have no public TCPv4 dialinfo, then we need to run a NAT check
@ -579,6 +562,24 @@ impl Network {
} }
} }
// Same but for WSv4
if protocol_config.inbound.ws
&& !ws_static_public_dialinfo
&& (network_class.inbound_capable() || network_class == NetworkClass::Invalid)
{
let filter = DialInfoFilter::all()
.with_protocol_type(ProtocolType::WS)
.with_address_type(AddressType::IPV4);
let need_wsv4_dialinfo = routing_table
.first_public_filtered_dial_info_detail(&filter)
.is_none();
if need_wsv4_dialinfo {
// If we have no public TCPv4 dialinfo, then we need to run a NAT check
// ensure the singlefuture is running for this
self.unlocked_inner.update_wsv4_dialinfo_task.tick().await?;
}
}
Ok(()) Ok(())
} }
} }

View File

@ -227,7 +227,7 @@ impl Network {
for ip_addr in ip_addrs { for ip_addr in ip_addrs {
let addr = SocketAddr::new(ip_addr, port); let addr = SocketAddr::new(ip_addr, port);
let ldi_addrs = Self::translate_unspecified_address(&*(self.inner.lock()), &addr); let idi_addrs = Self::translate_unspecified_address(&*(self.inner.lock()), &addr);
// see if we've already bound to this already // see if we've already bound to this already
// if not, spawn a listener // if not, spawn a listener
@ -262,9 +262,9 @@ impl Network {
)); ));
} }
// Return local dial infos we listen on // Return interface dial infos we listen on
for ldi_addr in ldi_addrs { for idi_addr in idi_addrs {
out.push(SocketAddress::from_socket_addr(ldi_addr)); out.push(SocketAddress::from_socket_addr(idi_addr));
} }
} }

View File

@ -173,13 +173,13 @@ impl Network {
.inbound_udp_protocol_handlers .inbound_udp_protocol_handlers
.contains_key(&addr) .contains_key(&addr)
{ {
let ldi_addrs = Self::translate_unspecified_address(&*self.inner.lock(), &addr); let idi_addrs = Self::translate_unspecified_address(&*self.inner.lock(), &addr);
self.clone().create_udp_inbound_socket(addr).await?; self.clone().create_udp_inbound_socket(addr).await?;
// Return local dial infos we listen on // Return interface dial infos we listen on
for ldi_addr in ldi_addrs { for idi_addr in idi_addrs {
out.push(DialInfo::udp_from_socketaddr(ldi_addr)); out.push(DialInfo::udp_from_socketaddr(idi_addr));
} }
} }
} }

View File

@ -60,9 +60,15 @@ impl Network {
.with_protocol_type(protocol_type) .with_protocol_type(protocol_type)
.with_address_type(address_type); .with_address_type(address_type);
routing_table routing_table
.all_filtered_dial_info_details(&filter) .interface_dial_info_details()
.iter() .iter()
.map(|did| did.dial_info.socket_address()) .filter_map(|did| {
if did.dial_info.matches_filter(&filter) {
Some(did.dial_info.socket_address())
} else {
None
}
})
.collect() .collect()
} }
@ -130,7 +136,7 @@ impl Network {
.await .await
{ {
// Add public dial info with Server network class // Add public dial info with Server network class
routing_table.register_dial_info( routing_table.register_public_dial_info(
external1_dial_info, external1_dial_info,
DialInfoOrigin::Discovered, DialInfoOrigin::Discovered,
Some(NetworkClass::Server), Some(NetworkClass::Server),
@ -151,7 +157,7 @@ impl Network {
{ {
// Got a port mapping, let's use it // Got a port mapping, let's use it
let external_mapped_dial_info = DialInfo::udp(external_mapped); let external_mapped_dial_info = DialInfo::udp(external_mapped);
routing_table.register_dial_info( routing_table.register_public_dial_info(
external_mapped_dial_info, external_mapped_dial_info,
DialInfoOrigin::Mapped, DialInfoOrigin::Mapped,
Some(NetworkClass::Mapped), Some(NetworkClass::Mapped),
@ -174,7 +180,7 @@ impl Network {
{ {
// Yes, another machine can use the dial info directly, so Full Cone // Yes, another machine can use the dial info directly, so Full Cone
// Add public dial info with full cone NAT network class // Add public dial info with full cone NAT network class
routing_table.register_dial_info( routing_table.register_public_dial_info(
external1_dial_info, external1_dial_info,
DialInfoOrigin::Discovered, DialInfoOrigin::Discovered,
Some(NetworkClass::FullConeNAT), Some(NetworkClass::FullConeNAT),
@ -224,14 +230,14 @@ impl Network {
.await .await
{ {
// Got a reply from a non-default port, which means we're only address restricted // Got a reply from a non-default port, which means we're only address restricted
routing_table.register_dial_info( routing_table.register_public_dial_info(
external1_dial_info, external1_dial_info,
DialInfoOrigin::Discovered, DialInfoOrigin::Discovered,
Some(NetworkClass::AddressRestrictedNAT), Some(NetworkClass::AddressRestrictedNAT),
); );
} else { } else {
// Didn't get a reply from a non-default port, which means we are also port restricted // Didn't get a reply from a non-default port, which means we are also port restricted
routing_table.register_dial_info( routing_table.register_public_dial_info(
external1_dial_info, external1_dial_info,
DialInfoOrigin::Discovered, DialInfoOrigin::Discovered,
Some(NetworkClass::PortRestrictedNAT), Some(NetworkClass::PortRestrictedNAT),
@ -258,4 +264,11 @@ impl Network {
//Err("unimplemented".to_owned()) //Err("unimplemented".to_owned())
Ok(()) Ok(())
} }
pub async fn update_wsv4_dialinfo_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
log_net!("looking for wsv4 public dial info");
// xxx
//Err("unimplemented".to_owned())
Ok(())
}
} }

View File

@ -287,22 +287,23 @@ impl Network {
"UDP: starting listeners on port {} at {:?}", "UDP: starting listeners on port {} at {:?}",
udp_port, ip_addrs udp_port, ip_addrs
); );
let dial_infos = self.create_udp_inbound_sockets(ip_addrs, udp_port).await?; let dial_info_list = self.create_udp_inbound_sockets(ip_addrs, udp_port).await?;
let mut static_public = false; let mut static_public = false;
for di in &dial_infos { for di in &dial_info_list {
// Register local dial info only here if we specify a public address // If the local interface address is global,
// register global dial info if no public address is specified
if public_address.is_none() && di.is_global() { if public_address.is_none() && di.is_global() {
// Register global dial info if no public address is specified routing_table.register_public_dial_info(
routing_table.register_dial_info(
di.clone(), di.clone(),
DialInfoOrigin::Static, DialInfoOrigin::Static,
Some(NetworkClass::Server), Some(NetworkClass::Server),
); );
static_public = true; static_public = true;
} else if di.is_local() {
// Register local dial info
routing_table.register_dial_info(di.clone(), DialInfoOrigin::Static, None);
} }
// Register interface dial info as well since the address is on the local interface
routing_table.register_interface_dial_info(di.clone(), DialInfoOrigin::Static);
} }
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
@ -315,7 +316,7 @@ impl Network {
// Add all resolved addresses as public dialinfo // Add all resolved addresses as public dialinfo
for pdi_addr in &mut public_sockaddrs { for pdi_addr in &mut public_sockaddrs {
routing_table.register_dial_info( routing_table.register_public_dial_info(
DialInfo::udp_from_socketaddr(pdi_addr), DialInfo::udp_from_socketaddr(pdi_addr),
DialInfoOrigin::Static, DialInfoOrigin::Static,
Some(NetworkClass::Server), Some(NetworkClass::Server),
@ -375,22 +376,21 @@ impl Network {
let di = DialInfo::try_ws(socket_address, global_url) let di = DialInfo::try_ws(socket_address, global_url)
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error))?;
routing_table.register_dial_info( routing_table.register_public_dial_info(
di, di,
DialInfoOrigin::Static, DialInfoOrigin::Static,
Some(NetworkClass::Server), Some(NetworkClass::Server),
); );
static_public = true; static_public = true;
} else if socket_address.address().is_local() {
// Build local dial info request url
let local_url = format!("ws://{}/{}", socket_address, path);
// Create local dial info
let di = DialInfo::try_ws(socket_address, local_url)
.map_err(map_to_string)
.map_err(logthru_net!(error))?;
routing_table.register_dial_info(di, DialInfoOrigin::Static, None);
} }
// Build interface dial info request url
let interface_url = format!("ws://{}/{}", socket_address, path);
// Create interface dial info
let di = DialInfo::try_ws(socket_address, interface_url)
.map_err(map_to_string)
.map_err(logthru_net!(error))?;
routing_table.register_interface_dial_info(di, DialInfoOrigin::Static);
} }
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
@ -410,7 +410,7 @@ impl Network {
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error))?;
for gsa in global_socket_addrs { for gsa in global_socket_addrs {
routing_table.register_dial_info( routing_table.register_public_dial_info(
DialInfo::try_ws(SocketAddress::from_socket_addr(gsa), url.clone()) DialInfo::try_ws(SocketAddress::from_socket_addr(gsa), url.clone())
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?, .map_err(logthru_net!(error))?,
@ -460,7 +460,7 @@ impl Network {
.await?; .await?;
trace!("WSS: listener started"); trace!("WSS: listener started");
// NOTE: No local dial info for WSS, as there is no way to connect to a local dialinfo via TLS // NOTE: No interface dial info for WSS, as there is no way to connect to a local dialinfo via TLS
// If the hostname is specified, it is the public dialinfo via the URL. If no hostname // If the hostname is specified, it is the public dialinfo via the URL. If no hostname
// is specified, then TLS won't validate, so no local dialinfo is possible. // is specified, then TLS won't validate, so no local dialinfo is possible.
// 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
@ -483,7 +483,7 @@ impl Network {
.map_err(logthru_net!(error))?; .map_err(logthru_net!(error))?;
for gsa in global_socket_addrs { for gsa in global_socket_addrs {
routing_table.register_dial_info( routing_table.register_public_dial_info(
DialInfo::try_wss(SocketAddress::from_socket_addr(gsa), url.clone()) DialInfo::try_wss(SocketAddress::from_socket_addr(gsa), url.clone())
.map_err(map_to_string) .map_err(map_to_string)
.map_err(logthru_net!(error))?, .map_err(logthru_net!(error))?,
@ -537,19 +537,17 @@ impl Network {
for socket_address in socket_addresses { for socket_address in socket_addresses {
let di = DialInfo::tcp(socket_address); let di = DialInfo::tcp(socket_address);
// Register local dial info only here if we specify a public address // Register global dial info if no public address is specified
if public_address.is_none() && di.is_global() { if public_address.is_none() && di.is_global() {
// Register global dial info if no public address is specified routing_table.register_public_dial_info(
routing_table.register_dial_info(
di.clone(), di.clone(),
DialInfoOrigin::Static, DialInfoOrigin::Static,
Some(NetworkClass::Server), Some(NetworkClass::Server),
); );
static_public = true; static_public = true;
} else if di.is_local() {
// Register local dial info
routing_table.register_dial_info(di.clone(), DialInfoOrigin::Static, None);
} }
// Register interface dial info
routing_table.register_interface_dial_info(di.clone(), DialInfoOrigin::Static);
} }
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
@ -562,7 +560,7 @@ impl Network {
// Add all resolved addresses as public dialinfo // Add all resolved addresses as public dialinfo
for pdi_addr in &mut public_sockaddrs { for pdi_addr in &mut public_sockaddrs {
routing_table.register_dial_info( routing_table.register_public_dial_info(
DialInfo::tcp_from_socketaddr(pdi_addr), DialInfo::tcp_from_socketaddr(pdi_addr),
DialInfoOrigin::Static, DialInfoOrigin::Static,
None, None,

View File

@ -75,7 +75,7 @@ impl Network {
res res
} }
async fn send_data_to_existing_connection( pub async fn send_data_to_existing_connection(
&self, &self,
descriptor: ConnectionDescriptor, descriptor: ConnectionDescriptor,
data: Vec<u8>, data: Vec<u8>,
@ -137,31 +137,6 @@ impl Network {
res res
} }
pub async fn send_data(&self, node_ref: NodeRef, data: Vec<u8>) -> Result<(), String> {
// First try to send data to the last socket we've seen this peer on
let data = if let Some(descriptor) = node_ref.last_connection() {
match self
.clone()
.send_data_to_existing_connection(descriptor, data)
.await?
{
None => {
return Ok(());
}
Some(d) => d,
}
} else {
data
};
// If that fails, try to make a connection or reach out to the peer via its dial info
let dial_info = node_ref
.best_dial_info()
.ok_or_else(|| "couldn't send data, no dial info or peer address".to_owned())?;
self.send_data_to_dial_info(dial_info, data).await
}
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
pub async fn startup(&self) -> Result<(), String> { pub async fn startup(&self) -> Result<(), String> {

View File

@ -17,32 +17,8 @@ pub const IPADDR_MAX_INACTIVE_DURATION_US: u64 = 300_000_000u64; // 5 minutes
#[derive(Copy, Clone, Debug, Default)] #[derive(Copy, Clone, Debug, Default)]
pub struct ProtocolConfig { pub struct ProtocolConfig {
pub udp_enabled: bool, pub outbound: ProtocolSet,
pub tcp_connect: bool, pub inbound: ProtocolSet,
pub tcp_listen: bool,
pub ws_connect: bool,
pub ws_listen: bool,
pub wss_connect: bool,
pub wss_listen: bool,
}
impl ProtocolConfig {
pub fn is_protocol_type_connect_enabled(&self, protocol_type: ProtocolType) -> bool {
match protocol_type {
ProtocolType::UDP => self.udp_enabled,
ProtocolType::TCP => self.tcp_connect,
ProtocolType::WS => self.ws_connect,
ProtocolType::WSS => self.wss_connect,
}
}
pub fn is_protocol_type_listen_enabled(&self, protocol_type: ProtocolType) -> bool {
match protocol_type {
ProtocolType::UDP => self.udp_enabled,
ProtocolType::TCP => self.tcp_listen,
ProtocolType::WS => self.ws_listen,
ProtocolType::WSS => self.wss_listen,
}
}
} }
// Things we get when we start up and go away when we shut down // Things we get when we start up and go away when we shut down
@ -91,6 +67,15 @@ impl Default for NetworkManagerStats {
struct ClientWhitelistEntry { struct ClientWhitelistEntry {
last_seen: u64, last_seen: u64,
} }
// Mechanism required to contact another node
enum InboundMethod {
Direct, // Contact the node directly
SignalReverse, // Request via signal the node connect back directly
SignalHolePunch, // Request via signal the node negotiate a hole punch
Relay, // Must use a third party relay to reach the node
}
// The mutable state of the network manager // The mutable state of the network manager
struct NetworkManagerInner { struct NetworkManagerInner {
routing_table: Option<RoutingTable>, routing_table: Option<RoutingTable>,
@ -476,12 +461,20 @@ impl NetworkManager {
} }
// Called by the RPC handler when we want to issue an RPC request or response // Called by the RPC handler when we want to issue an RPC request or response
// node_ref is the direct destination to which the envelope will be sent
// If 'node_id' is specified, it can be different than node_ref.node_id()
// which will cause the envelope to be relayed
pub async fn send_envelope<B: AsRef<[u8]>>( pub async fn send_envelope<B: AsRef<[u8]>>(
&self, &self,
node_ref: NodeRef, node_ref: NodeRef,
node_id: Option<DHTKey>,
body: B, body: B,
) -> Result<(), String> { ) -> Result<(), String> {
log_net!("sending envelope to {:?}", node_ref); if let Some(node_id) = node_id {
log_net!("sending envelope to {:?} via {:?}", node_id, node_ref);
} else {
log_net!("sending envelope to {:?}", node_ref);
}
// Get node's min/max version and see if we can send to it // Get node's min/max version and see if we can send to it
// and if so, get the max version we can use // and if so, get the max version we can use
let version = if let Some((node_min, node_max)) = node_ref.operate(|e| e.min_max_version()) let version = if let Some((node_min, node_max)) = node_ref.operate(|e| e.min_max_version())
@ -503,11 +496,11 @@ impl NetworkManager {
// Build the envelope to send // Build the envelope to send
let out = self let out = self
.build_envelope(node_ref.node_id(), version, body) .build_envelope(node_id.unwrap_or_else(|| node_ref.node_id()), version, body)
.map_err(logthru_rpc!(error))?; .map_err(logthru_rpc!(error))?;
// Send via relay if we have to // Send the envelope via whatever means necessary
self.net().send_data(node_ref, out).await self.send_data(node_ref, out).await
} }
// Called by the RPC handler when we want to issue an direct receipt // Called by the RPC handler when we want to issue an direct receipt
@ -533,6 +526,203 @@ impl NetworkManager {
} }
} }
// Figure out how to reach a node
// Node info here must be the filtered kind, with only
fn get_inbound_method(&self, node_info: &NodeInfo) -> Result<InboundMethod, String> {
// Get our network class
let network_class = self.get_network_class().unwrap_or(NetworkClass::Invalid);
// If we don't have a network class yet (no public dial info or haven't finished detection)
// then we just need to try to send to the best direct dial info because we won't
// know how to use relays effectively yet
if matches!(network_class, NetworkClass::Invalid) {
return Ok(InboundMethod::Direct);
}
// Get the protocol of the best matching direct dial info
let protocol_type = node_info.dial_info_list.first().map(|d| d.protocol_type());
// Can the target node do inbound?
if node_info.network_class.inbound_capable() {
// Do we need to signal before going inbound?
if node_info.network_class.inbound_requires_signal() {
// Can we receive a direct reverse connection?
if network_class.inbound_capable() && !network_class.inbound_requires_signal() {
Ok(InboundMethod::SignalReverse)
}
// Is this a hole-punch capable protocol?
else if protocol_type == Some(ProtocolType::UDP) {
Ok(InboundMethod::SignalHolePunch)
}
// Otherwise we have to relay
else {
Ok(InboundMethod::Relay)
}
}
// Can go direct
else {
Ok(InboundMethod::Direct)
}
// If the other node is not inbound capable at all, it requires a relay
} else {
Ok(InboundMethod::Relay)
}
}
// Send a reverse connection signal and wait for the return receipt over it
// Then send the data across the new connection
pub async fn do_reverse_connect(
&self,
best_node_info: &NodeInfo,
data: Vec<u8>,
) -> Result<(), String> {
// Get relay to signal from
let relay_nr = if let Some(rpi) = best_node_info.relay_peer_info {
// Get the noderef for this inbound relay
self.routing_table().register_node_with_node_info(rpi.node_id.key, rpi.node_info)?;
} else {
// If we don't have a relay dial info that matches our protocol configuration
// then we can't send to this node!
return Err("Can't send to this relay".to_owned())
}
// Get the receipt timeout
let receipt_time = ms_to_us(self.config.get().network.reverse_connection_receipt_time_ms);
// Build a return receipt for the signal
let (rcpt_data, eventual_value) = self
.generate_single_shot_receipt(receipt_time, [])
.map_err(map_error_string!())?;
// Issue the signal
let rpc = self.rpc_processor();
rpc.rpc_call_signal(dest, )
// Wait for the return receipt
match eventual_value.await {
ReceiptEvent::Returned => (),
ReceiptEvent::Expired => {
return Err("receipt was dropped before expiration".to_owned());
}
ReceiptEvent::Cancelled => {
return Err("receipt was dropped before expiration".to_owned());
}
};
// And now use the existing connection to send over
if let Some(descriptor) = node_ref.last_connection() {
match self
.net()
.send_data_to_existing_connection(descriptor, data)
.await
.map_err(logthru_net!())?
{
None => {
return Ok(());
}
Some(d) => d,
}
}
Ok(())
}
// Send a hole punch signal and do a negotiating ping and wait for the return receipt
// Then send the data across the new connection
pub async fn do_hole_punch(&self, best_node_info: &NodeInfo, data: Vec<u8>) -> Result<(), String> {
if let Some(relay_dial_info) = node_info.relay_dial_info_list.first() {
self.net()
.do_hole_punch(relay_dial_info.clone(), data)
.await
.map_err(logthru_net!())
} else {
// If we don't have a relay dial info that matches our protocol configuration
// then we can't send to this node!
Err("Can't send to this node yet".to_owned())
}
}
// Send raw data to a node
//
// We may not have dial info for a node, but have an existing connection for it
// because an inbound connection happened first, and no FindNodeQ has happened to that
// node yet to discover its dial info. The existing connection should be tried first
// in this case.
//
// Sending to a node requires determining a NetworkClass compatible mechanism
//
pub fn send_data(&self, node_ref: NodeRef, data: Vec<u8>) -> SystemPinBoxFuture<Result<(), String>> {
let this = self.clone();
Box::pin(async move {
// First try to send data to the last socket we've seen this peer on
let data = if let Some(descriptor) = node_ref.last_connection() {
match this
.net()
.send_data_to_existing_connection(descriptor, data)
.await
.map_err(logthru_net!())?
{
None => {
return Ok(());
}
Some(d) => d,
}
} else {
data
};
// If we don't have last_connection, try to reach out to the peer via its dial info
let best_node_info = match node_ref
.best_node_info() {
Some(ni) => ni,
None => {
// If neither this node nor its relays would never ever be
// reachable by any of our protocols
// then we need to go through the outbound relay
if let Some(relay_node) = this.relay_node() {
// We have an outbound relay, lets use it
return this.send_data(relay_node, data).await;
}
else {
// We have no way to reach the node nor an outbound relay to use
return Err("Can't reach this node".to_owned());
}
}
};
// If we aren't using an outbound relay to reach this node, what inbound method do we use?
match this.get_inbound_method(&best_node_info)? {
InboundMethod::Direct => {
if let Some(dial_info) = best_node_info.dial_info_list.first() {
this.net()
.send_data_to_dial_info(dial_info.clone(), data)
.await
.map_err(logthru_net!())
} else {
// If we don't have a direct dial info that matches our protocol configuration
// then we can't send to this node!
Err("Can't send to this node yet".to_owned())
}
}
InboundMethod::SignalReverse => this.do_reverse_connect(&best_node_info, data).await,
InboundMethod::SignalHolePunch => this.do_hole_punch(&best_node_info, data).await,
InboundMethod::Relay => {
if let Some(rpi) = best_node_info.relay_peer_info {
// Get the noderef for this inbound relay
let inbound_relay_noderef = this.routing_table().register_node_with_node_info(rpi.node_id.key, rpi.node_info)?;
// Send to the inbound relay
this.send_data(inbound_relay_noderef, data).await
} else {
// If we don't have a relay dial info that matches our protocol configuration
// then we can't send to this node!
Err("Can't send to this relay".to_owned())
}
}
}
})
}
// Called when a packet potentially containing an RPC envelope is received by a low-level // Called when a packet potentially containing an RPC envelope is received by a low-level
// network protocol handler. Processes the envelope, authenticates and decrypts the RPC message // network protocol handler. Processes the envelope, authenticates and decrypts the RPC message
// and passes it to the RPC handler // and passes it to the RPC handler
@ -608,14 +798,7 @@ impl NetworkManager {
// nodes are allowed to do this, for example PWA users // nodes are allowed to do this, for example PWA users
let relay_nr = if self.check_client_whitelist(sender_id) { let relay_nr = if self.check_client_whitelist(sender_id) {
// Cache the envelope information in the routing table // Full relay allowed, do a full resolve_node
// let source_noderef = routing_table
// .register_node_with_existing_connection(envelope.get_sender_id(), descriptor, ts)
// .map_err(|e| format!("node id registration failed: {}", e))?;
// source_noderef.operate(|e| e.set_min_max_version(envelope.get_min_max_version()));
// If the sender is in the client whitelist, allow a full resolve_node,
// which effectively lets the client use our routing table
rpc.resolve_node(recipient_id).await.map_err(|e| { rpc.resolve_node(recipient_id).await.map_err(|e| {
format!( format!(
"failed to resolve recipient node for relay, dropping outbound relayed packet...: {:?}", "failed to resolve recipient node for relay, dropping outbound relayed packet...: {:?}",
@ -630,27 +813,16 @@ impl NetworkManager {
// We should, because relays are chosen by nodes that have established connectivity and // We should, because relays are chosen by nodes that have established connectivity and
// should be mutually in each others routing tables. The node needing the relay will be // should be mutually in each others routing tables. The node needing the relay will be
// pinging this node regularly to keep itself in the routing table // pinging this node regularly to keep itself in the routing table
if let Some(nr) = routing_table.lookup_node_ref(recipient_id) { routing_table.lookup_node_ref(recipient_id).ok_or_else(|| {
// ensure we have dial_info for the entry already, format!(
if !nr.operate(|e| e.dial_infos().is_empty()) {
nr
} else {
return Err(format!(
"Inbound relay asked for recipient with no dial info: {}",
recipient_id
));
}
} else {
return Err(format!(
"Inbound relay asked for recipient not in routing table: {}", "Inbound relay asked for recipient not in routing table: {}",
recipient_id recipient_id
)); )
} })?
}; };
// Re-send the packet to the leased node // Relay the packet to the desired destination
self.net() self.send_data(relay_nr, data.to_vec())
.send_data(relay_nr, data.to_vec())
.await .await
.map_err(|e| format!("failed to forward envelope: {}", e))?; .map_err(|e| format!("failed to forward envelope: {}", e))?;
// Inform caller that we dealt with the envelope, but did not process it locally // Inform caller that we dealt with the envelope, but did not process it locally
@ -683,7 +855,7 @@ impl NetworkManager {
} }
// Keep relays assigned and accessible // Keep relays assigned and accessible
async fn relay_management_task_routine(self, last_ts: u64, cur_ts: u64) -> Result<(), String> { async fn relay_management_task_routine(self, _last_ts: u64, cur_ts: u64) -> Result<(), String> {
log_net!("--- network manager relay_management task"); log_net!("--- network manager relay_management task");
// Get our node's current network class and do the right thing // Get our node's current network class and do the right thing
@ -712,9 +884,9 @@ impl NetworkManager {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
// Register new outbound relay // Register new outbound relay
let nr = routing_table.register_node_with_dial_info( let nr = routing_table.register_node_with_node_info(
outbound_relay_peerinfo.node_id.key, outbound_relay_peerinfo.node_id.key,
&outbound_relay_peerinfo.dial_infos, outbound_relay_peerinfo.node_info,
)?; )?;
inner.relay_node = Some(nr); inner.relay_node = Some(nr);
} }

View File

@ -35,9 +35,10 @@ pub enum BucketEntryState {
pub struct BucketEntry { pub struct BucketEntry {
pub(super) ref_count: u32, pub(super) ref_count: u32,
min_max_version: Option<(u8, u8)>, min_max_version: Option<(u8, u8)>,
seen_our_dial_info: bool, seen_our_node_info: bool,
last_connection: Option<(ConnectionDescriptor, u64)>, last_connection: Option<(ConnectionDescriptor, u64)>,
node_info: NodeInfo, node_info: NodeInfo,
local_node_info: LocalNodeInfo,
peer_stats: PeerStats, peer_stats: PeerStats,
latency_stats_accounting: LatencyStatsAccounting, latency_stats_accounting: LatencyStatsAccounting,
transfer_stats_accounting: TransferStatsAccounting, transfer_stats_accounting: TransferStatsAccounting,
@ -49,9 +50,10 @@ impl BucketEntry {
Self { Self {
ref_count: 0, ref_count: 0,
min_max_version: None, min_max_version: None,
seen_our_dial_info: false, seen_our_node_info: false,
last_connection: None, last_connection: None,
node_info: NodeInfo::default(), node_info: NodeInfo::default(),
local_node_info: LocalNodeInfo::default(),
latency_stats_accounting: LatencyStatsAccounting::new(), latency_stats_accounting: LatencyStatsAccounting::new(),
transfer_stats_accounting: TransferStatsAccounting::new(), transfer_stats_accounting: TransferStatsAccounting::new(),
peer_stats: PeerStats { peer_stats: PeerStats {
@ -108,34 +110,20 @@ impl BucketEntry {
pub fn update_node_info(&mut self, node_info: NodeInfo) { pub fn update_node_info(&mut self, node_info: NodeInfo) {
self.node_info = node_info self.node_info = node_info
} }
pub fn update_local_node_info(&mut self, local_node_info: LocalNodeInfo) {
self.local_node_info = local_node_info
}
pub fn node_info(&self) -> &NodeInfo { pub fn node_info(&self) -> &NodeInfo {
&self.node_info &self.node_info
} }
pub fn local_node_info(&self) -> &LocalNodeInfo {
pub fn first_filtered_node_info<F>(&self, filter: F) -> Option<NodeInfo> &self.local_node_info
where
F: Fn(&DialInfo) -> bool,
{
let out = self.node_info.first_filtered(filter);
if out.dial_infos.is_empty() && out.relay_dial_infos.is_empty() {
None
} else {
Some(out)
}
} }
pub fn peer_info(&self, key: DHTKey) -> PeerInfo {
pub fn all_filtered_node_info<F>(&self, filter: F) -> NodeInfo
where
F: Fn(&DialInfo) -> bool,
{
self.node_info.all_filtered(filter)
}
pub fn get_peer_info(&self, key: DHTKey, scope: PeerScope) -> PeerInfo {
PeerInfo { PeerInfo {
node_id: NodeId::new(key), node_id: NodeId::new(key),
node_info: self.all_filtered_node_info(|di| di.matches_peer_scope(scope)), node_info: self.node_info.clone(),
} }
} }
@ -173,12 +161,12 @@ impl BucketEntry {
self.peer_stats.status = Some(status); self.peer_stats.status = Some(status);
} }
pub fn set_seen_our_dial_info(&mut self, seen: bool) { pub fn set_seen_our_node_info(&mut self, seen: bool) {
self.seen_our_dial_info = seen; self.seen_our_node_info = seen;
} }
pub fn has_seen_our_dial_info(&self) -> bool { pub fn has_seen_our_node_info(&self) -> bool {
self.seen_our_dial_info self.seen_our_node_info
} }
///// stats methods ///// stats methods

View File

@ -23,15 +23,15 @@ impl RoutingTable {
out out
} }
pub fn debug_info_dialinfo(&self) -> String { pub fn debug_info_dialinfo(&self) -> String {
let ldis = self.local_dial_info_details(); let ldis = self.interface_dial_info_details();
let gdis = self.global_dial_info_details(); let gdis = self.public_dial_info_details();
let mut out = String::new(); let mut out = String::new();
out += "Local Dial Info Details:\n"; out += "Interface Dial Info Details:\n";
for (n, ldi) in ldis.iter().enumerate() { for (n, ldi) in ldis.iter().enumerate() {
out += &format!(" {:>2}: {:?}\n", n, ldi); out += &format!(" {:>2}: {:?}\n", n, ldi);
} }
out += "Global Dial Info Details:\n"; out += "Public Dial Info Details:\n";
for (n, gdi) in gdis.iter().enumerate() { for (n, gdi) in gdis.iter().enumerate() {
out += &format!(" {:>2}: {:?}\n", n, gdi); out += &format!(" {:>2}: {:?}\n", n, gdi);
} }

View File

@ -12,7 +12,6 @@ impl RoutingTable {
// Returns noderefs are are scoped to that address type only // Returns noderefs are are scoped to that address type only
pub fn find_fast_nodes_filtered(&self, dial_info_filter: &DialInfoFilter) -> Vec<NodeRef> { pub fn find_fast_nodes_filtered(&self, dial_info_filter: &DialInfoFilter) -> Vec<NodeRef> {
let dial_info_filter1 = dial_info_filter.clone(); let dial_info_filter1 = dial_info_filter.clone();
let dial_info_filter2 = dial_info_filter.clone();
self.find_fastest_nodes( self.find_fastest_nodes(
// filter // filter
Some(Box::new( Some(Box::new(
@ -21,50 +20,53 @@ impl RoutingTable {
.1 .1
.as_ref() .as_ref()
.unwrap() .unwrap()
.first_filtered_node_info(|di| di.matches_filter(&dial_info_filter1)) .node_info()
.first_filtered_dial_info(|di| di.matches_filter(&dial_info_filter1))
.is_some() .is_some()
}, },
)), )),
// transform // transform
|e| { |e| NodeRef::new(self.clone(), *e.0, e.1.as_mut().unwrap()),
NodeRef::new_filtered(
self.clone(),
*e.0,
e.1.as_mut().unwrap(),
dial_info_filter2.clone(),
)
},
) )
} }
pub fn get_own_peer_info(&self, scope: PeerScope) -> PeerInfo { pub fn get_own_peer_info(&self) -> PeerInfo {
let filter = DialInfoFilter::scoped(scope);
let netman = self.network_manager(); let netman = self.network_manager();
let enable_local_peer_scope = netman.config().get().network.enable_local_peer_scope;
let relay_node = netman.relay_node(); let relay_node = netman.relay_node();
PeerInfo { PeerInfo {
node_id: NodeId::new(self.node_id()), node_id: NodeId::new(self.node_id()),
node_info: NodeInfo { node_info: NodeInfo {
network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid), network_class: netman.get_network_class().unwrap_or(NetworkClass::Invalid),
dial_infos: self outbound_protocols: netman.get_protocol_config().unwrap_or_default().outbound,
.all_filtered_dial_info_details(&filter) dial_info_list: if !enable_local_peer_scope {
.iter() self.public_dial_info_details()
.map(|did| did.dial_info.clone()) .iter()
.collect(), .map(|did| did.dial_info.clone())
relay_dial_infos: relay_node .collect()
.map(|rn| rn.node_info().dial_infos) } else {
.unwrap_or_default(), self.public_dial_info_details()
.iter()
.map(|did| did.dial_info.clone())
.chain(
self.interface_dial_info_details()
.iter()
.map(|did| did.dial_info.clone()),
)
.collect()
},
relay_peer_info: relay_node.map(|rn| Box::new(rn.peer_info())),
}, },
} }
} }
pub fn transform_to_peer_info( pub fn transform_to_peer_info(
kv: &mut (&DHTKey, Option<&mut BucketEntry>), kv: &mut (&DHTKey, Option<&mut BucketEntry>),
scope: PeerScope,
own_peer_info: &PeerInfo, own_peer_info: &PeerInfo,
) -> PeerInfo { ) -> PeerInfo {
match &kv.1 { match &kv.1 {
None => own_peer_info.clone(), None => own_peer_info.clone(),
Some(entry) => entry.get_peer_info(*kv.0, scope), Some(entry) => entry.peer_info(*kv.0),
} }
} }

View File

@ -48,7 +48,8 @@ struct RoutingTableInner {
node_id: DHTKey, node_id: DHTKey,
node_id_secret: DHTKeySecret, node_id_secret: DHTKeySecret,
buckets: Vec<Bucket>, buckets: Vec<Bucket>,
dial_info_details: Vec<DialInfoDetail>, public_dial_info_details: Vec<DialInfoDetail>,
interface_dial_info_details: Vec<DialInfoDetail>,
bucket_entry_count: usize, bucket_entry_count: usize,
// Waiters // Waiters
@ -89,7 +90,8 @@ impl RoutingTable {
node_id: DHTKey::default(), node_id: DHTKey::default(),
node_id_secret: DHTKeySecret::default(), node_id_secret: DHTKeySecret::default(),
buckets: Vec::new(), buckets: Vec::new(),
dial_info_details: Vec::new(), public_dial_info_details: Vec::new(),
interface_dial_info_details: Vec::new(),
bucket_entry_count: 0, bucket_entry_count: 0,
eventual_changed_dial_info: Eventual::new(), eventual_changed_dial_info: Eventual::new(),
self_latency_stats_accounting: LatencyStatsAccounting::new(), self_latency_stats_accounting: LatencyStatsAccounting::new(),
@ -163,40 +165,42 @@ impl RoutingTable {
self.inner.lock().node_id_secret self.inner.lock().node_id_secret
} }
pub fn has_local_dial_info(&self) -> bool { pub fn has_interface_dial_info(&self) -> bool {
self.first_filtered_dial_info_detail(&DialInfoFilter::local()) !self.inner.lock().interface_dial_info_details.is_empty()
.is_some()
} }
pub fn has_global_dial_info(&self) -> bool { pub fn has_public_dial_info(&self) -> bool {
self.first_filtered_dial_info_detail(&DialInfoFilter::global()) !self.inner.lock().public_dial_info_details.is_empty()
.is_some()
} }
pub fn global_dial_info_details(&self) -> Vec<DialInfoDetail> { pub fn public_dial_info_details(&self) -> Vec<DialInfoDetail> {
self.all_filtered_dial_info_details(&DialInfoFilter::global()) self.inner.lock().public_dial_info_details.clone()
} }
pub fn local_dial_info_details(&self) -> Vec<DialInfoDetail> { pub fn interface_dial_info_details(&self) -> Vec<DialInfoDetail> {
self.all_filtered_dial_info_details(&DialInfoFilter::local()) self.inner.lock().interface_dial_info_details.clone()
} }
pub fn first_filtered_dial_info_detail( pub fn first_public_filtered_dial_info_detail(
&self, &self,
filter: &DialInfoFilter, filter: &DialInfoFilter,
) -> Option<DialInfoDetail> { ) -> Option<DialInfoDetail> {
let inner = self.inner.lock(); let inner = self.inner.lock();
for did in &inner.dial_info_details { for did in &inner.public_dial_info_details {
if did.matches_filter(filter) { if did.matches_filter(filter) {
return Some(did.clone()); return Some(did.clone());
} }
} }
None None
} }
pub fn all_filtered_dial_info_details(&self, filter: &DialInfoFilter) -> Vec<DialInfoDetail> {
pub fn all_public_filtered_dial_info_details(
&self,
filter: &DialInfoFilter,
) -> Vec<DialInfoDetail> {
let inner = self.inner.lock(); let inner = self.inner.lock();
let mut ret = Vec::new(); let mut ret = Vec::new();
for did in &inner.dial_info_details { for did in &inner.public_dial_info_details {
if did.matches_filter(filter) { if did.matches_filter(filter) {
ret.push(did.clone()); ret.push(did.clone());
} }
@ -204,16 +208,48 @@ impl RoutingTable {
ret ret
} }
pub fn register_dial_info( pub fn first_interface_filtered_dial_info_detail(
&self,
filter: &DialInfoFilter,
) -> Option<DialInfoDetail> {
let inner = self.inner.lock();
for did in &inner.interface_dial_info_details {
if did.matches_filter(filter) {
return Some(did.clone());
}
}
None
}
pub fn all_interface_filtered_dial_info_details(
&self,
filter: &DialInfoFilter,
) -> Vec<DialInfoDetail> {
let inner = self.inner.lock();
let mut ret = Vec::new();
for did in &inner.interface_dial_info_details {
if did.matches_filter(filter) {
ret.push(did.clone());
}
}
ret
}
pub fn register_public_dial_info(
&self, &self,
dial_info: DialInfo, dial_info: DialInfo,
origin: DialInfoOrigin, origin: DialInfoOrigin,
network_class: Option<NetworkClass>, network_class: Option<NetworkClass>,
) { ) {
let timestamp = get_timestamp(); let timestamp = get_timestamp();
let enable_local_peer_scope = {
let c = self.network_manager().config().get();
c.network.enable_local_peer_scope
};
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.dial_info_details.push(DialInfoDetail { inner.public_dial_info_details.push(DialInfoDetail {
dial_info: dial_info.clone(), dial_info: dial_info.clone(),
origin, origin,
network_class, network_class,
@ -222,18 +258,11 @@ impl RoutingTable {
// Re-sort dial info to endure preference ordering // Re-sort dial info to endure preference ordering
inner inner
.dial_info_details .public_dial_info_details
.sort_by(|a, b| a.dial_info.cmp(&b.dial_info)); .sort_by(|a, b| a.dial_info.cmp(&b.dial_info));
info!( info!(
"{}Dial Info: {}", "Public Dial Info: {}",
if dial_info.is_local() {
"Local "
} else if dial_info.is_global() {
"Global "
} else {
"Other "
},
NodeDialInfo { NodeDialInfo {
node_id: NodeId::new(inner.node_id), node_id: NodeId::new(inner.node_id),
dial_info dial_info
@ -246,9 +275,44 @@ impl RoutingTable {
Self::trigger_changed_dial_info(&mut *inner); Self::trigger_changed_dial_info(&mut *inner);
} }
pub fn register_interface_dial_info(&self, dial_info: DialInfo, origin: DialInfoOrigin) {
let timestamp = get_timestamp();
let enable_local_peer_scope = {
let c = self.network_manager().config().get();
c.network.enable_local_peer_scope
};
let mut inner = self.inner.lock();
inner.interface_dial_info_details.push(DialInfoDetail {
dial_info: dial_info.clone(),
origin,
network_class: None,
timestamp,
});
// Re-sort dial info to endure preference ordering
inner
.interface_dial_info_details
.sort_by(|a, b| a.dial_info.cmp(&b.dial_info));
info!(
"Interface Dial Info: {}",
NodeDialInfo {
node_id: NodeId::new(inner.node_id),
dial_info
}
.to_string(),
);
debug!(" Origin: {:?}", origin);
Self::trigger_changed_dial_info(&mut *inner);
}
pub fn clear_dial_info_details(&self) { pub fn clear_dial_info_details(&self) {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
inner.dial_info_details.clear(); inner.public_dial_info_details.clear();
inner.interface_dial_info_details.clear();
Self::trigger_changed_dial_info(&mut *inner); Self::trigger_changed_dial_info(&mut *inner);
} }
@ -262,10 +326,10 @@ impl RoutingTable {
} }
fn trigger_changed_dial_info(inner: &mut RoutingTableInner) { fn trigger_changed_dial_info(inner: &mut RoutingTableInner) {
// Clear 'seen dial info' bits on routing table entries so we know to ping them // Clear 'seen node info' bits on routing table entries so we know to ping them
for b in &mut inner.buckets { for b in &mut inner.buckets {
for e in b.entries_mut() { for e in b.entries_mut() {
e.1.set_seen_our_dial_info(false); e.1.set_seen_our_node_info(false);
} }
} }
// //
@ -608,9 +672,10 @@ impl RoutingTable {
.register_node_with_node_info( .register_node_with_node_info(
k, k,
NodeInfo { NodeInfo {
network_class: NetworkClass::Server, network_class: NetworkClass::Server, // Bootstraps are always full servers
dial_infos: v, outbound_protocols: ProtocolSet::default(), // Bootstraps do not participate in relaying and will not make outbound requests
relay_dial_infos: Default::default(), dial_info_list: v, // Dial info is as specified in the bootstrap list
relay_peer_info: None, // Bootstraps never require a relay themselves
}, },
) )
.map_err(logthru_rtab!("Couldn't add bootstrap node: {}", k))?; .map_err(logthru_rtab!("Couldn't add bootstrap node: {}", k))?;

View File

@ -5,7 +5,6 @@ use alloc::fmt;
pub struct NodeRef { pub struct NodeRef {
routing_table: RoutingTable, routing_table: RoutingTable,
node_id: DHTKey, node_id: DHTKey,
dial_info_filter: DialInfoFilter,
} }
impl NodeRef { impl NodeRef {
@ -14,20 +13,6 @@ impl NodeRef {
Self { Self {
routing_table, routing_table,
node_id: key, node_id: key,
dial_info_filter: DialInfoFilter::default(),
}
}
pub fn new_filtered(
routing_table: RoutingTable,
key: DHTKey,
entry: &mut BucketEntry,
dial_info_filter: DialInfoFilter,
) -> Self {
entry.ref_count += 1;
Self {
routing_table,
node_id: key,
dial_info_filter,
} }
} }
@ -35,10 +20,6 @@ impl NodeRef {
self.node_id self.node_id
} }
pub fn dial_info_filter(&self) -> &DialInfoFilter {
&self.dial_info_filter
}
pub fn operate<T, F>(&self, f: F) -> T pub fn operate<T, F>(&self, f: F) -> T
where where
F: FnOnce(&mut BucketEntry) -> T, F: FnOnce(&mut BucketEntry) -> T,
@ -46,52 +27,23 @@ impl NodeRef {
self.routing_table.operate_on_bucket_entry(self.node_id, f) self.routing_table.operate_on_bucket_entry(self.node_id, f)
} }
pub fn peer_info(&self) -> PeerInfo {
self.operate(|e| e.peer_info(self.node_id()))
}
pub fn node_info(&self) -> NodeInfo { pub fn node_info(&self) -> NodeInfo {
self.operate(|e| e.node_info().clone()) self.operate(|e| e.node_info().clone())
} }
pub fn local_node_info(&self) -> LocalNodeInfo {
pub fn has_dial_info(&self) -> bool { self.operate(|e| e.local_node_info().clone())
self.operate(|e| !e.node_info().dial_infos.is_empty())
} }
pub fn has_seen_our_node_info(&self) -> bool {
// Returns if this node has seen and acknowledged our node's dial info yet self.operate(|e| e.has_seen_our_node_info())
pub fn has_seen_our_dial_info(&self) -> bool {
self.operate(|e| e.has_seen_our_dial_info())
} }
pub fn set_seen_our_dial_info(&self) { pub fn set_seen_our_node_info(&self) {
self.operate(|e| e.set_seen_our_dial_info(true)); self.operate(|e| e.set_seen_our_node_info(true));
}
// Returns the best node info to attempt a connection to this node
pub fn best_node_info(&self) -> Option<NodeInfo> {
let nm = self.routing_table.network_manager();
let protocol_config = nm.get_protocol_config()?;
self.operate(|e| {
e.first_filtered_node_info(|di| {
// Does it match the dial info filter
if !di.matches_filter(&self.dial_info_filter) {
return false;
}
// Filter out dial infos that don't match our protocol config
// for outbound connections. This routine filters on 'connect' settings
// to ensure we connect using only the protocols we have enabled.
protocol_config.is_protocol_type_connect_enabled(di.protocol_type())
})
})
} }
pub fn last_connection(&self) -> Option<ConnectionDescriptor> { pub fn last_connection(&self) -> Option<ConnectionDescriptor> {
match self.operate(|e| e.last_connection()) { self.operate(|e| e.last_connection())
None => None,
Some(c) => {
if !c.matches_filter(&self.dial_info_filter) {
return None;
}
// We don't filter this out by protocol config because if a connection
// succeeded, it's allowed to persist and be used for communication
// regardless of any other configuration
Some(c)
}
}
} }
} }
@ -103,18 +55,13 @@ impl Clone for NodeRef {
Self { Self {
routing_table: self.routing_table.clone(), routing_table: self.routing_table.clone(),
node_id: self.node_id, node_id: self.node_id,
dial_info_filter: self.dial_info_filter.clone(),
} }
} }
} }
impl fmt::Debug for NodeRef { impl fmt::Debug for NodeRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = self.node_id.encode(); write!(f, "{}", self.node_id.encode())
if !self.dial_info_filter.is_empty() {
out += &format!("{:?}", self.dial_info_filter);
}
write!(f, "{}", out)
} }
} }

View File

@ -7,8 +7,10 @@ mod node_status;
mod nonce; mod nonce;
mod peer_info; mod peer_info;
mod private_safety_route; mod private_safety_route;
mod protocol_set;
mod public_key; mod public_key;
mod sender_info; mod sender_info;
mod signal_info;
mod socket_address; mod socket_address;
pub use address::*; pub use address::*;
@ -20,6 +22,8 @@ pub use node_status::*;
pub use nonce::*; pub use nonce::*;
pub use peer_info::*; pub use peer_info::*;
pub use private_safety_route::*; pub use private_safety_route::*;
pub use protocol_set::*;
pub use public_key::*; pub use public_key::*;
pub use sender_info::*; pub use sender_info::*;
pub use signal_info::*;
pub use socket_address::*; pub use socket_address::*;

View File

@ -7,38 +7,34 @@ pub fn encode_node_info(
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
builder.set_network_class(encode_network_class(node_info.network_class)); builder.set_network_class(encode_network_class(node_info.network_class));
let mut ps_builder = builder.reborrow().init_outbound_protocols();
encode_protocol_set(&node_info.outbound_protocols, &mut ps_builder)?;
let mut dil_builder = builder.reborrow().init_dial_info_list( let mut dil_builder = builder.reborrow().init_dial_info_list(
node_info node_info
.dial_infos .dial_info_list
.len() .len()
.try_into() .try_into()
.map_err(map_error_protocol!("too many dial infos in node info"))?, .map_err(map_error_protocol!("too many dial infos in node info"))?,
); );
for idx in 0..node_info.dial_infos.len() { for idx in 0..node_info.dial_info_list.len() {
let mut di_builder = dil_builder.reborrow().get(idx as u32); let mut di_builder = dil_builder.reborrow().get(idx as u32);
encode_dial_info(&node_info.dial_infos[idx], &mut di_builder)?; encode_dial_info(&node_info.dial_info_list[idx], &mut di_builder)?;
} }
let mut rdil_builder = builder.reborrow().init_relay_dial_info_list( if let Some(rpi) = node_info.relay_peer_info {
node_info let mut rpi_builder = builder.reborrow().init_relay_peer_info();
.relay_dial_infos encode_peer_info(&rpi, &mut rpi_builder)?;
.len()
.try_into()
.map_err(map_error_protocol!(
"too many relay dial infos in node info"
))?,
);
for idx in 0..node_info.relay_dial_infos.len() {
let mut rdi_builder = rdil_builder.reborrow().get(idx as u32);
encode_dial_info(&node_info.relay_dial_infos[idx], &mut rdi_builder)?;
} }
Ok(()) Ok(())
} }
pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result<NodeInfo, RPCError> { pub fn decode_node_info(
reader: &veilid_capnp::node_info::Reader,
allow_relay_peer_info: bool,
) -> Result<NodeInfo, RPCError> {
let network_class = decode_network_class( let network_class = decode_network_class(
reader reader
.reborrow() .reborrow()
@ -46,37 +42,47 @@ pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result<Node
.map_err(map_error_capnp_notinschema!())?, .map_err(map_error_capnp_notinschema!())?,
); );
let outbound_protocols = decode_protocol_set(
&reader
.reborrow()
.get_outbound_protocols()
.map_err(map_error_capnp_notinschema!())?,
)?;
let dil_reader = reader let dil_reader = reader
.reborrow() .reborrow()
.get_dial_info_list() .get_dial_info_list()
.map_err(map_error_capnp_error!())?; .map_err(map_error_capnp_error!())?;
let mut dial_infos = Vec::<DialInfo>::with_capacity( let mut dial_info_list = Vec::<DialInfo>::with_capacity(
dil_reader dil_reader
.len() .len()
.try_into() .try_into()
.map_err(map_error_protocol!("too many dial infos"))?, .map_err(map_error_protocol!("too many dial infos"))?,
); );
for di in dil_reader.iter() { for di in dil_reader.iter() {
dial_infos.push(decode_dial_info(&di)?) dial_info_list.push(decode_dial_info(&di)?)
} }
let rdil_reader = reader let relay_peer_info = if allow_relay_peer_info {
.reborrow() if reader.has_relay_peer_info() {
.get_relay_dial_info_list() Some(Box::new(decode_peer_info(
.map_err(map_error_capnp_error!())?; &reader
let mut relay_dial_infos = Vec::<DialInfo>::with_capacity( .reborrow()
rdil_reader .get_relay_peer_info()
.len() .map_err(map_error_capnp_notinschema!())?,
.try_into() false,
.map_err(map_error_protocol!("too many relay dial infos"))?, )?))
); } else {
for di in rdil_reader.iter() { None
relay_dial_infos.push(decode_dial_info(&di)?) }
} } else {
None
};
Ok(NodeInfo { Ok(NodeInfo {
network_class, network_class,
dial_infos, outbound_protocols,
relay_dial_infos, dial_info_list,
relay_peer_info,
}) })
} }

View File

@ -14,7 +14,10 @@ pub fn encode_peer_info(
Ok(()) Ok(())
} }
pub fn decode_peer_info(reader: &veilid_capnp::peer_info::Reader) -> Result<PeerInfo, RPCError> { pub fn decode_peer_info(
reader: &veilid_capnp::peer_info::Reader,
allow_relay_peer_info: bool,
) -> Result<PeerInfo, RPCError> {
let nid_reader = reader let nid_reader = reader
.reborrow() .reborrow()
.get_node_id() .get_node_id()
@ -23,7 +26,7 @@ pub fn decode_peer_info(reader: &veilid_capnp::peer_info::Reader) -> Result<Peer
.reborrow() .reborrow()
.get_node_info() .get_node_info()
.map_err(map_error_capnp_error!())?; .map_err(map_error_capnp_error!())?;
let node_info = decode_node_info(&ni_reader)?; let node_info = decode_node_info(&ni_reader, allow_relay_peer_info)?;
Ok(PeerInfo { Ok(PeerInfo {
node_id: NodeId::new(decode_public_key(&nid_reader)), node_id: NodeId::new(decode_public_key(&nid_reader)),

View File

@ -0,0 +1,25 @@
use crate::*;
use rpc_processor::*;
pub fn encode_protocol_set(
protocol_set: &ProtocolSet,
builder: &mut veilid_capnp::protocol_set::Builder,
) -> Result<(), RPCError> {
builder.set_udp(protocol_set.udp);
builder.set_tcp(protocol_set.tcp);
builder.set_ws(protocol_set.ws);
builder.set_wss(protocol_set.wss);
Ok(())
}
pub fn decode_protocol_set(
reader: &veilid_capnp::protocol_set::Reader,
) -> Result<ProtocolSet, RPCError> {
Ok(ProtocolSet {
udp: reader.reborrow().get_udp(),
tcp: reader.reborrow().get_tcp(),
ws: reader.reborrow().get_ws(),
wss: reader.reborrow().get_wss(),
})
}

View File

@ -0,0 +1,86 @@
use crate::*;
use rpc_processor::*;
pub fn encode_signal_info(
signal_info: &SignalInfo,
builder: &mut veilid_capnp::operation_signal::Builder,
) -> Result<(), RPCError> {
match signal_info {
SignalInfo::HolePunch { receipt, node_info } => {
let mut hp_builder = builder.init_hole_punch();
let rcpt_builder =
hp_builder
.reborrow()
.init_receipt(receipt.len().try_into().map_err(map_error_protocol!(
"invalid receipt length in hole punch signal info"
))?);
rcpt_builder.copy_from_slice(receipt.as_slice());
let mut ni_builder = hp_builder.init_node_info();
encode_node_info(&node_info, &mut ni_builder)?;
}
SignalInfo::ReverseConnect { receipt, node_info } => {
let mut hp_builder = builder.init_reverse_connect();
let rcpt_builder =
hp_builder
.reborrow()
.init_receipt(receipt.len().try_into().map_err(map_error_protocol!(
"invalid receipt length in reverse connect signal info"
))?);
rcpt_builder.copy_from_slice(receipt.as_slice());
let mut ni_builder = hp_builder.init_node_info();
encode_node_info(&node_info, &mut ni_builder)?;
}
}
Ok(())
}
pub fn decode_signal_info(
reader: &veilid_capnp::operation_signal::Reader,
) -> Result<SignalInfo, RPCError> {
Ok(
match reader
.which()
.map_err(map_error_internal!("invalid signal operation"))?
{
veilid_capnp::operation_signal::HolePunch(r) => {
// Extract hole punch reader
let r = match r {
Ok(r) => r,
Err(_) => return Err(rpc_error_internal("invalid hole punch")),
};
let receipt = r
.get_receipt()
.map_err(map_error_protocol!(
"invalid receipt in hole punch signal info"
))?
.to_vec();
let ni_reader = r.get_node_info().map_err(map_error_protocol!(
"invalid node info in hole punch signal info"
))?;
let node_info = decode_node_info(&ni_reader, true)?;
SignalInfo::HolePunch { receipt, node_info }
}
veilid_capnp::operation_signal::ReverseConnect(r) => {
// Extract reverse connect reader
let r = match r {
Ok(r) => r,
Err(_) => return Err(rpc_error_internal("invalid reverse connect")),
};
let receipt = r
.get_receipt()
.map_err(map_error_protocol!(
"invalid receipt in reverse connect signal info"
))?
.to_vec();
let ni_reader = r.get_node_info().map_err(map_error_protocol!(
"invalid node info in reverse connect signal info"
))?;
let node_info = decode_node_info(&ni_reader, true)?;
SignalInfo::ReverseConnect { receipt, node_info }
}
},
)
}

View File

@ -4,10 +4,12 @@ use super::*;
pub enum RPCError { pub enum RPCError {
Timeout, Timeout,
InvalidFormat, InvalidFormat,
Unreachable(DHTKey),
Unimplemented(String), Unimplemented(String),
Protocol(String), Protocol(String),
Internal(String), Internal(String),
} }
pub fn rpc_error_internal<T: AsRef<str>>(x: T) -> RPCError { pub fn rpc_error_internal<T: AsRef<str>>(x: T) -> RPCError {
error!("RPCError Internal: {}", x.as_ref()); error!("RPCError Internal: {}", x.as_ref());
RPCError::Internal(x.as_ref().to_owned()) RPCError::Internal(x.as_ref().to_owned())
@ -34,6 +36,7 @@ impl fmt::Display for RPCError {
match self { match self {
RPCError::Timeout => write!(f, "[RPCError: Timeout]"), RPCError::Timeout => write!(f, "[RPCError: Timeout]"),
RPCError::InvalidFormat => write!(f, "[RPCError: InvalidFormat]"), RPCError::InvalidFormat => write!(f, "[RPCError: InvalidFormat]"),
RPCError::Unreachable(k) => write!(f, "[RPCError: Unreachable({})]", k),
RPCError::Unimplemented(s) => write!(f, "[RPCError: Unimplemented({})]", s), RPCError::Unimplemented(s) => write!(f, "[RPCError: Unimplemented({})]", s),
RPCError::Protocol(s) => write!(f, "[RPCError: Protocol({})]", s), RPCError::Protocol(s) => write!(f, "[RPCError: Protocol({})]", s),
RPCError::Internal(s) => write!(f, "[RPCError: Internal({})]", s), RPCError::Internal(s) => write!(f, "[RPCError: Internal({})]", s),
@ -202,37 +205,55 @@ impl RPCProcessor {
} }
}; };
let dil_reader = match fnqr.reborrow().get_dial_info_list() { let sni_reader = match fnqr.reborrow().get_sender_node_info() {
Ok(dilr) => dilr, Ok(snir) => snir,
Err(e) => { Err(e) => {
return format!("(invalid dial info list: {})", e); return format!("(invalid sender node info: {})", e);
}
};
let sender_node_info = match decode_node_info(&sni_reader, true) {
Ok(v) => v,
Err(e) => {
return format!("(unable to decode node info: {})", e);
} }
}; };
let mut dial_infos =
Vec::<DialInfo>::with_capacity(match dil_reader.len().try_into() {
Ok(v) => v,
Err(e) => {
return format!("(too many dial infos: {})", e);
}
});
for di in dil_reader.iter() {
dial_infos.push(match decode_dial_info(&di) {
Ok(v) => v,
Err(e) => {
return format!("(unable to decode dial info: {})", e);
}
});
}
let node_id = decode_public_key(&nidr); let node_id = decode_public_key(&nidr);
format!( format!(
"FindNodeQ: node_id={} dial_infos={:?}", "FindNodeQ: node_id={} sender_node_info={:#?}",
node_id.encode(), node_id.encode(),
dial_infos sender_node_info
) )
} }
veilid_capnp::operation::detail::FindNodeA(_) => { veilid_capnp::operation::detail::FindNodeA(d) => {
format!("FindNodeA") let fnar = match d {
Ok(fnar) => fnar,
Err(e) => {
return format!("(invalid detail: {})", e);
}
};
let p_reader = match fnar.reborrow().get_peers() {
Ok(pr) => pr,
Err(e) => {
return format!("(invalid sender node info: {})", e);
}
};
let mut peers = Vec::<PeerInfo>::with_capacity(match p_reader.len().try_into() {
Ok(v) => v,
Err(e) => return format!("invalid peer count: {}", e),
});
for p in p_reader.iter() {
let peer_info = match decode_peer_info(&p, true) {
Ok(v) => v,
Err(e) => {
return format!("(unable to decode peer info: {})", e);
}
};
peers.push(peer_info);
}
format!("FindNodeA: peers={:#?}", peers)
} }
veilid_capnp::operation::detail::Route(_) => { veilid_capnp::operation::detail::Route(_) => {
format!("Route") format!("Route")
@ -270,11 +291,8 @@ impl RPCProcessor {
veilid_capnp::operation::detail::FindBlockA(_) => { veilid_capnp::operation::detail::FindBlockA(_) => {
format!("FindBlockA") format!("FindBlockA")
} }
veilid_capnp::operation::detail::SignalQ(_) => { veilid_capnp::operation::detail::Signal(_) => {
format!("SignalQ") format!("Signal")
}
veilid_capnp::operation::detail::SignalA(_) => {
format!("SignalA")
} }
veilid_capnp::operation::detail::ReturnReceipt(_) => { veilid_capnp::operation::detail::ReturnReceipt(_) => {
format!("ReturnReceipt") format!("ReturnReceipt")

View File

@ -23,8 +23,10 @@ type OperationId = u64;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Destination { pub enum Destination {
Direct(NodeRef), Direct(NodeRef), // Can only be sent directly
PrivateRoute(PrivateRoute), Normal(NodeRef), // Can be sent via relays as well as directly
Relay(NodeRef, DHTKey), // Can only be sent via a relay
PrivateRoute(PrivateRoute), // Must be encapsulated in a private route
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -131,7 +133,7 @@ struct WaitableReply {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct InfoAnswer { pub struct InfoAnswer {
pub latency: u64, pub latency: u64,
pub node_info: NodeInfo, pub node_status: NodeStatus,
pub sender_info: SenderInfo, pub sender_info: SenderInfo,
} }
@ -159,7 +161,7 @@ pub struct RPCProcessorInner {
pub struct RPCProcessor { pub struct RPCProcessor {
crypto: Crypto, crypto: Crypto,
config: VeilidConfig, config: VeilidConfig,
default_peer_scope: PeerScope, enable_local_peer_scope: bool,
inner: Arc<Mutex<RPCProcessorInner>>, inner: Arc<Mutex<RPCProcessorInner>>,
} }
@ -181,16 +183,11 @@ impl RPCProcessor {
Self { Self {
crypto: network_manager.crypto(), crypto: network_manager.crypto(),
config: network_manager.config(), config: network_manager.config(),
default_peer_scope: if !network_manager enable_local_peer_scope: network_manager
.config() .config()
.get() .get()
.network .network
.enable_local_peer_scope .enable_local_peer_scope,
{
PeerScope::Global
} else {
PeerScope::All
},
inner: Arc::new(Mutex::new(Self::new_inner(network_manager))), inner: Arc::new(Mutex::new(Self::new_inner(network_manager))),
} }
} }
@ -220,16 +217,18 @@ impl RPCProcessor {
fn filter_peer_scope(&self, peer_info: &PeerInfo) -> bool { fn filter_peer_scope(&self, peer_info: &PeerInfo) -> bool {
// reject attempts to include non-public addresses in results // reject attempts to include non-public addresses in results
if self.default_peer_scope == PeerScope::Global { if self.default_peer_scope == PeerScope::Global {
for di in &peer_info.node_info.dial_infos { for di in &peer_info.node_info.dial_info_list {
if !di.is_global() { if !di.is_global() {
// non-public address causes rejection // non-public address causes rejection
return false; return false;
} }
} }
for di in &peer_info.node_info.relay_dial_infos { if let Some(rpi) = peer_info.node_info.relay_peer_info {
if !di.is_global() { for di in &rpi.node_info.dial_info_list {
// non-public address causes rejection if !di.is_global() {
return false; // non-public address causes rejection
return false;
}
} }
} }
} }
@ -277,9 +276,9 @@ impl RPCProcessor {
// First see if we have the node in our routing table already // First see if we have the node in our routing table already
if let Some(nr) = routing_table.lookup_node_ref(node_id) { if let Some(nr) = routing_table.lookup_node_ref(node_id) {
// ensure we have dial_info for the entry already, // ensure we have some dial info for the entry already,
// if not, we should do the find_node anyway // if not, we should do the find_node anyway
if !nr.has_dial_info() { if !nr.has_any_dial_info() {
return Ok(nr); return Ok(nr);
} }
} }
@ -377,8 +376,8 @@ impl RPCProcessor {
} }
} }
Ok((rpcreader, _)) => { Ok((rpcreader, _)) => {
// Note that we definitely received this peer info since we got a reply // Note that we definitely received this node info since we got a reply
waitable_reply.node_ref.set_seen_our_dial_info(); waitable_reply.node_ref.set_seen_our_node_info();
// Reply received // Reply received
let recv_ts = get_timestamp(); let recv_ts = get_timestamp();
@ -434,10 +433,20 @@ impl RPCProcessor {
let out; let out;
// To where are we sending the request // To where are we sending the request
match dest { match &dest {
Destination::Direct(node_ref) => { Destination::Direct(node_ref) | Destination::Normal(node_ref) => {
// Send to a node without a private route // Send to a node without a private route
// -------------------------------------- // --------------------------------------
// Get the actual destination node id, accounting for outbound relaying
let (node_ref, node_id) = if matches!(dest, Destination::Normal(_)) {
self.get_direct_destination(node_ref.clone())?
} else {
let node_id = node_ref.node_id();
(node_ref.clone(), node_id)
};
// Handle the existence of safety route
match safety_route_spec { match safety_route_spec {
None => { None => {
// If no safety route is being used, and we're not sending to a private // If no safety route is being used, and we're not sending to a private
@ -445,7 +454,7 @@ impl RPCProcessor {
out = reader_to_vec(message)?; out = reader_to_vec(message)?;
// Message goes directly to the node // Message goes directly to the node
out_node_id = node_ref.node_id(); out_node_id = node_id;
out_noderef = Some(node_ref); out_noderef = Some(node_ref);
hopcount = 1; hopcount = 1;
} }
@ -454,7 +463,7 @@ impl RPCProcessor {
// but we are using a safety route, so we must create an empty private route // but we are using a safety route, so we must create an empty private route
let mut pr_builder = ::capnp::message::Builder::new_default(); let mut pr_builder = ::capnp::message::Builder::new_default();
let private_route = let private_route =
self.new_stub_private_route(node_ref.node_id(), &mut pr_builder)?; self.new_stub_private_route(node_id, &mut pr_builder)?;
let message_vec = reader_to_vec(message)?; let message_vec = reader_to_vec(message)?;
// first // first
@ -487,7 +496,7 @@ impl RPCProcessor {
None => { None => {
// If no safety route, the first node is the first hop of the private route // If no safety route, the first node is the first hop of the private route
hopcount = private_route.hop_count as usize; hopcount = private_route.hop_count as usize;
let out_node_id = match private_route.hops { let out_node_id = match &private_route.hops {
Some(rh) => rh.dial_info.node_id.key, Some(rh) => rh.dial_info.node_id.key,
_ => return Err(rpc_error_internal("private route has no hops")), _ => return Err(rpc_error_internal("private route has no hops")),
}; };
@ -547,7 +556,7 @@ impl RPCProcessor {
let bytes = out.len() as u64; let bytes = out.len() as u64;
if let Err(e) = self if let Err(e) = self
.network_manager() .network_manager()
.send_envelope(node_ref.clone(), out) .send_envelope(node_ref.clone(), Some(out_node_id), out)
.await .await
.map_err(logthru_rpc!(error)) .map_err(logthru_rpc!(error))
.map_err(RPCError::Internal) .map_err(RPCError::Internal)
@ -735,7 +744,7 @@ impl RPCProcessor {
// Send the reply // Send the reply
let bytes = out.len() as u64; let bytes = out.len() as u64;
self.network_manager() self.network_manager()
.send_envelope(node_ref.clone(), out) .send_envelope(node_ref.clone(), Some(out_node_id), out)
.await .await
.map_err(RPCError::Internal)?; .map_err(RPCError::Internal)?;
@ -762,17 +771,17 @@ impl RPCProcessor {
} }
} }
fn get_respond_to_sender_dial_info( fn get_respond_to_sender_node_info(
&self, &self,
operation: &veilid_capnp::operation::Reader, operation: &veilid_capnp::operation::Reader,
) -> Result<Option<DialInfo>, RPCError> { ) -> Result<Option<NodeInfo>, RPCError> {
if let veilid_capnp::operation::respond_to::Sender(Ok(sender_di_reader)) = operation if let veilid_capnp::operation::respond_to::Sender(Ok(sender_ni_reader)) = operation
.get_respond_to() .get_respond_to()
.which() .which()
.map_err(map_error_capnp_notinschema!())? .map_err(map_error_capnp_notinschema!())?
{ {
// Sender DialInfo was specified, update our routing table with it // Sender DialInfo was specified, update our routing table with it
Ok(Some(decode_dial_info(&sender_di_reader)?)) Ok(Some(decode_node_info(&sender_ni_reader, true)?))
} else { } else {
Ok(None) Ok(None)
} }
@ -809,17 +818,17 @@ impl RPCProcessor {
}; };
// Parse out fields // Parse out fields
let node_info = decode_node_info( let node_status = decode_node_status(
&iq_reader &iq_reader
.get_node_info() .get_node_status()
.map_err(map_error_internal!("no valid node info"))?, .map_err(map_error_internal!("no valid node status"))?,
)?; )?;
// add node information for the requesting node to our routing table // update node status for the requesting node to our routing table
if let Some(sender_nr) = rpcreader.opt_sender_nr.clone() { if let Some(sender_nr) = rpcreader.opt_sender_nr.clone() {
// Update latest node info in routing table for the infoq sender // Update latest node status in routing table for the infoq sender
sender_nr.operate(|e| { sender_nr.operate(|e| {
e.update_node_info(node_info); e.update_node_status(node_status);
}); });
} }
@ -831,10 +840,12 @@ impl RPCProcessor {
respond_to.set_none(()); respond_to.set_none(());
let detail = answer.reborrow().init_detail(); let detail = answer.reborrow().init_detail();
let mut info_a = detail.init_info_a(); let mut info_a = detail.init_info_a();
// Add node info
let node_info = self.network_manager().generate_node_info(); // Add node status
let mut nib = info_a.reborrow().init_node_info(); let node_status = self.network_manager().generate_node_status();
encode_node_info(&node_info, &mut nib)?; let mut nsb = info_a.reborrow().init_node_status();
encode_node_status(&node_status, &mut nsb)?;
// Add sender info // Add sender info
let sender_info = self.generate_sender_info(&rpcreader); let sender_info = self.generate_sender_info(&rpcreader);
let mut sib = info_a.reborrow().init_sender_info(); let mut sib = info_a.reborrow().init_sender_info();
@ -898,7 +909,7 @@ impl RPCProcessor {
for peer in peers { for peer in peers {
// See if this peer will validate dial info // See if this peer will validate dial info
let will_validate_dial_info = peer.operate(|e: &mut BucketEntry| { let will_validate_dial_info = peer.operate(|e: &mut BucketEntry| {
if let Some(ni) = &e.peer_stats().node_info { if let Some(ni) = &e.peer_stats().status {
ni.will_validate_dial_info ni.will_validate_dial_info
} else { } else {
true true
@ -980,23 +991,14 @@ impl RPCProcessor {
.map_err(logthru_rpc!())?, .map_err(logthru_rpc!())?,
); );
// get the peerinfo/dialinfos of the requesting node // get the sender NodeInfo of the requesting node
let dil_reader = fnq_reader let sni_reader = fnq_reader
.reborrow() .reborrow()
.get_dial_info_list() .get_sender_node_info()
.map_err(map_error_capnp_error!())?; .map_err(map_error_capnp_error!())?;
let mut dial_infos = Vec::<DialInfo>::with_capacity(
dil_reader
.len()
.try_into()
.map_err(map_error_protocol!("too many dial infos"))?,
);
for di in dil_reader.iter() {
dial_infos.push(decode_dial_info(&di)?)
}
let peer_info = PeerInfo { let peer_info = PeerInfo {
node_id: NodeId::new(rpcreader.header.envelope.get_sender_id()), node_id: NodeId::new(rpcreader.header.envelope.get_sender_id()),
dial_infos, node_info: decode_node_info(&sni_reader, true)?,
}; };
// filter out attempts to pass non-public addresses in for peers // filter out attempts to pass non-public addresses in for peers
@ -1007,19 +1009,17 @@ impl RPCProcessor {
// add node information for the requesting node to our routing table // add node information for the requesting node to our routing table
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let _requesting_node_ref = routing_table let _requesting_node_ref = routing_table
.register_node_with_dial_info(peer_info.node_id.key, &peer_info.dial_infos) .register_node_with_node_info(peer_info.node_id.key, peer_info.node_info)
.map_err(map_error_string!())?; .map_err(map_error_string!())?;
// find N nodes closest to the target node in our routing table // find N nodes closest to the target node in our routing table
let own_peer_info = routing_table.get_own_peer_info(self.default_peer_scope); let own_peer_info = routing_table.get_own_peer_info();
let closest_nodes = routing_table.find_closest_nodes( let closest_nodes = routing_table.find_closest_nodes(
target_node_id, target_node_id,
// filter // filter
None, None,
// transform // transform
|e| { |e| RoutingTable::transform_to_peer_info(e, &own_peer_info),
RoutingTable::transform_to_peer_info(e, self.default_peer_scope, &own_peer_info)
},
); );
log_rpc!(">>>> Returning {} closest peers", closest_nodes.len()); log_rpc!(">>>> Returning {} closest peers", closest_nodes.len());
@ -1076,8 +1076,8 @@ impl RPCProcessor {
Err(rpc_error_unimplemented("process_find_block_q")) Err(rpc_error_unimplemented("process_find_block_q"))
} }
async fn process_signal_q(&self, _rpcreader: RPCMessageReader) -> Result<(), RPCError> { async fn process_signal(&self, _rpcreader: RPCMessageReader) -> Result<(), RPCError> {
Err(rpc_error_unimplemented("process_signal_q")) Err(rpc_error_unimplemented("process_signal"))
} }
async fn process_return_receipt(&self, rpcreader: RPCMessageReader) -> Result<(), RPCError> { async fn process_return_receipt(&self, rpcreader: RPCMessageReader) -> Result<(), RPCError> {
@ -1176,28 +1176,27 @@ impl RPCProcessor {
veilid_capnp::operation::detail::SupplyBlockA(_) => (14u32, false), veilid_capnp::operation::detail::SupplyBlockA(_) => (14u32, false),
veilid_capnp::operation::detail::FindBlockQ(_) => (15u32, true), veilid_capnp::operation::detail::FindBlockQ(_) => (15u32, true),
veilid_capnp::operation::detail::FindBlockA(_) => (16u32, false), veilid_capnp::operation::detail::FindBlockA(_) => (16u32, false),
veilid_capnp::operation::detail::SignalQ(_) => (17u32, true), veilid_capnp::operation::detail::Signal(_) => (17u32, true),
veilid_capnp::operation::detail::SignalA(_) => (18u32, false), veilid_capnp::operation::detail::ReturnReceipt(_) => (18u32, true),
veilid_capnp::operation::detail::ReturnReceipt(_) => (19u32, true), veilid_capnp::operation::detail::StartTunnelQ(_) => (19u32, true),
veilid_capnp::operation::detail::StartTunnelQ(_) => (20u32, true), veilid_capnp::operation::detail::StartTunnelA(_) => (20u32, false),
veilid_capnp::operation::detail::StartTunnelA(_) => (21u32, false), veilid_capnp::operation::detail::CompleteTunnelQ(_) => (21u32, true),
veilid_capnp::operation::detail::CompleteTunnelQ(_) => (22u32, true), veilid_capnp::operation::detail::CompleteTunnelA(_) => (22u32, false),
veilid_capnp::operation::detail::CompleteTunnelA(_) => (23u32, false), veilid_capnp::operation::detail::CancelTunnelQ(_) => (23u32, true),
veilid_capnp::operation::detail::CancelTunnelQ(_) => (24u32, true), veilid_capnp::operation::detail::CancelTunnelA(_) => (24u32, false),
veilid_capnp::operation::detail::CancelTunnelA(_) => (25u32, false),
}; };
// Accounting for questions we receive // Accounting for questions we receive
if is_q { if is_q {
// See if we have some Sender DialInfo to incorporate // See if we have some Sender NodeInfo to incorporate
opt_sender_nr = opt_sender_nr =
if let Some(sender_di) = self.get_respond_to_sender_dial_info(&operation)? { if let Some(sender_ni) = self.get_respond_to_sender_node_info(&operation)? {
// Sender DialInfo was specified, update our routing table with it // Sender NodeInfo was specified, update our routing table with it
let nr = self let nr = self
.routing_table() .routing_table()
.update_node_with_single_dial_info( .register_node_with_node_info(
msg.header.envelope.get_sender_id(), msg.header.envelope.get_sender_id(),
&sender_di, sender_ni,
) )
.map_err(RPCError::Internal)?; .map_err(RPCError::Internal)?;
Some(nr) Some(nr)
@ -1251,15 +1250,14 @@ impl RPCProcessor {
14 => self.process_answer(rpcreader).await, // SupplyBlockA 14 => self.process_answer(rpcreader).await, // SupplyBlockA
15 => self.process_find_block_q(rpcreader).await, // FindBlockQ 15 => self.process_find_block_q(rpcreader).await, // FindBlockQ
16 => self.process_answer(rpcreader).await, // FindBlockA 16 => self.process_answer(rpcreader).await, // FindBlockA
17 => self.process_signal_q(rpcreader).await, // SignalQ 17 => self.process_signal(rpcreader).await, // SignalQ
18 => self.process_answer(rpcreader).await, // SignalA 18 => self.process_return_receipt(rpcreader).await, // ReturnReceipt
19 => self.process_return_receipt(rpcreader).await, // ReturnReceipt 19 => self.process_start_tunnel_q(rpcreader).await, // StartTunnelQ
20 => self.process_start_tunnel_q(rpcreader).await, // StartTunnelQ 20 => self.process_answer(rpcreader).await, // StartTunnelA
21 => self.process_answer(rpcreader).await, // StartTunnelA 21 => self.process_complete_tunnel_q(rpcreader).await, // CompleteTunnelQ
22 => self.process_complete_tunnel_q(rpcreader).await, // CompleteTunnelQ 22 => self.process_answer(rpcreader).await, // CompleteTunnelA
23 => self.process_answer(rpcreader).await, // CompleteTunnelA 23 => self.process_cancel_tunnel_q(rpcreader).await, // CancelTunnelQ
24 => self.process_cancel_tunnel_q(rpcreader).await, // CancelTunnelQ 24 => self.process_answer(rpcreader).await, // CancelTunnelA
25 => self.process_answer(rpcreader).await, // CancelTunnelA
_ => panic!("must update rpc table"), _ => panic!("must update rpc table"),
} }
} }
@ -1361,19 +1359,15 @@ impl RPCProcessor {
// Gets a 'RespondTo::Sender' that contains either our dial info, // Gets a 'RespondTo::Sender' that contains either our dial info,
// or None if the peer has seen our dial info before // or None if the peer has seen our dial info before
pub fn get_respond_to_sender(&self, peer: NodeRef) -> RespondTo { pub fn get_respond_to_sender(&self, peer: NodeRef) -> RespondTo {
if peer.has_seen_our_dial_info() { if peer.has_seen_our_node_info() {
RespondTo::Sender(None) RespondTo::Sender(None)
} else if let Some(did) = self
.routing_table()
.first_filtered_dial_info_detail(peer.dial_info_filter())
{
RespondTo::Sender(Some(did.dial_info))
} else { } else {
RespondTo::Sender(None) RespondTo::Sender(Some(self.routing_table().get_own_peer_info().node_info))
} }
} }
// Send InfoQ RPC request, receive InfoA answer // Send InfoQ RPC request, receive InfoA answer
// Can be sent via relays, but not via routes
pub async fn rpc_call_info(self, peer: NodeRef) -> Result<InfoAnswer, RPCError> { pub async fn rpc_call_info(self, peer: NodeRef) -> Result<InfoAnswer, RPCError> {
let info_q_msg = { let info_q_msg = {
let mut info_q_msg = ::capnp::message::Builder::new_default(); let mut info_q_msg = ::capnp::message::Builder::new_default();
@ -1384,9 +1378,9 @@ impl RPCProcessor {
.encode(&mut respond_to)?; .encode(&mut respond_to)?;
let detail = question.reborrow().init_detail(); let detail = question.reborrow().init_detail();
let mut iqb = detail.init_info_q(); let mut iqb = detail.init_info_q();
let mut node_info_builder = iqb.reborrow().init_node_info(); let mut node_status_builder = iqb.reborrow().init_node_status();
let node_info = self.network_manager().generate_node_info(); let node_status = self.network_manager().generate_node_status();
encode_node_info(&node_info, &mut node_info_builder)?; encode_node_status(&node_status, &mut node_status_builder)?;
info_q_msg.into_reader() info_q_msg.into_reader()
}; };
@ -1418,13 +1412,13 @@ impl RPCProcessor {
}; };
// Decode node info // Decode node info
if !info_a.has_node_info() { if !info_a.has_node_status() {
return Err(rpc_error_internal("Missing node info")); return Err(rpc_error_internal("Missing node status"));
} }
let nir = info_a let nsr = info_a
.get_node_info() .get_node_status()
.map_err(map_error_internal!("Broken node info"))?; .map_err(map_error_internal!("Broken node status"))?;
let node_info = decode_node_info(&nir)?; let node_status = decode_node_status(&nsr)?;
// Decode sender info // Decode sender info
let sender_info = if info_a.has_sender_info() { let sender_info = if info_a.has_sender_info() {
@ -1436,21 +1430,22 @@ impl RPCProcessor {
SenderInfo::default() SenderInfo::default()
}; };
// Update latest node info in routing table // Update latest node status in routing table
peer.operate(|e| { peer.operate(|e| {
e.update_node_info(node_info.clone()); e.update_node_status(node_status.clone());
}); });
// Return the answer for anyone who may care // Return the answer for anyone who may care
let out = InfoAnswer { let out = InfoAnswer {
latency, latency,
node_info, node_status,
sender_info, sender_info,
}; };
Ok(out) Ok(out)
} }
// Can only be sent directly, not via relays or routes
pub async fn rpc_call_validate_dial_info( pub async fn rpc_call_validate_dial_info(
&self, &self,
peer: NodeRef, peer: NodeRef,
@ -1496,7 +1491,8 @@ impl RPCProcessor {
}; };
// Send the validate_dial_info request // Send the validate_dial_info request
self.request(Destination::Direct(peer.clone()), vdi_msg, None) // This can only be sent directly, as relays can not validate dial info
self.request(Destination::Direct(peer), vdi_msg, None)
.await?; .await?;
// Wait for receipt // Wait for receipt
@ -1510,6 +1506,7 @@ impl RPCProcessor {
} }
// Send FindNodeQ RPC request, receive FindNodeA answer // Send FindNodeQ RPC request, receive FindNodeA answer
// Can be sent via all methods including relays and routes
pub async fn rpc_call_find_node( pub async fn rpc_call_find_node(
self, self,
dest: Destination, dest: Destination,
@ -1528,22 +1525,10 @@ impl RPCProcessor {
let mut node_id_builder = fnq.reborrow().init_node_id(); let mut node_id_builder = fnq.reborrow().init_node_id();
encode_public_key(&key, &mut node_id_builder)?; encode_public_key(&key, &mut node_id_builder)?;
let own_peer_info = self let own_peer_info = self.routing_table().get_own_peer_info();
.routing_table()
.get_own_peer_info(self.default_peer_scope);
let mut dil_builder = fnq.reborrow().init_dial_info_list( let mut ni_builder = fnq.reborrow().init_sender_node_info();
own_peer_info encode_node_info(&own_peer_info.node_info, &mut ni_builder)?;
.dial_infos
.len()
.try_into()
.map_err(map_error_internal!("too many dial infos in peer info"))?,
);
for idx in 0..own_peer_info.dial_infos.len() {
let mut di_builder = dil_builder.reborrow().get(idx as u32);
encode_dial_info(&own_peer_info.dial_infos[idx], &mut di_builder)?;
}
find_node_q_msg.into_reader() find_node_q_msg.into_reader()
}; };
@ -1584,7 +1569,7 @@ impl RPCProcessor {
.map_err(map_error_internal!("too many peers"))?, .map_err(map_error_internal!("too many peers"))?,
); );
for p in peers_reader.iter() { for p in peers_reader.iter() {
let peer_info = decode_peer_info(&p)?; let peer_info = decode_peer_info(&p, true)?;
if !self.filter_peer_scope(&peer_info) { if !self.filter_peer_scope(&peer_info) {
return Err(RPCError::InvalidFormat); return Err(RPCError::InvalidFormat);
@ -1598,5 +1583,35 @@ impl RPCProcessor {
Ok(out) Ok(out)
} }
// Sends a unidirectional signal to a node
// Can be sent via all methods including relays and routes
pub async fn rpc_call_signal(
&self,
dest: Destination,
relay_dial_info: DialInfo,
safety_route: Option<&SafetyRouteSpec>,
signal_info: SignalInfo,
) -> Result<(), RPCError> {
let network_manager = self.network_manager();
//
let sig_msg = {
let mut sig_msg = ::capnp::message::Builder::new_default();
let mut question = sig_msg.init_root::<veilid_capnp::operation::Builder>();
question.set_op_id(self.get_next_op_id());
let mut respond_to = question.reborrow().init_respond_to();
respond_to.set_none(());
let detail = question.reborrow().init_detail();
let mut sig_builder = detail.init_signal();
encode_signal_info(&signal_info, &mut sig_builder)?;
sig_msg.into_reader()
};
// Send the signal request
self.request(dest, sig_msg, safety_route).await?;
Ok(())
}
// xxx do not process latency for routed messages // xxx do not process latency for routed messages
} }

View File

@ -110,6 +110,9 @@ impl fmt::Display for VeilidAPIError {
fn convert_rpc_error(x: RPCError) -> VeilidAPIError { fn convert_rpc_error(x: RPCError) -> VeilidAPIError {
match x { match x {
RPCError::Timeout => VeilidAPIError::Timeout, RPCError::Timeout => VeilidAPIError::Timeout,
RPCError::Unreachable(n) => VeilidAPIError::NodeNotFound {
node_id: NodeId::new(n),
},
RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented { message: s }, RPCError::Unimplemented(s) => VeilidAPIError::Unimplemented { message: s },
RPCError::Internal(s) => VeilidAPIError::Internal { message: s }, RPCError::Internal(s) => VeilidAPIError::Internal { message: s },
RPCError::Protocol(s) => VeilidAPIError::Internal { message: s }, RPCError::Protocol(s) => VeilidAPIError::Internal { message: s },
@ -324,50 +327,54 @@ pub struct NodeStatus {
#[derive(Clone, Debug, Default, Serialize, Deserialize)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeInfo { pub struct NodeInfo {
pub network_class: NetworkClass, pub network_class: NetworkClass,
pub dial_infos: Vec<DialInfo>, pub outbound_protocols: ProtocolSet,
pub relay_dial_infos: Vec<DialInfo>, pub dial_info_list: Vec<DialInfo>,
pub relay_peer_info: Option<Box<PeerInfo>>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct LocalNodeInfo {
pub outbound_protocols: ProtocolSet,
pub dial_info_list: Vec<DialInfo>,
} }
impl NodeInfo { impl NodeInfo {
pub fn first_filtered<F>(&self, filter: F) -> NodeInfo pub fn first_filtered_dial_info<F>(&self, filter: F) -> Option<DialInfo>
where where
F: Fn(&DialInfo) -> bool, F: Fn(&DialInfo) -> bool,
{ {
let mut node_info = NodeInfo::default(); for di in &self.dial_info_list {
node_info.network_class = self.network_class;
for di in &self.dial_infos {
if filter(di) { if filter(di) {
node_info.dial_infos.push(di.clone()); return Some(di.clone());
break;
} }
} }
for di in &self.relay_dial_infos { None
if filter(di) {
node_info.relay_dial_infos.push(di.clone());
break;
}
}
node_info
} }
pub fn all_filtered<F>(&self, filter: F) -> NodeInfo
pub fn all_filtered_dial_info<F>(&self, filter: F) -> Vec<DialInfo>
where where
F: Fn(&DialInfo) -> bool, F: Fn(&DialInfo) -> bool,
{ {
let mut node_info = NodeInfo::default(); let mut dial_info_list = Vec::new();
node_info.network_class = self.network_class;
for di in &self.dial_infos { for di in &self.dial_info_list {
if filter(di) { if filter(di) {
node_info.dial_infos.push(di.clone()); dial_info_list.push(di.clone());
} }
} }
for di in &self.relay_dial_infos { dial_info_list
if filter(di) { }
node_info.relay_dial_infos.push(di.clone());
} pub fn has_any_dial_info(&self) -> bool {
} !self.dial_info_list.is_empty()
node_info || !self
.relay_peer_info
.map(|rpi| rpi.node_info.has_direct_dial_info())
.unwrap_or_default()
}
pub fn has_direct_dial_info(&self) -> bool {
!self.dial_info_list.is_empty()
} }
} }
@ -381,6 +388,28 @@ pub enum ProtocolType {
WSS, WSS,
} }
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ProtocolSet {
pub udp: bool,
pub tcp: bool,
pub ws: bool,
pub wss: bool,
}
impl ProtocolSet {
pub fn is_protocol_type_enabled(&self, protocol_type: ProtocolType) -> bool {
match protocol_type {
ProtocolType::UDP => self.udp,
ProtocolType::TCP => self.tcp,
ProtocolType::WS => self.ws,
ProtocolType::WSS => self.wss,
}
}
pub fn filter_dial_info(&self, di: &DialInfo) -> bool {
self.is_protocol_type_enabled(di.protocol_type())
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub enum AddressType { pub enum AddressType {
IPV4, IPV4,
@ -1057,7 +1086,25 @@ cfg_if! {
Arc<dyn Fn(ValueKey, Vec<u8>) -> SystemPinBoxFuture<()> + Send + Sync + 'static>; Arc<dyn Fn(ValueKey, Vec<u8>) -> SystemPinBoxFuture<()> + Send + Sync + 'static>;
} }
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum SignalInfo {
HolePunch {
// UDP Hole Punch Request
receipt: Vec<u8>, // Receipt to be returned after the hole punch
node_info: NodeInfo, // Sender's node info
},
ReverseConnect {
// Reverse Connection Request
receipt: Vec<u8>, // Receipt to be returned by the reverse connection
node_info: NodeInfo, // Sender's node info
},
// XXX: WebRTC
// XXX: App-level signalling
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub enum TunnelMode { pub enum TunnelMode {
Raw, Raw,
@ -1139,14 +1186,6 @@ pub struct RoutingContextOptions {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SearchDHTAnswer {
pub node_id: NodeId,
pub dial_info: Vec<DialInfo>,
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
pub struct RoutingContextInner { pub struct RoutingContextInner {
api: VeilidAPI, api: VeilidAPI,
options: RoutingContextOptions, options: RoutingContextOptions,
@ -1397,7 +1436,7 @@ impl VeilidAPI {
.map_err(map_rpc_error!()) .map_err(map_rpc_error!())
} }
pub async fn search_dht(&self, node_id: NodeId) -> Result<SearchDHTAnswer, VeilidAPIError> { pub async fn search_dht(&self, node_id: NodeId) -> Result<PeerInfo, VeilidAPIError> {
let rpc_processor = self.rpc_processor()?; let rpc_processor = self.rpc_processor()?;
let config = self.config()?; let config = self.config()?;
let (count, fanout, timeout) = { let (count, fanout, timeout) = {
@ -1414,18 +1453,12 @@ impl VeilidAPI {
.await .await
.map_err(map_rpc_error!())?; .map_err(map_rpc_error!())?;
let answer = node_ref.operate(|e| SearchDHTAnswer { let answer = node_ref.peer_info();
node_id: NodeId::new(node_ref.node_id()),
dial_info: e.dial_infos().to_vec(),
});
Ok(answer) Ok(answer)
} }
pub async fn search_dht_multi( pub async fn search_dht_multi(&self, node_id: NodeId) -> Result<Vec<PeerInfo>, VeilidAPIError> {
&self,
node_id: NodeId,
) -> Result<Vec<SearchDHTAnswer>, VeilidAPIError> {
let rpc_processor = self.rpc_processor()?; let rpc_processor = self.rpc_processor()?;
let config = self.config()?; let config = self.config()?;
let (count, fanout, timeout) = { let (count, fanout, timeout) = {
@ -1442,14 +1475,7 @@ impl VeilidAPI {
.await .await
.map_err(map_rpc_error!())?; .map_err(map_rpc_error!())?;
let mut answer = Vec::<SearchDHTAnswer>::new(); let answer = node_refs.iter().map(|x| x.peer_info()).collect();
for nr in node_refs {
let a = nr.operate(|e| SearchDHTAnswer {
node_id: NodeId::new(nr.node_id()),
dial_info: e.dial_infos().to_vec(),
});
answer.push(a);
}
Ok(answer) Ok(answer)
} }

View File

@ -15,7 +15,7 @@ cfg_if! {
} }
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigHTTPS { pub struct VeilidConfigHTTPS {
pub enabled: bool, pub enabled: bool,
pub listen_address: String, pub listen_address: String,
@ -23,7 +23,7 @@ pub struct VeilidConfigHTTPS {
pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigHTTP { pub struct VeilidConfigHTTP {
pub enabled: bool, pub enabled: bool,
pub listen_address: String, pub listen_address: String,
@ -31,13 +31,13 @@ pub struct VeilidConfigHTTP {
pub url: Option<String>, pub url: Option<String>,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigApplication { pub struct VeilidConfigApplication {
pub https: VeilidConfigHTTPS, pub https: VeilidConfigHTTPS,
pub http: VeilidConfigHTTP, pub http: VeilidConfigHTTP,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigUDP { pub struct VeilidConfigUDP {
pub enabled: bool, pub enabled: bool,
pub socket_pool_size: u32, pub socket_pool_size: u32,
@ -45,7 +45,7 @@ pub struct VeilidConfigUDP {
pub public_address: Option<String>, pub public_address: Option<String>,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigTCP { pub struct VeilidConfigTCP {
pub connect: bool, pub connect: bool,
pub listen: bool, pub listen: bool,
@ -54,7 +54,7 @@ pub struct VeilidConfigTCP {
pub public_address: Option<String>, pub public_address: Option<String>,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigWS { pub struct VeilidConfigWS {
pub connect: bool, pub connect: bool,
pub listen: bool, pub listen: bool,
@ -64,7 +64,7 @@ pub struct VeilidConfigWS {
pub url: Option<String>, pub url: Option<String>,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigWSS { pub struct VeilidConfigWSS {
pub connect: bool, pub connect: bool,
pub listen: bool, pub listen: bool,
@ -74,7 +74,7 @@ pub struct VeilidConfigWSS {
pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigProtocol { pub struct VeilidConfigProtocol {
pub udp: VeilidConfigUDP, pub udp: VeilidConfigUDP,
pub tcp: VeilidConfigTCP, pub tcp: VeilidConfigTCP,
@ -82,14 +82,14 @@ pub struct VeilidConfigProtocol {
pub wss: VeilidConfigWSS, pub wss: VeilidConfigWSS,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigTLS { pub struct VeilidConfigTLS {
pub certificate_path: String, pub certificate_path: String,
pub private_key_path: String, pub private_key_path: String,
pub connection_initial_timeout_ms: u32, pub connection_initial_timeout_ms: u32,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigDHT { pub struct VeilidConfigDHT {
pub resolve_node_timeout_ms: Option<u32>, pub resolve_node_timeout_ms: Option<u32>,
pub resolve_node_count: u32, pub resolve_node_count: u32,
@ -107,7 +107,7 @@ pub struct VeilidConfigDHT {
pub nearby_node_percentage: u32, pub nearby_node_percentage: u32,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigRPC { pub struct VeilidConfigRPC {
pub concurrency: u32, pub concurrency: u32,
pub queue_size: u32, pub queue_size: u32,
@ -117,14 +117,14 @@ pub struct VeilidConfigRPC {
pub max_route_hop_count: u8, pub max_route_hop_count: u8,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigLeases { pub struct VeilidConfigLeases {
pub max_server_signal_leases: u32, pub max_server_signal_leases: u32,
pub max_server_relay_leases: u32, pub max_server_relay_leases: u32,
pub max_client_signal_leases: u32, pub max_client_signal_leases: u32,
pub max_client_relay_leases: u32, pub max_client_relay_leases: u32,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigRoutingTable { pub struct VeilidConfigRoutingTable {
pub limit_over_attached: u32, pub limit_over_attached: u32,
pub limit_fully_attached: u32, pub limit_fully_attached: u32,
@ -133,12 +133,14 @@ pub struct VeilidConfigRoutingTable {
pub limit_attached_weak: u32, pub limit_attached_weak: u32,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigNetwork { pub struct VeilidConfigNetwork {
pub max_connections: u32, pub max_connections: u32,
pub connection_initial_timeout_ms: u32, pub connection_initial_timeout_ms: u32,
pub connection_inactivity_timeout_ms: u32, pub connection_inactivity_timeout_ms: u32,
pub client_whitelist_timeout_ms: u32, pub client_whitelist_timeout_ms: u32,
pub reverse_connection_receipt_time_ms: u32,
pub hole_punch_receipt_time_ms: u32,
pub node_id: key::DHTKey, pub node_id: key::DHTKey,
pub node_id_secret: key::DHTKeySecret, pub node_id_secret: key::DHTKeySecret,
pub bootstrap: Vec<String>, pub bootstrap: Vec<String>,
@ -155,19 +157,19 @@ pub struct VeilidConfigNetwork {
pub leases: VeilidConfigLeases, pub leases: VeilidConfigLeases,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigTableStore { pub struct VeilidConfigTableStore {
pub directory: String, pub directory: String,
pub delete: bool, pub delete: bool,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigBlockStore { pub struct VeilidConfigBlockStore {
pub directory: String, pub directory: String,
pub delete: bool, pub delete: bool,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigProtectedStore { pub struct VeilidConfigProtectedStore {
pub allow_insecure_fallback: bool, pub allow_insecure_fallback: bool,
pub always_use_insecure_storage: bool, pub always_use_insecure_storage: bool,
@ -175,7 +177,7 @@ pub struct VeilidConfigProtectedStore {
pub delete: bool, pub delete: bool,
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigCapabilities { pub struct VeilidConfigCapabilities {
pub protocol_udp: bool, pub protocol_udp: bool,
pub protocol_connect_tcp: bool, pub protocol_connect_tcp: bool,
@ -214,7 +216,7 @@ impl Default for VeilidConfigLogLevel {
} }
} }
#[derive(Default, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct VeilidConfigInner { pub struct VeilidConfigInner {
pub program_name: String, pub program_name: String,
pub namespace: String, pub namespace: String,