1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
//! A library for creating and sending Wake-on-LAN magic packets.
//!
//! # Usage
//!
//! ```
//! use wake_on_lan;
//!
//! // The MAC address of the target device
//! let mac_address: [u8; 6] = [0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A];
//!
//! // Create a magic packet (but don't send it yet)
//! let magic_packet = wake_on_lan::MagicPacket::new(&mac_address);
//!
//! // Send the magic packet via UDP to the broadcast address 255.255.255.255:9 from 0.0.0.0:0
//! magic_packet.send()?;
//! ```
//!
//! To choose the source and destination IPs and ports, use `send_to()`. If you want to access the
//! contents of the magic packet, use `magic_bytes()`.
use std::net::{UdpSocket, ToSocketAddrs, Ipv4Addr};
/// A Wake-on-LAN magic packet.
pub struct MagicPacket {
magic_bytes: [u8; 102]
}
impl MagicPacket {
/// Creates a new `MagicPacket` intended for `mac_address` (but doesn't send it yet).
pub fn new(mac_address: &[u8; 6]) -> MagicPacket {
let mut magic_bytes: [u8; 102];
// We use `unsafe` code to skip unnecessary array initialization and bounds checking.
unsafe {
magic_bytes = std::mem::uninitialized();
// Copy the header to the beginning.
let mut src: *const u8 = &MAGIC_BYTES_HEADER[0];
let mut dst: *mut u8 = &mut magic_bytes[0];
dst.copy_from_nonoverlapping(src, 6);
// Copy the MAC address once from the argument.
src = &mac_address[0];
dst = dst.offset(6);
dst.copy_from_nonoverlapping(src, 6);
// Repeat the MAC.
let src: *const u8 = dst; // src points to magic_bytes[6]
dst = dst.offset(6);
dst.copy_from_nonoverlapping(src, 6);
dst = dst.offset(6);
dst.copy_from_nonoverlapping(src, 12);
dst = dst.offset(12);
dst.copy_from_nonoverlapping(src, 24);
dst = dst.offset(24);
dst.copy_from_nonoverlapping(src, 48);
}
MagicPacket { magic_bytes }
}
/// Sends the magic packet via UDP to the broadcast address `255.255.255.255:9`.
/// Lets the operating system choose the source port and network interface.
pub fn send(&self) -> std::io::Result<()> {
self.send_to(
(Ipv4Addr::new(255, 255, 255, 255), 9),
(Ipv4Addr::new(0, 0, 0, 0), 0)
)
}
/// Sends the magic packet via UDP to/from an IP address and port number of your choosing.
pub fn send_to<A: ToSocketAddrs>(&self, to_addr: A, from_addr: A) -> std::io::Result<()> {
let socket = UdpSocket::bind(from_addr)?;
socket.set_broadcast(true)?;
socket.send_to(&self.magic_bytes, to_addr)?;
Ok(())
}
/// Returns the magic packet's payload (6 repetitions of `0xFF` and 16 repetitions of the
/// target device's MAC address). Send these bytes yourself over the network if you want to do
/// something more advanced (like reuse a single UDP socket when sending a large number of
/// magic packets).
pub fn magic_bytes(&self) -> &[u8; 102] {
&self.magic_bytes
}
}
const MAGIC_BYTES_HEADER: [u8; 6] = [0xFF; 6];