Merge pull request #869 from majestrate/vpn-api-2019-10-03

android jni shim and vpn api for mobile
pull/872/head
Jeff 5 years ago committed by GitHub
commit 175e9f1324
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -167,8 +167,8 @@ endif()
if (NOT MSVC OR NOT MSVC_VERSION) if (NOT MSVC OR NOT MSVC_VERSION)
add_compile_options(${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS}) add_compile_options(${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS})
endif() endif()
add_subdirectory(${ABSEIL_DIR})
add_subdirectory(vendor/gtest) add_subdirectory(vendor/gtest)
add_subdirectory(${ABSEIL_DIR})
if (FS_LIB STREQUAL "cppbackport") if (FS_LIB STREQUAL "cppbackport")
add_subdirectory(vendor) add_subdirectory(vendor)
@ -233,9 +233,6 @@ enable_testing()
if (NOT SHADOW) if (NOT SHADOW)
add_subdirectory(test) add_subdirectory(test)
if(ANDROID) if(ANDROID)
add_library(${ANDROID_LIB} SHARED jni/lokinet_android.cpp) add_subdirectory(jni)
set_property(TARGET ${ANDROID_LIB} PROPERTY CXX_STANDARD 14)
add_log_tag(${ANDROID_LIB})
target_link_libraries(${ANDROID_LIB} ${STATIC_LIB} ${LIBS})
endif(ANDROID) endif(ANDROID)
endif() endif()

@ -33,20 +33,16 @@ import android.widget.TextView;
public class LokiNetActivity extends Activity { public class LokiNetActivity extends Activity {
private static final String TAG = "lokinet-activity"; private static final String TAG = "lokinet-activity";
private TextView textView; private TextView textView;
private static final String DefaultBootstrapURL = "https://i2p.rocks/bootstrap.signed"; private static final String DefaultBootstrapURL = "https://seed.lokinet.org/bootstrap.signed";
private AsyncBootstrap bootstrapper; private AsyncBootstrap bootstrapper;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// copy assets
//String conf = copyFileAsset("daemon.ini");
textView = new TextView(this); textView = new TextView(this);
setContentView(textView); setContentView(textView);
System.loadLibrary("lokinetandroid");
Lokinet_JNI.loadLibraries();
} }

@ -5,4 +5,5 @@ import android.net.VpnService;
public class LokinetService extends VpnService public class LokinetService extends VpnService
{ {
} }

@ -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");
}
}

@ -21,8 +21,6 @@ public class NetworkStateChangeReceiver extends BroadcastReceiver {
boolean isConnected = activeNetworkInfo!=null && activeNetworkInfo.isConnected(); boolean isConnected = activeNetworkInfo!=null && activeNetworkInfo.isConnected();
// https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html?hl=ru // https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html?hl=ru
// boolean isWiFi = activeNetworkInfo!=null && (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI); // boolean isWiFi = activeNetworkInfo!=null && (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
Lokinet_JNI.onNetworkStateChanged(isConnected);
} catch (Throwable tr) { } catch (Throwable tr) {
Log.d(TAG,"",tr); Log.d(TAG,"",tr);
} }

@ -1,6 +1,6 @@
set(CMAKE_SYSTEM_NAME Windows) set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
set(TOOLCHAIN_SUFFIX "") set(TOOLCHAIN_SUFFIX "-posix")
set(WIN64_CROSS_COMPILE ON) set(WIN64_CROSS_COMPILE ON)
set(TOOLCHAIN_PATHS set(TOOLCHAIN_PATHS

@ -14,6 +14,7 @@
#include <cxxopts.hpp> #include <cxxopts.hpp>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <future>
#ifdef _WIN32 #ifdef _WIN32
#define wmin(x, y) (((x) < (y)) ? (x) : (y)) #define wmin(x, y) (((x) < (y)) ? (x) : (y))
@ -85,12 +86,12 @@ resolvePath(std::string conffname)
/// this sets up, configures and runs the main context /// this sets up, configures and runs the main context
static void static void
run_main_context(std::string conffname, bool multiThreaded, bool backgroundMode) run_main_context(std::string conffname, llarp_main_runtime_opts opts)
{ {
// this is important, can downgrade from Info though // this is important, can downgrade from Info though
llarp::LogDebug("Running from: ", fs::current_path().string()); llarp::LogDebug("Running from: ", fs::current_path().string());
llarp::LogInfo("Using config file: ", conffname); llarp::LogInfo("Using config file: ", conffname);
ctx = llarp_main_init(conffname.c_str(), multiThreaded); ctx = llarp_main_init(conffname.c_str());
int code = 1; int code = 1;
if(ctx) if(ctx)
{ {
@ -102,7 +103,7 @@ run_main_context(std::string conffname, bool multiThreaded, bool backgroundMode)
code = llarp_main_setup(ctx); code = llarp_main_setup(ctx);
llarp::util::SetThreadName("llarp-mainloop"); llarp::util::SetThreadName("llarp-mainloop");
if(code == 0) if(code == 0)
code = llarp_main_run(ctx, backgroundMode); code = llarp_main_run(ctx, opts);
llarp_main_free(ctx); llarp_main_free(ctx);
} }
exit_code.set_value(code); exit_code.set_value(code);
@ -111,11 +112,11 @@ run_main_context(std::string conffname, bool multiThreaded, bool backgroundMode)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
bool multiThreaded = true; llarp_main_runtime_opts opts;
const char *singleThreadVar = getenv("LLARP_SHADOW"); const char *singleThreadVar = getenv("LLARP_SHADOW");
if(singleThreadVar && std::string(singleThreadVar) == "1") if(singleThreadVar && std::string(singleThreadVar) == "1")
{ {
multiThreaded = false; opts.singleThreaded = true;
} }
#ifdef _WIN32 #ifdef _WIN32
@ -148,12 +149,10 @@ main(int argc, char *argv[])
options.parse_positional("config"); options.parse_positional("config");
// clang-format on // clang-format on
bool genconfigOnly = false; bool genconfigOnly = false;
bool asRouter = false; bool asRouter = false;
bool overWrite = false; bool overWrite = false;
bool backgroundMode = false;
std::string conffname; // suggestions: confFName? conf_fname? std::string conffname; // suggestions: confFName? conf_fname?
try try
{ {
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
@ -178,7 +177,7 @@ main(int argc, char *argv[])
if(result.count("version")) if(result.count("version"))
{ {
std::cout << LLARP_VERSION << std::endl; std::cout << llarp_version() << std::endl;
return 0; return 0;
} }
@ -189,7 +188,7 @@ main(int argc, char *argv[])
if(result.count("background") > 0) if(result.count("background") > 0)
{ {
backgroundMode = true; opts.background = true;
} }
if(result.count("force") > 0) if(result.count("force") > 0)
@ -315,8 +314,7 @@ main(int argc, char *argv[])
return 0; return 0;
} }
std::thread main_thread{ std::thread main_thread{std::bind(&run_main_context, conffname, opts)};
std::bind(&run_main_context, conffname, multiThreaded, backgroundMode)};
auto ftr = exit_code.get_future(); auto ftr = exit_code.get_future();
do do
{ {
@ -324,11 +322,9 @@ main(int argc, char *argv[])
} while(ftr.wait_for(std::chrono::seconds(1)) != std::future_status::ready); } while(ftr.wait_for(std::chrono::seconds(1)) != std::future_status::ready);
main_thread.join(); main_thread.join();
const auto code = ftr.get();
#ifdef _WIN32 #ifdef _WIN32
::WSACleanup(); ::WSACleanup();
#endif #endif
const auto code = ftr.get();
exit(code);
return code; return code;
} }

@ -1,15 +1,8 @@
#ifndef LLARP_H_ #ifndef LLARP_H_
#define LLARP_H_ #define LLARP_H_
#include <stdint.h>
#include <unistd.h>
#ifdef __cplusplus #ifdef __cplusplus
#include <constants/version.hpp>
#include <ev/ev.h>
#include <handlers/tun.hpp> // for handlers
#include <service/address.hpp> // for service::address
#include <service/endpoint.hpp>
#include <util/thread/logic.hpp>
#include <util/mem.h>
extern "C" extern "C"
{ {
#endif #endif
@ -27,106 +20,211 @@ extern "C"
/// llarp application context for C api /// llarp application context for C api
struct llarp_main; struct llarp_main;
/// initialize application context and load config /// runtime options for main context from cli
struct llarp_main * struct llarp_main_runtime_opts
llarp_main_init(const char *fname, bool multiProcess); {
bool background = false;
/// handle signal for main context bool debug = false;
void bool singleThreaded = false;
llarp_main_signal(struct llarp_main *ptr, int sig); };
/// give main context a vpn file descriptor pair (android/ios)
void
llarp_main_inject_vpn_fd(struct llarp_main *m, int rfd, int wfd);
/// setup main context, returns 0 on success /// llarp_application config
int struct llarp_config;
llarp_main_setup(struct llarp_main *ptr);
/// run main context, returns 0 on success, blocks until program end /// get default config for current platform
int struct llarp_config *
llarp_main_run(struct llarp_main *ptr, bool backgroundMode); llarp_default_config();
/// free main context and end all operations /// free previously allocated configuration
void void
llarp_main_free(struct llarp_main *ptr); llarp_config_free(struct llarp_config *);
/// packet writer to send packets to lokinet internals
struct llarp_vpn_writer_pipe;
/// packet reader to recv packets from lokinet internals
struct llarp_vpn_reader_pipe;
/// vpn io api
/// all hooks called in native code
/// for use with a vpn interface managed by external code
/// the external vpn interface MUST be up and have addresses set
struct llarp_vpn_io
{
/// private implementation
void *impl;
/// user data
void *user;
/// hook set by user called by lokinet core when lokinet is done with the
/// vpn io
void (*closed)(struct llarp_vpn_io *);
/// hook set by user called from lokinet core after attempting to inject
/// into endpoint passed a bool set to true if we were injected otherwise
/// set to false
void (*injected)(struct llarp_vpn_io *, bool);
/// hook set by user called every event loop tick
void (*tick)(struct llarp_vpn_io *);
};
#ifdef __cplusplus /// info about the network interface that we give to lokinet core
struct llarp_vpn_ifaddr_info
{
/// name of the network interface
char ifname[64];
/// interface's address as string
char ifaddr[128];
/// netmask number of bits set
uint8_t netmask;
};
/// initialize llarp_vpn_io private implementation
/// returns false if either parameter is nullptr
bool
llarp_vpn_io_init(struct llarp_main *m, struct llarp_vpn_io *io);
/// get the packet pipe for writing IP packets to lokinet internals
/// returns nullptr if llarp_vpn_io is nullptr or not initialized
struct llarp_vpn_pkt_writer *
llarp_vpn_io_packet_writer(struct llarp_vpn_io *io);
/// get the packet pipe for reading IP packets from lokinet internals
/// returns nullptr if llarp_vpn_io is nullptr or not initialized
struct llarp_vpn_pkt_reader *
llarp_vpn_io_packet_reader(struct llarp_vpn_io *io);
/// blocking read on packet reader from lokinet internals
/// returns -1 on error, returns size of packet read
/// thread safe
ssize_t
llarp_vpn_io_readpkt(struct llarp_vpn_pkt_reader *r, unsigned char *dst,
size_t dstlen);
/// blocking write on packet writer to lokinet internals
/// returns false if we can't write this packet
/// return true if we wrote this packet
/// thread safe
bool
llarp_vpn_io_writepkt(struct llarp_vpn_pkt_writer *w, unsigned char *pktbuf,
size_t pktlen);
/// close vpn io and free private implementation after done
/// operation is async and calls llarp_vpn_io.closed after fully closed
/// after fully closed the llarp_vpn_io MUST be re-initialized by
/// llarp_vpn_io_init if it is to be used again
void void
llarp_main_abort(struct llarp_main *ptr); llarp_vpn_io_close_async(struct llarp_vpn_io *io);
/// get the default endpoint's name for injection
const char * const char *
handleBaseCmdLineArgs(int argc, char *argv[]); llarp_main_get_default_endpoint_name(struct llarp_main *m);
/// load nodeDB into memory /// give main context a vpn io for mobile when it is reader to do io with
int /// associated info tries to give the vpn io to endpoint with name epName a
llarp_main_loadDatabase(struct llarp_main *ptr); /// deferred call to llarp_vpn_io.injected is queued unconditionally
/// thread safe
/// iterator on nodedb entries bool
int llarp_main_inject_vpn_by_name(struct llarp_main *m, const char *epName,
llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_vpn_io *io,
struct llarp_nodedb_iter i); struct llarp_vpn_ifaddr_info info);
/// give main context a vpn io on its default endpoint
static bool
llarp_main_inject_default_vpn(struct llarp_main *m, struct llarp_vpn_io *io,
struct llarp_vpn_ifaddr_info info)
{
return llarp_main_inject_vpn_by_name(
m, llarp_main_get_default_endpoint_name(m), io, info);
}
/// put RC into nodeDB /// load config from file by name
/// allocates new config and puts it into c
/// return false on failure
bool bool
llarp_main_putDatabase(struct llarp_main *ptr, llarp_config_load_file(const char *fname, struct llarp_config **c);
struct llarp::RouterContact &rc);
// fwd declr /// loads config from file by name
struct check_online_request; /// uses already allocated config
/// return false on failure
bool
llarp_config_read_file(struct llarp_config *c, const char *f);
/// check_online_request hook definition /// make a main context from configuration
typedef void (*check_online_request_hook_func)(struct check_online_request *); /// copies config contents
struct llarp_main *
llarp_main_init_from_config(struct llarp_config *conf);
struct check_online_request /// initialize application context and load config
static struct llarp_main *
llarp_main_init(const char *fname)
{ {
struct llarp_main *ptr; struct llarp_main *m = 0;
struct llarp_router_lookup_job *job; struct llarp_config *conf = 0;
bool online; if(!llarp_config_load_file(fname, &conf))
size_t nodes; return 0;
bool first; if(conf == NULL)
check_online_request_hook_func hook; return 0;
}; m = llarp_main_init_from_config(conf);
llarp_config_free(conf);
return m;
}
/// initialize applicatin context with all defaults
static struct llarp_main *
llarp_main_default_init()
{
struct llarp_main *m;
struct llarp_config *conf;
conf = llarp_default_config();
if(conf == 0)
return 0;
m = llarp_main_init_from_config(conf);
llarp_config_free(conf);
return m;
}
/// (re)configure main context
/// return true if (re)configuration was successful
bool
llarp_main_configure(struct llarp_main *ptr, struct llarp_config *conf);
/// get RC from DHT but wait until online /// return true if this main context is running
void /// return false otherwise
llarp_main_queryDHT(struct check_online_request *request); bool
llarp_main_is_running(struct llarp_main *ptr);
/// get RC from DHT /// handle signal for main context
void void
llarp_main_queryDHT_RC(struct llarp_main *ptr, llarp_main_signal(struct llarp_main *ptr, int sig);
struct llarp_router_lookup_job *job);
/// set up DNS libs with a context /// setup main context, returns 0 on success
bool int
llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd, llarp_main_setup(struct llarp_main *ptr);
const llarp::Addr &dnsd_sockaddr,
const llarp::Addr &dnsc_sockaddr);
/// set up dotLokiLookup with logic for setting timers /// run main context, returns 0 on success, blocks until program end
bool int
llarp_main_init_dotLokiLookup(struct llarp_main *ptr, llarp_main_run(struct llarp_main *ptr, struct llarp_main_runtime_opts opts);
struct dotLokiLookup *dll);
/// tell main context to stop and wait for complete stop
/// after calling this you can call llarp_main_free safely
void
llarp_main_stop(struct llarp_main *ptr);
/// free main context and end all operations
void
llarp_main_free(struct llarp_main *ptr);
llarp::RouterContact * /// get version string
llarp_main_getLocalRC(struct llarp_main *ptr); const char *
/// get RC from nodeDB llarp_version();
llarp::RouterContact *
llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk);
llarp_tun_io * /// return sizeof(llarp_main); for jni
main_router_getRange(struct llarp_main *ptr); size_t
llarp_main_size();
/// map an (host byte order) ip to a hidden service address /// return sizeof(llarp_config); for jni
bool size_t
main_router_mapAddress(struct llarp_main *ptr, llarp_config_size();
const llarp::service::Address &addr, uint32_t ip);
/// info of possible path usage #ifdef __cplusplus
bool
main_router_prefetch(struct llarp_main *ptr,
const llarp::service::Address &addr);
} }
#endif #endif
#endif #endif

@ -1,6 +1,6 @@
#ifndef LLARP_HPP #ifndef LLARP_HPP
#define LLARP_HPP #define LLARP_HPP
#include <llarp.h>
#include <util/fs.hpp> #include <util/fs.hpp>
#include <util/types.hpp> #include <util/types.hpp>
#include <ev/ev.hpp> #include <ev/ev.hpp>
@ -43,6 +43,10 @@ namespace llarp
struct Context struct Context
{ {
/// get context from main pointer
static Context *
Get(llarp_main *);
Context(); Context();
~Context(); ~Context();
@ -71,24 +75,32 @@ namespace llarp
int int
LoadDatabase(); LoadDatabase();
int
IterateDatabase(llarp_nodedb_iter &i);
bool
PutDatabase(struct llarp::RouterContact &rc);
llarp::RouterContact *
GetDatabase(const byte_t *pk);
int int
Setup(); Setup();
int int
Run(bool daemonMode); Run(llarp_main_runtime_opts opts);
void void
HandleSignal(int sig); HandleSignal(int sig);
bool
Configure();
/// close async
void
CloseAsync();
/// wait until closed and done
void
Wait();
/// call a function in logic thread
/// return true if queued for calling
/// return false if not queued for calling
bool
CallSafe(std::function< void(void) > f);
private: private:
void void
SetPIDFile(const std::string &fname); SetPIDFile(const std::string &fname);
@ -99,9 +111,6 @@ namespace llarp
void void
RemovePIDFile() const; RemovePIDFile() const;
bool
Configure();
void void
SigINT(); SigINT();
@ -116,10 +125,8 @@ namespace llarp
std::string configfile; std::string configfile;
std::string pidfile; std::string pidfile;
std::unique_ptr< std::promise< void > > closeWaiter;
}; };
} // namespace llarp } // namespace llarp
llarp::Context *
llarp_main_get_context(llarp_main *m);
#endif #endif

@ -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

@ -78,6 +78,7 @@ set(LIB_PLATFORM_SRC
# for networking # for networking
ev/ev.cpp ev/ev.cpp
ev/pipe.cpp ev/pipe.cpp
ev/vpnio.cpp
net/ip.cpp net/ip.cpp
net/net.cpp net/net.cpp
net/net_addr.cpp net/net_addr.cpp

@ -1,5 +1,5 @@
#include <llarp.hpp> #include <llarp.hpp>
#include <llarp.h> #include <constants/version.hpp>
#include <config/config.hpp> #include <config/config.hpp>
#include <crypto/crypto_libsodium.hpp> #include <crypto/crypto_libsodium.hpp>
@ -7,8 +7,10 @@
#include <dht/context.hpp> #include <dht/context.hpp>
#include <dnsd.hpp> #include <dnsd.hpp>
#include <ev/ev.hpp> #include <ev/ev.hpp>
#include <ev/vpnio.hpp>
#include <nodedb.hpp> #include <nodedb.hpp>
#include <router/router.hpp> #include <router/router.hpp>
#include <service/context.hpp>
#include <util/logging/logger.h> #include <util/logging/logger.h>
#include <util/meta/memfn.hpp> #include <util/meta/memfn.hpp>
#include <util/metrics/json_publisher.hpp> #include <util/metrics/json_publisher.hpp>
@ -34,6 +36,12 @@ namespace llarp
m_scheduler->stop(); m_scheduler->stop();
} }
bool
Context::CallSafe(std::function< void(void) > f)
{
return logic && logic->queue_func(std::move(f));
}
void void
Context::progress() Context::progress()
{ {
@ -45,11 +53,14 @@ namespace llarp
{ {
logic = std::make_shared< Logic >(); logic = std::make_shared< Logic >();
// llarp::LogInfo("loading config at ", configfile); // llarp::LogInfo("loading config at ", configfile);
if(!config->Load(configfile.c_str())) if(configfile.size())
{ {
config.release(); if(!config->Load(configfile.c_str()))
llarp::LogError("failed to load config file ", configfile); {
return false; config.release();
llarp::LogError("failed to load config file ", configfile);
return false;
}
} }
// System config // System config
@ -176,22 +187,6 @@ __ ___ ____ _ _ ___ _ _ ____
return 1; return 1;
} }
bool
Context::PutDatabase(__attribute__((unused)) struct llarp::RouterContact &rc)
{
// FIXME
// return llarp_nodedb_put_rc(nodedb, rc);
return false;
}
llarp::RouterContact *
Context::GetDatabase(__attribute__((unused)) const byte_t *pk)
{
// FIXME
// return llarp_nodedb_get_rc(nodedb, pk);
return nullptr;
}
int int
Context::Setup() Context::Setup()
{ {
@ -222,7 +217,7 @@ __ ___ ____ _ _ ___ _ _ ____
} }
int int
Context::Run(bool backgroundMode) Context::Run(llarp_main_runtime_opts opts)
{ {
if(router == nullptr) if(router == nullptr)
{ {
@ -236,7 +231,7 @@ __ ___ ____ _ _ ___ _ _ ____
if(!router->StartJsonRpc()) if(!router->StartJsonRpc())
return 1; return 1;
if(!backgroundMode) if(!opts.background)
{ {
if(!router->Run()) if(!router->Run())
return 2; return 2;
@ -245,10 +240,34 @@ __ ___ ____ _ _ ___ _ _ ____
// run net io thread // run net io thread
llarp::LogInfo("running mainloop"); llarp::LogInfo("running mainloop");
llarp_ev_loop_run_single_process(mainloop, logic); llarp_ev_loop_run_single_process(mainloop, logic);
// waits for router graceful stop if(closeWaiter)
{
// inform promise if called by CloseAsync
closeWaiter->set_value();
}
return 0; return 0;
} }
void
Context::CloseAsync()
{
/// already closing
if(closeWaiter)
return;
if(CallSafe(std::bind(&Context::HandleSignal, this, SIGTERM)))
closeWaiter = std::make_unique< std::promise< void > >();
}
void
Context::Wait()
{
if(closeWaiter)
{
closeWaiter->get_future().wait();
closeWaiter.reset();
}
}
bool bool
Context::WritePIDFile() const Context::WritePIDFile() const
{ {
@ -377,37 +396,87 @@ __ ___ ____ _ _ ___ _ _ ____
struct llarp_main struct llarp_main
{ {
llarp_main(llarp_config *conf);
~llarp_main() = default;
std::unique_ptr< llarp::Context > ctx; std::unique_ptr< llarp::Context > ctx;
}; };
llarp::Context * struct llarp_config
llarp_main_get_context(llarp_main *m)
{ {
return m->ctx.get(); llarp::Config impl;
} llarp_config() = default;
llarp_config(const llarp_config *other) : impl(other->impl)
{
}
};
extern "C" extern "C"
{ {
size_t
llarp_main_size()
{
return sizeof(llarp_main);
}
size_t
llarp_config_size()
{
return sizeof(llarp_config);
}
struct llarp_config *
llarp_default_config()
{
llarp_config *conf = new llarp_config();
#ifdef ANDROID
// put andrid config overrides here
#endif
#ifdef IOS
// put IOS config overrides here
#endif
return conf;
}
void
llarp_config_free(struct llarp_config *conf)
{
if(conf)
delete conf;
}
struct llarp_main * struct llarp_main *
llarp_main_init(const char *fname, bool multiProcess) llarp_main_init_from_config(struct llarp_config *conf)
{ {
(void)multiProcess; if(conf == nullptr)
if(!fname)
fname = "daemon.ini";
char *var = getenv("LLARP_DEBUG");
if(var && *var == '1')
{
cSetLogLevel(eLogDebug);
}
auto *m = new llarp_main;
m->ctx = std::make_unique< llarp::Context >();
if(!m->ctx->LoadConfig(fname))
{
m->ctx->Close();
delete m;
return nullptr; return nullptr;
llarp_main *m = new llarp_main(conf);
if(m->ctx->Configure())
return m;
delete m;
return nullptr;
}
bool
llarp_config_read_file(struct llarp_config *conf, const char *fname)
{
if(conf == nullptr)
return false;
return conf->impl.Load(fname);
}
bool
llarp_config_load_file(const char *fname, struct llarp_config **conf)
{
llarp_config *c = new llarp_config();
if(c->impl.Load(fname))
{
*conf = c;
return true;
} }
return m; delete c;
*conf = nullptr;
return false;
} }
void void
@ -424,47 +493,97 @@ extern "C"
} }
int int
llarp_main_run(struct llarp_main *ptr, bool backgroundMode) llarp_main_run(struct llarp_main *ptr, struct llarp_main_runtime_opts opts)
{ {
if(!ptr) return ptr->ctx->Run(opts);
{
llarp::LogError("No ptr passed in");
return 1;
}
return ptr->ctx->Run(backgroundMode);
} }
void const char *
llarp_main_abort(struct llarp_main *ptr) llarp_version()
{ {
ptr->ctx->router->logic()->stop_timer(); return LLARP_VERSION;
} }
void ssize_t
llarp_main_queryDHT_RC(struct llarp_main *ptr, llarp_vpn_io_readpkt(struct llarp_vpn_pkt_reader *r, unsigned char *dst,
struct llarp_router_lookup_job *job) size_t dstlen)
{ {
llarp_dht_lookup_router(ptr->ctx->router->dht(), job); if(r == nullptr)
return -1;
if(not r->queue.enabled())
return -1;
auto pkt = r->queue.popFront();
ManagedBuffer mbuf = pkt.ConstBuffer();
const llarp_buffer_t &buf = mbuf;
if(buf.sz > dstlen || buf.sz == 0)
return -1;
std::copy_n(buf.base, buf.sz, dst);
return buf.sz;
} }
bool bool
llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd, llarp_vpn_io_writepkt(struct llarp_vpn_pkt_writer *w, unsigned char *pktbuf,
const llarp::Addr &dnsd_sockaddr, size_t pktlen)
const llarp::Addr &dnsc_sockaddr)
{ {
return llarp_dnsd_init(dnsd, ptr->ctx->logic.get(), if(pktlen == 0 || pktbuf == nullptr)
ptr->ctx->mainloop.get(), dnsd_sockaddr, return false;
dnsc_sockaddr); if(w == nullptr)
return false;
llarp_vpn_pkt_queue::Packet_t pkt;
llarp_buffer_t buf(pktbuf, pktlen);
if(not pkt.Load(buf))
return false;
return w->queue.pushBack(std::move(pkt))
== llarp::thread::QueueReturn::Success;
} }
bool bool
llarp_main_init_dotLokiLookup(struct llarp_main *ptr, llarp_main_inject_vpn_by_name(struct llarp_main *ptr, const char *name,
struct dotLokiLookup *dll) struct llarp_vpn_io *io,
struct llarp_vpn_ifaddr_info info)
{ {
(void)ptr; if(name == nullptr || io == nullptr)
(void)dll; return false;
// TODO: gut me if(ptr == nullptr || ptr->ctx == nullptr || ptr->ctx->router == nullptr)
return false; return false;
auto ep = ptr->ctx->router->hiddenServiceContext().GetEndpointByName(name);
return ep && ep->InjectVPN(io, info);
}
void
llarp_vpn_io_close_async(struct llarp_vpn_io *io)
{
if(io == nullptr || io->impl == nullptr)
return;
static_cast< llarp_vpn_io_impl * >(io->impl)->AsyncClose();
}
bool
llarp_vpn_io_init(struct llarp_main *ptr, struct llarp_vpn_io *io)
{
if(io == nullptr || ptr == nullptr)
return false;
llarp_vpn_io_impl *impl = new llarp_vpn_io_impl(ptr, io);
io->impl = impl;
return true;
}
struct llarp_vpn_pkt_writer *
llarp_vpn_io_packet_writer(struct llarp_vpn_io *io)
{
if(io == nullptr || io->impl == nullptr)
return nullptr;
llarp_vpn_io_impl *vpn = static_cast< llarp_vpn_io_impl * >(io->impl);
return &vpn->writer;
}
struct llarp_vpn_pkt_reader *
llarp_vpn_io_packet_reader(struct llarp_vpn_io *io)
{
if(io == nullptr || io->impl == nullptr)
return nullptr;
llarp_vpn_io_impl *vpn = static_cast< llarp_vpn_io_impl * >(io->impl);
return &vpn->reader;
} }
void void
@ -473,49 +592,52 @@ extern "C"
delete ptr; delete ptr;
} }
int const char *
llarp_main_loadDatabase(struct llarp_main *ptr) llarp_main_get_default_endpoint_name(struct llarp_main *)
{ {
return ptr->ctx->LoadDatabase(); return "default";
} }
const char * void
handleBaseCmdLineArgs(int argc, char *argv[]) llarp_main_stop(struct llarp_main *ptr)
{ {
// clang-format off if(ptr == nullptr)
cxxopts::Options options( return;
"lokinet", ptr->ctx->CloseAsync();
"Lokinet is a private, decentralized and IP based overlay network for the internet" ptr->ctx->Wait();
); }
options.add_options()
("c,config", "Config file", cxxopts::value< std::string >()->default_value("daemon.ini"))
("o,logLevel", "logging level");
// clang-format on
auto result = options.parse(argc, argv);
std::string logLevel = result["logLevel"].as< std::string >();
if(logLevel == "debug")
{
cSetLogLevel(eLogDebug);
}
else if(logLevel == "info")
{
cSetLogLevel(eLogInfo);
}
else if(logLevel == "warn")
{
cSetLogLevel(eLogWarn);
}
else if(logLevel == "error")
{
cSetLogLevel(eLogError);
}
// this isn't thread safe, but reconfiguring during run is likely unsafe bool
// either way llarp_main_configure(struct llarp_main *ptr, struct llarp_config *conf)
static std::string confname = result["config"].as< std::string >(); {
if(ptr == nullptr || conf == nullptr)
return false;
// give new config
ptr->ctx->config.reset(new llarp::Config(conf->impl));
return ptr->ctx->Configure();
}
return confname.c_str(); bool
llarp_main_is_running(struct llarp_main *ptr)
{
return ptr && ptr->ctx->router && ptr->ctx->router->IsRunning();
} }
} }
llarp_main::llarp_main(llarp_config *conf)
: ctx(new llarp::Context())
{
ctx->config.reset(new llarp::Config(conf->impl));
}
namespace llarp
{
Context *
Context::Get(llarp_main *m)
{
if(m == nullptr || m->ctx == nullptr)
return nullptr;
return m->ctx.get();
}
} // namespace llarp

@ -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

@ -24,10 +24,12 @@ namespace llarp
{ {
namespace handlers namespace handlers
{ {
static llarp_fd_promise * void
get_tun_fd_promise(llarp_tun_io *tun) TunEndpoint::FlushToUser(std::function< bool(net::IPPacket &) > send)
{ {
return static_cast< TunEndpoint * >(tun->user)->Promise.get(); m_ExitMap.ForEachValue([](const auto &exit) { exit->FlushDownstream(); });
// flush network to user
m_NetworkToUserPktQueue.Process(send);
} }
static void static void
@ -38,7 +40,7 @@ namespace llarp
} }
TunEndpoint::TunEndpoint(const std::string &nickname, AbstractRouter *r, TunEndpoint::TunEndpoint(const std::string &nickname, AbstractRouter *r,
service::Context *parent) service::Context *parent, bool lazyVPN)
: service::Endpoint(nickname, r, parent) : service::Endpoint(nickname, r, parent)
, m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop(), , m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop(),
r->netloop()) r->netloop())
@ -47,22 +49,19 @@ namespace llarp
, m_Resolver(std::make_shared< dns::Proxy >( , m_Resolver(std::make_shared< dns::Proxy >(
r->netloop(), r->logic(), r->netloop(), r->logic(), this)) r->netloop(), r->logic(), r->netloop(), r->logic(), this))
{ {
std::fill(tunif.ifaddr, tunif.ifaddr + sizeof(tunif.ifaddr), 0); if(not lazyVPN)
std::fill(tunif.ifname, tunif.ifname + sizeof(tunif.ifname), 0); {
tunif.netmask = 0; tunif.reset(new llarp_tun_io());
std::fill(tunif->ifaddr, tunif->ifaddr + sizeof(tunif->ifaddr), 0);
#ifdef ANDROID std::fill(tunif->ifname, tunif->ifname + sizeof(tunif->ifname), 0);
tunif.get_fd_promise = &get_tun_fd_promise; tunif->netmask = 0;
Promise.reset(new llarp_fd_promise(&m_VPNPromise)); tunif->get_fd_promise = nullptr;
#else tunif->user = this;
tunif.get_fd_promise = nullptr; // eh this shouldn't do anything on windows anyway
#endif tunif->tick = &tunifTick;
tunif.user = this; tunif->before_write = &tunifBeforeWrite;
tunif->recvpkt = &tunifRecvPkt;
// eh this shouldn't do anything on windows anyway }
tunif.tick = &tunifTick;
tunif.before_write = &tunifBeforeWrite;
tunif.recvpkt = &tunifRecvPkt;
} }
util::StatusObject util::StatusObject
@ -241,18 +240,18 @@ namespace llarp
} }
return MapAddress(addr, ipv6, false); return MapAddress(addr, ipv6, false);
} }
if(k == "ifname") if(k == "ifname" && tunif)
{ {
if(v.length() >= sizeof(tunif.ifname)) if(v.length() >= sizeof(tunif->ifname))
{ {
llarp::LogError(Name() + " ifname '", v, "' is too long"); llarp::LogError(Name() + " ifname '", v, "' is too long");
return false; return false;
} }
strncpy(tunif.ifname, v.c_str(), sizeof(tunif.ifname) - 1); strncpy(tunif->ifname, v.c_str(), sizeof(tunif->ifname) - 1);
llarp::LogInfo(Name() + " setting ifname to ", tunif.ifname); llarp::LogInfo(Name() + " setting ifname to ", tunif->ifname);
return true; return true;
} }
if(k == "ifaddr") if(k == "ifaddr" && tunif)
{ {
std::string addr; std::string addr;
m_UseV6 = addr.find(":") != std::string::npos; m_UseV6 = addr.find(":") != std::string::npos;
@ -268,8 +267,8 @@ namespace llarp
#endif #endif
if(num > 0) if(num > 0)
{ {
tunif.netmask = num; tunif->netmask = num;
addr = v.substr(0, pos); addr = v.substr(0, pos);
} }
else else
{ {
@ -280,14 +279,14 @@ namespace llarp
else else
{ {
if(m_UseV6) if(m_UseV6)
tunif.netmask = 128; tunif->netmask = 128;
else else
tunif.netmask = 32; tunif->netmask = 32;
addr = v; addr = v;
} }
llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ",
tunif.netmask); tunif->netmask);
strncpy(tunif.ifaddr, addr.c_str(), sizeof(tunif.ifaddr) - 1); strncpy(tunif->ifaddr, addr.c_str(), sizeof(tunif->ifaddr) - 1);
return true; return true;
} }
return Endpoint::SetOption(k, v); return Endpoint::SetOption(k, v);
@ -585,80 +584,120 @@ namespace llarp
bool bool
TunEndpoint::SetupTun() TunEndpoint::SetupTun()
{ {
lazy_vpn vpn;
huint32_t ip;
auto loop = EndpointNetLoop(); auto loop = EndpointNetLoop();
if(!llarp_ev_add_tun(loop.get(), &tunif)) if(tunif == nullptr)
{
llarp::LogError(Name(),
" failed to set up tun interface: ", tunif.ifaddr,
" on ", tunif.ifname);
return false;
}
struct addrinfo hint, *res = nullptr;
int ret;
memset(&hint, 0, sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(tunif.ifaddr, nullptr, &hint, &res);
if(ret)
{
llarp::LogError(Name(),
" failed to set up tun interface, cant determine "
"family from ",
tunif.ifaddr);
return false;
}
/*
// output is in network byte order
unsigned char buf[sizeof(struct in6_addr)];
int s = inet_pton(res->ai_family, tunif.ifaddr, buf);
if (s <= 0)
{
llarp::LogError(Name(), " failed to set up tun interface, cant parse
", tunif.ifaddr); return false;
}
*/
if(res->ai_family == AF_INET6)
{ {
m_UseV6 = true; llarp::LogInfo(Name(), " waiting for vpn to start");
} vpn = m_LazyVPNPromise.get_future().get();
vpnif = vpn.io;
if(vpnif == nullptr)
{
llarp::LogError(Name(), " failed to recieve vpn interface");
return false;
}
llarp::LogInfo(Name(), " got vpn interface");
auto self = shared_from_this();
// function to queue a packet to send to vpn interface
auto sendpkt = [self](net::IPPacket &pkt) -> bool {
// drop if no endpoint
auto impl = self->GetVPNImpl();
// drop if no vpn interface
if(impl == nullptr)
return true;
// drop if queue to vpn not enabled
if(not impl->reader.queue.enabled())
return true;
// drop if queue to vpn full
if(impl->reader.queue.full())
return true;
// queue to reader
impl->reader.queue.pushBack(pkt);
return false;
};
// event loop ticker
auto ticker = [self, sendpkt]() {
TunEndpoint *ep = self.get();
const bool running = not ep->IsStopped();
auto impl = ep->GetVPNImpl();
if(impl)
{
/// get packets from vpn
while(not impl->writer.queue.empty())
{
// queue it to be sent over lokinet
auto pkt = impl->writer.queue.popFront();
if(running)
ep->m_UserToNetworkPktQueue.Emplace(pkt);
}
}
freeaddrinfo(res); // process packets queued from vpn
if(m_UseV6) if(running)
{ {
llarp::LogInfo(Name(), " using IPV6"); ep->Flush();
ep->FlushToUser(sendpkt);
}
// if impl has a tick function call it
if(impl && impl->parent && impl->parent->tick)
impl->parent->tick(impl->parent);
};
if(not loop->add_ticker(ticker))
{
llarp::LogError(Name(), " failed to add vpn to event loop");
if(vpnif->injected)
vpnif->injected(vpnif, false);
return false;
}
} }
else else
{ {
struct in_addr addr; // network byte order if(!llarp_ev_add_tun(loop.get(), tunif.get()))
if(inet_aton(tunif.ifaddr, &addr) == 0)
{ {
llarp::LogError(Name(), llarp::LogError(Name(),
" failed to set up tun interface, cant parse ", " failed to set up tun interface: ", tunif->ifaddr,
tunif.ifaddr); " on ", tunif->ifname);
return false; return false;
} }
} }
huint32_t ip; const char *ifname;
if(ip.FromString(tunif.ifaddr)) const char *ifaddr;
unsigned char netmask;
if(tunif)
{
ifname = tunif->ifname;
ifaddr = tunif->ifaddr;
netmask = tunif->netmask;
}
else
{
ifname = vpn.info.ifname;
ifaddr = vpn.info.ifaddr;
netmask = vpn.info.netmask;
}
if(ip.FromString(ifaddr))
{ {
m_OurIP = net::IPPacket::ExpandV4(ip); m_OurIP = net::IPPacket::ExpandV4(ip);
m_OurRange.netmask_bits = netmask_ipv6_bits(tunif.netmask + 96); m_OurRange.netmask_bits = netmask_ipv6_bits(netmask + 96);
} }
else if(m_OurIP.FromString(tunif.ifaddr)) else if(m_OurIP.FromString(ifaddr))
{ {
m_OurRange.netmask_bits = netmask_ipv6_bits(tunif.netmask); m_OurRange.netmask_bits = netmask_ipv6_bits(netmask);
m_UseV6 = true;
}
else
{
LogError(Name(), " invalid interface address given, ifaddr=", ifaddr);
if(vpnif && vpnif->injected)
vpnif->injected(vpnif, false);
return false;
} }
m_NextIP = m_OurIP; m_NextIP = m_OurIP;
m_OurRange.addr = m_OurIP; m_OurRange.addr = m_OurIP;
m_MaxIP = m_OurRange.HighestAddr(); m_MaxIP = m_OurRange.HighestAddr();
llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", llarp::LogInfo(Name(), " set ", ifname, " to have address ", m_OurIP);
m_OurIP);
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ",
m_OurRange); m_OurRange);
@ -667,6 +706,10 @@ namespace llarp
{ {
m_OnUp->NotifyAsync(NotifyParams()); m_OnUp->NotifyAsync(NotifyParams());
} }
if(vpnif && vpnif->injected)
{
vpnif->injected(vpnif, true);
}
return true; return true;
} }
@ -676,7 +719,8 @@ namespace llarp
auto env = Endpoint::NotifyParams(); auto env = Endpoint::NotifyParams();
env.emplace("IP_ADDR", m_OurIP.ToString()); env.emplace("IP_ADDR", m_OurIP.ToString());
env.emplace("IF_ADDR", m_OurRange.ToString()); env.emplace("IF_ADDR", m_OurRange.ToString());
env.emplace("IF_NAME", tunif.ifname); if(tunif)
env.emplace("IF_NAME", tunif->ifname);
std::string strictConnect; std::string strictConnect;
for(const auto &addr : m_StrictConnectAddrs) for(const auto &addr : m_StrictConnectAddrs)
strictConnect += addr.ToString() + " "; strictConnect += addr.ToString() + " ";
@ -929,20 +973,17 @@ namespace llarp
TunEndpoint::tunifBeforeWrite(llarp_tun_io *tun) TunEndpoint::tunifBeforeWrite(llarp_tun_io *tun)
{ {
// called in the isolated network thread // called in the isolated network thread
auto *self = static_cast< TunEndpoint * >(tun->user); auto *self = static_cast< TunEndpoint * >(tun->user);
// flush user to network auto sendpkt = [self, tun](net::IPPacket &pkt) -> bool {
self->EndpointLogic()->queue_func(
std::bind(&TunEndpoint::FlushSend, self));
// flush exit traffic queues if it's there
self->EndpointLogic()->queue_func([self] {
self->m_ExitMap.ForEachValue(
[](const auto &exit) { exit->FlushDownstream(); });
});
// flush network to user
self->m_NetworkToUserPktQueue.Process([tun](net::IPPacket &pkt) {
if(!llarp_ev_tun_async_write(tun, pkt.Buffer())) if(!llarp_ev_tun_async_write(tun, pkt.Buffer()))
llarp::LogWarn("packet dropped"); {
}); llarp::LogWarn(self->Name(), " packet dropped");
return true;
}
return false;
};
self->EndpointLogic()->queue_func(std::bind(
&TunEndpoint::FlushToUser, self->shared_from_this(), sendpkt));
} }
void void

@ -3,6 +3,7 @@
#include <dns/server.hpp> #include <dns/server.hpp>
#include <ev/ev.h> #include <ev/ev.h>
#include <ev/vpnio.hpp>
#include <net/ip.hpp> #include <net/ip.hpp>
#include <net/net.hpp> #include <net/net.hpp>
#include <service/endpoint.hpp> #include <service/endpoint.hpp>
@ -20,7 +21,7 @@ namespace llarp
public std::enable_shared_from_this< TunEndpoint > public std::enable_shared_from_this< TunEndpoint >
{ {
TunEndpoint(const std::string& nickname, AbstractRouter* r, TunEndpoint(const std::string& nickname, AbstractRouter* r,
llarp::service::Context* parent); llarp::service::Context* parent, bool lazyVPN = false);
~TunEndpoint() override; ~TunEndpoint() override;
path::PathSet_ptr path::PathSet_ptr
@ -114,8 +115,17 @@ namespace llarp
bool bool
HasLocalIP(const huint128_t& ip) const; HasLocalIP(const huint128_t& ip) const;
llarp_tun_io tunif; std::unique_ptr< llarp_tun_io > tunif;
std::unique_ptr< llarp_fd_promise > Promise; llarp_vpn_io* vpnif = nullptr;
bool
InjectVPN(llarp_vpn_io* io, llarp_vpn_ifaddr_info info)
{
if(tunif)
return false;
m_LazyVPNPromise.set_value(lazy_vpn{info, io});
return true;
}
/// called before writing to tun interface /// called before writing to tun interface
static void static void
@ -206,6 +216,14 @@ namespace llarp
m_SNodes; m_SNodes;
private: private:
llarp_vpn_io_impl*
GetVPNImpl()
{
if(vpnif && vpnif->impl)
return static_cast< llarp_vpn_io_impl* >(vpnif->impl);
return nullptr;
}
bool bool
QueueInboundPacketForExit(const llarp_buffer_t& buf) QueueInboundPacketForExit(const llarp_buffer_t& buf)
{ {
@ -255,12 +273,6 @@ namespace llarp
reply(*query); reply(*query);
delete query; delete query;
} }
#ifndef WIN32
/// handles fd injection force android
std::promise< std::pair< int, int > > m_VPNPromise;
#endif
/// our dns resolver /// our dns resolver
std::shared_ptr< dns::Proxy > m_Resolver; std::shared_ptr< dns::Proxy > m_Resolver;
@ -283,6 +295,18 @@ namespace llarp
std::vector< llarp::Addr > m_StrictConnectAddrs; std::vector< llarp::Addr > m_StrictConnectAddrs;
/// use v6? /// use v6?
bool m_UseV6; bool m_UseV6;
struct lazy_vpn
{
llarp_vpn_ifaddr_info info;
llarp_vpn_io* io;
};
std::promise< lazy_vpn > m_LazyVPNPromise;
/// send packets on endpoint to user using send function
/// send function returns true to indicate stop iteration and do codel
/// drop
void
FlushToUser(std::function< bool(net::IPPacket&) > sendfunc);
}; };
} // namespace handlers } // namespace handlers
} // namespace llarp } // namespace llarp

@ -90,20 +90,24 @@ namespace llarp
if(pkt.sz > sizeof(buf)) if(pkt.sz > sizeof(buf))
return false; return false;
sz = pkt.sz; sz = pkt.sz;
memcpy(buf, pkt.base, sz); std::copy_n(pkt.base, sz, buf);
return true; return true;
} }
llarp_buffer_t ManagedBuffer
IPPacket::ConstBuffer() const IPPacket::ConstBuffer() const
{ {
return {buf, sz}; const byte_t *ptr = buf;
llarp_buffer_t b(ptr, sz);
return ManagedBuffer(b);
} }
llarp_buffer_t ManagedBuffer
IPPacket::Buffer() IPPacket::Buffer()
{ {
return {buf, sz}; byte_t *ptr = buf;
llarp_buffer_t b(ptr, sz);
return ManagedBuffer(b);
} }
huint32_t huint32_t

@ -116,10 +116,10 @@ namespace llarp
size_t sz; size_t sz;
byte_t buf[MaxSize]; byte_t buf[MaxSize];
llarp_buffer_t ManagedBuffer
Buffer(); Buffer();
llarp_buffer_t ManagedBuffer
ConstBuffer() const; ConstBuffer() const;
bool bool

@ -132,6 +132,9 @@ namespace llarp
virtual bool virtual bool
Run() = 0; Run() = 0;
virtual bool
IsRunning() const = 0;
/// stop running the router logic gracefully /// stop running the router logic gracefully
virtual void virtual void
Stop() = 0; Stop() = 0;

