Commit 31beb160 authored by Mygod's avatar Mygod

Implement RE2 builder

parent fd4d7f46
...@@ -36,8 +36,9 @@ class AclMatcher : AutoCloseable { ...@@ -36,8 +36,9 @@ class AclMatcher : AutoCloseable {
@JvmStatic private external fun init(): Long @JvmStatic private external fun init(): Long
@JvmStatic private external fun close(handle: Long) @JvmStatic private external fun close(handle: Long)
@JvmStatic private external fun addBypassDomain(handle: Long, regex: String): String? @JvmStatic private external fun addBypassDomain(handle: Long, regex: String): Boolean
@JvmStatic private external fun addProxyDomain(handle: Long, regex: String): String? @JvmStatic private external fun addProxyDomain(handle: Long, regex: String): Boolean
@JvmStatic private external fun build(handle: Long): String?
@JvmStatic private external fun matchHost(handle: Long, host: String): Int @JvmStatic private external fun matchHost(handle: Long, host: String): Int
} }
...@@ -71,10 +72,11 @@ class AclMatcher : AutoCloseable { ...@@ -71,10 +72,11 @@ class AclMatcher : AutoCloseable {
handle = init() handle = init()
val time = measureNanoTime { val time = measureNanoTime {
val (bypass, subnets) = Acl.parse(Acl.getFile(id).bufferedReader(), { val (bypass, subnets) = Acl.parse(Acl.getFile(id).bufferedReader(), {
addBypassDomain(handle, it)?.fail() check(addBypassDomain(handle, it))
}, { }, {
addProxyDomain(handle, it)?.fail() check(addProxyDomain(handle, it))
}) })
build(handle)
subnetsIpv4 = subnets.asSequence().filter { it.address is Inet4Address }.dedup() subnetsIpv4 = subnets.asSequence().filter { it.address is Inet4Address }.dedup()
subnetsIpv6 = subnets.asSequence().filter { it.address is Inet6Address }.dedup() subnetsIpv6 = subnets.asSequence().filter { it.address is Inet6Address }.dedup()
this.bypass = bypass this.bypass = bypass
......
#include <utility> #include <sstream>
#include <vector> #include <vector>
#include "jni.h" #include "jni.h"
...@@ -7,31 +7,22 @@ ...@@ -7,31 +7,22 @@
using namespace std; using namespace std;
struct AclMatcher { struct AclMatcher {
vector<RE2 *> bypassDomains, proxyDomains; stringstream bypassDomainsBuilder, proxyDomainsBuilder;
RE2 *bypassDomains, *proxyDomains;
~AclMatcher() { ~AclMatcher() {
for (RE2 *re2 : bypassDomains) delete re2; if (bypassDomains) delete bypassDomains;
for (RE2 *re2 : proxyDomains) delete re2; if (proxyDomains) delete proxyDomains;
} }
}; };
jstring addDomain(JNIEnv *env, vector<RE2 *> &domains, jstring regex) { bool addDomain(JNIEnv *env, stringstream &domains, jstring regex) {
const char *regexChars = env->GetStringUTFChars(regex, nullptr); const char *regexChars = env->GetStringUTFChars(regex, nullptr);
RE2 *re2 = new RE2(regexChars); if (regexChars == nullptr) return false;
if (domains.rdbuf()->in_avail()) domains << '|';
domains << regexChars;
env->ReleaseStringUTFChars(regex, regexChars); env->ReleaseStringUTFChars(regex, regexChars);
if (re2->ok()) { return true;
domains.push_back(re2);
return nullptr;
} else {
auto result = env->NewStringUTF(re2->error().c_str());
delete re2;
return result;
}
}
bool matches(const vector<RE2 *> &domains, const char *host) {
return any_of(domains.cbegin(), domains.cend(), [host](const RE2 *re){
return RE2::FullMatch(host, *re);
});
} }
#pragma clang diagnostic push #pragma clang diagnostic push
...@@ -46,18 +37,30 @@ Java_com_github_shadowsocks_acl_AclMatcher_close(JNIEnv *env, jclass clazz, jlon ...@@ -46,18 +37,30 @@ Java_com_github_shadowsocks_acl_AclMatcher_close(JNIEnv *env, jclass clazz, jlon
delete reinterpret_cast<AclMatcher *>(handle); delete reinterpret_cast<AclMatcher *>(handle);
} }
JNIEXPORT jstring JNICALL JNIEXPORT jboolean JNICALL
Java_com_github_shadowsocks_acl_AclMatcher_addBypassDomain(JNIEnv *env, jclass clazz, jlong handle, Java_com_github_shadowsocks_acl_AclMatcher_addBypassDomain(JNIEnv *env, jclass clazz, jlong handle,
jstring regex) { jstring regex) {
if (!handle) return env->NewStringUTF("AclMatcher closed"); return static_cast<jboolean>(handle &&
return ::addDomain(env, reinterpret_cast<AclMatcher *>(handle)->bypassDomains, regex); ::addDomain(env, reinterpret_cast<AclMatcher *>(handle)->bypassDomainsBuilder, regex));
} }
JNIEXPORT jstring JNICALL JNIEXPORT jboolean JNICALL
Java_com_github_shadowsocks_acl_AclMatcher_addProxyDomain(JNIEnv *env, jclass clazz, jlong handle, Java_com_github_shadowsocks_acl_AclMatcher_addProxyDomain(JNIEnv *env, jclass clazz, jlong handle,
jstring regex) { jstring regex) {
return static_cast<jboolean>(handle &&
::addDomain(env, reinterpret_cast<AclMatcher *>(handle)->proxyDomainsBuilder, regex));
}
JNIEXPORT jstring JNICALL
Java_com_github_shadowsocks_acl_AclMatcher_build(JNIEnv *env, jclass clazz, jlong handle) {
if (!handle) return env->NewStringUTF("AclMatcher closed"); if (!handle) return env->NewStringUTF("AclMatcher closed");
return ::addDomain(env, reinterpret_cast<AclMatcher *>(handle)->proxyDomains, regex); auto matcher = reinterpret_cast<AclMatcher *>(handle);
if (matcher->bypassDomains || matcher->proxyDomains) return env->NewStringUTF("already built");
matcher->bypassDomains = new RE2(matcher->bypassDomainsBuilder.str());
if (!matcher->bypassDomains->ok()) return env->NewStringUTF(matcher->bypassDomains->error().c_str());
matcher->proxyDomains = new RE2(matcher->proxyDomainsBuilder.str());
if (!matcher->proxyDomains->ok()) return env->NewStringUTF(matcher->proxyDomains->error().c_str());
return nullptr;
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
...@@ -67,8 +70,8 @@ Java_com_github_shadowsocks_acl_AclMatcher_matchHost(JNIEnv *env, jclass clazz, ...@@ -67,8 +70,8 @@ Java_com_github_shadowsocks_acl_AclMatcher_matchHost(JNIEnv *env, jclass clazz,
auto matcher = reinterpret_cast<const AclMatcher *>(handle); auto matcher = reinterpret_cast<const AclMatcher *>(handle);
const char *hostChars = env->GetStringUTFChars(host, nullptr); const char *hostChars = env->GetStringUTFChars(host, nullptr);
jint result = 0; jint result = 0;
if (::matches(matcher->bypassDomains, hostChars)) result = 1; if (RE2::FullMatch(hostChars, *matcher->bypassDomains)) result = 1;
else if (::matches(matcher->proxyDomains, hostChars)) result = 2; else if (RE2::FullMatch(hostChars, *matcher->proxyDomains)) result = 2;
env->ReleaseStringUTFChars(host, hostChars); env->ReleaseStringUTFChars(host, hostChars);
return result; return result;
} }
......
Markdown is supported
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