network class refactor checkpoint
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
mod network_class_discovery;
|
||||
mod network_tcp;
|
||||
mod network_udp;
|
||||
mod protocol;
|
||||
mod public_dialinfo_discovery;
|
||||
mod start_protocols;
|
||||
|
||||
use crate::connection_manager::*;
|
||||
@@ -41,9 +41,7 @@ struct NetworkInner {
|
||||
network_started: bool,
|
||||
network_needs_restart: bool,
|
||||
protocol_config: Option<ProtocolConfig>,
|
||||
udp_static_public_dialinfo: bool,
|
||||
tcp_static_public_dialinfo: bool,
|
||||
ws_static_public_dialinfo: bool,
|
||||
static_public_dialinfo: ProtocolSet,
|
||||
network_class: Option<NetworkClass>,
|
||||
join_handles: Vec<JoinHandle<()>>,
|
||||
udp_port: u16,
|
||||
@@ -64,7 +62,7 @@ struct NetworkInner {
|
||||
|
||||
struct NetworkUnlockedInner {
|
||||
// Background processes
|
||||
update_public_dialinfo_task: TickTask,
|
||||
update_network_class_task: TickTask,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -82,9 +80,7 @@ impl Network {
|
||||
network_started: false,
|
||||
network_needs_restart: false,
|
||||
protocol_config: None,
|
||||
udp_static_public_dialinfo: false,
|
||||
tcp_static_public_dialinfo: false,
|
||||
ws_static_public_dialinfo: false,
|
||||
static_public_dialinfo: ProtocolSet::empty(),
|
||||
network_class: None,
|
||||
join_handles: Vec::new(),
|
||||
udp_port: 0u16,
|
||||
@@ -104,7 +100,7 @@ impl Network {
|
||||
|
||||
fn new_unlocked_inner() -> NetworkUnlockedInner {
|
||||
NetworkUnlockedInner {
|
||||
update_public_dialinfo_task: TickTask::new(1),
|
||||
update_network_class_task: TickTask::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,13 +111,13 @@ impl Network {
|
||||
unlocked_inner: Arc::new(Self::new_unlocked_inner()),
|
||||
};
|
||||
|
||||
// Set public dialinfo tick task
|
||||
// Set update network class tick task
|
||||
{
|
||||
let this2 = this.clone();
|
||||
this.unlocked_inner
|
||||
.update_public_dialinfo_task
|
||||
.update_network_class_task
|
||||
.set_routine(move |l, t| {
|
||||
Box::pin(this2.clone().update_public_dialinfo_task_routine(l, t))
|
||||
Box::pin(this2.clone().update_network_class_task_routine(l, t))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -239,6 +235,26 @@ impl Network {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_interface_addresses<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[IpAddr]) -> R,
|
||||
{
|
||||
let inner = self.inner.lock();
|
||||
inner.interfaces.with_best_addresses(f)
|
||||
}
|
||||
|
||||
// See if our interface addresses have changed, if so we need to punt the network
|
||||
// and redo all our addresses. This is overkill, but anything more accurate
|
||||
// would require inspection of routing tables that we dont want to bother with
|
||||
pub async fn check_interface_addresses(&self) -> Result<bool, String> {
|
||||
let mut inner = self.inner.lock();
|
||||
if !inner.interfaces.refresh().await? {
|
||||
return Ok(false);
|
||||
}
|
||||
inner.network_needs_restart = true;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Send data to a dial info, unbound, using a new connection from a random port
|
||||
@@ -386,34 +402,50 @@ impl Network {
|
||||
// get protocol config
|
||||
let protocol_config = {
|
||||
let c = self.config.get();
|
||||
ProtocolConfig {
|
||||
inbound: ProtocolSet {
|
||||
udp: c.network.protocol.udp.enabled && c.capabilities.protocol_udp,
|
||||
tcp: c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp,
|
||||
ws: c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws,
|
||||
wss: 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,
|
||||
},
|
||||
let mut inbound = ProtocolSet::new();
|
||||
|
||||
if c.network.protocol.udp.enabled && c.capabilities.protocol_udp {
|
||||
inbound.insert(ProtocolType::UDP);
|
||||
}
|
||||
if c.network.protocol.tcp.listen && c.capabilities.protocol_accept_tcp {
|
||||
inbound.insert(ProtocolType::TCP);
|
||||
}
|
||||
if c.network.protocol.ws.listen && c.capabilities.protocol_accept_ws {
|
||||
inbound.insert(ProtocolType::WS);
|
||||
}
|
||||
if c.network.protocol.wss.listen && c.capabilities.protocol_accept_wss {
|
||||
inbound.insert(ProtocolType::WSS);
|
||||
}
|
||||
|
||||
let mut outbound = ProtocolSet::new();
|
||||
if c.network.protocol.udp.enabled && c.capabilities.protocol_udp {
|
||||
outbound.insert(ProtocolType::UDP);
|
||||
}
|
||||
if c.network.protocol.tcp.connect && c.capabilities.protocol_connect_tcp {
|
||||
outbound.insert(ProtocolType::TCP);
|
||||
}
|
||||
if c.network.protocol.ws.connect && c.capabilities.protocol_connect_ws {
|
||||
outbound.insert(ProtocolType::WS);
|
||||
}
|
||||
if c.network.protocol.wss.connect && c.capabilities.protocol_connect_wss {
|
||||
outbound.insert(ProtocolType::WSS);
|
||||
}
|
||||
|
||||
ProtocolConfig { inbound, outbound }
|
||||
};
|
||||
self.inner.lock().protocol_config = Some(protocol_config);
|
||||
|
||||
// start listeners
|
||||
if protocol_config.inbound.udp {
|
||||
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
||||
self.start_udp_listeners().await?;
|
||||
}
|
||||
if protocol_config.inbound.ws {
|
||||
if protocol_config.inbound.contains(ProtocolType::WS) {
|
||||
self.start_ws_listeners().await?;
|
||||
}
|
||||
if protocol_config.inbound.wss {
|
||||
if protocol_config.inbound.contains(ProtocolType::WSS) {
|
||||
self.start_wss_listeners().await?;
|
||||
}
|
||||
if protocol_config.inbound.tcp {
|
||||
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
||||
self.start_tcp_listeners().await?;
|
||||
}
|
||||
|
||||
@@ -431,17 +463,21 @@ impl Network {
|
||||
self.inner.lock().network_needs_restart
|
||||
}
|
||||
|
||||
pub fn restart_network(&self) {
|
||||
self.inner.lock().network_needs_restart = true;
|
||||
}
|
||||
|
||||
pub async fn shutdown(&self) {
|
||||
info!("stopping network");
|
||||
|
||||
let network_manager = self.network_manager();
|
||||
let routing_table = self.routing_table();
|
||||
|
||||
// Reset state
|
||||
|
||||
// Drop all dial info
|
||||
routing_table.clear_dial_info_details();
|
||||
routing_table.clear_dial_info_details(RoutingDomain::PublicInternet);
|
||||
routing_table.clear_dial_info_details(RoutingDomain::LocalNetwork);
|
||||
|
||||
// Reset state including network class
|
||||
// Cancels all async background tasks by dropping join handles
|
||||
*self.inner.lock() = Self::new_inner(network_manager);
|
||||
|
||||
@@ -451,109 +487,22 @@ impl Network {
|
||||
//////////////////////////////////////////
|
||||
pub fn get_network_class(&self) -> Option<NetworkClass> {
|
||||
let inner = self.inner.lock();
|
||||
if !inner.network_started {
|
||||
return None;
|
||||
}
|
||||
return inner.network_class;
|
||||
}
|
||||
|
||||
// If we've fixed the network class, return it rather than calculating it
|
||||
if inner.network_class.is_some() {
|
||||
return inner.network_class;
|
||||
}
|
||||
|
||||
// Go through our global dialinfo and see what our best network class is
|
||||
let mut network_class = NetworkClass::Invalid;
|
||||
for did in inner.routing_table.public_dial_info_details() {
|
||||
if let Some(nc) = did.network_class {
|
||||
if nc < network_class {
|
||||
network_class = nc;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(network_class)
|
||||
pub fn reset_network_class(&self) {
|
||||
let inner = self.inner.lock();
|
||||
inner.network_class = None;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
pub async fn tick(&self) -> Result<(), String> {
|
||||
let (
|
||||
routing_table,
|
||||
protocol_config,
|
||||
udp_static_public_dialinfo,
|
||||
tcp_static_public_dialinfo,
|
||||
ws_static_public_dialinfo,
|
||||
network_class,
|
||||
) = {
|
||||
let inner = self.inner.lock();
|
||||
(
|
||||
inner.routing_table.clone(),
|
||||
inner.protocol_config.unwrap_or_default(),
|
||||
inner.udp_static_public_dialinfo,
|
||||
inner.tcp_static_public_dialinfo,
|
||||
inner.ws_static_public_dialinfo,
|
||||
inner.network_class.unwrap_or(NetworkClass::Invalid),
|
||||
)
|
||||
};
|
||||
let network_class = self.get_network_class().unwrap_or(NetworkClass::Invalid);
|
||||
|
||||
// See if we have any UDPv4 public dialinfo, and if we should have it
|
||||
// If we have statically configured public dialinfo, don't bother with this
|
||||
// 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 assess our network class if we haven't already
|
||||
if (network_class.inbound_capable() || network_class == NetworkClass::Invalid)
|
||||
&&
|
||||
{
|
||||
let filter = DialInfoFilter::global()
|
||||
.with_protocol_type(ProtocolType::TCP)
|
||||
.with_address_type(AddressType::IPV4);
|
||||
let need_tcpv4_dialinfo = routing_table
|
||||
.first_public_filtered_dial_info_detail(&filter)
|
||||
.is_none();
|
||||
if need_tcpv4_dialinfo {
|
||||
}
|
||||
|
||||
self.unlocked_inner
|
||||
.update_public_dialinfo_task
|
||||
.tick()
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Same but for TCPv4
|
||||
if protocol_config.inbound.tcp
|
||||
&& !tcp_static_public_dialinfo
|
||||
&& (network_class.inbound_capable() || network_class == NetworkClass::Invalid)
|
||||
{
|
||||
let filter = DialInfoFilter::all()
|
||||
.with_protocol_type(ProtocolType::TCP)
|
||||
.with_address_type(AddressType::IPV4);
|
||||
let need_tcpv4_dialinfo = routing_table
|
||||
.first_public_filtered_dial_info_detail(&filter)
|
||||
.is_none();
|
||||
if need_tcpv4_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_tcpv4_dialinfo_task
|
||||
.tick()
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
// 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?;
|
||||
}
|
||||
// If we need to figure out our network class, tick the task for it
|
||||
if network_class == NetworkClass::Invalid {
|
||||
self.unlocked_inner.update_network_class_task.tick().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@@ -60,7 +60,7 @@ impl Network {
|
||||
.with_protocol_type(protocol_type)
|
||||
.with_address_type(address_type);
|
||||
routing_table
|
||||
.interface_dial_info_details()
|
||||
.dial_info_details(RoutingDomain::LocalNetwork)
|
||||
.iter()
|
||||
.filter_map(|did| {
|
||||
if did.dial_info.matches_filter(&filter) {
|
||||
@@ -100,7 +100,7 @@ impl Network {
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn update_udpv4_dialinfo_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
||||
pub async fn update_udpv4_dialinfo(&self) -> Result<(), String> {
|
||||
log_net!("looking for udpv4 public dial info");
|
||||
let routing_table = self.routing_table();
|
||||
|
||||
@@ -258,17 +258,42 @@ impl Network {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_tcpv4_dialinfo_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
||||
pub async fn update_tcpv4_dialinfo(&self) -> Result<(), String> {
|
||||
log_net!("looking for tcpv4 public dial info");
|
||||
// xxx
|
||||
//Err("unimplemented".to_owned())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_wsv4_dialinfo_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
||||
pub async fn update_wsv4_dialinfo(&self) -> Result<(), String> {
|
||||
log_net!("looking for wsv4 public dial info");
|
||||
// xxx
|
||||
//Err("unimplemented".to_owned())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_network_class_task_routine(self, _l: u64, _t: u64) -> Result<(), String> {
|
||||
log_net!("updating network class");
|
||||
|
||||
let protocol_config = self
|
||||
.inner
|
||||
.lock()
|
||||
.protocol_config
|
||||
.clone()
|
||||
.unwrap_or_default();
|
||||
|
||||
if protocol_config.inbound.contains(ProtocolType::UDP) {
|
||||
self.update_udpv4_dialinfo().await?;
|
||||
}
|
||||
|
||||
if protocol_config.inbound.contains(ProtocolType::TCP) {
|
||||
self.update_tcpv4_dialinfo().await?;
|
||||
}
|
||||
|
||||
if protocol_config.inbound.contains(ProtocolType::WS) {
|
||||
self.update_wsv4_dialinfo().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -261,11 +261,12 @@ impl Network {
|
||||
pub(super) async fn start_udp_listeners(&self) -> Result<(), String> {
|
||||
trace!("starting udp listeners");
|
||||
let routing_table = self.routing_table();
|
||||
let (listen_address, public_address) = {
|
||||
let (listen_address, public_address, enable_local_peer_scope) = {
|
||||
let c = self.config.get();
|
||||
(
|
||||
c.network.protocol.udp.listen_address.clone(),
|
||||
c.network.protocol.udp.public_address.clone(),
|
||||
c.network.enable_local_peer_scope,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -287,23 +288,28 @@ impl Network {
|
||||
"UDP: starting listeners on port {} at {:?}",
|
||||
udp_port, ip_addrs
|
||||
);
|
||||
let dial_info_list = self.create_udp_inbound_sockets(ip_addrs, udp_port).await?;
|
||||
let local_dial_info_list = self.create_udp_inbound_sockets(ip_addrs, udp_port).await?;
|
||||
let mut static_public = false;
|
||||
for di in &dial_info_list {
|
||||
// If the local interface address is global,
|
||||
|
||||
// Register local dial info
|
||||
for di in &local_dial_info_list {
|
||||
// If the local interface address is global, or we are enabling local peer scope
|
||||
// register global dial info if no public address is specified
|
||||
if public_address.is_none() && di.is_global() {
|
||||
routing_table.register_public_dial_info(
|
||||
if public_address.is_none() && (di.is_global() || enable_local_peer_scope) {
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
di.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
|
||||
static_public = true;
|
||||
}
|
||||
|
||||
// Register interface dial info as well since the address is on the local interface
|
||||
routing_table.register_interface_dial_info(di.clone(), DialInfoOrigin::Static);
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
di.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
// Add static public dialinfo if it's configured
|
||||
@@ -316,16 +322,43 @@ impl Network {
|
||||
|
||||
// Add all resolved addresses as public dialinfo
|
||||
for pdi_addr in &mut public_sockaddrs {
|
||||
routing_table.register_public_dial_info(
|
||||
DialInfo::udp_from_socketaddr(pdi_addr),
|
||||
let pdi = DialInfo::udp_from_socketaddr(pdi_addr);
|
||||
|
||||
// Register the public address
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
pdi.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
|
||||
// See if this public address is also a local interface address
|
||||
if !local_dial_info_list.contains(&pdi)
|
||||
&& self.with_interface_addresses(|ip_addrs| {
|
||||
for ip_addr in ip_addrs {
|
||||
if pdi_addr.ip() == *ip_addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
{
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
DialInfo::udp_from_socketaddr(pdi_addr),
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
static_public = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.inner.lock().udp_static_public_dialinfo = static_public;
|
||||
if static_public {
|
||||
self.inner
|
||||
.lock()
|
||||
.static_public_dialinfo
|
||||
.insert(ProtocolType::UDP);
|
||||
}
|
||||
|
||||
// Now create tasks for udp listeners
|
||||
self.create_udp_listener_tasks().await
|
||||
@@ -334,12 +367,13 @@ impl Network {
|
||||
pub(super) async fn start_ws_listeners(&self) -> Result<(), String> {
|
||||
trace!("starting ws listeners");
|
||||
let routing_table = self.routing_table();
|
||||
let (listen_address, url, path) = {
|
||||
let (listen_address, url, path, enable_local_peer_scope) = {
|
||||
let c = self.config.get();
|
||||
(
|
||||
c.network.protocol.ws.listen_address.clone(),
|
||||
c.network.protocol.ws.url.clone(),
|
||||
c.network.protocol.ws.path.clone(),
|
||||
c.network.enable_local_peer_scope,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -367,31 +401,7 @@ impl Network {
|
||||
trace!("WS: listener started");
|
||||
|
||||
let mut static_public = false;
|
||||
for socket_address in socket_addresses {
|
||||
if url.is_none() && socket_address.address().is_global() {
|
||||
// Build global dial info request url
|
||||
let global_url = format!("ws://{}/{}", socket_address, path);
|
||||
|
||||
// Create global dial info
|
||||
let di = DialInfo::try_ws(socket_address, global_url)
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?;
|
||||
routing_table.register_public_dial_info(
|
||||
di,
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
static_public = true;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
|
||||
|
||||
// Add static public dialinfo if it's configured
|
||||
if let Some(url) = url.as_ref() {
|
||||
@@ -410,17 +420,74 @@ impl Network {
|
||||
.map_err(logthru_net!(error))?;
|
||||
|
||||
for gsa in global_socket_addrs {
|
||||
routing_table.register_public_dial_info(
|
||||
DialInfo::try_ws(SocketAddress::from_socket_addr(gsa), url.clone())
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?,
|
||||
let pdi = DialInfo::try_ws(SocketAddress::from_socket_addr(gsa), url.clone())
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?;
|
||||
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
pdi.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
static_public = true;
|
||||
|
||||
// See if this public address is also a local interface address
|
||||
if !registered_addresses.contains(&gsa.ip())
|
||||
&& self.with_interface_addresses(|ip_addrs| {
|
||||
for ip_addr in ip_addrs {
|
||||
if gsa.ip() == *ip_addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
{
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
pdi,
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
registered_addresses.insert(gsa.ip());
|
||||
}
|
||||
static_public = true;
|
||||
}
|
||||
self.inner.lock().ws_static_public_dialinfo = static_public;
|
||||
|
||||
for socket_address in socket_addresses {
|
||||
// Skip addresses we already did
|
||||
if registered_addresses.contains(&socket_address.to_ip_addr()) {
|
||||
continue;
|
||||
}
|
||||
// Build dial info request url
|
||||
let local_url = format!("ws://{}/{}", socket_address, path);
|
||||
let local_di = DialInfo::try_ws(socket_address, local_url)
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?;
|
||||
|
||||
if url.is_none() && (socket_address.address().is_global() || enable_local_peer_scope) {
|
||||
// Register public dial info
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
local_di.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
static_public = true;
|
||||
}
|
||||
|
||||
// Register local dial info
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
local_di,
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
if static_public {
|
||||
self.inner
|
||||
.lock()
|
||||
.static_public_dialinfo
|
||||
.insert(ProtocolType::WS);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -429,11 +496,12 @@ impl Network {
|
||||
trace!("starting wss listeners");
|
||||
|
||||
let routing_table = self.routing_table();
|
||||
let (listen_address, url) = {
|
||||
let (listen_address, url, enable_local_peer_scope) = {
|
||||
let c = self.config.get();
|
||||
(
|
||||
c.network.protocol.wss.listen_address.clone(),
|
||||
c.network.protocol.wss.url.clone(),
|
||||
c.network.enable_local_peer_scope,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -465,6 +533,9 @@ impl Network {
|
||||
// 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
|
||||
|
||||
let mut static_public = false;
|
||||
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
|
||||
|
||||
// Add static public dialinfo if it's configured
|
||||
if let Some(url) = url.as_ref() {
|
||||
// Add static public dialinfo if it's configured
|
||||
@@ -483,18 +554,48 @@ impl Network {
|
||||
.map_err(logthru_net!(error))?;
|
||||
|
||||
for gsa in global_socket_addrs {
|
||||
routing_table.register_public_dial_info(
|
||||
DialInfo::try_wss(SocketAddress::from_socket_addr(gsa), url.clone())
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?,
|
||||
let pdi = DialInfo::try_wss(SocketAddress::from_socket_addr(gsa), url.clone())
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_net!(error))?;
|
||||
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
pdi.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
static_public = true;
|
||||
|
||||
// See if this public address is also a local interface address
|
||||
if !registered_addresses.contains(&gsa.ip())
|
||||
&& self.with_interface_addresses(|ip_addrs| {
|
||||
for ip_addr in ip_addrs {
|
||||
if gsa.ip() == *ip_addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
{
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
pdi,
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
registered_addresses.insert(gsa.ip());
|
||||
}
|
||||
} else {
|
||||
return Err("WSS URL must be specified due to TLS requirements".to_owned());
|
||||
}
|
||||
|
||||
if static_public {
|
||||
self.inner
|
||||
.lock()
|
||||
.static_public_dialinfo
|
||||
.insert(ProtocolType::WSS);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -502,11 +603,12 @@ impl Network {
|
||||
trace!("starting tcp listeners");
|
||||
|
||||
let routing_table = self.routing_table();
|
||||
let (listen_address, public_address) = {
|
||||
let (listen_address, public_address, enable_local_peer_scope) = {
|
||||
let c = self.config.get();
|
||||
(
|
||||
c.network.protocol.tcp.listen_address.clone(),
|
||||
c.network.protocol.tcp.public_address.clone(),
|
||||
c.network.enable_local_peer_scope,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -534,20 +636,27 @@ impl Network {
|
||||
trace!("TCP: listener started");
|
||||
|
||||
let mut static_public = false;
|
||||
let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
|
||||
|
||||
for socket_address in socket_addresses {
|
||||
let di = DialInfo::tcp(socket_address);
|
||||
|
||||
// Register global dial info if no public address is specified
|
||||
if public_address.is_none() && di.is_global() {
|
||||
routing_table.register_public_dial_info(
|
||||
if public_address.is_none() && (di.is_global() || enable_local_peer_scope) {
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
di.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
Some(NetworkClass::Server),
|
||||
);
|
||||
static_public = true;
|
||||
}
|
||||
// Register interface dial info
|
||||
routing_table.register_interface_dial_info(di.clone(), DialInfoOrigin::Static);
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
di.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
registered_addresses.insert(socket_address.to_ip_addr());
|
||||
}
|
||||
|
||||
// Add static public dialinfo if it's configured
|
||||
@@ -560,16 +669,45 @@ impl Network {
|
||||
|
||||
// Add all resolved addresses as public dialinfo
|
||||
for pdi_addr in &mut public_sockaddrs {
|
||||
routing_table.register_public_dial_info(
|
||||
DialInfo::tcp_from_socketaddr(pdi_addr),
|
||||
// Skip addresses we already did
|
||||
if registered_addresses.contains(&pdi_addr.ip()) {
|
||||
continue;
|
||||
}
|
||||
let pdi = DialInfo::tcp_from_socketaddr(pdi_addr);
|
||||
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::PublicInternet,
|
||||
pdi.clone(),
|
||||
DialInfoOrigin::Static,
|
||||
None,
|
||||
);
|
||||
static_public = true;
|
||||
|
||||
// See if this public address is also a local interface address
|
||||
if self.with_interface_addresses(|ip_addrs| {
|
||||
for ip_addr in ip_addrs {
|
||||
if pdi_addr.ip() == *ip_addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}) {
|
||||
routing_table.register_dial_info(
|
||||
RoutingDomain::LocalNetwork,
|
||||
pdi,
|
||||
DialInfoOrigin::Static,
|
||||
);
|
||||
}
|
||||
|
||||
static_public = true;
|
||||
}
|
||||
}
|
||||
|
||||
self.inner.lock().tcp_static_public_dialinfo = static_public;
|
||||
if static_public {
|
||||
self.inner
|
||||
.lock()
|
||||
.static_public_dialinfo
|
||||
.insert(ProtocolType::TCP);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@@ -295,6 +295,7 @@ impl NetworkInterface {
|
||||
pub struct NetworkInterfaces {
|
||||
valid: bool,
|
||||
interfaces: BTreeMap<String, NetworkInterface>,
|
||||
interface_address_cache: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for NetworkInterfaces {
|
||||
@@ -317,6 +318,7 @@ impl NetworkInterfaces {
|
||||
Self {
|
||||
valid: false,
|
||||
interfaces: BTreeMap::new(),
|
||||
interface_address_cache: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
@@ -324,6 +326,7 @@ impl NetworkInterfaces {
|
||||
}
|
||||
pub fn clear(&mut self) {
|
||||
self.interfaces.clear();
|
||||
self.interface_address_cache.clear();
|
||||
self.valid = false;
|
||||
}
|
||||
// returns Ok(false) if refresh had no changes, Ok(true) if changes were present
|
||||
@@ -341,6 +344,8 @@ impl NetworkInterfaces {
|
||||
let changed = last_interfaces != self.interfaces;
|
||||
if changed {
|
||||
trace!("NetworkInterfaces refreshed: {:#?}?", self);
|
||||
|
||||
self.cache_best_addresses();
|
||||
}
|
||||
Ok(changed)
|
||||
}
|
||||
@@ -351,7 +356,7 @@ impl NetworkInterfaces {
|
||||
self.interfaces.iter()
|
||||
}
|
||||
|
||||
pub fn best_addresses(&self) -> Vec<IpAddr> {
|
||||
fn cache_best_addresses(&mut self) {
|
||||
// Reduce interfaces to their best routable ip addresses
|
||||
let mut intf_addrs = Vec::new();
|
||||
for intf in self.interfaces.values() {
|
||||
@@ -370,6 +375,17 @@ impl NetworkInterfaces {
|
||||
intf_addrs.sort();
|
||||
|
||||
// Now export just the addresses
|
||||
intf_addrs.iter().map(|x| x.if_addr().ip()).collect()
|
||||
self.interface_address_cache = intf_addrs.iter().map(|x| x.if_addr().ip()).collect()
|
||||
}
|
||||
|
||||
pub fn best_addresses(&self) -> Vec<IpAddr> {
|
||||
self.interface_address_cache.clone()
|
||||
}
|
||||
|
||||
pub fn with_best_addresses<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[IpAddr]) -> R,
|
||||
{
|
||||
f(&self.interface_address_cache)
|
||||
}
|
||||
}
|
||||
|
@@ -162,6 +162,10 @@ impl Network {
|
||||
self.inner.lock().network_needs_restart
|
||||
}
|
||||
|
||||
pub fn restart_network(&self) {
|
||||
self.inner.lock().network_needs_restart = true;
|
||||
}
|
||||
|
||||
pub async fn shutdown(&self) {
|
||||
trace!("stopping network");
|
||||
|
||||
@@ -178,6 +182,18 @@ impl Network {
|
||||
trace!("network stopped");
|
||||
}
|
||||
|
||||
pub fn with_interface_addresses<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[IpAddr]) -> R,
|
||||
{
|
||||
f(&[])
|
||||
}
|
||||
|
||||
pub async fn check_interface_addresses(&self) -> Result<bool, String> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
pub fn get_network_class(&self) -> Option<NetworkClass> {
|
||||
// xxx eventually detect tor browser?
|
||||
|
Reference in New Issue
Block a user