You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.3 KiB
127 lines
4.3 KiB
package tv.anypoint.proxy.util |
|
|
|
import jakarta.servlet.http.HttpServletRequest |
|
import kotlinx.coroutines.* |
|
import java.net.Inet4Address |
|
import java.net.InetAddress |
|
import java.net.NetworkInterface |
|
import java.util.* |
|
|
|
object NetworkUtil { |
|
fun getPrivateIpV4(setTopBoxAddress: InetAddress): String = getPrivateIpV4List() |
|
.chooseSimilarIp(setTopBoxAddress)?.hostAddress |
|
?: throw RuntimeException("셋톱과 공유하는 private IP가 없습니다") |
|
|
|
/** |
|
* Gives the private IP of this device |
|
* @return The private IP |
|
*/ |
|
fun getPrivateIpV4List(): List<InetAddress> { |
|
val result = mutableListOf<InetAddress>() |
|
NetworkInterface.getNetworkInterfaces().forEach { n -> |
|
result += n.inetAddresses.filter { it is Inet4Address && it.isSiteLocalAddress } |
|
} |
|
return result |
|
} |
|
|
|
/** |
|
* Gives the list of all open IPs of the private network |
|
* in which this device is connected to. |
|
* |
|
* For the time saving, this method performs multithreaded |
|
* ping test for 5 seconds in each thread, excluding |
|
* 192.168.0.1 and this device's private IP. |
|
* |
|
* @return List of all open IPs as [InetAddress] |
|
*/ |
|
fun findAllOpenPrivateIps(skipSelf: Boolean = false) = runBlocking { |
|
val todos = mutableListOf<Deferred<Unit?>>() |
|
val privateIpList = getPrivateIpV4List() |
|
val available2dArray = Array(privateIpList.size) { arrayOfNulls<InetAddress>(256) } |
|
|
|
privateIpList.forEachIndexed { i, inetAddress -> |
|
todos += Inet4Iterator(inetAddress, skipSelf) |
|
.map { |
|
async(Dispatchers.IO) { |
|
if (it.second.isReachable(1000)) available2dArray[i][it.first] = it.second else null |
|
} |
|
} |
|
} |
|
|
|
todos.awaitAll() |
|
return@runBlocking available2dArray.flatten().filterNotNull() |
|
} |
|
|
|
/** |
|
* The iterator that iterates all near IPs from the given [originalIp] |
|
* |
|
* If the given IP is a.b.c.d, then it will iterate from |
|
* a.b.c.2 to a.b.c.255, when start=2 and [end]=255 (default) |
|
*/ |
|
class Inet4Iterator( |
|
private val originalIp: InetAddress, |
|
private val skipOriginal: Boolean = true, |
|
start: UInt = 2u, |
|
private val end: UInt = 255u |
|
) : Iterator<Pair<Int, InetAddress>>, Iterable<Pair<Int, InetAddress>> { |
|
|
|
private val a: UByte |
|
private val b: UByte |
|
private val c: UByte |
|
private val skip: UByte |
|
private var d = start |
|
|
|
init { |
|
val addressBytes = originalIp.address |
|
a = addressBytes[0].toUByte() |
|
b = addressBytes[1].toUByte() |
|
c = addressBytes[2].toUByte() |
|
skip = addressBytes[3].toUByte() |
|
} |
|
|
|
override fun hasNext(): Boolean { |
|
return if (skipOriginal && skip == 0xFFu.toUByte()) d < end else d < (end + 1u) |
|
} |
|
|
|
override fun next(): Pair<Int, InetAddress> { |
|
val result = Pair(d.toInt(), Inet4Util.fromIpClasses(a, b, c, d.toUByte())) |
|
d += if (d == skip - 1u) 2u else 1u |
|
return result |
|
} |
|
|
|
override fun iterator() = this |
|
} |
|
|
|
object Inet4Util { |
|
fun fromIpClasses(a: UByte, b: UByte, c: UByte, d: UByte): InetAddress { |
|
return Inet4Address.getByName("$a.$b.$c.$d") |
|
} |
|
} |
|
|
|
fun InetAddress.getIpClassSimilarity(other: InetAddress): Int { |
|
if (this::class != other::class) return 0 |
|
val ipClasses = this.address |
|
val otherIpClasses = other.address |
|
|
|
for (i in 0 until ipClasses.size.coerceAtMost(otherIpClasses.size)) { |
|
if (ipClasses[i] != otherIpClasses[i]) return i |
|
} |
|
return ipClasses.size |
|
} |
|
|
|
fun List<InetAddress>.chooseSimilarIp(other: InetAddress) = this.maxByOrNull { it.getIpClassSimilarity(other) } |
|
|
|
fun <T> Enumeration<T>.forEach(block: (T) -> Unit) { |
|
for (i in this) block(i) |
|
} |
|
|
|
fun <T> Enumeration<T>.filter(block: (T) -> Boolean): List<T> { |
|
val result = mutableListOf<T>() |
|
for (i in this) if (block(i)) result += i |
|
return result |
|
} |
|
} |
|
|
|
fun HttpServletRequest.getIpAddressString(): String = this.getHeader("X-FORWARDED-FOR") ?: this.remoteAddr |
|
|
|
fun HttpServletRequest.getIpAddress(): InetAddress = InetAddress.getByName(this.getIpAddressString())
|
|
|