Deprecate WSS via feature flag

This commit is contained in:
Christien Rioux 2025-09-07 17:25:25 -04:00
parent 88e0d420b4
commit dbc5bd495b
34 changed files with 441 additions and 1517 deletions

View file

@ -24,6 +24,7 @@
- Crypto / CryptoSystem functions now use typed keys everywhere (#483)
- Eliminated 'best' CryptoKind concept, crypto kinds must now be explicitly stated, otherwise upgrades of veilid-core that change the 'best' CryptoKind could break functionality silently.
- Encryption is enabled by default for all DHT operations, closes [#300](https://gitlab.com/veilid/veilid/-/issues/300) (@neequ57)
- Deprecation of WSS config and removal of Application config
- veilid-core:
- Add private route example
@ -40,6 +41,7 @@
- Update keyring-manager to eliminate licensing issue
- Added 'tick lag' detection to check for missed watch updates
- Added 'DHT Widening', separates consensus width (server side dht operation acceptance) from consensus count (client side), fixes [#435](https://gitlab.com/veilid/veilid/-/issues/435)
- Deprecation of WSS protocol, closes [#487](https://gitlab.com/veilid/veilid/-/issues/487)
- veilid-python:
- Correction of type hints

View file

@ -64,6 +64,9 @@ enable-crypto-none = [
"digest",
]
# Protocol support features
enable-protocol-wss = []
# Debugging and testing features
verbose-tracing = []
tracking = []

View file

@ -47,6 +47,7 @@ where
"W" => {
format!("ws://{}:{}", hostname, &short[1..])
}
#[cfg(feature = "enable-protocol-wss")]
"S" => {
format!("wss://{}:{}", hostname, &short[1..])
}
@ -66,6 +67,7 @@ where
.port
.ok_or_else(|| VeilidAPIError::parse_error("Missing port in udp url", url))?,
"ws" => split_url.port.unwrap_or(80u16),
#[cfg(feature = "enable-protocol-wss")]
"wss" => split_url.port.unwrap_or(443u16),
_ => {
apibail_parse_error!("Invalid dial info url scheme", split_url.scheme);
@ -92,6 +94,7 @@ where
SocketAddress::from_socket_addr(sa).canonical(),
url.to_string(),
)?,
#[cfg(feature = "enable-protocol-wss")]
"wss" => DialInfo::try_wss(
SocketAddress::from_socket_addr(sa).canonical(),
url.to_string(),
@ -141,6 +144,7 @@ where
hostname: split_url.host.to_string(),
}
}
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(di) => {
let mut split_url =
SplitUrl::from_str(&format!("wss://{}", di.request)).unwrap();
@ -188,6 +192,7 @@ where
}
split_url.to_string()
}
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(di) => {
let mut split_url =
SplitUrl::from_str(&format!("wss://{}", di.request)).unwrap();

View file

@ -41,6 +41,7 @@ impl NetworkManager {
ProtocolType::UDP,
ProtocolType::TCP,
ProtocolType::WS,
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS,
];

View file

@ -41,12 +41,12 @@ pub enum ConnectionRefKind {
#[derive(Debug)]
struct ConnectionTableInner {
max_connections: Vec<usize>,
conn_by_id: Vec<LruCache<NetworkConnectionId, NetworkConnection>>,
protocol_index_by_id: BTreeMap<NetworkConnectionId, usize>,
max_connections: BTreeMap<ProtocolType, usize>,
conn_by_id: BTreeMap<ProtocolType, LruCache<NetworkConnectionId, NetworkConnection>>,
protocol_type_by_id: BTreeMap<NetworkConnectionId, ProtocolType>,
id_by_flow: BTreeMap<Flow, NetworkConnectionId>,
ids_by_remote: BTreeMap<PeerAddress, Vec<NetworkConnectionId>>,
priority_flows: Vec<LruCache<Flow, ()>>,
priority_flows: BTreeMap<ProtocolType, LruCache<Flow, ()>>,
}
#[derive(Debug)]
@ -62,62 +62,57 @@ impl ConnectionTable {
let config = registry.config();
let max_connections = {
let c = config.get();
vec![
let mut max_connections = BTreeMap::<ProtocolType, usize>::new();
max_connections.insert(
ProtocolType::TCP,
c.network.protocol.tcp.max_connections as usize,
);
max_connections.insert(
ProtocolType::WS,
c.network.protocol.ws.max_connections as usize,
);
#[cfg(feature = "enable-protocol-wss")]
max_connections.insert(
ProtocolType::WSS,
c.network.protocol.wss.max_connections as usize,
]
);
max_connections
};
Self {
registry,
inner: Mutex::new(ConnectionTableInner {
conn_by_id: max_connections
.iter()
.map(|_| LruCache::new_unbounded())
.keys()
.map(|pt| (*pt, LruCache::new_unbounded()))
.collect(),
protocol_index_by_id: BTreeMap::new(),
protocol_type_by_id: BTreeMap::new(),
id_by_flow: BTreeMap::new(),
ids_by_remote: BTreeMap::new(),
priority_flows: max_connections
.iter()
.map(|x| LruCache::new(x * PRIORITY_FLOW_PERCENTAGE / 100))
.map(|(pt, x)| (*pt, LruCache::new(*x * PRIORITY_FLOW_PERCENTAGE / 100)))
.collect(),
max_connections,
}),
}
}
fn protocol_to_index(protocol: ProtocolType) -> usize {
match protocol {
ProtocolType::TCP => 0,
ProtocolType::WS => 1,
ProtocolType::WSS => 2,
ProtocolType::UDP => panic!("not a connection-oriented protocol"),
}
}
fn index_to_protocol(idx: usize) -> ProtocolType {
match idx {
0 => ProtocolType::TCP,
1 => ProtocolType::WS,
2 => ProtocolType::WSS,
_ => panic!("not a connection-oriented protocol"),
}
}
#[instrument(level = "trace", skip(self))]
pub async fn join(&self) {
let mut unord = {
let mut inner = self.inner.lock();
let unord = FuturesUnordered::new();
for table in &mut inner.conn_by_id {
for (pt, table) in &mut inner.conn_by_id {
for (_, mut v) in table.drain() {
veilid_log!(self trace "connection table join: {:?}", v);
veilid_log!(self trace "connection table {} join: {:?}", pt, v);
v.close();
unord.push(v);
}
}
inner.protocol_index_by_id.clear();
inner.protocol_type_by_id.clear();
inner.id_by_flow.clear();
inner.ids_by_remote.clear();
unord
@ -165,8 +160,12 @@ impl ConnectionTable {
/// If connections 'must' stay alive, use 'NetworkConnection::protect'.
pub fn add_priority_flow(&self, flow: Flow) {
let mut inner = self.inner.lock();
let protocol_index = Self::protocol_to_index(flow.protocol_type());
inner.priority_flows[protocol_index].insert(flow, ());
let protocol_type = flow.protocol_type();
if let Some(pf) = inner.priority_flows.get_mut(&protocol_type) {
pf.insert(flow, ());
} else {
veilid_log!(self error "Missing priority flow table for protocol type: {}", protocol_type);
}
}
/// The mechanism for selecting which connections get evicted from the connection table
@ -175,22 +174,22 @@ impl ConnectionTable {
fn lru_out_connection_inner(
&self,
inner: &mut ConnectionTableInner,
protocol_index: usize,
protocol_type: ProtocolType,
) -> Result<Option<NetworkConnection>, ()> {
// If nothing needs to be LRUd out right now, then just return
if inner.conn_by_id[protocol_index].len() < inner.max_connections[protocol_index] {
if inner.conn_by_id[&protocol_type].len() < inner.max_connections[&protocol_type] {
return Ok(None);
}
// Find a free connection to terminate to make room
let dead_k = {
let Some(lruk) = inner.conn_by_id[protocol_index].iter().find_map(|(k, v)| {
let Some(lruk) = inner.conn_by_id[&protocol_type].iter().find_map(|(k, v)| {
// Ensure anything being LRU evicted isn't protected somehow
// 1. connections that are 'in-use' are kept
// 2. connections with flows in the priority list are kept
// 3. connections that are protected are kept
if !v.is_in_use()
&& !inner.priority_flows[protocol_index].contains_key(&v.flow())
&& !inner.priority_flows[&protocol_type].contains_key(&v.flow())
&& v.protected_node_ref().is_none()
{
Some(*k)
@ -216,7 +215,7 @@ impl ConnectionTable {
// Get indices for network connection table
let id = network_connection.connection_id();
let flow = network_connection.flow();
let protocol_index = Self::protocol_to_index(flow.protocol_type());
let protocol_type = flow.protocol_type();
let remote = flow.remote();
let mut inner = self.inner.lock();
@ -227,10 +226,10 @@ impl ConnectionTable {
}
// Sanity checking this implementation (hard fails that would invalidate the representation)
if inner.conn_by_id[protocol_index].contains_key(&id) {
if inner.conn_by_id[&protocol_type].contains_key(&id) {
panic!("duplicate connection id: {:#?}", network_connection);
}
if inner.protocol_index_by_id.contains_key(&id) {
if inner.protocol_type_by_id.contains_key(&id) {
panic!("duplicate id to protocol index: {:#?}", network_connection);
}
if let Some(ids) = inner.ids_by_remote.get(&flow.remote()) {
@ -255,7 +254,7 @@ impl ConnectionTable {
// if we have reached the maximum number of connections per protocol type
// then drop the least recently used connection that is not protected or referenced
let out_conn = match self.lru_out_connection_inner(&mut inner, protocol_index) {
let out_conn = match self.lru_out_connection_inner(&mut inner, protocol_type) {
Ok(v) => v,
Err(()) => {
return Err(ConnectionTableAddError::table_full(network_connection));
@ -263,11 +262,12 @@ impl ConnectionTable {
};
// Add the connection to the table
let res = inner.conn_by_id[protocol_index].insert(id, network_connection);
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
let res = conn_by_id_table.insert(id, network_connection);
assert!(res.is_none());
// add connection records
inner.protocol_index_by_id.insert(id, protocol_index);
inner.protocol_type_by_id.insert(id, protocol_type);
inner.id_by_flow.insert(flow, id);
inner.ids_by_remote.entry(remote).or_default().push(id);
@ -283,18 +283,19 @@ impl ConnectionTable {
let inner = self.inner.lock();
let id = *inner.id_by_flow.get(&flow)?;
let protocol_index = Self::protocol_to_index(flow.protocol_type());
let out = inner.conn_by_id[protocol_index].peek(&id).unwrap();
let protocol_type = flow.protocol_type();
let out = inner.conn_by_id[&protocol_type].peek(&id).unwrap();
Some(out.get_handle())
}
//#[instrument(level = "trace", skip(self), ret)]
pub fn touch_connection_by_id(&self, id: NetworkConnectionId) {
let mut inner = self.inner.lock();
let Some(protocol_index) = inner.protocol_index_by_id.get(&id).copied() else {
let Some(protocol_type) = inner.protocol_type_by_id.get(&id).copied() else {
return;
};
let _ = inner.conn_by_id[protocol_index].get(&id).unwrap();
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
let _ = conn_by_id_table.get(&id);
}
#[expect(dead_code)]
@ -310,8 +311,8 @@ impl ConnectionTable {
let inner = self.inner.lock();
let id = *inner.id_by_flow.get(&flow)?;
let protocol_index = Self::protocol_to_index(flow.protocol_type());
let out = inner.conn_by_id[protocol_index].peek(&id).unwrap();
let protocol_type = flow.protocol_type();
let out = inner.conn_by_id[&protocol_type].peek(&id).unwrap();
Some(closure(out))
}
@ -328,8 +329,9 @@ impl ConnectionTable {
let mut inner = self.inner.lock();
let id = *inner.id_by_flow.get(&flow)?;
let protocol_index = Self::protocol_to_index(flow.protocol_type());
let out = inner.conn_by_id[protocol_index].peek_mut(&id).unwrap();
let protocol_type = flow.protocol_type();
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
let out = conn_by_id_table.peek_mut(&id).unwrap();
Some(closure(out))
}
@ -339,8 +341,9 @@ impl ConnectionTable {
) -> Option<R> {
let mut inner_lock = self.inner.lock();
let inner = &mut *inner_lock;
for (id, idx) in inner.protocol_index_by_id.iter() {
if let Some(conn) = inner.conn_by_id[*idx].peek_mut(id) {
for (id, pt) in inner.protocol_type_by_id.iter() {
let conn_by_id_table = inner.conn_by_id.get_mut(pt).unwrap();
if let Some(conn) = conn_by_id_table.peek_mut(id) {
if let Some(out) = closure(conn) {
return Some(out);
}
@ -356,11 +359,12 @@ impl ConnectionTable {
ref_type: ConnectionRefKind,
) -> bool {
let mut inner = self.inner.lock();
let Some(protocol_index) = inner.protocol_index_by_id.get(&id).copied() else {
let Some(protocol_type) = inner.protocol_type_by_id.get(&id).copied() else {
// Sometimes network connections die before we can ref/unref them
return false;
};
let out = inner.conn_by_id[protocol_index].get_mut(&id).unwrap();
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
let out = conn_by_id_table.get_mut(&id).unwrap();
match ref_type {
ConnectionRefKind::AddRef => out.add_ref(),
ConnectionRefKind::RemoveRef => out.remove_ref(),
@ -377,7 +381,9 @@ impl ConnectionTable {
let inner = &mut *self.inner.lock();
let all_ids_by_remote = inner.ids_by_remote.get(&remote)?;
let protocol_index = Self::protocol_to_index(remote.protocol_type());
let protocol_type = remote.protocol_type();
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
if all_ids_by_remote.is_empty() {
// no connections
return None;
@ -385,16 +391,16 @@ impl ConnectionTable {
if all_ids_by_remote.len() == 1 {
// only one connection
let id = all_ids_by_remote[0];
let nc = inner.conn_by_id[protocol_index].get(&id).unwrap();
let nc = conn_by_id_table.get(&id).unwrap();
return Some(nc.get_handle());
}
// multiple connections, find the one that matches the best port, or the most recent
if let Some(best_port) = best_port {
for id in all_ids_by_remote {
let nc = inner.conn_by_id[protocol_index].peek(id).unwrap();
let nc = conn_by_id_table.peek(id).unwrap();
if let Some(local_addr) = nc.flow().local() {
if local_addr.port() == best_port {
let nc = inner.conn_by_id[protocol_index].get(id).unwrap();
let nc = conn_by_id_table.get(id).unwrap();
return Some(nc.get_handle());
}
}
@ -402,7 +408,7 @@ impl ConnectionTable {
}
// just return most recent network connection if a best port match can not be found
let best_id = *all_ids_by_remote.last().unwrap();
let nc = inner.conn_by_id[protocol_index].get(&best_id).unwrap();
let nc = conn_by_id_table.get(&best_id).unwrap();
Some(nc.get_handle())
}
@ -440,7 +446,10 @@ impl ConnectionTable {
pub fn connection_count(&self) -> usize {
let inner = self.inner.lock();
inner.conn_by_id.iter().fold(0, |acc, c| acc + c.len())
inner
.conn_by_id
.iter()
.fold(0, |acc, (_pt, c)| acc + c.len())
}
#[instrument(level = "trace", skip(inner), ret)]
@ -449,10 +458,11 @@ impl ConnectionTable {
inner: &mut ConnectionTableInner,
id: NetworkConnectionId,
) -> NetworkConnection {
// protocol_index_by_id
let protocol_index = inner.protocol_index_by_id.remove(&id).unwrap();
// protocol_type_by_id
let protocol_type = inner.protocol_type_by_id.remove(&id).unwrap();
// conn_by_id
let conn = inner.conn_by_id[protocol_index].remove(&id).unwrap();
let conn_by_id_table = inner.conn_by_id.get_mut(&protocol_type).unwrap();
let conn = conn_by_id_table.remove(&id).unwrap();
// id_by_flow
let flow = conn.flow();
let _ = inner
@ -484,8 +494,8 @@ impl ConnectionTable {
pub fn remove_connection_by_id(&self, id: NetworkConnectionId) -> Option<NetworkConnection> {
let mut inner = self.inner.lock();
let protocol_index = *inner.protocol_index_by_id.get(&id)?;
if !inner.conn_by_id[protocol_index].contains_key(&id) {
let protocol_type = *inner.protocol_type_by_id.get(&id)?;
if !inner.conn_by_id[&protocol_type].contains_key(&id) {
return None;
}
let conn = self.remove_connection_records_inner(&mut inner, id);
@ -496,16 +506,16 @@ impl ConnectionTable {
let mut out = String::new();
let inner = self.inner.lock();
let cur_ts = Timestamp::now();
for t in 0..inner.conn_by_id.len() {
for pt in inner.conn_by_id.keys() {
out += &format!(
" {} Connections: ({}/{})\n",
Self::index_to_protocol(t),
inner.conn_by_id[t].len(),
inner.max_connections[t]
pt,
inner.conn_by_id[pt].len(),
inner.max_connections[pt]
);
for (_, conn) in &inner.conn_by_id[t] {
let is_priority_flow = inner.priority_flows[t].contains_key(&conn.flow());
for (_, conn) in &inner.conn_by_id[pt] {
let is_priority_flow = inner.priority_flows[pt].contains_key(&conn.flow());
out += &format!(
" {}{}\n",
@ -515,15 +525,15 @@ impl ConnectionTable {
}
}
for t in 0..inner.priority_flows.len() {
for pt in inner.priority_flows.keys() {
out += &format!(
" {} Priority Flows: ({}/{})\n",
Self::index_to_protocol(t),
inner.priority_flows[t].len(),
inner.priority_flows[t].capacity(),
pt,
inner.priority_flows[pt].len(),
inner.priority_flows[pt].capacity(),
);
for (flow, _) in &inner.priority_flows[t] {
for (flow, _) in &inner.priority_flows[pt] {
out += &format!(" {}\n", flow);
}
}

View file

@ -404,7 +404,19 @@ impl Network {
.wrap_err("connect failure")?);
network_result_try!(pnc.send(data).await.wrap_err("send failure")?);
}
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
let pnc = network_result_try!(WebsocketProtocolHandler::connect(
self.registry(),
None,
&dial_info,
connect_timeout_ms
)
.await
.wrap_err("connect failure")?);
network_result_try!(pnc.send(data).await.wrap_err("send failure")?);
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
let pnc = network_result_try!(WebsocketProtocolHandler::connect(
self.registry(),
None,
@ -458,6 +470,7 @@ impl Network {
}
match dial_info.protocol_type() {
// Connectionless protocols
ProtocolType::UDP => {
let peer_socket_addr = dial_info.to_socket_addr();
let h = RawUdpProtocolHandler::new_unspecified_bound_handler(
@ -498,7 +511,8 @@ impl Network {
out.resize(recv_len, 0u8);
Ok(NetworkResult::Value(out))
}
ProtocolType::TCP | ProtocolType::WS | ProtocolType::WSS => {
// Connection-oriented protocols
_ => {
let pnc = network_result_try!(match dial_info.protocol_type() {
ProtocolType::UDP => unreachable!(),
ProtocolType::TCP => {
@ -512,7 +526,18 @@ impl Network {
.await
.wrap_err("connect failure")?
}
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
WebsocketProtocolHandler::connect(
self.registry(),
None,
&dial_info,
connect_timeout_ms,
)
.await
.wrap_err("connect failure")?
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
WebsocketProtocolHandler::connect(
self.registry(),
None,
@ -843,6 +868,8 @@ impl Network {
return res;
}
}
#[cfg(feature = "enable-protocol-wss")]
if network_state
.protocol_config
.inbound
@ -927,6 +954,7 @@ impl Network {
self.register_ws_dial_info(editor_public_internet, editor_local_network)
.await?;
}
#[cfg(feature = "enable-protocol-wss")]
if protocol_config.inbound.contains(ProtocolType::WSS) {
self.register_wss_dial_info(editor_public_internet, editor_local_network)
.await?;

View file

@ -99,6 +99,7 @@ impl Network {
if c.network.protocol.ws.listen {
inbound.insert(ProtocolType::WS);
}
#[cfg(feature = "enable-protocol-wss")]
if c.network.protocol.wss.listen {
inbound.insert(ProtocolType::WSS);
}
@ -113,6 +114,7 @@ impl Network {
if c.network.protocol.ws.connect {
outbound.insert(ProtocolType::WS);
}
#[cfg(feature = "enable-protocol-wss")]
if c.network.protocol.wss.connect {
outbound.insert(ProtocolType::WSS);
}

View file

@ -12,6 +12,7 @@ pub(crate) enum ProtocolNetworkConnection {
RawTcp(tcp::RawTcpNetworkConnection),
WsAccepted(ws::WebSocketNetworkConnectionAccepted),
Ws(ws::WebsocketNetworkConnectionWS),
#[cfg(feature = "enable-protocol-wss")]
Wss(ws::WebsocketNetworkConnectionWSS),
//WebRTC(wrtc::WebRTCNetworkConnection),
}
@ -40,7 +41,17 @@ impl ProtocolNetworkConnection {
)
.await
}
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
ws::WebsocketProtocolHandler::connect(
registry,
local_address,
dial_info,
timeout_ms,
)
.await
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
ws::WebsocketProtocolHandler::connect(
registry,
local_address,
@ -58,6 +69,7 @@ impl ProtocolNetworkConnection {
Self::RawTcp(t) => t.flow(),
Self::WsAccepted(w) => w.flow(),
Self::Ws(w) => w.flow(),
#[cfg(feature = "enable-protocol-wss")]
Self::Wss(w) => w.flow(),
}
}
@ -68,6 +80,7 @@ impl ProtocolNetworkConnection {
Self::RawTcp(t) => t.close().await,
Self::WsAccepted(w) => w.close().await,
Self::Ws(w) => w.close().await,
#[cfg(feature = "enable-protocol-wss")]
Self::Wss(w) => w.close().await,
}
}
@ -78,6 +91,7 @@ impl ProtocolNetworkConnection {
Self::RawTcp(t) => t.send(message).await,
Self::WsAccepted(w) => w.send(message).await,
Self::Ws(w) => w.send(message).await,
#[cfg(feature = "enable-protocol-wss")]
Self::Wss(w) => w.send(message).await,
}
}
@ -87,6 +101,7 @@ impl ProtocolNetworkConnection {
Self::RawTcp(t) => t.recv().await,
Self::WsAccepted(w) => w.recv().await,
Self::Ws(w) => w.recv().await,
#[cfg(feature = "enable-protocol-wss")]
Self::Wss(w) => w.recv().await,
}
}

View file

@ -1,6 +1,8 @@
use super::*;
#[cfg(feature = "enable-protocol-wss")]
use async_tls::TlsConnector;
use async_tungstenite::tungstenite::error::ProtocolError;
use async_tungstenite::tungstenite::handshake::server::{
Callback, ErrorResponse, Request, Response,
@ -22,10 +24,12 @@ const MAX_WS_BEFORE_BODY: usize = 2048;
cfg_if! {
if #[cfg(feature="rt-async-std")] {
#[cfg(feature="enable-protocol-wss")]
pub type WebsocketNetworkConnectionWSS =
WebsocketNetworkConnection<async_tls::client::TlsStream<TcpStream>>;
pub type WebsocketNetworkConnectionWS = WebsocketNetworkConnection<TcpStream>;
} else if #[cfg(feature="rt-tokio")] {
#[cfg(feature="enable-protocol-wss")]
pub type WebsocketNetworkConnectionWSS =
WebsocketNetworkConnection<async_tls::client::TlsStream<Compat<TcpStream>>>;
pub type WebsocketNetworkConnectionWS = WebsocketNetworkConnection<Compat<TcpStream>>;
@ -192,7 +196,13 @@ impl WebsocketProtocolHandler {
let config = registry.config();
let c = config.get();
let path = if tls {
format!("GET /{}", c.network.protocol.wss.path.trim_end_matches('/'))
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
format!("GET /{}", c.network.protocol.wss.path.trim_end_matches('/'))
} else {
unreachable!("no tls protocols are enabled");
}
}
} else {
format!("GET /{}", c.network.protocol.ws.path.trim_end_matches('/'))
};
@ -276,7 +286,13 @@ impl WebsocketProtocolHandler {
// Wrap the websocket in a NetworkConnection and register it
let protocol_type = if self.arc.tls {
ProtocolType::WSS
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
ProtocolType::WSS
} else {
return Ok(None);
}
}
} else {
ProtocolType::WS
};
@ -309,15 +325,15 @@ impl WebsocketProtocolHandler {
// Split dial info up
let (tls, scheme) = match dial_info {
DialInfo::WS(_) => (false, "ws"),
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(_) => (true, "wss"),
_ => panic!("invalid dialinfo for WS/WSS protocol"),
_ => panic!("invalid dialinfo for websocket protocol"),
};
let request = dial_info.request().unwrap();
let split_url = SplitUrl::from_str(&request).map_err(to_io_error_other)?;
if split_url.scheme != scheme {
bail_io_error_other!("invalid websocket url scheme");
}
let domain = split_url.host.clone();
// Resolve remote address
let remote_address = dial_info.to_socket_addr();
@ -346,18 +362,26 @@ impl WebsocketProtocolHandler {
// Negotiate TLS if this is WSS
if tls {
let connector = TlsConnector::default();
let tls_stream = network_result_try!(connector
.connect(domain.to_string(), tcp_stream)
.await
.into_network_result()?);
let (ws_stream, _response) = client_async(request, tls_stream)
.await
.map_err(to_io_error_other)?;
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
let domain = split_url.host.clone();
Ok(NetworkResult::Value(ProtocolNetworkConnection::Wss(
WebsocketNetworkConnection::new(registry, flow, ws_stream),
)))
let connector = TlsConnector::default();
let tls_stream = network_result_try!(connector
.connect(domain.to_string(), tcp_stream)
.await
.into_network_result()?);
let (ws_stream, _response) = client_async(request, tls_stream)
.await
.map_err(to_io_error_other)?;
Ok(NetworkResult::Value(ProtocolNetworkConnection::Wss(
WebsocketNetworkConnection::new(registry, flow, ws_stream),
)))
} else {
unreachable!("no tls support for websockets enabled");
}
}
} else {
let (ws_stream, _response) = client_async(request, tcp_stream)
.await

View file

@ -419,6 +419,7 @@ impl Network {
Ok(())
}
#[cfg(feature = "enable-protocol-wss")]
#[instrument(level = "trace", skip_all)]
pub(super) async fn start_wss_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "WSS: binding protocol handlers");
@ -472,6 +473,7 @@ impl Network {
Ok(StartupDisposition::Success)
}
#[cfg(feature = "enable-protocol-wss")]
#[instrument(level = "trace", skip_all)]
pub(super) async fn register_wss_dial_info(
&self,

View file

@ -252,6 +252,7 @@ impl Network {
.with(|c| format!("ws://{}/{}", addr, c.network.protocol.ws.path)),
)
.unwrap(),
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => DialInfo::try_wss(
addr,
self.config()

View file

@ -15,6 +15,7 @@ fn make_mock_bootstrap_record(include_timestamp: bool) -> BootstrapRecord {
)
.expect("should make ws dialinfo"),
},
#[cfg(feature = "enable-protocol-wss")]
DialInfoDetail {
class: DialInfoClass::Direct,
dial_info: DialInfo::try_wss(

View file

@ -39,7 +39,7 @@ pub async fn test_add_get_remove() {
let a5 = Flow::new(
PeerAddress::new(
SocketAddress::new(Address::IPV6(Ipv6Addr::new(192, 0, 0, 0, 0, 0, 0, 1)), 8090),
ProtocolType::WSS,
ProtocolType::WS,
),
SocketAddress::from_socket_addr(SocketAddr::V6(SocketAddrV6::new(
Ipv6Addr::new(193, 0, 0, 0, 0, 0, 0, 1),

View file

@ -1,6 +1,7 @@
mod tcp;
mod udp;
mod ws;
#[cfg(feature = "enable-protocol-wss")]
mod wss;
use super::*;
@ -8,6 +9,7 @@ use super::*;
pub(crate) use tcp::*;
pub(crate) use udp::*;
pub(crate) use ws::*;
#[cfg(feature = "enable-protocol-wss")]
pub(crate) use wss::*;
// Keep member order appropriate for sorting < preference
@ -18,6 +20,7 @@ pub(crate) enum DialInfo {
UDP(DialInfoUDP),
TCP(DialInfoTCP),
WS(DialInfoWS),
#[cfg(feature = "enable-protocol-wss")]
WSS(DialInfoWSS),
}
impl Default for DialInfo {
@ -47,6 +50,7 @@ impl fmt::Display for DialInfo {
}
}
}
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(di) => {
let url = format!("wss://{}", di.request);
let split_url = SplitUrl::from_str(&url).unwrap();
@ -110,6 +114,7 @@ impl FromStr for DialInfo {
}
}
}
#[cfg(feature = "enable-protocol-wss")]
"wss" => {
let url = format!("wss://{}", rest);
let split_url = SplitUrl::from_str(&url).map_err(|e| {
@ -191,6 +196,7 @@ impl DialInfo {
request: url[5..].to_string(),
}))
}
#[cfg(feature = "enable-protocol-wss")]
pub fn try_wss(socket_address: SocketAddress, url: String) -> VeilidAPIResult<Self> {
let split_url = SplitUrl::from_str(&url).map_err(|e| {
VeilidAPIError::parse_error(format!("unable to split WSS url: {}", e), &url)
@ -220,6 +226,7 @@ impl DialInfo {
Self::UDP(_) => ProtocolType::UDP,
Self::TCP(_) => ProtocolType::TCP,
Self::WS(_) => ProtocolType::WS,
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(_) => ProtocolType::WSS,
}
}
@ -231,6 +238,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.address(),
Self::TCP(di) => di.socket_address.address(),
Self::WS(di) => di.socket_address.address(),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.address(),
}
}
@ -240,6 +248,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.set_address(address),
Self::TCP(di) => di.socket_address.set_address(address),
Self::WS(di) => di.socket_address.set_address(address),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.set_address(address),
}
}
@ -248,6 +257,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address,
Self::TCP(di) => di.socket_address,
Self::WS(di) => di.socket_address,
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address,
}
}
@ -256,6 +266,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.ip_addr(),
Self::TCP(di) => di.socket_address.ip_addr(),
Self::WS(di) => di.socket_address.ip_addr(),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.ip_addr(),
}
}
@ -264,6 +275,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.port(),
Self::TCP(di) => di.socket_address.port(),
Self::WS(di) => di.socket_address.port(),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.port(),
}
}
@ -273,6 +285,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.set_port(port),
Self::TCP(di) => di.socket_address.set_port(port),
Self::WS(di) => di.socket_address.set_port(port),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.set_port(port),
}
}
@ -281,6 +294,7 @@ impl DialInfo {
Self::UDP(di) => di.socket_address.socket_addr(),
Self::TCP(di) => di.socket_address.socket_addr(),
Self::WS(di) => di.socket_address.socket_addr(),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => di.socket_address.socket_addr(),
}
}
@ -289,6 +303,7 @@ impl DialInfo {
Self::UDP(di) => PeerAddress::new(di.socket_address, ProtocolType::UDP),
Self::TCP(di) => PeerAddress::new(di.socket_address, ProtocolType::TCP),
Self::WS(di) => PeerAddress::new(di.socket_address, ProtocolType::WS),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => PeerAddress::new(di.socket_address, ProtocolType::WSS),
}
}
@ -297,6 +312,7 @@ impl DialInfo {
Self::UDP(_) => None,
Self::TCP(_) => None,
Self::WS(di) => Some(format!("ws://{}", di.request)),
#[cfg(feature = "enable-protocol-wss")]
Self::WSS(di) => Some(format!("wss://{}", di.request)),
}
}
@ -323,6 +339,7 @@ impl DialInfo {
(DialInfo::UDP(a), DialInfo::UDP(b)) => a.cmp(b),
(DialInfo::TCP(a), DialInfo::TCP(b)) => a.cmp(b),
(DialInfo::WS(a), DialInfo::WS(b)) => a.cmp(b),
#[cfg(feature = "enable-protocol-wss")]
(DialInfo::WSS(a), DialInfo::WSS(b)) => a.cmp(b),
_ => unreachable!(),
}

View file

@ -1,6 +1,65 @@
#![allow(non_snake_case)]
use super::*;
lazy_static::lazy_static! {
static ref PROTOCOL_TYPE_ORDERING: BTreeMap<(Sequencing, ProtocolType), usize>= {
let mut out = BTreeMap::<(Sequencing, ProtocolType), usize>::new();
// Sequencing::NoPreference
{
let pref = Sequencing::NoPreference;
let mut order = 0;
out.insert((pref, ProtocolType::UDP), order);
order += 1;
out.insert((pref, ProtocolType::TCP), order);
order += 1;
out.insert((pref, ProtocolType::WS), order);
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
order += 1;
out.insert((pref, ProtocolType::WSS), order);
}
}
}
// Sequencing::PreferOrdered | Sequencing::EnsureOrdered
for pref in [Sequencing::PreferOrdered, Sequencing::EnsureOrdered]
{
let mut order = 0;
out.insert((pref, ProtocolType::TCP), order);
order += 1;
out.insert((pref, ProtocolType::WS), order);
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
order += 1;
out.insert((pref, ProtocolType::WSS), order);
}
}
order += 1;
out.insert((pref, ProtocolType::UDP), order);
}
out
};
static ref PROTOCOL_TYPE_ALL_ORDERED_SET: ProtocolTypeSet = {
let mut out = ProtocolTypeSet::new();
out.insert(ProtocolType::TCP);
out.insert(ProtocolType::WS);
#[cfg(feature="enable-protocol-wss")]
out.insert(ProtocolType::WSS);
out
};
}
// Keep member order appropriate for sorting < preference
// Must match DialInfo order
#[allow(clippy::derived_hash_with_manual_eq)]
@ -10,6 +69,7 @@ pub(crate) enum ProtocolType {
UDP = 0,
TCP = 1,
WS = 2,
#[cfg(feature = "enable-protocol-wss")]
WSS = 3,
}
@ -19,6 +79,7 @@ impl ProtocolType {
ProtocolType::UDP => SequenceOrdering::Unordered,
ProtocolType::TCP => SequenceOrdering::Ordered,
ProtocolType::WS => SequenceOrdering::Ordered,
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => SequenceOrdering::Ordered,
}
}
@ -26,43 +87,16 @@ impl ProtocolType {
pub fn low_level_protocol_type(&self) -> LowLevelProtocolType {
match self {
ProtocolType::UDP => LowLevelProtocolType::UDP,
ProtocolType::TCP | ProtocolType::WS | ProtocolType::WSS => LowLevelProtocolType::TCP,
ProtocolType::TCP | ProtocolType::WS => LowLevelProtocolType::TCP,
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => LowLevelProtocolType::TCP,
}
}
pub fn sort_order(&self, sequencing: Sequencing) -> usize {
match self {
ProtocolType::UDP => {
if sequencing != Sequencing::NoPreference {
3
} else {
0
}
}
ProtocolType::TCP => {
if sequencing != Sequencing::NoPreference {
0
} else {
1
}
}
ProtocolType::WS => {
if sequencing != Sequencing::NoPreference {
1
} else {
2
}
}
ProtocolType::WSS => {
if sequencing != Sequencing::NoPreference {
2
} else {
3
}
}
}
*PROTOCOL_TYPE_ORDERING.get(&(sequencing, *self)).unwrap()
}
pub fn all_ordered_set() -> ProtocolTypeSet {
ProtocolType::TCP | ProtocolType::WS | ProtocolType::WSS
*PROTOCOL_TYPE_ALL_ORDERED_SET
}
pub fn ordered_sequencing_sort(a: Self, b: Self) -> core::cmp::Ordering {
@ -84,6 +118,7 @@ impl fmt::Display for ProtocolType {
ProtocolType::UDP => write!(f, "UDP"),
ProtocolType::TCP => write!(f, "TCP"),
ProtocolType::WS => write!(f, "WS"),
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => write!(f, "WSS"),
}
}
@ -96,6 +131,7 @@ impl FromStr for ProtocolType {
"UDP" => Ok(ProtocolType::UDP),
"TCP" => Ok(ProtocolType::TCP),
"WS" => Ok(ProtocolType::WS),
#[cfg(feature = "enable-protocol-wss")]
"WSS" => Ok(ProtocolType::WSS),
_ => Err(VeilidAPIError::parse_error(
"ProtocolType::from_str failed",

View file

@ -156,7 +156,18 @@ impl Network {
ProtocolType::TCP => {
bail!("no support for TCP protocol")
}
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
let pnc = network_result_try!(ws::WebsocketProtocolHandler::connect(
self.registry(),
&dial_info,
timeout_ms
)
.await
.wrap_err("connect failure")?);
network_result_try!(pnc.send(data).await.wrap_err("send failure")?);
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
let pnc = network_result_try!(ws::WebsocketProtocolHandler::connect(
self.registry(),
&dial_info,
@ -212,11 +223,21 @@ impl Network {
ProtocolType::TCP => {
bail!("no support for TCP protocol")
}
ProtocolType::WS | ProtocolType::WSS => {
_ => {
let pnc = network_result_try!(match dial_info.protocol_type() {
ProtocolType::UDP => unreachable!(),
ProtocolType::TCP => unreachable!(),
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
ws::WebsocketProtocolHandler::connect(
self.registry(),
&dial_info,
connect_timeout_ms,
)
.await
.wrap_err("connect failure")?
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
ws::WebsocketProtocolHandler::connect(
self.registry(),
&dial_info,
@ -368,6 +389,7 @@ impl Network {
if c.network.protocol.ws.connect {
outbound.insert(ProtocolType::WS);
}
#[cfg(feature = "enable-protocol-wss")]
if c.network.protocol.wss.connect {
outbound.insert(ProtocolType::WSS);
}

View file

@ -29,7 +29,11 @@ impl ProtocolNetworkConnection {
ProtocolType::TCP => {
panic!("TCP dial info is not supported on WASM targets");
}
ProtocolType::WS | ProtocolType::WSS => {
ProtocolType::WS => {
ws::WebsocketProtocolHandler::connect(registry, dial_info, timeout_ms).await
}
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => {
ws::WebsocketProtocolHandler::connect(registry, dial_info, timeout_ms).await
}
}

View file

@ -127,6 +127,7 @@ impl WebsocketProtocolHandler {
// Split dial info up
let (_tls, scheme) = match dial_info {
DialInfo::WS(_) => (false, "ws"),
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(_) => (true, "wss"),
_ => panic!("invalid dialinfo for WS/WSS protocol"),
};

View file

@ -43,6 +43,7 @@ pub fn decode_dial_info(reader: &veilid_capnp::dial_info::Reader) -> Result<Dial
)
.map_err(RPCError::map_protocol("invalid WS dial info"))
}
#[cfg(feature = "enable-protocol-wss")]
FOURCC_PROTOCOL_TYPE_WSS => {
let wss = reader
.get_detail()
@ -119,6 +120,7 @@ pub fn encode_dial_info(
);
requestb.push_str(request.as_str());
}
#[cfg(feature = "enable-protocol-wss")]
DialInfo::WSS(wss) => {
builder.set_protocol_type(FOURCC_PROTOCOL_TYPE_WSS);
let mut di_wss_builder = builder

View file

@ -3,6 +3,7 @@ use super::*;
pub const FOURCC_PROTOCOL_TYPE_UDP: u32 = u32::from_be_bytes(*b"pUDP");
pub const FOURCC_PROTOCOL_TYPE_TCP: u32 = u32::from_be_bytes(*b"pTCP");
pub const FOURCC_PROTOCOL_TYPE_WS: u32 = u32::from_be_bytes(*b"p_WS");
#[cfg(feature = "enable-protocol-wss")]
pub const FOURCC_PROTOCOL_TYPE_WSS: u32 = u32::from_be_bytes(*b"pWSS");
pub fn decode_protocol_type_set(
@ -21,6 +22,7 @@ pub fn decode_protocol_type_set(
FOURCC_PROTOCOL_TYPE_WS => {
out.insert(ProtocolType::WS);
}
#[cfg(feature = "enable-protocol-wss")]
FOURCC_PROTOCOL_TYPE_WSS => {
out.insert(ProtocolType::WSS);
}
@ -44,6 +46,7 @@ pub fn encode_protocol_type_set(
ProtocolType::UDP => FOURCC_PROTOCOL_TYPE_UDP,
ProtocolType::TCP => FOURCC_PROTOCOL_TYPE_TCP,
ProtocolType::WS => FOURCC_PROTOCOL_TYPE_WS,
#[cfg(feature = "enable-protocol-wss")]
ProtocolType::WSS => FOURCC_PROTOCOL_TYPE_WSS,
},
);

View file

@ -89,15 +89,6 @@ fn test_config() {
assert_eq!(inner.network.tls.private_key_path, get_keyfile_path());
assert_eq!(inner.network.tls.connection_initial_timeout_ms, 2_000u32);
assert!(!inner.network.application.https.enabled);
assert_eq!(inner.network.application.https.listen_address, "");
assert_eq!(inner.network.application.https.path, "app");
assert_eq!(inner.network.application.https.url, None);
assert!(!inner.network.application.http.enabled);
assert_eq!(inner.network.application.http.listen_address, "");
assert_eq!(inner.network.application.http.path, "app");
assert_eq!(inner.network.application.http.url, None);
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
assert!(!inner.network.protocol.udp.enabled);
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
@ -131,12 +122,17 @@ fn test_config() {
assert_eq!(inner.network.protocol.ws.listen_address, "");
assert_eq!(inner.network.protocol.ws.path, "ws");
assert_eq!(inner.network.protocol.ws.url, None);
assert!(inner.network.protocol.wss.connect);
assert!(!inner.network.protocol.wss.listen);
assert_eq!(inner.network.protocol.wss.max_connections, 32u32);
assert_eq!(inner.network.protocol.wss.listen_address, "");
assert_eq!(inner.network.protocol.wss.path, "ws");
assert_eq!(inner.network.protocol.wss.url, None);
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
assert!(inner.network.protocol.wss.connect);
assert!(!inner.network.protocol.wss.listen);
assert_eq!(inner.network.protocol.wss.max_connections, 32u32);
assert_eq!(inner.network.protocol.wss.listen_address, "");
assert_eq!(inner.network.protocol.wss.path, "ws");
assert_eq!(inner.network.protocol.wss.url, None);
}
}
assert!(!inner.network.privacy.require_inbound_relay);
#[cfg(feature = "geolocation")]

View file

@ -268,20 +268,6 @@ pub fn fix_fake_veilid_config() -> VeilidConfig {
private_key_path: "/etc/ssl/keys/key.pem".to_string(),
connection_initial_timeout_ms: 1000,
},
application: VeilidConfigApplication {
https: VeilidConfigHTTPS {
enabled: true,
listen_address: "10.0.0.3".to_string(),
path: "/https_path/".to_string(),
url: Some("https://veilid.com/".to_string()),
},
http: VeilidConfigHTTP {
enabled: true,
listen_address: "10.0.0.4".to_string(),
path: "/http_path/".to_string(),
url: Some("http://veilid.com/".to_string()),
},
},
protocol: VeilidConfigProtocol {
udp: VeilidConfigUDP {
enabled: false,
@ -304,6 +290,7 @@ pub fn fix_fake_veilid_config() -> VeilidConfig {
path: "Straight".to_string(),
url: Some("https://veilid.com/ws".to_string()),
},
#[cfg(feature = "enable-protocol-wss")]
wss: VeilidConfigWSS {
connect: true,
listen: false,

View file

@ -411,16 +411,20 @@ fn get_filtered_node_ref(
fn get_protocol_type(text: &str) -> Option<ProtocolType> {
let lctext = text.to_ascii_lowercase();
if lctext == "udp" {
Some(ProtocolType::UDP)
} else if lctext == "tcp" {
Some(ProtocolType::TCP)
} else if lctext == "ws" {
Some(ProtocolType::WS)
} else if lctext == "wss" {
Some(ProtocolType::WSS)
} else {
None
return Some(ProtocolType::UDP);
}
if lctext == "tcp" {
return Some(ProtocolType::TCP);
}
if lctext == "ws" {
return Some(ProtocolType::WS);
}
#[cfg(feature = "enable-protocol-wss")]
if lctext == "wss" {
return Some(ProtocolType::WSS);
}
None
}
fn get_sequencing(text: &str) -> Option<Sequencing> {
let seqtext = text.to_ascii_lowercase();

View file

@ -89,24 +89,6 @@ impl Default for VeilidConfigHTTP {
}
}
/// Application configuration.
///
/// Configure web access to the Progressive Web App (PWA).
///
/// To be implemented...
///
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(
all(target_arch = "wasm32", target_os = "unknown"),
derive(Tsify),
tsify(into_wasm_abi, from_wasm_abi)
)]
#[must_use]
pub struct VeilidConfigApplication {
pub https: VeilidConfigHTTPS,
pub http: VeilidConfigHTTP,
}
/// Enable and configure UDP.
///
/// ```yaml
@ -265,6 +247,7 @@ impl Default for VeilidConfigWS {
tsify(into_wasm_abi, from_wasm_abi)
)]
#[must_use]
#[cfg(feature = "enable-protocol-wss")]
pub struct VeilidConfigWSS {
pub connect: bool,
pub listen: bool,
@ -275,6 +258,7 @@ pub struct VeilidConfigWSS {
pub url: Option<String>, // Fixed URL is not optional for TLS-based protocols and is dynamically validated
}
#[cfg(feature = "enable-protocol-wss")]
impl Default for VeilidConfigWSS {
fn default() -> Self {
Self {
@ -306,6 +290,7 @@ pub struct VeilidConfigProtocol {
pub udp: VeilidConfigUDP,
pub tcp: VeilidConfigTCP,
pub ws: VeilidConfigWS,
#[cfg(feature = "enable-protocol-wss")]
pub wss: VeilidConfigWSS,
}
@ -629,7 +614,6 @@ pub struct VeilidConfigNetwork {
pub detect_address_changes: Option<bool>,
pub restricted_nat_retries: u32,
pub tls: VeilidConfigTLS,
pub application: VeilidConfigApplication,
pub protocol: VeilidConfigProtocol,
pub privacy: VeilidConfigPrivacy,
#[cfg(feature = "virtual-network")]
@ -656,7 +640,6 @@ impl Default for VeilidConfigNetwork {
detect_address_changes: Some(true),
restricted_nat_retries: 0,
tls: VeilidConfigTLS::default(),
application: VeilidConfigApplication::default(),
protocol: VeilidConfigProtocol::default(),
privacy: VeilidConfigPrivacy::default(),
#[cfg(feature = "virtual-network")]
@ -1197,17 +1180,8 @@ impl VeilidStartupOptions {
if inner.network.protocol.ws.max_connections == 0 {
apibail_generic!("WS max connections must be > 0 in config key 'network.protocol.ws.max_connections'");
}
if inner.network.application.https.enabled
&& inner.network.application.https.path == inner.network.protocol.ws.path
{
apibail_generic!("WS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'");
}
if inner.network.application.http.enabled
&& inner.network.application.http.path == inner.network.protocol.ws.path
{
apibail_generic!("WS path conflicts with HTTP application path in config key 'network.protocol.ws.path'");
}
}
#[cfg(feature = "enable-protocol-wss")]
if inner.network.protocol.wss.listen {
// Validate WSS settings
if inner.network.protocol.wss.max_connections == 0 {
@ -1226,32 +1200,6 @@ impl VeilidStartupOptions {
"WSS URL must be specified in config key 'network.protocol.wss.url'"
);
}
if inner.network.application.https.enabled
&& inner.network.application.https.path == inner.network.protocol.wss.path
{
apibail_generic!("WSS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'");
}
if inner.network.application.http.enabled
&& inner.network.application.http.path == inner.network.protocol.wss.path
{
apibail_generic!("WSS path conflicts with HTTP application path in config key 'network.protocol.ws.path'");
}
}
if inner.network.application.https.enabled {
// Validate HTTPS settings
if inner
.network
.application
.https
.url
.as_ref()
.map(|u| u.is_empty())
.unwrap_or_default()
{
apibail_generic!(
"HTTPS URL must be specified in config key 'network.application.https.url'"
);
}
}
if inner.network.rpc.max_route_hop_count == 0 {
apibail_generic!(

View file

@ -149,50 +149,6 @@ enum VeilidConfigLogLevel {
String toJson() => name.toPascalCase();
}
//////////////////////////////////////
/// VeilidConfig
@freezed
sealed class VeilidConfigHTTPS with _$VeilidConfigHTTPS {
const factory VeilidConfigHTTPS({
required bool enabled,
required String listenAddress,
required String path,
String? url,
}) = _VeilidConfigHTTPS;
factory VeilidConfigHTTPS.fromJson(dynamic json) =>
_$VeilidConfigHTTPSFromJson(json as Map<String, dynamic>);
}
////////////
@freezed
sealed class VeilidConfigHTTP with _$VeilidConfigHTTP {
const factory VeilidConfigHTTP({
required bool enabled,
required String listenAddress,
required String path,
String? url,
}) = _VeilidConfigHTTP;
factory VeilidConfigHTTP.fromJson(dynamic json) =>
_$VeilidConfigHTTPFromJson(json as Map<String, dynamic>);
}
////////////
@freezed
sealed class VeilidConfigApplication with _$VeilidConfigApplication {
const factory VeilidConfigApplication({
required VeilidConfigHTTPS https,
required VeilidConfigHTTP http,
}) = _VeilidConfigApplication;
factory VeilidConfigApplication.fromJson(dynamic json) =>
_$VeilidConfigApplicationFromJson(json as Map<String, dynamic>);
}
////////////
@freezed
sealed class VeilidConfigUDP with _$VeilidConfigUDP {
@ -239,8 +195,10 @@ sealed class VeilidConfigWS with _$VeilidConfigWS {
}
////////////
@Deprecated('WSS is disabled by default in veilid-flutter')
@freezed
sealed class VeilidConfigWSS with _$VeilidConfigWSS {
@Deprecated('WSS is disabled by default in veilid-flutter')
const factory VeilidConfigWSS({
required bool connect,
required bool listen,
@ -250,6 +208,7 @@ sealed class VeilidConfigWSS with _$VeilidConfigWSS {
String? url,
}) = _VeilidConfigWSS;
@Deprecated('WSS is disabled by default in veilid-flutter')
factory VeilidConfigWSS.fromJson(dynamic json) =>
_$VeilidConfigWSSFromJson(json as Map<String, dynamic>);
}
@ -262,6 +221,7 @@ sealed class VeilidConfigProtocol with _$VeilidConfigProtocol {
required VeilidConfigUDP udp,
required VeilidConfigTCP tcp,
required VeilidConfigWS ws,
@Deprecated('WSS is disabled by default in veilid-flutter')
required VeilidConfigWSS wss,
}) = _VeilidConfigProtocol;
@ -386,7 +346,6 @@ sealed class VeilidConfigNetwork with _$VeilidConfigNetwork {
required bool? detectAddressChanges,
required int restrictedNatRetries,
required VeilidConfigTLS tls,
required VeilidConfigApplication application,
required VeilidConfigProtocol protocol,
required VeilidConfigPrivacy privacy,
String? networkKeyPassword,

File diff suppressed because it is too large Load diff

View file

@ -171,52 +171,6 @@ _VeilidWASMConfig _$VeilidWASMConfigFromJson(Map<String, dynamic> json) =>
Map<String, dynamic> _$VeilidWASMConfigToJson(_VeilidWASMConfig instance) =>
<String, dynamic>{'logging': instance.logging.toJson()};
_VeilidConfigHTTPS _$VeilidConfigHTTPSFromJson(Map<String, dynamic> json) =>
_VeilidConfigHTTPS(
enabled: json['enabled'] as bool,
listenAddress: json['listen_address'] as String,
path: json['path'] as String,
url: json['url'] as String?,
);
Map<String, dynamic> _$VeilidConfigHTTPSToJson(_VeilidConfigHTTPS instance) =>
<String, dynamic>{
'enabled': instance.enabled,
'listen_address': instance.listenAddress,
'path': instance.path,
'url': instance.url,
};
_VeilidConfigHTTP _$VeilidConfigHTTPFromJson(Map<String, dynamic> json) =>
_VeilidConfigHTTP(
enabled: json['enabled'] as bool,
listenAddress: json['listen_address'] as String,
path: json['path'] as String,
url: json['url'] as String?,
);
Map<String, dynamic> _$VeilidConfigHTTPToJson(_VeilidConfigHTTP instance) =>
<String, dynamic>{
'enabled': instance.enabled,
'listen_address': instance.listenAddress,
'path': instance.path,
'url': instance.url,
};
_VeilidConfigApplication _$VeilidConfigApplicationFromJson(
Map<String, dynamic> json,
) => _VeilidConfigApplication(
https: VeilidConfigHTTPS.fromJson(json['https']),
http: VeilidConfigHTTP.fromJson(json['http']),
);
Map<String, dynamic> _$VeilidConfigApplicationToJson(
_VeilidConfigApplication instance,
) => <String, dynamic>{
'https': instance.https.toJson(),
'http': instance.http.toJson(),
};
_VeilidConfigUDP _$VeilidConfigUDPFromJson(Map<String, dynamic> json) =>
_VeilidConfigUDP(
enabled: json['enabled'] as bool,
@ -476,7 +430,6 @@ _VeilidConfigNetwork _$VeilidConfigNetworkFromJson(Map<String, dynamic> json) =>
detectAddressChanges: json['detect_address_changes'] as bool?,
restrictedNatRetries: (json['restricted_nat_retries'] as num).toInt(),
tls: VeilidConfigTLS.fromJson(json['tls']),
application: VeilidConfigApplication.fromJson(json['application']),
protocol: VeilidConfigProtocol.fromJson(json['protocol']),
privacy: VeilidConfigPrivacy.fromJson(json['privacy']),
networkKeyPassword: json['network_key_password'] as String?,
@ -502,7 +455,6 @@ Map<String, dynamic> _$VeilidConfigNetworkToJson(
'detect_address_changes': instance.detectAddressChanges,
'restricted_nat_retries': instance.restrictedNatRetries,
'tls': instance.tls.toJson(),
'application': instance.application.toJson(),
'protocol': instance.protocol.toJson(),
'privacy': instance.privacy.toJson(),
'network_key_password': instance.networkKeyPassword,

View file

@ -33,6 +33,7 @@ rt-tokio = [
"opentelemetry/rt-tokio",
]
debug-load = ["dep:ctor", "dep:libc-print", "dep:android_log-sys", "dep:oslog"]
enable-protocol-wss = ["veilid-core/enable-protocol-wss"]
footgun = ["veilid-core/footgun"]
[dependencies]

View file

@ -123,28 +123,6 @@ class VeilidConfigTLS(ConfigBase):
connection_initial_timeout_ms: int
@dataclass
class VeilidConfigHTTPS(ConfigBase):
enabled: bool
listen_address: str
path: str
url: Optional[str]
@dataclass
class VeilidConfigHTTP(ConfigBase):
enabled: bool
listen_address: str
path: str
url: Optional[str]
@dataclass
class VeilidConfigApplication(ConfigBase):
https: VeilidConfigHTTPS
http: VeilidConfigHTTP
@dataclass
class VeilidConfigUDP(ConfigBase):
enabled: bool
@ -172,14 +150,14 @@ class VeilidConfigWS(ConfigBase):
url: Optional[str]
@dataclass
class VeilidConfigWSS(ConfigBase):
connect: bool
listen: bool
max_connections: int
listen_address: str
path: str
url: Optional[str]
# @dataclass
# class VeilidConfigWSS(ConfigBase):
# connect: bool
# listen: bool
# max_connections: int
# listen_address: str
# path: str
# url: Optional[str]
@dataclass
@ -187,7 +165,7 @@ class VeilidConfigProtocol(ConfigBase):
udp: VeilidConfigUDP
tcp: VeilidConfigTCP
ws: VeilidConfigWS
wss: VeilidConfigWSS
# wss: VeilidConfigWSS
@dataclass
@ -214,7 +192,6 @@ class VeilidConfigNetwork(ConfigBase):
detect_address_changes: Optional[bool]
restricted_nat_retries: int
tls: VeilidConfigTLS
application: VeilidConfigApplication
protocol: VeilidConfigProtocol
privacy: VeilidConfigPrivacy

View file

@ -4015,22 +4015,6 @@
"network"
]
},
"VeilidConfigApplication": {
"description": "Application configuration.\n\nConfigure web access to the Progressive Web App (PWA).\n\nTo be implemented...",
"type": "object",
"properties": {
"http": {
"$ref": "#/$defs/VeilidConfigHTTP"
},
"https": {
"$ref": "#/$defs/VeilidConfigHTTPS"
}
},
"required": [
"https",
"http"
]
},
"VeilidConfigBlockStore": {
"type": "object",
"properties": {
@ -4206,64 +4190,9 @@
"max_watch_expiration_ms"
]
},
"VeilidConfigHTTP": {
"description": "Enable and configure HTTP access to the Veilid node.\n\n```yaml\nhttp:\n enabled: false\n listen_address: ':5150'\n path: 'app\"\n url: 'https://localhost:5150'\n```",
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"listen_address": {
"type": "string"
},
"path": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
}
},
"required": [
"enabled",
"listen_address",
"path"
]
},
"VeilidConfigHTTPS": {
"description": "Enable and configure HTTPS access to the Veilid node.\n\n```yaml\nhttps:\n enabled: false\n listen_address: ':5150'\n path: 'app'\n url: 'https://localhost:5150'\n```",
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"listen_address": {
"type": "string"
},
"path": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
}
},
"required": [
"enabled",
"listen_address",
"path"
]
},
"VeilidConfigNetwork": {
"type": "object",
"properties": {
"application": {
"$ref": "#/$defs/VeilidConfigApplication"
},
"client_allowlist_timeout_ms": {
"type": "integer",
"format": "uint32",
@ -4364,7 +4293,6 @@
"upnp",
"restricted_nat_retries",
"tls",
"application",
"protocol",
"privacy"
]
@ -4426,16 +4354,12 @@
},
"ws": {
"$ref": "#/$defs/VeilidConfigWS"
},
"wss": {
"$ref": "#/$defs/VeilidConfigWSS"
}
},
"required": [
"udp",
"tcp",
"ws",
"wss"
"ws"
]
},
"VeilidConfigRPC": {
@ -4693,42 +4617,6 @@
"path"
]
},
"VeilidConfigWSS": {
"description": "Enable and configure Secure Web Sockets.\n\n```yaml\nwss:\n connect: true\n listen: false\n max_connections: 32\n listen_address: ':5150'\n path: 'ws'\n url: ''",
"type": "object",
"properties": {
"connect": {
"type": "boolean"
},
"listen": {
"type": "boolean"
},
"listen_address": {
"type": "string"
},
"max_connections": {
"type": "integer",
"format": "uint32",
"minimum": 0
},
"path": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
}
},
"required": [
"connect",
"listen",
"max_connections",
"listen_address",
"path"
]
},
"VeilidLog": {
"description": "A VeilidCore log message with optional backtrace.",
"type": "object",

View file

@ -30,6 +30,7 @@ default-async-std = [
"veilid-remote-api/default-async-std",
]
enable-protocol-wss = ["veilid-core/enable-protocol-wss"]
footgun = ["veilid-core/footgun"]
rt-tokio = [

View file

@ -392,7 +392,10 @@ fn main() -> EyreResult<()> {
settingsrw.core.network.protocol.udp.listen_address = listen_address.clone();
settingsrw.core.network.protocol.tcp.listen_address = listen_address.clone();
settingsrw.core.network.protocol.ws.listen_address = listen_address.clone();
settingsrw.core.network.protocol.wss.listen_address = listen_address;
#[cfg(feature = "enable-protocol-wss")]
{
settingsrw.core.network.protocol.wss.listen_address = listen_address;
}
}
drop(settingsrw);

View file

@ -64,6 +64,17 @@ pub fn load_default_config() -> EyreResult<config::Config> {
listen_address: 'localhost:5148'
"#;
#[cfg(not(feature = "enable-protocol-wss"))]
let protocol_wss_section = "";
#[cfg(feature = "enable-protocol-wss")]
let protocol_wss_section = r#"wss:
connect: true
listen: false
max_connections: 256
listen_address: ':5150'
path: 'ws'
# url: ''"#;
let mut default_config = String::from(
r#"---
daemon:
@ -187,17 +198,6 @@ core:
certificate_path: '%CERTIFICATE_PATH%'
private_key_path: '%PRIVATE_KEY_PATH%'
connection_initial_timeout_ms: 2000
application:
https:
enabled: false
listen_address: ':443'
path: 'app'
# url: 'https://localhost'
http:
enabled: false
listen_address: ':80'
path: 'app'
# url: 'http://localhost'
protocol:
udp:
enabled: true
@ -217,13 +217,7 @@ core:
listen_address: ':5150'
path: 'ws'
# url: 'ws://localhost:5150/ws'
wss:
connect: true
listen: false
max_connections: 256
listen_address: ':5150'
path: 'ws'
# url: ''
%PROTOCOL_WSS_SECTION%
privacy:
require_inbound_relay: false
%PRIVACY_GEOLOCATION_SECTION%
@ -263,6 +257,10 @@ core:
.replace(
"%VIRTUAL_NETWORK_SERVER_SECTION%",
virtual_network_server_section,
)
.replace(
"%PROTOCOL_WSS_SECTION%",
protocol_wss_section,
);
let dek_password = if let Some(dek_password) = std::env::var_os("DEK_PASSWORD") {
@ -597,12 +595,6 @@ pub struct Http {
pub url: Option<ParsedUrl>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Application {
pub https: Https,
pub http: Http,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Udp {
pub enabled: bool,
@ -630,6 +622,7 @@ pub struct Ws {
pub url: Option<ParsedUrl>,
}
#[cfg(feature = "enable-protocol-wss")]
#[derive(Debug, Deserialize, Serialize)]
pub struct Wss {
pub connect: bool,
@ -645,6 +638,7 @@ pub struct Protocol {
pub udp: Udp,
pub tcp: Tcp,
pub ws: Ws,
#[cfg(feature = "enable-protocol-wss")]
pub wss: Wss,
}
@ -839,7 +833,6 @@ pub struct Network {
pub detect_address_changes: Option<bool>,
pub restricted_nat_retries: u32,
pub tls: Tls,
pub application: Application,
pub protocol: Protocol,
pub privacy: Privacy,
#[cfg(feature = "virtual-network")]
@ -1360,14 +1353,6 @@ impl Settings {
set_config_value!(inner.core.network.tls.certificate_path, value);
set_config_value!(inner.core.network.tls.private_key_path, value);
set_config_value!(inner.core.network.tls.connection_initial_timeout_ms, value);
set_config_value!(inner.core.network.application.https.enabled, value);
set_config_value!(inner.core.network.application.https.listen_address, value);
set_config_value!(inner.core.network.application.https.path, value);
set_config_value!(inner.core.network.application.https.url, value);
set_config_value!(inner.core.network.application.http.enabled, value);
set_config_value!(inner.core.network.application.http.listen_address, value);
set_config_value!(inner.core.network.application.http.path, value);
set_config_value!(inner.core.network.application.http.url, value);
set_config_value!(inner.core.network.protocol.udp.enabled, value);
set_config_value!(inner.core.network.protocol.udp.socket_pool_size, value);
set_config_value!(inner.core.network.protocol.udp.listen_address, value);
@ -1383,12 +1368,17 @@ impl Settings {
set_config_value!(inner.core.network.protocol.ws.listen_address, value);
set_config_value!(inner.core.network.protocol.ws.path, value);
set_config_value!(inner.core.network.protocol.ws.url, value);
set_config_value!(inner.core.network.protocol.wss.connect, value);
set_config_value!(inner.core.network.protocol.wss.listen, value);
set_config_value!(inner.core.network.protocol.wss.max_connections, value);
set_config_value!(inner.core.network.protocol.wss.listen_address, value);
set_config_value!(inner.core.network.protocol.wss.path, value);
set_config_value!(inner.core.network.protocol.wss.url, value);
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
set_config_value!(inner.core.network.protocol.wss.connect, value);
set_config_value!(inner.core.network.protocol.wss.listen, value);
set_config_value!(inner.core.network.protocol.wss.max_connections, value);
set_config_value!(inner.core.network.protocol.wss.listen_address, value);
set_config_value!(inner.core.network.protocol.wss.path, value);
set_config_value!(inner.core.network.protocol.wss.url, value);
}
}
set_config_value!(inner.core.network.privacy.require_inbound_relay, value);
#[cfg(feature = "geolocation")]
set_config_value!(inner.core.network.privacy.country_code_denylist, value);
@ -1552,66 +1542,6 @@ impl Settings {
.tls
.connection_initial_timeout_ms,
},
application: VeilidConfigApplication {
https: VeilidConfigHTTPS {
enabled: inner.core.network.application.https.enabled,
listen_address: inner
.core
.network
.application
.https
.listen_address
.with_offset_port(subnode_offset)
.map_err(VeilidAPIError::internal)?
.name
.clone(),
path: inner
.core
.network
.application
.https
.path
.to_string_lossy()
.to_string(),
url: match inner.core.network.application.https.url {
Some(ref a) => Some(
a.with_offset_port(subnode_offset)
.map_err(VeilidAPIError::internal)
.map(|x| x.urlstring.clone())?,
),
None => None,
},
},
http: VeilidConfigHTTP {
enabled: inner.core.network.application.http.enabled,
listen_address: inner
.core
.network
.application
.http
.listen_address
.with_offset_port(subnode_offset)
.map_err(VeilidAPIError::internal)?
.name
.clone(),
path: inner
.core
.network
.application
.http
.path
.to_string_lossy()
.to_string(),
url: match inner.core.network.application.http.url {
Some(ref a) => Some(
a.with_offset_port(subnode_offset)
.map_err(VeilidAPIError::internal)
.map(|x| x.urlstring.clone())?,
),
None => None,
},
},
},
protocol: VeilidConfigProtocol {
udp: VeilidConfigUDP {
enabled: inner.core.network.protocol.udp.enabled,
@ -1689,6 +1619,7 @@ impl Settings {
None => None,
},
},
#[cfg(feature = "enable-protocol-wss")]
wss: VeilidConfigWSS {
connect: inner.core.network.protocol.wss.connect,
listen: inner.core.network.protocol.wss.listen,
@ -1928,28 +1859,6 @@ mod tests {
);
assert_eq!(s.core.network.tls.connection_initial_timeout_ms, 2_000u32);
//
assert!(!s.core.network.application.https.enabled);
assert_eq!(s.core.network.application.https.listen_address.name, ":443");
assert_eq!(
s.core.network.application.https.listen_address.addrs,
listen_address_to_socket_addrs(":443").unwrap()
);
assert_eq!(
s.core.network.application.https.path,
std::path::PathBuf::from("app")
);
assert_eq!(s.core.network.application.https.url, None);
assert!(!s.core.network.application.http.enabled);
assert_eq!(s.core.network.application.http.listen_address.name, ":80");
assert_eq!(
s.core.network.application.http.listen_address.addrs,
listen_address_to_socket_addrs(":80").unwrap()
);
assert_eq!(
s.core.network.application.http.path,
std::path::PathBuf::from("app")
);
assert_eq!(s.core.network.application.http.url, None);
//
let valid_socket_addrs = [
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 5150),
@ -1991,19 +1900,23 @@ mod tests {
);
assert_eq!(s.core.network.protocol.ws.url, None);
//
assert!(s.core.network.protocol.wss.connect);
assert!(!s.core.network.protocol.wss.listen);
assert_eq!(s.core.network.protocol.wss.max_connections, 256);
assert_eq!(s.core.network.protocol.wss.listen_address.name, ":5150");
for addr in &s.core.network.protocol.wss.listen_address.addrs {
assert!(valid_socket_addrs.contains(addr));
cfg_if::cfg_if! {
if #[cfg(feature="enable-protocol-wss")] {
assert!(s.core.network.protocol.wss.connect);
assert!(!s.core.network.protocol.wss.listen);
assert_eq!(s.core.network.protocol.wss.max_connections, 256);
assert_eq!(s.core.network.protocol.wss.listen_address.name, ":5150");
for addr in &s.core.network.protocol.wss.listen_address.addrs {
assert!(valid_socket_addrs.contains(addr));
}
assert!(!s.core.network.protocol.wss.listen_address.addrs.is_empty());
assert_eq!(
s.core.network.protocol.wss.path,
std::path::PathBuf::from("ws")
);
assert_eq!(s.core.network.protocol.wss.url, None);
}
}
assert!(!s.core.network.protocol.wss.listen_address.addrs.is_empty());
assert_eq!(
s.core.network.protocol.wss.path,
std::path::PathBuf::from("ws")
);
assert_eq!(s.core.network.protocol.wss.url, None);
//
assert!(!s.core.network.privacy.require_inbound_relay);
#[cfg(feature = "geolocation")]

View file

@ -26,6 +26,7 @@ enable-crypto-vld0 = ["veilid-core/enable-crypto-vld0"]
enable-crypto-none = ["veilid-core/enable-crypto-none"]
crypto-test = ["enable-crypto-vld0", "enable-crypto-none"]
crypto-test-none = ["enable-crypto-none"]
enable-protocol-wss = ["veilid-core/enable-protocol-wss"]
footgun = ["veilid-core/footgun"]
[dependencies]