Speed up Acl.fromReader
It should run 9x faster than before now. Past mistakes: * InetAddress.parseNumericAddress throws TWO exceptions underthehood if the string passed is invalid. This caused a huge overhead; * CharSequence.split in Kotlin is EXTREMELY SLOW.
This commit is contained in:
@@ -116,7 +116,8 @@ class Acl {
|
||||
var subnets: SortedList<Subnet>? = if (defaultBypass) proxySubnets else bypassSubnets
|
||||
reader.useLines {
|
||||
for (line in it) {
|
||||
val blocks = line.split('#', limit = 2)
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
val blocks = (line as java.lang.String).split("#", 2)
|
||||
val url = networkAclParser.matchEntire(blocks.getOrElse(1, {""}))?.groupValues?.getOrNull(1)
|
||||
if (url != null) urls.add(URL(url))
|
||||
val input = blocks[0].trim()
|
||||
@@ -135,10 +136,9 @@ class Acl {
|
||||
}
|
||||
"[reject_all]", "[bypass_all]" -> bypass = true
|
||||
"[accept_all]", "[proxy_all]" -> bypass = false
|
||||
else -> if (subnets != null && input.isNotEmpty()) try {
|
||||
subnets!!.add(Subnet.fromString(input))
|
||||
} catch (_: IllegalArgumentException) {
|
||||
hostnames!!.add(input)
|
||||
else -> if (subnets != null && input.isNotEmpty()) {
|
||||
val subnet = Subnet.fromString(input)
|
||||
if (subnet == null) hostnames!!.add(input) else subnets!!.add(subnet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,8 +333,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (savedInstanceState != null) {
|
||||
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_SUBNETS)?.map(Subnet.Companion::fromString)
|
||||
?: listOf())
|
||||
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_SUBNETS)
|
||||
?.mapNotNull(Subnet.Companion::fromString) ?: listOf())
|
||||
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_HOSTNAMES)
|
||||
?: arrayOf())
|
||||
selectedItems.addAll(savedInstanceState.getStringArray(SELECTED_URLS)?.map { URL(it) }
|
||||
|
||||
@@ -159,10 +159,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
Acl.ALL, Acl.BYPASS_CHN, Acl.CUSTOM_RULES -> builder.addRoute("0.0.0.0", 0)
|
||||
else -> {
|
||||
resources.getStringArray(R.array.bypass_private_route).forEach {
|
||||
val subnet = Subnet.fromString(it)
|
||||
val subnet = Subnet.fromString(it)!!
|
||||
builder.addRoute(subnet.address.hostAddress, subnet.prefixSize)
|
||||
}
|
||||
profile.remoteDns.split(",").map { it.trim().parseNumericAddress() }
|
||||
profile.remoteDns.split(",").mapNotNull { it.trim().parseNumericAddress() }
|
||||
.forEach { builder.addRoute(it, it.address.size shl 3) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@ import java.util.*
|
||||
|
||||
class Subnet(val address: InetAddress, val prefixSize: Int) : Comparable<Subnet> {
|
||||
companion object {
|
||||
@Throws(IllegalArgumentException::class)
|
||||
fun fromString(value: String): Subnet {
|
||||
val parts = value.split('/')
|
||||
val addr = parts[0].parseNumericAddress()
|
||||
return when (parts.size) {
|
||||
1 -> Subnet(addr, addr.address.size shl 3)
|
||||
2 -> Subnet(addr, parts[1].toInt())
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
fun fromString(value: String): Subnet? {
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
val parts = (value as java.lang.String).split("/", 2)
|
||||
val addr = parts[0].parseNumericAddress() ?: return null
|
||||
return if (parts.size == 2) try {
|
||||
Subnet(addr, parts[1].toInt())
|
||||
} catch (_: NumberFormatException) {
|
||||
null
|
||||
} else Subnet(addr, addr.address.size shl 3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,31 +11,20 @@ import android.support.v4.app.FragmentManager
|
||||
import android.support.v7.util.SortedList
|
||||
import android.util.TypedValue
|
||||
import com.github.shadowsocks.App.Companion.app
|
||||
import com.github.shadowsocks.JniHelper
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.net.Inet4Address
|
||||
import java.net.InetAddress
|
||||
import java.net.URLConnection
|
||||
|
||||
private val isNumericMethod by lazy { InetAddress::class.java.getMethod("isNumeric", String::class.java) }
|
||||
private val parseNumericAddressMethod by lazy {
|
||||
try {
|
||||
InetAddress::class.java.getMethod("parseNumericAddress", String::class.java)
|
||||
} catch (_: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
private val fieldChildFragmentManager by lazy {
|
||||
val field = Fragment::class.java.getDeclaredField("mChildFragmentManager")
|
||||
field.isAccessible = true
|
||||
field
|
||||
}
|
||||
|
||||
fun String.isNumericAddress(): Boolean = isNumericMethod.invoke(null, this) as Boolean
|
||||
fun String.parseNumericAddress(): InetAddress =
|
||||
if (parseNumericAddressMethod == null) InetAddress.getByName(this) else try {
|
||||
parseNumericAddressMethod!!.invoke(null, this) as InetAddress
|
||||
} catch (exc: InvocationTargetException) {
|
||||
throw exc.cause ?: exc
|
||||
}
|
||||
fun String.isNumericAddress() = parseNumericAddress() != null
|
||||
fun String.parseNumericAddress() = JniHelper.parseNumericAddress(this)
|
||||
|
||||
fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
|
||||
val x = str?.toIntOrNull() ?: default
|
||||
|
||||
Reference in New Issue
Block a user