package org.openhab.binding.network.internal;
import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
+import java.net.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Stream;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.net.NetUtil;
private final Logger logger = LoggerFactory.getLogger(WakeOnLanPacketSender.class);
private final String macAddress;
+
+ @Nullable
+ private final String hostname;
+
+ @Nullable
+ private final Integer port;
+
private byte @Nullable [] magicPacket;
private final Consumer<byte[]> magicPacketSender;
+ public WakeOnLanPacketSender(String macAddress, @Nullable String hostname, @Nullable Integer port) {
+ this.macAddress = macAddress;
+ this.hostname = hostname;
+ this.port = port;
+ this.magicPacketSender = this::sendMagicPacket;
+ }
+
public WakeOnLanPacketSender(String macAddress) {
this.macAddress = macAddress;
- this.magicPacketSender = this::broadcastMagicPacket;
+ this.hostname = null;
+ this.port = null;
+ this.magicPacketSender = this::sendMagicPacket;
}
/**
*/
WakeOnLanPacketSender(String macAddress, Consumer<byte[]> magicPacketSender) {
this.macAddress = macAddress;
+ this.hostname = null;
+ this.port = null;
this.magicPacketSender = magicPacketSender;
}
return bytes;
}
- private void broadcastMagicPacket(byte[] magicPacket) {
+ private void sendMagicPacket(byte[] magicPacket) {
try (DatagramSocket socket = new DatagramSocket()) {
- broadcastAddressStream().forEach(broadcastAddress -> {
- try {
- DatagramPacket packet = new DatagramPacket(magicPacket, MAGIC_PACKET_BYTE_SIZE, broadcastAddress,
- WOL_UDP_PORT);
- socket.send(packet);
- logger.debug("Wake-on-LAN packet sent (MAC address: {}, broadcast address: {})", macAddress,
- broadcastAddress.getHostAddress());
- } catch (IOException e) {
- logger.debug("Failed to send Wake-on-LAN packet (MAC address: {}, broadcast address: {})",
- macAddress, broadcastAddress.getHostAddress(), e);
- }
- });
- logger.info("Wake-on-LAN packets sent (MAC address: {})", macAddress);
+ if (StringUtils.isEmpty(hostname)) {
+ broadcastMagicPacket(magicPacket, socket);
+ } else {
+ SocketAddress socketAddress = new InetSocketAddress(this.hostname,
+ Objects.requireNonNullElse(this.port, WOL_UDP_PORT));
+ sendMagicPacketToIp(magicPacket, socket, socketAddress);
+ }
} catch (SocketException e) {
logger.error("Failed to open Wake-on-LAN datagram socket", e);
}
}
+ private void broadcastMagicPacket(byte[] magicPacket, DatagramSocket socket) {
+ broadcastAddressStream().forEach(broadcastAddress -> {
+ try {
+ DatagramPacket packet = new DatagramPacket(magicPacket, MAGIC_PACKET_BYTE_SIZE, broadcastAddress,
+ WOL_UDP_PORT);
+ socket.send(packet);
+ logger.debug("Wake-on-LAN packet sent (MAC address: {}, broadcast address: {})", macAddress,
+ broadcastAddress.getHostAddress());
+ } catch (IOException e) {
+ logger.debug("Failed to send Wake-on-LAN packet (MAC address: {}, broadcast address: {})", macAddress,
+ broadcastAddress.getHostAddress(), e);
+ }
+ });
+ logger.info("Wake-on-LAN packets sent (MAC address: {})", macAddress);
+ }
+
+ private void sendMagicPacketToIp(byte[] magicPacket, DatagramSocket socket, SocketAddress ip) {
+ DatagramPacket packet = new DatagramPacket(magicPacket, MAGIC_PACKET_BYTE_SIZE, ip);
+ try {
+ socket.send(packet);
+ } catch (IOException e) {
+ logger.debug("Failed to send Wake-on-LAN packet (MAC address: {}, address: {})", macAddress, ip, e);
+ }
+ logger.info("Wake-on-LAN packets sent (MAC address: {}, IP address: {})", macAddress, ip);
+ }
+
private Stream<InetAddress> broadcastAddressStream() {
return NetUtil.getAllBroadcastAddresses().stream().map(address -> {
try {
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.openhab.binding.network.internal.WakeOnLanPacketSender.*;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.openhab.core.util.HexUtils;
*
* @author Wouter Born - Initial contribution
*/
-@Timeout(value = 10, unit = TimeUnit.SECONDS)
+@Timeout(value = 10)
public class WakeOnLanPacketSenderTest {
private void assertValidMagicPacket(byte[] macBytes, byte[] packet) {
assertValidMagicPacket(HexUtils.hexToBytes("6f70656e4841"), actualPacket);
}
+ @Test
+ public void sendWithHostnameAndPort() throws IOException, InterruptedException {
+ sendWOLTest("127.0.0.1", 4444);
+ }
+
+ @Test
+ public void sendWithHostnameAndPortNull() throws IOException, InterruptedException {
+ sendWOLTest("127.0.0.1", null);
+ }
+
+ @Test
+ public void sendWithHostnameNullAndPortNull() throws IOException, InterruptedException {
+ sendWOLTest(null, null);
+ }
+
+ @Test
+ public void sendWithHostnameNull() throws IOException, InterruptedException {
+ sendWOLTest(null, 4444);
+ }
+
+ private void sendWOLTest(String hostname, Integer port) throws InterruptedException, IOException {
+ DatagramSocket socket = new DatagramSocket(4444);
+
+ byte[] buf = new byte[256];
+ DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
+
+ while (socket.isClosed()) {
+ Thread.sleep(100);
+ }
+
+ WakeOnLanPacketSender sender = new WakeOnLanPacketSender("6f70656e4841", hostname, port);
+ sender.sendPacket();
+
+ // This Test is only applicable for IP Requests
+ if (hostname != null && port != null) {
+ socket.receive(datagramPacket);
+ }
+
+ socket.close();
+
+ Assertions.assertTrue(datagramPacket.getData().length > 0);
+ }
+
@Test
public void sendWithEmptyMacAddressThrowsException() {
assertThrows(IllegalStateException.class, () -> new WakeOnLanPacketSender("").sendPacket());