feat(ssh): Add SCP subsystem packet processing framework (Phase 8 partial)
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

This commit is contained in:
Warren
2026-06-20 11:32:55 +08:00
parent 3e6acee2c5
commit ac17e1725c
2 changed files with 60 additions and 0 deletions

Binary file not shown.

View File

@@ -762,6 +762,66 @@ impl ChannelManager {
data.len()
);
// ⭐⭐⭐⭐⭐ Phase 8: SCP handler (subsystem)
if let Some(scp_handler) = &mut channel.scp_handler {
info!(
"⭐⭐⭐⭐⭐ [SCP_DATA] Feeding {} bytes to ScpHandler",
data.len()
);
// Window Control - decrease local_window
channel.local_window -= data.len() as u32;
channel.local_consumed += data.len() as u32;
// ⭐⭐⭐⭐⭐ Phase 14.4: SCP packet accumulation
channel.scp_input_buffer.extend_from_slice(&data);
info!(
"SCP buffer accumulated: {} bytes total",
channel.scp_input_buffer.len()
);
// Process SCP packets (line-based protocol)
// SCP uses newline-terminated commands: C0644, D0755, E, T
// Reference: OpenSSH scp.c
// Find complete lines in buffer
let mut responses: Vec<Vec<u8>> = Vec::new();
while let Some(newline_pos) = channel.scp_input_buffer.iter().position(|&b| b == b'\n') {
let line = channel.scp_input_buffer[..newline_pos].to_vec();
channel.scp_input_buffer = channel.scp_input_buffer[newline_pos + 1..].to_vec();
info!("SCP command: {}", String::from_utf8_lossy(&line));
// Process SCP command
// TODO: Full implementation requires ScpHandler.handle_scp() with ReadWrite trait
// Current implementation: basic ACK (0 byte)
responses.push(vec![0]); // SCP ACK
}
// Check for window adjust
if let Some(window_adjust_packet) =
channel_check_window(recipient_channel, &mut self.channels)
{
return Ok(Some(window_adjust_packet));
}
// Send SCP responses
if !responses.is_empty() {
// All responses except last go to pending_packets
for i in 0..responses.len().saturating_sub(1) {
let pending = self.build_channel_data(recipient_channel, &responses[i])?;
self.pending_packets.push_back(pending);
}
// Last response is returned
if let Some(last_response) = responses.into_iter().last() {
return Ok(Some(self.build_channel_data(recipient_channel, &last_response)?));
}
}
return Ok(None);
}
// ⭐⭐⭐⭐⭐ Phase 16.5: rsync in-process handler (no child process)
if let Some(rsync_handler) = &mut channel.rsync_handler {
info!(