Skip to content
Closed
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
29 changes: 18 additions & 11 deletions crates/openshell-server/src/ssh_tunnel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,29 @@ async fn ssh_connect(
}

// Enforce per-sandbox concurrent connection limit.
{
let sandbox_over_limit = {
let mut counts = state.ssh_connections_by_sandbox.lock().unwrap();
let count = counts.entry(sandbox_id.clone()).or_insert(0);
if *count >= MAX_CONNECTIONS_PER_SANDBOX {
// Roll back the per-token increment.
let mut token_counts = state.ssh_connections_by_token.lock().unwrap();
if let Some(c) = token_counts.get_mut(&token) {
*c = c.saturating_sub(1);
if *c == 0 {
token_counts.remove(&token);
}
true
} else {
*count += 1;
false
}
};
// Lock is released here before any rollback — avoids nested mutex acquisition.

if sandbox_over_limit {
// Roll back the per-token increment — no nested locks.
let mut token_counts = state.ssh_connections_by_token.lock().unwrap();
if let Some(c) = token_counts.get_mut(&token) {
*c = c.saturating_sub(1);
if *c == 0 {
token_counts.remove(&token);
}
warn!(sandbox_id = %sandbox_id, "SSH tunnel: per-sandbox connection limit reached");
return StatusCode::TOO_MANY_REQUESTS.into_response();
}
*count += 1;
warn!(sandbox_id = %sandbox_id, "SSH tunnel: per-sandbox connection limit reached");
return StatusCode::TOO_MANY_REQUESTS.into_response();
}

let handshake_secret = state.config.ssh_handshake_secret.clone();
Expand Down
Loading