From f11266972e81a6db65aeecc3f77fe2b47418385c Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Fri, 30 Mar 2018 15:50:30 +0300 Subject: [PATCH] Change jni to build executable. Clone with minimal changes DaemonUnix into DaemonAndroid --- android/jni/Android.mk | 8 +- android/jni/Application.mk | 8 +- android/jni/DaemonAndroid.cpp | 334 +++++++++++----------- android/jni/DaemonAndroid.h | 129 ++++----- android/jni/i2pd_android.cpp | 66 ----- android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 33 --- 6 files changed, 227 insertions(+), 351 deletions(-) delete mode 100755 android/jni/i2pd_android.cpp delete mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index d5a8f05f..90284995 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -12,15 +12,15 @@ LOCAL_STATIC_LIBRARIES := \ miniupnpc LOCAL_LDLIBS := -lz -LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \ +LOCAL_SRC_FILES := DaemonAndroid.cpp $(IFADDRS_PATH)/ifaddrs.c \ $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/Daemon.cpp \ $(DAEMON_SRC_PATH)/UPnP.cpp \ $(DAEMON_SRC_PATH)/HTTPServer.cpp \ - $(DAEMON_SRC_PATH)/I2PControl.cpp - -include $(BUILD_SHARED_LIBRARY) + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/i2pd.cpp +include $(BUILD_EXECUTABLE) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0fa116c2..acc6f895 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,12 +9,14 @@ APP_PLATFORM := android-14 # http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse NDK_TOOLCHAIN_VERSION := 4.9 # APP_STL := stlport_shared --> does not seem to contain C++11 features -APP_STL := gnustl_shared +#APP_STL := gnustl_shared +APP_STL := gnustl_static # Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 +APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif @@ -26,7 +28,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /path/to/libraries +I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..94c679be 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,193 +1,193 @@ #include "DaemonAndroid.h" -#include "Daemon.h" -#include -#include -#include -#include -//#include "mainwindow.h" -namespace i2p -{ -namespace android -{ -/* Worker::Worker (DaemonAndroidImpl& daemon): - m_Daemon (daemon) - { - } +#ifndef _WIN32 - void Worker::startDaemon() - { - Log.d(TAG"Performing daemon start..."); - m_Daemon.start(); - Log.d(TAG"Daemon started."); - emit resultReady(); - } - void Worker::restartDaemon() - { - Log.d(TAG"Performing daemon restart..."); - m_Daemon.restart(); - Log.d(TAG"Daemon restarted."); - emit resultReady(); - } - void Worker::stopDaemon() { - Log.d(TAG"Performing daemon stop..."); - m_Daemon.stop(); - Log.d(TAG"Daemon stopped."); - emit resultReady(); - } +#include +#include +#include +#include +#include +#include +#include - Controller::Controller(DaemonAndroidImpl& daemon): - m_Daemon (daemon) - { - Worker *worker = new Worker (m_Daemon); - worker->moveToThread(&workerThread); - connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); - connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); - connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); - connect(worker, &Worker::resultReady, this, &Controller::handleResults); - workerThread.start(); - } - Controller::~Controller() - { - Log.d(TAG"Closing and waiting for daemon worker thread..."); - workerThread.quit(); - workerThread.wait(); - Log.d(TAG"Waiting for daemon worker thread finished."); - if(m_Daemon.isRunning()) - { - Log.d(TAG"Stopping the daemon..."); - m_Daemon.stop(); - Log.d(TAG"Stopped the daemon."); - } - } -*/ - DaemonAndroidImpl::DaemonAndroidImpl () - //: - /*mutex(nullptr), */ - //m_IsRunning(false), - //m_RunningChangedCallback(nullptr) - { - } +#include "Config.h" +#include "FS.h" +#include "Log.h" +#include "Tunnel.h" +#include "RouterContext.h" +#include "ClientContext.h" - DaemonAndroidImpl::~DaemonAndroidImpl () - { - //delete mutex; - } - - bool DaemonAndroidImpl::init(int argc, char* argv[]) - { - //mutex=new QMutex(QMutex::Recursive); - //setRunningCallback(0); - //m_IsRunning=false; - return Daemon.init(argc,argv); - } - - void DaemonAndroidImpl::start() - { - //QMutexLocker locker(mutex); - //setRunning(true); - Daemon.start(); +void handle_signal(int sig) +{ + switch (sig) + { + case SIGHUP: + LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration..."); + i2p::client::context.ReloadConfig(); + break; + case SIGUSR1: + LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs..."); + i2p::log::Logger().Reopen (); + break; + case SIGINT: + if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) + { + i2p::context.SetAcceptsTunnels (false); + Daemon.gracefulShutdownInterval = 10*60; // 10 minutes + LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); + } + else + Daemon.running = 0; + break; + case SIGABRT: + case SIGTERM: + Daemon.running = 0; // Exit loop + break; + case SIGPIPE: + LogPrint(eLogInfo, "SIGPIPE received"); + break; } +} - void DaemonAndroidImpl::stop() +namespace i2p +{ + namespace util { - //QMutexLocker locker(mutex); - Daemon.stop(); - //setRunning(false); - } + bool DaemonAndroid::start() + { + if (isDaemon) + { + pid_t pid; + pid = fork(); + if (pid > 0) // parent + ::exit (EXIT_SUCCESS); - void DaemonAndroidImpl::restart() - { - //QMutexLocker locker(mutex); - stop(); - start(); - } - /* - void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) - { - m_RunningChangedCallback = cb; - } + if (pid < 0) // error + { + LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); + return false; + } - bool DaemonAndroidImpl::isRunning() - { - return m_IsRunning; - } + // child + umask(S_IWGRP | S_IRWXO); // 0027 + int sid = setsid(); + if (sid < 0) + { + LogPrint(eLogError, "Daemon: could not create process group."); + return false; + } + std::string d = i2p::fs::GetDataDir(); + if (chdir(d.c_str()) != 0) + { + LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); + return false; + } - void DaemonAndroidImpl::setRunning(bool newValue) - { - bool oldValue = m_IsRunning; - if(oldValue!=newValue) - { - m_IsRunning = newValue; - if(m_RunningChangedCallback) - m_RunningChangedCallback(); - } - } -*/ - static DaemonAndroidImpl daemon; - static char* argv[1]={strdup("tmp")}; - /** - * returns error details if failed - * returns "ok" if daemon initialized and started okay - */ - std::string start(/*int argc, char* argv[]*/) - { - try - { - //int result; + // point std{in,out,err} descriptors to /dev/null + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + } + // set proc limits + struct rlimit limit; + uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); + getrlimit(RLIMIT_NOFILE, &limit); + if (nfiles == 0) { + LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); + } else if (nfiles <= limit.rlim_max) { + limit.rlim_cur = nfiles; + if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { + LogPrint(eLogInfo, "Daemon: set max number of open files to ", + nfiles, " (system limit is ", limit.rlim_max, ")"); + } else { + LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); + } + } else { + LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); + } + uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); + if (cfsize) // core file size set { - //Log.d(TAG"Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(1,argv); - if(!daemonInitSuccess) - { - //QMessageBox::critical(0, "Error", "Daemon init failed"); - return "Daemon init failed"; + cfsize *= 1024; + getrlimit(RLIMIT_CORE, &limit); + if (cfsize <= limit.rlim_max) { + limit.rlim_cur = cfsize; + if (setrlimit(RLIMIT_CORE, &limit) != 0) { + LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); + } else if (cfsize == 0) { + LogPrint(eLogInfo, "Daemon: coredumps disabled"); + } else { + LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); + } + } else { + LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); } - //Log.d(TAG"Initialised, creating the main window..."); - //MainWindow w; - //Log.d(TAG"Before main window.show()..."); - //w.show (); + } + // Pidfile + // this code is c-styled and a bit ugly + std::string pidfile; i2p::config::GetOption("pidfile", pidfile); + if (pidfile == "") { + pidfile = i2p::fs::DataDirPath("i2pd.pid"); + } + if (pidfile != "") { + pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); + if (pidFH < 0) + { + LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); + return false; + } + char pid[10]; + sprintf(pid, "%d\n", getpid()); + ftruncate(pidFH, 0); + if (write(pidFH, pid, strlen(pid)) < 0) { - //i2p::qt::Controller daemonQtController(daemon); - //Log.d(TAG"Starting the daemon..."); - //emit daemonQtController.startDaemon(); - //daemon.start (); - //Log.d(TAG"Starting GUI event loop..."); - //result = app.exec(); - //daemon.stop (); - daemon.start(); + LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); + return false; } } + gracefulShutdownInterval = 0; // not specified - //QMessageBox::information(&w, "Debug", "demon stopped"); - //Log.d(TAG"Exiting the application"); - //return result; - } - catch (boost::exception& ex) - { - std::stringstream ss; - ss << boost::diagnostic_information(ex); - return ss.str(); + // Signal handler + struct sigaction sa; + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + + return Daemon_Singleton::start(); } - catch (std::exception& ex) + + bool DaemonAndroid::stop() { - std::stringstream ss; - ss << ex.what(); - return ss.str(); + i2p::fs::Remove(pidfile); + + return Daemon_Singleton::stop(); } - catch(...) + + void DaemonAndroid::run () { - return "unknown exception"; + while (running) + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + if (gracefulShutdownInterval) + { + gracefulShutdownInterval--; // - 1 second + if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0) + { + LogPrint(eLogInfo, "Graceful shutdown"); + return; + } + } + } } - return "ok"; - } - - void stop() - { - daemon.stop(); } } -} + +#endif diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index 9cc8219b..c62d7c76 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -1,87 +1,60 @@ -#ifndef DAEMON_ANDROID_H -#define DAEMON_ANDROID_H +#ifndef DAEMON_H__ +#define DAEMON_H__ +#include #include namespace i2p { -namespace android +namespace util { - class DaemonAndroidImpl - { - public: - - DaemonAndroidImpl (); - ~DaemonAndroidImpl (); - - //typedef void (*runningChangedCallback)(); - - /** - * @return success - */ - bool init(int argc, char* argv[]); - void start(); - void stop(); - void restart(); - //void setRunningCallback(runningChangedCallback cb); - //bool isRunning(); - private: - //void setRunning(bool running); - private: - //QMutex* mutex; - //bool m_IsRunning; - //runningChangedCallback m_RunningChangedCallback; - }; - - /** - * returns "ok" if daemon init failed - * returns errinfo if daemon initialized and started okay - */ - std::string start(); - - // stops the daemon - void stop(); - - /* - class Worker : public QObject - { - Q_OBJECT - public: - - Worker (DaemonAndroidImpl& daemon); - - private: - - DaemonAndroidImpl& m_Daemon; - - public slots: - void startDaemon(); - void restartDaemon(); - void stopDaemon(); - - signals: - void resultReady(); - }; - - class Controller : public QObject - { - Q_OBJECT - QThread workerThread; - public: - Controller(DaemonAndroidImpl& daemon); - ~Controller(); - private: - DaemonAndroidImpl& m_Daemon; - - public slots: - void handleResults(){} - signals: - void startDaemon(); - void stopDaemon(); - void restartDaemon(); - }; - */ + class Daemon_Singleton_Private; + class Daemon_Singleton + { + public: + virtual bool init(int argc, char* argv[]); + virtual bool start(); + virtual bool stop(); + virtual void run () {}; + + bool isDaemon; + bool running; + + protected: + Daemon_Singleton(); + virtual ~Daemon_Singleton(); + + bool IsService () const; + + // d-pointer for httpServer, httpProxy, etc. + class Daemon_Singleton_Private; + Daemon_Singleton_Private &d; + }; + +#if defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + class DaemonAndroid : public Daemon_Singleton + { + public: + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } + + bool start(); + bool stop(); + void run (); + + private: + std::string pidfile; + int pidFH; + + public: + int gracefulShutdownInterval; // in seconds + }; +#endif } } -#endif // DAEMON_ANDROID_H +#endif // DAEMON_H__ diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp deleted file mode 100755 index 8791c90b..00000000 --- a/android/jni/i2pd_android.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -//#include -#include -#include "org_purplei2p_i2pd_I2PD_JNI.h" -#include "DaemonAndroid.h" -#include "RouterContext.h" -#include "Transports.h" - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv * env, jclass clazz) { -#if defined(__arm__) - #if defined(__ARM_ARCH_7A__) - #if defined(__ARM_NEON__) - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a/NEON (hard-float)" - #else - #define ABI "armeabi-v7a/NEON" - #endif - #else - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a (hard-float)" - #else - #define ABI "armeabi-v7a" - #endif - #endif - #else - #define ABI "armeabi" - #endif -#elif defined(__i386__) - #define ABI "x86" -#elif defined(__x86_64__) - #define ABI "x86_64" -#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ - #define ABI "mips64" -#elif defined(__mips__) - #define ABI "mips" -#elif defined(__aarch64__) - #define ABI "arm64-v8a" -#else - #define ABI "unknown" -#endif - - return env->NewStringUTF(ABI); -} - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv * env, jclass clazz) { - return env->NewStringUTF(i2p::android::start().c_str()); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv * env, jclass clazz) { - i2p::android::stop(); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv * env, jclass clazz) { - i2p::context.SetAcceptsTunnels (false); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected) -{ - bool isConnectedBool = (bool) isConnected; - i2p::transport::transports.SetOnline (isConnectedBool); -} diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h deleted file mode 100644 index 04923d22..00000000 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ /dev/null @@ -1,33 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class org_purplei2p_i2pd_I2PD_JNI */ - -#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI -#define _Included_org_purplei2p_i2pd_I2PD_JNI -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_purplei2p_i2pd_I2PD_JNI - * Method: stringFromJNI - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv *, jclass); - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected); - -#ifdef __cplusplus -} -#endif -#endif