#include #include #include #include #include #include #include #include #include #include #include #include #include #if (__FreeBSD__) || (__OpenBSD__) || (__NetBSD__) #include #endif namespace llarp { bool Context::CallSafe(std::function f) { return logic && LogicCall(logic, f); } bool Context::Configure(bool isRelay, std::optional dataDir) { fs::path defaultDataDir = dataDir.has_value() ? dataDir.value() : GetDefaultDataDir(); if (configfile.size()) { if (!config->Load(configfile.c_str(), isRelay, defaultDataDir)) { config.release(); llarp::LogError("failed to load config file ", configfile); return false; } } auto threads = config->router.m_workerThreads; if (threads <= 0) threads = 1; worker = std::make_shared(threads, 1024, "llarp-worker"); auto jobQueueSize = config->router.m_JobQueueSize; if (jobQueueSize < 1024) jobQueueSize = 1024; logic = std::make_shared(jobQueueSize); nodedb_dir = config->router.m_dataDir / nodedb_dirname; return true; } bool Context::IsUp() const { return router && router->IsRunning(); } bool Context::LooksAlive() const { return router && router->LooksAlive(); } int Context::LoadDatabase() { llarp_nodedb::ensure_dir(nodedb_dir.c_str()); return 1; } int Context::Setup() { llarp::LogInfo(llarp::VERSION_FULL, " ", llarp::RELEASE_MOTTO); llarp::LogInfo("starting up"); if (mainloop == nullptr) mainloop = llarp_make_ev_loop(); logic->set_event_loop(mainloop.get()); mainloop->set_logic(logic); crypto = std::make_unique(); cryptoManager = std::make_unique(crypto.get()); router = std::make_unique(worker, mainloop, logic); nodedb = std::make_unique(router->diskworker(), nodedb_dir); if (!router->Configure(config.get(), nodedb.get())) { llarp::LogError("Failed to configure router"); return 1; } // must be done after router is made so we can use its disk io worker // must also be done after configure so that netid is properly set if it // is provided by config if (!this->LoadDatabase()) return 2; return 0; } int Context::Run(llarp_main_runtime_opts opts) { if (router == nullptr) { // we are not set up so we should die llarp::LogError("cannot run non configured context"); return 1; } // run if (!router->StartJsonRpc()) return 1; if (!opts.background) { if (!router->Run()) return 2; } // run net io thread llarp::LogInfo("running mainloop"); llarp_ev_loop_run_single_process(mainloop, logic); 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>(); } void Context::Wait() { if (closeWaiter) { closeWaiter->get_future().wait(); closeWaiter.reset(); } } void Context::HandleSignal(int sig) { if (sig == SIGINT || sig == SIGTERM) { SigINT(); } // TODO: Hot reloading would be kewl // (it used to exist here, but wasn't maintained) } void Context::SigINT() { if (router) { /// async stop router on sigint router->Stop(); } else { if (logic) logic->stop(); llarp_ev_loop_stop(mainloop); Close(); } } void Context::Close() { llarp::LogDebug("stop workers"); if (worker) worker->stop(); llarp::LogDebug("free config"); config.release(); llarp::LogDebug("free workers"); worker.reset(); llarp::LogDebug("free nodedb"); nodedb.release(); llarp::LogDebug("free router"); router.release(); llarp::LogDebug("free logic"); logic.reset(); } bool Context::LoadConfig(const std::string& fname, bool isRelay) { config = std::make_unique(); configfile = fname; const fs::path filepath(fname); return Configure(isRelay, filepath.parent_path()); } #ifdef LOKINET_HIVE void Context::InjectHive(tooling::RouterHive* hive) { router->hive = hive; } #endif } // namespace llarp struct llarp_main { llarp_main(llarp_config* conf); ~llarp_main() = default; std::shared_ptr ctx; }; struct llarp_config { llarp::Config impl; llarp_config() = default; llarp_config(const llarp_config* other) : impl(other->impl) { } }; namespace llarp { llarp_config* Config::Copy() const { llarp_config* ptr = new llarp_config(); ptr->impl = *this; return ptr; } } // namespace llarp 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_from_config(struct llarp_config* conf, bool isRelay) { if (conf == nullptr) return nullptr; llarp_main* m = new llarp_main(conf); if (m->ctx->Configure(isRelay, {})) return m; delete m; return nullptr; } bool llarp_config_load_file(const char* fname, struct llarp_config** conf, bool isRelay) { llarp_config* c = new llarp_config(); const fs::path filepath(fname); if (c->impl.Load(fname, isRelay, filepath.parent_path())) { *conf = c; return true; } delete c; *conf = nullptr; return false; } void llarp_main_signal(struct llarp_main* ptr, int sig) { LogicCall(ptr->ctx->logic, std::bind(&llarp::Context::HandleSignal, ptr->ctx.get(), sig)); } int llarp_main_setup(struct llarp_main* ptr) { return ptr->ctx->Setup(); } int llarp_main_run(struct llarp_main* ptr, struct llarp_main_runtime_opts opts) { return ptr->ctx->Run(opts); } const char* llarp_version() { return llarp::VERSION_FULL; } ssize_t llarp_vpn_io_readpkt(struct llarp_vpn_pkt_reader* r, unsigned char* dst, size_t dstlen) { 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_vpn_io_writepkt(struct llarp_vpn_pkt_writer* w, unsigned char* pktbuf, size_t pktlen) { 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_inject_vpn_by_name( struct llarp_main* ptr, const char* name, struct llarp_vpn_io* io, struct llarp_vpn_ifaddr_info info) { 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(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(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(io->impl); return &vpn->reader; } void llarp_main_free(struct llarp_main* ptr) { delete ptr; } const char* llarp_main_get_default_endpoint_name(struct llarp_main*) { return "default"; } void llarp_main_stop(struct llarp_main* ptr) { if (ptr == nullptr) return; ptr->ctx->CloseAsync(); ptr->ctx->Wait(); } bool llarp_main_configure(struct llarp_main* ptr, struct llarp_config* conf, bool isRelay) { if (ptr == nullptr || conf == nullptr) return false; // give new config ptr->ctx->config.reset(new llarp::Config(conf->impl)); return ptr->ctx->Configure(isRelay, {}); } 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 { std::shared_ptr Context::Get(llarp_main* m) { if (m == nullptr || m->ctx == nullptr) return nullptr; return m->ctx; } } // namespace llarp