Compare commits

...

7 Commits

Author SHA1 Message Date
Dustin 22c5fd4832 Add rustdoc comments
This commit adds documentation comments to the public API. In order for
`cargo doc` to build the documentation site, though, the crate must be a
library, so the `lib.rs` is needed to expose the necessary bits.
2018-09-29 12:11:10 -05:00
Dustin 60dd1f72dc main: Accept addresses as command-line arguments
Now that the `MacAddress` struct can handle parsing arbitrary input
without panicking, the main entry point can accept values from the user
in the form of command-line arguments. Users can pass one or more
addresses as positional arguments to the `wakeonlan` program, and a
magic packet will be sent to each one in series.
2018-09-29 11:42:34 -05:00
Dustin 823cfc2593 mac: Support parsing hyphen-separated addresses
Windows utilities typically display MAC addresses formatted with hyphens
separating the octets. Natively supporting parsing these representations
makes it easier for users to simply paste them, without having to
manually change the hyphens to colons.
2018-09-29 11:40:55 -05:00
Dustin 989a6eb0e6 mac: impl Debug and Display for MacAddress
Adding implementations of the `Debug` and `Display` traits to the
`MacAddress` struct allows creating string representations of these
objects.
2018-09-29 11:39:19 -05:00
Dustin ff8316895a mac: Handle improperly-formatted addresses
This commit introduces a new variant to the `ParseError` enumeration,
`ParseError::Format`. This error is returned by
`MacAddress::from_string()` when the input string is not correctly
formatted.
2018-09-29 11:38:35 -05:00
Dustin cc9f630dbc mac: Add ParseError enum
The `mac::ParseError` enumeration is intended to represent all of the
possible ways `MacAddress::from_string` could fail. For now, the only
known problem is an invalid hexadecimal integer found in one of the
octets, which causes a `ParseIntError`. The `ParseError` enum implements
the `Debug`, `Display`, and `Error` traits.
2018-09-20 20:56:37 -05:00
Dustin e3e4c39f21 mac: Add test for MacAddress::from_string 2018-09-19 22:38:55 -05:00
4 changed files with 141 additions and 10 deletions

19
src/lib.rs Normal file
View File

@ -0,0 +1,19 @@
//! Send Wake-on-LAN magic packets to wake sleeping machines
//!
//! This create provides a library and command-line interface for building
//! wake-on-LAN magic packets and sending them to network destinations.
//!
//! # Examples
//!
//! Basic usage:
//!
//! ```
//! use wakeonlan::{mac, magic};
//!
//! let mac = mac::MacAddress::from_string("aa:bb:cc:dd:ee:ff").unwrap();
//! let packet = magic::MagicPacket::new(&mac);
//! packet.send().unwrap();
//! ```
pub mod mac;
pub mod magic;

View File

