Matthias Nott
2026-03-21 a85c355d27a2016d3fe3f942ae6edfd9978d0e30
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
import 'dart:io';
import 'dart:typed_data';
/// Wake-on-LAN magic packet sender.
class WolService {
  WolService._();
  /// Parse a MAC address string (colon or dash separated) to bytes.
  static List<int>? _parseMac(String mac) {
    final cleaned = mac.replaceAll(RegExp(r'[:\-]'), '');
    if (cleaned.length != 12) return null;
    final bytes = <int>[];
    for (var i = 0; i < 12; i += 2) {
      final byte = int.tryParse(cleaned.substring(i, i + 2), radix: 16);
      if (byte == null) return null;
      bytes.add(byte);
    }
    return bytes;
  }
  /// Build the magic packet: 6x 0xFF followed by MAC address repeated 16 times.
  static Uint8List _buildPacket(List<int> macBytes) {
    final packet = BytesBuilder();
    // 6 bytes of 0xFF
    for (var i = 0; i < 6; i++) {
      packet.addByte(0xFF);
    }
    // MAC address repeated 16 times
    for (var i = 0; i < 16; i++) {
      packet.add(macBytes);
    }
    return packet.toBytes();
  }
  /// Send a Wake-on-LAN packet for the given MAC address.
  /// Broadcasts to 255.255.255.255:9 and optionally to a subnet broadcast.
  static Future<void> wake(String macAddress, {String? subnetBroadcast}) async {
    final macBytes = _parseMac(macAddress);
    if (macBytes == null) {
      throw ArgumentError('Invalid MAC address: $macAddress');
    }
    final packet = _buildPacket(macBytes);
    final socket = await RawDatagramSocket.bind(
      InternetAddress.anyIPv4,
      0,
    );
    socket.broadcastEnabled = true;
    // Send to broadcast address
    final broadcastAddr = InternetAddress('255.255.255.255');
    socket.send(packet, broadcastAddr, 9);
    // Also send to subnet broadcast if provided
    if (subnetBroadcast != null && subnetBroadcast.isNotEmpty) {
      try {
        final subnetAddr = InternetAddress(subnetBroadcast);
        socket.send(packet, subnetAddr, 9);
      } catch (_) {
        // Ignore invalid subnet broadcast address
      }
    }
    // Send a few extra packets for reliability
    await Future.delayed(const Duration(milliseconds: 100));
    socket.send(packet, broadcastAddr, 9);
    await Future.delayed(const Duration(milliseconds: 100));
    socket.send(packet, broadcastAddr, 9);
    socket.close();
  }
}