@NonNullByDefault
public class NetworkBindingConstants {
- public static final String BINDING_ID = "network";
+ private static final String BINDING_ID = "network";
// List of all Thing Type UIDs
public static final ThingTypeUID BACKWARDS_COMPATIBLE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.network.internal.dhcp.DHCPListenService;
+import org.openhab.binding.network.internal.dhcp.DHCPPacketListenerServer;
import org.openhab.binding.network.internal.dhcp.IPRequestReceivedCallback;
import org.openhab.binding.network.internal.toberemoved.cache.ExpiringCacheAsync;
import org.openhab.binding.network.internal.utils.NetworkUtils;
@NonNullByDefault
public class PresenceDetection implements IPRequestReceivedCallback {
- public static final double NOT_REACHABLE = -1;
- public static final int DESTINATION_TTL = 300 * 1000; // in ms, 300 s
+ private static final int DESTINATION_TTL = 300 * 1000; // in ms, 300 s
NetworkUtils networkUtils = new NetworkUtils();
private final Logger logger = LoggerFactory.getLogger(PresenceDetection.class);
private boolean useDHCPsniffing = false;
private String ipPingState = "Disabled";
protected String arpPingUtilPath = "";
- protected ArpPingUtilEnum arpPingMethod = ArpPingUtilEnum.DISABLED;
+ private ArpPingUtilEnum arpPingMethod = ArpPingUtilEnum.DISABLED;
protected @Nullable IpPingMethodEnum pingMethod = null;
private boolean iosDevice;
private Set<Integer> tcpPorts = new HashSet<>();
private @NonNullByDefault({}) ExpiringCache<@Nullable InetAddress> destination;
private @Nullable InetAddress cachedDestination = null;
- public boolean preferResponseTimeAsLatency;
+ private boolean preferResponseTimeAsLatency;
/// State variables (cannot be final because of test dependency injections)
ExpiringCacheAsync<PresenceDetectionValue> cache;
private @Nullable ScheduledFuture<?> refreshJob;
protected @Nullable ExecutorService executorService;
private String dhcpState = "off";
- Integer currentCheck = 0;
+ private Integer currentCheck = 0;
int detectionChecks;
public PresenceDetection(final PresenceDetectionListener updateListener, int cacheDeviceStateTimeInMS)
this.destination = new ExpiringCache<>(DESTINATION_TTL, () -> {
try {
InetAddress destinationAddress = InetAddress.getByName(hostname);
- if (!destinationAddress.equals(cachedDestination)) {
+ InetAddress cached = cachedDestination;
+ if (!destinationAddress.equals(cached)) {
logger.trace("host name resolved to other address, (re-)setup presence detection");
setUseArpPing(true, destinationAddress);
if (useDHCPsniffing) {
- if (cachedDestination != null) {
- disableDHCPListen(cachedDestination);
+ if (cached != null) {
+ disableDHCPListen(cached);
}
enableDHCPListen(destinationAddress);
}
return destinationAddress;
} catch (UnknownHostException e) {
logger.trace("hostname resolution failed");
- if (cachedDestination != null) {
- disableDHCPListen(cachedDestination);
+ InetAddress cached = cachedDestination;
+ if (cached != null) {
+ disableDHCPListen(cached);
cachedDestination = null;
}
return null;
future.cancel(true);
refreshJob = null;
}
- if (cachedDestination != null) {
- disableDHCPListen(cachedDestination);
+ InetAddress cached = cachedDestination;
+ if (cached != null) {
+ disableDHCPListen(cached);
}
}
*/
private void enableDHCPListen(InetAddress destinationAddress) {
try {
- if (DHCPListenService.register(destinationAddress.getHostAddress(), this).isUseUnprevilegedPort()) {
- dhcpState = "No access right for port 67. Bound to port 6767 instead. Port forwarding necessary!";
- } else {
- dhcpState = "Running normally";
- }
+ DHCPPacketListenerServer listener = DHCPListenService.register(destinationAddress.getHostAddress(), this);
+ dhcpState = String.format("Bound to port %d - %s", listener.getCurrentPort(),
+ (listener.usingPrivilegedPort() ? "Running normally" : "Port forwarding necessary !"));
} catch (SocketException e) {
- logger.warn("Cannot use DHCP sniffing.", e);
+ dhcpState = String.format("Cannot use DHCP sniffing: %s", e.getMessage());
+ logger.warn("{}", dhcpState);
useDHCPsniffing = false;
- dhcpState = "Cannot use DHCP sniffing: " + e.getLocalizedMessage();
}
}
- private void disableDHCPListen(@Nullable InetAddress destinationAddress) {
- if (destinationAddress != null) {
- DHCPListenService.unregister(destinationAddress.getHostAddress());
- dhcpState = "off";
- }
+ private void disableDHCPListen(InetAddress destinationAddress) {
+ DHCPListenService.unregister(destinationAddress.getHostAddress());
+ dhcpState = "off";
}
}
// Wake-on-LAN magic packet constants
static final int PREFIX_BYTE_SIZE = 6;
- static final int MAC_REPETITIONS = 16;
+ private static final int MAC_REPETITIONS = 16;
static final int MAC_BYTE_SIZE = 6;
static final int MAGIC_PACKET_BYTE_SIZE = PREFIX_BYTE_SIZE + MAC_REPETITIONS * MAC_BYTE_SIZE;
- static final String[] MAC_SEPARATORS = new String[] { ":", "-" };
+ private static final String[] MAC_SEPARATORS = new String[] { ":", "-" };
private final Logger logger = LoggerFactory.getLogger(WakeOnLanPacketSender.class);
@NonNullByDefault
public class DHCPListenService {
static @Nullable DHCPPacketListenerServer instance;
- static Map<String, IPRequestReceivedCallback> registeredListeners = new TreeMap<>();
- static Logger logger = LoggerFactory.getLogger(DHCPListenService.class);
+ private static Map<String, IPRequestReceivedCallback> registeredListeners = new TreeMap<>();
+ private static Logger logger = LoggerFactory.getLogger(DHCPListenService.class);
- @SuppressWarnings({ "null", "unused" })
public static synchronized DHCPPacketListenerServer register(String hostAddress,
IPRequestReceivedCallback dhcpListener) throws SocketException {
DHCPPacketListenerServer instance = DHCPListenService.instance;
*
* @return option type, of <tt>null</tt> if not present.
*/
- @SuppressWarnings({ "null", "unused" })
public @Nullable Byte getDHCPMessageType() {
byte[] opt = options.get(DHO_DHCP_MESSAGE_TYPE);
if (opt == null) {
/**
* Returns the requested IP address of a BOOTREQUEST packet.
*/
- @SuppressWarnings({ "null", "unused" })
public @Nullable InetAddress getRequestedIPAddress() throws IllegalArgumentException, UnknownHostException {
byte[] opt = options.get(DHO_DHCP_REQUESTED_ADDRESS);
if (opt == null) {
package org.openhab.binding.network.internal.dhcp;
import java.io.IOException;
-import java.net.BindException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
*/
@NonNullByDefault
public class DHCPPacketListenerServer extends Thread {
+ private static final int PRIVILEGED_PORT = 67;
+ private static final int UNPRIVILEGED_PORT = 6767;
private byte[] buffer = new byte[1024];
- protected @Nullable DatagramSocket dsocket;
+ private @Nullable DatagramSocket dsocket;
private DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
- boolean willbeclosed = false;
- Logger logger = LoggerFactory.getLogger(DHCPPacketListenerServer.class);
- private boolean useUnprevilegedPort = false;
private final IPRequestReceivedCallback listener;
+ private final Logger logger = LoggerFactory.getLogger(DHCPPacketListenerServer.class);
+ private boolean willbeclosed = false;
+ private int currentPort = PRIVILEGED_PORT;
- DHCPPacketListenerServer(IPRequestReceivedCallback listener) throws SocketException, BindException {
+ DHCPPacketListenerServer(IPRequestReceivedCallback listener) throws SocketException {
this.listener = listener;
try {
- bindSocketTo(67);
+ bindSocketTo(currentPort);
} catch (SocketException e) {
- useUnprevilegedPort = true;
- bindSocketTo(6767);
+ currentPort = UNPRIVILEGED_PORT;
+ bindSocketTo(currentPort);
}
}
- protected void bindSocketTo(int port) throws SocketException {
+ private void bindSocketTo(int port) throws SocketException {
DatagramSocket dsocket = new DatagramSocket(null);
dsocket.setReuseAddress(true);
dsocket.setBroadcast(true);
return dsocket;
}
- // Return true if the instance couldn't bind to port 67 and used port 6767 instead
- // to listen to DHCP traffic (port forwarding necessary).
- public boolean isUseUnprevilegedPort() {
- return useUnprevilegedPort;
+ // Return true if the instance is using port 67 to listen to DHCP traffic (no port forwarding necessary).
+ public boolean usingPrivilegedPort() {
+ return currentPort == PRIVILEGED_PORT;
}
/**
dsocket = null;
}
}
+
+ public int getCurrentPort() {
+ return currentPort;
+ }
}
*/
@NonNullByDefault
public class ExpiringCacheAsync<V> {
- final long expiry;
- ExpiringCacheUpdate cacheUpdater;
+ private final long expiry;
+ private ExpiringCacheUpdate cacheUpdater;
long expiresAt = 0;
- boolean refreshRequested = false;
- V value;
- final List<Consumer<V>> waitingCacheCallbacks = new LinkedList<>();
+ private boolean refreshRequested = false;
+ private V value;
+ private final List<Consumer<V>> waitingCacheCallbacks = new LinkedList<>();
/**
* Implement the requestCacheUpdate method which will be called when the cache
*
* @return the new value
*/
- public void refreshValue(Consumer<V> callback) {
+ private void refreshValue(Consumer<V> callback) {
waitingCacheCallbacks.add(callback);
if (refreshRequested) {
return;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.commons.lang3.SystemUtils;
-import org.apache.commons.net.util.SubnetUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.io.net.exec.ExecUtil;
.collect(Collectors.toSet());
}
+ /**
+ * Gets every IPv4 address on the network defined by its cidr
+ *
+ * @return The collected IPv4 Addresses
+ */
+ private List<String> getIPAddresses(CidrAddress adr) {
+ List<String> result = new ArrayList<>();
+ byte[] octets = adr.getAddress().getAddress();
+ final int addressCount = (1 << (32 - adr.getPrefix())) - 2;
+ final int ipMask = 0xFFFFFFFF << (32 - adr.getPrefix());
+ octets[0] &= ipMask >> 24;
+ octets[1] &= ipMask >> 16;
+ octets[2] &= ipMask >> 8;
+ octets[3] &= ipMask;
+ try {
+ final CidrAddress baseIp = new CidrAddress(InetAddress.getByAddress(octets), (short) adr.getPrefix());
+ for (int i = 1; i <= addressCount; i++) {
+ int octet = i & ~ipMask;
+ byte[] segments = baseIp.getAddress().getAddress();
+ segments[2] += (octet >> 8);
+ segments[3] += octet;
+ result.add(InetAddress.getByAddress(segments).getHostAddress());
+ }
+ } catch (UnknownHostException e) {
+ logger.debug("Could not build net ip address.", e);
+ }
+ return result;
+ }
+
/**
* Get a set of all interface names.
*
* @param maximumPerInterface The maximum of IP addresses per interface or 0 to get all.
* @return Every single IP which can be assigned on the Networks the computer is connected to
*/
- public Set<String> getNetworkIPs(Set<CidrAddress> interfaceIPs, int maximumPerInterface) {
+ private Set<String> getNetworkIPs(Set<CidrAddress> interfaceIPs, int maximumPerInterface) {
LinkedHashSet<String> networkIPs = new LinkedHashSet<>();
short minCidrPrefixLength = 8; // historic Class A network, addresses = 16777214
cidrNotation = new CidrAddress(cidrNotation.getAddress(), minCidrPrefixLength);
}
- SubnetUtils utils = new SubnetUtils(cidrNotation.toString());
- String[] addresses = utils.getInfo().getAllAddresses();
- int len = addresses.length;
+ List<String> addresses = getIPAddresses(cidrNotation);
+ int len = addresses.size();
if (maximumPerInterface != 0 && maximumPerInterface < len) {
len = maximumPerInterface;
}
for (int i = 0; i < len; i++) {
- networkIPs.add(addresses[i]);
+ networkIPs.add(addresses.get(i));
}
}
* works JavaPing is returned.
*/
public IpPingMethodEnum determinePingMethod() {
+ String os = System.getProperty("os.name");
IpPingMethodEnum method;
- if (SystemUtils.IS_OS_WINDOWS) {
- method = IpPingMethodEnum.WINDOWS_PING;
- } else if (SystemUtils.IS_OS_MAC) {
- method = IpPingMethodEnum.MAC_OS_PING;
- } else if (SystemUtils.IS_OS_UNIX) {
- method = IpPingMethodEnum.IPUTILS_LINUX_PING;
- } else {
- // We cannot estimate the command line for any other operating system and just return false
+ if (os == null) {
return IpPingMethodEnum.JAVA_PING;
+ } else {
+ os = os.toLowerCase();
+ if (os.indexOf("win") >= 0) {
+ method = IpPingMethodEnum.WINDOWS_PING;
+ } else if (os.indexOf("mac") >= 0) {
+ method = IpPingMethodEnum.MAC_OS_PING;
+ } else if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0 || os.indexOf("aix") >= 0) {
+ method = IpPingMethodEnum.IPUTILS_LINUX_PING;
+ } else {
+ // We cannot estimate the command line for any other operating system and just return false
+ return IpPingMethodEnum.JAVA_PING;
+ }
}
try {