@ -1,24 +1,108 @@
//! MAC address parsing
//!
//! This module provides tools for parsing and using MAC addresses. MAC
//! addresses are used as physical device addresses in Ethernet and other
//! layer-2 networking protocols.
use std::error;
use std::fmt;
use std::num; use std::num;
/// Error returned when attempting to parse a MAC address
#[derive(Debug)]
pub enum ParseError {
/// The input contained an invalid numeric value
Value(num::ParseIntError),
/// The input was not correctly formatted
Format,
}
impl From<num::ParseIntError> for ParseError {
fn from(e: num::ParseIntError) -> Self {
ParseError::Value(e)
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ParseError::Value(ref e) => e.fmt(f),
ParseError::Format => write!(f, "Invalid MAC address format"),
}
}
}
impl error::Error for ParseError {
fn cause(&self) -> Option<&error::Error> {
match *self {
ParseError::Value(ref e) => Some(e),
ParseError::Format => None,
}
}
}
/// MAC address
#[derive(Debug)]
pub struct MacAddress { pub struct MacAddress {
addr: [u8; 6], addr: [u8; 6],
} }
impl MacAddress { impl MacAddress {
pub fn from_string(s: &str) -> Result<Self, num::ParseIntError> {
s.split(":") /// Parse a MAC address from a string
///
/// This method parses a 48-bit MAC address from a standard string of
/// six hexadecimal octets separated by colons or hyphens.
pub fn from_string(s: &str) -> Result<Self, ParseError> {
let split: Result<Vec<_>, _> = s.split(|c| c == ':' || c == '-')
.map(|b| u8::from_str_radix(b, 16)) .map(|b| u8::from_str_radix(b, 16))
.collect::<Result<Vec<u8>, _>>() .collect();
.and_then(|parts| { match split {
Ok(parts) => {
let mut addr = [0u8; 6]; let mut addr = [0u8; 6];
addr.copy_from_slice(&parts[..6]); if parts.len() == 6 {
Ok(MacAddress { addr }) addr.copy_from_slice(&parts[..6]);
}) Ok(MacAddress { addr })
} else {
Err(ParseError::Format)
}
},
Err(e) => Err(ParseError::from(e)),
}
} }
/// Get the MAC address as an array of bytes
pub fn as_bytes(&self) -> &[u8; 6] { pub fn as_bytes(&self) -> &[u8; 6] {
&self.addr &self.addr
} }
} }
impl fmt::Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = self.addr.iter()
.map(|b| format!("{:x}", b))
.collect::<Vec<_>>()
.join(":");
write!(f, "{}", s)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_mac_from_string() {
let mac = MacAddress::from_string("a:bb:cc:dd:ee:ff").unwrap();
assert_eq!(&[0xa, 0xbb, 0xcc, 0xdd, 0xee, 0xff], mac.as_bytes());
}
}

View File

@ -1,22 +1,37 @@
//! Wake-On-LAN Magic Packets
//!
//! This module contains tools for creating and sending WOL magic packets.
use std::io; use std::io;
use std::net; use std::net;
use mac; use mac;
/// Magic packet for a specific MAC address
pub struct MagicPacket<'a> { pub struct MagicPacket<'a> {
mac: &'a mac::MacAddress, mac: &'a mac::MacAddress,
} }
impl<'a> MagicPacket<'a> { impl<'a> MagicPacket<'a> {
/// Create a new magic packet the given MAC address
pub fn new(mac: &'a mac::MacAddress) -> Self { pub fn new(mac: &'a mac::MacAddress) -> Self {
MagicPacket { mac } MagicPacket { mac }
} }
/// Send the magic packet
///
/// This method sends the magic packet to the default destination: the
/// subnet-directed broadcast on UDP port 9.
pub fn send(&self) -> io::Result<usize> { pub fn send(&self) -> io::Result<usize> {
self.send_to("255.255.255.255:9") self.send_to("255.255.255.255:9")
} }
/// Send the magic packet to a specific destination
///
/// This method sends the magic packet to the given destination address
/// and UDP port.
pub fn send_to<A: net::ToSocketAddrs>(&self, addr: A) -> io::Result<usize> { pub fn send_to<A: net::ToSocketAddrs>(&self, addr: A) -> io::Result<usize> {
let socket = net::UdpSocket::bind("0.0.0.0:0")?; let socket = net::UdpSocket::bind("0.0.0.0:0")?;
socket.set_broadcast(true)?; socket.set_broadcast(true)?;

View File

@ -1,9 +1,22 @@
use std::env;
mod mac; mod mac;
mod magic; mod magic;
fn main() { fn main() {
let mac = mac::MacAddress::from_string("0c:9d:92:0e:3a:41").unwrap(); let mut args = env::args();
let packet = magic::MagicPacket::new(&mac); args.next();
packet.send().unwrap(); for arg in args {
let mac = match mac::MacAddress::from_string(&arg) {
Ok(m) => m,
Err(e) => {
eprintln!("Invalid address: {} ({})", &arg, e);
continue;
},
};
let packet = magic::MagicPacket::new(&mac);
println!("Sending magic packet to {}", mac);
packet.send().unwrap();
}
} }