Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Network] fix oom bug #4827

Merged
merged 5 commits into from
Feb 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Import-Package:
org.eclipse.smarthome.config.discovery,
org.eclipse.smarthome.core.cache,
org.eclipse.smarthome.core.library.types,
org.eclipse.smarthome.core.net,
org.eclipse.smarthome.core.thing,
org.eclipse.smarthome.core.thing.binding,
org.eclipse.smarthome.core.types,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
import java.net.ConnectException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.NoRouteToHostException;
import java.net.PortUnreachableException;
Expand All @@ -30,16 +30,20 @@
import java.net.SocketTimeoutException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.net.util.SubnetUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.net.CidrAddress;
import org.eclipse.smarthome.core.net.NetUtil;
import org.eclipse.smarthome.io.net.exec.ExecUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Network utility functions for pinging and for determining all interfaces and assigned IP addresses.
Expand All @@ -48,45 +52,17 @@
*/
@NonNullByDefault
public class NetworkUtils {
private final Logger logger = LoggerFactory.getLogger(NetworkUtils.class);

/**
* Gets every IPv4 Address on each Interface except the loopback
* The Address format is ip/subnet
*
* @return The collected IPv4 Addresses
*/
public Set<String> getInterfaceIPs() {
Set<String> interfaceIPs = new HashSet<>();

Enumeration<NetworkInterface> interfaces;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException ignored) {
// If we are not allowed to enumerate, we return an empty result set.
return interfaceIPs;
}

// For each interface ...
for (Enumeration<NetworkInterface> en = interfaces; en.hasMoreElements();) {
NetworkInterface networkInterface = en.nextElement();
boolean isLoopback = true;
try {
isLoopback = networkInterface.isLoopback();
} catch (SocketException ignored) {
}
if (!isLoopback) {
// .. and for each address ...
for (Iterator<InterfaceAddress> it = networkInterface.getInterfaceAddresses().iterator(); it
.hasNext();) {

// ... get IP and Subnet
InterfaceAddress interfaceAddress = it.next();
interfaceIPs.add(interfaceAddress.getAddress().getHostAddress() + "/"
+ interfaceAddress.getNetworkPrefixLength());
}
}
}

return interfaceIPs;
public Set<CidrAddress> getInterfaceIPs() {
return NetUtil.getAllInterfaceAddresses().stream().filter(a -> a.getAddress() instanceof Inet4Address)
.collect(Collectors.toSet());
}

/**
Expand Down Expand Up @@ -129,22 +105,38 @@ public Set<String> getNetworkIPs(int maximumPerInterface) {
* @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<String> interfaceIPs, int maximumPerInterface) {
public Set<String> getNetworkIPs(Set<CidrAddress> interfaceIPs, int maximumPerInterface) {
LinkedHashSet<String> networkIPs = new LinkedHashSet<>();

for (String string : interfaceIPs) {
try {
// gets every ip which can be assigned on the given network
SubnetUtils utils = new SubnetUtils(string);
String[] addresses = utils.getInfo().getAllAddresses();
int len = addresses.length;
if (maximumPerInterface != 0 && maximumPerInterface < len) {
len = maximumPerInterface;
}
for (int i = 0; i < len; i++) {
networkIPs.add(addresses[i]);
}
} catch (Exception ex) {
short minCidrPrefixLength = 8; // historic Class A network, addresses = 16777214
if (maximumPerInterface != 0) {
// calculate minimum CIDR prefix length from maximumPerInterface
// (equals leading unset bits (Integer has 32 bits)
minCidrPrefixLength = (short) Integer.numberOfLeadingZeros(maximumPerInterface);
if (Integer.bitCount(maximumPerInterface) == 1) {
// if only the highest is set, decrease prefix by 1 to cover all addresses
minCidrPrefixLength--;
}
}
logger.trace("set minCidrPrefixLength to {}, maximumPerInterface is {}", minCidrPrefixLength,
maximumPerInterface);

for (CidrAddress cidrNotation : interfaceIPs) {
if (cidrNotation.getPrefix() < minCidrPrefixLength) {
logger.info(
"CIDR prefix is smaller than /{} on interface with address {}, truncating to /{}, some addresses might be lost",
minCidrPrefixLength, cidrNotation, minCidrPrefixLength);
cidrNotation = new CidrAddress(cidrNotation.getAddress(), minCidrPrefixLength);
}

SubnetUtils utils = new SubnetUtils(cidrNotation.toString());
String[] addresses = utils.getInfo().getAllAddresses();
int len = addresses.length;
if (maximumPerInterface != 0 && maximumPerInterface < len) {
len = maximumPerInterface;
}
for (int i = 0; i < len; i++) {
networkIPs.add(addresses[i]);
}
}

Expand Down