| .. | .. |
|---|
| 32 | 32 | return packet.toBytes(); |
|---|
| 33 | 33 | } |
|---|
| 34 | 34 | |
|---|
| 35 | + /// Derive subnet broadcast from an IP address (e.g., 192.168.1.100 → 192.168.1.255). |
|---|
| 36 | + static String? _subnetBroadcast(String? ip) { |
|---|
| 37 | + if (ip == null || ip.isEmpty) return null; |
|---|
| 38 | + final parts = ip.split('.'); |
|---|
| 39 | + if (parts.length != 4) return null; |
|---|
| 40 | + return '${parts[0]}.${parts[1]}.${parts[2]}.255'; |
|---|
| 41 | + } |
|---|
| 42 | + |
|---|
| 35 | 43 | /// Send a Wake-on-LAN packet for the given MAC address. |
|---|
| 36 | | - /// Broadcasts to 255.255.255.255:9 and optionally to a subnet broadcast. |
|---|
| 37 | | - static Future<void> wake(String macAddress, {String? subnetBroadcast}) async { |
|---|
| 44 | + /// Broadcasts to 255.255.255.255 and subnet broadcast derived from localHost. |
|---|
| 45 | + /// Sends on ports 7 and 9 for maximum compatibility. |
|---|
| 46 | + static Future<void> wake(String macAddress, {String? localHost}) async { |
|---|
| 38 | 47 | final macBytes = _parseMac(macAddress); |
|---|
| 39 | 48 | if (macBytes == null) { |
|---|
| 40 | 49 | throw ArgumentError('Invalid MAC address: $macAddress'); |
|---|
| .. | .. |
|---|
| 48 | 57 | ); |
|---|
| 49 | 58 | socket.broadcastEnabled = true; |
|---|
| 50 | 59 | |
|---|
| 51 | | - // Send to broadcast address |
|---|
| 52 | | - final broadcastAddr = InternetAddress('255.255.255.255'); |
|---|
| 53 | | - socket.send(packet, broadcastAddr, 9); |
|---|
| 60 | + final targets = <InternetAddress>[ |
|---|
| 61 | + InternetAddress('255.255.255.255'), |
|---|
| 62 | + ]; |
|---|
| 54 | 63 | |
|---|
| 55 | | - // Also send to subnet broadcast if provided |
|---|
| 56 | | - if (subnetBroadcast != null && subnetBroadcast.isNotEmpty) { |
|---|
| 64 | + // Add subnet broadcast derived from localHost |
|---|
| 65 | + final subnet = _subnetBroadcast(localHost); |
|---|
| 66 | + if (subnet != null) { |
|---|
| 57 | 67 | try { |
|---|
| 58 | | - final subnetAddr = InternetAddress(subnetBroadcast); |
|---|
| 59 | | - socket.send(packet, subnetAddr, 9); |
|---|
| 60 | | - } catch (_) { |
|---|
| 61 | | - // Ignore invalid subnet broadcast address |
|---|
| 62 | | - } |
|---|
| 68 | + targets.add(InternetAddress(subnet)); |
|---|
| 69 | + } catch (_) {} |
|---|
| 63 | 70 | } |
|---|
| 64 | 71 | |
|---|
| 65 | | - // Send a few extra packets for reliability |
|---|
| 66 | | - await Future.delayed(const Duration(milliseconds: 100)); |
|---|
| 67 | | - socket.send(packet, broadcastAddr, 9); |
|---|
| 68 | | - await Future.delayed(const Duration(milliseconds: 100)); |
|---|
| 69 | | - socket.send(packet, broadcastAddr, 9); |
|---|
| 72 | + // Send to all targets on both common WoL ports |
|---|
| 73 | + for (final addr in targets) { |
|---|
| 74 | + socket.send(packet, addr, 9); |
|---|
| 75 | + socket.send(packet, addr, 7); |
|---|
| 76 | + } |
|---|
| 77 | + |
|---|
| 78 | + // Repeat for reliability |
|---|
| 79 | + for (var i = 0; i < 3; i++) { |
|---|
| 80 | + await Future.delayed(const Duration(milliseconds: 100)); |
|---|
| 81 | + for (final addr in targets) { |
|---|
| 82 | + socket.send(packet, addr, 9); |
|---|
| 83 | + } |
|---|
| 84 | + } |
|---|
| 70 | 85 | |
|---|
| 71 | 86 | socket.close(); |
|---|
| 72 | 87 | } |
|---|