fixes
This commit is contained in:
parent
ce36df5cad
commit
d80a81e460
@ -178,7 +178,7 @@ impl ConnectionManager {
|
|||||||
match res {
|
match res {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log_net!(error e);
|
log_net!(debug e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use super::envelope::{MAX_VERSION, MIN_VERSION};
|
|||||||
use super::key::*;
|
use super::key::*;
|
||||||
use crate::xx::*;
|
use crate::xx::*;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
use data_encoding::BASE64URL_NOPAD;
|
||||||
|
|
||||||
// #[repr(C, packed)]
|
// #[repr(C, packed)]
|
||||||
// struct ReceiptHeader {
|
// struct ReceiptHeader {
|
||||||
@ -32,6 +33,16 @@ pub const MIN_RECEIPT_SIZE: usize = 128;
|
|||||||
pub const RECEIPT_MAGIC: &[u8; 4] = b"RCPT";
|
pub const RECEIPT_MAGIC: &[u8; 4] = b"RCPT";
|
||||||
pub type ReceiptNonce = [u8; 24];
|
pub type ReceiptNonce = [u8; 24];
|
||||||
|
|
||||||
|
pub trait Encodable {
|
||||||
|
fn encode(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for ReceiptNonce {
|
||||||
|
fn encode(&self) -> String {
|
||||||
|
BASE64URL_NOPAD.encode(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct Receipt {
|
pub struct Receipt {
|
||||||
version: u8,
|
version: u8,
|
||||||
|
@ -4,16 +4,24 @@ use crate::intf::*;
|
|||||||
use crate::routing_table::*;
|
use crate::routing_table::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
|
use futures_util::stream::FuturesUnordered;
|
||||||
|
use futures_util::FutureExt;
|
||||||
|
|
||||||
|
struct DetectedPublicDialInfo {
|
||||||
|
dial_info: DialInfo,
|
||||||
|
class: DialInfoClass,
|
||||||
|
}
|
||||||
struct DiscoveryContextInner {
|
struct DiscoveryContextInner {
|
||||||
network_class: Option<NetworkClass>,
|
|
||||||
// per-protocol
|
// per-protocol
|
||||||
intf_addrs: Option<Vec<SocketAddress>>,
|
intf_addrs: Option<Vec<SocketAddress>>,
|
||||||
protocol_type: Option<ProtocolType>,
|
protocol_type: Option<ProtocolType>,
|
||||||
address_type: Option<AddressType>,
|
address_type: Option<AddressType>,
|
||||||
low_level_protocol_type: Option<ProtocolType>,
|
|
||||||
external1_dial_info: Option<DialInfo>,
|
external1_dial_info: Option<DialInfo>,
|
||||||
external1: Option<SocketAddress>,
|
external1: Option<SocketAddress>,
|
||||||
node_b: Option<NodeRef>,
|
node_b: Option<NodeRef>,
|
||||||
|
// detected public dialinfo
|
||||||
|
detected_network_class: Option<NetworkClass>,
|
||||||
|
detected_public_dial_info: Option<DetectedPublicDialInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DiscoveryContext {
|
pub struct DiscoveryContext {
|
||||||
@ -28,15 +36,15 @@ impl DiscoveryContext {
|
|||||||
routing_table,
|
routing_table,
|
||||||
net,
|
net,
|
||||||
inner: Arc::new(Mutex::new(DiscoveryContextInner {
|
inner: Arc::new(Mutex::new(DiscoveryContextInner {
|
||||||
network_class: None,
|
|
||||||
// per-protocol
|
// per-protocol
|
||||||
intf_addrs: None,
|
intf_addrs: None,
|
||||||
protocol_type: None,
|
protocol_type: None,
|
||||||
address_type: None,
|
address_type: None,
|
||||||
low_level_protocol_type: None,
|
|
||||||
external1_dial_info: None,
|
external1_dial_info: None,
|
||||||
external1: None,
|
external1: None,
|
||||||
node_b: None,
|
node_b: None,
|
||||||
|
detected_network_class: None,
|
||||||
|
detected_public_dial_info: None,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,16 +53,14 @@ impl DiscoveryContext {
|
|||||||
// Utilities
|
// Utilities
|
||||||
|
|
||||||
// Pick the best network class we have seen so far
|
// Pick the best network class we have seen so far
|
||||||
pub fn upgrade_network_class(&self, network_class: NetworkClass) {
|
pub fn set_detected_network_class(&self, network_class: NetworkClass) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
inner.detected_network_class = Some(network_class);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(old_nc) = inner.network_class {
|
pub fn set_detected_public_dial_info(&self, dial_info: DialInfo, class: DialInfoClass) {
|
||||||
if network_class < old_nc {
|
let mut inner = self.inner.lock();
|
||||||
inner.network_class = Some(network_class);
|
inner.detected_public_dial_info = Some(DetectedPublicDialInfo { dial_info, class });
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inner.network_class = Some(network_class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask for a public address check from a particular noderef
|
// Ask for a public address check from a particular noderef
|
||||||
@ -66,7 +72,11 @@ impl DiscoveryContext {
|
|||||||
"failed to get status answer from {:?}",
|
"failed to get status answer from {:?}",
|
||||||
node_ref
|
node_ref
|
||||||
))
|
))
|
||||||
.map(|sa| sa.sender_info.socket_address)
|
.map(|sa| {
|
||||||
|
let ret = sa.sender_info.socket_address;
|
||||||
|
log_net!("request_public_address: {:?}", ret);
|
||||||
|
ret
|
||||||
|
})
|
||||||
.unwrap_or(None)
|
.unwrap_or(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +179,6 @@ impl DiscoveryContext {
|
|||||||
inner.intf_addrs = Some(intf_addrs);
|
inner.intf_addrs = Some(intf_addrs);
|
||||||
inner.protocol_type = Some(protocol_type);
|
inner.protocol_type = Some(protocol_type);
|
||||||
inner.address_type = Some(address_type);
|
inner.address_type = Some(address_type);
|
||||||
inner.low_level_protocol_type = Some(match protocol_type {
|
|
||||||
ProtocolType::UDP => ProtocolType::UDP,
|
|
||||||
ProtocolType::TCP => ProtocolType::TCP,
|
|
||||||
ProtocolType::WS => ProtocolType::TCP,
|
|
||||||
ProtocolType::WSS => ProtocolType::TCP,
|
|
||||||
});
|
|
||||||
inner.external1_dial_info = None;
|
inner.external1_dial_info = None;
|
||||||
inner.external1 = None;
|
inner.external1 = None;
|
||||||
inner.node_b = None;
|
inner.node_b = None;
|
||||||
@ -193,6 +197,7 @@ impl DiscoveryContext {
|
|||||||
{
|
{
|
||||||
None => {
|
None => {
|
||||||
// If we can't get an external address, exit but don't throw an error so we can try again later
|
// If we can't get an external address, exit but don't throw an error so we can try again later
|
||||||
|
log_net!(debug "couldn't get external address 1");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
@ -204,6 +209,8 @@ impl DiscoveryContext {
|
|||||||
inner.external1 = Some(external1);
|
inner.external1 = Some(external1);
|
||||||
inner.node_b = Some(node_b);
|
inner.node_b = Some(node_b);
|
||||||
|
|
||||||
|
log_net!(debug "external1_dial_info: {:?}\nexternal1: {:?}\nnode_b: {:?}", inner.external1_dial_info, inner.external1, inner.node_b);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,29 +229,17 @@ impl DiscoveryContext {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// Add public dial info with Direct dialinfo class
|
// Add public dial info with Direct dialinfo class
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(external1_dial_info, DialInfoClass::Direct);
|
||||||
RoutingDomain::PublicInternet,
|
|
||||||
external1_dial_info,
|
|
||||||
DialInfoClass::Direct,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
// Attempt a UDP port mapping via all available and enabled mechanisms
|
// Attempt a UDP port mapping via all available and enabled mechanisms
|
||||||
else if let Some(external_mapped_dial_info) = self.try_port_mapping().await {
|
else if let Some(external_mapped_dial_info) = self.try_port_mapping().await {
|
||||||
// Got a port mapping, let's use it
|
// Got a port mapping, let's use it
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped);
|
||||||
RoutingDomain::PublicInternet,
|
|
||||||
external_mapped_dial_info,
|
|
||||||
DialInfoClass::Mapped,
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
// Add public dial info with Blocked dialinfo class
|
// Add public dial info with Blocked dialinfo class
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(external1_dial_info, DialInfoClass::Blocked);
|
||||||
RoutingDomain::PublicInternet,
|
|
||||||
external1_dial_info,
|
|
||||||
DialInfoClass::Blocked,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
self.upgrade_network_class(NetworkClass::InboundCapable);
|
self.set_detected_network_class(NetworkClass::InboundCapable);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,12 +258,8 @@ impl DiscoveryContext {
|
|||||||
// Attempt a UDP port mapping via all available and enabled mechanisms
|
// Attempt a UDP port mapping via all available and enabled mechanisms
|
||||||
if let Some(external_mapped_dial_info) = self.try_port_mapping().await {
|
if let Some(external_mapped_dial_info) = self.try_port_mapping().await {
|
||||||
// Got a port mapping, let's use it
|
// Got a port mapping, let's use it
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(external_mapped_dial_info, DialInfoClass::Mapped);
|
||||||
RoutingDomain::PublicInternet,
|
self.set_detected_network_class(NetworkClass::InboundCapable);
|
||||||
external_mapped_dial_info,
|
|
||||||
DialInfoClass::Mapped,
|
|
||||||
)?;
|
|
||||||
self.upgrade_network_class(NetworkClass::InboundCapable);
|
|
||||||
|
|
||||||
// No more retries
|
// No more retries
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -283,13 +274,10 @@ impl DiscoveryContext {
|
|||||||
{
|
{
|
||||||
// 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
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(external1_dial_info, DialInfoClass::FullConeNAT);
|
||||||
RoutingDomain::PublicInternet,
|
self.set_detected_network_class(NetworkClass::InboundCapable);
|
||||||
external1_dial_info,
|
|
||||||
DialInfoClass::FullConeNAT,
|
|
||||||
)?;
|
|
||||||
self.upgrade_network_class(NetworkClass::InboundCapable);
|
|
||||||
|
|
||||||
|
// No more retries
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +298,7 @@ impl DiscoveryContext {
|
|||||||
// If we have two different external addresses, then this is a symmetric NAT
|
// If we have two different external addresses, then this is a symmetric NAT
|
||||||
if external2 != external1 {
|
if external2 != external1 {
|
||||||
// Symmetric NAT is outbound only, no public dial info will work
|
// Symmetric NAT is outbound only, no public dial info will work
|
||||||
self.upgrade_network_class(NetworkClass::OutboundOnly);
|
self.set_detected_network_class(NetworkClass::OutboundOnly);
|
||||||
|
|
||||||
// No more retries
|
// No more retries
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -326,20 +314,18 @@ impl DiscoveryContext {
|
|||||||
.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
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(
|
||||||
RoutingDomain::PublicInternet,
|
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoClass::AddressRestrictedNAT,
|
DialInfoClass::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
|
||||||
self.routing_table.register_dial_info(
|
self.set_detected_public_dial_info(
|
||||||
RoutingDomain::PublicInternet,
|
|
||||||
external1_dial_info,
|
external1_dial_info,
|
||||||
DialInfoClass::PortRestrictedNAT,
|
DialInfoClass::PortRestrictedNAT,
|
||||||
)?;
|
);
|
||||||
}
|
}
|
||||||
self.upgrade_network_class(NetworkClass::InboundCapable);
|
self.set_detected_network_class(NetworkClass::InboundCapable);
|
||||||
|
|
||||||
// Allow another retry because sometimes trying again will get us Full Cone NAT instead
|
// Allow another retry because sometimes trying again will get us Full Cone NAT instead
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@ -442,42 +428,159 @@ impl Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_network_class_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
pub async fn update_network_class_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
||||||
log_net!("updating network class");
|
log_net!("--- updating network class");
|
||||||
|
|
||||||
|
// Ensure we aren't trying to update this without clearing it first
|
||||||
|
let old_network_class = self.inner.lock().network_class;
|
||||||
|
assert_eq!(old_network_class, None);
|
||||||
|
|
||||||
let protocol_config = self.inner.lock().protocol_config.unwrap_or_default();
|
let protocol_config = self.inner.lock().protocol_config.unwrap_or_default();
|
||||||
let old_network_class = self.inner.lock().network_class;
|
let mut unord = FuturesUnordered::new();
|
||||||
|
|
||||||
let context = DiscoveryContext::new(self.routing_table(), self.clone());
|
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
||||||
self.update_ipv4_protocol_dialinfo(&context, ProtocolType::UDP)
|
// UDPv4
|
||||||
.await?;
|
unord.push(
|
||||||
self.update_ipv6_protocol_dialinfo(&context, ProtocolType::UDP)
|
async {
|
||||||
.await?;
|
let udpv4_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv4_protocol_dialinfo(&udpv4_context, ProtocolType::UDP)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed UDPv4 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(udpv4_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// UDPv6
|
||||||
|
unord.push(
|
||||||
|
async {
|
||||||
|
let udpv6_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv6_protocol_dialinfo(&udpv6_context, ProtocolType::UDP)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed UDPv6 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(udpv6_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
||||||
self.update_ipv4_protocol_dialinfo(&context, ProtocolType::TCP)
|
// TCPv4
|
||||||
.await?;
|
unord.push(
|
||||||
self.update_ipv6_protocol_dialinfo(&context, ProtocolType::TCP)
|
async {
|
||||||
.await?;
|
let tcpv4_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv4_protocol_dialinfo(&tcpv4_context, ProtocolType::TCP)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed TCPv4 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(tcpv4_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// TCPv6
|
||||||
|
unord.push(
|
||||||
|
async {
|
||||||
|
let tcpv6_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv6_protocol_dialinfo(&tcpv6_context, ProtocolType::TCP)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed TCPv6 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(tcpv6_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if protocol_config.inbound.contains(ProtocolType::WS) {
|
if protocol_config.inbound.contains(ProtocolType::WS) {
|
||||||
self.update_ipv4_protocol_dialinfo(&context, ProtocolType::WS)
|
// WS4
|
||||||
.await?;
|
unord.push(
|
||||||
self.update_ipv6_protocol_dialinfo(&context, ProtocolType::WS)
|
async {
|
||||||
.await?;
|
let wsv4_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv4_protocol_dialinfo(&wsv4_context, ProtocolType::WS)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed WSv4 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(wsv4_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// WSv6
|
||||||
|
unord.push(
|
||||||
|
async {
|
||||||
|
let wsv6_context = DiscoveryContext::new(self.routing_table(), self.clone());
|
||||||
|
if let Err(e) = self
|
||||||
|
.update_ipv6_protocol_dialinfo(&wsv6_context, ProtocolType::TCP)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log_net!(debug "Failed WSv6 dialinfo discovery: {}", e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(wsv6_context)
|
||||||
|
}
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let network_class = context.inner.lock().network_class;
|
// Wait for all discovery futures to complete and collect contexts
|
||||||
if network_class != old_network_class {
|
let mut contexts = Vec::<DiscoveryContext>::new();
|
||||||
|
let mut network_class = Option::<NetworkClass>::None;
|
||||||
|
while let Some(ctx) = unord.next().await {
|
||||||
|
if let Some(ctx) = ctx {
|
||||||
|
if let Some(nc) = ctx.inner.lock().detected_network_class {
|
||||||
|
if let Some(last_nc) = network_class {
|
||||||
|
if nc < last_nc {
|
||||||
|
network_class = Some(nc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
network_class = Some(nc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contexts.push(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get best network class
|
||||||
|
if network_class.is_some() {
|
||||||
|
// Update public dial info
|
||||||
|
let routing_table = self.routing_table();
|
||||||
|
for ctx in contexts {
|
||||||
|
let inner = ctx.inner.lock();
|
||||||
|
if let Some(pdi) = &inner.detected_public_dial_info {
|
||||||
|
if let Err(e) = routing_table.register_dial_info(
|
||||||
|
RoutingDomain::PublicInternet,
|
||||||
|
pdi.dial_info.clone(),
|
||||||
|
pdi.class,
|
||||||
|
) {
|
||||||
|
log_net!(warn "Failed to register detected public dial info: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update network class
|
||||||
self.inner.lock().network_class = network_class;
|
self.inner.lock().network_class = network_class;
|
||||||
log_net!(debug "network class changed to {:?}", network_class);
|
log_net!(debug "network class changed to {:?}", network_class);
|
||||||
}
|
|
||||||
|
|
||||||
// send updates to everyone
|
// Send updates to everyone
|
||||||
self.routing_table().send_node_info_updates();
|
routing_table.send_node_info_updates();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -310,6 +310,7 @@ impl ReceiptManager {
|
|||||||
expected_returns: u32,
|
expected_returns: u32,
|
||||||
callback: impl ReceiptCallback,
|
callback: impl ReceiptCallback,
|
||||||
) {
|
) {
|
||||||
|
log_rpc!(debug "== New Multiple Receipt ({}) {} ", expected_returns, receipt.get_nonce().encode());
|
||||||
let record = Arc::new(Mutex::new(ReceiptRecord::from_receipt(
|
let record = Arc::new(Mutex::new(ReceiptRecord::from_receipt(
|
||||||
&receipt,
|
&receipt,
|
||||||
expiration,
|
expiration,
|
||||||
@ -318,6 +319,8 @@ impl ReceiptManager {
|
|||||||
)));
|
)));
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.receipts_by_nonce.insert(receipt.get_nonce(), record);
|
inner.receipts_by_nonce.insert(receipt.get_nonce(), record);
|
||||||
|
|
||||||
|
Self::update_next_oldest_timestamp(&mut *inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_single_shot_receipt(
|
pub fn record_single_shot_receipt(
|
||||||
@ -326,11 +329,15 @@ impl ReceiptManager {
|
|||||||
expiration: u64,
|
expiration: u64,
|
||||||
eventual: ReceiptSingleShotType,
|
eventual: ReceiptSingleShotType,
|
||||||
) {
|
) {
|
||||||
|
log_rpc!(debug "== New SingleShot Receipt {}", receipt.get_nonce().encode());
|
||||||
|
|
||||||
let record = Arc::new(Mutex::new(ReceiptRecord::from_single_shot_receipt(
|
let record = Arc::new(Mutex::new(ReceiptRecord::from_single_shot_receipt(
|
||||||
&receipt, expiration, eventual,
|
&receipt, expiration, eventual,
|
||||||
)));
|
)));
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner.receipts_by_nonce.insert(receipt.get_nonce(), record);
|
inner.receipts_by_nonce.insert(receipt.get_nonce(), record);
|
||||||
|
|
||||||
|
Self::update_next_oldest_timestamp(&mut *inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_next_oldest_timestamp(inner: &mut ReceiptManagerInner) {
|
fn update_next_oldest_timestamp(inner: &mut ReceiptManagerInner) {
|
||||||
@ -350,6 +357,8 @@ impl ReceiptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn cancel_receipt(&self, nonce: &ReceiptNonce) -> Result<(), String> {
|
pub async fn cancel_receipt(&self, nonce: &ReceiptNonce) -> Result<(), String> {
|
||||||
|
log_rpc!(debug "== Cancel Receipt {}", nonce.encode());
|
||||||
|
|
||||||
// Remove the record
|
// Remove the record
|
||||||
let record = {
|
let record = {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
@ -378,6 +387,8 @@ impl ReceiptManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_receipt(&self, node_ref: NodeRef, receipt: Receipt) -> Result<(), String> {
|
pub async fn handle_receipt(&self, node_ref: NodeRef, receipt: Receipt) -> Result<(), String> {
|
||||||
|
log_rpc!(debug "<<== RECEIPT {} <- {}", receipt.get_nonce().encode(), node_ref);
|
||||||
|
|
||||||
// Increment return count
|
// Increment return count
|
||||||
let callback_future = {
|
let callback_future = {
|
||||||
// Look up the receipt record from the nonce
|
// Look up the receipt record from the nonce
|
||||||
|
@ -91,7 +91,8 @@ impl BucketEntry {
|
|||||||
self.node_ref_tracks.remove(&track_id);
|
self.node_ref_tracks.remove(&track_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort_fastest(e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
// Less is faster
|
||||||
|
pub fn cmp_fastest(e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
||||||
// Lower latency to the front
|
// Lower latency to the front
|
||||||
if let Some(e1_latency) = &e1.peer_stats.latency {
|
if let Some(e1_latency) = &e1.peer_stats.latency {
|
||||||
if let Some(e2_latency) = &e2.peer_stats.latency {
|
if let Some(e2_latency) = &e2.peer_stats.latency {
|
||||||
@ -106,6 +107,7 @@ impl BucketEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Less is more reliable then faster
|
||||||
pub fn cmp_fastest_reliable(cur_ts: u64, e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
pub fn cmp_fastest_reliable(cur_ts: u64, e1: &Self, e2: &Self) -> std::cmp::Ordering {
|
||||||
// Reverse compare so most reliable is at front
|
// Reverse compare so most reliable is at front
|
||||||
let ret = e2.state(cur_ts).cmp(&e1.state(cur_ts));
|
let ret = e2.state(cur_ts).cmp(&e1.state(cur_ts));
|
||||||
|
@ -258,11 +258,9 @@ impl RoutingTable {
|
|||||||
dial_info: DialInfo,
|
dial_info: DialInfo,
|
||||||
class: DialInfoClass,
|
class: DialInfoClass,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
trace!(
|
log_rtab!(debug
|
||||||
"registering dial_info with:\n domain: {:?}\n dial_info: {:?}\n class: {:?}",
|
"Registering dial_info with:\n domain: {:?}\n dial_info: {:?}\n class: {:?}",
|
||||||
domain,
|
domain, dial_info, class
|
||||||
dial_info,
|
|
||||||
class
|
|
||||||
);
|
);
|
||||||
let enable_local_peer_scope = {
|
let enable_local_peer_scope = {
|
||||||
let config = self.network_manager().config();
|
let config = self.network_manager().config();
|
||||||
@ -680,37 +678,46 @@ impl RoutingTable {
|
|||||||
|
|
||||||
pub fn find_inbound_relay(&self, cur_ts: u64) -> Option<NodeRef> {
|
pub fn find_inbound_relay(&self, cur_ts: u64) -> Option<NodeRef> {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
let mut best_inbound_relay: Option<NodeRef> = None;
|
let inner = &mut *inner;
|
||||||
|
let mut best_inbound_relay: Option<(&DHTKey, &mut BucketEntry)> = None;
|
||||||
|
|
||||||
// Iterate all known nodes for candidates
|
// Iterate all known nodes for candidates
|
||||||
Self::with_entries(&mut *inner, cur_ts, BucketEntryState::Unreliable, |k, e| {
|
for bucket in &mut inner.buckets {
|
||||||
// Ensure this node is not on our local network
|
for (k, e) in bucket.entries_mut() {
|
||||||
if !e
|
if e.state(cur_ts) >= BucketEntryState::Unreliable {
|
||||||
.local_node_info()
|
// Ensure this node is not on our local network
|
||||||
.map(|l| l.has_dial_info())
|
if !e
|
||||||
.unwrap_or(false)
|
.local_node_info()
|
||||||
{
|
.map(|l| l.has_dial_info())
|
||||||
// Ensure we have the node's status
|
.unwrap_or(false)
|
||||||
if let Some(node_status) = &e.peer_stats().status {
|
{
|
||||||
// Ensure the node will relay
|
// Ensure we have the node's status
|
||||||
if node_status.will_relay {
|
if let Some(node_status) = &e.peer_stats().status {
|
||||||
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
|
// Ensure the node will relay
|
||||||
if best_inbound_relay
|
if node_status.will_relay {
|
||||||
.operate(|best| BucketEntry::cmp_fastest_reliable(cur_ts, best, e))
|
// Compare against previous candidate
|
||||||
== std::cmp::Ordering::Greater
|
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
|
||||||
{
|
// Less is faster
|
||||||
*best_inbound_relay = NodeRef::new(self.clone(), *k, e, None);
|
if BucketEntry::cmp_fastest_reliable(
|
||||||
|
cur_ts,
|
||||||
|
e,
|
||||||
|
best_inbound_relay.1,
|
||||||
|
) == std::cmp::Ordering::Less
|
||||||
|
{
|
||||||
|
*best_inbound_relay = (k, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Always store the first candidate
|
||||||
|
best_inbound_relay = Some((k, e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
best_inbound_relay = Some(NodeRef::new(self.clone(), *k, e, None));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Option::<()>::None
|
}
|
||||||
});
|
// Return the best inbound relay noderef
|
||||||
|
best_inbound_relay.map(|(k, e)| NodeRef::new(self.clone(), *k, e, None))
|
||||||
best_inbound_relay
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_find_node_answer(&self, fna: FindNodeAnswer) -> Result<Vec<NodeRef>, String> {
|
pub fn register_find_node_answer(&self, fna: FindNodeAnswer) -> Result<Vec<NodeRef>, String> {
|
||||||
@ -920,7 +927,7 @@ impl RoutingTable {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
log_rtab!("--- bootstrap_task");
|
log_rtab!(debug "--- bootstrap_task");
|
||||||
|
|
||||||
// If we aren't specifying a bootstrap node list explicitly, then pull from the bootstrap server(s)
|
// If we aren't specifying a bootstrap node list explicitly, then pull from the bootstrap server(s)
|
||||||
let bootstrap_node_dial_infos = if !bootstrap_nodes.is_empty() {
|
let bootstrap_node_dial_infos = if !bootstrap_nodes.is_empty() {
|
||||||
@ -952,12 +959,11 @@ impl RoutingTable {
|
|||||||
class: DialInfoClass::Direct, // Bootstraps are always directly reachable
|
class: DialInfoClass::Direct, // Bootstraps are always directly reachable
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
log_rtab!(" bootstrap node dialinfo: {:?}", bsmap);
|
|
||||||
|
|
||||||
// Run all bootstrap operations concurrently
|
// Run all bootstrap operations concurrently
|
||||||
let mut unord = FuturesUnordered::new();
|
let mut unord = FuturesUnordered::new();
|
||||||
for (k, v) in bsmap {
|
for (k, v) in bsmap {
|
||||||
log_rtab!(" bootstrapping {} with {:?}", k.encode(), &v);
|
log_rtab!("--- bootstrapping {} with {:?}", k.encode(), &v);
|
||||||
|
|
||||||
// Make invalid signed node info (no signature)
|
// Make invalid signed node info (no signature)
|
||||||
let nr = self
|
let nr = self
|
||||||
@ -970,7 +976,7 @@ impl RoutingTable {
|
|||||||
relay_peer_info: None, // Bootstraps never require a relay themselves
|
relay_peer_info: None, // Bootstraps never require a relay themselves
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.map_err(logthru_rtab!("Couldn't add bootstrap node: {}", k))?;
|
.map_err(logthru_rtab!(error "Couldn't add bootstrap node: {}", k))?;
|
||||||
|
|
||||||
// Add this our futures to process in parallel
|
// Add this our futures to process in parallel
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
@ -981,7 +987,7 @@ impl RoutingTable {
|
|||||||
|
|
||||||
// Ensure we got the signed peer info
|
// Ensure we got the signed peer info
|
||||||
if !nr.operate(|e| e.has_valid_signed_node_info()) {
|
if !nr.operate(|e| e.has_valid_signed_node_info()) {
|
||||||
warn!(
|
log_rtab!(warn
|
||||||
"bootstrap at {:?} did not return valid signed node info",
|
"bootstrap at {:?} did not return valid signed node info",
|
||||||
nr
|
nr
|
||||||
);
|
);
|
||||||
@ -1004,7 +1010,7 @@ impl RoutingTable {
|
|||||||
// Ask our remaining peers to give us more peers before we go
|
// Ask our remaining peers to give us more peers before we go
|
||||||
// back to the bootstrap servers to keep us from bothering them too much
|
// back to the bootstrap servers to keep us from bothering them too much
|
||||||
async fn peer_minimum_refresh_task_routine(self) -> Result<(), String> {
|
async fn peer_minimum_refresh_task_routine(self) -> Result<(), String> {
|
||||||
log_rtab!("--- peer_minimum_refresh task");
|
// log_rtab!("--- peer_minimum_refresh task");
|
||||||
|
|
||||||
// get list of all peers we know about, even the unreliable ones, and ask them to find nodes close to our node too
|
// get list of all peers we know about, even the unreliable ones, and ask them to find nodes close to our node too
|
||||||
let noderefs = {
|
let noderefs = {
|
||||||
@ -1022,12 +1028,11 @@ impl RoutingTable {
|
|||||||
);
|
);
|
||||||
noderefs
|
noderefs
|
||||||
};
|
};
|
||||||
log_rtab!(" refreshing with nodes: {:?}", noderefs);
|
|
||||||
|
|
||||||
// do peer minimum search concurrently
|
// do peer minimum search concurrently
|
||||||
let mut unord = FuturesUnordered::new();
|
let mut unord = FuturesUnordered::new();
|
||||||
for nr in noderefs {
|
for nr in noderefs {
|
||||||
debug!(" --- peer minimum search with {:?}", nr);
|
log_rtab!("--- peer minimum search with {:?}", nr);
|
||||||
unord.push(self.reverse_find_node(nr, false));
|
unord.push(self.reverse_find_node(nr, false));
|
||||||
}
|
}
|
||||||
while unord.next().await.is_some() {}
|
while unord.next().await.is_some() {}
|
||||||
|
@ -78,7 +78,7 @@ impl RespondTo {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct RPCMessageHeader {
|
struct RPCMessageHeader {
|
||||||
timestamp: u64,
|
timestamp: u64, // time the message was received, not sent
|
||||||
envelope: envelope::Envelope,
|
envelope: envelope::Envelope,
|
||||||
body_len: u64,
|
body_len: u64,
|
||||||
peer_noderef: NodeRef, // ensures node doesn't get evicted from routing table until we're done with it
|
peer_noderef: NodeRef, // ensures node doesn't get evicted from routing table until we're done with it
|
||||||
@ -911,6 +911,7 @@ impl RPCProcessor {
|
|||||||
if redirect {
|
if redirect {
|
||||||
let routing_table = self.routing_table();
|
let routing_table = self.routing_table();
|
||||||
let filter = dial_info.make_filter(true);
|
let filter = dial_info.make_filter(true);
|
||||||
|
let sender_id = rpcreader.header.envelope.get_sender_id();
|
||||||
let peers = routing_table.find_fast_public_nodes_filtered(&filter);
|
let peers = routing_table.find_fast_public_nodes_filtered(&filter);
|
||||||
if peers.is_empty() {
|
if peers.is_empty() {
|
||||||
return Err(rpc_error_internal(format!(
|
return Err(rpc_error_internal(format!(
|
||||||
@ -919,6 +920,12 @@ impl RPCProcessor {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
for peer in peers {
|
for peer in peers {
|
||||||
|
|
||||||
|
// Ensure the peer is not the one asking for the validation
|
||||||
|
if peer.node_id() == sender_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 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().status {
|
if let Some(ni) = &e.peer_stats().status {
|
||||||
@ -1259,7 +1266,7 @@ impl RPCProcessor {
|
|||||||
veilid_capnp::operation::detail::CancelTunnelA(_) => (25u32, false),
|
veilid_capnp::operation::detail::CancelTunnelA(_) => (25u32, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
log_rpc!(debug "<<== {}({}) <- {}",
|
log_rpc!(debug "<<== {}({}) <- {:?}",
|
||||||
if is_q { "REQUEST" } else { "REPLY" },
|
if is_q { "REQUEST" } else { "REPLY" },
|
||||||
self.get_rpc_message_debug_info(&reader),
|
self.get_rpc_message_debug_info(&reader),
|
||||||
msg.header.envelope.get_sender_id()
|
msg.header.envelope.get_sender_id()
|
||||||
@ -1604,10 +1611,17 @@ impl RPCProcessor {
|
|||||||
self.request(Destination::Direct(peer), vdi_msg, None)
|
self.request(Destination::Direct(peer), vdi_msg, None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
log_net!(debug "waiting for validate_dial_info receipt");
|
||||||
// Wait for receipt
|
// Wait for receipt
|
||||||
match eventual_value.await.take_value().unwrap() {
|
match eventual_value.await.take_value().unwrap() {
|
||||||
ReceiptEvent::Returned(_) => Ok(true),
|
ReceiptEvent::Returned(_) => {
|
||||||
ReceiptEvent::Expired => Ok(false),
|
log_net!(debug "validate_dial_info receipt returned");
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
ReceiptEvent::Expired => {
|
||||||
|
log_net!(debug "validate_dial_info receipt expired");
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
ReceiptEvent::Cancelled => {
|
ReceiptEvent::Cancelled => {
|
||||||
Err(rpc_error_internal("receipt was dropped before expiration"))
|
Err(rpc_error_internal("receipt was dropped before expiration"))
|
||||||
}
|
}
|
||||||
|
@ -63,15 +63,7 @@ pub fn retry_falloff_log(
|
|||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
// Exponential falloff between 'interval_start_us' and 'interval_max_us' microseconds
|
// Exponential falloff between 'interval_start_us' and 'interval_max_us' microseconds
|
||||||
// Optimal equation here is: y = Sum[Power[b,x],{n,0,x}] --> y = (x+1)b^x
|
last_us <= secs_to_timestamp(timestamp_to_secs(cur_us) / interval_multiplier_us)
|
||||||
// but we're just gonna simplify this to a log curve for speed
|
|
||||||
let last_secs = timestamp_to_secs(last_us);
|
|
||||||
let nth = (last_secs / timestamp_to_secs(interval_start_us))
|
|
||||||
.log(interval_multiplier_us)
|
|
||||||
.floor() as i32;
|
|
||||||
let next_secs = timestamp_to_secs(interval_start_us) * interval_multiplier_us.powi(nth + 1);
|
|
||||||
let next_us = secs_to_timestamp(next_secs);
|
|
||||||
cur_us >= next_us
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,6 +1186,8 @@ mod tests {
|
|||||||
listen_address_to_socket_addrs("localhost:5959").unwrap()
|
listen_address_to_socket_addrs("localhost:5959").unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(s.auto_attach, true);
|
assert_eq!(s.auto_attach, true);
|
||||||
|
assert_eq!(s.logging.system.enabled, false);
|
||||||
|
assert_eq!(s.logging.system.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.terminal.enabled, true);
|
assert_eq!(s.logging.terminal.enabled, true);
|
||||||
assert_eq!(s.logging.terminal.level, LogLevel::Info);
|
assert_eq!(s.logging.terminal.level, LogLevel::Info);
|
||||||
assert_eq!(s.logging.file.enabled, false);
|
assert_eq!(s.logging.file.enabled, false);
|
||||||
|
Loading…
Reference in New Issue
Block a user