Fix 5MB SFTP download hang: batch process SFTP packets + WINDOW_ADJUST chaining
Root cause: handle_channel_data processed only ONE SFTP packet per call, leaving remaining batched packets stuck in the buffer. Client waited for READ responses while server waited for more data — deadlock after ~3.1MB. Fix: - sftp_handler.rs: fix SSH_FXP_VERSION format (remove uint32 extension_count) - sftp_handler.rs: fix handle_open error mapping (.ok() → build_status_from_io_error) - channel.rs: batch-process ALL complete SFTP packets from buffer in loop - channel.rs: add pending_packets VecDeque for multi-response queuing - channel.rs: chain WINDOW_ADJUST + SFTP response when window is low - channel.rs: add adjust_remote_window() for client WINDOW_ADJUST - server.rs: drain pending_packets after each CHANNEL_DATA handler Verified: 5MB upload + download with matching MD5
This commit is contained in:
@@ -501,6 +501,13 @@ fn handle_ssh_service_loop(
|
||||
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");
|
||||
@@ -518,6 +525,15 @@ fn handle_ssh_service_loop(
|
||||
info!("Received SSH_MSG_DISCONNECT");
|
||||
break;
|
||||
}
|
||||
Some(&pt) if pt == PacketType::SSH_MSG_CHANNEL_WINDOW_ADJUST as u8 => {
|
||||
let payload = &packet.payload;
|
||||
if payload.len() >= 9 {
|
||||
// Format: uint32 recipient_channel || uint32 bytes_to_add
|
||||
let recipient_channel = u32::from_be_bytes([payload[1], payload[2], payload[3], payload[4]]);
|
||||
let bytes_to_add = u32::from_be_bytes([payload[5], payload[6], payload[7], payload[8]]);
|
||||
channel_manager.adjust_remote_window(recipient_channel, bytes_to_add);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
warn!("Unknown packet type: {:?}", packet.payload.first());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user