feat(client): add --port option to specify server port
Allow users to override the default TFTP port (69) when connecting to servers running on non-standard ports. The port can be specified via -p or --port flag. Examples: tftp -p 6969 get 192.168.1.1 config.txt tftp --port 1069 put myserver firmware.bin If a port is embedded in the host (host:port format), the --port option takes precedence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
//! put <HOST> <LOCAL_FILE> [REMOTE_FILE] Upload a file
|
//! put <HOST> <LOCAL_FILE> [REMOTE_FILE] Upload a file
|
||||||
//!
|
//!
|
||||||
//! Options:
|
//! Options:
|
||||||
|
//! -p, --port <PORT> Server port (default: 69)
|
||||||
//! -m, --mode <MODE> Transfer mode: octet (default) or netascii
|
//! -m, --mode <MODE> Transfer mode: octet (default) or netascii
|
||||||
//! -v, --verbose Enable verbose output
|
//! -v, --verbose Enable verbose output
|
||||||
//! -h, --help Print help
|
//! -h, --help Print help
|
||||||
@@ -23,8 +24,8 @@
|
|||||||
//! # Download a file
|
//! # Download a file
|
||||||
//! tftp get 192.168.1.1 config.txt
|
//! tftp get 192.168.1.1 config.txt
|
||||||
//!
|
//!
|
||||||
//! # Download to a specific local file
|
//! # Download from a custom port
|
||||||
//! tftp get 192.168.1.1 config.txt local_config.txt
|
//! tftp -p 6969 get 192.168.1.1 config.txt
|
||||||
//!
|
//!
|
||||||
//! # Upload a file
|
//! # Upload a file
|
||||||
//! tftp put 192.168.1.1 firmware.bin
|
//! tftp put 192.168.1.1 firmware.bin
|
||||||
@@ -48,14 +49,15 @@ fn print_usage(program: &str) {
|
|||||||
eprintln!(" put <HOST> <LOCAL_FILE> [REMOTE_FILE] Upload a file");
|
eprintln!(" put <HOST> <LOCAL_FILE> [REMOTE_FILE] Upload a file");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
eprintln!("Options:");
|
eprintln!("Options:");
|
||||||
|
eprintln!(" -p, --port <PORT> Server port (default: 69)");
|
||||||
eprintln!(" -m, --mode <MODE> Transfer mode: octet (default) or netascii");
|
eprintln!(" -m, --mode <MODE> Transfer mode: octet (default) or netascii");
|
||||||
eprintln!(" -v, --verbose Enable verbose output");
|
eprintln!(" -v, --verbose Enable verbose output");
|
||||||
eprintln!(" -h, --help Print help");
|
eprintln!(" -h, --help Print help");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
eprintln!("Examples:");
|
eprintln!("Examples:");
|
||||||
eprintln!(" {program} get 192.168.1.1 config.txt");
|
eprintln!(" {program} get 192.168.1.1 config.txt");
|
||||||
eprintln!(" {program} put 192.168.1.1 firmware.bin");
|
eprintln!(" {program} -p 6969 get 192.168.1.1 config.txt");
|
||||||
eprintln!(" {program} -m netascii get 192.168.1.1:69 readme.txt local.txt");
|
eprintln!(" {program} -m netascii put 192.168.1.1 readme.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Command to execute.
|
/// Command to execute.
|
||||||
@@ -75,6 +77,7 @@ enum Command {
|
|||||||
/// Parsed command-line arguments.
|
/// Parsed command-line arguments.
|
||||||
struct Args {
|
struct Args {
|
||||||
command: Command,
|
command: Command,
|
||||||
|
port: Option<u16>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
}
|
}
|
||||||
@@ -84,6 +87,7 @@ fn parse_args() -> Result<Args, String> {
|
|||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let program = &args[0];
|
let program = &args[0];
|
||||||
|
|
||||||
|
let mut port: Option<u16> = None;
|
||||||
let mut mode = Mode::Octet;
|
let mut mode = Mode::Octet;
|
||||||
let mut verbose = false;
|
let mut verbose = false;
|
||||||
|
|
||||||
@@ -96,6 +100,17 @@ fn parse_args() -> Result<Args, String> {
|
|||||||
print_usage(program);
|
print_usage(program);
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
"-p" | "--port" => {
|
||||||
|
i += 1;
|
||||||
|
if i >= args.len() {
|
||||||
|
return Err("--port requires an argument".to_string());
|
||||||
|
}
|
||||||
|
port = Some(
|
||||||
|
args[i]
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| format!("invalid port: {}", args[i]))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
"-m" | "--mode" => {
|
"-m" | "--mode" => {
|
||||||
i += 1;
|
i += 1;
|
||||||
if i >= args.len() {
|
if i >= args.len() {
|
||||||
@@ -172,14 +187,23 @@ fn parse_args() -> Result<Args, String> {
|
|||||||
|
|
||||||
Ok(Args {
|
Ok(Args {
|
||||||
command,
|
command,
|
||||||
|
port,
|
||||||
mode,
|
mode,
|
||||||
verbose,
|
verbose,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format host for connection (add default port if needed).
|
/// Format host for connection.
|
||||||
fn format_host(host: &str) -> String {
|
///
|
||||||
if host.contains(':') {
|
/// If a port override is provided, it is used. Otherwise, if the host already
|
||||||
|
/// contains a port (has ':'), it is used as-is. Otherwise, the default TFTP
|
||||||
|
/// port 69 is appended.
|
||||||
|
fn format_host(host: &str, port_override: Option<u16>) -> String {
|
||||||
|
if let Some(port) = port_override {
|
||||||
|
// Strip any existing port from host and use override
|
||||||
|
let host_part = host.split(':').next().unwrap_or(host);
|
||||||
|
format!("{host_part}:{port}")
|
||||||
|
} else if host.contains(':') {
|
||||||
host.to_string()
|
host.to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{host}:69")
|
format!("{host}:69")
|
||||||
@@ -203,7 +227,7 @@ fn main() -> ExitCode {
|
|||||||
remote_file,
|
remote_file,
|
||||||
local_file,
|
local_file,
|
||||||
} => {
|
} => {
|
||||||
let addr = format_host(&host);
|
let addr = format_host(&host, args.port);
|
||||||
|
|
||||||
if args.verbose {
|
if args.verbose {
|
||||||
eprintln!("Getting '{remote_file}' from {addr} -> '{local_file}'");
|
eprintln!("Getting '{remote_file}' from {addr} -> '{local_file}'");
|
||||||
@@ -255,7 +279,7 @@ fn main() -> ExitCode {
|
|||||||
local_file,
|
local_file,
|
||||||
remote_file,
|
remote_file,
|
||||||
} => {
|
} => {
|
||||||
let addr = format_host(&host);
|
let addr = format_host(&host, args.port);
|
||||||
|
|
||||||
if args.verbose {
|
if args.verbose {
|
||||||
eprintln!("Putting '{local_file}' -> {addr} as '{remote_file}'");
|
eprintln!("Putting '{local_file}' -> {addr} as '{remote_file}'");
|
||||||
|
|||||||
Reference in New Issue
Block a user