pub mod client;
pub mod message;
pub mod server;
pub mod socket;
pub const VERSION: [u8; 3] = [0, 1, 4];
#[cfg(test)]
mod tests {
use crate::message::BtpPackage;
use crate::socket::{BtpConfig, BtpSocket};
use tempfile::tempdir;
use tokio::net::TcpListener;
mod tests {
use std::time::Duration;
use tokio::{fs::File, time::sleep};
use super::*;
use crate::server::BtpListener;
type Error = Box<dyn std::error::Error + Send + Sync>;
#[tokio::test]
async fn test_message_exchange_no_tls() -> Result<(), Error> {
println!("start of file");
let listener = TcpListener::bind("127.0.0.1:0").await?;
let server_addr = listener.local_addr()?;
let btp_conf = BtpConfig::from_addr(server_addr);
let server_task = tokio::spawn(async move {
let btp_listener = BtpListener::from(listener, btp_conf).await;
let mut server_socket = btp_listener.accept().await?;
sleep(Duration::from_secs(2)).await;
let package = server_socket.read().await?;
assert_eq!(package.unwrap().body1, "Hello, BTP!");
let response = BtpPackage::from_str("ACK");
server_socket.write(response).await?;
server_socket.shutdown().await?;
Ok::<_, Error>(())
});
let client_conf = BtpConfig::from_addr(server_addr);
let mut client_socket = BtpSocket::connect(client_conf).await?;
let request = BtpPackage::from_str("Hello, BTP!");
client_socket.write(request).await?;
sleep(Duration::from_secs(2)).await;
let response = client_socket.read().await?;
assert_eq!(response.unwrap().body1, "ACK");
server_task.await??;
client_socket.shutdown().await?;
Ok(())
}
#[tokio::test]
async fn test_file_transfer_no_tls() -> Result<(), Error> {
println!("start of file");
let tmp_dir = tempdir()?;
let file_path = tmp_dir.path().join("test.txt");
let original_content = "Hello, this is a test file.";
tokio::fs::write(&file_path, original_content).await?;
let listener = TcpListener::bind("127.0.0.1:0").await?;
let server_addr = listener.local_addr()?;
let btp_conf = BtpConfig::from_addr(server_addr);
let server_task = tokio::spawn(async move {
println!("ehh");
let btp_listener = BtpListener::from(listener, btp_conf).await;
println!("ehh2x");
let mut server_socket = btp_listener.accept().await?;
println!("ehh3x");
sleep(Duration::from_secs(2)).await;
let file = server_socket.read().await?;
assert_eq!(file.unwrap().body1, original_content);
let ack = BtpPackage::from_str("FILE_RECEIVED");
server_socket.write(ack).await?;
server_socket.shutdown().await?;
Ok::<_, Error>(())
});
let client_conf = BtpConfig::from_addr(server_addr);
let mut client_socket = BtpSocket::connect(client_conf).await?;
println!("Clien created, connected");
let mut file = File::open(file_path).await?;
let file_pkg = BtpPackage::from_file(&mut file, String::from("test.txt")).await?;
client_socket.write(file_pkg).await?;
sleep(Duration::from_secs(2)).await;
let ack = client_socket.read().await?;
assert_eq!(ack.unwrap().body1, "FILE_RECEIVED");
server_task.await??;
client_socket.shutdown().await?;
Ok(())
}
#[cfg(feature = "tls")]
mod tls_tests {
type Error = Box<dyn std::error::Error + Send + Sync>;
use crate::server::BtpListenerTls;
use super::*;
use rustls::ServerConfig;
use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
use std::sync::Arc;
use tokio::fs::File;
use tokio_rustls::TlsConnector;
fn make_test_tls_config() -> (Arc<ServerConfig>, Vec<u8>) {
let certified =
rcgen::generate_simple_self_signed(vec!["127.0.0.1".into()]).unwrap();
let cert_der = certified.cert.der().to_vec();
let server_cert =
rustls::pki_types::CertificateDer::from(certified.cert.der().clone());
let key_der = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
certified.signing_key.serialize_der(),
));
let config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(vec![server_cert], key_der)
.unwrap();
(Arc::new(config), cert_der)
}
#[tokio::test]
async fn test_message_exchange_with_tls() -> Result<(), Error> {
let listener = TcpListener::bind("127.0.0.1:0").await?;
let server_addr = listener.local_addr()?;
let btp_conf = BtpConfig::from_addr(server_addr);
let (tls_conf, cert_der) = make_test_tls_config();
let mut root_store = rustls::RootCertStore::empty();
root_store.add(cert_der.into()).unwrap();
let client_config = rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
let server_task = tokio::spawn(async move {
let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
let mut server_socket = btp_listener.accept().await?;
let msg = server_socket.read().await?;
assert_eq!(msg.unwrap().body1, "Hello, TLS BTP!");
let response = BtpPackage::from_str("TLS ACK");
server_socket.write(response).await?;
Ok::<_, Error>(())
});
let connector = TlsConnector::from(Arc::new(client_config));
let client_conf = BtpConfig::from_addr(server_addr);
let mut client_socket = BtpSocket::connect_tls(connector, client_conf).await?;
let request = BtpPackage::from_str("Hello, TLS BTP!");
client_socket.write(request).await?;
let response = client_socket.read().await?;
assert_eq!(response.unwrap().body1, "TLS ACK");
server_task.await??;
Ok(())
}
#[tokio::test]
async fn test_file_transfer_with_tls() -> Result<(), Error> {
let tmp_dir = tempdir()?;
let file_path = tmp_dir.path().join("tls_test.txt");
let original_content = "TLS file transfer test content.";
tokio::fs::write(&file_path, original_content).await?;
let listener = TcpListener::bind("127.0.0.1:0").await?;
let server_addr = listener.local_addr()?;
let btp_conf = BtpConfig::from_addr(server_addr);
let (tls_conf, cert_der) = make_test_tls_config();
let mut root_store = rustls::RootCertStore::empty();
root_store.add(cert_der.into()).unwrap();
let client_config = rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
let server_task = tokio::spawn(async move {
let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
let mut server_socket = btp_listener.accept().await?;
let file = server_socket.read().await?;
assert_eq!(file.unwrap().body1, original_content);
let ack = BtpPackage::from_str("TLS FILE RECEIVED");
server_socket.write(ack).await?;
Ok::<_, Error>(())
});
let connector = TlsConnector::from(Arc::new(client_config));
let client_conf = BtpConfig::from_addr(server_addr);
let mut client_socket = BtpSocket::connect_tls(connector, client_conf).await?;
let mut file = File::open(file_path).await?;
let file_pkg =
BtpPackage::from_file(&mut file, String::from("tls_test.txt")).await?;
client_socket.write(file_pkg).await?;
let ack = client_socket.read().await?;
assert_eq!(ack.unwrap().body1, "TLS FILE RECEIVED");
server_task.await??;
Ok(())
}
}
}
}