Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions common/client-core/src/cli_helpers/client_add_gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ where
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(common_args.latency_based_selection),
common_args.force_tls_gateway,
false,
);
tracing::debug!("Gateway selection specification: {selection_spec:?}");

Expand Down
1 change: 1 addition & 0 deletions common/client-core/src/cli_helpers/client_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ where
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(common_args.latency_based_selection),
common_args.force_tls_gateway,
false,
);
tracing::debug!("Gateway selection specification: {selection_spec:?}");

Expand Down
3 changes: 3 additions & 0 deletions common/client-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub enum ClientCoreError {
#[error("Invalid URL: {0}")]
InvalidUrl(String),

#[error("node doesn't advertise ip addresses : {0}")]
MissingIpAddress(String),

#[cfg(not(target_arch = "wasm32"))]
#[error("resolution failed: {0}")]
ResolutionFailed(#[from] nym_http_api_client::ResolveError),
Expand Down
17 changes: 12 additions & 5 deletions common/client-core/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,28 @@ where
let mut rng = OsRng;

let selected_gateway = match selection_specification {
GatewaySelectionSpecification::UniformRemote { must_use_tls } => {
GatewaySelectionSpecification::UniformRemote {
must_use_tls,
no_hostname,
} => {
let gateway = uniformly_random_gateway(&mut rng, &available_gateways, must_use_tls)?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, must_use_tls, no_hostname)?
}
GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => {
GatewaySelectionSpecification::RemoteByLatency {
must_use_tls,
no_hostname,
} => {
let gateway =
choose_gateway_by_latency(&mut rng, &available_gateways, must_use_tls).await?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, must_use_tls, no_hostname)?
}
GatewaySelectionSpecification::Specified {
must_use_tls,
no_hostname,
identity,
} => {
let gateway = get_specified_gateway(&identity, &available_gateways, must_use_tls)?;
SelectedGateway::from_topology_node(gateway, must_use_tls)?
SelectedGateway::from_topology_node(gateway, must_use_tls, no_hostname)?
}
GatewaySelectionSpecification::Custom {
gateway_identity,
Expand Down
52 changes: 38 additions & 14 deletions common/client-core/src/init/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,32 @@ impl SelectedGateway {
pub fn from_topology_node(
node: RoutingNode,
must_use_tls: bool,
no_hostname: bool,
) -> Result<Self, ClientCoreError> {
// for now, let's use 'old' behaviour, if you want to change it, you can pass it up the enum stack yourself : )
let prefer_ipv6 = false;

let gateway_listener = if must_use_tls {
node.ws_entry_address_tls()
.ok_or(ClientCoreError::UnsupportedWssProtocol {
gateway: node.identity_key.to_base58_string(),
})?
let (gateway_listener, _) = if must_use_tls {
// WSS main, no fallback
let primary =
node.ws_entry_address_tls()
.ok_or(ClientCoreError::UnsupportedWssProtocol {
gateway: node.identity_key.to_base58_string(),
})?;
(primary, None)
} else {
node.ws_entry_address(prefer_ipv6)
.ok_or(ClientCoreError::UnsupportedEntry {
let (maybe_primary, fallback) =
node.ws_entry_address_with_fallback(prefer_ipv6, no_hostname);
(
maybe_primary.ok_or(ClientCoreError::UnsupportedEntry {
id: node.node_id,
identity: node.identity_key.to_base58_string(),
})?
})?,
fallback,
)
};

let gateway_listener =
let gateway_listener_url =
Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener {
gateway_id: node.identity_key.to_base58_string(),
raw_listener: gateway_listener,
Expand All @@ -69,7 +77,7 @@ impl SelectedGateway {
Ok(SelectedGateway::Remote {
gateway_id: node.identity_key,
gateway_owner_address: None,
gateway_listener,
gateway_listener: gateway_listener_url,
})
}

Expand Down Expand Up @@ -150,15 +158,22 @@ impl InitialisationResult {
#[derive(Clone, Debug)]
pub enum GatewaySelectionSpecification {
/// Uniformly choose a random remote gateway.
UniformRemote { must_use_tls: bool },
UniformRemote {
must_use_tls: bool,
no_hostname: bool,
},

/// Should the new, remote, gateway be selected based on latency.
RemoteByLatency { must_use_tls: bool },
RemoteByLatency {
must_use_tls: bool,
no_hostname: bool,
},

/// Gateway with this specific identity should be chosen.
// JS: I don't really like the name of this enum variant but couldn't think of anything better at the time
Specified {
must_use_tls: bool,
no_hostname: bool,
identity: IdentityKey,
},

Expand All @@ -174,6 +189,7 @@ impl Default for GatewaySelectionSpecification {
fn default() -> Self {
GatewaySelectionSpecification::UniformRemote {
must_use_tls: false,
no_hostname: false,
}
}
}
Expand All @@ -183,16 +199,24 @@ impl GatewaySelectionSpecification {
gateway_identity: Option<String>,
latency_based_selection: Option<bool>,
must_use_tls: bool,
no_hostname: bool,
) -> Self {
if let Some(identity) = gateway_identity {
GatewaySelectionSpecification::Specified {
identity,
must_use_tls,
no_hostname,
}
} else if let Some(true) = latency_based_selection {
GatewaySelectionSpecification::RemoteByLatency { must_use_tls }
GatewaySelectionSpecification::RemoteByLatency {
must_use_tls,
no_hostname,
}
} else {
GatewaySelectionSpecification::UniformRemote { must_use_tls }
GatewaySelectionSpecification::UniformRemote {
must_use_tls,
no_hostname,
}
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions common/topology/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,45 @@ impl RoutingNode {
self.ws_entry_address_no_tls(prefer_ipv6)
}

pub fn ws_entry_address_with_fallback(
&self,
prefer_ipv6: bool,
no_hostname: bool,
) -> (Option<String>, Option<String>) {
let Some(entry) = &self.entry else {
return (None, None);
};

// Put hostname first if we want it
let maybe_hostname = if !no_hostname {
entry.hostname.clone()
} else {
None
};

// Put ipv6 first or keep them as is
let ips: Vec<&IpAddr> = if prefer_ipv6 {
entry
.ip_addresses
.iter()
.filter(|ip| ip.is_ipv6())
.chain(entry.ip_addresses.iter().filter(|ip| ip.is_ipv4()))
.collect()
} else {
entry.ip_addresses.iter().collect()
};

// chain everything and keep the top two as ws addresses
let ws_addresses: Vec<_> = maybe_hostname
.into_iter()
.chain(ips.into_iter().map(|ip| ip.to_string()))
.take(2)
.map(|host| format!("ws://{host}:{}", entry.clients_ws_port))
.collect();

(ws_addresses.first().cloned(), ws_addresses.get(1).cloned())
}

pub fn identity(&self) -> ed25519::PublicKey {
self.identity_key
}
Expand Down
1 change: 1 addition & 0 deletions nym-registration-client/src/builder/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ impl BuilderConfig {
.network_details(self.network_env)
.debug_config(debug_config)
.credentials_mode(true)
.no_hostname(true)
.with_remember_me(remember_me)
.custom_topology_provider(self.custom_topology_provider);

Expand Down
17 changes: 17 additions & 0 deletions sdk/rust/nym-sdk/src/mixnet/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub struct MixnetClientBuilder<S: MixnetClientStorage = Ephemeral> {
custom_shutdown: Option<ShutdownTracker>,
event_tx: Option<EventSender>,
force_tls: bool,
no_hostname: bool,
user_agent: Option<UserAgent>,
#[cfg(unix)]
connection_fd_callback: Option<Arc<dyn Fn(std::os::fd::RawFd) + Send + Sync>>,
Expand Down Expand Up @@ -101,6 +102,7 @@ impl MixnetClientBuilder<OnDiskPersistent> {
event_tx: None,
custom_gateway_transceiver: None,
force_tls: false,
no_hostname: false,
user_agent: None,
#[cfg(unix)]
connection_fd_callback: None,
Expand Down Expand Up @@ -134,6 +136,7 @@ where
custom_shutdown: None,
event_tx: None,
force_tls: false,
no_hostname: false,
user_agent: None,
#[cfg(unix)]
connection_fd_callback: None,
Expand All @@ -158,6 +161,7 @@ where
custom_shutdown: self.custom_shutdown,
event_tx: self.event_tx,
force_tls: self.force_tls,
no_hostname: self.no_hostname,
user_agent: self.user_agent,
#[cfg(unix)]
connection_fd_callback: self.connection_fd_callback,
Expand Down Expand Up @@ -229,6 +233,13 @@ where
self
}

/// Attempt to only choose a gateway with its IP address only, ignored if force_tls is set
#[must_use]
pub fn no_hostname(mut self, no_hostname: bool) -> Self {
self.no_hostname = no_hostname;
self
}

/// Enable paid coconut bandwidth credentials mode.
#[must_use]
pub fn enable_credentials_mode(mut self) -> Self {
Expand Down Expand Up @@ -341,6 +352,7 @@ where
client.custom_shutdown = self.custom_shutdown;
client.wait_for_gateway = self.wait_for_gateway;
client.force_tls = self.force_tls;
client.no_hostname = self.no_hostname;
client.user_agent = self.user_agent;
#[cfg(unix)]
if self.connection_fd_callback.is_some() {
Expand Down Expand Up @@ -393,6 +405,9 @@ where
/// Force the client to connect using wss protocol with the gateway.
force_tls: bool,

/// Force the client to pick gateway IP and not hostname, ignored if force_tls is set
no_hostname: bool,

/// Allows passing an externally controlled shutdown handle.
custom_shutdown: Option<ShutdownTracker>,

Expand Down Expand Up @@ -461,6 +476,7 @@ where
custom_gateway_transceiver: None,
wait_for_gateway: false,
force_tls: false,
no_hostname: false,
custom_shutdown: None,
event_tx,
user_agent: None,
Expand Down Expand Up @@ -580,6 +596,7 @@ where
self.config.user_chosen_gateway.clone(),
None,
self.force_tls,
self.no_hostname,
);

let available_gateways = self.available_gateways().await?;
Expand Down
Loading