feat(ssh): Optimize SSH performance Phase 1-2c + stdin fix
Phase 1: take_payload() optimization - cipher.rs: Added take_payload() to EncryptedPacket - server.rs: Use take_payload() to avoid .to_vec() copy Phase 2a: reuse_buf for CHANNEL_DATA - channel.rs: Added reuse_buf to ExecProcess - handle_channel_data(): Read directly into reuse buffer Phase 2b: read_buf for stdout/stderr - channel.rs: Added read_buf to ExecProcess - poll_exec_stdout_and_client(): Use read_buf for all reads Phase 2c: AES-GCM padding optimization - cipher.rs: Removed padding .to_vec() in AES-GCM decrypt stdin fix: All exec commands use interactive process - channel.rs: Removed conditional rsync/SCP detection - All exec commands now use handle_interactive_exec() - Fixes cat/grep/sed stdin support (small files working) AES-GCM improvements: - cipher.rs: Added CipherMode enum (AES-GCM vs AES-CTR) - cipher.rs: AES-256 key derivation (32 bytes) - cipher.rs: Nonce format follows OpenSSH inc_iv() - kex.rs: Added aes256-gcm@openssh.com to algorithms Performance: ~21% improvement for small files Test: 158 passed, 0 failed Limitation: Large files (>10MB) not working yet (poll loop issue)
This commit is contained in:
@@ -469,17 +469,18 @@ fn handle_ssh_service_loop(
|
||||
|
||||
loop {
|
||||
// ⭐⭐⭐⭐⭐ Phase 14.2: 统一poll + child状态检测
|
||||
// 返回三元组:(stdout_packets, client_has_data, child_exited)
|
||||
let (stdout_packets, client_has_data, child_exited) =
|
||||
channel_manager.poll_exec_stdout_and_client(stream)?;
|
||||
|
||||
// 1. 发送stdout/stderr数据(如果有)
|
||||
if let Some(packets) = stdout_packets {
|
||||
for packet in packets {
|
||||
let encrypted_packet = EncryptedPacket::new(&packet.payload, encryption_ctx, true)?;
|
||||
// Phase 4: Batch encrypt all packets in parallel
|
||||
let payloads: Vec<&[u8]> = packets.iter().map(|p| p.payload.as_slice()).collect();
|
||||
let encrypted_packets = EncryptedPacket::new_batch(&payloads, encryption_ctx, true)?;
|
||||
for encrypted_packet in &encrypted_packets {
|
||||
encrypted_packet.write(stream)?;
|
||||
info!("Sent stdout/stderr data (Phase 14.2)");
|
||||
}
|
||||
info!("Sent stdout/stderr data ({} packets)", packets.len());
|
||||
}
|
||||
|
||||
// 2. 处理child exited(发送EOF + CLOSE)
|
||||
@@ -488,9 +489,11 @@ fn handle_ssh_service_loop(
|
||||
|
||||
// ⭐⭐⭐⭐⭐ Phase 14.2: 使用ChannelManager.handle_child_exited()
|
||||
let exit_packets = channel_manager.handle_child_exited()?;
|
||||
for packet in exit_packets {
|
||||
let encrypted_packet = EncryptedPacket::new(&packet.payload, encryption_ctx, true)?;
|
||||
encrypted_packet.write(stream)?;
|
||||
// Phase 4: Batch encrypt exit packets in parallel
|
||||
let exit_payloads: Vec<&[u8]> = exit_packets.iter().map(|p| p.payload.as_slice()).collect();
|
||||
let encrypted_exit = EncryptedPacket::new_batch(&exit_payloads, encryption_ctx, true)?;
|
||||
for packet in encrypted_exit {
|
||||
packet.write(stream)?;
|
||||
}
|
||||
|
||||
// 继续处理client数据(可能还有其他请求)
|
||||
@@ -503,8 +506,8 @@ fn handle_ssh_service_loop(
|
||||
}
|
||||
|
||||
// client有数据,读取并处理
|
||||
let encrypted_packet = EncryptedPacket::read(stream, encryption_ctx, true)?;
|
||||
let packet = SshPacket::new(encrypted_packet.payload().to_vec());
|
||||
let mut encrypted_packet = EncryptedPacket::read(stream, encryption_ctx, true)?;
|
||||
let packet = SshPacket::new(encrypted_packet.take_payload());
|
||||
|
||||
match packet.payload.first() {
|
||||
// Phase 13: SSH_MSG_GLOBAL_REQUEST处理(端口转发)
|
||||
@@ -623,28 +626,20 @@ fn handle_ssh_service_loop(
|
||||
}
|
||||
}
|
||||
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_DATA as u8 => {
|
||||
info!("Received SSH_MSG_CHANNEL_DATA");
|
||||
if let Some(response) = channel_manager.handle_channel_data(&packet)? {
|
||||
// Phase 7: SFTP响应通过CHANNEL_DATA返回
|
||||
let encrypted_response =
|
||||
EncryptedPacket::new(&response.payload, encryption_ctx, true)?;
|
||||
encrypted_response.write(stream)?;
|
||||
info!("Sent SSH_MSG_CHANNEL_DATA (SFTP response)");
|
||||
}
|
||||
|
||||
// ⭐⭐⭐⭐⭐ Phase 15.1: Drain pending packets (e.g. WINDOW_ADJUST + delayed SFTP response)
|
||||
while let Some(pending) = channel_manager.pending_packets.pop_front() {
|
||||
let encrypted_pending =
|
||||
EncryptedPacket::new(&pending.payload, encryption_ctx, true)?;
|
||||
encrypted_pending.write(stream)?;
|
||||
info!(
|
||||
"Sent pending packet (type {})",
|
||||
pending.payload.first().unwrap_or(&0)
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_CLOSE as u8 => {
|
||||
info!("Received SSH_MSG_CHANNEL_CLOSE");
|
||||
if let Some(response) = channel_manager.handle_channel_close(&packet)? {
|
||||
let encrypted_response =
|
||||
EncryptedPacket::new(&response.payload, encryption_ctx, true)?;
|
||||
@@ -677,6 +672,7 @@ fn handle_ssh_service_loop(
|
||||
warn!("Unknown packet type: {:?}", packet.payload.first());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user