From 85d97c685b598df129ca6efff88b228fba4e4dda Mon Sep 17 00:00:00 2001 From: dr-frmr Date: Fri, 22 Mar 2024 12:45:19 -0600 Subject: [PATCH] fix: reserve ws port early and enforce it (hopefully) --- kinode/src/http/utils.rs | 10 +++---- kinode/src/main.rs | 39 ++++++++++++++++++++----- kinode/src/register.rs | 63 +++++++--------------------------------- 3 files changed, 48 insertions(+), 64 deletions(-) diff --git a/kinode/src/http/utils.rs b/kinode/src/http/utils.rs index 3f7f3c1f..cb80678c 100644 --- a/kinode/src/http/utils.rs +++ b/kinode/src/http/utils.rs @@ -100,18 +100,18 @@ pub fn deserialize_headers(hashmap: HashMap) -> HeaderMap { header_map } -pub async fn find_open_port(start_at: u16, end_at: u16) -> Option { +pub async fn find_open_port(start_at: u16, end_at: u16) -> Option { for port in start_at..end_at { let bind_addr = format!("0.0.0.0:{}", port); - if is_port_available(&bind_addr).await { - return Some(port); + if let Some(bound) = is_port_available(&bind_addr).await { + return Some(bound); } } None } -pub async fn is_port_available(bind_addr: &str) -> bool { - TcpListener::bind(bind_addr).await.is_ok() +pub async fn is_port_available(bind_addr: &str) -> Option { + TcpListener::bind(bind_addr).await.ok() } pub fn _binary_encoded_string_to_bytes(s: &str) -> Vec { diff --git a/kinode/src/main.rs b/kinode/src/main.rs index 1f082e8c..72b1d3d3 100644 --- a/kinode/src/main.rs +++ b/kinode/src/main.rs @@ -44,7 +44,7 @@ const DEFAULT_PROVIDERS_MAINNET: &str = include_str!("eth/default_providers_main async fn serve_register_fe( home_directory_path: &str, our_ip: String, - ws_networking_port: Option, + ws_networking: (tokio::net::TcpListener, bool), http_server_port: u16, testnet: bool, ) -> (Identity, Vec, Keyfile) { @@ -67,7 +67,7 @@ async fn serve_register_fe( let (tx, mut rx) = mpsc::channel::<(Identity, Keyfile, Vec)>(1); let (our, decoded_keyfile, encoded_keyfile) = tokio::select! { - _ = register::register(tx, kill_rx, our_ip, ws_networking_port, http_server_port, disk_keyfile, testnet) => { + _ = register::register(tx, kill_rx, our_ip, ws_networking, http_server_port, disk_keyfile, testnet) => { panic!("registration failed") } Some((our, decoded_keyfile, encoded_keyfile)) = rx.recv() => { @@ -260,7 +260,7 @@ async fn main() { let http_server_port = if let Some(port) = http_port { match http::utils::find_open_port(*port, port + 1).await { - Some(port) => port, + Some(bound) => bound.local_addr().unwrap().port(), None => { println!( "error: couldn't bind {}; first available port found was {}. \ @@ -268,14 +268,17 @@ async fn main() { port, http::utils::find_open_port(*port, port + 1000) .await - .expect("no ports found in range"), + .expect("no ports found in range") + .local_addr() + .unwrap() + .port(), ); panic!(); } } } else { match http::utils::find_open_port(8080, 8999).await { - Some(port) => port, + Some(bound) => bound.local_addr().unwrap().port(), None => { println!( "error: couldn't bind any ports between 8080 and 8999. \ @@ -286,6 +289,28 @@ async fn main() { } }; + // if the --ws-port flag is used, bind to that port right away. + // if the flag is not used, find the first available port between 9000 and 65535. + // NOTE: if the node has a different port specified in its onchain (direct) id, + // booting will fail if the flag was used to select a different port. + // if the flag was not used, the bound port will be dropped in favor of the onchain port. + + let (ws_tcp_handle, flag_used) = if let Some(port) = ws_networking_port { + ( + http::utils::find_open_port(*port, port + 1) + .await + .expect("ws-port selected with flag could not be bound"), + true, + ) + } else { + ( + http::utils::find_open_port(9000, 65535) + .await + .expect("no ports found in range 9000-65535 for websocket server"), + false, + ) + }; + println!( "login or register at http://localhost:{}\r", http_server_port @@ -295,7 +320,7 @@ async fn main() { let (our, encoded_keyfile, decoded_keyfile) = serve_register_fe( home_directory_path, our_ip.to_string(), - ws_networking_port.copied(), + (ws_tcp_handle, flag_used), http_server_port, on_testnet, // true if testnet mode ) @@ -309,7 +334,7 @@ async fn main() { serve_register_fe( &home_directory_path, our_ip.to_string(), - ws_networking_port.copied(), + (ws_tcp_handle, flag_used), http_server_port, on_testnet, // true if testnet mode ) diff --git a/kinode/src/register.rs b/kinode/src/register.rs index 73ac717b..a47afdf4 100644 --- a/kinode/src/register.rs +++ b/kinode/src/register.rs @@ -117,7 +117,7 @@ pub async fn register( tx: RegistrationSender, kill_rx: oneshot::Receiver, ip: String, - ws_networking_port: Option, + ws_networking: (tokio::net::TcpListener, bool), http_port: u16, keyfile: Option>, testnet: bool, @@ -127,29 +127,12 @@ pub async fn register( let net_keypair = Arc::new(serialized_networking_keypair.as_ref().to_vec()); let tx = Arc::new(tx); - let (ws_port, flag_used) = if let Some(port) = ws_networking_port { - ( - crate::http::utils::find_open_port(port, port + 1) - .await - .expect(&format!( - "error: couldn't bind {}; first available port found was {}. \ - Set an available port with `--ws-port` and try again.", - port, - crate::http::utils::find_open_port(port, port + 1000) - .await - .expect("no ports found in range"), - )), - true, - ) - } else { - (crate::http::utils::find_open_port(9000, 65535) - .await - .expect( - "Unable to find free port between 9000 and 65535 for a new websocket, are you kidding?", - ), false) - }; + let ws_port = ws_networking.0.local_addr().unwrap().port(); + let ws_flag_used = ws_networking.1; - // This is a temporary identity, passed to the UI. If it is confirmed through a /boot or /confirm-change-network-keys, then it will be used to replace the current identity + // This is a **temporary** identity, passed to the UI. + // If it is confirmed through a /boot or /confirm-change-network-keys, + // then it will be used to replace the current identity. let our_temp_id = Arc::new(Identity { networking_key: format!("0x{}", public_key), name: "".to_string(), @@ -185,6 +168,7 @@ pub async fn register( let net_keypair = warp::any().map(move || net_keypair.clone()); let tx = warp::any().map(move || tx.clone()); let ip = warp::any().map(move || ip.clone()); + let ws_port = warp::any().map(move || if ws_flag_used { Some(ws_port) } else { None }); let static_files = warp::path("static").and(static_dir!("src/register-ui/build/static/")); @@ -228,10 +212,10 @@ pub async fn register( Vec, )>(keyfile.as_ref()) { - return warp::reply::json(&username); + return warp::reply::html(username); } } - warp::reply::json(&"") + warp::reply::html(String::new()) }, )); @@ -282,7 +266,7 @@ pub async fn register( .and(warp::body::content_length_limit(1024 * 16)) .and(warp::body::json()) .and(ip.clone()) - .and(warp::any().map(move || if flag_used { Some(ws_port) } else { None })) + .and(ws_port.clone()) .and(tx.clone()) .and_then(move |boot_info, ip, ws_port, tx| { let import_provider = import_provider.clone(); @@ -294,7 +278,7 @@ pub async fn register( .and(warp::body::content_length_limit(1024 * 16)) .and(warp::body::json()) .and(ip) - .and(warp::any().map(move || if flag_used { Some(ws_port) } else { None })) + .and(ws_port.clone()) .and(tx.clone()) .and(keyfile.clone()) .and_then(move |boot_info, ip, ws_port, tx, keyfile| { @@ -320,31 +304,6 @@ pub async fn register( .and(keyfile) .and_then(confirm_change_network_keys), )); - // .or( - // warp::path("our").and(warp::get().and(keyfile.clone()).and_then(move |keyfile| { - // if let Some(keyfile) = keyfile { - // if let Ok((username, _, _, _, _, _)) = bincode::deserialize::<( - // String, - // Vec, - // Vec, - // Vec, - // Vec, - // Vec, - // )>(&keyfile) - // { - // return Ok(warp::reply::with_status( - // warp::reply::json(&username), - // StatusCode::OK, - // ) - // .into_response()); - // } - // } - // Ok( - // warp::reply::with_status(warp::reply::json(&""), StatusCode::OK) - // .into_response(), - // ) - // })), - // ); let mut headers = HeaderMap::new(); headers.insert(