1#[cfg(feature = "client")]
166pub mod client;
167
168pub mod message;
170
171#[cfg(feature = "server")]
175pub mod server;
176
177pub mod socket;
179
180pub const VERSION: [u8; 3] = [0, 1, 2];
184
185#[cfg(test)]
186#[cfg(feature = "server")]
187#[cfg(feature = "client")]
188mod tests {
189 use super::*;
190 use crate::message::{BtpFile, BtpMessage, StatusCode};
191 use crate::socket::{BtpConfig, BtpSocket};
192 use std::io::Write;
193 use tempfile::tempdir;
194 use tokio::net::TcpListener;
195
196 fn make_test_file(content: &str, name: &str) -> BtpFile {
197 let mut temp_file = tempfile::NamedTempFile::new().unwrap();
198 write!(temp_file, "{}", content).unwrap();
199 let file = temp_file.reopen().unwrap();
200 BtpFile::from([StatusCode::File as u8], VERSION, file, name.to_string()).unwrap()
201 }
202
203 mod tests {
204 use std::net::SocketAddr;
205
206 use tokio::net::TcpStream;
207
208 use super::*;
209 use crate::server::BtpListener;
210 type Error = Box<dyn std::error::Error + Send + Sync>;
211 #[tokio::test]
212 async fn test_message_exchange_no_tls() -> Result<(), Error> {
213 let listener = TcpListener::bind("127.0.0.1:0").await?;
214 let server_addr = listener.local_addr()?;
215 let btp_conf = BtpConfig::from_addr(server_addr);
216 let server_task = tokio::spawn(async move {
217 let btp_listener = BtpListener::from(listener, btp_conf).await;
218 let mut server_socket = btp_listener.accept().await?;
219 let (_file_opt, msg_opt) = server_socket.read().await?;
220 let msg = msg_opt.ok_or("No message received")?;
221 assert_eq!(msg.body, "Hello, BTP!");
222 let response = BtpMessage::from_str("ACK");
223 server_socket.write_message(response).await?;
224
225 Ok::<_, Error>(())
226 });
227 let client_conf = BtpConfig::from_addr(server_addr);
228 let mut client_socket = BtpSocket::connect(client_conf).await?;
229
230 let request = BtpMessage::from_str("Hello, BTP!");
231 client_socket.write_message(request).await?;
232
233 let (_file_opt, msg_opt) = client_socket.read().await?;
234 let response = msg_opt.ok_or("No response received")?;
235 assert_eq!(response.body, "ACK");
236
237 server_task.await??;
238
239 Ok(())
240 }
241
242 #[tokio::test]
243 async fn test_file_transfer_no_tls() -> Result<(), Error> {
244 let tmp_dir = tempdir()?;
245 let file_path = tmp_dir.path().join("test.txt");
246 let original_content = "Hello, this is a test file.";
247 tokio::fs::write(&file_path, original_content).await?;
248
249 let listener = TcpListener::bind("127.0.0.1:0").await?;
250 let server_addr = listener.local_addr()?;
251 let btp_conf = BtpConfig::from_addr(server_addr);
252
253 let server_task = tokio::spawn(async move {
254 let btp_listener = BtpListener::from(listener, btp_conf).await;
255 let mut server_socket = btp_listener.accept().await?;
256
257 let (file_opt, _msg_opt) = server_socket.read().await?;
258 let file = file_opt.ok_or("No file received")?;
259 assert_eq!(file.file_content, original_content);
260
261 let ack = BtpMessage::from_str("FILE_RECEIVED");
262 server_socket.write_message(ack).await?;
263
264 Ok::<_, Error>(())
265 });
266
267 let client_conf = BtpConfig::from_addr(server_addr);
268 let mut client_socket = BtpSocket::connect(client_conf).await?;
269
270 let file = make_test_file(original_content, "test.txt");
271 client_socket.write_file(file).await?;
272
273 let (_file_opt, msg_opt) = client_socket.read().await?;
274 let ack = msg_opt.ok_or("No acknowledgment received")?;
275 assert_eq!(ack.body, "FILE_RECEIVED");
276
277 server_task.await??;
278
279 Ok(())
280 }
281
282 #[tokio::test]
283 async fn test_full_session_no_tls() -> Result<(), Error> {
284 let listener = TcpListener::bind("127.0.0.1:0").await?;
285 let server_addr = listener.local_addr()?;
286 let btp_conf = BtpConfig::from_addr(server_addr);
287
288 let server_task = tokio::spawn(async move {
289 let btp_listener = BtpListener::from(listener, btp_conf).await;
290 let server_socket = btp_listener.accept().await?;
291
292 server_socket.attach_handler(
293 |msg: BtpMessage, _: BtpSocket<TcpStream, SocketAddr>| {
294 println!("Server received: {}", msg.body);
295 },
296 |_file: BtpFile, _: BtpSocket<TcpStream, SocketAddr>| {
297 println!("Server received a file");
298 },
299 )?;
300
301 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
302 Ok::<_, Error>(())
303 });
304
305 let client_conf = BtpConfig::from_addr(server_addr);
306 let mut client_socket = BtpSocket::connect(client_conf).await?;
307
308 let msg = BtpMessage::from_str("Hello, echo!");
309 client_socket.write_message(msg).await?;
310
311 tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
312
313 server_task.await??;
314
315 Ok(())
316 }
317 }
318
319 #[cfg(feature = "tls")]
320 mod tls_tests {
321
322 type Error = Box<dyn std::error::Error + Send + Sync>;
323 use crate::server::BtpListenerTls;
324
325 use super::*;
326 use rustls::ServerConfig;
327 use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
328 use std::sync::Arc;
329 use tokio_rustls::TlsConnector;
330
331 fn make_test_tls_config() -> (Arc<ServerConfig>, Vec<u8>) {
332 let certified = rcgen::generate_simple_self_signed(vec!["127.0.0.1".into()]).unwrap();
333
334 let cert_der = certified.cert.der().to_vec();
335
336 let server_cert = rustls::pki_types::CertificateDer::from(certified.cert.der().clone());
337
338 let key_der = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
339 certified.signing_key.serialize_der(),
340 ));
341
342 let config = ServerConfig::builder()
343 .with_no_client_auth()
344 .with_single_cert(vec![server_cert], key_der)
345 .unwrap();
346
347 (Arc::new(config), cert_der)
348 }
349
350 #[tokio::test]
351 async fn test_message_exchange_with_tls() -> Result<(), Error> {
352 let listener = TcpListener::bind("127.0.0.1:0").await?;
353 let server_addr = listener.local_addr()?;
354 let btp_conf = BtpConfig::from_addr(server_addr);
355 let (tls_conf, cert_der) = make_test_tls_config();
356
357 let mut root_store = rustls::RootCertStore::empty();
358 root_store.add(cert_der.into()).unwrap();
359
360 let client_config = rustls::ClientConfig::builder()
361 .with_root_certificates(root_store)
362 .with_no_client_auth();
363
364 let server_task = tokio::spawn(async move {
365 let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
366 let mut server_socket = btp_listener.accept().await?;
367
368 let (_file_opt, msg_opt) = server_socket.read().await?;
369 let msg = msg_opt.ok_or("No message received")?;
370 assert_eq!(msg.body, "Hello, TLS BTP!");
371
372 let response = BtpMessage::from_str("TLS ACK");
373 server_socket.write_message(response).await?;
374
375 Ok::<_, Error>(())
376 });
377
378 let connector = TlsConnector::from(Arc::new(client_config));
379 let client_conf = BtpConfig::from_addr(server_addr);
380 let mut client_socket = BtpSocket::connect_tls(connector, client_conf).await?;
381
382 let request = BtpMessage::from_str("Hello, TLS BTP!");
383 client_socket.write_message(request).await?;
384
385 let (_file_opt, msg_opt) = client_socket.read().await?;
386 let response = msg_opt.ok_or("No response received")?;
387 assert_eq!(response.body, "TLS ACK");
388
389 server_task.await??;
390
391 Ok(())
392 }
393
394 #[tokio::test]
395 async fn test_file_transfer_with_tls() -> Result<(), Error> {
396 let tmp_dir = tempdir()?;
397 let file_path = tmp_dir.path().join("tls_test.txt");
398 let original_content = "TLS file transfer test content.";
399 tokio::fs::write(&file_path, original_content).await?;
400
401 let listener = TcpListener::bind("127.0.0.1:0").await?;
402 let server_addr = listener.local_addr()?;
403 let btp_conf = BtpConfig::from_addr(server_addr);
404 let (tls_conf, cert_der) = make_test_tls_config();
405
406 let mut root_store = rustls::RootCertStore::empty();
407 root_store.add(cert_der.into()).unwrap();
408
409 let client_config = rustls::ClientConfig::builder()
410 .with_root_certificates(root_store)
411 .with_no_client_auth();
412
413 let server_task = tokio::spawn(async move {
414 let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
415 let mut server_socket = btp_listener.accept().await?;
416
417 let (file_opt, _msg_opt) = server_socket.read().await?;
418 let file = file_opt.ok_or("No file received")?;
419 assert_eq!(file.file_content, original_content);
420
421 let ack = BtpMessage::from_str("TLS FILE RECEIVED");
422 server_socket.write_message(ack).await?;
423
424 Ok::<_, Error>(())
425 });
426
427 let connector = TlsConnector::from(Arc::new(client_config));
428 let client_conf = BtpConfig::from_addr(server_addr);
429 let mut client_socket = BtpSocket::connect_tls(connector, client_conf).await?;
430
431 let file = make_test_file(original_content, "tls_test.txt");
432 client_socket.write_file(file).await?;
433
434 let (_file_opt, msg_opt) = client_socket.read().await?;
435 let ack = msg_opt.ok_or("No acknowledgment received")?;
436 assert_eq!(ack.body, "TLS FILE RECEIVED");
437
438 server_task.await??;
439
440 Ok(())
441 }
442 }
443}