Add server config
This commit is contained in:
commit
713cadaaa0
6 changed files with 211 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "tftpd"
|
||||
version = "0.0.0"
|
||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "tftpd"
|
||||
version = "0.0.0"
|
||||
authors = ["Altuğ Bakan <mail@alt.ug>"]
|
||||
edition = "2021"
|
||||
description = "TFTP Server Daemon implemented in Rust"
|
||||
repository = "https://github.com/altugbakan/rs-tftpd"
|
||||
license = "MIT"
|
||||
keywords = ["tftp", "server"]
|
||||
categories = ["command-line-utilities"]
|
||||
177
src/config.rs
Normal file
177
src/config.rs
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
use std::error::Error;
|
||||
use std::net::{AddrParseError, Ipv4Addr};
|
||||
use std::num::ParseIntError;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fmt, process};
|
||||
|
||||
pub struct Config {
|
||||
pub ip_address: Ipv4Addr,
|
||||
pub port: u16,
|
||||
pub directory: PathBuf,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<T>(mut args: T) -> Result<Config, ConfigError>
|
||||
where
|
||||
T: Iterator<Item = String>,
|
||||
{
|
||||
let mut config = Config {
|
||||
ip_address: Ipv4Addr::new(127, 0, 0, 1),
|
||||
port: 69,
|
||||
directory: env::current_dir().unwrap_or(env::temp_dir()),
|
||||
};
|
||||
|
||||
args.next();
|
||||
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"-i" | "--ip-address" => {
|
||||
if let Some(ip_str) = args.next() {
|
||||
config.ip_address = ip_str.parse::<Ipv4Addr>()?;
|
||||
} else {
|
||||
return Err("missing ip address after flag".into());
|
||||
}
|
||||
}
|
||||
"-p" | "--port" => {
|
||||
if let Some(port_str) = args.next() {
|
||||
config.port = port_str.parse::<u16>()?;
|
||||
} else {
|
||||
return Err("missing port number after flag".into());
|
||||
}
|
||||
}
|
||||
"-d" | "--directory" => {
|
||||
if let Some(dir_str) = args.next() {
|
||||
if !Path::new(&dir_str).exists() {
|
||||
return Err(format!("{} does not exist", dir_str).into());
|
||||
}
|
||||
config.directory = PathBuf::from(dir_str);
|
||||
} else {
|
||||
return Err("missing directory after flag".into());
|
||||
}
|
||||
}
|
||||
"-h" | "--help" => {
|
||||
println!("TFTP Server Daemon\n");
|
||||
println!("Usage: tftpd [OPTIONS]\n");
|
||||
println!("Options:");
|
||||
println!(" -i, --ip-address <IP ADDRESS>\tSet the ip address of the server (Default: 127.0.0.1)");
|
||||
println!(
|
||||
" -p, --port <PORT>\t\tSet the listening port of the server (Default: )"
|
||||
);
|
||||
println!(" -d, --directory <DIRECTORY>\tSet the listening port of the server (Default: )");
|
||||
println!(" -h, --help\t\t\tPrint help information");
|
||||
process::exit(0);
|
||||
}
|
||||
invalid => return Err(format!("invalid flag: {}", invalid).into()),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConfigError {
|
||||
description: String,
|
||||
}
|
||||
|
||||
impl Error for ConfigError {
|
||||
fn description(&self) -> &str {
|
||||
self.description.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfigError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.description)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AddrParseError> for ConfigError {
|
||||
fn from(value: AddrParseError) -> Self {
|
||||
ConfigError {
|
||||
description: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for ConfigError {
|
||||
fn from(value: ParseIntError) -> Self {
|
||||
ConfigError {
|
||||
description: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ConfigError {
|
||||
fn from(value: String) -> Self {
|
||||
ConfigError { description: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ConfigError {
|
||||
fn from(value: &str) -> Self {
|
||||
ConfigError {
|
||||
description: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_full_config() {
|
||||
let config = Config::new(
|
||||
vec!["/", "-i", "0.0.0.0", "-p", "1234", "-d", "/"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(config.ip_address, Ipv4Addr::new(0, 0, 0, 0));
|
||||
assert_eq!(config.port, 1234);
|
||||
assert_eq!(config.directory, PathBuf::from_str("/").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_some_config() {
|
||||
let config = Config::new(
|
||||
vec!["/", "-i", "0.0.0.0", "-d", "/"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(config.ip_address, Ipv4Addr::new(0, 0, 0, 0));
|
||||
assert_eq!(config.port, 69);
|
||||
assert_eq!(config.directory, PathBuf::from_str("/").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_error_on_invalid_ip() {
|
||||
assert!(Config::new(
|
||||
vec!["/", "-i", "1234.5678.9012.3456"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()),
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_error_on_invalid_port() {
|
||||
assert!(Config::new(vec!["/", "-p", "1234567"].iter().map(|s| s.to_string()),).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_error_on_invalid_directory() {
|
||||
assert!(Config::new(
|
||||
vec!["/", "-d", "/this/does/not/exist"]
|
||||
.iter()
|
||||
.map(|s| s.to_string()),
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pub mod config;
|
||||
pub use config::Config;
|
||||
14
src/main.rs
Normal file
14
src/main.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use std::{env, process};
|
||||
use tftpd::Config;
|
||||
|
||||
fn main() {
|
||||
let config = Config::new(env::args()).unwrap_or_else(|err| {
|
||||
eprintln!("Problem parsing arguments: {}", err);
|
||||
process::exit(1)
|
||||
});
|
||||
|
||||
println!(
|
||||
"Running TFTP Server on {}:{}",
|
||||
config.ip_address, config.port
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue