diff --git a/CMakeLists.txt b/CMakeLists.txt index c09709eee..d1166178d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ option(ASAN "use address sanitiser, if your system has it" ) option(JEMALLOC "use jemalloc. Not required on BSD" ) option(DEBIAN "build for debian" ) option(TESTNET "testnet build" ) +option(WITH_SHARED "build shared library") if(WIN32) set(CMAKE_CXX_STANDARD 17) @@ -86,6 +87,10 @@ if(AMD_RYZEN_HACK AND USE_AVX2) set(CRYPTO_FLAGS -march=native -mfpmath=sse -mavx -mavx2 -mfma) endif(AMD_RYZEN_HACK AND USE_AVX2) +if(WITH_SHARED) + set(CRYPTO_FLAGS ${CRYPTO_FLAGS} -fPIC) +endif() + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads REQUIRED) @@ -189,7 +194,7 @@ if(ANDROID) endif(ANDROID) set(LIB lokinet) -set(SHARED_LIB ${LIB}) +set(SHARED_LIB ${LIB}-shared) set(STATIC_LIB ${LIB}-static) set(CRYPTOGRAPHY_LIB ${LIB}-cryptography) set(PLATFORM_LIB ${LIB}-platform) @@ -706,46 +711,45 @@ endif(NOT WIN32) install(CODE "execute_process(COMMAND setcap cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)") endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") -if(WITH_STATIC) - add_library(${STATIC_LIB} STATIC ${LIB_SRC}) - add_library(${PLATFORM_LIB} STATIC ${LIB_PLATFORM_SRC}) - if(USE_LIBABYSS) - target_link_libraries(${PLATFORM_LIB} Threads::Threads ${ABYSS_LIB}) + add_library(${STATIC_LIB} STATIC ${LIB_SRC}) + add_library(${PLATFORM_LIB} STATIC ${LIB_PLATFORM_SRC}) + if(USE_LIBABYSS) + target_link_libraries(${PLATFORM_LIB} Threads::Threads ${ABYSS_LIB}) + else() + target_link_libraries(${PLATFORM_LIB} Threads::Threads) + endif(USE_LIBABYSS) + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + if(NON_PC_TARGET) + target_link_libraries(${PLATFORM_LIB} -lrt) else() - target_link_libraries(${PLATFORM_LIB} Threads::Threads) - endif(USE_LIBABYSS) - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - if(NON_PC_TARGET) - target_link_libraries(${PLATFORM_LIB} -lrt) - else() - target_link_libraries(${PLATFORM_LIB} -lcap) - endif(NON_PC_TARGET) - endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - target_link_libraries(${STATIC_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${PLATFORM_LIB}) - if(NOT WITH_SHARED) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) - #target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) - #target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) - target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB}) - #target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB}) - if (WIN32) - target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) - #target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) - #target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) - target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) - #target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) - endif(WIN32) - endif(NOT WITH_SHARED) - endif(WITH_STATIC) + target_link_libraries(${PLATFORM_LIB} -lcap) + endif(NON_PC_TARGET) + endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(${STATIC_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${PLATFORM_LIB}) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) + #target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) + #target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB}) + target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB}) + #target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB}) + if (WIN32) + target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) + #target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) + #target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) + target_link_libraries(${TEST_EXE} ${STATIC_LINK_LIBS} gtest_main ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) + #target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi) + endif(WIN32) + + if(ANDROID) add_library(${ANDROID_LIB} SHARED jni/lokinet_android.cpp) target_link_libraries(${ANDROID_LIB} ${STATIC_LIB} ${LIBS}) endif(ANDROID) if(WITH_SHARED) - add_library(${SHARED_LIB} SHARED ${LIB_SRC} ${LIB_PLATFORM_SRC} ${CRYPTOGRAPHY_SRC}) - target_link_libraries(${SHARED_LIB} ${LIBS} Threads::Threads) - target_link_libraries(${EXE} ${SHARED_LIB}) + add_library(${SHARED_LIB} SHARED ${LIB_SRC}) + target_link_libraries(${SHARED_LIB} ${CRYPTOGRAPHY_LIB} ${LIBS} ${PLATFORM_LIB} Threads::Threads) + #target_link_libraries(${EXE} ${SHARED_LIB}) + #target_link_libraries(${TEST_EXE} ${SHARED_LIB}) #target_link_libraries(${RC_EXE} ${SHARED_LIB}) #target_link_libraries(${DNS_EXE} ${SHARED_LIB} Threads::Threads) endif(WITH_SHARED) diff --git a/Makefile b/Makefile index f05520c90..4798a360e 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,8 @@ release-configure: clean debug: debug-configure $(MAKE) -C $(BUILD_ROOT) cp $(EXE) lokinet + cp $(BUILD_ROOT)/liblokinet-shared.so liblokinet-shared.so + release-compile: release-configure $(MAKE) -C $(BUILD_ROOT) diff --git a/contrib/kubernetes/lokinet.py b/contrib/kubernetes/lokinet.py new file mode 100644 index 000000000..de1c815bd --- /dev/null +++ b/contrib/kubernetes/lokinet.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +# +# lokinet kubernetes runtime wrapper +# + +from ctypes import * +import configparser +import signal +import time +import threading +import os +import sys +import requests + +lib_file = os.path.join(os.path.realpath('.'), 'liblokinet-shared.so') + + +def log(msg): + sys.stderr.write("lokinet: {}\n".format(msg)) + sys.stderr.flush() + +class LokiNET(threading.Thread): + + lib = None + ctx = 0 + failed = False + up = False + + asRouter = True + + def configure(self, lib, conf, ip=None, port=None, ifname=None): + log("configure lib={} conf={}".format(lib, conf)) + try: + self.lib = CDLL(lib) + except OSError as ex: + log("failed to load library: {}".format(ex)) + return False + if self.lib.llarp_ensure_config(conf.encode('utf-8'), os.path.dirname(conf).encode('utf-8'), True, self.asRouter): + config = configparser.ConfigParser() + config.read(conf) + log('overwrite ip="{}" port="{}" ifname="{}"'.format(ip, port, ifname)) + if ip: + config['router']['public-address'] = '{}'.format(ip) + if port: + config['router']['public-port'] = '{}'.format(port) + if ifname and port: + config['bind'] = { + ifname: '{}'.format(port) + } + with open(conf, "w") as f: + config.write(f) + self.ctx = self.lib.llarp_main_init(conf.encode('utf-8')) + else: + return False + return self.lib.llarp_main_setup(self.ctx) == 0 + + + def inform_fail(self): + """ + inform lokinet crashed + """ + self.failed = True + self._inform() + + def inform_up(self): + self.up = True + self._inform() + + def _inform(self): + """ + inform waiter + """ + + def wait_for_up(self, timeout): + """ + wait for lokinet to go up for :timeout: seconds + :return True if we are up and running otherwise False: + """ + # return self._up.wait(timeout) + + def signal(self, sig): + if self.ctx and self.lib: + self.lib.llarp_main_signal(self.ctx, int(sig)) + + def run(self): + # self._up.acquire() + self.up = True + code = self.lib.llarp_main_run(self.ctx) + log("llarp_main_run exited with status {}".format(code)) + if code: + self.inform_fail() + self.up = False + # self._up.release() + + def close(self): + if self.lib and self.ctx: + self.lib.llarp_main_free(self.ctx) + +def getconf(name, fallback=None): + return name in os.environ and os.environ[name] or fallback + +def main(args): + log("going up") + root = getconf("LOKINET_ROOT") + if root is None: + print("LOKINET_ROOT was not set") + return + + rc_callback = getconf("LOKINET_SUBMIT_URL") + if rc_callback is None: + print("LOKINET_SUBMIT_URL was not set") + return + + lib = getconf("LOKINET_LIB", lib_file) + timeout = int(getconf("LOKINET_TIMEOUT", "5")) + ping_interval = int(getconf("LOKINET_PING_INTERVAL", "60")) + ping_callback = getconf("LOKINET_PING_URL") + ip = getconf("LOKINET_IP") + port = getconf("LOKINET_PORT") + ifname = getconf("LOKINET_IFNAME") + if ping_callback is None: + print("LOKINET_PING_URL was not set") + return + conf = os.path.join(root, "daemon.ini") + loki = LokiNET() + if loki.configure(lib, conf, ip, port, ifname): + log("configured") + loki.start() + try: + log("waiting for spawn") + while timeout > 0: + time.sleep(1) + if loki.failed: + log("failed") + break + log("waiting {}".format(timeout)) + timeout -= 1 + if loki.up: + log("submitting rc") + try: + with open(os.path.join(root, 'self.signed'), 'rb') as f: + r = requests.put(rc_callback, data=f.read(), headers={"content-type": "application/octect-stream"}) + log('submit rc reply: HTTP {}'.format(r.status_code)) + except Exception as ex: + log("failed to submit rc: {}".format(ex)) + while loki.up: + time.sleep(ping_interval) + try: + r = requests.get(ping_callback) + log("ping reply: HTTP {}".format(r.status_code)) + except Exception as ex: + log("failed to submit ping: {}".format(ex)) + else: + log("failed to go up") + loki.signal(signal.SIGINT) + except KeyboardInterrupt: + loki.signal(signal.SIGINT) + time.sleep(2) + finally: + loki.close() + else: + loki.close() + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/contrib/py/ffi-example/lokinet.py b/contrib/py/ffi-example/lokinet.py index e57a8f9f4..3a15361f6 100644 --- a/contrib/py/ffi-example/lokinet.py +++ b/contrib/py/ffi-example/lokinet.py @@ -20,6 +20,16 @@ class LokiNET(threading.Thread): self.ctx = self.lib.llarp_main_init(conf) return self.ctx != 0 + def inform_fail(self): + """ + inform lokinet crashed + """ + + def inform_end(self): + """ + inform lokinet ended clean + """ + def signal(self, sig): if self.ctx and self.lib: @@ -28,7 +38,11 @@ class LokiNET(threading.Thread): def run(self): code = self.lib.llarp_main_run(self.ctx) print("llarp_main_run exited with status {}".format(code)) - + if code: + self.inform_fail() + else: + self.inform_end() + def close(self): if self.lib and self.ctx: self.lib.llarp_main_free(self.ctx) @@ -36,7 +50,10 @@ class LokiNET(threading.Thread): def main(): loki = LokiNET() if loki.load(lib_file, b'daemon.ini'): - loki.start() + if loki.configure(): + loki.start() + else: + print("failed to configure lokinet context") try: while True: time.sleep(1) diff --git a/include/llarp.h b/include/llarp.h index 013d191bf..3e79b4023 100644 --- a/include/llarp.h +++ b/include/llarp.h @@ -21,7 +21,8 @@ extern "C" /// if basedir is not nullptr then use basedir as an absolute /// base path for all files in config bool - llarp_ensure_config(const char *, const char *, bool, bool); + llarp_ensure_config(const char *, const char *, bool overwrite, + bool asrouter); /// llarp application context for C api struct llarp_main; diff --git a/llarp/config.cpp b/llarp/config.cpp index 1488bd5cf..7211502cb 100644 --- a/llarp/config.cpp +++ b/llarp/config.cpp @@ -154,12 +154,8 @@ llarp_generic_ensure_config(std::ofstream &f, std::string basepath) f << "# dns provider configuration section" << std::endl; f << "[dns]" << std::endl; - f << "# opennic us resolver" << std::endl; + f << "# resolver" << std::endl; f << "upstream=" << DEFAULT_RESOLVER_US << std::endl; - f << "# opennic eu resolver" << std::endl; - f << "upstream=" << DEFAULT_RESOLVER_EU << std::endl; - f << "# opennic au resolver" << std::endl; - f << "upstream=" << DEFAULT_RESOLVER_AU << std::endl; // Make auto-config smarter // will this break reproducibility rules? diff --git a/llarp/ev_epoll.cpp b/llarp/ev_epoll.cpp index c06c85b01..8b1378917 100644 --- a/llarp/ev_epoll.cpp +++ b/llarp/ev_epoll.cpp @@ -1 +1 @@ -#include +