refactor clash bridge

This commit is contained in:
Kr328 committed 2020-06-10 21:24:38 +08:00
1 parent f6263940f1
commit 123bf65c55
18 files changed
+465 -202

No files matched your search

+3 -2
View File
@@ -1,10 +1,11 @@
cmake_minimum_required(VERSION 3.0)
project(clash_bridge)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 11)
include_directories(${CLASH_OUTPUT}/${ANDROID_ABI} ${CLASH_SOURCE})
link_directories(${CLASH_OUTPUT}/${CMAKE_ANDROID_ARCH_ABI})
link_libraries(log clash)
add_library(bridge SHARED bridge.c)
add_library(bridge SHARED main.cpp main.h init.cpp query.cpp patch.cpp)
-159
View File
@@ -1,159 +0,0 @@
#include <jni.h>
#include <stddef.h>
#include <string.h>
#include <malloc.h>
#include "libclash.h"
jclass cClashException;
jclass cTraffic;
jclass cGeneral;
jmethodID cTrafficConstructor;
jmethodID cGeneralConstructor;
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_initialize(JNIEnv *env, jclass clazz,
jbyteArray database,
jstring home,
jstring version) {
buffer_t databaseBuffer = {
.buffer = (*env)->GetByteArrayElements(env, database, NULL),
.length = (*env)->GetArrayLength(env, database)
};
const_string_t homeString = (*env)->GetStringUTFChars(env, home, NULL);
const_string_t versionString = (*env)->GetStringUTFChars(env, version, NULL);
initialize(&databaseBuffer, homeString, versionString);
(*env)->ReleaseByteArrayElements(env, database, databaseBuffer.buffer, databaseBuffer.length);
(*env)->ReleaseStringUTFChars(env, home, homeString);
(*env)->ReleaseStringUTFChars(env, version, versionString);
}
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_reset(JNIEnv *env, jclass clazz) {
reset();
}
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_queryGeneral(JNIEnv *env, jclass clazz) {
general_t general;
queryGeneral(&general);
const char *mode = "";
switch (general.mode) {
case MODE_DIRECT:
mode = "Direct";
break;
case MODE_GLOBAL:
mode = "Global";
break;
case MODE_RULE:
mode = "Rule";
break;
}
return (*env)->NewObject(env,
cGeneral,
cGeneralConstructor,
(*env)->NewStringUTF(env, mode),
general.http_port,
general.socks_port,
general.redirect_port,
general.mixed_port);
}
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_querySpeed(JNIEnv *env, jclass clazz) {
traffic_t traffic;
querySpeed(&traffic);
return (*env)->NewObject(env, cTraffic, cTrafficConstructor, (jlong)traffic.upload, (jlong)traffic.download);
}
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_queryBandwidth(JNIEnv *env, jclass clazz) {
traffic_t traffic;
queryBandwidth(&traffic);
return (*env)->NewObject(env, cTraffic, cTrafficConstructor, (jlong)traffic.upload, (jlong)traffic.download);
}
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_startTunDevice(JNIEnv *env, jclass clazz,
jint fd,
jint mtu,
jstring gateway,
jstring mirror,
jstring dns,
jint new_socket) {
const_string_t gatewayString = (*env)->GetStringUTFChars(env, gateway, NULL);
const_string_t mirrorString = (*env)->GetStringUTFChars(env, mirror, NULL);
const_string_t dnsString = (*env)->GetStringUTFChars(env, dns, NULL);
char *exception = startTunDevice(fd, mtu, gatewayString, mirrorString, dnsString, new_socket);
if ( exception != NULL )
(*env)->ThrowNew(env, cClashException, exception);
free(exception);
(*env)->ReleaseStringUTFChars(env, gateway, gatewayString);
(*env)->ReleaseStringUTFChars(env, mirror, mirrorString);
(*env)->ReleaseStringUTFChars(env, dns, dnsString);
}
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_stopTunDevice(JNIEnv *env, jclass clazz) {
stopTunDevice();
}
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_setDnsOverride(JNIEnv *env, jclass clazz,
jboolean override_dns,
jstring append_nameservers) {
dns_override_t dns = {
.override_dns = override_dns,
.append_nameservers = (*env)->GetStringUTFChars(env, append_nameservers, NULL)
};
setDnsOverride(&dns);
(*env)->ReleaseStringUTFChars(env, append_nameservers, dns.append_nameservers);
}
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_setProxyMode(JNIEnv *env, jclass clazz,
jstring mode) {
const char *m = (*env)->GetStringUTFChars(env, mode, NULL);
if (strcmp(m, "Direct") == 0) {
setProxyMode(MODE_DIRECT);
} else if (strcmp(m, "Global") == 0) {
setProxyMode(MODE_GLOBAL);
} else if (strcmp(m, "Rule") == 0) {
setProxyMode(MODE_RULE);
}
(*env)->ReleaseStringUTFChars(env, mode, m);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *unused) {
(void) unused;
JNIEnv *env = NULL;
if ( (*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK )
return -1;
cClashException = (*env)->FindClass(env, "com/github/kr328/clash/core/bridge/ClashException");
cTraffic = (*env)->FindClass(env, "com/github/kr328/clash/core/model/Traffic");
cGeneral = (*env)->FindClass(env, "com/github/kr328/clash/core/model/General");
cTrafficConstructor = (*env)->GetMethodID(env, cTraffic, "<init>", "(JJ)V");
cGeneralConstructor = (*env)->GetMethodID(env, cGeneral, "<init>", "(Ljava/lang/String;IIII)V");
return JNI_VERSION_1_6;
}
+30
View File
@@ -0,0 +1,30 @@
#include "main.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_initialize(JNIEnv *env, jclass clazz,
jbyteArray database, jstring home,
jstring version) {
UNUSED(clazz);
Master::runWithContext<void>(env, [&](Master::Context *context) {
const_buffer_t databaseBuffer = context->createConstBufferFromByteArray(database);
const char *homeString = context->getString(home);
const char *versionString = context->getString(version);
initialize(&databaseBuffer, homeString, versionString);
context->releaseConstBufferFromByteArray(database, databaseBuffer);
context->releaseString(home, homeString);
context->releaseString(version, versionString);
});
}
extern "C"
JNIEXPORT void JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_reset(JNIEnv *env, jclass clazz) {
UNUSED(env);
UNUSED(clazz);
reset();
}
+113
View File
@@ -0,0 +1,113 @@
#include "main.h"
Master *Master::master = nullptr;
Master::Master(JNIEnv *env) {
master = this;
cClashException = env->FindClass("com/github/kr328/clash/core/bridge/ClashException");
cTraffic = env->FindClass("com/github/kr328/clash/core/model/Traffic");
cGeneral = env->FindClass("com/github/kr328/clash/core/model/General");
cCompletableFuture = env->FindClass("java/util/concurrent/CompletableFuture");
cClashExceptionConstructor = env->GetMethodID(cClashException, "<init>",
"(Ljava/lang/String;)V");
cTrafficConstructor = env->GetMethodID(cTraffic, "<init>", "(JJ)V");
cGeneralConstructor = env->GetMethodID(cGeneral, "<init>", "(Ljava/lang/String;IIII)V");
cCompletableFutureConstructor = env->GetMethodID(cCompletableFuture, "<init>", "()V");
mCompletableFutureComplete = env->GetMethodID(cCompletableFuture, "complete",
"(Ljava/lang/Object;)Z");
mCompletableFutureCompleteExceptionally = env->GetMethodID(cCompletableFuture,
"completeExceptionally",
"(Ljava/lang/Throwable;)Z");
}
Master::Context::Context(JNIEnv *env) {
this->env = env;
}
jthrowable Master::Context::newClashException(std::string const &reason) {
return reinterpret_cast<jthrowable>(env->NewObject(master->cClashException,
master->cClashExceptionConstructor,
env->NewStringUTF(reason.c_str())));
}
void Master::Context::throwThrowable(jthrowable throwable) {
env->Throw(throwable);
}
jobject Master::Context::newTraffic(long upload, long download) {
return env->NewObject(master->cTraffic, master->cTrafficConstructor, upload, download);
}
jobject Master::Context::newGeneral(std::string const &mode, int http, int socks, int redirect,
int mixed) {
return env->NewObject(master->cGeneral, master->cGeneralConstructor,
env->NewStringUTF(mode.c_str()), http, socks, redirect, mixed);
}
jobject Master::Context::newCompletableFuture() {
return env->NewObject(master->cCompletableFuture, master->cCompletableFutureConstructor);
}
jobject Master::Context::newGlobalReference(jobject obj) {
return env->NewGlobalRef(obj);
}
jobject Master::Context::removeGlobalReference(jobject obj) {
env->DeleteGlobalRef(obj);
return obj;
}
bool Master::Context::completeCompletableFuture(jobject completable, jobject object) {
return env->CallBooleanMethod(completable, master->mCompletableFutureComplete, object);
}
bool
Master::Context::completeExceptionallyCompletableFuture(jobject completable, jthrowable throwable) {
return env->CallBooleanMethod(completable, master->mCompletableFutureCompleteExceptionally,
throwable);
}
buffer_t Master::Context::createBufferFromByteArray(jbyteArray array) {
return {
.buffer = env->GetByteArrayElements(array, nullptr),
.length = env->GetArrayLength(array)
};
}
void Master::Context::releaseBufferFromByteArray(jbyteArray array, buffer_t &buffer) {
env->ReleaseByteArrayElements(array, reinterpret_cast<jbyte*>(buffer.buffer), JNI_COMMIT);
}
const_buffer_t Master::Context::createConstBufferFromByteArray(jbyteArray array) {
return {
.buffer = env->GetByteArrayElements(array, nullptr),
.length = env->GetArrayLength(array)
};
}
void Master::Context::releaseConstBufferFromByteArray(jbyteArray array, const_buffer_t &buffer) {
env->ReleaseByteArrayElements(array, const_cast<jbyte*>(reinterpret_cast<const jbyte*>(buffer.buffer)), JNI_ABORT);
}
const char *Master::Context::getString(jstring str) {
return env->GetStringUTFChars(str, nullptr);
}
void Master::Context::releaseString(jstring str, const char *c) {
env->ReleaseStringUTFChars(str, c);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *unused) {
UNUSED(unused);
JNIEnv *env = nullptr;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
return -1;
new Master(env);
return JNI_VERSION_1_6;
}
+77
View File
@@ -0,0 +1,77 @@
#include <jni.h>
#include <string>
#include <functional>
#include "libclash.h"
#define UNUSED(v) ((void)v)
class Master {
public:
class Context;
public:
Master(JNIEnv *env);
public:
template <class R>
static R runWithContext(JNIEnv *env, const std::function<R (Context *)>& func);
private:
jclass cClashException;
jclass cTraffic;
jclass cGeneral;
jclass cCompletableFuture;
jmethodID cClashExceptionConstructor;
jmethodID cTrafficConstructor;
jmethodID cGeneralConstructor;
jmethodID cCompletableFutureConstructor;
jmethodID mCompletableFutureComplete;
jmethodID mCompletableFutureCompleteExceptionally;
private:
static Master *master;
private:
friend class Context;
};
class Master::Context {
public:
Context(JNIEnv *env);
public:
jthrowable newClashException(std::string const &message);
jobject newTraffic(long upload, long download);
jobject newGeneral(std::string const &mode, int http, int socks, int redirect, int mixed);
jobject newCompletableFuture();
public:
void throwThrowable(jthrowable throwable);
public:
jobject newGlobalReference(jobject obj);
jobject removeGlobalReference(jobject obj);
public:
bool completeCompletableFuture(jobject completable, jobject object);
bool completeExceptionallyCompletableFuture(jobject completable, jthrowable throwable);
public:
buffer_t createBufferFromByteArray(jbyteArray array);
void releaseBufferFromByteArray(jbyteArray array, buffer_t &buffer);
const_buffer_t createConstBufferFromByteArray(jbyteArray array);
void releaseConstBufferFromByteArray(jbyteArray array, const_buffer_t &buffer);
const char *getString(jstring str);
void releaseString(jstring str, const char *c);
private:
JNIEnv *env;
};
template <class R>
R Master::runWithContext(JNIEnv *env, const std::function<R (Master::Context *)>& func) {
Master::Context context(env);
return func(&context);
}
+2
View File
@@ -0,0 +1,2 @@
#include "main.h"
+62
View File
@@ -0,0 +1,62 @@
#include "main.h"
extern "C"
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_queryGeneral(JNIEnv *env, jclass clazz) {
UNUSED(clazz);
return Master::runWithContext<jobject>(env, [&](Master::Context *context) -> jobject {
general_t general;
queryGeneral(&general);
const char *mode = nullptr;
switch (general.mode) {
case MODE_DIRECT:
mode = "Direct";
break;
case MODE_GLOBAL:
mode = "Global";
break;
case MODE_RULE:
mode = "Rule";
break;
case MODE_SCRIPT:
mode = "Script";
break;
}
return context->newGeneral(mode,
general.http_port, general.socks_port,
general.redirect_port, general.mixed_port);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_queryBandwidth(JNIEnv *env, jclass clazz) {
UNUSED(clazz);
return Master::runWithContext<jobject>(env, [&](Master::Context *context) -> jobject {
traffic_t traffic;
queryBandwidth(&traffic);
return context->newTraffic(traffic.upload, traffic.download);
});
}
extern "C"
JNIEXPORT jobject JNICALL
Java_com_github_kr328_clash_core_bridge_Bridge_querySpeed(JNIEnv *env, jclass clazz) {
UNUSED(clazz);
return Master::runWithContext<jobject>(env, [&](Master::Context *context) -> jobject {
traffic_t traffic;
querySpeed(&traffic);
return context->newTraffic(traffic.upload, traffic.download);
});
}