Skip to content

Commit 9c6be63

Browse files
authored
Merge pull request #27 from lablup/feature/issue-24-implement-pty-allocation
feat: implement true PTY allocation for interactive SSH sessions
2 parents 9550834 + ee036d2 commit 9c6be63

23 files changed

Lines changed: 4285 additions & 145 deletions

ARCHITECTURE.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,140 @@ Interactive mode provides persistent shell sessions with single-node or multiple
309309
- Node-prefixed output with color coding
310310
- Visual status indicators (● connected, ○ disconnected)
311311

312+
## PTY Implementation Design
313+
314+
### Architecture Overview
315+
316+
The PTY implementation provides true terminal emulation for interactive SSH sessions. It's designed with careful attention to performance, memory usage, and user experience through systematic configuration of timeouts, buffer sizes, and concurrency controls.
317+
318+
### Core Components
319+
320+
1. **PTY Session (`pty/session.rs`)**
321+
- Manages bidirectional terminal communication
322+
- Handles terminal resize events
323+
- Processes key sequences and ANSI escape codes
324+
- Provides graceful shutdown with proper cleanup
325+
326+
2. **PTY Manager (`pty/mod.rs`)**
327+
- Orchestrates multiple PTY sessions
328+
- Supports both single-node and multiplex modes
329+
- Manages session lifecycle and resource cleanup
330+
331+
3. **Terminal State Management (`pty/terminal.rs`)**
332+
- RAII guards for terminal state preservation
333+
- Raw mode management with global synchronization
334+
- Mouse support and alternate screen handling
335+
336+
### Buffer Pool Design (`utils/buffer_pool.rs`)
337+
338+
The buffer pool uses a three-tier system optimized for different I/O patterns:
339+
340+
**Buffer Tier Design Rationale:**
341+
- **Small (1KB)**: Terminal key sequences, command responses
342+
- Optimal for individual keypresses and short responses
343+
- Minimizes memory waste for frequent small allocations
344+
- **Medium (8KB)**: SSH command I/O, multi-line output
345+
- Balances memory usage with syscall efficiency
346+
- Matches common SSH channel packet sizes
347+
- **Large (64KB)**: SFTP transfers, bulk operations
348+
- Reduces syscall overhead for high-throughput operations
349+
- Standard size for network I/O buffers
350+
351+
**Pool Management:**
352+
- Maximum 16 buffers per tier prevents unbounded memory growth
353+
- Total pooled memory: 16KB (small) + 128KB (medium) + 1MB (large) = ~1.14MB
354+
- Automatic return to pool on buffer drop (RAII pattern)
355+
356+
### Timeout and Performance Constants
357+
358+
All timeouts and buffer sizes have been carefully chosen based on empirical testing and user experience requirements:
359+
360+
**Connection Timeouts:**
361+
- **SSH Connection**: 30 seconds - Industry standard, handles slow networks and SSH negotiation
362+
- **Command Execution**: 300 seconds (5 minutes) - Accommodates long-running operations
363+
- **File Operations**: 300s (single files), 600s (directories) - Based on typical transfer sizes
364+
365+
**Interactive Response Times:**
366+
- **Input Polling**: 10ms - Appears instantaneous to users (<20ms perception threshold)
367+
- **Output Processing**: 10ms - Maintains real-time feel for terminal output
368+
- **PTY Timeout**: 10ms - Rapid response for interactive terminals
369+
- **Input Poll (blocking)**: 500ms - Longer timeout in blocking thread reduces CPU usage
370+
371+
**Channel and Buffer Sizing:**
372+
- **PTY Message Channel**: 256 messages - Handles burst I/O without delays (~16KB memory)
373+
- **SSH Output Channel**: 128 messages - Smooths bursty shell command output
374+
- **Session Switch Channel**: 32 messages - Sufficient for user switching actions
375+
- **Resize Signal Channel**: 16 messages - Handles rapid window resizing events
376+
377+
**Cleanup and Shutdown:**
378+
- **Task Cleanup**: 100ms - Allows graceful task termination
379+
- **PTY Shutdown**: 5 seconds - Time for multiple sessions to cleanup
380+
- **SSH Exit Delay**: 100ms - Ensures remote shell processes exit command
381+
382+
### Memory Management Strategy
383+
384+
**Stack-Allocated Optimizations:**
385+
- `SmallVec<[u8; 8]>` for key sequences - Most terminal key sequences are 1-5 bytes
386+
- `SmallVec<[u8; 64]>` for output messages - Typical terminal lines fit in 64 bytes
387+
- Pre-allocated constant arrays for common key sequences (Ctrl+C, arrows, function keys)
388+
389+
**Bounded Channels:**
390+
- All channels use bounded capacity to prevent memory exhaustion
391+
- Graceful degradation when channels reach capacity (drop oldest data)
392+
- Non-blocking sends with error handling prevent deadlocks
393+
394+
### Concurrency Design
395+
396+
**Event Multiplexing:**
397+
- Extensive use of `tokio::select!` for efficient event handling
398+
- Separate tasks for input reading, output processing, and resize handling
399+
- Cancellation tokens for coordinated shutdown across all tasks
400+
401+
**Thread Pool Usage:**
402+
- Input reading runs in blocking thread pool (crossterm limitation)
403+
- All other operations use async runtime for maximum concurrency
404+
- Semaphore-based concurrency limiting in parallel execution
405+
406+
### Error Handling and Recovery
407+
408+
**Graceful Degradation:**
409+
- Connection failures don't crash entire session
410+
- Output channel saturation drops data rather than blocking
411+
- Terminal state always restored on exit (RAII guards)
412+
413+
**Resource Cleanup:**
414+
- Multiple cleanup mechanisms ensure terminal restoration
415+
- `Drop` implementations provide failsafe cleanup
416+
- Force cleanup functions for emergency recovery
417+
418+
### Performance Characteristics
419+
420+
**Target Performance:**
421+
- **Latency**: <10ms for key press to remote echo
422+
- **Throughput**: Handle 1000+ lines/second output streams
423+
- **Memory**: <50MB for 100 concurrent PTY sessions
424+
- **CPU**: <5% on modern systems for typical workloads
425+
426+
**Optimization Techniques:**
427+
- Constant arrays for frequent key sequences avoid allocations
428+
- Buffer pooling reduces GC pressure
429+
- Bounded channels prevent unbounded memory growth
430+
- Event-driven architecture minimizes polling overhead
431+
432+
### Security Considerations
433+
434+
**Input Sanitization:**
435+
- All key sequences validated before transmission
436+
- Terminal escape sequences handled safely
437+
- No arbitrary code execution from terminal sequences
438+
439+
**Resource Limits:**
440+
- Channel capacities prevent memory exhaustion attacks
441+
- Timeout values prevent resource starvation
442+
- Proper cleanup prevents resource leaks
443+
444+
This design provides a production-ready PTY implementation that balances performance, reliability, and user experience while maintaining strict resource controls and graceful error handling.
445+
312446
### Implementation Details
313447

