diff --git a/.gitignore b/.gitignore
index 89a17a3c..b6cffd15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -237,3 +237,4 @@ pip-log.txt
# Sphinx
docs/_build
+/androidIdea/
diff --git a/Daemon.h b/Daemon.h
index fa4f47ec..85b31240 100644
--- a/Daemon.h
+++ b/Daemon.h
@@ -45,6 +45,20 @@ namespace i2p
}
};
+#elif defined(ANDROID)
+#define Daemon i2p::util::DaemonAndroid::Instance()
+ // dummy, invoked from android/jni/DaemonAndroid.*
+ class DaemonAndroid: public i2p::util::Daemon_Singleton
+ {
+ public:
+
+ static DaemonAndroid& Instance()
+ {
+ static DaemonAndroid instance;
+ return instance;
+ }
+ };
+
#elif defined(_WIN32)
#define Daemon i2p::util::DaemonWin32::Instance()
class DaemonWin32 : public Daemon_Singleton
diff --git a/HTTPServer.cpp b/HTTPServer.cpp
index cfcf4261..39ced94a 100644
--- a/HTTPServer.cpp
+++ b/HTTPServer.cpp
@@ -377,7 +377,7 @@ namespace http {
s << " Stop accepting tunnels
\r\n";
else
s << " Start accepting tunnels
\r\n";
-#if (!defined(WIN32) && !defined(QT_GUI_LIB))
+#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (Daemon.gracefullShutdownInterval) {
s << " Cancel gracefull shutdown (";
s << Daemon.gracefullShutdownInterval;
@@ -690,12 +690,12 @@ namespace http {
i2p::context.SetAcceptsTunnels (false);
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
i2p::context.SetAcceptsTunnels (false);
-#if (!defined(WIN32) && !defined(QT_GUI_LIB))
+#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefullShutdownInterval = 10*60;
#endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
i2p::context.SetAcceptsTunnels (true);
-#if (!defined(WIN32) && !defined(QT_GUI_LIB))
+#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefullShutdownInterval = 0;
#endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 00000000..8364f857
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,4 @@
+/gen/
+/libs/
+/tests/
+.idea
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100755
index 00000000..58d46ed8
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
new file mode 100755
index 00000000..bef6d5ec
--- /dev/null
+++ b/android/jni/Android.mk
@@ -0,0 +1,115 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := i2pd
+LOCAL_CPP_FEATURES := rtti exceptions
+LOCAL_C_INCLUDES += $(IFADDRS_PATH) ../..
+LOCAL_STATIC_LIBRARIES := \
+ boost_system-gcc-mt-1_53 \
+ boost_date_time-gcc-mt-1_53 \
+ boost_filesystem-gcc-mt-1_53 \
+ boost_program_options-gcc-mt-1_53 \
+ crypto ssl \
+ miniupnpc
+LOCAL_LDLIBS := -lz
+
+#LOCAL_CFLAGS :=
+LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
+ $(IFADDRS_PATH)/ifaddrs.c \
+ ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \
+ ../../AddressBook.cpp \
+ ../../api.cpp \
+ ../../Base.cpp \
+ ../../BOB.cpp \
+ ../../ClientContext.cpp \
+ ../../Crypto.cpp \
+ ../../Datagram.cpp \
+ ../../Destination.cpp \
+ ../../Family.cpp \
+ ../../FS.cpp \
+ ../../Garlic.cpp \
+ ../../Gzip.cpp \
+ ../../HTTP.cpp \
+ ../../HTTPProxy.cpp \
+ ../../I2CP.cpp \
+ ../../I2NPProtocol.cpp \
+ ../../I2PEndian.cpp \
+ ../../I2PService.cpp \
+ ../../I2PTunnel.cpp \
+ ../../Identity.cpp \
+ ../../LeaseSet.cpp \
+ ../../Log.cpp \
+ ../../NetDb.cpp \
+ ../../NetDbRequests.cpp \
+ ../../NTCPSession.cpp \
+ ../../Profiling.cpp \
+ ../../Reseed.cpp \
+ ../../RouterContext.cpp \
+ ../../RouterInfo.cpp \
+ ../../SAM.cpp \
+ ../../Signature.cpp \
+ ../../SOCKS.cpp \
+ ../../SSU.cpp \
+ ../../SSUData.cpp \
+ ../../SSUSession.cpp \
+ ../../Streaming.cpp \
+ ../../TransitTunnel.cpp \
+ ../../Transports.cpp \
+ ../../Tunnel.cpp \
+ ../../TunnelEndpoint.cpp \
+ ../../TunnelGateway.cpp \
+ ../../TunnelPool.cpp \
+ ../../UPnP.cpp \
+ ../../util.cpp \
+ ../../i2pd.cpp
+
+include $(BUILD_SHARED_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := boost_system-gcc-mt-1_53
+LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_system-gcc-mt-1_53.a
+LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := boost_date_time-gcc-mt-1_53
+LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time-gcc-mt-1_53.a
+LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := boost_filesystem-gcc-mt-1_53
+LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem-gcc-mt-1_53.a
+LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := boost_program_options-gcc-mt-1_53
+LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options-gcc-mt-1_53.a
+LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := crypto
+LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.0.2/$(TARGET_ARCH_ABI)/lib/libcrypto.a
+LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.0.2/include
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := ssl
+LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.0.2/$(TARGET_ARCH_ABI)/lib/libssl.a
+LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.0.2/include
+LOCAL_STATIC_LIBRARIES := crypto
+include $(PREBUILT_STATIC_LIBRARY)
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE := miniupnpc
+LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
+LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include
+include $(PREBUILT_STATIC_LIBRARY)
diff --git a/android/jni/Application.mk b/android/jni/Application.mk
new file mode 100755
index 00000000..34f9dd63
--- /dev/null
+++ b/android/jni/Application.mk
@@ -0,0 +1,30 @@
+#APP_ABI := all
+APP_ABI := armeabi-v7a x86
+#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
+APP_PLATFORM := android-9
+
+# 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
+
+# Enable c++11 extentions in source code
+APP_CPPFLAGS += -std=c++11
+
+APP_CPPFLAGS += -DUSE_UPNP -DANDROID -D__ANDROID__
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+APP_CPPFLAGS += -DANDROID_ARM7A
+endif
+
+APP_OPTIM := debug
+
+# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
+# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
+# 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
+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
+IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs
diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp
new file mode 100644
index 00000000..02f6e3f7
--- /dev/null
+++ b/android/jni/DaemonAndroid.cpp
@@ -0,0 +1,170 @@
+#include "DaemonAndroid.h"
+#include "../../Daemon.h"
+//#include "mainwindow.h"
+
+namespace i2p
+{
+namespace android
+{
+/* Worker::Worker (DaemonAndroidImpl& daemon):
+ m_Daemon (daemon)
+ {
+ }
+
+ 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();
+ }
+
+ 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)
+ {
+ }
+
+ 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 DaemonAndroidImpl::stop()
+ {
+ //QMutexLocker locker(mutex);
+ Daemon.stop();
+ setRunning(false);
+ }
+
+ void DaemonAndroidImpl::restart()
+ {
+ //QMutexLocker locker(mutex);
+ stop();
+ start();
+ }
+
+ void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb)
+ {
+ m_RunningChangedCallback = cb;
+ }
+
+ bool DaemonAndroidImpl::isRunning()
+ {
+ return m_IsRunning;
+ }
+
+ void DaemonAndroidImpl::setRunning(bool newValue)
+ {
+ bool oldValue = m_IsRunning;
+ if(oldValue!=newValue)
+ {
+ m_IsRunning = newValue;
+ if(m_RunningChangedCallback)
+ m_RunningChangedCallback();
+ }
+ }
+
+ static DaemonAndroidImpl daemon;
+
+ /**
+ * returns 1 if daemon init failed
+ * returns 0 if daemon initialized and started okay
+ */
+ int start(/*int argc, char* argv[]*/)
+ {
+ int result;
+
+ {
+ //Log.d(TAG"Initialising the daemon...");
+ bool daemonInitSuccess = daemon.init(0,0/*argc, argv*/);
+ if(!daemonInitSuccess)
+ {
+ //QMessageBox::critical(0, "Error", "Daemon init failed");
+ return 1;
+ }
+ //Log.d(TAG"Initialised, creating the main window...");
+ //MainWindow w;
+ //Log.d(TAG"Before main window.show()...");
+ //w.show ();
+
+ {
+ //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();
+ return 0;
+ }
+ }
+
+ //QMessageBox::information(&w, "Debug", "demon stopped");
+ //Log.d(TAG"Exiting the application");
+ //return result;
+ }
+
+ void stop()
+ {
+ daemon.stop();
+ }
+}
+}
+
diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h
new file mode 100644
index 00000000..f6ee618f
--- /dev/null
+++ b/android/jni/DaemonAndroid.h
@@ -0,0 +1,86 @@
+#ifndef DAEMON_ANDROID_H
+#define DAEMON_ANDROID_H
+
+namespace i2p
+{
+namespace android
+{
+ //FIXME currently NOT threadsafe
+ 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 1 if daemon init failed
+ * returns 0 if daemon initialized and started okay
+ */
+ int 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();
+ };
+ */
+}
+}
+
+#endif // DAEMON_ANDROID_H
diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp
new file mode 100755
index 00000000..b84ec1ac
--- /dev/null
+++ b/android/jni/i2pd_android.cpp
@@ -0,0 +1,53 @@
+
+//#include
+#include
+#include "org_purplei2p_i2pd_I2PD_JNI.h"
+#include "DaemonAndroid.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 jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
+ (JNIEnv * env, jclass clazz) {
+ return (jint)i2p::android::start();
+}
+
+JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
+ (JNIEnv * env, jclass clazz) {
+ i2p::android::stop();
+}
+
diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h
new file mode 100644
index 00000000..ddbcace8
--- /dev/null
+++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h
@@ -0,0 +1,21 @@
+/* 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);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/android/project.properties b/android/project.properties
new file mode 100644
index 00000000..c6998b3d
--- /dev/null
+++ b/android/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-9
diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png
new file mode 100644
index 00000000..a5dc7b68
Binary files /dev/null and b/android/res/drawable/icon.png differ
diff --git a/android/res/drawable/itoopie_notification_icon.png b/android/res/drawable/itoopie_notification_icon.png
new file mode 100644
index 00000000..8fbe2468
Binary files /dev/null and b/android/res/drawable/itoopie_notification_icon.png differ
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
new file mode 100755
index 00000000..b02181c8
--- /dev/null
+++ b/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ i2pd
+
diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java
new file mode 100755
index 00000000..6f77c53f
--- /dev/null
+++ b/android/src/org/purplei2p/i2pd/I2PD.java
@@ -0,0 +1,20 @@
+package org.purplei2p.i2pd;
+
+import android.app.Activity;
+import android.widget.TextView;
+import android.os.Bundle;
+
+public class I2PD extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ TextView tv = new TextView(this);
+ tv.setText( "libi2pd.so was compiled with ABI " + getABICompiledWith());
+ setContentView(tv);
+ }
+
+ public String getABICompiledWith() {
+ return I2PD_JNI.getABICompiledWith();
+ }
+}
diff --git a/android/src/org/purplei2p/i2pd/I2PD_JNI.java b/android/src/org/purplei2p/i2pd/I2PD_JNI.java
new file mode 100644
index 00000000..040cca1c
--- /dev/null
+++ b/android/src/org/purplei2p/i2pd/I2PD_JNI.java
@@ -0,0 +1,16 @@
+package org.purplei2p.i2pd;
+
+public class I2PD_JNI {
+ public static native String getABICompiledWith();
+ /**
+ * returns 1 if daemon init failed
+ * returns 0 if daemon initialized and started okay
+ */
+ public static native int startDaemon();
+ //should only be called after startDaemon() success
+ public static native void stopDaemon();
+
+ static {
+ System.loadLibrary("i2pd");
+ }
+}