1pub mod client;
77pub mod message;
78pub mod server;
79pub mod socket;
80
81pub const VERSION: [u8; 3] = [0, 1, 1];
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use crate::message::{BtpFile, BtpMessage, StatusCode};
88 use crate::socket::{BtpConfig, BtpSocket};
89 use std::io::Write;
90 use std::net::SocketAddr;
91 use tempfile::tempdir;
92 use tokio::net::TcpListener;
93
94 fn make_config(addr: SocketAddr) -> BtpConfig {
95 BtpConfig { ver: VERSION, addr }
96 }
97
98 fn make_test_file(content: &str, name: &str) -> BtpFile {
99 let mut temp_file = tempfile::NamedTempFile::new().unwrap();
100 write!(temp_file, "{}", content).unwrap();
101 let file = temp_file.reopen().unwrap();
102 BtpFile::from([StatusCode::File as u8], VERSION, file, name.to_string()).unwrap()
103 }
104
105 mod tests {
106 use super::*;
107 use crate::server::BtpListener;
108 type Error = Box<dyn std::error::Error + Send + Sync>;
109 #[tokio::test]
110 async fn test_message_exchange_no_tls() -> Result<(), Error> {
111 let listener = TcpListener::bind("127.0.0.1:0").await?;
112 let server_addr = listener.local_addr()?;
113 let btp_conf = make_config(server_addr);
114 let server_task = tokio::spawn(async move {
115 let btp_listener = BtpListener::from(listener, btp_conf).await;
116 let mut server_socket = btp_listener.accept().await?;
117 let (_file_opt, msg_opt) = server_socket.read().await?;
118 let msg = msg_opt.ok_or("No message received")?;
119 assert_eq!(msg.body, "Hello, BTP!");
120 let response = BtpMessage::from_str("ACK");
121 server_socket.write_message(response).await?;
122
123 Ok::<_, Error>(())
124 });
125 let client_conf = make_config(server_addr);
126 let mut client_socket = BtpSocket::connect(client_conf).await?;
127
128 let request = BtpMessage::from_str("Hello, BTP!");
129 client_socket.write_message(request).await?;
130
131 let (_file_opt, msg_opt) = client_socket.read().await?;
132 let response = msg_opt.ok_or("No response received")?;
133 assert_eq!(response.body, "ACK");
134
135 server_task.await??;
136
137 Ok(())
138 }
139
140 #[tokio::test]
141 async fn test_file_transfer_no_tls() -> Result<(), Error> {
142 let tmp_dir = tempdir()?;
143 let file_path = tmp_dir.path().join("test.txt");
144 let original_content = "Hello, this is a test file.";
145 tokio::fs::write(&file_path, original_content).await?;
146
147 let listener = TcpListener::bind("127.0.0.1:0").await?;
148 let server_addr = listener.local_addr()?;
149 let btp_conf = make_config(server_addr);
150
151 let server_task = tokio::spawn(async move {
152 let btp_listener = BtpListener::from(listener, btp_conf).await;
153 let mut server_socket = btp_listener.accept().await?;
154
155 let (file_opt, _msg_opt) = server_socket.read().await?;
156 let file = file_opt.ok_or("No file received")?;
157 assert_eq!(file.file_content, original_content);
158
159 let ack = BtpMessage::from_str("FILE_RECEIVED");
160 server_socket.write_message(ack).await?;
161
162 Ok::<_, Error>(())
163 });
164
165 let client_conf = make_config(server_addr);
166 let mut client_socket = BtpSocket::connect(client_conf).await?;
167
168 let file = make_test_file(original_content, "test.txt");
169 client_socket.write_file(file).await?;
170
171 let (_file_opt, msg_opt) = client_socket.read().await?;
172 let ack = msg_opt.ok_or("No acknowledgment received")?;
173 assert_eq!(ack.body, "FILE_RECEIVED");
174
175 server_task.await??;
176
177 Ok(())
178 }
179
180 #[tokio::test]
181 async fn test_full_session_no_tls() -> Result<(), Error> {
182 let listener = TcpListener::bind("127.0.0.1:0").await?;
183 let server_addr = listener.local_addr()?;
184 let btp_conf = make_config(server_addr);
185
186 let server_task = tokio::spawn(async move {
187 let btp_listener = BtpListener::from(listener, btp_conf).await;
188 let server_socket = btp_listener.accept().await?;
189
190 server_socket.attach_handler(
191 |msg: BtpMessage| {
192 println!("Server received: {}", msg.body);
193 },
194 |_file: BtpFile| {
195 println!("Server received a file");
196 },
197 )?;
198
199 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
200 Ok::<_, Error>(())
201 });
202
203 let client_conf = make_config(server_addr);
204 let mut client_socket = BtpSocket::connect(client_conf).await?;
205
206 let msg = BtpMessage::from_str("Hello, echo!");
207 client_socket.write_message(msg).await?;
208
209 tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
210
211 server_task.await??;
212
213 Ok(())
214 }
215 }
216
217 #[cfg(feature = "tls")]
218 mod tls_tests {
219
220 type Error = Box<dyn std::error::Error + Send + Sync>;
221 use crate::server::BtpListenerTls;
222
223 use super::*;
224 use rustls::ServerConfig;
225 use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
226 use std::sync::Arc;
227 use tokio_rustls::TlsConnector;
228
229 fn make_test_tls_config() -> (Arc<ServerConfig>, Vec<u8>) {
230 let certified = rcgen::generate_simple_self_signed(vec!["127.0.0.1".into()]).unwrap();
231
232 let cert_der = certified.cert.der().to_vec();
233
234 let server_cert = rustls::pki_types::CertificateDer::from(certified.cert.der().clone());
235
236 let key_der = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
237 certified.signing_key.serialize_der(),
238 ));
239
240 let config = ServerConfig::builder()
241 .with_no_client_auth()
242 .with_single_cert(vec![server_cert], key_der)
243 .unwrap();
244
245 (Arc::new(config), cert_der)
246 }
247
248 #[tokio::test]
249 async fn test_message_exchange_with_tls() -> Result<(), Error> {
250 let listener = TcpListener::bind("127.0.0.1:0").await?;
251 let server_addr = listener.local_addr()?;
252 let btp_conf = make_config(server_addr);
253 let (tls_conf, cert_der) = make_test_tls_config();
254
255 let mut root_store = rustls::RootCertStore::empty();
256 root_store.add(cert_der.into()).unwrap();
257
258 let client_config = rustls::ClientConfig::builder()
259 .with_root_certificates(root_store)
260 .with_no_client_auth();
261
262 let server_task = tokio::spawn(async move {
263 let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
264 let mut server_socket = btp_listener.accept().await?;
265
266 let (_file_opt, msg_opt) = server_socket.read().await?;
267 let msg = msg_opt.ok_or("No message received")?;
268 assert_eq!(msg.body, "Hello, TLS BTP!");
269
270 let response = BtpMessage::from_str("TLS ACK");
271 server_socket.write_message(response).await?;
272
273 Ok::<_, Error>(())
274 });
275
276 let connector = TlsConnector::from(Arc::new(client_config));
277 let client_conf = make_config(server_addr);
278 let mut client_socket =
279 BtpSocket::connect_tls(server_addr, connector, client_conf).await?;
280
281 let request = BtpMessage::from_str("Hello, TLS BTP!");
282 client_socket.write_message(request).await?;
283
284 let (_file_opt, msg_opt) = client_socket.read().await?;
285 let response = msg_opt.ok_or("No response received")?;
286 assert_eq!(response.body, "TLS ACK");
287
288 server_task.await??;
289
290 Ok(())
291 }
292
293 #[tokio::test]
294 async fn test_file_transfer_with_tls() -> Result<(), Error> {
295 let tmp_dir = tempdir()?;
296 let file_path = tmp_dir.path().join("tls_test.txt");
297 let original_content = "TLS file transfer test content.";
298 tokio::fs::write(&file_path, original_content).await?;
299
300 let listener = TcpListener::bind("127.0.0.1:0").await?;
301 let server_addr = listener.local_addr()?;
302 let btp_conf = make_config(server_addr);
303 let (tls_conf, cert_der) = make_test_tls_config();
304
305 let mut root_store = rustls::RootCertStore::empty();
306 root_store.add(cert_der.into()).unwrap();
307
308 let client_config = rustls::ClientConfig::builder()
309 .with_root_certificates(root_store)
310 .with_no_client_auth();
311
312 let server_task = tokio::spawn(async move {
313 let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;
314 let mut server_socket = btp_listener.accept().await?;
315
316 let (file_opt, _msg_opt) = server_socket.read().await?;
317 let file = file_opt.ok_or("No file received")?;
318 assert_eq!(file.file_content, original_content);
319
320 let ack = BtpMessage::from_str("TLS FILE RECEIVED");
321 server_socket.write_message(ack).await?;
322
323 Ok::<_, Error>(())
324 });
325
326 let connector = TlsConnector::from(Arc::new(client_config));
327 let client_conf = make_config(server_addr);
328 let mut client_socket =
329 BtpSocket::connect_tls(server_addr, connector, client_conf).await?;
330
331 let file = make_test_file(original_content, "tls_test.txt");
332 client_socket.write_file(file).await?;
333
334 let (_file_opt, msg_opt) = client_socket.read().await?;
335 let ack = msg_opt.ok_or("No acknowledgment received")?;
336 assert_eq!(ack.body, "TLS FILE RECEIVED");
337
338 server_task.await??;
339
340 Ok(())
341 }
342 }
343}