314448
```rust

Cargo.lock

Lines changed: 32 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,15 @@ whoami = "1.6.1"
3333
owo-colors = "4.2.2"
3434
unicode-width = "0.2.1"
3535
terminal_size = "0.4.3"
36+
once_cell = "1.20"
37+
zeroize = "1.8"
3638
rustyline = "17.0.1"
3739
crossterm = "0.29"
3840
ctrlc = "3.4"
41+
signal-hook = "0.3.18"
42+
atty = "0.2.14"
43+
arrayvec = "0.7.6"
44+
smallvec = "1.13.2"
3945

4046
[dev-dependencies]
4147
tempfile = "3"

examples/interactive_demo.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use bssh::commands::interactive::InteractiveCommand;
1818
use bssh::config::{Config, InteractiveConfig};
1919
use bssh::node::Node;
20+
use bssh::pty::PtyConfig;
2021
use bssh::ssh::known_hosts::StrictHostKeyChecking;
2122
use std::path::PathBuf;
2223

@@ -53,6 +54,8 @@ async fn main() -> anyhow::Result<()> {
5354
use_agent: false,
5455
use_password: false,
5556
strict_mode: StrictHostKeyChecking::AcceptNew,
57+
pty_config: PtyConfig::default(),
58+
use_pty: None,
5659
};
5760

5861
println!("Starting interactive session...");

src/cli.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use std::path::PathBuf;
1919
#[command(
2020
name = "bssh",
2121
version,
22-
before_help = "",
22+
before_help = "\n\nBackend.AI SSH - Parallel command execution across cluster nodes",
2323
about = "Backend.AI SSH - SSH-compatible parallel command execution tool",
24-
long_about = "bssh is a high-performance SSH client with parallel execution capabilities.\nIt can be used as a drop-in replacement for SSH (single host) or as a powerful cluster management tool (multiple hosts).\n\nSSH Compatibility Mode:\n bssh user@host # Interactive shell\n bssh user@host command # Execute command\n bssh -p 2222 user@host # Custom port\n bssh -i key.pem user@host # Custom key\n\nMulti-Server Mode:\n bssh -C production \"uptime\" # Execute on cluster\n bssh -H \"host1,host2\" \"df -h\" # Execute on hosts\n\nThe tool provides secure file transfer using SFTP and supports SSH keys, SSH agent, and password authentication.\nIt automatically detects Backend.AI multi-node session environments.",
25-
after_help = "EXAMPLES:\n SSH Mode:\n bssh user@host # Interactive shell\n bssh admin@server.com \"uptime\" # Execute command\n bssh -p 2222 -i ~/.ssh/key user@host # Custom port and key\n\n Multi-Server Mode:\n bssh -C production \"systemctl status\" # Use cluster config\n bssh -H \"web1,web2,web3\" \"df -h\" # Direct hosts\n\n File Operations:\n bssh -C staging upload file.txt /tmp/ # Upload to cluster\n bssh -H host1,host2 download /etc/hosts ./backups/\n\n Other Commands:\n bssh list # List configured clusters\n bssh -C production ping # Test connectivity\n\nFor more information: https://github.com/lablup/bssh"
24+
long_about = "bssh is a high-performance SSH client with parallel execution capabilities.\nIt can be used as a drop-in replacement for SSH (single host) or as a powerful cluster management tool (multiple hosts).\n\nThe tool provides secure file transfer using SFTP and supports SSH keys, SSH agent, and password authentication.\nIt automatically detects Backend.AI multi-node session environments.",
25+
after_help = "EXAMPLES:\n SSH Mode:\n bssh user@host # Interactive shell\n bssh admin@server.com \"uptime\" # Execute command\n bssh -p 2222 -i ~/.ssh/key user@host # Custom port and key\n\n Multi-Server Mode:\n bssh -C production \"systemctl status\" # Use cluster config\n bssh -H \"web1,web2,web3\" \"df -h\" # Direct hosts\n\n File Operations:\n bssh -C staging upload file.txt /tmp/ # Upload to cluster\n bssh -H host1,host2 download /etc/hosts ./backups/\n\n Other Commands:\n bssh list # List configured clusters\n bssh -C production ping # Test connectivity\n\nDeveloped and maintained as part of the Backend.AI project.\nFor more information: https://github.com/lablup/bssh"
2626
)]
2727
pub struct Cli {
2828
/// SSH destination in format: [user@]hostname[:port] or ssh://[user@]hostname[:port]

0 commit comments

Comments
 (0)