refactor clash bridge
This commit is contained in:
18 files changed
+465
-202
No files matched your search
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "main.h"
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user