[WIP] A simple wake-on-lan service
at main 72 lines 1.9 kB view raw
1use std::{fmt::Display, net::UdpSocket, num::ParseIntError, str::FromStr}; 2 3use thiserror::Error; 4 5#[derive(Clone, Debug)] 6pub struct MacAddress([u8; 6]); 7 8#[derive(Error, Debug)] 9pub enum MacAddressParseError { 10 #[error("Integer error: {}", .0)] 11 ParseInt(#[from] ParseIntError), 12 #[error("Mac address to short")] 13 TooShort, 14} 15 16impl MacAddress { 17 pub fn packet(&self) -> [u8; 102] { 18 let mut magic = [0xffu8; 17 * 6]; 19 let mut head: *mut u8 = &mut magic[0]; 20 let mac: *const u8 = &self.0[0]; 21 unsafe { 22 for _ in 0..16 { 23 head = head.offset(6); 24 head.copy_from_nonoverlapping(mac, 6); 25 } 26 }; 27 28 magic 29 } 30 31 pub async fn wake(&self) -> Result<(), std::io::Error> { 32 let packet = self.packet(); 33 let socket = UdpSocket::bind("0.0.0.0:0")?; 34 socket.set_broadcast(true)?; 35 socket.send_to(&packet, "255.255.255.255:9")?; 36 37 Ok(()) 38 } 39} 40 41impl Display for MacAddress { 42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 43 write!( 44 f, 45 "{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}:{:0<2X}", 46 self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5] 47 ) 48 } 49} 50 51impl From<MacAddress> for [u8; 6] { 52 fn from(value: MacAddress) -> Self { 53 value.0 54 } 55} 56 57impl FromStr for MacAddress { 58 type Err = MacAddressParseError; 59 60 fn from_str(s: &str) -> Result<Self, Self::Err> { 61 let address = s.split(":"); 62 let address = address 63 .map(|x| u8::from_str_radix(x, 16)) 64 .collect::<Result<Vec<_>, ParseIntError>>()?; 65 if address.len() != 6 { 66 return Err(MacAddressParseError::TooShort); 67 } 68 Ok(MacAddress([ 69 address[0], address[1], address[2], address[3], address[4], address[5], 70 ])) 71 } 72}