diff --git a/src/convert.rs b/src/convert.rs index 715f14a..c535b17 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -11,12 +11,61 @@ impl Convert { } } - pub fn to_string(buf: &[u8]) -> Result<(String, usize), Box> { - let zero_index = match buf[2..].iter().position(|&b| b == 0x00) { - Some(index) => index, + pub fn to_string(buf: &[u8], start: usize) -> Result<(String, usize), Box> { + match buf[start..].iter().position(|&b| b == 0x00) { + Some(index) => Ok(( + String::from_utf8(buf[start..start + index].to_vec())?, + index + start, + )), None => return Err("invalid string".into()), - }; - - Ok((String::from_utf8(buf[2..zero_index].to_vec())?, zero_index)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn converts_to_u16() { + assert_eq!(Convert::to_u16(&[0x01, 0x02]).unwrap(), 0x0102); + assert_eq!(Convert::to_u16(&[0x00, 0x02]).unwrap(), 0x0002); + assert_eq!(Convert::to_u16(&[0xfe, 0xdc, 0xba]).unwrap(), 0xfedc); + } + + #[test] + fn returns_error_on_short_array() { + assert!(Convert::to_u16(&[0x01]).is_err()); + assert!(Convert::to_u16(&[]).is_err()); + } + + #[test] + fn converts_to_string() { + let (result, index) = Convert::to_string(b"hello world\0", 0).unwrap(); + assert_eq!(result, "hello world"); + assert_eq!(index, 11); + + let (result, index) = Convert::to_string(b"hello\0world", 0).unwrap(); + assert_eq!(result, "hello"); + assert_eq!(index, 5); + + let (result, index) = Convert::to_string(b"\0hello world", 0).unwrap(); + assert_eq!(result, ""); + assert_eq!(index, 0); + } + + #[test] + fn converts_to_string_with_index() { + let (result, index) = Convert::to_string(b"hello\0world\0", 0).unwrap(); + assert_eq!(result, "hello"); + assert_eq!(index, 5); + + let (result, index) = Convert::to_string(b"hello\0world\0", 5).unwrap(); + assert_eq!(result, ""); + assert_eq!(index, 5); + + let (result, index) = Convert::to_string(b"hello\0world\0", 6).unwrap(); + assert_eq!(result, "world"); + assert_eq!(index, 11); } } diff --git a/src/lib.rs b/src/lib.rs index b3f8e16..ec561cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,12 @@ mod config; mod convert; +mod message; mod packet; mod server; +mod worker; pub use config::Config; pub use convert::Convert; +pub use message::Message; pub use server::Server; +pub use worker::Worker; diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000..85ae55d --- /dev/null +++ b/src/message.rs @@ -0,0 +1,65 @@ +use std::{ + error::Error, + net::{SocketAddr, UdpSocket}, +}; + +use crate::packet::{ErrorCode, Opcode, Option}; + +pub struct Message; + +impl Message { + pub fn send_data(socket: &UdpSocket, data: &[u8]) -> Result<(), Box> { + let buf = [&[0x00, Opcode::Data as u8], data].concat(); + + socket.send(&buf)?; + + Ok(()) + } + + pub fn send_ack(socket: &UdpSocket, block: u16) -> Result<(), Box> { + let buf = [&[0x00, Opcode::Ack as u8], &block.to_be_bytes()[..]].concat(); + + socket.send(&buf)?; + + Ok(()) + } + + pub fn send_error( + socket: &UdpSocket, + code: ErrorCode, + msg: &str, + ) -> Result<(), Box> { + socket.send(&get_error_buf(code, msg))?; + + Ok(()) + } + + pub fn send_error_to(socket: &UdpSocket, to: &SocketAddr, code: ErrorCode, msg: &str) { + if socket.send_to(&get_error_buf(code, msg), to).is_err() { + eprintln!("could not send an error message"); + } + } + + pub fn send_oack_to( + socket: &UdpSocket, + to: &SocketAddr, + options: Vec