Commit a4e61044 authored by Daniel Wolf's avatar Daniel Wolf
Browse files

Only create cronet engine for https tests, properly close connections in...

Only create cronet engine for https tests, properly close connections in tests, pass in reusable cronet engine for https tests
parent b9cb3438
...@@ -195,7 +195,8 @@ class SpeedTestActivity : BaseActivity() { ...@@ -195,7 +195,8 @@ class SpeedTestActivity : BaseActivity() {
if(wasStartedBefore) prepareList() if(wasStartedBefore) prepareList()
testJob = launchWithLifecycle { testJob = launchWithLifecycle {
prepareListJob?.join() prepareListJob?.join()
val engine = createQuicCronetEngineIfInstalled(this@SpeedTestActivity) val engine = if(BuildConfig.SHOW_DOQ) createQuicCronetEngineIfInstalled(this@SpeedTestActivity) else null
val httpsEngine = createHttpCronetEngineIfInstalled(this@SpeedTestActivity)
testRunning = true testRunning = true
wasStartedBefore = true wasStartedBefore = true
val testsLeft = testResults!!.shuffled() val testsLeft = testResults!!.shuffled()
...@@ -208,7 +209,7 @@ class SpeedTestActivity : BaseActivity() { ...@@ -208,7 +209,7 @@ class SpeedTestActivity : BaseActivity() {
if(testJob?.isCancelled == false) { if(testJob?.isCancelled == false) {
pendingTest.started = true pendingTest.started = true
log("Running SpeedTest for ${pendingTest.server.name}") log("Running SpeedTest for ${pendingTest.server.name}")
val res = DnsSpeedTest(this@SpeedTestActivity, pendingTest.server, highestLatency, highestLatency+250, engine) { line -> val res = DnsSpeedTest(this@SpeedTestActivity, pendingTest.server, highestLatency, highestLatency+250, engine, httpsEngine) { line ->
log(line) log(line)
}.runTest(passes) }.runTest(passes)
...@@ -226,7 +227,7 @@ class SpeedTestActivity : BaseActivity() { ...@@ -226,7 +227,7 @@ class SpeedTestActivity : BaseActivity() {
} }
} }
} }
httpsEngine?.shutdown()
if(testJob?.isCancelled == false)runOnUiThread { if(testJob?.isCancelled == false)runOnUiThread {
startTest.isEnabled = true startTest.isEnabled = true
abort.visibility = View.GONE abort.visibility = View.GONE
......
...@@ -376,6 +376,7 @@ class MainFragment : Fragment() { ...@@ -376,6 +376,7 @@ class MainFragment : Fragment() {
// And in that case the smaller server should be measured on the bigger ones to have a point of reference // And in that case the smaller server should be measured on the bigger ones to have a point of reference
// as the values I chose are between average to best-case, not worst-case. // as the values I chose are between average to best-case, not worst-case.
launchWithLifecycle { launchWithLifecycle {
val httpsEngine = createHttpCronetEngineIfInstalled(context)
val fastServerAverage = (AbstractHttpsDNSHandle.suspendUntilKnownServersArePopulated( val fastServerAverage = (AbstractHttpsDNSHandle.suspendUntilKnownServersArePopulated(
1500 1500
) { ) {
...@@ -383,11 +384,19 @@ class MainFragment : Fragment() { ...@@ -383,11 +384,19 @@ class MainFragment : Fragment() {
} + AbstractTLSDnsHandle.suspendUntilKnownServersArePopulated(1500) { } + AbstractTLSDnsHandle.suspendUntilKnownServersArePopulated(1500) {
setOf(it[1], it[0]) //Quad9, CF setOf(it[1], it[0]) //Quad9, CF
}).mapNotNull { }).mapNotNull {
DnsSpeedTest(context, it as DnsServerInformation<*>, log = {}, cronetEngine = null /* We do not need quic here*/ ).runTest(4) DnsSpeedTest(
context,
it as DnsServerInformation<*>,
log = {},
cronetEngine = null, /* We do not need quic here*/
httpsCronetEngine = httpsEngine
).runTest(4)
}.takeIf { }.takeIf {
it.isNotEmpty() it.isNotEmpty()
}?.let { }?.let {
it.sum() / it.size it.sum() / it.size
}.also {
httpsEngine?.shutdown()
} ?: return@launchWithLifecycle } ?: return@launchWithLifecycle
val rawFactor = maxOf( val rawFactor = maxOf(
greatLatencyThreshold.toDouble(), greatLatencyThreshold.toDouble(),
......
...@@ -12,13 +12,10 @@ import com.frostnerd.encrypteddnstunnelproxy.tls.TLSUpstreamAddress ...@@ -12,13 +12,10 @@ import com.frostnerd.encrypteddnstunnelproxy.tls.TLSUpstreamAddress
import com.frostnerd.smokescreen.createHttpCronetEngineIfInstalled import com.frostnerd.smokescreen.createHttpCronetEngineIfInstalled
import com.frostnerd.smokescreen.type import com.frostnerd.smokescreen.type
import com.frostnerd.smokescreen.util.ServerType import com.frostnerd.smokescreen.util.ServerType
import okhttp3.Dns import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.chromium.net.CronetEngine import org.chromium.net.CronetEngine
import org.minidns.dnsmessage.DnsMessage import org.minidns.dnsmessage.DnsMessage
import org.minidns.dnsmessage.Question import org.minidns.dnsmessage.Question
...@@ -54,20 +51,23 @@ class DnsSpeedTest(context:Context, ...@@ -54,20 +51,23 @@ class DnsSpeedTest(context:Context,
private val connectTimeout: Int = 2500, private val connectTimeout: Int = 2500,
private val readTimeout:Int = 1500, private val readTimeout:Int = 1500,
private val cronetEngine: CronetEngine?, private val cronetEngine: CronetEngine?,
httpsCronetEngine: CronetEngine? = null,
val log:(line:String) -> Unit) { val log:(line:String) -> Unit) {
private val httpClient by lazy { private val httpClient by lazy(LazyThreadSafetyMode.NONE) {
OkHttpClient.Builder() OkHttpClient.Builder()
.dns(httpsDnsClient) .dns(httpsDnsClient)
.connectTimeout(3, TimeUnit.SECONDS) .connectTimeout(3, TimeUnit.SECONDS)
.readTimeout(readTimeout.toLong(), TimeUnit.MILLISECONDS) .readTimeout(readTimeout.toLong(), TimeUnit.MILLISECONDS)
.build() .build()
} }
private val httpsDnsClient by lazy { private val httpsDnsClient by lazy(LazyThreadSafetyMode.NONE) {
PinnedDns((server as HttpsDnsServerInformation).serverConfigurations.values.map { PinnedDns((server as HttpsDnsServerInformation).serverConfigurations.values.map {
it.urlCreator.address it.urlCreator.address
}) })
} }
private val httpsCronetEngine = createHttpCronetEngineIfInstalled(context) private val _httpsCronetEngine by lazy(LazyThreadSafetyMode.NONE) {
httpsCronetEngine ?: createHttpCronetEngineIfInstalled(context)
}
companion object { companion object {
val testDomains = listOf("google.com", "frostnerd.com", "amazon.com", "youtube.com", "github.com", val testDomains = listOf("google.com", "frostnerd.com", "amazon.com", "youtube.com", "github.com",
...@@ -79,7 +79,6 @@ class DnsSpeedTest(context:Context, ...@@ -79,7 +79,6 @@ class DnsSpeedTest(context:Context,
* @return The average response time (in ms) * @return The average response time (in ms)
*/ */
fun runTest(@IntRange(from = 1) passes: Int, strategy: Strategy = Strategy.AVERAGE): Int? { fun runTest(@IntRange(from = 1) passes: Int, strategy: Strategy = Strategy.AVERAGE): Int? {
log("Running with cronet: ${httpsCronetEngine != null}. Testing DoQ: ${cronetEngine != null}")
val latencies = mutableListOf<Int>() val latencies = mutableListOf<Int>()
var firstPass = true var firstPass = true
...@@ -95,7 +94,7 @@ class DnsSpeedTest(context:Context, ...@@ -95,7 +94,7 @@ class DnsSpeedTest(context:Context,
ServerType.DOH -> { ServerType.DOH -> {
server as HttpsDnsServerInformation server as HttpsDnsServerInformation
server.serverConfigurations.values.forEach { server.serverConfigurations.values.forEach {
latencies += if(httpsCronetEngine == null) { latencies += if(_httpsCronetEngine == null) {
if(firstPass) testHttps(it) if(firstPass) testHttps(it)
testHttps(it) ?: 0 testHttps(it) ?: 0
} else { } else {
...@@ -117,6 +116,9 @@ class DnsSpeedTest(context:Context, ...@@ -117,6 +116,9 @@ class DnsSpeedTest(context:Context,
} }
firstPass = false firstPass = false
} }
if(server.type == ServerType.DOH) {
if(_httpsCronetEngine == null) httpClient.connectionPool.evictAll()
}
return when (strategy) { return when (strategy) {
Strategy.BEST_CASE -> { Strategy.BEST_CASE -> {
latencies.minByOrNull { latencies.minByOrNull {
...@@ -208,8 +210,10 @@ class DnsSpeedTest(context:Context, ...@@ -208,8 +210,10 @@ class DnsSpeedTest(context:Context,
return null return null
} }
var connection:HttpURLConnection? = null
var wasEstablished = false
try { try {
val connection = httpsCronetEngine!!.openConnection(url) as HttpURLConnection connection = _httpsCronetEngine!!.openConnection(url) as HttpURLConnection
connection.connectTimeout = connectTimeout connection.connectTimeout = connectTimeout
if(config.requestHasBody) { if(config.requestHasBody) {
val body = config.bodyCreator?.createBody(msg, config.urlCreator.address) ?: return null val body = config.bodyCreator?.createBody(msg, config.urlCreator.address) ?: return null
...@@ -218,11 +222,13 @@ class DnsSpeedTest(context:Context, ...@@ -218,11 +222,13 @@ class DnsSpeedTest(context:Context,
connection.doOutput = true connection.doOutput = true
body.mediaType?.also {connection.setRequestProperty("Accept", it) } body.mediaType?.also {connection.setRequestProperty("Accept", it) }
connection.readTimeout = (connectTimeout*1.5).toInt() connection.readTimeout = (connectTimeout*1.5).toInt()
wasEstablished = true
val outputStream = connection.outputStream val outputStream = connection.outputStream
outputStream.write(body.rawBody) outputStream.write(body.rawBody)
outputStream.flush() outputStream.flush()
} else { } else {
connection.requestMethod = "GET" connection.requestMethod = "GET"
wasEstablished = true
connection.connect() connection.connect()
} }
val status = connection.responseCode val status = connection.responseCode
...@@ -240,6 +246,12 @@ class DnsSpeedTest(context:Context, ...@@ -240,6 +246,12 @@ class DnsSpeedTest(context:Context,
} }
} catch (ex:Throwable) { } catch (ex:Throwable) {
return null return null
} finally {
connection?.disconnect()
if(wasEstablished) {
connection?.inputStream?.closeSilently()
connection?.outputStream?.closeSilently()
}
} }
} }
...@@ -250,6 +262,7 @@ class DnsSpeedTest(context:Context, ...@@ -250,6 +262,7 @@ class DnsSpeedTest(context:Context,
return null return null
} }
var socket:Socket? = null var socket:Socket? = null
var outputStream:DataOutputStream? = null
try { try {
socket = SSLSocketFactory.getDefault().createSocket() socket = SSLSocketFactory.getDefault().createSocket()
val msg = createTestDnsPacket() val msg = createTestDnsPacket()
...@@ -257,7 +270,7 @@ class DnsSpeedTest(context:Context, ...@@ -257,7 +270,7 @@ class DnsSpeedTest(context:Context,
socket!!.connect(InetSocketAddress(addr[0], address.port), connectTimeout) socket!!.connect(InetSocketAddress(addr[0], address.port), connectTimeout)
socket.soTimeout = readTimeout socket.soTimeout = readTimeout
val data: ByteArray = msg.toArray() val data: ByteArray = msg.toArray()
val outputStream = DataOutputStream(socket.getOutputStream()) outputStream = DataOutputStream(socket.getOutputStream())
val size = data.size val size = data.size
val arr: ByteArray = byteArrayOf(((size shr 8) and 0xFF).toByte(), (size and 0xFF).toByte()) val arr: ByteArray = byteArrayOf(((size shr 8) and 0xFF).toByte(), (size and 0xFF).toByte())
outputStream.write(arr) outputStream.write(arr)
...@@ -269,7 +282,6 @@ class DnsSpeedTest(context:Context, ...@@ -269,7 +282,6 @@ class DnsSpeedTest(context:Context,
inStream.read(readData) inStream.read(readData)
val time = (System.currentTimeMillis() - start).toInt() val time = (System.currentTimeMillis() - start).toInt()
socket = null
if(!testResponse(DnsMessage(readData))) { if(!testResponse(DnsMessage(readData))) {
log("DoT test failed once for ${server.name}: Testing the response for valid dns message failed") log("DoT test failed once for ${server.name}: Testing the response for valid dns message failed")
return null return null
...@@ -318,9 +330,11 @@ class DnsSpeedTest(context:Context, ...@@ -318,9 +330,11 @@ class DnsSpeedTest(context:Context,
} catch (ex: java.lang.Exception) { } catch (ex: java.lang.Exception) {
return null return null
} finally { } finally {
if(wasEstablished) try { connection?.disconnect()
if(wasEstablished) {
connection?.outputStream?.closeSilently()
connection?.inputStream?.closeSilently() connection?.inputStream?.closeSilently()
} catch (ignored:Throwable) {} }
} }
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment