net.dankito.utils.network.NetworkHelper.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-utils Show documentation
Show all versions of java-utils Show documentation
Some basic utils needed in many projects
package net.dankito.utils.network
import org.slf4j.LoggerFactory
import java.io.IOException
import java.net.*
import java.util.*
import kotlin.collections.ArrayList
open class NetworkHelper : INetworkHelper {
companion object {
const val MaxPortNumber = 65535
const val MinTcpPortNumber = 1
const val MinUdpPortNumber = 0
private val log = LoggerFactory.getLogger(NetworkHelper::class.java)
}
// in IPv6 there's no such thing as broadcast
override fun getBroadcastAddress(networkInterface: NetworkInterface): Inet4Address? {
for(address in networkInterface.inetAddresses) {
if(address is Inet4Address) {
try {
return getBroadcastAddress(address)
} catch(e: Exception) { log.error("Could not determine Broadcast Address of " + address.hostAddress, e)}
}
}
return null
}
override fun getBroadcastAddress(address: Inet4Address): Inet4Address? {
val broadcastAddress = address.address
broadcastAddress[broadcastAddress.size - 1] = 255.toByte()
return Inet4Address.getByAddress(broadcastAddress) as? Inet4Address
}
/**
* Returns MAC address of the given interface name.
* @param interfaceName eth0, wlan0 or NULL=use first interface
* *
* @return mac address or empty string
*/
override fun getMACAddress(interfaceName: String?): String {
try {
val interfaces = Collections.list(NetworkInterface.getNetworkInterfaces())
for (intf in interfaces) {
if (interfaceName != null) {
if (!intf.name.equals(interfaceName, ignoreCase = true)) continue
}
val mac = intf.hardwareAddress ?: return ""
val buf = StringBuilder()
for (idx in mac.indices)
buf.append(String.format("%02X:", mac[idx]))
if (buf.length > 0) buf.deleteCharAt(buf.length - 1)
return buf.toString()
}
} catch (ex: Exception) {
}
// for now eat exceptions
return ""
}
/**
* Get IP address from first non-localhost interface
* @param useIPv4 true=return ipv4, false=return ipv6
* *
* @return address or empty string
*/
override fun getIPAddress(useIPv4: Boolean): InetAddress? {
val addresses = getIPAddresses(useIPv4)
if (addresses.size > 0) {
return addresses[0]
}
return null
}
override fun getIPAddresses(onlyIPv4: Boolean): List {
val addresses = ArrayList()
try {
for(networkInterface in getConnectedRealNetworkInterfaces()) {
addresses.addAll(getIPAddresses(networkInterface, onlyIPv4))
}
} catch (ignored: Exception) { } // for now eat exceptions
return addresses
}
override fun getIPAddresses(networkInterface: NetworkInterface, onlyIPv4: Boolean): List {
val addresses = ArrayList()
val interfaceAddresses = Collections.list(networkInterface.inetAddresses)
for(address in interfaceAddresses) {
if(address.isLoopbackAddress == false) {
if(onlyIPv4 == false || address is Inet4Address) {
addresses.add(address)
}
}
}
return addresses
}
override fun getRealNetworkInterfaces(): Collection {
val allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces())
return allInterfaces.filter { shouldInterfaceBeIgnored(it) == false }
}
override fun getConnectedRealNetworkInterfaces(): Collection {
return getRealNetworkInterfaces().filter { it.isUp }
}
@Throws(SocketException::class)
protected open fun shouldInterfaceBeIgnored(networkInterface: NetworkInterface): Boolean {
return networkInterface.isLoopback ||
isCellularOrUsbInterface(networkInterface) ||
isDockerInterface(networkInterface) ||
isDummyInterface(networkInterface)
}
protected open fun isCellularOrUsbInterface(networkInterface: NetworkInterface): Boolean {
return networkInterface.name.startsWith("rmnet") // see for example https://stackoverflow.com/a/33748594
}
protected open fun isDockerInterface(networkInterface: NetworkInterface): Boolean {
return networkInterface.name.startsWith("docker")
}
protected open fun isDummyInterface(networkInterface: NetworkInterface): Boolean {
return networkInterface.name.startsWith("dummy")
}
override fun isSocketCloseException(exception: Exception): Boolean {
return exception is SocketException && "Socket closed" == exception.message
}
override fun isTcpPortAvailable(port: Int): Boolean {
if (port < MinTcpPortNumber || port > MaxPortNumber) {
throw IllegalArgumentException("Port has to be in range [$MinTcpPortNumber, $MaxPortNumber]")
}
var serverSocket: ServerSocket? = null
try {
serverSocket = ServerSocket(port)
serverSocket.reuseAddress = true
return true
}
catch (e: IOException) { }
finally {
try {
serverSocket?.close()
} catch (ignored: Exception) { }
}
return false
}
override fun isUdpPortAvailable(port: Int): Boolean {
if (port < MinUdpPortNumber || port > MaxPortNumber) {
throw IllegalArgumentException("Port has to be in range [$MinUdpPortNumber, $MaxPortNumber]")
}
var datagramSocket: DatagramSocket? = null
try {
datagramSocket = DatagramSocket(port)
datagramSocket.reuseAddress = true
return true
} catch (e: IOException) {
} finally {
try {
datagramSocket?.close()
} catch (ignored: Exception) { }
}
return false
}
}