2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.lifx.internal.util;
15 import static org.openhab.binding.lifx.internal.LifxBindingConstants.BROADCAST_PORT;
17 import java.net.Inet4Address;
18 import java.net.InetAddress;
19 import java.net.InetSocketAddress;
20 import java.net.InterfaceAddress;
21 import java.net.NetworkInterface;
22 import java.net.SocketException;
23 import java.time.Duration;
24 import java.util.ArrayList;
25 import java.util.Enumeration;
26 import java.util.List;
27 import java.util.concurrent.atomic.AtomicInteger;
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * The {@link LifxNetworkUtil} provides network interface information to the LIFX binding objects. The information is
35 * updated when it is older than {@link #UPDATE_INTERVAL_MILLIS}.
37 * @author Wouter Born - Initial contribution
40 public final class LifxNetworkUtil {
42 private static final Logger LOGGER = LoggerFactory.getLogger(LifxNetworkUtil.class);
43 private static final AtomicInteger BROADCAST_PORT_COUNTER = new AtomicInteger(1);
44 private static final long UPDATE_INTERVAL_MILLIS = Duration.ofSeconds(15).toMillis();
45 private static final int PORT_MAX = 65535;
47 private static List<InetSocketAddress> broadcastAddresses = new ArrayList<>();
48 private static List<InetAddress> interfaceAddresses = new ArrayList<>();
49 private static int bufferSize; // upper bound of the MTUs of all available IPv4 network interfaces
50 private static long lastUpdateMillis;
52 private LifxNetworkUtil() {
53 // hidden utility class constructor
57 * Updates the network information without any synchronization in a thread-safe way.
59 private static void updateNetworkInformation() {
60 LOGGER.debug("Updating network information");
62 List<InetSocketAddress> newBroadcastAddresses = new ArrayList<>();
63 List<InetAddress> newInterfaceAddresses = new ArrayList<>();
64 int newBufferSize = 0;
66 Enumeration<NetworkInterface> networkInterfaces = null;
68 networkInterfaces = NetworkInterface.getNetworkInterfaces();
69 } catch (SocketException e) {
70 LOGGER.debug("Exception while getting network interfaces: '{}'", e.getMessage());
73 if (networkInterfaces != null) {
74 while (networkInterfaces.hasMoreElements()) {
75 NetworkInterface iface = networkInterfaces.nextElement();
77 if (iface.isUp() && !iface.isLoopback()) {
78 for (InterfaceAddress ifaceAddr : iface.getInterfaceAddresses()) {
79 if (ifaceAddr.getAddress() instanceof Inet4Address) {
80 newInterfaceAddresses.add(ifaceAddr.getAddress());
81 newBufferSize = Math.max(newBufferSize, iface.getMTU());
82 if (ifaceAddr.getBroadcast() != null) {
84 .add(new InetSocketAddress(ifaceAddr.getBroadcast(), BROADCAST_PORT));
89 } catch (SocketException e) {
90 LOGGER.debug("Exception while getting information for network interface '{}': '{}'",
91 iface.getName(), e.getMessage());
95 broadcastAddresses = newBroadcastAddresses;
96 interfaceAddresses = newInterfaceAddresses;
97 bufferSize = newBufferSize;
100 lastUpdateMillis = System.currentTimeMillis();
103 private static void updateOutdatedNetworkInformation() {
104 boolean updateIntervalElapsed = System.currentTimeMillis() - lastUpdateMillis > UPDATE_INTERVAL_MILLIS;
105 if (updateIntervalElapsed) {
106 updateNetworkInformation();
110 public static List<InetSocketAddress> getBroadcastAddresses() {
111 updateOutdatedNetworkInformation();
112 return broadcastAddresses;
115 public static List<InetAddress> getInterfaceAddresses() {
116 updateOutdatedNetworkInformation();
117 return interfaceAddresses;
120 public static int getBufferSize() {
121 updateOutdatedNetworkInformation();
125 public static boolean isLocalAddress(InetAddress address) {
126 return getInterfaceAddresses().contains(address);
129 public static boolean isRemoteAddress(InetAddress address) {
130 return !isLocalAddress(address);
133 public static int getNewBroadcastPort() {
134 int offset = BROADCAST_PORT_COUNTER.getAndUpdate((value) -> {
135 return (value + 1) % Integer.MAX_VALUE;
137 return BROADCAST_PORT + (offset % (PORT_MAX - BROADCAST_PORT));