diff --git a/HTTPServer.cpp b/HTTPServer.cpp
index 1ba22303..184e02b1 100644
--- a/HTTPServer.cpp
+++ b/HTTPServer.cpp
@@ -494,8 +494,9 @@ namespace http {
auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
if (ntcpServer)
{
- s << "NTCP
\r\n";
- for (const auto& it: ntcpServer->GetNTCPSessions ())
+ auto sessions = ntcpServer->GetNTCPSessions ();
+ s << "NTCP ( " << (int) sessions.size() << " )
\r\n";
+ for (const auto& it: sessions )
{
if (it.second && it.second->IsEstablished ())
{
@@ -512,8 +513,9 @@ namespace http {
auto ssuServer = i2p::transport::transports.GetSSUServer ();
if (ssuServer)
{
- s << "
\r\nSSU
\r\n";
- for (const auto& it: ssuServer->GetSessions ())
+ auto sessions = ssuServer->GetSessions ();
+ s << "
\r\nSSU ( " << (int) sessions.size() << " )
\r\n";
+ for (const auto& it: sessions)
{
auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << " ⇒ ";
@@ -713,20 +715,22 @@ namespace http {
}
/* method #2: 'Authorization' header sent */
if (req.headers.count("Authorization") > 0) {
+ bool result = false;
std::string provided = req.headers.find("Authorization")->second;
std::string expected = user + ":" + pass;
- char b64_creds[64];
+ size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1;
+ char * b64_creds = new char[b64_sz];
std::size_t len = 0;
- len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
+ len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, b64_sz);
/* if we decoded properly then check credentials */
if(len) {
b64_creds[len] = '\0';
expected = "Basic ";
expected += b64_creds;
- return expected == provided;
+ result = expected == provided;
}
- /** we decoded wrong so it's not a correct login credential */
- return false;
+ delete [] b64_creds;
+ return result;
}
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
diff --git a/I2PControl.cpp b/I2PControl.cpp
index 3e2e3997..523f10e1 100644
--- a/I2PControl.cpp
+++ b/I2PControl.cpp
@@ -2,6 +2,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -14,7 +16,6 @@
#include "Crypto.h"
#include "FS.h"
#include "Log.h"
-#include "HTTP.h"
#include "Config.h"
#include "NetDb.h"
#include "RouterContext.h"
@@ -189,64 +190,71 @@ namespace client
if (ecode) {
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
return;
- }
- /* try to parse received data */
- std::stringstream json;
- std::string response;
- bool isHTTP = false;
- if (memcmp (buf->data (), "POST", 4) == 0) {
- long int remains = 0;
- isHTTP = true;
- i2p::http::HTTPReq req;
- std::size_t len = req.parse(buf->data(), bytes_transferred);
- if (len <= 0) {
- LogPrint(eLogError, "I2PControl: incomplete/malformed POST request");
- return;
- }
- /* append to json chunk of data from 1st request */
- json.write(buf->data() + len, bytes_transferred - len);
- remains = req.content_length() - len;
- /* if request has Content-Length header, fetch rest of data and store to json buffer */
- while (remains > 0) {
- len = ((long int) buf->size() < remains) ? buf->size() : remains;
- bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len));
- json.write(buf->data(), bytes_transferred);
- remains -= bytes_transferred;
- }
} else {
- json.write(buf->data(), bytes_transferred);
- }
- LogPrint(eLogDebug, "I2PControl: json from request: ", json.str());
+ try
+ {
+ bool isHtml = !memcmp (buf->data (), "POST", 4);
+ std::stringstream ss;
+ ss.write (buf->data (), bytes_transferred);
+ if (isHtml)
+ {
+ std::string header;
+ size_t contentLength = 0;
+ while (!ss.eof () && header != "\r")
+ {
+ std::getline(ss, header);
+ auto colon = header.find (':');
+ if (colon != std::string::npos && header.substr (0, colon) == "Content-Length")
+ contentLength = std::stoi (header.substr (colon + 1));
+ }
+ if (ss.eof ())
+ {
+ LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected");
+ return; // TODO:
+ }
+ std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
+ if (rem > 0)
+ {
+ bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), rem));
+ ss.write (buf->data (), bytes_transferred);
+ }
+ }
+ std::ostringstream response;
#if GCC47_BOOST149
- LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7");
- BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost");
+ LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7");
+ response << "{\"id\":null,\"error\":";
+ response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},";
+ response << "\"jsonrpc\":\"2.0\"}";
#else
- /* now try to parse json itself */
- try {
- boost::property_tree::ptree pt;
- boost::property_tree::read_json (json, pt);
-
- std::string id = pt.get("id");
- std::string method = pt.get("method");
- auto it = m_MethodHandlers.find (method);
- if (it != m_MethodHandlers.end ()) {
- std::ostringstream ss;
- ss << "{\"id\":" << id << ",\"result\":{";
- (this->*(it->second))(pt.get_child ("params"), ss);
- ss << "},\"jsonrpc\":\"2.0\"}";
- response = ss.str();
- } else {
- LogPrint (eLogWarning, "I2PControl: unknown method ", method);
- BuildErrorResponse(response, 32601, "Method not found");
+ boost::property_tree::ptree pt;
+ boost::property_tree::read_json (ss, pt);
+
+ std::string id = pt.get("id");
+ std::string method = pt.get("method");
+ auto it = m_MethodHandlers.find (method);
+ if (it != m_MethodHandlers.end ())
+ {
+ response << "{\"id\":" << id << ",\"result\":{";
+ (this->*(it->second))(pt.get_child ("params"), response);
+ response << "},\"jsonrpc\":\"2.0\"}";
+ } else {
+ LogPrint (eLogWarning, "I2PControl: unknown method ", method);
+ response << "{\"id\":null,\"error\":";
+ response << "{\"code\":-32601,\"message\":\"Method not found\"},";
+ response << "\"jsonrpc\":\"2.0\"}";
+ }
+#endif
+ SendResponse (socket, buf, response, isHtml);
+ }
+ catch (std::exception& ex)
+ {
+ LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
+ }
+ catch (...)
+ {
+ LogPrint (eLogError, "I2PControl: handle request unknown exception");
}
- } catch (std::exception& ex) {
- LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
- BuildErrorResponse(response, 32603, ex.what());
- } catch (...) {
- LogPrint (eLogError, "I2PControl: handle request unknown exception");
}
-#endif
- SendResponse (socket, buf, response, isHTTP);
}
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
@@ -268,28 +276,27 @@ namespace client
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
}
- void I2PControlService::BuildErrorResponse (std::string & content, int code, const char *message) {
- std::stringstream ss;
- ss << "{\"id\":null,\"error\":";
- ss << "{\"code\":" << -code << ",\"message\":\"" << message << "\"},";
- ss << "\"jsonrpc\":\"2.0\"}";
- content = ss.str();
- }
-
void I2PControlService::SendResponse (std::shared_ptr socket,
- std::shared_ptr buf, std::string& content, bool isHTTP)
- {
- if (isHTTP) {
- i2p::http::HTTPRes res;
- res.code = 200;
- res.add_header("Content-Type", "application/json");
- res.add_header("Connection", "close");
- res.body = content;
- std::string tmp = res.to_string();
- content = tmp;
+ std::shared_ptr buf, std::ostringstream& response, bool isHtml)
+ {
+ size_t len = response.str ().length (), offset = 0;
+ if (isHtml)
+ {
+ std::ostringstream header;
+ header << "HTTP/1.1 200 OK\r\n";
+ header << "Connection: close\r\n";
+ header << "Content-Length: " << boost::lexical_cast(len) << "\r\n";
+ header << "Content-Type: application/json\r\n";
+ header << "Date: ";
+ auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
+ header.imbue(std::locale (header.getloc(), facet));
+ header << boost::posix_time::second_clock::local_time() << "\r\n";
+ header << "\r\n";
+ offset = header.str ().size ();
+ memcpy (buf->data (), header.str ().c_str (), offset);
}
- std::copy(content.begin(), content.end(), buf->begin());
- boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), content.length()),
+ memcpy (buf->data () + offset, response.str ().c_str (), len);
+ boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
boost::asio::transfer_all (),
std::bind(&I2PControlService::HandleResponseSent, this,
std::placeholders::_1, std::placeholders::_2, socket, buf));
@@ -316,7 +323,7 @@ namespace client
}
InsertParam (results, "API", api);
results << ",";
- std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ());
+ std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ());
m_Tokens.insert (token);
InsertParam (results, "Token", token);
}
@@ -358,7 +365,7 @@ namespace client
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
- for (auto it = params.begin (); it != params.end (); ++it)
+ for (auto it = params.begin (); it != params.end (); it++)
{
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
auto it1 = m_RouterInfoHandlers.find (it->first);
@@ -434,7 +441,7 @@ namespace client
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
- for (auto it = params.begin (); it != params.end (); ++it)
+ for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
@@ -483,7 +490,7 @@ namespace client
// network setting
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
- for (auto it = params.begin (); it != params.end (); ++it)
+ for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
@@ -529,7 +536,7 @@ namespace client
X509_gmtime_adj (X509_get_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration
X509_set_pubkey (x509, pkey); // public key
X509_NAME * name = X509_get_subject_name (x509);
- X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"RU", -1, -1, 0); // country (Russia by default)
+ X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy)
X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization
X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name
X509_set_issuer_name (x509, name); // set issuer to ourselves
diff --git a/I2PControl.h b/I2PControl.h
index bd5b9bad..047c2fe2 100644
--- a/I2PControl.h
+++ b/I2PControl.h
@@ -45,9 +45,8 @@ namespace client
void ReadRequest (std::shared_ptr socket);
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
std::shared_ptr socket, std::shared_ptr buf);
- void BuildErrorResponse (std::string & content, int code, const char *message);
void SendResponse (std::shared_ptr socket,
- std::shared_ptr buf, std::string& response, bool isHtml);
+ std::shared_ptr buf, std::ostringstream& response, bool isHtml);
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr socket, std::shared_ptr buf);
@@ -120,4 +119,3 @@ namespace client
}
#endif
-
diff --git a/NTCPSession.cpp b/NTCPSession.cpp
index 9e790966..44b4791e 100644
--- a/NTCPSession.cpp
+++ b/NTCPSession.cpp
@@ -493,7 +493,8 @@ namespace transport
void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
- if (ecode) {
+ if (ecode)
+ {
if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ());
//if (ecode != boost::asio::error::operation_aborted)
@@ -507,48 +508,66 @@ namespace transport
if (m_ReceiveBufferOffset >= 16)
{
- int numReloads = 0;
- do
- {
- uint8_t * nextBlock = m_ReceiveBuffer;
- while (m_ReceiveBufferOffset >= 16)
+ // process received data
+ uint8_t * nextBlock = m_ReceiveBuffer;
+ while (m_ReceiveBufferOffset >= 16)
+ {
+ if (!DecryptNextBlock (nextBlock)) // 16 bytes
{
- if (!DecryptNextBlock (nextBlock)) // 16 bytes
- {
- Terminate ();
- return;
- }
- nextBlock += 16;
- m_ReceiveBufferOffset -= 16;
+ Terminate ();
+ return;
}
- if (m_ReceiveBufferOffset > 0)
- memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
-
- // try to read more
- if (numReloads < 5)
- {
- boost::system::error_code ec;
- size_t moreBytes = m_Socket.available(ec);
- if (moreBytes && !ec)
- {
- if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset)
- moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset;
- moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes), ec);
- if (ec)
- {
- LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ());
- Terminate ();
- return;
- }
- m_NumReceivedBytes += moreBytes;
- m_ReceiveBufferOffset += moreBytes;
- numReloads++;
- }
+ nextBlock += 16;
+ m_ReceiveBufferOffset -= 16;
+ }
+ if (m_ReceiveBufferOffset > 0)
+ memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
+ }
+
+ // read and process more is available
+ boost::system::error_code ec;
+ size_t moreBytes = m_Socket.available(ec);
+ if (moreBytes && !ec)
+ {
+ uint8_t * buf = nullptr, * moreBuf = m_ReceiveBuffer;
+ if (moreBytes + m_ReceiveBufferOffset > NTCP_BUFFER_SIZE)
+ {
+ buf = new uint8_t[moreBytes + m_ReceiveBufferOffset + 16];
+ moreBuf = buf;
+ uint8_t rem = ((size_t)buf) & 0x0f;
+ if (rem) moreBuf += (16 - rem); // align 16
+ if (m_ReceiveBufferOffset)
+ memcpy (moreBuf, m_ReceiveBuffer, m_ReceiveBufferOffset);
+ }
+ moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec);
+ if (ec)
+ {
+ LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ());
+ delete[] buf;
+ Terminate ();
+ return;
+ }
+ m_ReceiveBufferOffset += moreBytes;
+ m_NumReceivedBytes += moreBytes;
+ i2p::transport::transports.UpdateReceivedBytes (moreBytes);
+ // process more data
+ uint8_t * nextBlock = moreBuf;
+ while (m_ReceiveBufferOffset >= 16)
+ {
+ if (!DecryptNextBlock (nextBlock)) // 16 bytes
+ {
+ delete[] buf;
+ Terminate ();
+ return;
}
+ nextBlock += 16;
+ m_ReceiveBufferOffset -= 16;
}
- while (m_ReceiveBufferOffset >= 16);
- m_Handler.Flush ();
- }
+ if (m_ReceiveBufferOffset > 0)
+ memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); // nextBlock points to memory inside buf
+ delete[] buf;
+ }
+ m_Handler.Flush ();
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
Receive ();
diff --git a/NTCPSession.h b/NTCPSession.h
index b02543be..a5d6f99f 100644
--- a/NTCPSession.h
+++ b/NTCPSession.h
@@ -35,12 +35,11 @@ namespace transport
};
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
- const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028)
+ const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message
const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448
- const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second
const int NTCP_CLOCK_SKEW = 60; // in seconds
const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up
diff --git a/RouterContext.cpp b/RouterContext.cpp
index 3c37e88c..966da6ac 100644
--- a/RouterContext.cpp
+++ b/RouterContext.cpp
@@ -266,8 +266,9 @@ namespace i2p
}
}
// delete previous introducers
- for (auto& addr : addresses)
- addr->introducers.clear ();
+ for (auto& addr : addresses)
+ if (addr->ssu)
+ addr->ssu->introducers.clear ();
// update
UpdateRouterInfo ();
@@ -298,7 +299,8 @@ namespace i2p
}
// delete previous introducers
for (auto& addr : addresses)
- addr->introducers.clear ();
+ if (addr->ssu)
+ addr->ssu->introducers.clear ();
// update
UpdateRouterInfo ();
diff --git a/RouterInfo.cpp b/RouterInfo.cpp
index 4ae2f9e5..08d46ecb 100644
--- a/RouterInfo.cpp
+++ b/RouterInfo.cpp
@@ -175,11 +175,14 @@ namespace data
if (!strcmp (transportStyle, "NTCP"))
address->transportStyle = eTransportNTCP;
else if (!strcmp (transportStyle, "SSU"))
+ {
address->transportStyle = eTransportSSU;
+ address->ssu.reset (new SSUExt ());
+ address->ssu->mtu = 0;
+ }
else
address->transportStyle = eTransportUnknown;
address->port = 0;
- address->mtu = 0;
uint16_t size, r = 0;
s.read ((char *)&size, sizeof (size)); if (!s) return;
size = be16toh (size);
@@ -220,9 +223,19 @@ namespace data
else if (!strcmp (key, "port"))
address->port = boost::lexical_cast(value);
else if (!strcmp (key, "mtu"))
- address->mtu = boost::lexical_cast(value);
+ {
+ if (address->ssu)
+ address->ssu->mtu = boost::lexical_cast(value);
+ else
+ LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
+ }
else if (!strcmp (key, "key"))
- Base64ToByteStream (value, strlen (value), address->key, 32);
+ {
+ if (address->ssu)
+ Base64ToByteStream (value, strlen (value), address->ssu->key, 32);
+ else
+ LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
+ }
else if (!strcmp (key, "caps"))
ExtractCaps (value);
else if (key[0] == 'i')
@@ -237,9 +250,9 @@ namespace data
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
if (s) continue; else return;
}
- if (index >= address->introducers.size ())
- address->introducers.resize (index + 1);
- Introducer& introducer = address->introducers.at (index);
+ if (index >= address->ssu->introducers.size ())
+ address->ssu->introducers.resize (index + 1);
+ Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "ihost"))
{
boost::system::error_code ecode;
@@ -417,10 +430,10 @@ namespace data
if (address.transportStyle == eTransportSSU)
{
// write introducers if any
- if (address.introducers.size () > 0)
+ if (address.ssu->introducers.size () > 0)
{
int i = 0;
- for (const auto& introducer: address.introducers)
+ for (const auto& introducer: address.ssu->introducers)
{
WriteString ("ihost" + boost::lexical_cast(i), properties);
properties << '=';
@@ -429,7 +442,7 @@ namespace data
i++;
}
i = 0;
- for (const auto& introducer: address.introducers)
+ for (const auto& introducer: address.ssu->introducers)
{
WriteString ("ikey" + boost::lexical_cast(i), properties);
properties << '=';
@@ -441,7 +454,7 @@ namespace data
i++;
}
i = 0;
- for (const auto& introducer: address.introducers)
+ for (const auto& introducer: address.ssu->introducers)
{
WriteString ("iport" + boost::lexical_cast(i), properties);
properties << '=';
@@ -450,7 +463,7 @@ namespace data
i++;
}
i = 0;
- for (const auto& introducer: address.introducers)
+ for (const auto& introducer: address.ssu->introducers)
{
WriteString ("itag" + boost::lexical_cast(i), properties);
properties << '=';
@@ -463,16 +476,16 @@ namespace data
WriteString ("key", properties);
properties << '=';
char value[64];
- size_t l = ByteStreamToBase64 (address.key, 32, value, 64);
+ size_t l = ByteStreamToBase64 (address.ssu->key, 32, value, 64);
value[l] = 0;
WriteString (value, properties);
properties << ';';
// write mtu
- if (address.mtu)
+ if (address.ssu->mtu)
{
WriteString ("mtu", properties);
properties << '=';
- WriteString (boost::lexical_cast(address.mtu), properties);
+ WriteString (boost::lexical_cast(address.ssu->mtu), properties);
properties << ';';
}
}
@@ -589,7 +602,6 @@ namespace data
addr->transportStyle = eTransportNTCP;
addr->cost = 2;
addr->date = 0;
- addr->mtu = 0;
for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return;
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
@@ -604,8 +616,9 @@ namespace data
addr->transportStyle = eTransportSSU;
addr->cost = 10; // NTCP should have priority over SSU
addr->date = 0;
- addr->mtu = mtu;
- memcpy (addr->key, key, 32);
+ addr->ssu.reset (new SSUExt ());
+ addr->ssu->mtu = mtu;
+ memcpy (addr->ssu->key, key, 32);
for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return;
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
@@ -621,9 +634,9 @@ namespace data
{
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{
- for (auto& intro: addr->introducers)
+ for (auto& intro: addr->ssu->introducers)
if (intro.iTag == introducer.iTag) return false; // already presented
- addr->introducers.push_back (introducer);
+ addr->ssu->introducers.push_back (introducer);
return true;
}
}
@@ -636,10 +649,10 @@ namespace data
{
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{
- for (auto it = addr->introducers.begin (); it != addr->introducers.end (); ++it)
+ for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
{
- addr->introducers.erase (it);
+ addr->ssu->introducers.erase (it);
return true;
}
}
diff --git a/RouterInfo.h b/RouterInfo.h
index c51d3ce4..7300e579 100644
--- a/RouterInfo.h
+++ b/RouterInfo.h
@@ -79,17 +79,22 @@ namespace data
uint32_t iTag;
};
+ struct SSUExt
+ {
+ int mtu;
+ IntroKey key; // intro key for SSU
+ std::vector introducers;
+ };
+
struct Address
{
TransportStyle transportStyle;
boost::asio::ip::address host;
std::string addressString;
- int port, mtu;
+ int port;
uint64_t date;
uint8_t cost;
- // SSU only
- IntroKey key; // intro key for SSU
- std::vector introducers;
+ std::unique_ptr ssu; // not null for SSU
bool IsCompatible (const boost::asio::ip::address& other) const
{
diff --git a/SAM.cpp b/SAM.cpp
index 2166ed72..929b144d 100644
--- a/SAM.cpp
+++ b/SAM.cpp
@@ -693,9 +693,9 @@ namespace client
LogPrint (eLogDebug, "SAM: datagram received ", len);
auto base64 = from.ToBase64 ();
#ifdef _MSC_VER
- size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
+ size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len);
#else
- size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
+ size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len);
#endif
if (len < SAM_SOCKET_BUFFER_SIZE - l)
{
diff --git a/SSU.cpp b/SSU.cpp
index 9f74185f..9dc05608 100644
--- a/SSU.cpp
+++ b/SSU.cpp
@@ -417,7 +417,7 @@ namespace transport
return;
}
// create new session
- int numIntroducers = address->introducers.size ();
+ int numIntroducers = address->ssu->introducers.size ();
if (numIntroducers > 0)
{
std::shared_ptr introducerSession;
@@ -425,7 +425,7 @@ namespace transport
// we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++)
{
- auto intr = &(address->introducers[i]);
+ auto intr = &(address->ssu->introducers[i]);
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
if (ep.address ().is_v4 ()) // ipv4 only
{
diff --git a/SSUData.cpp b/SSUData.cpp
index cb20b3e8..b9b1d93e 100644
--- a/SSUData.cpp
+++ b/SSUData.cpp
@@ -54,23 +54,23 @@ namespace transport
{
if (remoteRouter) return;
auto ssuAddress = remoteRouter->GetSSUAddress ();
- if (ssuAddress && ssuAddress->mtu)
+ if (ssuAddress && ssuAddress->ssu->mtu)
{
if (m_Session.IsV6 ())
- m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
+ m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
else
- m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
+ m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
if (m_PacketSize > 0)
{
// make sure packet size multiple of 16
m_PacketSize >>= 4;
m_PacketSize <<= 4;
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
- LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
+ LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
}
else
{
- LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu);
+ LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
m_PacketSize = m_MaxPacketSize;
}
}
diff --git a/SSUSession.cpp b/SSUSession.cpp
index dbb26bc9..050b2f9a 100644
--- a/SSUSession.cpp
+++ b/SSUSession.cpp
@@ -22,14 +22,14 @@ namespace transport
{
// we are client
auto address = router->GetSSUAddress (false);
- if (address) m_IntroKey = address->key;
+ if (address) m_IntroKey = address->ssu->key;
m_Data.AdjustPacketSize (router); // mtu
}
else
{
// we are server
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
- if (address) m_IntroKey = address->key;
+ if (address) m_IntroKey = address->ssu->key;
}
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
}
@@ -115,8 +115,8 @@ namespace transport
LogPrint (eLogInfo, "SSU is not supported");
return;
}
- if (Validate (buf, len, address->key))
- Decrypt (buf, len, address->key);
+ if (Validate (buf, len, address->ssu->key))
+ Decrypt (buf, len, address->ssu->key);
else
{
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
@@ -403,7 +403,7 @@ namespace transport
payload += 2;
*payload = 0; // challenge
payload++;
- memcpy (payload, (const uint8_t *)address->key, 32);
+ memcpy (payload, (const uint8_t *)address->ssu->key, 32);
payload += 32;
htobe32buf (payload, nonce); // nonce
@@ -1081,7 +1081,7 @@ namespace transport
// send our intro key to address instead it's own
auto addr = i2p::context.GetRouterInfo ().GetSSUAddress ();
if (addr)
- memcpy (payload, addr->key, 32); // intro key
+ memcpy (payload, addr->ssu->key, 32); // intro key
else
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
}
@@ -1121,7 +1121,7 @@ namespace transport
if (!nonce) nonce = 1;
m_IsPeerTest = false;
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
- SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice
+ SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice
}
void SSUSession::SendKeepAlive ()
diff --git a/Transports.cpp b/Transports.cpp
index dda9b7c6..1659eeed 100644
--- a/Transports.cpp
+++ b/Transports.cpp
@@ -384,7 +384,7 @@ namespace transport
}
}
}
- LogPrint (eLogError, "Transports: No NTCP or SSU addresses available");
+ LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
peer.Done ();
std::unique_lock l(m_PeersMutex);
m_Peers.erase (ident);
diff --git a/Tunnel.cpp b/Tunnel.cpp
index e271052e..6f9346d2 100644
--- a/Tunnel.cpp
+++ b/Tunnel.cpp
@@ -19,36 +19,11 @@
namespace i2p
{
namespace tunnel
-{
-
- void TunnelLatency::AddSample(Sample s)
- {
- std::unique_lock l(m_access);
- m_samples.push_back(s);
- }
-
- bool TunnelLatency::HasSamples() const
- {
- std::unique_lock l(m_access);
- return m_samples.size() > 0;
- }
-
- TunnelLatency::Latency TunnelLatency::GetMeanLatency() const
- {
- std::unique_lock lock(m_access);
- if (m_samples.size() > 0) {
- Latency l = 0;
- for(auto s : m_samples)
- l += s;
- return l / m_samples.size();
- }
- return 0;
- }
-
-
+{
Tunnel::Tunnel (std::shared_ptr config):
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
- m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
+ m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false),
+ m_Latency (0)
{
}
diff --git a/Tunnel.h b/Tunnel.h
index f3c31461..08533ec4 100644
--- a/Tunnel.h
+++ b/Tunnel.h
@@ -78,21 +78,6 @@ namespace tunnel
eTunnelStateFailed,
eTunnelStateExpiring
};
-
- /** @brief for storing latency history */
- struct TunnelLatency
- {
- typedef uint64_t Sample;
- typedef uint64_t Latency;
-
-
- void AddSample(Sample s);
- bool HasSamples() const;
- Latency GetMeanLatency() const;
-
- std::vector m_samples;
- mutable std::mutex m_access;
- };
class OutboundTunnel;
class InboundTunnel;
@@ -133,14 +118,14 @@ namespace tunnel
void SendTunnelDataMsg (std::shared_ptr msg);
void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out);
- /** @brief add latency sample */
- void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); }
- /** @brief get this tunnel's estimated latency */
- uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); }
- /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
- bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
+ /** @brief add latency sample */
+ void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
+ /** @brief get this tunnel's estimated latency */
+ uint64_t GetMeanLatency() const { return m_Latency; }
+ /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
+ bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
- bool LatencyIsKnown() const { return m_Latency.HasSamples(); }
+ bool LatencyIsKnown() const { return m_Latency > 0; }
protected:
void PrintHops (std::stringstream& s) const;
@@ -152,7 +137,7 @@ namespace tunnel
std::shared_ptr m_Pool; // pool, tunnel belongs to, or null
TunnelState m_State;
bool m_IsRecreated;
- TunnelLatency m_Latency;
+ uint64_t m_Latency; // in milliseconds
};
class OutboundTunnel: public Tunnel
diff --git a/android/project.properties b/android/project.properties
index 7ce68660..f72b9716 100644
--- a/android/project.properties
+++ b/android/project.properties
@@ -11,4 +11,4 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
-target=android-24
+target=android-25
diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png
index a5dc7b68..9a2f7404 100644
Binary files a/android/res/drawable/icon.png and b/android/res/drawable/icon.png differ
diff --git a/android/res/drawable/itoopie_notification_icon.png b/android/res/drawable/itoopie_notification_icon.png
index 8fbe2468..d055bc8f 100644
Binary files a/android/res/drawable/itoopie_notification_icon.png and b/android/res/drawable/itoopie_notification_icon.png differ
diff --git a/docs/configuration.md b/docs/configuration.md
index b04be9fb..3212aea9 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -73,9 +73,12 @@ All options below still possible in cmdline, but better write it in config file:
* --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP
-* --i2pcontrol.address= - The address to listen on (I2P control service)
-* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
-* --i2pcontrol.enabled= - If I2P control is enabled. false by default
+* --i2pcontrol.address= - The address to listen on (I2P control service)
+* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
+* --i2pcontrol.enabled= - If I2P control is enabled. false by default
+* --i2pcontrol.password= - I2P control authentication password. itoopie by default
+* --i2pcontrol.cert= - I2P control HTTPS certificate file name. i2pcontrol.crt.pem by default
+* --i2pcontrol.key= - I2P control HTTPS certificate key file name. i2pcontrol.key.pem by default
* --upnp.enabled= - Enable or disable UPnP, false by default for CLI and true for GUI (Windows, Android)
* --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default
diff --git a/qt/i2pd_qt/README.md b/qt/i2pd_qt/README.md
new file mode 100644
index 00000000..94186ecf
--- /dev/null
+++ b/qt/i2pd_qt/README.md
@@ -0,0 +1,3 @@
+# Build Requirements
+
+ * Qt 5 is necessary (because Qt4 lacks QtWidgets/ folder)