diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-01-12 04:28:28 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-01-12 04:51:34 +0800 |
| commit | c5fb22694e95f12c24b8d8af76999be7aea3fcec (patch) | |
| tree | 399d8a24ce491fb635f3d09f2123290fe784059e /crates/utils/tcp_connection | |
| parent | 444754489aca0454eb54e15a49fb8a6db0b68a07 (diff) | |
Reorganize crate structure and move documentation files
Diffstat (limited to 'crates/utils/tcp_connection')
21 files changed, 0 insertions, 1976 deletions
diff --git a/crates/utils/tcp_connection/Cargo.toml b/crates/utils/tcp_connection/Cargo.toml deleted file mode 100644 index da258be..0000000 --- a/crates/utils/tcp_connection/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "tcp_connection" -edition = "2024" -version.workspace = true - -[dependencies] -tokio = { version = "1.48.0", features = ["full"] } - -# Serialization -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.145" -rmp-serde = "1.3.0" - -# Error handling -thiserror = "2.0.17" - -# Uuid & Random -uuid = "1.18.1" - -# Crypto -rsa = { version = "0.9", features = ["pkcs5", "sha2"] } -ed25519-dalek = "3.0.0-pre.1" -ring = "0.17.14" -rand = "0.10.0-rc.0" -base64 = "0.22.1" -pem = "3.0.6" -crc = "3.3.0" -blake3 = "1.8.2" diff --git a/crates/utils/tcp_connection/src/error.rs b/crates/utils/tcp_connection/src/error.rs deleted file mode 100644 index 32d06cc..0000000 --- a/crates/utils/tcp_connection/src/error.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::io; -use thiserror::Error; - -#[derive(Error, Debug, Clone)] -pub enum TcpTargetError { - #[error("Authentication failed: {0}")] - Authentication(String), - - #[error("Reference sheet not allowed: {0}")] - ReferenceSheetNotAllowed(String), - - #[error("Cryptographic error: {0}")] - Crypto(String), - - #[error("File operation error: {0}")] - File(String), - - #[error("I/O error: {0}")] - Io(String), - - #[error("Invalid configuration: {0}")] - Config(String), - - #[error("Locked: {0}")] - Locked(String), - - #[error("Network error: {0}")] - Network(String), - - #[error("No result: {0}")] - NoResult(String), - - #[error("Not found: {0}")] - NotFound(String), - - #[error("Not local machine: {0}")] - NotLocal(String), - - #[error("Not remote machine: {0}")] - NotRemote(String), - - #[error("Pool already exists: {0}")] - PoolAlreadyExists(String), - - #[error("Protocol error: {0}")] - Protocol(String), - - #[error("Serialization error: {0}")] - Serialization(String), - - #[error("Timeout: {0}")] - Timeout(String), - - #[error("Unsupported operation: {0}")] - Unsupported(String), -} - -impl From<io::Error> for TcpTargetError { - fn from(error: io::Error) -> Self { - TcpTargetError::Io(error.to_string()) - } -} - -impl From<serde_json::Error> for TcpTargetError { - fn from(error: serde_json::Error) -> Self { - TcpTargetError::Serialization(error.to_string()) - } -} - -impl From<&str> for TcpTargetError { - fn from(value: &str) -> Self { - TcpTargetError::Protocol(value.to_string()) - } -} - -impl From<String> for TcpTargetError { - fn from(value: String) -> Self { - TcpTargetError::Protocol(value) - } -} - -impl From<rsa::errors::Error> for TcpTargetError { - fn from(error: rsa::errors::Error) -> Self { - TcpTargetError::Crypto(error.to_string()) - } -} - -impl From<ed25519_dalek::SignatureError> for TcpTargetError { - fn from(error: ed25519_dalek::SignatureError) -> Self { - TcpTargetError::Crypto(error.to_string()) - } -} - -impl From<ring::error::Unspecified> for TcpTargetError { - fn from(error: ring::error::Unspecified) -> Self { - TcpTargetError::Crypto(error.to_string()) - } -} - -impl From<base64::DecodeError> for TcpTargetError { - fn from(error: base64::DecodeError) -> Self { - TcpTargetError::Serialization(error.to_string()) - } -} - -impl From<pem::PemError> for TcpTargetError { - fn from(error: pem::PemError) -> Self { - TcpTargetError::Crypto(error.to_string()) - } -} - -impl From<rmp_serde::encode::Error> for TcpTargetError { - fn from(error: rmp_serde::encode::Error) -> Self { - TcpTargetError::Serialization(error.to_string()) - } -} - -impl From<rmp_serde::decode::Error> for TcpTargetError { - fn from(error: rmp_serde::decode::Error) -> Self { - TcpTargetError::Serialization(error.to_string()) - } -} diff --git a/crates/utils/tcp_connection/src/instance.rs b/crates/utils/tcp_connection/src/instance.rs deleted file mode 100644 index 8e6886c..0000000 --- a/crates/utils/tcp_connection/src/instance.rs +++ /dev/null @@ -1,542 +0,0 @@ -use std::{path::Path, time::Duration}; - -use serde::Serialize; -use tokio::{ - fs::{File, OpenOptions}, - io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter}, - net::TcpStream, -}; - -use ring::signature::{self}; - -use crate::error::TcpTargetError; - -const DEFAULT_CHUNK_SIZE: usize = 4096; -const DEFAULT_TIMEOUT_SECS: u64 = 10; - -const ECDSA_P256_SHA256_ASN1_SIGNING: &signature::EcdsaSigningAlgorithm = - &signature::ECDSA_P256_SHA256_ASN1_SIGNING; -const ECDSA_P384_SHA384_ASN1_SIGNING: &signature::EcdsaSigningAlgorithm = - &signature::ECDSA_P384_SHA384_ASN1_SIGNING; - -#[derive(Debug, Clone)] -pub struct ConnectionConfig { - pub chunk_size: usize, - pub timeout_secs: u64, - pub enable_crc_validation: bool, -} - -impl Default for ConnectionConfig { - fn default() -> Self { - Self { - chunk_size: DEFAULT_CHUNK_SIZE, - timeout_secs: DEFAULT_TIMEOUT_SECS, - enable_crc_validation: false, - } - } -} - -pub struct ConnectionInstance { - pub(crate) stream: TcpStream, - config: ConnectionConfig, -} - -impl From<TcpStream> for ConnectionInstance { - fn from(stream: TcpStream) -> Self { - Self { - stream, - config: ConnectionConfig::default(), - } - } -} - -impl ConnectionInstance { - /// Create a new ConnectionInstance with custom configuration - pub fn with_config(stream: TcpStream, config: ConnectionConfig) -> Self { - Self { stream, config } - } - - /// Get a reference to the current configuration - pub fn config(&self) -> &ConnectionConfig { - &self.config - } - - /// Get a mutable reference to the current configuration - pub fn config_mut(&mut self) -> &mut ConnectionConfig { - &mut self.config - } - /// Serialize data and write to the target machine - pub async fn write<Data>(&mut self, data: Data) -> Result<(), TcpTargetError> - where - Data: Default + Serialize, - { - let Ok(json_text) = serde_json::to_string(&data) else { - return Err(TcpTargetError::Serialization( - "Serialize failed.".to_string(), - )); - }; - Self::write_text(self, json_text).await?; - Ok(()) - } - - /// Serialize data to MessagePack and write to the target machine - pub async fn write_msgpack<Data>(&mut self, data: Data) -> Result<(), TcpTargetError> - where - Data: Serialize, - { - let msgpack_data = rmp_serde::to_vec(&data)?; - let len = msgpack_data.len() as u32; - - self.stream.write_all(&len.to_be_bytes()).await?; - self.stream.write_all(&msgpack_data).await?; - Ok(()) - } - - /// Read data from target machine and deserialize from MessagePack - pub async fn read_msgpack<Data>(&mut self) -> Result<Data, TcpTargetError> - where - Data: serde::de::DeserializeOwned, - { - let mut len_buf = [0u8; 4]; - self.stream.read_exact(&mut len_buf).await?; - let len = u32::from_be_bytes(len_buf) as usize; - - let mut buffer = vec![0; len]; - self.stream.read_exact(&mut buffer).await?; - - let data = rmp_serde::from_slice(&buffer)?; - Ok(data) - } - - /// Read data from target machine and deserialize - pub async fn read<Data>(&mut self) -> Result<Data, TcpTargetError> - where - Data: Default + serde::de::DeserializeOwned, - { - let Ok(json_text) = Self::read_text(self).await else { - return Err(TcpTargetError::Io("Read failed.".to_string())); - }; - let Ok(deser_obj) = serde_json::from_str::<Data>(&json_text) else { - return Err(TcpTargetError::Serialization( - "Deserialize failed.".to_string(), - )); - }; - Ok(deser_obj) - } - - /// Serialize data and write to the target machine - pub async fn write_large<Data>(&mut self, data: Data) -> Result<(), TcpTargetError> - where - Data: Default + Serialize, - { - let Ok(json_text) = serde_json::to_string(&data) else { - return Err(TcpTargetError::Serialization( - "Serialize failed.".to_string(), - )); - }; - Self::write_large_text(self, json_text).await?; - Ok(()) - } - - /// Read data from target machine and deserialize - pub async fn read_large<Data>( - &mut self, - buffer_size: impl Into<u32>, - ) -> Result<Data, TcpTargetError> - where - Data: Default + serde::de::DeserializeOwned, - { - let Ok(json_text) = Self::read_large_text(self, buffer_size).await else { - return Err(TcpTargetError::Io("Read failed.".to_string())); - }; - let Ok(deser_obj) = serde_json::from_str::<Data>(&json_text) else { - return Err(TcpTargetError::Serialization( - "Deserialize failed.".to_string(), - )); - }; - Ok(deser_obj) - } - - /// Write text to the target machine - pub async fn write_text(&mut self, text: impl Into<String>) -> Result<(), TcpTargetError> { - let text = text.into(); - let bytes = text.as_bytes(); - let len = bytes.len() as u32; - - self.stream.write_all(&len.to_be_bytes()).await?; - match self.stream.write_all(bytes).await { - Ok(_) => Ok(()), - Err(err) => Err(TcpTargetError::Io(err.to_string())), - } - } - - /// Read text from the target machine - pub async fn read_text(&mut self) -> Result<String, TcpTargetError> { - let mut len_buf = [0u8; 4]; - self.stream.read_exact(&mut len_buf).await?; - let len = u32::from_be_bytes(len_buf) as usize; - - let mut buffer = vec![0; len]; - self.stream.read_exact(&mut buffer).await?; - - match String::from_utf8(buffer) { - Ok(text) => Ok(text), - Err(err) => Err(TcpTargetError::Serialization(format!( - "Invalid UTF-8 sequence: {}", - err - ))), - } - } - - /// Write large text to the target machine (chunked) - pub async fn write_large_text( - &mut self, - text: impl Into<String>, - ) -> Result<(), TcpTargetError> { - let text = text.into(); - let bytes = text.as_bytes(); - let mut offset = 0; - - while offset < bytes.len() { - let chunk = &bytes[offset..]; - let written = match self.stream.write(chunk).await { - Ok(n) => n, - Err(err) => return Err(TcpTargetError::Io(err.to_string())), - }; - offset += written; - } - - Ok(()) - } - - /// Read large text from the target machine (chunked) - pub async fn read_large_text( - &mut self, - chunk_size: impl Into<u32>, - ) -> Result<String, TcpTargetError> { - let chunk_size = chunk_size.into() as usize; - let mut buffer = Vec::new(); - let mut chunk_buf = vec![0; chunk_size]; - - loop { - match self.stream.read(&mut chunk_buf).await { - Ok(0) => break, // EOF - Ok(n) => { - buffer.extend_from_slice(&chunk_buf[..n]); - } - Err(err) => return Err(TcpTargetError::Io(err.to_string())), - } - } - - Ok(String::from_utf8_lossy(&buffer).to_string()) - } - - /// Write large MessagePack data to the target machine (chunked) - pub async fn write_large_msgpack<Data>( - &mut self, - data: Data, - chunk_size: impl Into<u32>, - ) -> Result<(), TcpTargetError> - where - Data: Serialize, - { - let msgpack_data = rmp_serde::to_vec(&data)?; - let chunk_size = chunk_size.into() as usize; - let len = msgpack_data.len() as u32; - - // Write total length first - self.stream.write_all(&len.to_be_bytes()).await?; - - // Write data in chunks - let mut offset = 0; - while offset < msgpack_data.len() { - let end = std::cmp::min(offset + chunk_size, msgpack_data.len()); - let chunk = &msgpack_data[offset..end]; - match self.stream.write(chunk).await { - Ok(n) => offset += n, - Err(err) => return Err(TcpTargetError::Io(err.to_string())), - } - } - - Ok(()) - } - - /// Read large MessagePack data from the target machine (chunked) - pub async fn read_large_msgpack<Data>( - &mut self, - chunk_size: impl Into<u32>, - ) -> Result<Data, TcpTargetError> - where - Data: serde::de::DeserializeOwned, - { - let chunk_size = chunk_size.into() as usize; - - // Read total length first - let mut len_buf = [0u8; 4]; - self.stream.read_exact(&mut len_buf).await?; - let total_len = u32::from_be_bytes(len_buf) as usize; - - // Read data in chunks - let mut buffer = Vec::with_capacity(total_len); - let mut remaining = total_len; - let mut chunk_buf = vec![0; chunk_size]; - - while remaining > 0 { - let read_size = std::cmp::min(chunk_size, remaining); - let chunk = &mut chunk_buf[..read_size]; - - match self.stream.read_exact(chunk).await { - Ok(_) => { - buffer.extend_from_slice(chunk); - remaining -= read_size; - } - Err(err) => return Err(TcpTargetError::Io(err.to_string())), - } - } - - let data = rmp_serde::from_slice(&buffer)?; - Ok(data) - } - - /// Write file to target machine. - pub async fn write_file(&mut self, file_path: impl AsRef<Path>) -> Result<(), TcpTargetError> { - let path = file_path.as_ref(); - - // Validate file - if !path.exists() { - return Err(TcpTargetError::File(format!( - "File not found: {}", - path.display() - ))); - } - if path.is_dir() { - return Err(TcpTargetError::File(format!( - "Path is directory: {}", - path.display() - ))); - } - - // Open file and get metadata - let mut file = File::open(path).await?; - let file_size = file.metadata().await?.len(); - - // Send file header (version + size + crc) - self.stream.write_all(&1u64.to_be_bytes()).await?; - self.stream.write_all(&file_size.to_be_bytes()).await?; - - // Calculate and send CRC32 if enabled - let file_crc = if self.config.enable_crc_validation { - let crc32 = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC); - let mut crc_calculator = crc32.digest(); - - let mut temp_reader = - BufReader::with_capacity(self.config.chunk_size, File::open(path).await?); - let mut temp_buffer = vec![0u8; self.config.chunk_size]; - let mut temp_bytes_read = 0; - - while temp_bytes_read < file_size { - let bytes_to_read = - (file_size - temp_bytes_read).min(self.config.chunk_size as u64) as usize; - temp_reader - .read_exact(&mut temp_buffer[..bytes_to_read]) - .await?; - crc_calculator.update(&temp_buffer[..bytes_to_read]); - temp_bytes_read += bytes_to_read as u64; - } - - crc_calculator.finalize() - } else { - 0 - }; - - self.stream.write_all(&file_crc.to_be_bytes()).await?; - - // If file size is 0, skip content transfer - if file_size == 0 { - self.stream.flush().await?; - - // Wait for receiver confirmation - let mut ack = [0u8; 1]; - tokio::time::timeout( - Duration::from_secs(self.config.timeout_secs), - self.stream.read_exact(&mut ack), - ) - .await - .map_err(|_| TcpTargetError::Timeout("Ack timeout".to_string()))??; - - if ack[0] != 1 { - return Err(TcpTargetError::Protocol( - "Receiver verification failed".to_string(), - )); - } - - return Ok(()); - } - - // Transfer file content - let mut reader = BufReader::with_capacity(self.config.chunk_size, &mut file); - let mut bytes_sent = 0; - - while bytes_sent < file_size { - let buffer = reader.fill_buf().await?; - if buffer.is_empty() { - break; - } - - let chunk_size = buffer.len().min((file_size - bytes_sent) as usize); - self.stream.write_all(&buffer[..chunk_size]).await?; - reader.consume(chunk_size); - - bytes_sent += chunk_size as u64; - } - - // Verify transfer completion - if bytes_sent != file_size { - return Err(TcpTargetError::File(format!( - "Transfer incomplete: expected {} bytes, sent {} bytes", - file_size, bytes_sent - ))); - } - - self.stream.flush().await?; - - // Wait for receiver confirmation - let mut ack = [0u8; 1]; - tokio::time::timeout( - Duration::from_secs(self.config.timeout_secs), - self.stream.read_exact(&mut ack), - ) - .await - .map_err(|_| TcpTargetError::Timeout("Ack timeout".to_string()))??; - - if ack[0] != 1 { - return Err(TcpTargetError::Protocol( - "Receiver verification failed".to_string(), - )); - } - - Ok(()) - } - - /// Read file from target machine - pub async fn read_file(&mut self, save_path: impl AsRef<Path>) -> Result<(), TcpTargetError> { - let path = save_path.as_ref(); - // Create CRC instance at function scope to ensure proper lifetime - let crc_instance = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC); - - // Make sure parent directory exists - if let Some(parent) = path.parent() - && !parent.exists() - { - tokio::fs::create_dir_all(parent).await?; - } - - // Read file header (version + size + crc) - let mut version_buf = [0u8; 8]; - self.stream.read_exact(&mut version_buf).await?; - let version = u64::from_be_bytes(version_buf); - if version != 1 { - return Err(TcpTargetError::Protocol( - "Unsupported transfer version".to_string(), - )); - } - - let mut size_buf = [0u8; 8]; - self.stream.read_exact(&mut size_buf).await?; - let file_size = u64::from_be_bytes(size_buf); - - let mut expected_crc_buf = [0u8; 4]; - self.stream.read_exact(&mut expected_crc_buf).await?; - let expected_crc = u32::from_be_bytes(expected_crc_buf); - if file_size == 0 { - // Create empty file and return early - let _file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - .await?; - // Send confirmation - self.stream.write_all(&[1u8]).await?; - self.stream.flush().await?; - return Ok(()); - } - - // Prepare output file - let file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - .await?; - let mut writer = BufWriter::with_capacity(self.config.chunk_size, file); - - // Receive file content with CRC calculation if enabled - let mut bytes_received = 0; - let mut buffer = vec![0u8; self.config.chunk_size]; - let mut crc_calculator = if self.config.enable_crc_validation { - Some(crc_instance.digest()) - } else { - None - }; - - while bytes_received < file_size { - let bytes_to_read = - (file_size - bytes_received).min(self.config.chunk_size as u64) as usize; - let chunk = &mut buffer[..bytes_to_read]; - - self.stream.read_exact(chunk).await?; - - writer.write_all(chunk).await?; - - // Update CRC if validation is enabled - if let Some(ref mut crc) = crc_calculator { - crc.update(chunk); - } - - bytes_received += bytes_to_read as u64; - } - - // Verify transfer completion - if bytes_received != file_size { - return Err(TcpTargetError::File(format!( - "Transfer incomplete: expected {} bytes, received {} bytes", - file_size, bytes_received - ))); - } - - writer.flush().await?; - - // Validate CRC if enabled - if self.config.enable_crc_validation - && let Some(crc_calculator) = crc_calculator - { - let actual_crc = crc_calculator.finalize(); - if actual_crc != expected_crc && expected_crc != 0 { - return Err(TcpTargetError::File(format!( - "CRC validation failed: expected {:08x}, got {:08x}", - expected_crc, actual_crc - ))); - } - } - - // Final flush and sync - writer.flush().await?; - writer.into_inner().sync_all().await?; - - // Verify completion - if bytes_received != file_size { - let _ = tokio::fs::remove_file(path).await; - return Err(TcpTargetError::File(format!( - "Transfer incomplete: expected {} bytes, received {} bytes", - file_size, bytes_received - ))); - } - - // Send confirmation - self.stream.write_all(&[1u8]).await?; - self.stream.flush().await?; - - Ok(()) - } -} diff --git a/crates/utils/tcp_connection/src/instance_challenge.rs b/crates/utils/tcp_connection/src/instance_challenge.rs deleted file mode 100644 index 3a7f6a3..0000000 --- a/crates/utils/tcp_connection/src/instance_challenge.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::path::Path; - -use rand::TryRngCore; -use rsa::{ - RsaPrivateKey, RsaPublicKey, - pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, - sha2, -}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; - -use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; -use ring::rand::SystemRandom; -use ring::signature::{ - self, ECDSA_P256_SHA256_ASN1, ECDSA_P384_SHA384_ASN1, EcdsaKeyPair, RSA_PKCS1_2048_8192_SHA256, - UnparsedPublicKey, -}; - -use crate::{error::TcpTargetError, instance::ConnectionInstance}; - -const ECDSA_P256_SHA256_ASN1_SIGNING: &signature::EcdsaSigningAlgorithm = - &signature::ECDSA_P256_SHA256_ASN1_SIGNING; -const ECDSA_P384_SHA384_ASN1_SIGNING: &signature::EcdsaSigningAlgorithm = - &signature::ECDSA_P384_SHA384_ASN1_SIGNING; - -impl ConnectionInstance { - /// Initiates a challenge to the target machine to verify connection security - /// - /// This method performs a cryptographic challenge-response authentication: - /// 1. Generates a random 32-byte challenge - /// 2. Sends the challenge to the target machine - /// 3. Receives a digital signature of the challenge - /// 4. Verifies the signature using the appropriate public key - /// - /// # Arguments - /// * `public_key_dir` - Directory containing public key files for verification - /// - /// # Returns - /// * `Ok((true, "KeyId"))` - Challenge verification successful - /// * `Ok((false, "KeyId"))` - Challenge verification failed - /// * `Err(TcpTargetError)` - Error during challenge process - pub async fn challenge( - &mut self, - public_key_dir: impl AsRef<Path>, - ) -> Result<(bool, String), TcpTargetError> { - // Generate random challenge - let mut challenge = [0u8; 32]; - rand::rngs::OsRng - .try_fill_bytes(&mut challenge) - .map_err(|e| { - TcpTargetError::Crypto(format!("Failed to generate random challenge: {}", e)) - })?; - - // Send challenge to target - self.stream.write_all(&challenge).await?; - self.stream.flush().await?; - - // Read signature from target - let mut signature = Vec::new(); - let mut signature_len_buf = [0u8; 4]; - self.stream.read_exact(&mut signature_len_buf).await?; - - let signature_len = u32::from_be_bytes(signature_len_buf) as usize; - signature.resize(signature_len, 0); - self.stream.read_exact(&mut signature).await?; - - // Read key identifier from target to identify which public key to use - let mut key_id_len_buf = [0u8; 4]; - self.stream.read_exact(&mut key_id_len_buf).await?; - let key_id_len = u32::from_be_bytes(key_id_len_buf) as usize; - - let mut key_id_buf = vec![0u8; key_id_len]; - self.stream.read_exact(&mut key_id_buf).await?; - let key_id = String::from_utf8(key_id_buf) - .map_err(|e| TcpTargetError::Crypto(format!("Invalid key identifier: {}", e)))?; - - // Load appropriate public key - let public_key_path = public_key_dir.as_ref().join(format!("{}.pem", key_id)); - if !public_key_path.exists() { - return Ok((false, key_id)); - } - - let public_key_pem = tokio::fs::read_to_string(&public_key_path).await?; - - // Try to verify with different key types - let verified = if let Ok(rsa_key) = RsaPublicKey::from_pkcs1_pem(&public_key_pem) { - let padding = rsa::pkcs1v15::Pkcs1v15Sign::new::<sha2::Sha256>(); - rsa_key.verify(padding, &challenge, &signature).is_ok() - } else if let Ok(ed25519_key) = - VerifyingKey::from_bytes(&parse_ed25519_public_key(&public_key_pem)) - { - if signature.len() == 64 { - let sig_bytes: [u8; 64] = signature.as_slice().try_into().map_err(|_| { - TcpTargetError::Crypto("Invalid signature length for Ed25519".to_string()) - })?; - let sig = Signature::from_bytes(&sig_bytes); - ed25519_key.verify(&challenge, &sig).is_ok() - } else { - false - } - } else if let Ok(dsa_key_info) = parse_dsa_public_key(&public_key_pem) { - verify_dsa_signature(&dsa_key_info, &challenge, &signature) - } else { - false - }; - - Ok((verified, key_id)) - } - - /// Accepts a challenge from the target machine to verify connection security - /// - /// This method performs a cryptographic challenge-response authentication: - /// 1. Receives a random 32-byte challenge from the target machine - /// 2. Signs the challenge using the appropriate private key - /// 3. Sends the digital signature back to the target machine - /// 4. Sends the key identifier for public key verification - /// - /// # Arguments - /// * `private_key_file` - Path to the private key file for signing - /// * `verify_public_key` - Key identifier for public key verification - /// - /// # Returns - /// * `Ok(true)` - Challenge response sent successfully - /// * `Ok(false)` - Private key format not supported - /// * `Err(TcpTargetError)` - Error during challenge response process - pub async fn accept_challenge( - &mut self, - private_key_file: impl AsRef<Path>, - verify_public_key: &str, - ) -> Result<bool, TcpTargetError> { - // Read challenge from initiator - let mut challenge = [0u8; 32]; - self.stream.read_exact(&mut challenge).await?; - - // Load private key - let private_key_pem = tokio::fs::read_to_string(&private_key_file) - .await - .map_err(|e| { - TcpTargetError::NotFound(format!( - "Read private key \"{}\" failed: \"{}\"", - private_key_file - .as_ref() - .display() - .to_string() - .split("/") - .last() - .unwrap_or("UNKNOWN"), - e - )) - })?; - - // Sign the challenge with supported key types - let signature = if let Ok(rsa_key) = RsaPrivateKey::from_pkcs1_pem(&private_key_pem) { - let padding = rsa::pkcs1v15::Pkcs1v15Sign::new::<sha2::Sha256>(); - rsa_key.sign(padding, &challenge)? - } else if let Ok(ed25519_key) = parse_ed25519_private_key(&private_key_pem) { - ed25519_key.sign(&challenge).to_bytes().to_vec() - } else if let Ok(dsa_key_info) = parse_dsa_private_key(&private_key_pem) { - sign_with_dsa(&dsa_key_info, &challenge)? - } else { - return Ok(false); - }; - - // Send signature length and signature - let signature_len = signature.len() as u32; - self.stream.write_all(&signature_len.to_be_bytes()).await?; - self.stream.flush().await?; - self.stream.write_all(&signature).await?; - self.stream.flush().await?; - - // Send key identifier for public key identification - let key_id_bytes = verify_public_key.as_bytes(); - let key_id_len = key_id_bytes.len() as u32; - self.stream.write_all(&key_id_len.to_be_bytes()).await?; - self.stream.flush().await?; - self.stream.write_all(key_id_bytes).await?; - self.stream.flush().await?; - - Ok(true) - } -} - -/// Parse Ed25519 public key from PEM format -fn parse_ed25519_public_key(pem: &str) -> [u8; 32] { - // Robust parsing for Ed25519 public key using pem crate - let mut key_bytes = [0u8; 32]; - - if let Ok(pem_data) = pem::parse(pem) - && pem_data.tag() == "PUBLIC KEY" - && pem_data.contents().len() >= 32 - { - let contents = pem_data.contents(); - key_bytes.copy_from_slice(&contents[contents.len() - 32..]); - } - key_bytes -} - -/// Parse Ed25519 private key from PEM format -fn parse_ed25519_private_key(pem: &str) -> Result<SigningKey, TcpTargetError> { - if let Ok(pem_data) = pem::parse(pem) - && pem_data.tag() == "PRIVATE KEY" - && pem_data.contents().len() >= 32 - { - let contents = pem_data.contents(); - let mut seed = [0u8; 32]; - seed.copy_from_slice(&contents[contents.len() - 32..]); - return Ok(SigningKey::from_bytes(&seed)); - } - Err(TcpTargetError::Crypto( - "Invalid Ed25519 private key format".to_string(), - )) -} - -/// Parse DSA public key information from PEM -fn parse_dsa_public_key( - pem: &str, -) -> Result<(&'static dyn signature::VerificationAlgorithm, Vec<u8>), TcpTargetError> { - if let Ok(pem_data) = pem::parse(pem) { - let contents = pem_data.contents().to_vec(); - - // Try different DSA algorithms based on PEM tag - match pem_data.tag() { - "EC PUBLIC KEY" | "PUBLIC KEY" if pem.contains("ECDSA") || pem.contains("ecdsa") => { - if pem.contains("P-256") { - return Ok((&ECDSA_P256_SHA256_ASN1, contents)); - } else if pem.contains("P-384") { - return Ok((&ECDSA_P384_SHA384_ASN1, contents)); - } - } - "RSA PUBLIC KEY" | "PUBLIC KEY" => { - return Ok((&RSA_PKCS1_2048_8192_SHA256, contents)); - } - _ => {} - } - - // Default to RSA for unknown types - return Ok((&RSA_PKCS1_2048_8192_SHA256, contents)); - } - Err(TcpTargetError::Crypto( - "Invalid DSA public key format".to_string(), - )) -} - -/// Parse DSA private key information from PEM -fn parse_dsa_private_key( - pem: &str, -) -> Result<(&'static dyn signature::VerificationAlgorithm, Vec<u8>), TcpTargetError> { - // For DSA, private key verification uses the same algorithm as public key - parse_dsa_public_key(pem) -} - -/// Verify DSA signature -fn verify_dsa_signature( - algorithm_and_key: &(&'static dyn signature::VerificationAlgorithm, Vec<u8>), - message: &[u8], - signature: &[u8], -) -> bool { - let (algorithm, key_bytes) = algorithm_and_key; - let public_key = UnparsedPublicKey::new(*algorithm, key_bytes); - public_key.verify(message, signature).is_ok() -} - -/// Sign with DSA -fn sign_with_dsa( - algorithm_and_key: &(&'static dyn signature::VerificationAlgorithm, Vec<u8>), - message: &[u8], -) -> Result<Vec<u8>, TcpTargetError> { - let (algorithm, key_bytes) = algorithm_and_key; - - // Handle different DSA/ECDSA algorithms by comparing algorithm identifiers - // Since we can't directly compare trait objects, we use pointer comparison - let algorithm_ptr = algorithm as *const _ as *const (); - let ecdsa_p256_ptr = &ECDSA_P256_SHA256_ASN1 as *const _ as *const (); - let ecdsa_p384_ptr = &ECDSA_P384_SHA384_ASN1 as *const _ as *const (); - - if algorithm_ptr == ecdsa_p256_ptr { - let key_pair = EcdsaKeyPair::from_pkcs8( - ECDSA_P256_SHA256_ASN1_SIGNING, - key_bytes, - &SystemRandom::new(), - ) - .map_err(|e| { - TcpTargetError::Crypto(format!("Failed to create ECDSA P-256 key pair: {}", e)) - })?; - - let signature = key_pair - .sign(&SystemRandom::new(), message) - .map_err(|e| TcpTargetError::Crypto(format!("ECDSA P-256 signing failed: {}", e)))?; - - Ok(signature.as_ref().to_vec()) - } else if algorithm_ptr == ecdsa_p384_ptr { - let key_pair = EcdsaKeyPair::from_pkcs8( - ECDSA_P384_SHA384_ASN1_SIGNING, - key_bytes, - &SystemRandom::new(), - ) - .map_err(|e| { - TcpTargetError::Crypto(format!("Failed to create ECDSA P-384 key pair: {}", e)) - })?; - - let signature = key_pair - .sign(&SystemRandom::new(), message) - .map_err(|e| TcpTargetError::Crypto(format!("ECDSA P-384 signing failed: {}", e)))?; - - Ok(signature.as_ref().to_vec()) - } else { - // RSA or unsupported algorithm - Err(TcpTargetError::Unsupported( - "DSA/ECDSA signing not supported for this algorithm type".to_string(), - )) - } -} diff --git a/crates/utils/tcp_connection/src/lib.rs b/crates/utils/tcp_connection/src/lib.rs deleted file mode 100644 index 6a2e599..0000000 --- a/crates/utils/tcp_connection/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[allow(dead_code)] -pub mod instance; - -pub mod instance_challenge; - -pub mod error; diff --git a/crates/utils/tcp_connection/tcp_connection_test/Cargo.toml b/crates/utils/tcp_connection/tcp_connection_test/Cargo.toml deleted file mode 100644 index 19a6e9b..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "tcp_connection_test" -edition = "2024" -version.workspace = true - -[dependencies] -tcp_connection = { path = "../../tcp_connection" } -tokio = { version = "1.48.0", features = ["full"] } -serde = { version = "1.0.228", features = ["derive"] } diff --git a/crates/utils/tcp_connection/tcp_connection_test/res/image/test_transfer.png b/crates/utils/tcp_connection/tcp_connection_test/res/image/test_transfer.png Binary files differdeleted file mode 100644 index 5fa94f0..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/res/image/test_transfer.png +++ /dev/null diff --git a/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key.pem b/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key.pem deleted file mode 100644 index e155876..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RSA PUBLIC KEY----- -MIICCgKCAgEAl5vyIwGYiQ1zZpW2tg+LwOUV547T2SjlzKQjcms5je/epP4CnUfT -5cmHCe8ZaSbnofcntCzi8FzMpQmzhNzFk5tCAe4tSrghfr2kYDO7aUL0G09KbNZ5 -iuMTkMaHx6LMjZ+Ljy8fC47yC2dFMUgLjGS7xS6rnIo4YtFuvMdwbLjs7mSn+vVc -kcEV8RLlQg8wDbzpl66Jd1kiUgPfVLBRTLE/iL8kUCz1l8c+DvOzr3ATwJysM9CG -LFahGLlTd3CZaj0QsEzf/AQsn79Su+rnCXhXqcvynhAcil0UW9RWp5Zsvp3Me3W8 -pJg6vZuAA6lQ062hkRLiJ91F2rpyqtkax5i/simLjelpsRzLKo6Xsz1bZht2+5d5 -ArgTBtZBxS044t8caZWLXetnPEcxEGz8KYUVKf7X9S7R53gy36y88Fbu9giqUr3m -b3Da+SYzBT//hacGn55nhzLRdsJGaFFWcKCbpue6JHLsFhizhdEAjaec0hfphw29 -veY0adPdIFLQDmMKaNk4ulrz8Lbgpqn9gxx6fRssj9jqNJmW64a0eV+Rw7BCJazH -xp3zz4A3rwdI8BjxLUb3YiCUcavA9WzJ1DUfdX1FSvbcFw4CEiGJjfpWGrm1jtc6 -DMOsoX/C6yFOyRpipsgqIToBClchLSNgrO6A7SIoSdIqNDEgIanFcjECAwEAAQ== ------END RSA PUBLIC KEY----- diff --git a/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key_private.pem b/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key_private.pem deleted file mode 100644 index 183d2d9..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/res/key/test_key_private.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/crates/utils/tcp_connection/tcp_connection_test/res/key/wrong_key_private.pem b/crates/utils/tcp_connection/tcp_connection_test/res/key/wrong_key_private.pem deleted file mode 100644 index 4b77eea..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/res/key/wrong_key_private.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -f9qBWGCwdZjeDjaVVUgwi+Waf+M0tQ== ------END PRIVATE KEY----- diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs b/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs deleted file mode 100644 index c9372d4..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[cfg(test)] -pub mod test_tcp_target_build; - -#[cfg(test)] -pub mod test_connection; - -#[cfg(test)] -pub mod test_challenge; - -#[cfg(test)] -pub mod test_file_transfer; - -#[cfg(test)] -pub mod test_msgpack; - -pub mod test_utils; -pub use test_utils::*; diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs deleted file mode 100644 index 9327b3e..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs +++ /dev/null @@ -1,160 +0,0 @@ -use std::{env::current_dir, time::Duration}; - -use tcp_connection::instance::ConnectionInstance; -use tokio::{ - join, - time::{sleep, timeout}, -}; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target::TcpServerTarget, - target_configure::ServerTargetConfig, -}; - -pub(crate) struct ExampleChallengeClientHandle; - -impl ClientHandle<ExampleChallengeServerHandle> for ExampleChallengeClientHandle { - async fn process(mut instance: ConnectionInstance) { - // Accept challenge with correct key - let key = current_dir() - .unwrap() - .join("res") - .join("key") - .join("test_key_private.pem"); - let result = instance.accept_challenge(key, "test_key").await.unwrap(); - - // Sent success - assert!(result); - let response = instance.read_text().await.unwrap(); - - // Verify success - assert_eq!("OK", response); - - // Accept challenge with wrong key - let key = current_dir() - .unwrap() - .join("res") - .join("key") - .join("wrong_key_private.pem"); - let result = instance.accept_challenge(key, "test_key").await.unwrap(); - - // Sent success - assert!(result); - let response = instance.read_text().await.unwrap(); - - // Verify fail - assert_eq!("ERROR", response); - - // Accept challenge with wrong name - let key = current_dir() - .unwrap() - .join("res") - .join("key") - .join("test_key_private.pem"); - let result = instance.accept_challenge(key, "test_key__").await.unwrap(); - - // Sent success - assert!(result); - let response = instance.read_text().await.unwrap(); - - // Verify fail - assert_eq!("ERROR", response); - } -} - -pub(crate) struct ExampleChallengeServerHandle; - -impl ServerHandle<ExampleChallengeClientHandle> for ExampleChallengeServerHandle { - async fn process(mut instance: ConnectionInstance) { - // Challenge with correct key - let key_dir = current_dir().unwrap().join("res").join("key"); - let (result, key_id) = instance.challenge(key_dir).await.unwrap(); - assert!(result); - assert_eq!(key_id, "test_key"); - - // Send response - instance - .write_text(if result { "OK" } else { "ERROR" }) - .await - .unwrap(); - - // Challenge again - let key_dir = current_dir().unwrap().join("res").join("key"); - let (result, key_id) = instance.challenge(key_dir).await.unwrap(); - assert!(!result); - assert_eq!(key_id, "test_key"); - - // Send response - instance - .write_text(if result { "OK" } else { "ERROR" }) - .await - .unwrap(); - - // Challenge again - let key_dir = current_dir().unwrap().join("res").join("key"); - let (result, key_id) = instance.challenge(key_dir).await.unwrap(); - assert!(!result); - assert_eq!(key_id, "test_key__"); - - // Send response - instance - .write_text(if result { "OK" } else { "ERROR" }) - .await - .unwrap(); - } -} - -#[tokio::test] -async fn test_connection_with_challenge_handle() -> Result<(), std::io::Error> { - let host = "localhost:5011"; - - // Server setup - let Ok(server_target) = TcpServerTarget::< - ExampleChallengeClientHandle, - ExampleChallengeServerHandle, - >::from_domain(host) - .await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - // Client setup - let Ok(client_target) = TcpServerTarget::< - ExampleChallengeClientHandle, - ExampleChallengeServerHandle, - >::from_domain(host) - .await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - let future_server = async move { - // Only process once - let configured_server = server_target.server_cfg(ServerTargetConfig::default().once()); - - // Listen here - let _ = configured_server.listen().await; - }; - - let future_client = async move { - // Wait for server start - let _ = sleep(Duration::from_secs_f32(1.5)).await; - - // Connect here - let _ = client_target.connect().await; - }; - - let test_timeout = Duration::from_secs(10); - - timeout(test_timeout, async { join!(future_client, future_server) }) - .await - .map_err(|_| { - std::io::Error::new( - std::io::ErrorKind::TimedOut, - format!("Test timed out after {:?}", test_timeout), - ) - })?; - - Ok(()) -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs deleted file mode 100644 index 8c3ab01..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::time::Duration; - -use tcp_connection::instance::ConnectionInstance; -use tokio::{join, time::sleep}; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target::TcpServerTarget, - target_configure::ServerTargetConfig, -}; - -pub(crate) struct ExampleClientHandle; - -impl ClientHandle<ExampleServerHandle> for ExampleClientHandle { - async fn process(mut instance: ConnectionInstance) { - // Write name - let Ok(_) = instance.write_text("Peter").await else { - panic!("Write text failed!"); - }; - // Read msg - let Ok(result) = instance.read_text().await else { - return; - }; - assert_eq!("Hello Peter!", result); - } -} - -pub(crate) struct ExampleServerHandle; - -impl ServerHandle<ExampleClientHandle> for ExampleServerHandle { - async fn process(mut instance: ConnectionInstance) { - // Read name - let Ok(name) = instance.read_text().await else { - return; - }; - // Write msg - let Ok(_) = instance.write_text(format!("Hello {}!", name)).await else { - panic!("Write text failed!"); - }; - } -} - -#[tokio::test] -async fn test_connection_with_example_handle() { - let host = "localhost:5012"; - - // Server setup - let Ok(server_target) = - TcpServerTarget::<ExampleClientHandle, ExampleServerHandle>::from_domain(host).await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - // Client setup - let Ok(client_target) = - TcpServerTarget::<ExampleClientHandle, ExampleServerHandle>::from_domain(host).await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - let future_server = async move { - // Only process once - let configured_server = server_target.server_cfg(ServerTargetConfig::default().once()); - - // Listen here - let _ = configured_server.listen().await; - }; - - let future_client = async move { - // Wait for server start - let _ = sleep(Duration::from_secs_f32(1.5)).await; - - // Connect here - let _ = client_target.connect().await; - }; - - let _ = async { join!(future_client, future_server) }.await; -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs deleted file mode 100644 index 4237ea7..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::{env::current_dir, time::Duration}; - -use tcp_connection::instance::ConnectionInstance; -use tokio::{ - join, - time::{sleep, timeout}, -}; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target::TcpServerTarget, - target_configure::ServerTargetConfig, -}; - -pub(crate) struct ExampleFileTransferClientHandle; - -impl ClientHandle<ExampleFileTransferServerHandle> for ExampleFileTransferClientHandle { - async fn process(mut instance: ConnectionInstance) { - let image_path = current_dir() - .unwrap() - .join("res") - .join("image") - .join("test_transfer.png"); - instance.write_file(image_path).await.unwrap(); - } -} - -pub(crate) struct ExampleFileTransferServerHandle; - -impl ServerHandle<ExampleFileTransferClientHandle> for ExampleFileTransferServerHandle { - async fn process(mut instance: ConnectionInstance) { - let save_path = current_dir() - .unwrap() - .join("res") - .join(".temp") - .join("image") - .join("test_transfer.png"); - instance.read_file(save_path).await.unwrap(); - } -} - -#[tokio::test] -async fn test_connection_with_challenge_handle() -> Result<(), std::io::Error> { - let host = "localhost:5010"; - - // Server setup - let Ok(server_target) = TcpServerTarget::< - ExampleFileTransferClientHandle, - ExampleFileTransferServerHandle, - >::from_domain(host) - .await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - // Client setup - let Ok(client_target) = TcpServerTarget::< - ExampleFileTransferClientHandle, - ExampleFileTransferServerHandle, - >::from_domain(host) - .await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - let future_server = async move { - // Only process once - let configured_server = server_target.server_cfg(ServerTargetConfig::default().once()); - - // Listen here - let _ = configured_server.listen().await; - }; - - let future_client = async move { - // Wait for server start - let _ = sleep(Duration::from_secs_f32(1.5)).await; - - // Connect here - let _ = client_target.connect().await; - }; - - let test_timeout = Duration::from_secs(10); - - timeout(test_timeout, async { join!(future_client, future_server) }) - .await - .map_err(|_| { - std::io::Error::new( - std::io::ErrorKind::TimedOut, - format!("Test timed out after {:?}", test_timeout), - ) - })?; - - Ok(()) -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs deleted file mode 100644 index 4c9c870..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs +++ /dev/null @@ -1,103 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::time::Duration; -use tcp_connection::instance::ConnectionInstance; -use tokio::{join, time::sleep}; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target::TcpServerTarget, - target_configure::ServerTargetConfig, -}; - -#[derive(Debug, PartialEq, Serialize, Deserialize, Default)] -struct TestData { - id: u32, - name: String, -} - -pub(crate) struct MsgPackClientHandle; - -impl ClientHandle<MsgPackServerHandle> for MsgPackClientHandle { - async fn process(mut instance: ConnectionInstance) { - // Test basic MessagePack serialization - let test_data = TestData { - id: 42, - name: "Test MessagePack".to_string(), - }; - - // Write MessagePack data - if let Err(e) = instance.write_msgpack(&test_data).await { - panic!("Write MessagePack failed: {}", e); - } - - // Read response - let response: TestData = match instance.read_msgpack().await { - Ok(data) => data, - Err(e) => panic!("Read MessagePack response failed: {}", e), - }; - - // Verify response - assert_eq!(response.id, test_data.id * 2); - assert_eq!(response.name, format!("Processed: {}", test_data.name)); - } -} - -pub(crate) struct MsgPackServerHandle; - -impl ServerHandle<MsgPackClientHandle> for MsgPackServerHandle { - async fn process(mut instance: ConnectionInstance) { - // Read MessagePack data - let received_data: TestData = match instance.read_msgpack().await { - Ok(data) => data, - Err(_) => return, - }; - - // Process data - let response = TestData { - id: received_data.id * 2, - name: format!("Processed: {}", received_data.name), - }; - - // Write response as MessagePack - if let Err(e) = instance.write_msgpack(&response).await { - panic!("Write MessagePack response failed: {}", e); - } - } -} - -#[tokio::test] -async fn test_msgpack_basic() { - let host = "localhost:5013"; - - // Server setup - let Ok(server_target) = - TcpServerTarget::<MsgPackClientHandle, MsgPackServerHandle>::from_domain(host).await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - // Client setup - let Ok(client_target) = - TcpServerTarget::<MsgPackClientHandle, MsgPackServerHandle>::from_domain(host).await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - let future_server = async move { - // Only process once - let configured_server = server_target.server_cfg(ServerTargetConfig::default().once()); - - // Listen here - let _ = configured_server.listen().await; - }; - - let future_client = async move { - // Wait for server start - let _ = sleep(Duration::from_secs_f32(1.5)).await; - - // Connect here - let _ = client_target.connect().await; - }; - - let _ = async { join!(future_client, future_server) }.await; -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs deleted file mode 100644 index aa1ec74..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{ - test_connection::{ExampleClientHandle, ExampleServerHandle}, - test_utils::target::TcpServerTarget, -}; - -#[test] -fn test_tcp_test_target_build() { - let host = "127.0.0.1:8080"; - - // Test build target by string - let Ok(target) = - TcpServerTarget::<ExampleClientHandle, ExampleServerHandle>::from_address_str(host) - else { - panic!("Test target built failed from a target addr `{}`", host); - }; - assert_eq!(target.to_string(), "127.0.0.1:8080"); -} - -#[tokio::test] -async fn test_tcp_test_target_build_domain() { - let host = "localhost"; - - // Test build target by DomainName and Connection - let Ok(target) = - TcpServerTarget::<ExampleClientHandle, ExampleServerHandle>::from_domain(host).await - else { - panic!("Test target built failed from a domain named `{}`", host); - }; - - // Test into string - assert_eq!(target.to_string(), "127.0.0.1:8080"); -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs deleted file mode 100644 index badf27d..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod handle; -pub mod target; -pub mod target_configure; -pub mod target_connection; diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs deleted file mode 100644 index 4f9bdbb..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::future::Future; - -use tcp_connection::instance::ConnectionInstance; - -pub trait ClientHandle<RequestServer> { - fn process(instance: ConnectionInstance) -> impl Future<Output = ()> + Send; -} - -pub trait ServerHandle<RequestClient> { - fn process(instance: ConnectionInstance) -> impl Future<Output = ()> + Send; -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs deleted file mode 100644 index 8972b2a..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs +++ /dev/null @@ -1,201 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::{ - fmt::{Display, Formatter}, - marker::PhantomData, - net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr}, - str::FromStr, -}; -use tokio::net::lookup_host; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target_configure::{ClientTargetConfig, ServerTargetConfig}, -}; - -const DEFAULT_PORT: u16 = 8080; - -#[derive(Debug, Serialize, Deserialize)] -pub struct TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - /// Client Config - client_cfg: Option<ClientTargetConfig>, - - /// Server Config - server_cfg: Option<ServerTargetConfig>, - - /// Server port - port: u16, - - /// Bind addr - bind_addr: IpAddr, - - /// Client Phantom Data - _client: PhantomData<Client>, - - /// Server Phantom Data - _server: PhantomData<Server>, -} - -impl<Client, Server> Default for TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - fn default() -> Self { - Self { - client_cfg: None, - server_cfg: None, - port: DEFAULT_PORT, - bind_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), - _client: PhantomData, - _server: PhantomData, - } - } -} - -impl<Client, Server> From<SocketAddr> for TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - /// Convert SocketAddr to TcpServerTarget - fn from(value: SocketAddr) -> Self { - Self { - port: value.port(), - bind_addr: value.ip(), - ..Self::default() - } - } -} - -impl<Client, Server> From<TcpServerTarget<Client, Server>> for SocketAddr -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - /// Convert TcpServerTarget to SocketAddr - fn from(val: TcpServerTarget<Client, Server>) -> Self { - SocketAddr::new(val.bind_addr, val.port) - } -} - -impl<Client, Server> Display for TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:{}", self.bind_addr, self.port) - } -} - -impl<Client, Server> TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - /// Create target by address - pub fn from_addr(addr: impl Into<IpAddr>, port: impl Into<u16>) -> Self { - Self { - port: port.into(), - bind_addr: addr.into(), - ..Self::default() - } - } - - /// Try to create target by string - pub fn from_address_str<'a>(addr_str: impl Into<&'a str>) -> Result<Self, AddrParseError> { - let socket_addr = SocketAddr::from_str(addr_str.into()); - match socket_addr { - Ok(socket_addr) => Ok(Self::from_addr(socket_addr.ip(), socket_addr.port())), - Err(err) => Err(err), - } - } - - /// Try to create target by domain name - pub async fn from_domain<'a>(domain: impl Into<&'a str>) -> Result<Self, std::io::Error> { - match domain_to_addr(domain).await { - Ok(domain_addr) => Ok(Self::from(domain_addr)), - Err(e) => Err(e), - } - } - - /// Set client config - pub fn client_cfg(mut self, config: ClientTargetConfig) -> Self { - self.client_cfg = Some(config); - self - } - - /// Set server config - pub fn server_cfg(mut self, config: ServerTargetConfig) -> Self { - self.server_cfg = Some(config); - self - } - - /// Add client config - pub fn add_client_cfg(&mut self, config: ClientTargetConfig) { - self.client_cfg = Some(config); - } - - /// Add server config - pub fn add_server_cfg(&mut self, config: ServerTargetConfig) { - self.server_cfg = Some(config); - } - - /// Get client config ref - pub fn get_client_cfg(&self) -> Option<&ClientTargetConfig> { - self.client_cfg.as_ref() - } - - /// Get server config ref - pub fn get_server_cfg(&self) -> Option<&ServerTargetConfig> { - self.server_cfg.as_ref() - } - - /// Get SocketAddr of TcpServerTarget - pub fn get_addr(&self) -> SocketAddr { - SocketAddr::new(self.bind_addr, self.port) - } -} - -/// Parse Domain Name to IpAddr via DNS -async fn domain_to_addr<'a>(domain: impl Into<&'a str>) -> Result<SocketAddr, std::io::Error> { - let domain = domain.into(); - let default_port: u16 = DEFAULT_PORT; - - if let Ok(socket_addr) = domain.parse::<SocketAddr>() { - return Ok(match socket_addr.ip() { - IpAddr::V4(_) => socket_addr, - IpAddr::V6(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), socket_addr.port()), - }); - } - - if let Ok(_v6_addr) = domain.parse::<std::net::Ipv6Addr>() { - return Ok(SocketAddr::new( - IpAddr::V4(Ipv4Addr::LOCALHOST), - default_port, - )); - } - - let (host, port_str) = if let Some((host, port)) = domain.rsplit_once(':') { - (host.trim_matches(|c| c == '[' || c == ']'), Some(port)) - } else { - (domain, None) - }; - - let port = port_str - .and_then(|p| p.parse::<u16>().ok()) - .map(|p| p.clamp(0, u16::MAX)) - .unwrap_or(default_port); - - let mut socket_iter = lookup_host((host, 0)).await?; - - if let Some(addr) = socket_iter.find(|addr| addr.is_ipv4()) { - return Ok(SocketAddr::new(addr.ip(), port)); - } - - Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) -} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs deleted file mode 100644 index d739ac9..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs +++ /dev/null @@ -1,53 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] -pub struct ServerTargetConfig { - /// Only process a single connection, then shut down the server. - once: bool, - - /// Timeout duration in milliseconds. (0 is Closed) - timeout: u64, -} - -impl ServerTargetConfig { - /// Set `once` to True - /// This method configures the `once` field of `ServerTargetConfig`. - pub fn once(mut self) -> Self { - self.once = true; - self - } - - /// Set `timeout` to the given value - /// This method configures the `timeout` field of `ServerTargetConfig`. - pub fn timeout(mut self, timeout: u64) -> Self { - self.timeout = timeout; - self - } - - /// Set `once` to the given value - /// This method configures the `once` field of `ServerTargetConfig`. - pub fn set_once(&mut self, enable: bool) { - self.once = enable; - } - - /// Set `timeout` to the given value - /// This method configures the `timeout` field of `ServerTargetConfig`. - pub fn set_timeout(&mut self, timeout: u64) { - self.timeout = timeout; - } - - /// Check if the server is configured to process only a single connection. - /// Returns `true` if the server will shut down after processing one connection. - pub fn is_once(&self) -> bool { - self.once - } - - /// Get the current timeout value in milliseconds. - /// Returns the timeout duration. A value of 0 indicates the connection is closed. - pub fn get_timeout(&self) -> u64 { - self.timeout - } -} - -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)] -pub struct ClientTargetConfig {} diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs deleted file mode 100644 index d5bf2c3..0000000 --- a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs +++ /dev/null @@ -1,89 +0,0 @@ -use tcp_connection::{error::TcpTargetError, instance::ConnectionInstance}; -use tokio::{ - net::{TcpListener, TcpSocket}, - spawn, -}; - -use crate::test_utils::{ - handle::{ClientHandle, ServerHandle}, - target::TcpServerTarget, - target_configure::ServerTargetConfig, -}; - -impl<Client, Server> TcpServerTarget<Client, Server> -where - Client: ClientHandle<Server>, - Server: ServerHandle<Client>, -{ - /// Attempts to establish a connection to the TCP server. - /// - /// This function initiates a connection to the server address - /// specified in the target configuration. - /// - /// This is a Block operation. - pub async fn connect(&self) -> Result<(), TcpTargetError> { - let addr = self.get_addr(); - let Ok(socket) = TcpSocket::new_v4() else { - return Err(TcpTargetError::from("Create tcp socket failed!")); - }; - let stream = match socket.connect(addr).await { - Ok(stream) => stream, - Err(e) => { - let err = format!("Connect to `{}` failed: {}", addr, e); - return Err(TcpTargetError::from(err)); - } - }; - let instance = ConnectionInstance::from(stream); - Client::process(instance).await; - Ok(()) - } - - /// Attempts to establish a connection to the TCP server. - /// - /// This function initiates a connection to the server address - /// specified in the target configuration. - pub async fn listen(&self) -> Result<(), TcpTargetError> { - let addr = self.get_addr(); - let listener = match TcpListener::bind(addr).await { - Ok(listener) => listener, - Err(_) => { - let err = format!("Bind to `{}` failed", addr); - return Err(TcpTargetError::from(err)); - } - }; - - let cfg: ServerTargetConfig = match self.get_server_cfg() { - Some(cfg) => *cfg, - None => ServerTargetConfig::default(), - }; - - if cfg.is_once() { - // Process once (Blocked) - let (stream, _) = match listener.accept().await { - Ok(result) => result, - Err(e) => { - let err = format!("Accept connection failed: {}", e); - return Err(TcpTargetError::from(err)); - } - }; - let instance = ConnectionInstance::from(stream); - Server::process(instance).await; - } else { - loop { - // Process multiple times (Concurrent) - let (stream, _) = match listener.accept().await { - Ok(result) => result, - Err(e) => { - let err = format!("Accept connection failed: {}", e); - return Err(TcpTargetError::from(err)); - } - }; - let instance = ConnectionInstance::from(stream); - spawn(async move { - Server::process(instance).await; - }); - } - } - Ok(()) - } -} |
