mirror of https://github.com/oxen-io/lokinet
Merge pull request #869 from majestrate/vpn-api-2019-10-03
android jni shim and vpn api for mobilepull/872/head
commit
175e9f1324
@ -1,44 +0,0 @@
|
|||||||
package network.loki.lokinet;
|
|
||||||
|
|
||||||
public class Lokinet_JNI {
|
|
||||||
|
|
||||||
public static final String STATUS_OK = "ok";
|
|
||||||
|
|
||||||
public static native String getABICompiledWith();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns error info if failed
|
|
||||||
* returns "ok" if daemon initialized and started okay
|
|
||||||
*/
|
|
||||||
public static native String startLokinet(String config);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stop daemon if running
|
|
||||||
*/
|
|
||||||
public static native void stopLokinet();
|
|
||||||
|
|
||||||
/** get interface address we want */
|
|
||||||
public static native String getIfAddr();
|
|
||||||
|
|
||||||
/** get interface address range we want */
|
|
||||||
public static native int getIfRange();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* change network status
|
|
||||||
*/
|
|
||||||
public static native void onNetworkStateChanged(boolean isConnected);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set vpn network interface fd pair
|
|
||||||
* @param rfd the file descriptor of read end
|
|
||||||
* @param wfd the file descriptor of the write end
|
|
||||||
*/
|
|
||||||
public static native void setVPNFileDescriptor(int rfd, int wfd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* load jni libraries
|
|
||||||
*/
|
|
||||||
public static void loadLibraries() {
|
|
||||||
System.loadLibrary("lokinetandroid");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
set(ANDROID_SRC
|
||||||
|
lokinet_config.cpp
|
||||||
|
lokinet_daemon.cpp
|
||||||
|
lokinet_vpn.cpp
|
||||||
|
)
|
||||||
|
add_library(${ANDROID_LIB} SHARED ${ANDROID_SRC})
|
||||||
|
set_property(TARGET ${ANDROID_LIB} PROPERTY CXX_STANDARD 14)
|
||||||
|
add_log_tag(${ANDROID_LIB})
|
||||||
|
target_link_libraries(${ANDROID_LIB} ${STATIC_LIB} ${LIBS})
|
@ -1,237 +0,0 @@
|
|||||||
#include <llarp.h>
|
|
||||||
#include <config/config.hpp>
|
|
||||||
#include <util/fs.hpp>
|
|
||||||
#include <llarp.hpp>
|
|
||||||
#include <router/router.hpp>
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
struct AndroidMain
|
|
||||||
{
|
|
||||||
llarp_main* m_impl = nullptr;
|
|
||||||
std::thread* m_thread = nullptr;
|
|
||||||
std::string configFile;
|
|
||||||
|
|
||||||
/// set configuration and ensure files
|
|
||||||
bool
|
|
||||||
Configure(const char* conf, const char* basedir)
|
|
||||||
{
|
|
||||||
configFile = conf;
|
|
||||||
return llarp_ensure_config(conf, basedir, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// reload config on runtime
|
|
||||||
bool
|
|
||||||
ReloadConfig()
|
|
||||||
{
|
|
||||||
if(!m_impl)
|
|
||||||
return false;
|
|
||||||
llarp_main_signal(m_impl, SIGHUP);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// start daemon thread
|
|
||||||
bool
|
|
||||||
Start()
|
|
||||||
{
|
|
||||||
if(m_impl || m_thread)
|
|
||||||
return true;
|
|
||||||
m_impl = llarp_main_init(configFile.c_str(), true);
|
|
||||||
if(m_impl == nullptr)
|
|
||||||
return false;
|
|
||||||
if(llarp_main_setup(m_impl, false))
|
|
||||||
{
|
|
||||||
llarp_main_free(m_impl);
|
|
||||||
m_impl = nullptr;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_thread = new std::thread(std::bind(&AndroidMain::Run, this));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// return true if we are running
|
|
||||||
bool
|
|
||||||
Running() const
|
|
||||||
{
|
|
||||||
return m_impl != nullptr && m_thread != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// blocking run
|
|
||||||
void
|
|
||||||
Run()
|
|
||||||
{
|
|
||||||
if(llarp_main_run(m_impl))
|
|
||||||
{
|
|
||||||
// on error
|
|
||||||
llarp::LogError("daemon run fail");
|
|
||||||
llarp_main* ptr = m_impl;
|
|
||||||
m_impl = nullptr;
|
|
||||||
llarp_main_signal(ptr, SIGINT);
|
|
||||||
llarp_main_free(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
GetIfAddr()
|
|
||||||
{
|
|
||||||
std::string addr;
|
|
||||||
if(m_impl)
|
|
||||||
{
|
|
||||||
auto* ctx = llarp_main_get_context(m_impl);
|
|
||||||
if(!ctx)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
ctx->router->hiddenServiceContext().ForEachService(
|
|
||||||
[&addr](const std::string&,
|
|
||||||
const llarp::service::Endpoint_ptr& ep) -> bool {
|
|
||||||
if(addr.empty())
|
|
||||||
{
|
|
||||||
if(ep->HasIfAddr())
|
|
||||||
{
|
|
||||||
// TODO: v4
|
|
||||||
const auto ip = ep->GetIfAddr();
|
|
||||||
if(ip.h)
|
|
||||||
{
|
|
||||||
addr = ip.ToString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return addr.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
GetIfRange() const
|
|
||||||
{
|
|
||||||
if(m_impl)
|
|
||||||
{
|
|
||||||
auto* ctx = llarp_main_get_context(m_impl);
|
|
||||||
if(!ctx)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SetVPN_FD(int rfd, int wfd)
|
|
||||||
{
|
|
||||||
(void)rfd;
|
|
||||||
(void)wfd;
|
|
||||||
// if(m_impl)
|
|
||||||
// llarp_main_inject_vpn_fd(m_impl, rfd, wfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// stop daemon thread
|
|
||||||
void
|
|
||||||
Stop()
|
|
||||||
{
|
|
||||||
if(m_impl)
|
|
||||||
llarp_main_signal(m_impl, SIGINT);
|
|
||||||
m_thread->join();
|
|
||||||
delete m_thread;
|
|
||||||
m_thread = nullptr;
|
|
||||||
if(m_impl)
|
|
||||||
llarp_main_free(m_impl);
|
|
||||||
m_impl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::unique_ptr< AndroidMain > Ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static AndroidMain::Ptr daemon_ptr(new AndroidMain());
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_getABICompiledWith(JNIEnv* env, jclass)
|
|
||||||
{
|
|
||||||
// TODO: fixme
|
|
||||||
return env->NewStringUTF("android");
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_startLokinet(JNIEnv* env, jclass,
|
|
||||||
jstring configfile)
|
|
||||||
{
|
|
||||||
if(daemon_ptr->Running())
|
|
||||||
return env->NewStringUTF("already running");
|
|
||||||
std::string conf;
|
|
||||||
fs::path basepath;
|
|
||||||
{
|
|
||||||
const char* nativeString = env->GetStringUTFChars(configfile, JNI_FALSE);
|
|
||||||
conf += std::string(nativeString);
|
|
||||||
env->ReleaseStringUTFChars(configfile, nativeString);
|
|
||||||
basepath = fs::path(conf).parent_path();
|
|
||||||
}
|
|
||||||
if(daemon_ptr->Configure(conf.c_str(), basepath.string().c_str()))
|
|
||||||
{
|
|
||||||
if(daemon_ptr->Start())
|
|
||||||
return env->NewStringUTF("ok");
|
|
||||||
else
|
|
||||||
return env->NewStringUTF("failed to start daemon");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return env->NewStringUTF("failed to configure daemon");
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_stopLokinet(JNIEnv*, jclass)
|
|
||||||
{
|
|
||||||
if(daemon_ptr->Running())
|
|
||||||
{
|
|
||||||
daemon_ptr->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_setVPNFileDescriptor(JNIEnv*, jclass,
|
|
||||||
jint rfd,
|
|
||||||
jint wfd)
|
|
||||||
{
|
|
||||||
daemon_ptr->SetVPN_FD(rfd, wfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_getIfAddr(JNIEnv* env, jclass)
|
|
||||||
{
|
|
||||||
if(daemon_ptr)
|
|
||||||
return env->NewStringUTF(daemon_ptr->GetIfAddr());
|
|
||||||
else
|
|
||||||
return env->NewStringUTF("");
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_getIfRange(JNIEnv*, jclass)
|
|
||||||
{
|
|
||||||
if(daemon_ptr)
|
|
||||||
return daemon_ptr->GetIfRange();
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_network_loki_lokinet_Lokinet_1JNI_onNetworkStateChanged(
|
|
||||||
JNIEnv*, jclass, jboolean isConnected)
|
|
||||||
{
|
|
||||||
if(isConnected)
|
|
||||||
{
|
|
||||||
if(!daemon_ptr->Running())
|
|
||||||
{
|
|
||||||
if(!daemon_ptr->Start())
|
|
||||||
{
|
|
||||||
// TODO: do some kind of callback here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(daemon_ptr->Running())
|
|
||||||
{
|
|
||||||
daemon_ptr->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
#include "network_loki_lokinet_LokinetConfig.h"
|
||||||
|
#include <llarp.hpp>
|
||||||
|
#include "lokinet_jni_common.hpp"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv* env, jclass)
|
||||||
|
{
|
||||||
|
llarp_config* conf = llarp_default_config();
|
||||||
|
if(conf == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return env->NewDirectByteBuffer(conf, llarp_config_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Free(JNIEnv* env, jclass, jobject buf)
|
||||||
|
{
|
||||||
|
llarp_config_free(FromBuffer< llarp_config >(env, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv* env, jobject self,
|
||||||
|
jstring fname)
|
||||||
|
{
|
||||||
|
llarp_config* conf = GetImpl< llarp_config >(env, self);
|
||||||
|
if(conf == nullptr)
|
||||||
|
return JNI_FALSE;
|
||||||
|
return VisitStringAsStringView< jboolean >(
|
||||||
|
env, fname, [conf](llarp::string_view val) -> jboolean {
|
||||||
|
const auto filename = llarp::string_view_string(val);
|
||||||
|
if(llarp_config_read_file(conf, filename.c_str()))
|
||||||
|
return JNI_TRUE;
|
||||||
|
return JNI_FALSE;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
#include "network_loki_lokinet_LokinetDaemon.h"
|
||||||
|
#include "lokinet_jni_common.hpp"
|
||||||
|
#include "lokinet_jni_vpnio.hpp"
|
||||||
|
#include <llarp.h>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Obtain(JNIEnv *env, jclass)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = llarp_main_default_init();
|
||||||
|
if(ptr == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return env->NewDirectByteBuffer(ptr, llarp_main_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Free(JNIEnv *env, jclass, jobject buf)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = FromBuffer< llarp_main >(env, buf);
|
||||||
|
llarp_main_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Configure(JNIEnv *env, jobject self,
|
||||||
|
jobject conf)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = GetImpl< llarp_main >(env, self);
|
||||||
|
llarp_config *config = GetImpl< llarp_config >(env, conf);
|
||||||
|
if(ptr == nullptr || config == nullptr)
|
||||||
|
return JNI_FALSE;
|
||||||
|
if(llarp_main_configure(ptr, config))
|
||||||
|
return JNI_TRUE;
|
||||||
|
return llarp_main_setup(ptr) == 0 ? JNI_TRUE : JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Mainloop(JNIEnv *env, jobject self)
|
||||||
|
{
|
||||||
|
static llarp_main_runtime_opts opts;
|
||||||
|
llarp_main *ptr = GetImpl< llarp_main >(env, self);
|
||||||
|
if(ptr == nullptr)
|
||||||
|
return -1;
|
||||||
|
return llarp_main_run(ptr, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_IsRunning(JNIEnv *env, jobject self)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = GetImpl< llarp_main >(env, self);
|
||||||
|
return (ptr != nullptr && llarp_main_is_running(ptr)) ? JNI_TRUE
|
||||||
|
: JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Stop(JNIEnv *env, jobject self)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = GetImpl< llarp_main >(env, self);
|
||||||
|
if(ptr == nullptr)
|
||||||
|
return JNI_FALSE;
|
||||||
|
if(not llarp_main_is_running(ptr))
|
||||||
|
return JNI_FALSE;
|
||||||
|
llarp_main_stop(ptr);
|
||||||
|
return llarp_main_is_running(ptr) ? JNI_FALSE : JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_InjectVPN(JNIEnv *env, jobject self,
|
||||||
|
jobject vpn)
|
||||||
|
{
|
||||||
|
llarp_main *ptr = GetImpl< llarp_main >(env, self);
|
||||||
|
lokinet_jni_vpnio *impl = GetImpl< lokinet_jni_vpnio >(env, vpn);
|
||||||
|
if(ptr == nullptr || impl == nullptr)
|
||||||
|
return JNI_FALSE;
|
||||||
|
if(impl->info.netmask == 0)
|
||||||
|
return JNI_FALSE;
|
||||||
|
if(not impl->Init(ptr))
|
||||||
|
return JNI_FALSE;
|
||||||
|
return llarp_main_inject_default_vpn(ptr, &impl->io, impl->info)
|
||||||
|
? JNI_TRUE
|
||||||
|
: JNI_FALSE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef LOKINET_JNI_COMMON_HPP
|
||||||
|
#define LOKINET_JNI_COMMON_HPP
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <util/string_view.hpp>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
/// visit string as native bytes
|
||||||
|
/// jvm uses some unholy encoding internally so we convert it to utf-8
|
||||||
|
template < typename T, typename V >
|
||||||
|
static T
|
||||||
|
VisitStringAsStringView(JNIEnv* env, jobject str, V visit)
|
||||||
|
{
|
||||||
|
const jclass stringClass = env->GetObjectClass(str);
|
||||||
|
const jmethodID getBytes =
|
||||||
|
env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
|
||||||
|
|
||||||
|
const jstring charsetName = env->NewStringUTF("UTF-8");
|
||||||
|
const jbyteArray stringJbytes =
|
||||||
|
(jbyteArray)env->CallObjectMethod(str, getBytes, charsetName);
|
||||||
|
env->DeleteLocalRef(charsetName);
|
||||||
|
|
||||||
|
const size_t length = env->GetArrayLength(stringJbytes);
|
||||||
|
jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
|
||||||
|
|
||||||
|
T result = visit(llarp::string_view((const char*)pBytes, length));
|
||||||
|
|
||||||
|
env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
|
||||||
|
env->DeleteLocalRef(stringJbytes);
|
||||||
|
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cast jni buffer to T *
|
||||||
|
template < typename T >
|
||||||
|
static T*
|
||||||
|
FromBuffer(JNIEnv* env, jobject o)
|
||||||
|
{
|
||||||
|
if(o == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return static_cast< T* >(env->GetDirectBufferAddress(o));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get T * from object member called membername
|
||||||
|
template < typename T >
|
||||||
|
static T*
|
||||||
|
FromObjectMember(JNIEnv* env, jobject self, const char* membername)
|
||||||
|
{
|
||||||
|
jclass cl = env->GetObjectClass(self);
|
||||||
|
jfieldID name = env->GetFieldID(cl, membername, "Ljava/nio/Buffer;");
|
||||||
|
jobject buffer = env->GetObjectField(self, name);
|
||||||
|
return FromBuffer< T >(env, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// visit object string member called membername as bytes
|
||||||
|
template < typename T, typename V >
|
||||||
|
static T
|
||||||
|
VisitObjectMemberStringAsStringView(JNIEnv* env, jobject self,
|
||||||
|
const char* membername, V v)
|
||||||
|
{
|
||||||
|
jclass cl = env->GetObjectClass(self);
|
||||||
|
jfieldID name = env->GetFieldID(cl, membername, "Ljava/lang/String;");
|
||||||
|
jobject str = env->GetObjectField(self, name);
|
||||||
|
return VisitStringAsStringView< T, V >(env, str, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get object member int called membername
|
||||||
|
template < typename Int_t >
|
||||||
|
Int_t
|
||||||
|
GetObjectMemberAsInt(JNIEnv* env, jobject self, const char* membername)
|
||||||
|
{
|
||||||
|
jclass cl = env->GetObjectClass(self);
|
||||||
|
jfieldID name = env->GetFieldID(cl, membername, "I");
|
||||||
|
return env->GetIntField(self, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get implementation on jni type
|
||||||
|
template < typename T >
|
||||||
|
T*
|
||||||
|
GetImpl(JNIEnv* env, jobject self)
|
||||||
|
{
|
||||||
|
return FromObjectMember< T >(env, self, "impl");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,150 @@
|
|||||||
|
#ifndef LOKINET_JNI_VPNIO_HPP
|
||||||
|
#define LOKINET_JNI_VPNIO_HPP
|
||||||
|
|
||||||
|
#include <llarp.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <future>
|
||||||
|
#include <util/string_view.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
namespace lokinet
|
||||||
|
{
|
||||||
|
struct VPNIO
|
||||||
|
{
|
||||||
|
static VPNIO *
|
||||||
|
Get(llarp_vpn_io *vpn)
|
||||||
|
{
|
||||||
|
return static_cast< VPNIO * >(vpn->user);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~VPNIO() = default;
|
||||||
|
|
||||||
|
llarp_vpn_io io;
|
||||||
|
llarp_vpn_ifaddr_info info{{0}, {0}, 0};
|
||||||
|
std::unique_ptr< std::promise< void > > closeWaiter;
|
||||||
|
|
||||||
|
void
|
||||||
|
Closed()
|
||||||
|
{
|
||||||
|
if(closeWaiter)
|
||||||
|
closeWaiter->set_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
InjectSuccess() = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
InjectFail() = 0;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
Tick() = 0;
|
||||||
|
|
||||||
|
VPNIO()
|
||||||
|
{
|
||||||
|
io.impl = nullptr;
|
||||||
|
io.user = this;
|
||||||
|
io.closed = [](llarp_vpn_io *vpn) { VPNIO::Get(vpn)->Closed(); };
|
||||||
|
io.injected = [](llarp_vpn_io *vpn, bool good) {
|
||||||
|
VPNIO *ptr = VPNIO::Get(vpn);
|
||||||
|
if(good)
|
||||||
|
ptr->InjectSuccess();
|
||||||
|
else
|
||||||
|
ptr->InjectFail();
|
||||||
|
};
|
||||||
|
io.tick = [](llarp_vpn_io *vpn) { VPNIO::Get(vpn)->Tick(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Init(llarp_main *ptr)
|
||||||
|
{
|
||||||
|
if(Ready())
|
||||||
|
return false;
|
||||||
|
return llarp_vpn_io_init(ptr, &io);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Ready() const
|
||||||
|
{
|
||||||
|
return io.impl != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Close()
|
||||||
|
{
|
||||||
|
if(not Ready())
|
||||||
|
return;
|
||||||
|
if(closeWaiter)
|
||||||
|
return;
|
||||||
|
closeWaiter = std::make_unique< std::promise< void > >();
|
||||||
|
llarp_vpn_io_close_async(&io);
|
||||||
|
closeWaiter->get_future().wait();
|
||||||
|
closeWaiter.reset();
|
||||||
|
io.impl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
llarp_vpn_pkt_reader *
|
||||||
|
Reader()
|
||||||
|
{
|
||||||
|
return llarp_vpn_io_packet_reader(&io);
|
||||||
|
}
|
||||||
|
|
||||||
|
llarp_vpn_pkt_writer *
|
||||||
|
Writer()
|
||||||
|
{
|
||||||
|
return llarp_vpn_io_packet_writer(&io);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
ReadPacket(void *dst, size_t len)
|
||||||
|
{
|
||||||
|
if(not Ready())
|
||||||
|
return -1;
|
||||||
|
unsigned char *buf = (unsigned char *)dst;
|
||||||
|
return llarp_vpn_io_readpkt(Reader(), buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WritePacket(void *pkt, size_t len)
|
||||||
|
{
|
||||||
|
if(not Ready())
|
||||||
|
return false;
|
||||||
|
unsigned char *buf = (unsigned char *)pkt;
|
||||||
|
return llarp_vpn_io_writepkt(Writer(), buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetIfName(llarp::string_view val)
|
||||||
|
{
|
||||||
|
const auto sz = std::min(val.size(), sizeof(info.ifname));
|
||||||
|
std::copy_n(val.data(), sz, info.ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetIfAddr(llarp::string_view val)
|
||||||
|
{
|
||||||
|
const auto sz = std::min(val.size(), sizeof(info.ifaddr));
|
||||||
|
std::copy_n(val.data(), sz, info.ifaddr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace lokinet
|
||||||
|
|
||||||
|
struct lokinet_jni_vpnio : public lokinet::VPNIO
|
||||||
|
{
|
||||||
|
void
|
||||||
|
InjectSuccess() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InjectFail() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Tick() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,86 @@
|
|||||||
|
#include "network_loki_lokinet_LokinetVPN.h"
|
||||||
|
#include "lokinet_jni_vpnio.hpp"
|
||||||
|
#include "lokinet_jni_common.hpp"
|
||||||
|
#include <net/ip.hpp>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_PacketSize(JNIEnv *, jclass)
|
||||||
|
{
|
||||||
|
return llarp::net::IPPacket::MaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Alloc(JNIEnv *env, jclass)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = new lokinet_jni_vpnio();
|
||||||
|
return env->NewDirectByteBuffer(vpn, sizeof(lokinet_jni_vpnio));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Free(JNIEnv *env, jclass, jobject buf)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = FromBuffer< lokinet_jni_vpnio >(env, buf);
|
||||||
|
if(vpn == nullptr)
|
||||||
|
return;
|
||||||
|
delete vpn;
|
||||||
|
}
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Stop(JNIEnv *env, jobject self)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = GetImpl< lokinet_jni_vpnio >(env, self);
|
||||||
|
if(vpn)
|
||||||
|
{
|
||||||
|
vpn->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_ReadPkt(JNIEnv *env, jobject self,
|
||||||
|
jobject pkt)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = GetImpl< lokinet_jni_vpnio >(env, self);
|
||||||
|
if(vpn == nullptr)
|
||||||
|
return -1;
|
||||||
|
void *pktbuf = env->GetDirectBufferAddress(pkt);
|
||||||
|
auto pktlen = env->GetDirectBufferCapacity(pkt);
|
||||||
|
if(pktbuf == nullptr)
|
||||||
|
return -1;
|
||||||
|
return vpn->ReadPacket(pktbuf, pktlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_WritePkt(JNIEnv *env, jobject self,
|
||||||
|
jobject pkt)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = GetImpl< lokinet_jni_vpnio >(env, self);
|
||||||
|
if(vpn == nullptr)
|
||||||
|
return false;
|
||||||
|
void *pktbuf = env->GetDirectBufferAddress(pkt);
|
||||||
|
auto pktlen = env->GetDirectBufferCapacity(pkt);
|
||||||
|
if(pktbuf == nullptr)
|
||||||
|
return false;
|
||||||
|
return vpn->WritePacket(pktbuf, pktlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_SetInfo(JNIEnv *env, jobject self,
|
||||||
|
jobject info)
|
||||||
|
{
|
||||||
|
lokinet_jni_vpnio *vpn = GetImpl< lokinet_jni_vpnio >(env, self);
|
||||||
|
if(vpn == nullptr)
|
||||||
|
return;
|
||||||
|
VisitObjectMemberStringAsStringView< bool >(
|
||||||
|
env, info, "ifaddr", [vpn](llarp::string_view val) -> bool {
|
||||||
|
vpn->SetIfAddr(val);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
VisitObjectMemberStringAsStringView< bool >(
|
||||||
|
env, info, "ifname", [vpn](llarp::string_view val) -> bool {
|
||||||
|
vpn->SetIfName(val);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
vpn->info.netmask = GetObjectMemberAsInt< uint8_t >(env, info, "netmask");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class network_loki_lokinet_LokinetConfig */
|
||||||
|
|
||||||
|
#ifndef _Included_network_loki_lokinet_LokinetConfig
|
||||||
|
#define _Included_network_loki_lokinet_LokinetConfig
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetConfig
|
||||||
|
* Method: Obtain
|
||||||
|
* Signature: ()Ljava/nio/Buffer;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Obtain(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetConfig
|
||||||
|
* Method: Free
|
||||||
|
* Signature: (Ljava/nio/Buffer;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Free(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetConfig
|
||||||
|
* Method: Load
|
||||||
|
* Signature: (Ljava/lang/String;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetConfig_Load(JNIEnv *, jobject, jstring);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,70 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class network_loki_lokinet_LokinetDaemon */
|
||||||
|
|
||||||
|
#ifndef _Included_network_loki_lokinet_LokinetDaemon
|
||||||
|
#define _Included_network_loki_lokinet_LokinetDaemon
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: Obtain
|
||||||
|
* Signature: ()Ljava/nio/Buffer;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Obtain(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: Free
|
||||||
|
* Signature: (Ljava/nio/Buffer;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Free(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: Configure
|
||||||
|
* Signature: (Lnetwork/loki/lokinet/LokinetConfig;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Configure(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: Mainloop
|
||||||
|
* Signature: ()I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Mainloop(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: IsRunning
|
||||||
|
* Signature: ()Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_IsRunning(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: Stop
|
||||||
|
* Signature: ()Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_Stop(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetDaemon
|
||||||
|
* Method: InjectVPN
|
||||||
|
* Signature: (Lnetwork/loki/lokinet/LokinetVPN;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetDaemon_InjectVPN(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,69 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class network_loki_lokinet_LokinetVPN */
|
||||||
|
|
||||||
|
#ifndef _Included_network_loki_lokinet_LokinetVPN
|
||||||
|
#define _Included_network_loki_lokinet_LokinetVPN
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: PacketSize
|
||||||
|
* Signature: ()I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_PacketSize(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: Alloc
|
||||||
|
* Signature: ()Ljava/nio/Buffer;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Alloc(JNIEnv *, jclass);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: Free
|
||||||
|
* Signature: (Ljava/nio/Buffer;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Free(JNIEnv *, jclass, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: Stop
|
||||||
|
* Signature: ()V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_Stop(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: ReadPkt
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_ReadPkt(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: WritePkt
|
||||||
|
* Signature: (Ljava/nio/ByteBuffer;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_WritePkt(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: network_loki_lokinet_LokinetVPN
|
||||||
|
* Method: SetInfo
|
||||||
|
* Signature: (Lnetwork/loki/lokinet/LokinetVPN/VPNInfo;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_network_loki_lokinet_LokinetVPN_SetInfo(JNIEnv *, jobject, jobject);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,14 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class network_loki_lokinet_LokinetVPN_VPNInfo */
|
||||||
|
|
||||||
|
#ifndef _Included_network_loki_lokinet_LokinetVPN_VPNInfo
|
||||||
|
#define _Included_network_loki_lokinet_LokinetVPN_VPNInfo
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,31 @@
|
|||||||
|
#include <ev/vpnio.hpp>
|
||||||
|
#include <llarp.hpp>
|
||||||
|
#include <router/abstractrouter.hpp>
|
||||||
|
#include <util/thread/logic.hpp>
|
||||||
|
|
||||||
|
void
|
||||||
|
llarp_vpn_io_impl::AsyncClose()
|
||||||
|
{
|
||||||
|
reader.queue.disable();
|
||||||
|
writer.queue.disable();
|
||||||
|
CallSafe(std::bind(&llarp_vpn_io_impl::Expunge, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
llarp_vpn_io_impl::CallSafe(std::function< void(void) > f)
|
||||||
|
{
|
||||||
|
llarp::Context* ctx = llarp::Context::Get(ptr);
|
||||||
|
if(ctx && ctx->CallSafe(f))
|
||||||
|
return;
|
||||||
|
else if(ctx == nullptr || ctx->logic == nullptr)
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
llarp_vpn_io_impl::Expunge()
|
||||||
|
{
|
||||||
|
parent->impl = nullptr;
|
||||||
|
if(parent->closed)
|
||||||
|
parent->closed(parent);
|
||||||
|
delete this;
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef LLARP_EV_VPNIO_HPP
|
||||||
|
#define LLARP_EV_VPNIO_HPP
|
||||||
|
#include <net/ip.hpp>
|
||||||
|
#include <util/thread/queue.hpp>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
struct llarp_main;
|
||||||
|
struct llarp_vpn_io;
|
||||||
|
|
||||||
|
struct llarp_vpn_pkt_queue
|
||||||
|
{
|
||||||
|
using Packet_t = llarp::net::IPPacket;
|
||||||
|
llarp::thread::Queue< Packet_t > queue;
|
||||||
|
|
||||||
|
llarp_vpn_pkt_queue() : queue(1024){};
|
||||||
|
~llarp_vpn_pkt_queue() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct llarp_vpn_pkt_writer : public llarp_vpn_pkt_queue
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct llarp_vpn_pkt_reader : public llarp_vpn_pkt_queue
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct llarp_vpn_io_impl
|
||||||
|
{
|
||||||
|
llarp_vpn_io_impl(llarp_main* p, llarp_vpn_io* io) : ptr(p), parent(io)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~llarp_vpn_io_impl() = default;
|
||||||
|
|
||||||
|
llarp_main* ptr;
|
||||||
|
llarp_vpn_io* parent;
|
||||||
|
|
||||||
|
llarp_vpn_pkt_writer writer;
|
||||||
|
llarp_vpn_pkt_reader reader;
|
||||||
|
|
||||||
|
void
|
||||||
|
AsyncClose();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
CallSafe(std::function< void(void) > f);
|
||||||
|
|
||||||
|
void
|
||||||
|
Expunge();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue