diff --git a/CMakeLists.txt b/CMakeLists.txt index 86b8f389c..add84a154 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,8 +167,8 @@ endif() if (NOT MSVC OR NOT MSVC_VERSION) add_compile_options(${OPTIMIZE_FLAGS} ${CRYPTO_FLAGS}) endif() -add_subdirectory(${ABSEIL_DIR}) add_subdirectory(vendor/gtest) +add_subdirectory(${ABSEIL_DIR}) if (FS_LIB STREQUAL "cppbackport") add_subdirectory(vendor) @@ -233,9 +233,6 @@ enable_testing() if (NOT SHADOW) add_subdirectory(test) if(ANDROID) - add_library(${ANDROID_LIB} SHARED jni/lokinet_android.cpp) - set_property(TARGET ${ANDROID_LIB} PROPERTY CXX_STANDARD 14) - add_log_tag(${ANDROID_LIB}) - target_link_libraries(${ANDROID_LIB} ${STATIC_LIB} ${LIBS}) + add_subdirectory(jni) endif(ANDROID) endif() diff --git a/android/src/network/loki/lokinet/LokiNetActivity.java b/android/src/network/loki/lokinet/LokiNetActivity.java index b299a94fd..8654d676b 100755 --- a/android/src/network/loki/lokinet/LokiNetActivity.java +++ b/android/src/network/loki/lokinet/LokiNetActivity.java @@ -33,20 +33,16 @@ import android.widget.TextView; public class LokiNetActivity extends Activity { private static final String TAG = "lokinet-activity"; 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; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - // copy assets - //String conf = copyFileAsset("daemon.ini"); textView = new TextView(this); setContentView(textView); - - Lokinet_JNI.loadLibraries(); + System.loadLibrary("lokinetandroid"); } diff --git a/android/src/network/loki/lokinet/LokinetService.java b/android/src/network/loki/lokinet/LokinetService.java index 9030a1f21..7dbae6236 100644 --- a/android/src/network/loki/lokinet/LokinetService.java +++ b/android/src/network/loki/lokinet/LokinetService.java @@ -5,4 +5,5 @@ import android.net.VpnService; public class LokinetService extends VpnService { + } diff --git a/android/src/network/loki/lokinet/Lokinet_JNI.java b/android/src/network/loki/lokinet/Lokinet_JNI.java deleted file mode 100644 index a5d3cda40..000000000 --- a/android/src/network/loki/lokinet/Lokinet_JNI.java +++ /dev/null @@ -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"); - } -} diff --git a/android/src/network/loki/lokinet/NetworkStateChangeReceiver.java b/android/src/network/loki/lokinet/NetworkStateChangeReceiver.java index d466e75c9..c4d7764fb 100644 --- a/android/src/network/loki/lokinet/NetworkStateChangeReceiver.java +++ b/android/src/network/loki/lokinet/NetworkStateChangeReceiver.java @@ -21,8 +21,6 @@ public class NetworkStateChangeReceiver extends BroadcastReceiver { boolean isConnected = activeNetworkInfo!=null && activeNetworkInfo.isConnected(); // https://developer.android.com/training/monitoring-device-state/connectivity-monitoring.html?hl=ru // boolean isWiFi = activeNetworkInfo!=null && (activeNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI); - - Lokinet_JNI.onNetworkStateChanged(isConnected); } catch (Throwable tr) { Log.d(TAG,"",tr); } diff --git a/contrib/cross/mingw.cmake b/contrib/cross/mingw.cmake index 0a591fb53..94221affd 100644 --- a/contrib/cross/mingw.cmake +++ b/contrib/cross/mingw.cmake @@ -1,6 +1,6 @@ set(CMAKE_SYSTEM_NAME Windows) set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) -set(TOOLCHAIN_SUFFIX "") +set(TOOLCHAIN_SUFFIX "-posix") set(WIN64_CROSS_COMPILE ON) set(TOOLCHAIN_PATHS diff --git a/daemon/main.cpp b/daemon/main.cpp index 22d162a86..e49384025 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef _WIN32 #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 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 llarp::LogDebug("Running from: ", fs::current_path().string()); llarp::LogInfo("Using config file: ", conffname); - ctx = llarp_main_init(conffname.c_str(), multiThreaded); + ctx = llarp_main_init(conffname.c_str()); int code = 1; if(ctx) { @@ -102,7 +103,7 @@ run_main_context(std::string conffname, bool multiThreaded, bool backgroundMode) code = llarp_main_setup(ctx); llarp::util::SetThreadName("llarp-mainloop"); if(code == 0) - code = llarp_main_run(ctx, backgroundMode); + code = llarp_main_run(ctx, opts); llarp_main_free(ctx); } exit_code.set_value(code); @@ -111,11 +112,11 @@ run_main_context(std::string conffname, bool multiThreaded, bool backgroundMode) int main(int argc, char *argv[]) { - bool multiThreaded = true; + llarp_main_runtime_opts opts; const char *singleThreadVar = getenv("LLARP_SHADOW"); if(singleThreadVar && std::string(singleThreadVar) == "1") { - multiThreaded = false; + opts.singleThreaded = true; } #ifdef _WIN32 @@ -148,12 +149,10 @@ main(int argc, char *argv[]) options.parse_positional("config"); // clang-format on - bool genconfigOnly = false; - bool asRouter = false; - bool overWrite = false; - bool backgroundMode = false; + bool genconfigOnly = false; + bool asRouter = false; + bool overWrite = false; std::string conffname; // suggestions: confFName? conf_fname? - try { auto result = options.parse(argc, argv); @@ -178,7 +177,7 @@ main(int argc, char *argv[]) if(result.count("version")) { - std::cout << LLARP_VERSION << std::endl; + std::cout << llarp_version() << std::endl; return 0; } @@ -189,7 +188,7 @@ main(int argc, char *argv[]) if(result.count("background") > 0) { - backgroundMode = true; + opts.background = true; } if(result.count("force") > 0) @@ -315,8 +314,7 @@ main(int argc, char *argv[]) return 0; } - std::thread main_thread{ - std::bind(&run_main_context, conffname, multiThreaded, backgroundMode)}; + std::thread main_thread{std::bind(&run_main_context, conffname, opts)}; auto ftr = exit_code.get_future(); do { @@ -324,11 +322,9 @@ main(int argc, char *argv[]) } while(ftr.wait_for(std::chrono::seconds(1)) != std::future_status::ready); main_thread.join(); - + const auto code = ftr.get(); #ifdef _WIN32 ::WSACleanup(); #endif - const auto code = ftr.get(); - exit(code); return code; } diff --git a/include/llarp.h b/include/llarp.h index 72f4856d5..f1dd044c7 100644 --- a/include/llarp.h +++ b/include/llarp.h @@ -1,15 +1,8 @@ #ifndef LLARP_H_ #define LLARP_H_ - +#include +#include #ifdef __cplusplus -#include -#include -#include // for handlers -#include // for service::address -#include -#include -#include - extern "C" { #endif @@ -27,106 +20,211 @@ extern "C" /// llarp application context for C api struct llarp_main; - /// initialize application context and load config - struct llarp_main * - llarp_main_init(const char *fname, bool multiProcess); - - /// handle signal for main context - void - 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); + /// runtime options for main context from cli + struct llarp_main_runtime_opts + { + bool background = false; + bool debug = false; + bool singleThreaded = false; + }; - /// setup main context, returns 0 on success - int - llarp_main_setup(struct llarp_main *ptr); + /// llarp_application config + struct llarp_config; - /// run main context, returns 0 on success, blocks until program end - int - llarp_main_run(struct llarp_main *ptr, bool backgroundMode); + /// get default config for current platform + struct llarp_config * + llarp_default_config(); - /// free main context and end all operations + /// free previously allocated configuration 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 - 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 * - handleBaseCmdLineArgs(int argc, char *argv[]); + llarp_main_get_default_endpoint_name(struct llarp_main *m); - /// load nodeDB into memory - int - llarp_main_loadDatabase(struct llarp_main *ptr); - - /// iterator on nodedb entries - int - llarp_main_iterateDatabase(struct llarp_main *ptr, - struct llarp_nodedb_iter i); + /// give main context a vpn io for mobile when it is reader to do io with + /// associated info tries to give the vpn io to endpoint with name epName a + /// deferred call to llarp_vpn_io.injected is queued unconditionally + /// thread safe + bool + llarp_main_inject_vpn_by_name(struct llarp_main *m, const char *epName, + struct llarp_vpn_io *io, + 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 - llarp_main_putDatabase(struct llarp_main *ptr, - struct llarp::RouterContact &rc); + llarp_config_load_file(const char *fname, struct llarp_config **c); - // fwd declr - struct check_online_request; + /// loads config from file by name + /// 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 - typedef void (*check_online_request_hook_func)(struct check_online_request *); + /// make a main context from configuration + /// 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_router_lookup_job *job; - bool online; - size_t nodes; - bool first; - check_online_request_hook_func hook; - }; + struct llarp_main *m = 0; + struct llarp_config *conf = 0; + if(!llarp_config_load_file(fname, &conf)) + return 0; + if(conf == NULL) + 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 - void - llarp_main_queryDHT(struct check_online_request *request); + /// return true if this main context is running + /// return false otherwise + bool + llarp_main_is_running(struct llarp_main *ptr); - /// get RC from DHT + /// handle signal for main context void - llarp_main_queryDHT_RC(struct llarp_main *ptr, - struct llarp_router_lookup_job *job); + llarp_main_signal(struct llarp_main *ptr, int sig); - /// set up DNS libs with a context - bool - llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd, - const llarp::Addr &dnsd_sockaddr, - const llarp::Addr &dnsc_sockaddr); + /// setup main context, returns 0 on success + int + llarp_main_setup(struct llarp_main *ptr); - /// set up dotLokiLookup with logic for setting timers - bool - llarp_main_init_dotLokiLookup(struct llarp_main *ptr, - struct dotLokiLookup *dll); + /// run main context, returns 0 on success, blocks until program end + int + llarp_main_run(struct llarp_main *ptr, struct llarp_main_runtime_opts opts); + + /// 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 * - llarp_main_getLocalRC(struct llarp_main *ptr); - /// get RC from nodeDB - llarp::RouterContact * - llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk); + /// get version string + const char * + llarp_version(); - llarp_tun_io * - main_router_getRange(struct llarp_main *ptr); + /// return sizeof(llarp_main); for jni + size_t + llarp_main_size(); - /// map an (host byte order) ip to a hidden service address - bool - main_router_mapAddress(struct llarp_main *ptr, - const llarp::service::Address &addr, uint32_t ip); + /// return sizeof(llarp_config); for jni + size_t + llarp_config_size(); - /// info of possible path usage - bool - main_router_prefetch(struct llarp_main *ptr, - const llarp::service::Address &addr); +#ifdef __cplusplus } #endif #endif diff --git a/include/llarp.hpp b/include/llarp.hpp index 9f34e22bf..ab0d87936 100644 --- a/include/llarp.hpp +++ b/include/llarp.hpp @@ -1,6 +1,6 @@ #ifndef LLARP_HPP #define LLARP_HPP - +#include #include #include #include @@ -43,6 +43,10 @@ namespace llarp struct Context { + /// get context from main pointer + static Context * + Get(llarp_main *); + Context(); ~Context(); @@ -71,24 +75,32 @@ namespace llarp int LoadDatabase(); - int - IterateDatabase(llarp_nodedb_iter &i); - - bool - PutDatabase(struct llarp::RouterContact &rc); - - llarp::RouterContact * - GetDatabase(const byte_t *pk); - int Setup(); int - Run(bool daemonMode); + Run(llarp_main_runtime_opts opts); void 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: void SetPIDFile(const std::string &fname); @@ -99,9 +111,6 @@ namespace llarp void RemovePIDFile() const; - bool - Configure(); - void SigINT(); @@ -116,10 +125,8 @@ namespace llarp std::string configfile; std::string pidfile; + std::unique_ptr< std::promise< void > > closeWaiter; }; } // namespace llarp -llarp::Context * -llarp_main_get_context(llarp_main *m); - #endif diff --git a/jni/CMakeLists.txt b/jni/CMakeLists.txt new file mode 100644 index 000000000..d265d4c87 --- /dev/null +++ b/jni/CMakeLists.txt @@ -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}) \ No newline at end of file diff --git a/jni/lokinet_android.cpp b/jni/lokinet_android.cpp deleted file mode 100644 index 2ecc41243..000000000 --- a/jni/lokinet_android.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -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(); - } - } -} diff --git a/jni/lokinet_config.cpp b/jni/lokinet_config.cpp new file mode 100644 index 000000000..c73cdee3c --- /dev/null +++ b/jni/lokinet_config.cpp @@ -0,0 +1,37 @@ +#include "network_loki_lokinet_LokinetConfig.h" +#include +#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; + }); + } +} \ No newline at end of file diff --git a/jni/lokinet_daemon.cpp b/jni/lokinet_daemon.cpp new file mode 100644 index 000000000..8db0324fb --- /dev/null +++ b/jni/lokinet_daemon.cpp @@ -0,0 +1,83 @@ +#include "network_loki_lokinet_LokinetDaemon.h" +#include "lokinet_jni_common.hpp" +#include "lokinet_jni_vpnio.hpp" +#include + +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; + } +} \ No newline at end of file diff --git a/jni/lokinet_jni_common.hpp b/jni/lokinet_jni_common.hpp new file mode 100644 index 000000000..4ddea9095 --- /dev/null +++ b/jni/lokinet_jni_common.hpp @@ -0,0 +1,85 @@ +#ifndef LOKINET_JNI_COMMON_HPP +#define LOKINET_JNI_COMMON_HPP + +#include +#include +#include + +/// 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 \ No newline at end of file diff --git a/jni/lokinet_jni_vpnio.hpp b/jni/lokinet_jni_vpnio.hpp new file mode 100644 index 000000000..30ca9f9b6 --- /dev/null +++ b/jni/lokinet_jni_vpnio.hpp @@ -0,0 +1,150 @@ +#ifndef LOKINET_JNI_VPNIO_HPP +#define LOKINET_JNI_VPNIO_HPP + +#include +#include +#include +#include +#include +#include + +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 \ No newline at end of file diff --git a/jni/lokinet_vpn.cpp b/jni/lokinet_vpn.cpp new file mode 100644 index 000000000..6febc606c --- /dev/null +++ b/jni/lokinet_vpn.cpp @@ -0,0 +1,86 @@ +#include "network_loki_lokinet_LokinetVPN.h" +#include "lokinet_jni_vpnio.hpp" +#include "lokinet_jni_common.hpp" +#include + +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"); + } +} \ No newline at end of file diff --git a/jni/network_loki_lokinet_LokinetConfig.h b/jni/network_loki_lokinet_LokinetConfig.h new file mode 100644 index 000000000..f39b87542 --- /dev/null +++ b/jni/network_loki_lokinet_LokinetConfig.h @@ -0,0 +1,38 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/jni/network_loki_lokinet_LokinetDaemon.h b/jni/network_loki_lokinet_LokinetDaemon.h new file mode 100644 index 000000000..400807bb6 --- /dev/null +++ b/jni/network_loki_lokinet_LokinetDaemon.h @@ -0,0 +1,70 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/jni/network_loki_lokinet_LokinetVPN.h b/jni/network_loki_lokinet_LokinetVPN.h new file mode 100644 index 000000000..0aca1654f --- /dev/null +++ b/jni/network_loki_lokinet_LokinetVPN.h @@ -0,0 +1,69 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/jni/network_loki_lokinet_LokinetVPN_VPNInfo.h b/jni/network_loki_lokinet_LokinetVPN_VPNInfo.h new file mode 100644 index 000000000..c7937a30f --- /dev/null +++ b/jni/network_loki_lokinet_LokinetVPN_VPNInfo.h @@ -0,0 +1,14 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 264e90ed3..9dc9510a8 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -78,6 +78,7 @@ set(LIB_PLATFORM_SRC # for networking ev/ev.cpp ev/pipe.cpp + ev/vpnio.cpp net/ip.cpp net/net.cpp net/net_addr.cpp diff --git a/llarp/context.cpp b/llarp/context.cpp index e26ab6277..7f88b6107 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -34,6 +36,12 @@ namespace llarp m_scheduler->stop(); } + bool + Context::CallSafe(std::function< void(void) > f) + { + return logic && logic->queue_func(std::move(f)); + } + void Context::progress() { @@ -45,11 +53,14 @@ namespace llarp { logic = std::make_shared< Logic >(); // llarp::LogInfo("loading config at ", configfile); - if(!config->Load(configfile.c_str())) + if(configfile.size()) { - config.release(); - llarp::LogError("failed to load config file ", configfile); - return false; + if(!config->Load(configfile.c_str())) + { + config.release(); + llarp::LogError("failed to load config file ", configfile); + return false; + } } // System config @@ -176,22 +187,6 @@ __ ___ ____ _ _ ___ _ _ ____ 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 Context::Setup() { @@ -222,7 +217,7 @@ __ ___ ____ _ _ ___ _ _ ____ } int - Context::Run(bool backgroundMode) + Context::Run(llarp_main_runtime_opts opts) { if(router == nullptr) { @@ -236,7 +231,7 @@ __ ___ ____ _ _ ___ _ _ ____ if(!router->StartJsonRpc()) return 1; - if(!backgroundMode) + if(!opts.background) { if(!router->Run()) return 2; @@ -245,10 +240,34 @@ __ ___ ____ _ _ ___ _ _ ____ // run net io thread llarp::LogInfo("running mainloop"); 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; } + 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 Context::WritePIDFile() const { @@ -377,37 +396,87 @@ __ ___ ____ _ _ ___ _ _ ____ struct llarp_main { + llarp_main(llarp_config *conf); + ~llarp_main() = default; std::unique_ptr< llarp::Context > ctx; }; -llarp::Context * -llarp_main_get_context(llarp_main *m) +struct llarp_config { - return m->ctx.get(); -} + llarp::Config impl; + llarp_config() = default; + + llarp_config(const llarp_config *other) : impl(other->impl) + { + } +}; 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 * - llarp_main_init(const char *fname, bool multiProcess) + llarp_main_init_from_config(struct llarp_config *conf) { - (void)multiProcess; - 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; + if(conf == 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 @@ -424,47 +493,97 @@ extern "C" } 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) - { - llarp::LogError("No ptr passed in"); - return 1; - } - return ptr->ctx->Run(backgroundMode); + return ptr->ctx->Run(opts); } - void - llarp_main_abort(struct llarp_main *ptr) + const char * + llarp_version() { - ptr->ctx->router->logic()->stop_timer(); + return LLARP_VERSION; } - void - llarp_main_queryDHT_RC(struct llarp_main *ptr, - struct llarp_router_lookup_job *job) + ssize_t + llarp_vpn_io_readpkt(struct llarp_vpn_pkt_reader *r, unsigned char *dst, + 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 - llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd, - const llarp::Addr &dnsd_sockaddr, - const llarp::Addr &dnsc_sockaddr) + llarp_vpn_io_writepkt(struct llarp_vpn_pkt_writer *w, unsigned char *pktbuf, + size_t pktlen) { - return llarp_dnsd_init(dnsd, ptr->ctx->logic.get(), - ptr->ctx->mainloop.get(), dnsd_sockaddr, - dnsc_sockaddr); + if(pktlen == 0 || pktbuf == nullptr) + return false; + 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 - llarp_main_init_dotLokiLookup(struct llarp_main *ptr, - struct dotLokiLookup *dll) + llarp_main_inject_vpn_by_name(struct llarp_main *ptr, const char *name, + struct llarp_vpn_io *io, + struct llarp_vpn_ifaddr_info info) { - (void)ptr; - (void)dll; - // TODO: gut me - return false; + if(name == nullptr || io == nullptr) + return false; + if(ptr == nullptr || ptr->ctx == nullptr || ptr->ctx->router == nullptr) + 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 @@ -473,49 +592,52 @@ extern "C" delete ptr; } - int - llarp_main_loadDatabase(struct llarp_main *ptr) + const char * + llarp_main_get_default_endpoint_name(struct llarp_main *) { - return ptr->ctx->LoadDatabase(); + return "default"; } - const char * - handleBaseCmdLineArgs(int argc, char *argv[]) - { - // clang-format off - cxxopts::Options options( - "lokinet", - "Lokinet is a private, decentralized and IP based overlay network for the internet" - ); - 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); - } + void + llarp_main_stop(struct llarp_main *ptr) + { + if(ptr == nullptr) + return; + ptr->ctx->CloseAsync(); + ptr->ctx->Wait(); + } - // this isn't thread safe, but reconfiguring during run is likely unsafe - // either way - static std::string confname = result["config"].as< std::string >(); + bool + llarp_main_configure(struct llarp_main *ptr, struct llarp_config *conf) + { + 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 diff --git a/llarp/ev/vpnio.cpp b/llarp/ev/vpnio.cpp new file mode 100644 index 000000000..ba107752f --- /dev/null +++ b/llarp/ev/vpnio.cpp @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/llarp/ev/vpnio.hpp b/llarp/ev/vpnio.hpp new file mode 100644 index 000000000..d522ddb29 --- /dev/null +++ b/llarp/ev/vpnio.hpp @@ -0,0 +1,51 @@ +#ifndef LLARP_EV_VPNIO_HPP +#define LLARP_EV_VPNIO_HPP +#include +#include +#include + +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 \ No newline at end of file diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 475b4ba67..837093bfd 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -24,10 +24,12 @@ namespace llarp { namespace handlers { - static llarp_fd_promise * - get_tun_fd_promise(llarp_tun_io *tun) + void + 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 @@ -38,7 +40,7 @@ namespace llarp } TunEndpoint::TunEndpoint(const std::string &nickname, AbstractRouter *r, - service::Context *parent) + service::Context *parent, bool lazyVPN) : service::Endpoint(nickname, r, parent) , m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop(), r->netloop()) @@ -47,22 +49,19 @@ namespace llarp , m_Resolver(std::make_shared< dns::Proxy >( r->netloop(), r->logic(), r->netloop(), r->logic(), this)) { - std::fill(tunif.ifaddr, tunif.ifaddr + sizeof(tunif.ifaddr), 0); - std::fill(tunif.ifname, tunif.ifname + sizeof(tunif.ifname), 0); - tunif.netmask = 0; - -#ifdef ANDROID - tunif.get_fd_promise = &get_tun_fd_promise; - Promise.reset(new llarp_fd_promise(&m_VPNPromise)); -#else - tunif.get_fd_promise = nullptr; -#endif - tunif.user = this; - - // eh this shouldn't do anything on windows anyway - tunif.tick = &tunifTick; - tunif.before_write = &tunifBeforeWrite; - tunif.recvpkt = &tunifRecvPkt; + if(not lazyVPN) + { + tunif.reset(new llarp_tun_io()); + std::fill(tunif->ifaddr, tunif->ifaddr + sizeof(tunif->ifaddr), 0); + std::fill(tunif->ifname, tunif->ifname + sizeof(tunif->ifname), 0); + tunif->netmask = 0; + tunif->get_fd_promise = nullptr; + tunif->user = this; + // eh this shouldn't do anything on windows anyway + tunif->tick = &tunifTick; + tunif->before_write = &tunifBeforeWrite; + tunif->recvpkt = &tunifRecvPkt; + } } util::StatusObject @@ -241,18 +240,18 @@ namespace llarp } 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"); return false; } - strncpy(tunif.ifname, v.c_str(), sizeof(tunif.ifname) - 1); - llarp::LogInfo(Name() + " setting ifname to ", tunif.ifname); + strncpy(tunif->ifname, v.c_str(), sizeof(tunif->ifname) - 1); + llarp::LogInfo(Name() + " setting ifname to ", tunif->ifname); return true; } - if(k == "ifaddr") + if(k == "ifaddr" && tunif) { std::string addr; m_UseV6 = addr.find(":") != std::string::npos; @@ -268,8 +267,8 @@ namespace llarp #endif if(num > 0) { - tunif.netmask = num; - addr = v.substr(0, pos); + tunif->netmask = num; + addr = v.substr(0, pos); } else { @@ -280,14 +279,14 @@ namespace llarp else { if(m_UseV6) - tunif.netmask = 128; + tunif->netmask = 128; else - tunif.netmask = 32; + tunif->netmask = 32; addr = v; } llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", - tunif.netmask); - strncpy(tunif.ifaddr, addr.c_str(), sizeof(tunif.ifaddr) - 1); + tunif->netmask); + strncpy(tunif->ifaddr, addr.c_str(), sizeof(tunif->ifaddr) - 1); return true; } return Endpoint::SetOption(k, v); @@ -585,80 +584,120 @@ namespace llarp bool TunEndpoint::SetupTun() { + lazy_vpn vpn; + huint32_t ip; auto loop = EndpointNetLoop(); - if(!llarp_ev_add_tun(loop.get(), &tunif)) - { - 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) + if(tunif == nullptr) { - 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); - if(m_UseV6) - { - llarp::LogInfo(Name(), " using IPV6"); + // process packets queued from vpn + if(running) + { + 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 { - struct in_addr addr; // network byte order - if(inet_aton(tunif.ifaddr, &addr) == 0) + if(!llarp_ev_add_tun(loop.get(), tunif.get())) { llarp::LogError(Name(), - " failed to set up tun interface, cant parse ", - tunif.ifaddr); + " failed to set up tun interface: ", tunif->ifaddr, + " on ", tunif->ifname); return false; } } - huint32_t ip; - if(ip.FromString(tunif.ifaddr)) + const char *ifname; + 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_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_OurRange.addr = m_OurIP; m_MaxIP = m_OurRange.HighestAddr(); - llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", - m_OurIP); + llarp::LogInfo(Name(), " set ", ifname, " to have address ", m_OurIP); llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", m_OurRange); @@ -667,6 +706,10 @@ namespace llarp { m_OnUp->NotifyAsync(NotifyParams()); } + if(vpnif && vpnif->injected) + { + vpnif->injected(vpnif, true); + } return true; } @@ -676,7 +719,8 @@ namespace llarp auto env = Endpoint::NotifyParams(); env.emplace("IP_ADDR", m_OurIP.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; for(const auto &addr : m_StrictConnectAddrs) strictConnect += addr.ToString() + " "; @@ -929,20 +973,17 @@ namespace llarp TunEndpoint::tunifBeforeWrite(llarp_tun_io *tun) { // called in the isolated network thread - auto *self = static_cast< TunEndpoint * >(tun->user); - // flush user to network - 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) { + auto *self = static_cast< TunEndpoint * >(tun->user); + auto sendpkt = [self, tun](net::IPPacket &pkt) -> bool { 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 diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index 61b60a85b..fc48ec547 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace llarp public std::enable_shared_from_this< TunEndpoint > { TunEndpoint(const std::string& nickname, AbstractRouter* r, - llarp::service::Context* parent); + llarp::service::Context* parent, bool lazyVPN = false); ~TunEndpoint() override; path::PathSet_ptr @@ -114,8 +115,17 @@ namespace llarp bool HasLocalIP(const huint128_t& ip) const; - llarp_tun_io tunif; - std::unique_ptr< llarp_fd_promise > Promise; + std::unique_ptr< llarp_tun_io > tunif; + 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 static void @@ -206,6 +216,14 @@ namespace llarp m_SNodes; private: + llarp_vpn_io_impl* + GetVPNImpl() + { + if(vpnif && vpnif->impl) + return static_cast< llarp_vpn_io_impl* >(vpnif->impl); + return nullptr; + } + bool QueueInboundPacketForExit(const llarp_buffer_t& buf) { @@ -255,12 +273,6 @@ namespace llarp reply(*query); delete query; } - -#ifndef WIN32 - /// handles fd injection force android - std::promise< std::pair< int, int > > m_VPNPromise; -#endif - /// our dns resolver std::shared_ptr< dns::Proxy > m_Resolver; @@ -283,6 +295,18 @@ namespace llarp std::vector< llarp::Addr > m_StrictConnectAddrs; /// use v6? 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 llarp diff --git a/llarp/net/ip.cpp b/llarp/net/ip.cpp index 80df045e3..8dba138d2 100644 --- a/llarp/net/ip.cpp +++ b/llarp/net/ip.cpp @@ -90,20 +90,24 @@ namespace llarp if(pkt.sz > sizeof(buf)) return false; sz = pkt.sz; - memcpy(buf, pkt.base, sz); + std::copy_n(pkt.base, sz, buf); return true; } - llarp_buffer_t + ManagedBuffer 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() { - return {buf, sz}; + byte_t *ptr = buf; + llarp_buffer_t b(ptr, sz); + return ManagedBuffer(b); } huint32_t diff --git a/llarp/net/ip.hpp b/llarp/net/ip.hpp index 83ddf3714..ac1bb9c73 100644 --- a/llarp/net/ip.hpp +++ b/llarp/net/ip.hpp @@ -116,10 +116,10 @@ namespace llarp size_t sz; byte_t buf[MaxSize]; - llarp_buffer_t + ManagedBuffer Buffer(); - llarp_buffer_t + ManagedBuffer ConstBuffer() const; bool diff --git a/llarp/router/abstractrouter.hpp b/llarp/router/abstractrouter.hpp index 08fbf449e..556ad9469 100644 --- a/llarp/router/abstractrouter.hpp +++ b/llarp/router/abstractrouter.hpp @@ -132,6 +132,9 @@ namespace llarp virtual bool Run() = 0; + virtual bool + IsRunning() const = 0; + /// stop running the router logic gracefully virtual void Stop() = 0; diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 9b9e637f3..ab909aab0 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -1040,6 +1040,12 @@ namespace llarp return _running; } + bool + Router::IsRunning() const + { + return _running; + } + llarp_time_t Router::Uptime() const { diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index e2d94536e..4e85e5fe0 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -310,6 +310,9 @@ namespace llarp bool InitServiceNode(); + bool + IsRunning() const override; + /// return true if we are running in service node mode bool IsServiceNode() const; diff --git a/llarp/service/context.cpp b/llarp/service/context.cpp index 072f178d1..cea4d0b50 100644 --- a/llarp/service/context.cpp +++ b/llarp/service/context.cpp @@ -20,23 +20,18 @@ namespace llarp {"tun", [](const std::string &nick, AbstractRouter *r, 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", - [](const std::string &, AbstractRouter *, - service::Context *) -> service::Endpoint_ptr { - return nullptr; - /// SOOOOOOON (tm) - // return std::make_shared(nick, - // r, c); + {"android", + [](const std::string &nick, AbstractRouter *r, + service::Context *c) -> service::Endpoint_ptr { + return std::make_shared< handlers::TunEndpoint >(nick, r, c, true); }}, - {"ios-tun", - [](const std::string &, AbstractRouter *, - service::Context *) -> service::Endpoint_ptr { - return nullptr; - /// SOOOOOOON (tm) - // return std::make_shared(nick, r, - // c); + {"ios", + [](const std::string &nick, AbstractRouter *r, + service::Context *c) -> service::Endpoint_ptr { + return std::make_shared< handlers::TunEndpoint >(nick, r, c, true); }}, {"null", [](const std::string &nick, AbstractRouter *r, @@ -133,12 +128,22 @@ namespace llarp return m_Endpoints.size() ? true : false; } + static const char * + DefaultEndpointType() + { +#ifdef ANDROID + return "android"; +#else + return "tun"; +#endif + } + bool Context::AddDefaultEndpoint( const std::unordered_multimap< std::string, std::string > &opts) { Config::section_values_t configOpts; - configOpts.push_back({"type", "tun"}); + configOpts.push_back({"type", DefaultEndpointType()}); { auto itr = opts.begin(); while(itr != opts.end()) @@ -167,6 +172,15 @@ namespace llarp 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 Context::AddEndpoint(const Config::section_t &conf, bool autostart) { @@ -180,7 +194,7 @@ namespace llarp } } // extract type - std::string endpointType = "tun"; + std::string endpointType = DefaultEndpointType(); std::string keyfile; for(const auto &option : conf.second) { diff --git a/llarp/service/context.hpp b/llarp/service/context.hpp index 9a860e30b..abc5fb716 100644 --- a/llarp/service/context.hpp +++ b/llarp/service/context.hpp @@ -51,6 +51,9 @@ namespace llarp bool RemoveEndpoint(const std::string &name); + Endpoint_ptr + GetEndpointByName(const std::string &name); + bool StartAll(); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 61467540f..68b088e01 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -1,6 +1,6 @@ #ifndef LLARP_SERVICE_ENDPOINT_HPP #define LLARP_SERVICE_ENDPOINT_HPP - +#include #include #include #include @@ -105,6 +105,14 @@ namespace llarp 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 virtual huint128_t GetIfAddr() const @@ -254,9 +262,6 @@ namespace llarp bool ShouldBundleRC() const override; - static void - HandlePathDead(void*); - /// return true if we have a convotag as an exit session /// or as a hidden service session /// set addr and issnode