mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-23 17:36:37 +02:00
Merge branch 'upstream-openssl'
This commit is contained in:
commit
f2bc71bc2a
65 changed files with 3283 additions and 188 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -5,6 +5,10 @@ router.keys
|
||||||
i2p
|
i2p
|
||||||
libi2pd.so
|
libi2pd.so
|
||||||
netDb
|
netDb
|
||||||
|
/i2pd
|
||||||
|
/libi2pd.a
|
||||||
|
/libi2pdclient.a
|
||||||
|
|
||||||
|
|
||||||
# Autotools
|
# Autotools
|
||||||
autom4te.cache
|
autom4te.cache
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
#include "util.h"
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -292,7 +293,7 @@ namespace client
|
||||||
template<typename Section, typename Type>
|
template<typename Section, typename Type>
|
||||||
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
||||||
{
|
{
|
||||||
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
|
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Section>
|
template<typename Section>
|
||||||
|
|
|
@ -298,11 +298,13 @@ namespace crypto
|
||||||
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
|
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
|
||||||
#endif
|
#endif
|
||||||
// calculate a
|
// calculate a
|
||||||
a = BN_new ();
|
|
||||||
if (g_ElggTable)
|
if (g_ElggTable)
|
||||||
a = ElggPow (k, g_ElggTable, ctx);
|
a = ElggPow (k, g_ElggTable, ctx);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
a = BN_new ();
|
||||||
BN_mod_exp (a, elgg, k, elgp, ctx);
|
BN_mod_exp (a, elgg, k, elgp, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
BIGNUM * y = BN_new ();
|
BIGNUM * y = BN_new ();
|
||||||
BN_bin2bn (key, 256, y);
|
BN_bin2bn (key, 256, y);
|
||||||
|
|
|
@ -265,5 +265,5 @@ namespace i2p
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
Daemon.h
27
Daemon.h
|
@ -1,14 +1,9 @@
|
||||||
#ifndef DAEMON_H__
|
#ifndef DAEMON_H__
|
||||||
#define DAEMON_H__
|
#define DAEMON_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define Daemon i2p::util::DaemonWin32::Instance()
|
|
||||||
#else
|
|
||||||
#define Daemon i2p::util::DaemonLinux::Instance()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
|
@ -36,7 +31,22 @@ namespace i2p
|
||||||
Daemon_Singleton_Private &d;
|
Daemon_Singleton_Private &d;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(QT_GUI_LIB) // check if QT
|
||||||
|
#define Daemon i2p::util::DaemonQT::Instance()
|
||||||
|
// dummy, invoked from RunQT
|
||||||
|
class DaemonQT: public i2p::util::Daemon_Singleton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static DaemonQT& Instance()
|
||||||
|
{
|
||||||
|
static DaemonQT instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define Daemon i2p::util::DaemonWin32::Instance()
|
||||||
class DaemonWin32 : public Daemon_Singleton
|
class DaemonWin32 : public Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -52,7 +62,8 @@ namespace i2p
|
||||||
void run ();
|
void run ();
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
class DaemonLinux : public Daemon_Singleton
|
#define Daemon i2p::util::DaemonLinux::Instance()
|
||||||
|
class DaemonLinux : public Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static DaemonLinux& Instance()
|
static DaemonLinux& Instance()
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace i2p
|
||||||
}
|
}
|
||||||
|
|
||||||
// point std{in,out,err} descriptors to /dev/null
|
// point std{in,out,err} descriptors to /dev/null
|
||||||
stdin = freopen("/dev/null", "r", stdin);
|
stdin = freopen("/dev/null", "r", stdin);
|
||||||
stdout = freopen("/dev/null", "w", stdout);
|
stdout = freopen("/dev/null", "w", stdout);
|
||||||
stderr = freopen("/dev/null", "w", stderr);
|
stderr = freopen("/dev/null", "w", stderr);
|
||||||
}
|
}
|
||||||
|
|
8
FS.cpp
8
FS.cpp
|
@ -55,6 +55,14 @@ namespace fs {
|
||||||
dataDir += "/Library/Application Support/" + appName;
|
dataDir += "/Library/Application Support/" + appName;
|
||||||
return;
|
return;
|
||||||
#else /* other unix */
|
#else /* other unix */
|
||||||
|
#if defined(ANDROID)
|
||||||
|
if (boost::filesystem::exists("/sdcard"))
|
||||||
|
{
|
||||||
|
dataDir = "/sdcard/" + appName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise use /data/files
|
||||||
|
#endif
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (isService) {
|
if (isService) {
|
||||||
dataDir = "/var/lib/" + appName;
|
dataDir = "/var/lib/" + appName;
|
||||||
|
|
3
HTTP.cpp
3
HTTP.cpp
|
@ -6,6 +6,7 @@
|
||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
#include "HTTP.h"
|
#include "HTTP.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
@ -342,7 +343,7 @@ namespace http {
|
||||||
if (status == "OK" && code != 200)
|
if (status == "OK" && code != 200)
|
||||||
status = HTTPCodeToStatus(code); // update
|
status = HTTPCodeToStatus(code); // update
|
||||||
if (body.length() > 0 && headers.count("Content-Length") == 0)
|
if (body.length() > 0 && headers.count("Content-Length") == 0)
|
||||||
add_header("Content-Length", std::to_string(body.length()).c_str());
|
add_header("Content-Length", std::to_string(body.length()).c_str());
|
||||||
/* build response */
|
/* build response */
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << version << " " << code << " " << status << CRLF;
|
ss << version << " " << code << " " << status << CRLF;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
#include "HTTPServer.h"
|
#include "HTTPServer.h"
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
// For image and info
|
// For image and info
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -127,7 +128,7 @@ namespace http {
|
||||||
"<html lang=\"en\">\r\n" /* TODO: Add support for locale */
|
"<html lang=\"en\">\r\n" /* TODO: Add support for locale */
|
||||||
" <head>\r\n"
|
" <head>\r\n"
|
||||||
" <meta charset=\"UTF-8\">\r\n" /* TODO: Find something to parse html/template system. This is horrible. */
|
" <meta charset=\"UTF-8\">\r\n" /* TODO: Find something to parse html/template system. This is horrible. */
|
||||||
" <link rel='shortcut icon' href='" << itoopieFavicon << "'>\r\n"
|
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
||||||
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"
|
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"
|
||||||
<< cssStyles <<
|
<< cssStyles <<
|
||||||
"</head>\r\n";
|
"</head>\r\n";
|
||||||
|
@ -136,15 +137,15 @@ namespace http {
|
||||||
"<div class=header><b>i2pd</b> webconsole</div>\r\n"
|
"<div class=header><b>i2pd</b> webconsole</div>\r\n"
|
||||||
"<div class=wrapper>\r\n"
|
"<div class=wrapper>\r\n"
|
||||||
"<div class=left>\r\n"
|
"<div class=left>\r\n"
|
||||||
" <a href=/>Main page</a><br>\r\n<br>\r\n"
|
" <a href=\"/\">Main page</a><br>\r\n<br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_COMMANDS << ">Router commands</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << ">Local destinations</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_TUNNELS << ">Tunnels</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_TRANSIT_TUNNELS << ">Transit tunnels</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_TRANSPORTS << ">Transports</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_I2P_TUNNELS << ">I2P tunnels</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_I2P_TUNNELS << "\">I2P tunnels</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_JUMPSERVICES << ">Jump services</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_JUMPSERVICES << "\">Jump services</a><br>\r\n"
|
||||||
" <a href=/?page=" << HTTP_PAGE_SAM_SESSIONS << ">SAM sessions</a><br>\r\n"
|
" <a href=\"/?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n"
|
||||||
"</div>\r\n"
|
"</div>\r\n"
|
||||||
"<div class=right>";
|
"<div class=right>";
|
||||||
}
|
}
|
||||||
|
@ -230,15 +231,15 @@ namespace http {
|
||||||
clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels();
|
clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels();
|
||||||
size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels();
|
size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels();
|
||||||
|
|
||||||
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
||||||
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
|
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowJumpServices (std::stringstream& s, const std::string& address)
|
void ShowJumpServices (std::stringstream& s, const std::string& address)
|
||||||
{
|
{
|
||||||
s << "<form type=\"GET\" action=\"/\">";
|
s << "<form method=\"get\" action=\"/\">";
|
||||||
s << "<input type=\"hidden\" name=\"page\" value=\"jumpservices\">";
|
s << "<input type=\"hidden\" name=\"page\" value=\"jumpservices\">";
|
||||||
s << "<input type=\"text\" name=\"address\" value=\"" << address << "\">";
|
s << "<input type=\"text\" name=\"address\" value=\"" << address << "\">";
|
||||||
s << "<input type=\"submit\" value=\"Update\">";
|
s << "<input type=\"submit\" value=\"Update\">";
|
||||||
s << "</form><br>\r\n";
|
s << "</form><br>\r\n";
|
||||||
s << "<b>Jump services for " << address << "</b>\r\n<ul>\r\n";
|
s << "<b>Jump services for " << address << "</b>\r\n<ul>\r\n";
|
||||||
|
@ -254,7 +255,7 @@ namespace http {
|
||||||
for (auto& it: i2p::client::context.GetDestinations ())
|
for (auto& it: i2p::client::context.GetDestinations ())
|
||||||
{
|
{
|
||||||
auto ident = it.second->GetIdentHash ();;
|
auto ident = it.second->GetIdentHash ();;
|
||||||
s << "<a href=/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << ">";
|
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,21 +359,21 @@ namespace http {
|
||||||
{
|
{
|
||||||
/* commands */
|
/* commands */
|
||||||
s << "<b>Router Commands</b><br>\r\n";
|
s << "<b>Router Commands</b><br>\r\n";
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "\">Run peer test</a><br>\r\n";
|
||||||
//s << " <a href=/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << ">Reload config</a><br>\r\n";
|
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
|
||||||
if (i2p::context.AcceptsTunnels ())
|
if (i2p::context.AcceptsTunnels ())
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << "\">Stop accepting tunnels</a><br>\r\n";
|
||||||
else
|
else
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << "\">Start accepting tunnels</a><br>\r\n";
|
||||||
#ifndef WIN32
|
#if (!defined(WIN32) && !defined(QT_GUI_LIB))
|
||||||
if (Daemon.gracefullShutdownInterval) {
|
if (Daemon.gracefullShutdownInterval) {
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << ">Cancel gracefull shutdown (";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "\">Cancel gracefull shutdown (";
|
||||||
s << Daemon.gracefullShutdownInterval;
|
s << Daemon.gracefullShutdownInterval;
|
||||||
s << " seconds remains)</a><br>\r\n";
|
s << " seconds remains)</a><br>\r\n";
|
||||||
} else {
|
} else {
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << ">Start gracefull shutdown</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Start gracefull shutdown</a><br>\r\n";
|
||||||
}
|
}
|
||||||
s << " <a href=/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << ">Force shutdown</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "\">Force shutdown</a><br>\r\n";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +451,7 @@ namespace http {
|
||||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
||||||
for (auto& it: sam->GetSessions ())
|
for (auto& it: sam->GetSessions ())
|
||||||
{
|
{
|
||||||
s << "<a href=/?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << ">";
|
s << "<a href=\"/?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
||||||
s << it.first << "</a><br>\r\n" << std::endl;
|
s << it.first << "</a><br>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,7 +470,7 @@ namespace http {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& ident = session->localDestination->GetIdentHash();
|
auto& ident = session->localDestination->GetIdentHash();
|
||||||
s << "<a href=/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << ">";
|
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>Streams:</b><br>\r\n";
|
s << "<b>Streams:</b><br>\r\n";
|
||||||
|
@ -493,7 +494,7 @@ namespace http {
|
||||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << ">";
|
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇐ ";
|
s << it.second->GetName () << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "<br>\r\n"<< std::endl;
|
||||||
|
@ -502,7 +503,7 @@ namespace http {
|
||||||
for (auto& it: i2p::client::context.GetServerTunnels ())
|
for (auto& it: i2p::client::context.GetServerTunnels ())
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << ">";
|
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇒ ";
|
s << it.second->GetName () << "</a> ⇒ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << ":" << it.second->GetLocalPort ();
|
s << ":" << it.second->GetLocalPort ();
|
||||||
|
@ -611,7 +612,7 @@ namespace http {
|
||||||
HandleCommand (req, res, s);
|
HandleCommand (req, res, s);
|
||||||
} else {
|
} else {
|
||||||
ShowStatus (s);
|
ShowStatus (s);
|
||||||
res.add_header("Refresh", "5");
|
//res.add_header("Refresh", "5");
|
||||||
}
|
}
|
||||||
ShowPageTail (s);
|
ShowPageTail (s);
|
||||||
|
|
||||||
|
@ -677,12 +678,12 @@ namespace http {
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
#ifndef WIN32
|
#if (!defined(WIN32) && !defined(QT_GUI_LIB))
|
||||||
Daemon.gracefullShutdownInterval = 10*60;
|
Daemon.gracefullShutdownInterval = 10*60;
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
#ifndef WIN32
|
#if (!defined(WIN32) && !defined(QT_GUI_LIB))
|
||||||
Daemon.gracefullShutdownInterval = 0;
|
Daemon.gracefullShutdownInterval = 0;
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
|
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
|
||||||
|
|
137
I2CP.cpp
137
I2CP.cpp
|
@ -115,15 +115,14 @@ namespace client
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||||
m_Owner (owner), m_Socket (socket),
|
m_Owner (owner), m_Socket (socket), m_Payload (nullptr),
|
||||||
m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0),
|
|
||||||
m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
|
m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CPSession::~I2CPSession ()
|
I2CPSession::~I2CPSession ()
|
||||||
{
|
{
|
||||||
delete[] m_NextMessage;
|
delete[] m_Payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::Start ()
|
void I2CPSession::Start ()
|
||||||
|
@ -141,117 +140,72 @@ namespace client
|
||||||
if (m_Socket)
|
if (m_Socket)
|
||||||
{
|
{
|
||||||
auto s = shared_from_this ();
|
auto s = shared_from_this ();
|
||||||
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, 1),
|
m_Socket->async_read_some (boost::asio::buffer (m_Header, 1),
|
||||||
[s](const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
[s](const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (!ecode && bytes_transferred > 0 && s->m_Buffer[0] == I2CP_PROTOCOL_BYTE)
|
if (!ecode && bytes_transferred > 0 && s->m_Header[0] == I2CP_PROTOCOL_BYTE)
|
||||||
s->Receive ();
|
s->ReceiveHeader ();
|
||||||
else
|
else
|
||||||
s->Terminate ();
|
s->Terminate ();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::Receive ()
|
void I2CPSession::ReceiveHeader ()
|
||||||
{
|
{
|
||||||
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, I2CP_SESSION_BUFFER_SIZE),
|
boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Header, I2CP_HEADER_SIZE),
|
||||||
std::bind (&I2CPSession::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
boost::asio::transfer_all (),
|
||||||
|
std::bind (&I2CPSession::HandleReceivedHeader, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
void I2CPSession::HandleReceivedHeader (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
Terminate ();
|
Terminate ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t offset = 0; // from m_Buffer
|
m_PayloadLen = bufbe32toh (m_Header + I2CP_HEADER_LENGTH_OFFSET);
|
||||||
if (m_NextMessage)
|
if (m_PayloadLen > 0)
|
||||||
{
|
{
|
||||||
if (!m_NextMessageLen) // we didn't receive header yet
|
m_Payload = new uint8_t[m_PayloadLen];
|
||||||
{
|
ReceivePayload ();
|
||||||
if (m_NextMessageOffset + bytes_transferred < I2CP_HEADER_SIZE)
|
}
|
||||||
{
|
else // no following payload
|
||||||
// still no complete header
|
|
||||||
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, bytes_transferred);
|
|
||||||
m_NextMessageOffset += bytes_transferred;
|
|
||||||
offset = bytes_transferred;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we know message length now
|
|
||||||
offset = I2CP_HEADER_SIZE - m_NextMessageOffset;
|
|
||||||
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer, offset);
|
|
||||||
m_NextMessageLen = bufbe32toh (m_NextMessage + I2CP_HEADER_LENGTH_OFFSET) + I2CP_HEADER_SIZE;
|
|
||||||
m_NextMessageOffset = I2CP_HEADER_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset < bytes_transferred)
|
|
||||||
{
|
|
||||||
auto msgRemainingLen = m_NextMessageLen - m_NextMessageOffset;
|
|
||||||
auto bufRemainingLen = bytes_transferred - offset;
|
|
||||||
if (bufRemainingLen < msgRemainingLen)
|
|
||||||
{
|
|
||||||
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer + offset, bufRemainingLen);
|
|
||||||
m_NextMessageOffset += bufRemainingLen;
|
|
||||||
offset += bufRemainingLen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// m_NextMessage complete
|
|
||||||
offset += msgRemainingLen;
|
|
||||||
memcpy (m_NextMessage + m_NextMessageOffset, m_Buffer + offset, msgRemainingLen);
|
|
||||||
HandleNextMessage (m_NextMessage);
|
|
||||||
delete[] m_NextMessage;
|
|
||||||
m_NextMessage = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// process the rest
|
|
||||||
while (offset < bytes_transferred)
|
|
||||||
{
|
{
|
||||||
if (bytes_transferred - offset < I2CP_HEADER_SIZE)
|
HandleMessage ();
|
||||||
{
|
ReceiveHeader (); // next message
|
||||||
// we don't have message header yet
|
}
|
||||||
m_NextMessage = new uint8_t[0xFFFF]; // allocate 64K
|
|
||||||
m_NextMessageLen = 0; // we must set message length later
|
|
||||||
m_NextMessageOffset = bytes_transferred - offset;
|
|
||||||
memcpy (m_NextMessage, m_Buffer + offset, m_NextMessageOffset); // just copy it
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto msgLen = bufbe32toh (m_Buffer + offset + I2CP_HEADER_LENGTH_OFFSET) + I2CP_HEADER_SIZE;
|
|
||||||
if (msgLen > 0xFFFF) // 64K
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "I2CP: message length ", msgLen, " exceeds 64K. Terminated");
|
|
||||||
Terminate ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (msgLen <= bytes_transferred - offset)
|
|
||||||
{
|
|
||||||
HandleNextMessage (m_Buffer + offset);
|
|
||||||
offset += msgLen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_NextMessageLen = msgLen;
|
|
||||||
m_NextMessageOffset = bytes_transferred - offset;
|
|
||||||
m_NextMessage = new uint8_t[m_NextMessageLen];
|
|
||||||
memcpy (m_NextMessage, m_Buffer + offset, m_NextMessageOffset);
|
|
||||||
offset = bytes_transferred;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Receive ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::HandleNextMessage (const uint8_t * buf)
|
void I2CPSession::ReceivePayload ()
|
||||||
{
|
{
|
||||||
auto handler = m_Owner.GetMessagesHandlers ()[buf[I2CP_HEADER_TYPE_OFFSET]];
|
boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Payload, m_PayloadLen),
|
||||||
if (handler)
|
boost::asio::transfer_all (),
|
||||||
(this->*handler)(buf + I2CP_HEADER_SIZE, bufbe32toh (buf + I2CP_HEADER_LENGTH_OFFSET));
|
std::bind (&I2CPSession::HandleReceivedPayload, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CPSession::HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
Terminate ();
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2CP: Unknown I2CP messsage ", (int)buf[I2CP_HEADER_TYPE_OFFSET]);
|
{
|
||||||
|
HandleMessage ();
|
||||||
|
delete[] m_Payload;
|
||||||
|
m_Payload = nullptr;
|
||||||
|
m_PayloadLen = 0;
|
||||||
|
ReceiveHeader (); // next message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CPSession::HandleMessage ()
|
||||||
|
{
|
||||||
|
auto handler = m_Owner.GetMessagesHandlers ()[m_Header[I2CP_HEADER_TYPE_OFFSET]];
|
||||||
|
if (handler)
|
||||||
|
(this->*handler)(m_Payload, m_PayloadLen);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "I2CP: Unknown I2CP messsage ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::Terminate ()
|
void I2CPSession::Terminate ()
|
||||||
|
@ -267,6 +221,7 @@ namespace client
|
||||||
m_Socket = nullptr;
|
m_Socket = nullptr;
|
||||||
}
|
}
|
||||||
m_Owner.RemoveSession (GetSessionID ());
|
m_Owner.RemoveSession (GetSessionID ());
|
||||||
|
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " terminated");
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
|
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
|
||||||
|
|
12
I2CP.h
12
I2CP.h
|
@ -126,9 +126,11 @@ namespace client
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ReadProtocolByte ();
|
void ReadProtocolByte ();
|
||||||
void Receive ();
|
void ReceiveHeader ();
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceivedHeader (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleNextMessage (const uint8_t * buf);
|
void ReceivePayload ();
|
||||||
|
void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
void HandleMessage ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
|
||||||
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf);
|
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf);
|
||||||
|
@ -143,8 +145,8 @@ namespace client
|
||||||
|
|
||||||
I2CPServer& m_Owner;
|
I2CPServer& m_Owner;
|
||||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||||
uint8_t m_Buffer[I2CP_SESSION_BUFFER_SIZE], * m_NextMessage;
|
uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload;
|
||||||
size_t m_NextMessageLen, m_NextMessageOffset;
|
size_t m_PayloadLen;
|
||||||
|
|
||||||
std::shared_ptr<I2CPDestination> m_Destination;
|
std::shared_ptr<I2CPDestination> m_Destination;
|
||||||
uint16_t m_SessionID;
|
uint16_t m_SessionID;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "util.h"
|
||||||
#include "I2PControl.h"
|
#include "I2PControl.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -315,7 +316,7 @@ namespace client
|
||||||
}
|
}
|
||||||
InsertParam (results, "API", api);
|
InsertParam (results, "API", api);
|
||||||
results << ",";
|
results << ",";
|
||||||
std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ());
|
std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ());
|
||||||
m_Tokens.insert (token);
|
m_Tokens.insert (token);
|
||||||
InsertParam (results, "Token", token);
|
InsertParam (results, "Token", token);
|
||||||
}
|
}
|
||||||
|
|
75
README.md
75
README.md
|
@ -1,38 +1,55 @@
|
||||||
i2pd
|
i2pd
|
||||||
====
|
====
|
||||||
|
|
||||||
Independent C++ implementation of I2P router
|
i2pd is a full-featured C++ implementation of
|
||||||
|
[I2P](https://geti2p.net/en/about/intro) client.
|
||||||
|
|
||||||
|
I2P (Invisible Internet Project) is anonymous network which works on top of
|
||||||
|
public Internet. Privacy and anonymity are achieved by strong encryption and
|
||||||
|
bouncing your traffic through thousands of I2P nodes all around the world.
|
||||||
|
|
||||||
|
We are building network which helps people to communicate and share information
|
||||||
|
without restrictions.
|
||||||
|
|
||||||
|
* [Website](http://i2pd.website)
|
||||||
|
* [Documentation](https://i2pd.readthedocs.io/en/latest/)
|
||||||
|
* [Wiki](https://github.com/PurpleI2P/i2pd/wiki)
|
||||||
|
* [Tickets/Issues](https://github.com/PurpleI2P/i2pd/issues)
|
||||||
|
* [Twitter](https://twitter.com/i2porignal)
|
||||||
|
|
||||||
|
Installing
|
||||||
|
----------
|
||||||
|
|
||||||
|
The easiest way to install i2pd is by using
|
||||||
|
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
|
||||||
|
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
||||||
|
i2pd from source on your OS.
|
||||||
|
|
||||||
|
**Supported systems:**
|
||||||
|
|
||||||
|
* Linux x86/x64 - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||||
|
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||||
|
* Mac OS X
|
||||||
|
* FreeBSD
|
||||||
|
* Android
|
||||||
|
|
||||||
|
Using i2pd
|
||||||
|
----------
|
||||||
|
|
||||||
|
See [documentation](https://i2pd.readthedocs.io/en/latest/) and
|
||||||
|
[example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/docs/i2pd.conf).
|
||||||
|
|
||||||
|
Donations
|
||||||
|
---------
|
||||||
|
|
||||||
|
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
||||||
|
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
|
||||||
|
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||||
|
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
||||||
|
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
This project is licensed under the BSD 3-clause license, which can be found in the file
|
This project is licensed under the BSD 3-clause license, which can be found in the file
|
||||||
LICENSE in the root of the project source code.
|
LICENSE in the root of the project source code.
|
||||||
|
|
||||||
Donations
|
|
||||||
---------
|
|
||||||
|
|
||||||
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
|
||||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
|
||||||
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
|
||||||
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
|
|
||||||
|
|
||||||
Documentation:
|
|
||||||
--------------
|
|
||||||
http://i2pd.readthedocs.org
|
|
||||||
|
|
||||||
Supported OS
|
|
||||||
------------
|
|
||||||
|
|
||||||
* Linux x86/x64 - [](https://travis-ci.org/PurpleI2P/i2pd)
|
|
||||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
|
||||||
* Mac OS X
|
|
||||||
* FreeBSD
|
|
||||||
|
|
||||||
More documentation
|
|
||||||
------------------
|
|
||||||
|
|
||||||
* [Building from source / unix](docs/build_notes_unix.md)
|
|
||||||
* [Building from source / windows](docs/build_notes_windows.md)
|
|
||||||
* [Configuring your i2pd](docs/configuration.md)
|
|
||||||
* [Github wiki](https://github.com/PurpleI2P/i2pd/wiki/)
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "NetDb.h"
|
#include "NetDb.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
|
@ -373,7 +372,7 @@ namespace data
|
||||||
boost::asio::io_service service;
|
boost::asio::io_service service;
|
||||||
boost::system::error_code ecode;
|
boost::system::error_code ecode;
|
||||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||||
boost::asio::ip::tcp::resolver::query (u.host_, std::to_string (u.port_)), ecode);
|
boost::asio::ip::tcp::resolver::query (u.host_, std::to_string (u.port_)), ecode);
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
boost::asio::ssl::context ctx(service, boost::asio::ssl::context::sslv23);
|
boost::asio::ssl::context ctx(service, boost::asio::ssl::context::sslv23);
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace i2p
|
||||||
routerInfo.AddNTCPAddress (host.c_str(), port);
|
routerInfo.AddNTCPAddress (host.c_str(), port);
|
||||||
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
||||||
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
||||||
routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID));
|
routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID));
|
||||||
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
||||||
routerInfo.CreateBuffer (m_Keys);
|
routerInfo.CreateBuffer (m_Keys);
|
||||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||||
|
|
|
@ -456,8 +456,13 @@ namespace transport
|
||||||
{
|
{
|
||||||
m_SSUServer->DeleteSession (ssuSession);
|
m_SSUServer->DeleteSession (ssuSession);
|
||||||
LogPrint (eLogDebug, "Transports: SSU session closed");
|
LogPrint (eLogDebug, "Transports: SSU session closed");
|
||||||
}
|
}
|
||||||
// TODO: delete NTCP
|
auto ntcpSession = m_NTCPServer ? m_NTCPServer->FindNTCPSession(router->GetIdentHash()) : nullptr;
|
||||||
|
if (ntcpSession) // try deleting ntcp session too
|
||||||
|
{
|
||||||
|
ntcpSession->Terminate ();
|
||||||
|
LogPrint(eLogDebug, "Transports: NTCP session closed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::DetectExternalIP ()
|
void Transports::DetectExternalIP ()
|
||||||
|
|
|
@ -861,6 +861,12 @@ namespace tunnel
|
||||||
// TODO: locking
|
// TODO: locking
|
||||||
return m_OutboundTunnels.size();
|
return m_OutboundTunnels.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ANDROID_ARM7A
|
||||||
|
template std::shared_ptr<InboundTunnel> Tunnels::CreateTunnel<InboundTunnel>(std::shared_ptr<TunnelConfig>, std::shared_ptr<OutboundTunnel>);
|
||||||
|
template std::shared_ptr<OutboundTunnel> Tunnels::CreateTunnel<OutboundTunnel>(std::shared_ptr<TunnelConfig>, std::shared_ptr<OutboundTunnel>);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
build/.gitignore
vendored
Normal file
10
build/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Various generated files
|
||||||
|
/CMakeFiles/
|
||||||
|
/i2pd
|
||||||
|
/libi2pd.a
|
||||||
|
/libi2pdclient.a
|
||||||
|
/cmake_install.cmake
|
||||||
|
/CMakeCache.txt
|
||||||
|
/CPackConfig.cmake
|
||||||
|
/CPackSourceConfig.cmake
|
||||||
|
/install_manifest.txt
|
|
@ -1,20 +1,27 @@
|
||||||
i2pd
|
i2pd
|
||||||
====
|
====
|
||||||
|
|
||||||
`Website <http://i2pd.website>`_ |
|
i2pd is a full-featured C++ implementation of
|
||||||
`Github <https://github.com/PurpleI2P/i2pd>`_ |
|
`I2P <https://geti2p.net/en/about/intro>`_ client.
|
||||||
`Issues <https://github.com/PurpleI2P/i2pd/issues>`_
|
|
||||||
|
|
||||||
i2pd is C++ implementation of `I2P <https://geti2p.net/en/about/intro>`_.
|
* `Website <http://i2pd.website>`_
|
||||||
|
* `GitHub <https://github.com/PurpleI2P/i2pd>`_
|
||||||
|
* `Wiki <https://github.com/PurpleI2P/i2pd/wiki>`_
|
||||||
|
* `Tickets/Issues <https://github.com/PurpleI2P/i2pd/issues>`_
|
||||||
|
* `Twitter <https://twitter.com/i2porignal>`_
|
||||||
|
|
||||||
Supports:
|
Installing
|
||||||
---------
|
----------
|
||||||
|
|
||||||
* Complete I2P router functionality
|
The easiest way to install i2pd is by using
|
||||||
* Floodfill
|
`precompiled binaries <https://github.com/PurpleI2P/i2pd/releases/latest>`_.
|
||||||
* HTTP and SOCKS proxy
|
See documentation for how to build i2pd from source on your OS.
|
||||||
* I2P client and server tunnels
|
|
||||||
* SAM and BOB interfaces
|
Using i2pd
|
||||||
|
----------
|
||||||
|
|
||||||
|
See documentation and
|
||||||
|
`example config file <https://github.com/PurpleI2P/i2pd/blob/openssl/docs/i2pd.conf>`_.
|
||||||
|
|
||||||
Contents:
|
Contents:
|
||||||
---------
|
---------
|
||||||
|
@ -28,3 +35,4 @@ Contents:
|
||||||
configuration
|
configuration
|
||||||
family
|
family
|
||||||
|
|
||||||
|
|
||||||
|
|
18
i2pd.cpp
18
i2pd.cpp
|
@ -1,9 +1,24 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
|
|
||||||
|
#if defined(QT_GUI_LIB)
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
int RunQT (int argc, char* argv[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
if (Daemon.init(argc, argv))
|
return i2p::qt::RunQT (argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
if (Daemon.init(argc, argv))
|
||||||
{
|
{
|
||||||
if (Daemon.start())
|
if (Daemon.start())
|
||||||
Daemon.run ();
|
Daemon.run ();
|
||||||
|
@ -11,6 +26,7 @@ int main( int argc, char* argv[] )
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
1
qt/.gitignore
vendored
Normal file
1
qt/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/build*/
|
161
qt/i2pd_qt/DaemonQT.cpp
Normal file
161
qt/i2pd_qt/DaemonQT.cpp
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
#include "DaemonQT.h"
|
||||||
|
#include "../../Daemon.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
Worker::Worker (DaemonQTImpl& daemon):
|
||||||
|
m_Daemon (daemon)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::startDaemon()
|
||||||
|
{
|
||||||
|
qDebug("Performing daemon start...");
|
||||||
|
m_Daemon.start();
|
||||||
|
qDebug("Daemon started.");
|
||||||
|
emit resultReady();
|
||||||
|
}
|
||||||
|
void Worker::restartDaemon()
|
||||||
|
{
|
||||||
|
qDebug("Performing daemon restart...");
|
||||||
|
m_Daemon.restart();
|
||||||
|
qDebug("Daemon restarted.");
|
||||||
|
emit resultReady();
|
||||||
|
}
|
||||||
|
void Worker::stopDaemon() {
|
||||||
|
qDebug("Performing daemon stop...");
|
||||||
|
m_Daemon.stop();
|
||||||
|
qDebug("Daemon stopped.");
|
||||||
|
emit resultReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller::Controller(DaemonQTImpl& 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()
|
||||||
|
{
|
||||||
|
qDebug("Closing and waiting for daemon worker thread...");
|
||||||
|
workerThread.quit();
|
||||||
|
workerThread.wait();
|
||||||
|
qDebug("Waiting for daemon worker thread finished.");
|
||||||
|
if(m_Daemon.isRunning())
|
||||||
|
{
|
||||||
|
qDebug("Stopping the daemon...");
|
||||||
|
m_Daemon.stop();
|
||||||
|
qDebug("Stopped the daemon.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DaemonQTImpl::DaemonQTImpl ():
|
||||||
|
mutex(nullptr), m_IsRunning(nullptr), m_RunningChangedCallback(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DaemonQTImpl::~DaemonQTImpl ()
|
||||||
|
{
|
||||||
|
delete mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DaemonQTImpl::init(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
mutex=new QMutex(QMutex::Recursive);
|
||||||
|
setRunningCallback(0);
|
||||||
|
m_IsRunning=false;
|
||||||
|
return Daemon.init(argc,argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonQTImpl::start()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(mutex);
|
||||||
|
setRunning(true);
|
||||||
|
Daemon.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonQTImpl::stop()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(mutex);
|
||||||
|
Daemon.stop();
|
||||||
|
setRunning(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonQTImpl::restart()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(mutex);
|
||||||
|
stop();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonQTImpl::setRunningCallback(runningChangedCallback cb)
|
||||||
|
{
|
||||||
|
m_RunningChangedCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DaemonQTImpl::isRunning()
|
||||||
|
{
|
||||||
|
return m_IsRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonQTImpl::setRunning(bool newValue)
|
||||||
|
{
|
||||||
|
bool oldValue = m_IsRunning;
|
||||||
|
if(oldValue!=newValue)
|
||||||
|
{
|
||||||
|
m_IsRunning = newValue;
|
||||||
|
if(m_RunningChangedCallback)
|
||||||
|
m_RunningChangedCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RunQT (int argc, char* argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
int result;
|
||||||
|
|
||||||
|
{
|
||||||
|
DaemonQTImpl daemon;
|
||||||
|
qDebug("Initialising the daemon...");
|
||||||
|
bool daemonInitSuccess = daemon.init(argc, argv);
|
||||||
|
if(!daemonInitSuccess)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(0, "Error", "Daemon init failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
qDebug("Initialised, creating the main window...");
|
||||||
|
MainWindow w;
|
||||||
|
qDebug("Before main window.show()...");
|
||||||
|
w.show ();
|
||||||
|
|
||||||
|
{
|
||||||
|
i2p::qt::Controller daemonQtController(daemon);
|
||||||
|
qDebug("Starting the daemon...");
|
||||||
|
emit daemonQtController.startDaemon();
|
||||||
|
//daemon.start ();
|
||||||
|
qDebug("Starting GUI event loop...");
|
||||||
|
result = app.exec();
|
||||||
|
//daemon.stop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//QMessageBox::information(&w, "Debug", "demon stopped");
|
||||||
|
qDebug("Exiting the application");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
81
qt/i2pd_qt/DaemonQT.h
Normal file
81
qt/i2pd_qt/DaemonQT.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef DAEMONQT_H
|
||||||
|
#define DAEMONQT_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
class DaemonQTImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
DaemonQTImpl ();
|
||||||
|
~DaemonQTImpl ();
|
||||||
|
|
||||||
|
typedef void (*runningChangedCallback)();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief init
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Worker : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
Worker (DaemonQTImpl& daemon);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DaemonQTImpl& m_Daemon;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startDaemon();
|
||||||
|
void restartDaemon();
|
||||||
|
void stopDaemon();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void resultReady();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Controller : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QThread workerThread;
|
||||||
|
public:
|
||||||
|
Controller(DaemonQTImpl& daemon);
|
||||||
|
~Controller();
|
||||||
|
private:
|
||||||
|
DaemonQTImpl& m_Daemon;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void handleResults(){}
|
||||||
|
signals:
|
||||||
|
void startDaemon();
|
||||||
|
void stopDaemon();
|
||||||
|
void restartDaemon();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DAEMONQT_H
|
1
qt/i2pd_qt/android/.gitignore
vendored
Normal file
1
qt/i2pd_qt/android/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/gen/
|
64
qt/i2pd_qt/android/AndroidManifest.xml
Normal file
64
qt/i2pd_qt/android/AndroidManifest.xml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="1" android:installLocation="auto">
|
||||||
|
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
|
||||||
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
|
<!-- <application android:hardwareAccelerated="true" -->
|
||||||
|
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="i2pd" android:icon="@drawable/icon">
|
||||||
|
<!-- android:configChanges="screenSize|smallestScreenSize" are since api 13, "layoutDirection" since api 17 -->
|
||||||
|
<activity android:configChanges="orientation|uiMode|screenLayout|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.purplei2p.i2pd.I2PDMainActivity" android:label="i2pd" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
|
||||||
|
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||||
|
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||||
|
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||||
|
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||||
|
<!-- Deploy Qt libs as part of package -->
|
||||||
|
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
|
||||||
|
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
|
||||||
|
<!-- Run with local libs -->
|
||||||
|
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||||
|
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
|
||||||
|
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
|
||||||
|
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
|
||||||
|
<!-- Messages maps -->
|
||||||
|
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||||
|
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||||
|
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||||
|
<!-- Messages maps -->
|
||||||
|
|
||||||
|
<!-- Splash screen -->
|
||||||
|
<!--
|
||||||
|
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
|
||||||
|
-->
|
||||||
|
<!-- Splash screen -->
|
||||||
|
|
||||||
|
<!-- Background running -->
|
||||||
|
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||||
|
application still try to draw after
|
||||||
|
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||||
|
signal is sent! -->
|
||||||
|
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||||
|
<!-- Background running -->
|
||||||
|
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
</activity>
|
||||||
|
<service android:enabled="true" android:name=".LocalService"/>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default permissions. -->
|
||||||
|
<!-- %%INSERT_PERMISSIONS -->
|
||||||
|
|
||||||
|
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default features. -->
|
||||||
|
<!-- %%INSERT_FEATURES -->
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
</manifest>
|
57
qt/i2pd_qt/android/build.gradle
Normal file
57
qt/i2pd_qt/android/build.gradle
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:1.1.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
/*******************************************************
|
||||||
|
* The following variables:
|
||||||
|
* - androidBuildToolsVersion,
|
||||||
|
* - androidCompileSdkVersion
|
||||||
|
* - qt5AndroidDir - holds the path to qt android files
|
||||||
|
* needed to build any Qt application
|
||||||
|
* on Android.
|
||||||
|
*
|
||||||
|
* are defined in gradle.properties file. This file is
|
||||||
|
* updated by QtCreator and androiddeployqt tools.
|
||||||
|
* Changing them manually might break the compilation!
|
||||||
|
*******************************************************/
|
||||||
|
|
||||||
|
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||||
|
|
||||||
|
buildToolsVersion androidBuildToolsVersion
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile 'AndroidManifest.xml'
|
||||||
|
java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java']
|
||||||
|
aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl']
|
||||||
|
res.srcDirs = [qt5AndroidDir + '/res', 'res']
|
||||||
|
resources.srcDirs = ['src']
|
||||||
|
renderscript.srcDirs = ['src']
|
||||||
|
assets.srcDirs = ['assets']
|
||||||
|
jniLibs.srcDirs = ['libs']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
}
|
BIN
qt/i2pd_qt/android/libs/android-support-v4.jar
Normal file
BIN
qt/i2pd_qt/android/libs/android-support-v4.jar
Normal file
Binary file not shown.
14
qt/i2pd_qt/android/project.properties
Normal file
14
qt/i2pd_qt/android/project.properties
Normal file
|
@ -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-11
|
BIN
qt/i2pd_qt/android/res/drawable-hdpi/icon.png
Normal file
BIN
qt/i2pd_qt/android/res/drawable-hdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
qt/i2pd_qt/android/res/drawable/itoopie_notification_icon.png
Normal file
BIN
qt/i2pd_qt/android/res/drawable/itoopie_notification_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
4
qt/i2pd_qt/android/res/layout/splash.xml
Normal file
4
qt/i2pd_qt/android/res/layout/splash.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent" />
|
6
qt/i2pd_qt/android/res/values-de/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-de/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Ministro-Dienst wurde nicht gefunden.\nAnwendung kann nicht gestartet werden</string>
|
||||||
|
<string name="ministro_needed_msg">Diese Anwendung benötigt den Ministro-Dienst. Möchten Sie ihn installieren?</string>
|
||||||
|
<string name="fatal_error_msg">In Ihrer Anwendung ist ein schwerwiegender Fehler aufgetreten, sie kann nicht fortgesetzt werden</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-el/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-el/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Δεν ήταν δυνατή η εύρεση της υπηρεσίας Ministro. Δεν είναι δυνατή η εκκίνηση της εφαρμογής.</string>
|
||||||
|
<string name="ministro_needed_msg">Η εφαρμογή απαιτεί την υπηρεσία Ministro. Να εγκατασταθεί η υπηρεσία?</string>
|
||||||
|
<string name="fatal_error_msg">Παρουσιάστηκε ένα κρίσιμο σφάλμα και η εφαρμογή δεν μπορεί να συνεχίσει.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-es/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-es/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Servicio Ministro inesistente. Imposible ejecutar la aplicación.</string>
|
||||||
|
<string name="ministro_needed_msg">Esta aplicación requiere el servicio Ministro. Instalarlo?</string>
|
||||||
|
<string name="fatal_error_msg">La aplicación ha causado un error grave y no es posible continuar.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-et/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-et/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Ei suuda leida Ministro teenust.\nProgrammi ei saa käivitada.</string>
|
||||||
|
<string name="ministro_needed_msg">See programm vajab Ministro teenust.\nKas soovite paigaldada?</string>
|
||||||
|
<string name="fatal_error_msg">Programmiga juhtus fataalne viga.\nKahjuks ei saa jätkata.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-fa/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-fa/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">سرویس Ministro را پیدا نمیکند. برنامه نمیتواند آغاز شود.</string>
|
||||||
|
<string name="ministro_needed_msg">این نرمافزار به سرویس Ministro احتیاج دارد. آیا دوست دارید آن را نصب کنید؟</string>
|
||||||
|
<string name="fatal_error_msg">خطایی اساسی در برنامهتان رخ داد و اجرای برنامه نمیتواند ادامه یابد.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-fr/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-fr/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Le service Ministro est introuvable.\nL\'application ne peut pas démarrer.</string>
|
||||||
|
<string name="ministro_needed_msg">Cette application requiert le service Ministro. Voulez-vous l\'installer?</string>
|
||||||
|
<string name="fatal_error_msg">Votre application a rencontré une erreur fatale et ne peut pas continuer.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-id/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-id/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Layanan Ministro tidak bisa ditemukan.\nAplikasi tidak bisa dimulai.</string>
|
||||||
|
<string name="ministro_needed_msg">Aplikasi ini membutuhkan layanan Ministro. Apakah Anda ingin menginstalnya?</string>
|
||||||
|
<string name="fatal_error_msg">Aplikasi Anda mengalami kesalahan fatal dan tidak dapat melanjutkan.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-it/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-it/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Servizio Ministro inesistente. Impossibile eseguire \nl\'applicazione.</string>
|
||||||
|
<string name="ministro_needed_msg">Questa applicazione richiede il servizio Ministro.Installarlo?</string>
|
||||||
|
<string name="fatal_error_msg">L\'applicazione ha provocato un errore grave e non puo\' continuare.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-ja/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-ja/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Ministroサービスが見つかりません。\nアプリケーションが起動できません。</string>
|
||||||
|
<string name="ministro_needed_msg">このアプリケーションにはMinistroサービスが必要です。 インストールしてもよろしいですか?</string>
|
||||||
|
<string name="fatal_error_msg">アプリケーションで致命的なエラーが発生したため続行できません。</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-ms/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-ms/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Tidak jumpa servis Ministro.\nAplikasi tidak boleh dimulakan.</string>
|
||||||
|
<string name="ministro_needed_msg">Aplikasi ini memerlukan servis Ministro. Adakah anda ingin pasang servis itu?</string>
|
||||||
|
<string name="fatal_error_msg">Aplikasi anda menemui ralat muat dan tidak boleh diteruskan.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-nb/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-nb/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Kan ikke finne tjenesten Ministro. Applikasjonen kan ikke starte.</string>
|
||||||
|
<string name="ministro_needed_msg">Denne applikasjonen krever tjenesten Ministro. Vil du installere denne?</string>
|
||||||
|
<string name="fatal_error_msg">Applikasjonen fikk en kritisk feil og kan ikke fortsette</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-nl/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-nl/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">De Ministro service is niet gevonden.\nDe applicatie kan niet starten.</string>
|
||||||
|
<string name="ministro_needed_msg">Deze applicatie maakt gebruik van de Ministro service. Wilt u deze installeren?</string>
|
||||||
|
<string name="fatal_error_msg">Er is een fatale fout in de applicatie opgetreden. De applicatie kan niet verder gaan.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-pl/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-pl/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Usługa Ministro nie została znaleziona.\nAplikacja nie może zostać uruchomiona.</string>
|
||||||
|
<string name="ministro_needed_msg">Aplikacja wymaga usługi Ministro. Czy chcesz ją zainstalować?</string>
|
||||||
|
<string name="fatal_error_msg">Wystąpił błąd krytyczny. Aplikacja zostanie zamknięta.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-pt-rBR/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-pt-rBR/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Não foi possível encontrar o serviço Ministro.\nA aplicação não pode iniciar.</string>
|
||||||
|
<string name="ministro_needed_msg">Essa aplicação requer o serviço Ministro. Gostaria de instalá-lo?</string>
|
||||||
|
<string name="fatal_error_msg">Sua aplicação encontrou um erro fatal e não pode continuar.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-ro/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-ro/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Serviciul Ministro nu poate fi găsit.\nAplicaţia nu poate porni.</string>
|
||||||
|
<string name="ministro_needed_msg">Această aplicaţie necesită serviciul Ministro.\nDoriţi să-l instalaţi?</string>
|
||||||
|
<string name="fatal_error_msg">Aplicaţia dumneavoastră a întâmpinat o eroare fatală şi nu poate continua.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-rs/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-rs/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Ministro servise nije pronađen. Aplikacija ne može biti pokrenuta.</string>
|
||||||
|
<string name="ministro_needed_msg">Ova aplikacija zahteva Ministro servis. Želite li da ga instalirate?</string>
|
||||||
|
<string name="fatal_error_msg">Vaša aplikacija je naišla na fatalnu grešku i ne može nastaviti sa radom.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-ru/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-ru/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">Сервис Ministro не найден.\nПриложение нельзя запустить.</string>
|
||||||
|
<string name="ministro_needed_msg">Этому приложению необходим сервис Ministro. Вы хотите его установить?</string>
|
||||||
|
<string name="fatal_error_msg">Ваше приложение столкнулось с фатальной ошибкой и не может более работать.</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-zh-rCN/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-zh-rCN/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">无法找到Ministro服务。\n应用程序无法启动。</string>
|
||||||
|
<string name="ministro_needed_msg">此应用程序需要Ministro服务。您想安装它吗?</string>
|
||||||
|
<string name="fatal_error_msg">您的应用程序遇到一个致命错误导致它无法继续。</string>
|
||||||
|
</resources>
|
6
qt/i2pd_qt/android/res/values-zh-rTW/strings.xml
Normal file
6
qt/i2pd_qt/android/res/values-zh-rTW/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="ministro_not_found_msg">無法找到Ministro服務。\n應用程序無法啟動。</string>
|
||||||
|
<string name="ministro_needed_msg">此應用程序需要Ministro服務。您想安裝它嗎?</string>
|
||||||
|
<string name="fatal_error_msg">您的應用程序遇到一個致命錯誤導致它無法繼續。</string>
|
||||||
|
</resources>
|
25
qt/i2pd_qt/android/res/values/libs.xml
Normal file
25
qt/i2pd_qt/android/res/values/libs.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<array name="qt_sources">
|
||||||
|
<item>https://download.qt-project.org/ministro/android/qt5/qt-5.4</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<!-- The following is handled automatically by the deployment tool. It should
|
||||||
|
not be edited manually. -->
|
||||||
|
|
||||||
|
<array name="bundled_libs">
|
||||||
|
<!-- %%INSERT_EXTRA_LIBS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="qt_libs">
|
||||||
|
<!-- %%INSERT_QT_LIBS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="bundled_in_lib">
|
||||||
|
<!-- %%INSERT_BUNDLED_IN_LIB%% -->
|
||||||
|
</array>
|
||||||
|
<array name="bundled_in_assets">
|
||||||
|
<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->
|
||||||
|
</array>
|
||||||
|
|
||||||
|
</resources>
|
10
qt/i2pd_qt/android/res/values/strings.xml
Normal file
10
qt/i2pd_qt/android/res/values/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<!-- %%INSERT_STRINGS -->
|
||||||
|
<string name="ministro_not_found_msg">Can\'t find Ministro service.\nThe application can\'t start.</string>
|
||||||
|
<string name="ministro_needed_msg">This application requires Ministro service. Would you like to install it?</string>
|
||||||
|
<string name="fatal_error_msg">Your application encountered a fatal error and cannot continue.</string>
|
||||||
|
<string name="local_service_started">i2pd started</string>
|
||||||
|
<string name="local_service_stopped">i2pd stopped</string>
|
||||||
|
<string name="local_service_label">i2pd</string>
|
||||||
|
</resources>
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011-2013, BogDan Vatra <bogdan@kde.org>
|
||||||
|
Contact: http://www.qt.io/licensing/
|
||||||
|
|
||||||
|
Commercial License Usage
|
||||||
|
Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
accordance with the commercial license agreement provided with the
|
||||||
|
Software or, alternatively, in accordance with the terms contained in
|
||||||
|
a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
and conditions see http://www.qt.io/terms-conditions. For further
|
||||||
|
information use the contact form at http://www.qt.io/contact-us.
|
||||||
|
|
||||||
|
BSD License Usage
|
||||||
|
Alternatively, this file may be used under the BSD license as follows:
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.kde.necessitas.ministro;
|
||||||
|
|
||||||
|
import org.kde.necessitas.ministro.IMinistroCallback;
|
||||||
|
|
||||||
|
interface IMinistro
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check/download required libs to run the application
|
||||||
|
*
|
||||||
|
* param callback - interface used by Minsitro service to notify the client when the loader is ready
|
||||||
|
* param parameters
|
||||||
|
* parameters fields:
|
||||||
|
* * Key Name Key type Explanations
|
||||||
|
* "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations.
|
||||||
|
* "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable
|
||||||
|
* "required.modules" StringArray Required modules by your application
|
||||||
|
* "application.title" String Application name, used to show more informations to user
|
||||||
|
* "qt.provider" String Qt libs provider, currently only "necessitas" is supported.
|
||||||
|
* "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 !
|
||||||
|
* "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)!
|
||||||
|
*/
|
||||||
|
void requestLoader(in IMinistroCallback callback, in Bundle parameters);
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2011-2013, BogDan Vatra <bogdan@kde.org>
|
||||||
|
Contact: http://www.qt.io/licensing/
|
||||||
|
|
||||||
|
Commercial License Usage
|
||||||
|
Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
accordance with the commercial license agreement provided with the
|
||||||
|
Software or, alternatively, in accordance with the terms contained in
|
||||||
|
a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
and conditions see http://www.qt.io/terms-conditions. For further
|
||||||
|
information use the contact form at http://www.qt.io/contact-us.
|
||||||
|
|
||||||
|
BSD License Usage
|
||||||
|
Alternatively, this file may be used under the BSD license as follows:
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kde.necessitas.ministro;
|
||||||
|
|
||||||
|
oneway interface IMinistroCallback {
|
||||||
|
/**
|
||||||
|
* This method is called by the Ministro service back into the application which
|
||||||
|
* implements this interface.
|
||||||
|
*
|
||||||
|
* param in - loaderParams
|
||||||
|
* loaderParams fields:
|
||||||
|
* * Key Name Key type Explanations
|
||||||
|
* * "error.code" Integer See below
|
||||||
|
* * "error.message" String Missing if no error, otherwise will contain the error message translated into phone language where available.
|
||||||
|
* * "dex.path" String The list of jar/apk files containing classes and resources, needed to be passed to application DexClassLoader
|
||||||
|
* * "lib.path" String The list of directories containing native libraries; may be missing, needed to be passed to application DexClassLoader
|
||||||
|
* * "loader.class.name" String Loader class name.
|
||||||
|
*
|
||||||
|
* "error.code" field possible errors:
|
||||||
|
* - 0 no error.
|
||||||
|
* - 1 incompatible Ministro version. Ministro needs to be upgraded.
|
||||||
|
* - 2 not all modules could be satisfy.
|
||||||
|
* - 3 invalid parameters
|
||||||
|
* - 4 invalid qt version
|
||||||
|
* - 5 download canceled
|
||||||
|
*
|
||||||
|
* The parameter contains additional fields which are used by the loader to start your application, so it must be passed to the loader.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void loaderReady(in Bundle loaderParams);
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
|
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
public class I2PDMainActivity extends QtActivity
|
||||||
|
{
|
||||||
|
|
||||||
|
private static I2PDMainActivity instance;
|
||||||
|
|
||||||
|
public I2PDMainActivity() {}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.qtproject.qt5.android.bindings.QtActivity#onCreate(android.os.Bundle)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
I2PDMainActivity.setInstance(this);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
//set the app be foreground (do not unload when RAM needed)
|
||||||
|
doBindService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.qtproject.qt5.android.bindings.QtActivity#onDestroy()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
I2PDMainActivity.setInstance(null);
|
||||||
|
doUnbindService();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static I2PDMainActivity getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setInstance(I2PDMainActivity instance) {
|
||||||
|
I2PDMainActivity.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// private LocalService mBoundService;
|
||||||
|
|
||||||
|
private ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
|
// This is called when the connection with the service has been
|
||||||
|
// established, giving us the service object we can use to
|
||||||
|
// interact with the service. Because we have bound to a explicit
|
||||||
|
// service that we know is running in our own process, we can
|
||||||
|
// cast its IBinder to a concrete class and directly access it.
|
||||||
|
// mBoundService = ((LocalService.LocalBinder)service).getService();
|
||||||
|
|
||||||
|
// Tell the user about this for our demo.
|
||||||
|
// Toast.makeText(Binding.this, R.string.local_service_connected,
|
||||||
|
// Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
// This is called when the connection with the service has been
|
||||||
|
// unexpectedly disconnected -- that is, its process crashed.
|
||||||
|
// Because it is running in our same process, we should never
|
||||||
|
// see this happen.
|
||||||
|
// mBoundService = null;
|
||||||
|
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
|
||||||
|
// Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean mIsBound;
|
||||||
|
|
||||||
|
private void doBindService() {
|
||||||
|
// Establish a connection with the service. We use an explicit
|
||||||
|
// class name because we want a specific service implementation that
|
||||||
|
// we know will be running in our own process (and thus won't be
|
||||||
|
// supporting component replacement by other applications).
|
||||||
|
bindService(new Intent(this,
|
||||||
|
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
mIsBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doUnbindService() {
|
||||||
|
if (mIsBound) {
|
||||||
|
// Detach our existing connection.
|
||||||
|
unbindService(mConnection);
|
||||||
|
mIsBound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
qt/i2pd_qt/android/src/org/purplei2p/i2pd/LocalService.java
Normal file
92
qt/i2pd_qt/android/src/org/purplei2p/i2pd/LocalService.java
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class LocalService extends Service {
|
||||||
|
// private NotificationManager mNM;
|
||||||
|
|
||||||
|
// Unique Identification Number for the Notification.
|
||||||
|
// We use it on Notification start, and to cancel it.
|
||||||
|
private int NOTIFICATION = R.string.local_service_started;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for clients to access. Because we know this service always
|
||||||
|
* runs in the same process as its clients, we don't need to deal with
|
||||||
|
* IPC.
|
||||||
|
*/
|
||||||
|
public class LocalBinder extends Binder {
|
||||||
|
LocalService getService() {
|
||||||
|
return LocalService.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
// mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
|
// Display a notification about us starting. We put an icon in the status bar.
|
||||||
|
showNotification();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
Log.i("LocalService", "Received start id " + startId + ": " + intent);
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
// Cancel the persistent notification.
|
||||||
|
//mNM.cancel(NOTIFICATION);
|
||||||
|
stopForeground(true);
|
||||||
|
|
||||||
|
// Tell the user we stopped.
|
||||||
|
Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the object that receives interactions from clients. See
|
||||||
|
// RemoteService for a more complete example.
|
||||||
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a notification while this service is running.
|
||||||
|
*/
|
||||||
|
private void showNotification() {
|
||||||
|
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||||
|
CharSequence text = getText(R.string.local_service_started);
|
||||||
|
|
||||||
|
// The PendingIntent to launch our activity if the user selects this notification
|
||||||
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
|
new Intent(this, I2PDMainActivity.class), 0);
|
||||||
|
|
||||||
|
// Set the info for the views that show in the notification panel.
|
||||||
|
Notification notification = new NotificationCompat.Builder(this)
|
||||||
|
.setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon
|
||||||
|
.setTicker(text) // the status text
|
||||||
|
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||||
|
.setContentTitle(getText(R.string.local_service_label)) // the label of the entry
|
||||||
|
.setContentText(text) // the contents of the entry
|
||||||
|
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Send the notification.
|
||||||
|
//mNM.notify(NOTIFICATION, notification);
|
||||||
|
startForeground(NOTIFICATION, notification);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2012-2013, BogDan Vatra <bogdan@kde.org>
|
||||||
|
Contact: http://www.qt.io/licensing/
|
||||||
|
|
||||||
|
Commercial License Usage
|
||||||
|
Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
accordance with the commercial license agreement provided with the
|
||||||
|
Software or, alternatively, in accordance with the terms contained in
|
||||||
|
a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
and conditions see http://www.qt.io/terms-conditions. For further
|
||||||
|
information use the contact form at http://www.qt.io/contact-us.
|
||||||
|
|
||||||
|
BSD License Usage
|
||||||
|
Alternatively, this file may be used under the BSD license as follows:
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.qtproject.qt5.android.bindings;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
public class QtApplication extends Application
|
||||||
|
{
|
||||||
|
public final static String QtTAG = "Qt";
|
||||||
|
public static Object m_delegateObject = null;
|
||||||
|
public static HashMap<String, ArrayList<Method>> m_delegateMethods= new HashMap<String, ArrayList<Method>>();
|
||||||
|
public static Method dispatchKeyEvent = null;
|
||||||
|
public static Method dispatchPopulateAccessibilityEvent = null;
|
||||||
|
public static Method dispatchTouchEvent = null;
|
||||||
|
public static Method dispatchTrackballEvent = null;
|
||||||
|
public static Method onKeyDown = null;
|
||||||
|
public static Method onKeyMultiple = null;
|
||||||
|
public static Method onKeyUp = null;
|
||||||
|
public static Method onTouchEvent = null;
|
||||||
|
public static Method onTrackballEvent = null;
|
||||||
|
public static Method onActivityResult = null;
|
||||||
|
public static Method onCreate = null;
|
||||||
|
public static Method onKeyLongPress = null;
|
||||||
|
public static Method dispatchKeyShortcutEvent = null;
|
||||||
|
public static Method onKeyShortcut = null;
|
||||||
|
public static Method dispatchGenericMotionEvent = null;
|
||||||
|
public static Method onGenericMotionEvent = null;
|
||||||
|
|
||||||
|
public static void setQtActivityDelegate(Object listener)
|
||||||
|
{
|
||||||
|
QtApplication.m_delegateObject = listener;
|
||||||
|
|
||||||
|
ArrayList<Method> delegateMethods = new ArrayList<Method>();
|
||||||
|
for (Method m : listener.getClass().getMethods()) {
|
||||||
|
if (m.getDeclaringClass().getName().startsWith("org.qtproject.qt5.android"))
|
||||||
|
delegateMethods.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Field> applicationFields = new ArrayList<Field>();
|
||||||
|
for (Field f : QtApplication.class.getFields()) {
|
||||||
|
if (f.getDeclaringClass().getName().equals(QtApplication.class.getName()))
|
||||||
|
applicationFields.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Method delegateMethod : delegateMethods) {
|
||||||
|
try {
|
||||||
|
QtActivity.class.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
|
||||||
|
if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) {
|
||||||
|
QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod);
|
||||||
|
} else {
|
||||||
|
ArrayList<Method> delegateSet = new ArrayList<Method>();
|
||||||
|
delegateSet.add(delegateMethod);
|
||||||
|
QtApplication.m_delegateMethods.put(delegateMethod.getName(), delegateSet);
|
||||||
|
}
|
||||||
|
for (Field applicationField:applicationFields) {
|
||||||
|
if (applicationField.getName().equals(delegateMethod.getName())) {
|
||||||
|
try {
|
||||||
|
applicationField.set(null, delegateMethod);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTerminate() {
|
||||||
|
if (m_delegateObject != null && m_delegateMethods.containsKey("onTerminate"))
|
||||||
|
invokeDelegateMethod(m_delegateMethods.get("onTerminate").get(0));
|
||||||
|
super.onTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InvokeResult
|
||||||
|
{
|
||||||
|
public boolean invoked = false;
|
||||||
|
public Object methodReturns = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int stackDeep=-1;
|
||||||
|
public static InvokeResult invokeDelegate(Object... args)
|
||||||
|
{
|
||||||
|
InvokeResult result = new InvokeResult();
|
||||||
|
if (m_delegateObject == null)
|
||||||
|
return result;
|
||||||
|
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
||||||
|
if (-1 == stackDeep) {
|
||||||
|
String activityClassName = QtActivity.class.getCanonicalName();
|
||||||
|
for (int it=0;it<elements.length;it++)
|
||||||
|
if (elements[it].getClassName().equals(activityClassName)) {
|
||||||
|
stackDeep = it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final String methodName=elements[stackDeep].getMethodName();
|
||||||
|
if (-1 == stackDeep || !m_delegateMethods.containsKey(methodName))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
for (Method m : m_delegateMethods.get(methodName)) {
|
||||||
|
if (m.getParameterTypes().length == args.length) {
|
||||||
|
result.methodReturns = invokeDelegateMethod(m, args);
|
||||||
|
result.invoked = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object invokeDelegateMethod(Method m, Object... args)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return m.invoke(m_delegateObject, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
59
qt/i2pd_qt/docs/patch_openssl_so_libs.html
Normal file
59
qt/i2pd_qt/docs/patch_openssl_so_libs.html
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="ru" class=" ya-page_js_yes"><head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
|
||||||
|
<h1 id="blog_title" style="font-size:14pt; font-weight:normal; margin:0px">
|
||||||
|
OpenSSL под Android в Qt
|
||||||
|
|
||||||
|
</h1> <div class="smallfont shade"> <span class="shade">Запись от <a href="http://www.cyberforum.ru/blogs/748276/">Wyn</a> размещена 18.01.2016 в 18:22</span> </div> <script type="text/javascript" src="./patch_openssl_so_libs_files/blog_ajax_tag.js"></script> <div class="smallfont" id="blogtagcontainer_4086"> <span class="shade">Метки</span> <span id="blogtaglist_4086"><a href="http://www.cyberforum.ru/blog.php?tag=android&u=748276">android</a>, <a href="http://www.cyberforum.ru/blog.php?tag=openssl&u=748276">openssl</a>, <a href="http://www.cyberforum.ru/blog.php?tag=qt&u=748276">qt</a></span> </div> <div style="clear:both; margin-top:4px"></div> <hr size="1" style="color:#AAAAAA; background-color:#AAAAAA; margin-bottom:10px"> <div id="blog_message" style="margin-bottom:10px"><!-- google_ad_section_start --><!-- google_ad_section_start -->Мини-руководство по тому, как быстро скомпилировать OpenSSL для Android и связать его с проектом Qt.<br>
|
||||||
|
Для Linux.<br> <br>
|
||||||
|
Вначале действия полностью идентичны <a rel="nofollow" href="https://wiki.openssl.org/index.php/Android" target="_blank" title="https://wiki.openssl.org/index.php/Android">"расово-верному" руководству по компилянию OpenSSL для Android</a>:<br>
|
||||||
|
Качаем исходники openssl нужной версии с их сайта, качаем setenv-android.sh(все ссылки на закачку выше по ссылке).<br>
|
||||||
|
Ложим их в одну папку. Запускаем консоль, переходим в ней в эту самую папку.<br>
|
||||||
|
Далее:<br> <div style="margin: 5px 10px 5px 30px"><table class="bash"><thead><tr><td colspan="2" class="head">Bash<a href="http://www.cyberforum.ru/#" style="float: right; color: rgb(96, 96, 96); font-weight: normal;">Выделить код</a></td></tr></thead><tbody><tr class="li1"><td><div id="52254522" style="overflow: auto; width: 805px; height: 73px"><table><tbody><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
</pre></td><td class="de1"><pre class="de1">$ <span class="kw2">rm</span> <span class="re5">-rf</span> openssl-1.0.1g<span class="sy0">/</span> <span class="co0"># удаляем исходники(вместо версии 1.0.1g - подставляем свою), если они уже были распакованы</span>
|
||||||
|
$ <span class="kw2">tar</span> xzf openssl-1.0.1g.tar.gz <span class="co0"># распаковываем исходники в подпапку</span>
|
||||||
|
$ <span class="kw2">chmod</span> a+x setenv-android.sh <span class="co0"># разрешаем setenv-android.sh исполняться</span></pre></td></tr></tbody></table></div></td></tr></tbody></table></div>Редактируем setenv-android.sh, настраивая там _ANDROID_EABI, _ANDROID_ARCH, _ANDROID_API на нужные значения.<br>
|
||||||
|
Дальше возвращаемся в консоль:<br> <div style="margin: 5px 10px 5px 30px"><table class="bash"><thead><tr><td colspan="2" class="head">Bash<a href="http://www.cyberforum.ru/#" style="float: right; color: rgb(96, 96, 96); font-weight: normal;">Выделить код</a></td></tr></thead><tbody><tr class="li1"><td><div id="701353202" style="overflow: auto; width: 805px; height: 201px"><table><tbody><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
10
|
||||||
|
11
|
||||||
|
</pre></td><td class="de1"><pre class="de1">$ <span class="kw3">export</span> <span class="re2">ANDROID_NDK_ROOT</span>=путь_до_ANDROID_NDK <span class="co0"># указываем путь до Android NDK для setenv-android.sh</span>
|
||||||
|
$ . .<span class="sy0">/</span>setenv-android.sh <span class="co0"># запускаем скрипт, чтобы он нам в окружение проставил необходимые далее переменные</span>
|
||||||
|
$ <span class="kw3">cd</span> openssl-1.0.1g<span class="sy0">/</span>
|
||||||
|
$ <span class="kw2">perl</span> <span class="re5">-pi</span> <span class="re5">-e</span> <span class="st_h">'s/install: all install_docs install_sw/install: install_docs install_sw/g'</span> Makefile.org
|
||||||
|
<span class="co0"># конфигурируем</span>
|
||||||
|
$ .<span class="sy0">/</span>config shared no-ssl2 no-ssl3 no-comp no-hw no-engine <span class="re5">--openssldir</span>=<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>ssl<span class="sy0">/</span><span class="re1">$ANDROID_API</span>
|
||||||
|
<span class="co0"># собираем</span>
|
||||||
|
$ <span class="kw2">make</span> depend
|
||||||
|
$ <span class="kw2">make</span> all
|
||||||
|
<span class="co0"># устанавливаем</span>
|
||||||
|
$ <span class="kw2">sudo</span> <span class="re5">-E</span> <span class="kw2">make</span> <span class="kw2">install</span> <span class="re2">CC</span>=<span class="re1">$ANDROID_TOOLCHAIN</span><span class="sy0">/</span>arm-linux-androideabi-gcc <span class="re2">RANLIB</span>=<span class="re1">$ANDROID_TOOLCHAIN</span><span class="sy0">/</span>arm-linux-androideabi-ranlib</pre></td></tr></tbody></table></div></td></tr></tbody></table></div>И тут начинается интересное. Андроид не принимает versioned shared object (это *.so.x и подобные). Казалось бы 2016 год, космические корабли уже давно бороздят просторы Большого театра, но вот те на. <br> <br>
|
||||||
|
Однако, есть обходной приём - нужно заменить *.so.x.x.x на *_x_x_x.so. Простым переименованием файлов данную проблему здесь, разумеется, не решить. Нужно лезть внутрь и переименовывать soname и внутренние ссылки на другие versioned shared object. В интернете есть много способов по подобному переименованию. Большинство из них обещают райскую жизнь с rpl, забывая упомянуть, что утилита уже давно отпета и закопана на большинстве дистрибутивов. Или хитро-хитро редактируют makefile, что в итоге на место левой руки собирается правая нога. В целом множество путей из разряда "как потратить много времени на полную фигню". <br> <br>
|
||||||
|
В итоге предлагаю решить данную проблему методом топора:<br>
|
||||||
|
Качаем hex-редактор, если ещё нет(в моём случае таковым оказался Okteta). Запускаем его из под рута(kdesu okteta), открываем в нём файлы openssldir/lib/libcrypto.so.1.0.0. Заменяем(ctrl+r) в нём символы ".so.1.0.0" на char "_1_0_0.so". Проделываем тоже самое с libssl.so.1.0.0. Всё, теперь осталось только переименовать сами файлы(в libcrypto_1_0_0.so и libssl_1_0_0.so) и поправить ссылки libssl.so и libcrypto.so, чтобы они вели на них.<br> <br>
|
||||||
|
Чтобы подключить и использовать данную библиотеку в проекте нужно добавить в .pro:<br> <div style="margin: 5px 10px 5px 30px"><table class="bash"><thead><tr><td colspan="2" class="head">Bash<a href="http://www.cyberforum.ru/#" style="float: right; color: rgb(96, 96, 96); font-weight: normal;">Выделить код</a></td></tr></thead><tbody><tr class="li1"><td><div id="304166412" style="overflow: auto; width: 805px; height: 105px"><table><tbody><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
</pre></td><td class="de1"><pre class="de1">android: <span class="br0">{</span>
|
||||||
|
INCLUDEPATH += <span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>ssl<span class="sy0">/</span>android-<span class="nu0">21</span><span class="sy0">/</span>include
|
||||||
|
LIBS += -L<span class="sy0">/</span>usr<span class="sy0">/</span>local<span class="sy0">/</span>ssl<span class="sy0">/</span>android-<span class="nu0">21</span><span class="sy0">/</span>lib
|
||||||
|
<span class="br0">}</span>
|
||||||
|
LIBS += <span class="re5">-lcrypto</span></pre></td></tr></tbody></table></div></td></tr></tbody></table></div>А затем в настройках проекта, в Buld/Build Steps/Bulild Android Apk добавить libcrypto_1_0_0.so и libssl_1_0_0.so в список Additional Libraries.<br> <br>
|
||||||
|
На этом всё.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<p><small>Original: http://www.cyberforum.ru/blogs/748276/blog4086.html</small></p>
|
||||||
|
|
||||||
|
</body></html>
|
192
qt/i2pd_qt/i2pd_qt.pro
Normal file
192
qt/i2pd_qt/i2pd_qt.pro
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#-------------------------------------------------
|
||||||
|
#
|
||||||
|
# Project created by QtCreator 2016-06-14T04:53:04
|
||||||
|
#
|
||||||
|
#-------------------------------------------------
|
||||||
|
|
||||||
|
QT += core gui
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
TARGET = i2pd_qt
|
||||||
|
TEMPLATE = app
|
||||||
|
QMAKE_CXXFLAGS *= -std=c++11
|
||||||
|
|
||||||
|
# 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/android-ifaddrs.git
|
||||||
|
# change to your own
|
||||||
|
BOOST_PATH = /mnt/media/android/Boost-for-Android-Prebuilt
|
||||||
|
OPENSSL_PATH = /mnt/media/android/OpenSSL-for-Android-Prebuilt
|
||||||
|
IFADDRS_PATH = /mnt/media/android/android-ifaddrs
|
||||||
|
|
||||||
|
# Steps in Android SDK manager:
|
||||||
|
# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html
|
||||||
|
# 2) Check API 11
|
||||||
|
# Finally, click Install.
|
||||||
|
|
||||||
|
SOURCES += DaemonQT.cpp\
|
||||||
|
mainwindow.cpp \
|
||||||
|
../../HTTPServer.cpp ../../I2PControl.cpp ../../UPnP.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 \
|
||||||
|
../../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 \
|
||||||
|
../../util.cpp \
|
||||||
|
../../i2pd.cpp \
|
||||||
|
$$IFADDRS_PATH/ifaddrs.c
|
||||||
|
|
||||||
|
HEADERS += DaemonQT.h mainwindow.h \
|
||||||
|
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
|
||||||
|
../../AddressBook.h \
|
||||||
|
../../api.h \
|
||||||
|
../../Base.h \
|
||||||
|
../../BOB.h \
|
||||||
|
../../ClientContext.h \
|
||||||
|
../../Crypto.h \
|
||||||
|
../../Datagram.h \
|
||||||
|
../../Destination.h \
|
||||||
|
../../Family.h \
|
||||||
|
../../FS.h \
|
||||||
|
../../Garlic.h \
|
||||||
|
../../HTTP.h \
|
||||||
|
../../HTTPProxy.h \
|
||||||
|
../../I2CP.h \
|
||||||
|
../../I2NPProtocol.h \
|
||||||
|
../../I2PEndian.h \
|
||||||
|
../../I2PService.h \
|
||||||
|
../../I2PTunnel.h \
|
||||||
|
../../Identity.h \
|
||||||
|
../../LeaseSet.h \
|
||||||
|
../../LittleBigEndian.h \
|
||||||
|
../../Log.h \
|
||||||
|
../../NetDb.h \
|
||||||
|
../../NetDbRequests.h \
|
||||||
|
../../NTCPSession.h \
|
||||||
|
../../Profiling.h \
|
||||||
|
../../Queue.h \
|
||||||
|
../../Reseed.h \
|
||||||
|
../../RouterContext.h \
|
||||||
|
../../RouterInfo.h \
|
||||||
|
../../SAM.h \
|
||||||
|
../../Signature.h \
|
||||||
|
../../SOCKS.h \
|
||||||
|
../../SSU.h \
|
||||||
|
../../SSUData.h \
|
||||||
|
../../SSUSession.h \
|
||||||
|
../../Streaming.h \
|
||||||
|
../../Timestamp.h \
|
||||||
|
../../TransitTunnel.h \
|
||||||
|
../../Transports.h \
|
||||||
|
../../TransportSession.h \
|
||||||
|
../../Tunnel.h \
|
||||||
|
../../TunnelBase.h \
|
||||||
|
../../TunnelConfig.h \
|
||||||
|
../../TunnelEndpoint.h \
|
||||||
|
../../TunnelGateway.h \
|
||||||
|
../../TunnelPool.h \
|
||||||
|
../../util.h \
|
||||||
|
../../version.h \
|
||||||
|
$$IFADDRS_PATH/ifaddrs.h
|
||||||
|
|
||||||
|
FORMS += mainwindow.ui
|
||||||
|
|
||||||
|
CONFIG += mobility
|
||||||
|
|
||||||
|
MOBILITY =
|
||||||
|
|
||||||
|
LIBS += -lz
|
||||||
|
|
||||||
|
android {
|
||||||
|
message("Using Android settings")
|
||||||
|
DEFINES += ANDROID=1
|
||||||
|
DEFINES += __ANDROID__
|
||||||
|
INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
|
||||||
|
$$OPENSSL_PATH/openssl-1.0.2/include \
|
||||||
|
$$IFADDRS_PATH
|
||||||
|
DISTFILES += \
|
||||||
|
android/AndroidManifest.xml
|
||||||
|
|
||||||
|
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||||
|
|
||||||
|
equals(ANDROID_TARGET_ARCH, armeabi-v7a){
|
||||||
|
|
||||||
|
DEFINES += ANDROID_ARM7A
|
||||||
|
|
||||||
|
# http://stackoverflow.com/a/30235934/529442
|
||||||
|
LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
|
||||||
|
-lboost_system-gcc-mt-1_53 \
|
||||||
|
-lboost_date_time-gcc-mt-1_53 \
|
||||||
|
-lboost_filesystem-gcc-mt-1_53 \
|
||||||
|
-lboost_program_options-gcc-mt-1_53 \
|
||||||
|
-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl
|
||||||
|
|
||||||
|
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
|
||||||
|
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a
|
||||||
|
|
||||||
|
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
|
||||||
|
|
||||||
|
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \
|
||||||
|
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so
|
||||||
|
}
|
||||||
|
equals(ANDROID_TARGET_ARCH, x86){
|
||||||
|
# http://stackoverflow.com/a/30235934/529442
|
||||||
|
LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
|
||||||
|
-lboost_system-gcc-mt-1_53 \
|
||||||
|
-lboost_date_time-gcc-mt-1_53 \
|
||||||
|
-lboost_filesystem-gcc-mt-1_53 \
|
||||||
|
-lboost_program_options-gcc-mt-1_53 \
|
||||||
|
-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl
|
||||||
|
|
||||||
|
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
|
||||||
|
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a
|
||||||
|
|
||||||
|
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
|
||||||
|
|
||||||
|
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \
|
||||||
|
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linux:!android {
|
||||||
|
message("Using Linux settings")
|
||||||
|
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||||
|
}
|
||||||
|
|
55
qt/i2pd_qt/mainwindow.cpp
Normal file
55
qt/i2pd_qt/mainwindow.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
//#include "ui_mainwindow.h"
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent)/*,
|
||||||
|
ui(new Ui::MainWindow)*/
|
||||||
|
{
|
||||||
|
//ui->setupUi(this);
|
||||||
|
if (objectName().isEmpty())
|
||||||
|
setObjectName(QStringLiteral("MainWindow"));
|
||||||
|
resize(800, 480);
|
||||||
|
centralWidget = new QWidget(this);
|
||||||
|
centralWidget->setObjectName(QStringLiteral("centralWidget"));
|
||||||
|
verticalLayoutWidget = new QWidget(centralWidget);
|
||||||
|
verticalLayoutWidget->setObjectName(QStringLiteral("verticalLayoutWidget"));
|
||||||
|
//verticalLayoutWidget->setGeometry(QRect(10, 20, 771, 441));
|
||||||
|
verticalLayout1 = new QVBoxLayout(verticalLayoutWidget);
|
||||||
|
verticalLayout1->setSpacing(6);
|
||||||
|
verticalLayout1->setContentsMargins(11, 11, 11, 11);
|
||||||
|
verticalLayout1->setObjectName(QStringLiteral("verticalLayout1"));
|
||||||
|
verticalLayout1->setContentsMargins(0, 0, 0, 0);
|
||||||
|
quitButton = new QPushButton(verticalLayoutWidget);
|
||||||
|
quitButton->setObjectName(QStringLiteral("quitButton"));
|
||||||
|
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||||
|
sizePolicy.setHorizontalStretch(0);
|
||||||
|
sizePolicy.setVerticalStretch(0);
|
||||||
|
sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth());
|
||||||
|
quitButton->setSizePolicy(sizePolicy);
|
||||||
|
|
||||||
|
verticalLayout1->addWidget(quitButton);
|
||||||
|
|
||||||
|
setCentralWidget(centralWidget);
|
||||||
|
|
||||||
|
setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
|
||||||
|
quitButton->setText(QApplication::translate("MainWindow", "Quit", 0));
|
||||||
|
|
||||||
|
QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton()));
|
||||||
|
|
||||||
|
//QMetaObject::connectSlotsByName(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::handleQuitButton() {
|
||||||
|
qDebug("Quit pressed. Hiding the main window");
|
||||||
|
close();
|
||||||
|
QApplication::instance()->quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
qDebug("Destroying main window");
|
||||||
|
//QMessageBox::information(0, "Debug", "mw destructor 1");
|
||||||
|
//delete ui;
|
||||||
|
//QMessageBox::information(0, "Debug", "mw destructor 2");
|
||||||
|
}
|
38
qt/i2pd_qt/mainwindow.h
Normal file
38
qt/i2pd_qt/mainwindow.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QtCore/QVariant>
|
||||||
|
#include <QtWidgets/QAction>
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#include <QtWidgets/QButtonGroup>
|
||||||
|
#include <QtWidgets/QHeaderView>
|
||||||
|
#include <QtWidgets/QMainWindow>
|
||||||
|
#include <QtWidgets/QPushButton>
|
||||||
|
#include <QtWidgets/QVBoxLayout>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleQuitButton();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *centralWidget;
|
||||||
|
QWidget *verticalLayoutWidget;
|
||||||
|
QVBoxLayout *verticalLayout1;
|
||||||
|
QPushButton *quitButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
67
qt/i2pd_qt/mainwindow.ui
Normal file
67
qt/i2pd_qt/mainwindow.ui
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget">
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>771</width>
|
||||||
|
<height>441</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout1">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="quitButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>quitButton</sender>
|
||||||
|
<signal>released()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>handleQuitButton()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>384</x>
|
||||||
|
<y>244</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>373</x>
|
||||||
|
<y>419</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<slots>
|
||||||
|
<slot>handleQuitButton()</slot>
|
||||||
|
</slots>
|
||||||
|
</ui>
|
11
util.h
11
util.h
|
@ -7,6 +7,17 @@
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
std::string to_string(T value)
|
||||||
|
{
|
||||||
|
return boost::lexical_cast<std::string>(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 7
|
#define I2PD_VERSION_MINOR 8
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||||
|
|
Loading…
Add table
Reference in a new issue