@ -1040,6 +1040,12 @@ namespace llarp
return _running; return _running;
} }
bool
Router::IsRunning() const
{
return _running;
}
llarp_time_t llarp_time_t
Router::Uptime() const Router::Uptime() const
{ {

@ -310,6 +310,9 @@ namespace llarp
bool bool
InitServiceNode(); InitServiceNode();
bool
IsRunning() const override;
/// return true if we are running in service node mode /// return true if we are running in service node mode
bool bool
IsServiceNode() const; IsServiceNode() const;

@ -20,23 +20,18 @@ namespace llarp
{"tun", {"tun",
[](const std::string &nick, AbstractRouter *r, [](const std::string &nick, AbstractRouter *r,
service::Context *c) -> service::Endpoint_ptr { service::Context *c) -> service::Endpoint_ptr {
return std::make_shared< handlers::TunEndpoint >(nick, r, c); return std::make_shared< handlers::TunEndpoint >(nick, r, c,
false);
}}, }},
{"android-tun", {"android",
[](const std::string &, AbstractRouter *, [](const std::string &nick, AbstractRouter *r,
service::Context *) -> service::Endpoint_ptr { service::Context *c) -> service::Endpoint_ptr {
return nullptr; return std::make_shared< handlers::TunEndpoint >(nick, r, c, true);
/// SOOOOOOON (tm)
// return std::make_shared<handlers::AndroidTunEndpoint>(nick,
// r, c);
}}, }},
{"ios-tun", {"ios",
[](const std::string &, AbstractRouter *, [](const std::string &nick, AbstractRouter *r,
service::Context *) -> service::Endpoint_ptr { service::Context *c) -> service::Endpoint_ptr {
return nullptr; return std::make_shared< handlers::TunEndpoint >(nick, r, c, true);
/// SOOOOOOON (tm)
// return std::make_shared<handlers::IOSTunEndpoint>(nick, r,
// c);
}}, }},
{"null", {"null",
[](const std::string &nick, AbstractRouter *r, [](const std::string &nick, AbstractRouter *r,
@ -133,12 +128,22 @@ namespace llarp
return m_Endpoints.size() ? true : false; return m_Endpoints.size() ? true : false;
} }
static const char *
DefaultEndpointType()
{
#ifdef ANDROID
return "android";
#else
return "tun";
#endif
}
bool bool
Context::AddDefaultEndpoint( Context::AddDefaultEndpoint(
const std::unordered_multimap< std::string, std::string > &opts) const std::unordered_multimap< std::string, std::string > &opts)
{ {
Config::section_values_t configOpts; Config::section_values_t configOpts;
configOpts.push_back({"type", "tun"}); configOpts.push_back({"type", DefaultEndpointType()});
{ {
auto itr = opts.begin(); auto itr = opts.begin();
while(itr != opts.end()) while(itr != opts.end())
@ -167,6 +172,15 @@ namespace llarp
return true; return true;
} }
Endpoint_ptr
Context::GetEndpointByName(const std::string &name)
{
auto itr = m_Endpoints.find(name);
if(itr != m_Endpoints.end())
return itr->second;
return nullptr;
}
bool bool
Context::AddEndpoint(const Config::section_t &conf, bool autostart) Context::AddEndpoint(const Config::section_t &conf, bool autostart)
{ {
@ -180,7 +194,7 @@ namespace llarp
} }
} }
// extract type // extract type
std::string endpointType = "tun"; std::string endpointType = DefaultEndpointType();
std::string keyfile; std::string keyfile;
for(const auto &option : conf.second) for(const auto &option : conf.second)
{ {

@ -51,6 +51,9 @@ namespace llarp
bool bool
RemoveEndpoint(const std::string &name); RemoveEndpoint(const std::string &name);
Endpoint_ptr
GetEndpointByName(const std::string &name);
bool bool
StartAll(); StartAll();

@ -1,6 +1,6 @@
#ifndef LLARP_SERVICE_ENDPOINT_HPP #ifndef LLARP_SERVICE_ENDPOINT_HPP
#define LLARP_SERVICE_ENDPOINT_HPP #define LLARP_SERVICE_ENDPOINT_HPP
#include <llarp.h>
#include <dht/messages/gotrouter.hpp> #include <dht/messages/gotrouter.hpp>
#include <ev/ev.h> #include <ev/ev.h>
#include <exit/session.hpp> #include <exit/session.hpp>
@ -105,6 +105,14 @@ namespace llarp
return false; return false;
} }
/// inject vpn io
/// return false if not supported
virtual bool
InjectVPN(llarp_vpn_io*, llarp_vpn_ifaddr_info)
{
return false;
}
/// get our ifaddr if it is set /// get our ifaddr if it is set
virtual huint128_t virtual huint128_t
GetIfAddr() const GetIfAddr() const
@ -254,9 +262,6 @@ namespace llarp
bool bool
ShouldBundleRC() const override; ShouldBundleRC() const override;
static void
HandlePathDead(void*);
/// return true if we have a convotag as an exit session /// return true if we have a convotag as an exit session
/// or as a hidden service session /// or as a hidden service session
/// set addr and issnode /// set addr and issnode

Loading…
Cancel
Save