diff --git a/build.gradle.kts b/build.gradle.kts index 283dcfc..78061fd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -80,6 +80,35 @@ licensing { url("http://archive.apache.org/dist/harmony/") note("This product contains a modified portion of 'Apache Harmony', an open source Java SE") } + extra("Apache HTTP Utils", License.APACHE_2) { + copyright(2010) + author("The Apache Software Foundation") + url("http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient5/src/main/java/org/apache/hc/client5/http/psl/") + note("This product contains a modified portion of 'PublicSuffixDomainFilter.java'") + } + } +} + +//kotlin { +// sourceSets { +// main { +// resources.apply { +// srcDirs("dorkbox/netUtil/dnsUtils/effective_tld_names.dat") +// } +// } +// } +//} + +sourceSets { + main { + java { + resources { + setSrcDirs(listOf("src")) + include( + "dorkbox/netUtil/dnsUtils/effective_tld_names.dat" + ) + } + } } } @@ -110,7 +139,6 @@ dependencies { testImplementation("junit:junit:4.13.2") testImplementation("ch.qos.logback:logback-classic:1.3.0-alpha4") - testImplementation("com.dorkbox:Utilities:1.25") } publishToSonatype { diff --git a/src/dorkbox/netUtil/IP.kt b/src/dorkbox/netUtil/IP.kt index 6675d5a..60c35f8 100644 --- a/src/dorkbox/netUtil/IP.kt +++ b/src/dorkbox/netUtil/IP.kt @@ -221,7 +221,7 @@ object IP { return it.localAddress } }.onFailure { - Common.logger.error("Unable to determine outbound traffic local address. Using alternate logic instead.", it) + logger.error("Unable to determine outbound traffic local address. Using alternate logic instead.", it) } // there was an error doing this! (it's possible that outbound traffic is not allowed diff --git a/src/dorkbox/netUtil/ping/Ping.kt b/src/dorkbox/netUtil/ping/Ping.kt index dda87de..eb6900e 100644 --- a/src/dorkbox/netUtil/ping/Ping.kt +++ b/src/dorkbox/netUtil/ping/Ping.kt @@ -18,40 +18,74 @@ package dorkbox.netUtil.ping import dorkbox.executor.Executor import dorkbox.netUtil.Common +import dorkbox.netUtil.IP import org.slf4j.LoggerFactory import java.io.IOException +import java.net.InetAddress import java.time.Duration /** * */ -class Ping { - companion object { - private val logger = LoggerFactory.getLogger(Ping::class.java.simpleName) +object Ping { + private val logger = LoggerFactory.getLogger(Ping::class.java.simpleName) - /** - * Gets the version number. - */ - const val version = Common.version + /** + * Gets the version number. + */ + const val version = Common.version + + private var host = "1.1.1.1" + private var count = 4 + private var waitTime = Duration.ofSeconds(4) + private var deadline: Int? = null + private var ttl: Short? = null + + fun host(host: String): Ping { + this.host = host + return this + } + + fun host(ipAddress: InetAddress): Ping { + this.host = IP.toString(ipAddress) + return this + } + + fun host(ipAddressBytes: ByteArray): Ping { + this.host = IP.toString(ipAddressBytes) + return this + } + + fun count(count: Int): Ping { + this.count = count + return this + } + + fun waitTime(seconds: Int): Ping { + this.waitTime = Duration.ofSeconds(seconds.toLong()) + return this + } + + fun deadline(seconds: Int): Ping { + this.deadline = seconds + return this + } + + fun ttl(ttl: Int): Ping { + this.ttl = ttl.toShort() + return this } - private val count = 4 - private val host = "1.1.1.1" - private val waitTime = Duration.ofSeconds(4) - private val deadline: Duration? = null - private val ttl: Short? = null @Throws(IOException::class) - fun run(): PingResult { + fun run(host: String = "1.1.1.1"): PingResult { val ping = Executor() .command("ping") if (Common.OS_WINDOWS) { - ping.addArg("-n") - ping.addArg("$count") + ping.addArg("-n $count") } else { - ping.addArg("-q") ping.addArg("-c $count") } @@ -72,13 +106,13 @@ class Ping { if (deadline != null) { when { Common.OS_MAC -> { - ping.addArg("-t " + deadline.seconds) + ping.addArg("-t $deadline") } Common.OS_WINDOWS -> { logger.info("Deadline is not supported on Windows") } else -> { - ping.addArg("-w " + deadline.seconds) + ping.addArg("-w $deadline") } } } @@ -96,7 +130,8 @@ class Ping { } } } -// ping.command("ping $host") + + ping.addArg(host) // wait for it to finish running val output: String = ping.enableRead().startAsShellBlocking().output.utf8() diff --git a/src/dorkbox/netUtil/ping/PingResult.kt b/src/dorkbox/netUtil/ping/PingResult.kt index 976c7fc..bfb1cad 100644 --- a/src/dorkbox/netUtil/ping/PingResult.kt +++ b/src/dorkbox/netUtil/ping/PingResult.kt @@ -17,12 +17,11 @@ package dorkbox.netUtil.ping import java.time.Duration -import java.util.* class PingResult { var host: String? = null var ip: String? = null - var responses: MutableList = LinkedList() + val responses= arrayListOf() var transmittedPackets = 0 var receivedPackets = 0 var packetLoss = 0.0 @@ -32,13 +31,13 @@ class PingResult { var maxRoundTripTime: Duration? = null var mdevRoundTripTime: Duration? = null - class Response(val bytes: Int, + data class Response(val bytes: Int, val host: String, val icmpSeq: Int, val ttl: Int, val time: Duration) override fun toString(): String { - return "PingResult(host=$host, ip=$ip, responses=$responses, transmittedPackets=$transmittedPackets, receivedPackets=$receivedPackets, packetLoss=$packetLoss, time=$time, minRoundTripTime=$minRoundTripTime, avgRoundTripTime=$avgRoundTripTime, maxRoundTripTime=$maxRoundTripTime, mdevRoundTripTime=$mdevRoundTripTime)" + return "PingResult(host=$host, ip=$ip, responses=$responses, transmittedPackets=$transmittedPackets, receivedPackets=$receivedPackets, packetLoss=$packetLoss%, time=$time, minRoundTripTime=$minRoundTripTime, avgRoundTripTime=$avgRoundTripTime, maxRoundTripTime=$maxRoundTripTime, mdevRoundTripTime=$mdevRoundTripTime)" } } diff --git a/src/dorkbox/netUtil/ping/PingResultBuilder.kt b/src/dorkbox/netUtil/ping/PingResultBuilder.kt index be39296..b90d1dc 100644 --- a/src/dorkbox/netUtil/ping/PingResultBuilder.kt +++ b/src/dorkbox/netUtil/ping/PingResultBuilder.kt @@ -19,7 +19,6 @@ package dorkbox.netUtil.ping import dorkbox.netUtil.Common import dorkbox.netUtil.IP import java.time.Duration -import java.time.temporal.ChronoUnit import java.util.regex.* internal object PingResultBuilder { @@ -30,10 +29,10 @@ internal object PingResultBuilder { val maxRTT = matcher.group(3).toDouble() val mdevRTT = matcher.group(4).toDouble() - result.minRoundTripTime = Duration.ofNanos((1000 * 1000 * minRTT).toLong()) - result.avgRoundTripTime = Duration.ofNanos((1000 * 1000 * avgRTT).toLong()) - result.maxRoundTripTime = Duration.ofNanos((1000 * 1000 * maxRTT).toLong()) - result.mdevRoundTripTime = Duration.ofNanos((1000 * 1000 * mdevRTT).toLong()) + result.minRoundTripTime = Duration.ofMillis(minRTT.toLong()) + result.avgRoundTripTime = Duration.ofMillis(avgRTT.toLong()) + result.maxRoundTripTime = Duration.ofMillis(maxRTT.toLong()) + result.mdevRoundTripTime = Duration.ofMillis(mdevRTT.toLong()) result } @@ -44,6 +43,11 @@ internal object PingResultBuilder { Common.OS_MAC -> { listOf( /* BSD Ping (MacOS) */ + ResultParser.of("PING (.*) \\((.*?)\\): (.*) data bytes") { result, matcher -> + result.host = IP.lanAddress().hostAddress // note: this is REALLY the host used for lan traffic + result.ip = matcher.group(1) + result + }, ResultParser.of("(.*) packets transmitted, (.*) packets received, (.*)% packet loss") { result, matcher -> val transmittedPackets: Int = matcher.group(1).toInt() result.transmittedPackets = transmittedPackets @@ -96,7 +100,7 @@ internal object PingResultBuilder { val host: String = matcher.group(2) val icmpSeq: Int = matcher.group(3).toInt() val ttl: Int = matcher.group(4).toInt() - val time = Duration.ofNanos(1000 * 1000 * matcher.group(5).toLong()) + val time = Duration.ofMillis(matcher.group(5).toLong()) val response = PingResult.Response(bytes, host, icmpSeq, ttl, time) result.responses.add(response) @@ -122,7 +126,7 @@ internal object PingResultBuilder { val packetLoss: Double = 0.01 * Integer.valueOf(matcher.group(3)) result.packetLoss = packetLoss - val time = Duration.of(matcher.group(4).toLong(), ChronoUnit.MILLIS) + val time = Duration.ofMillis(matcher.group(4).toLong()) result.time = time result diff --git a/test/dorkbox/netUtil/IpValidationTests.kt b/test/dorkbox/netUtil/IpValidationTests.kt index 1c75fff..2140ed0 100644 --- a/test/dorkbox/netUtil/IpValidationTests.kt +++ b/test/dorkbox/netUtil/IpValidationTests.kt @@ -15,7 +15,7 @@ */ package dorkbox.netUtil -import dorkbox.util.Sys +import dorkbox.netUtil.ping.Ping import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -572,15 +572,36 @@ class IpValidationTests { private fun assertHexDumpEquals(expected: String?, actual: ByteArray?, message: String) { - assertEquals(message, expected, if (actual == null) null else hex(actual)) + assertEquals(message, expected, actual?.toHex()) } - private fun hex(byteArray: ByteArray): String { - return Sys.bytesToHex(byteArray).toLowerCase() + private val hexChars = "0123456789abcdef".toCharArray() + private fun ByteArray.toHex(): String { + val hex = CharArray(2 * this.size) + this.forEachIndexed { i, byte -> + val unsigned = 0xff and byte.toInt() + hex[2 * i] = hexChars[unsigned / 16] + hex[2 * i + 1] = hexChars[unsigned % 16] + } + + return hex.joinToString("") } - private fun unhex(value: String?): ByteArray? { - return if (value != null) Sys.hexToBytes(value) else null + private fun String.decodeHex(): ByteArray { + check(length % 2 == 0) { "Must have an even length" } + + val bytes = ByteArray(length / 2) + + var i = 0 + while (i < length) { + // using left shift operator on every character + val a = Character.digit(this[i], 16) shl 4 + val b = Character.digit(this[i+1], 16) + bytes[i / 2] = (a + b).toByte() + i += 2 + } + + return bytes } } @@ -702,7 +723,7 @@ class IpValidationTests { @Throws(UnknownHostException::class) fun testIp4AddressToString() { for ((key, value) in validIpV4Hosts) { - assertEquals(key, IP.toString(InetAddress.getByAddress(unhex(value)))) + assertEquals(key, IP.toString(InetAddress.getByAddress(value.decodeHex()))) } } @@ -737,15 +758,14 @@ class IpValidationTests { @Throws(UnknownHostException::class) fun testIp4SocketAddressToString() { for ((key, value) in validIpV4Hosts) { - assertEquals("$key:9999", IP.toString(InetSocketAddress(InetAddress.getByAddress(unhex(value)), 9999))) + assertEquals("$key:9999", IP.toString(InetSocketAddress(InetAddress.getByAddress(value.decodeHex()), 9999))) } } -// -// @Test -// fun testPing() { -// println(Ping().run()) -//// println(Executor().command("ping 1.1.1.1").readOutput().startAsShellBlocking().output.utf8()) -// } + + @Test + fun testPing() { + println(Ping.host("1.1.1.1").run()) + } @Test