Browse Source

Merge pull request #604 from PurpleI2P/openssl

recent changes
pull/613/head
orignal 8 years ago committed by GitHub
parent
commit
c09212de81
  1. 1
      .travis.yml
  2. 24
      AddressBook.cpp
  3. 4
      AddressBook.h
  4. 8
      BOB.cpp
  5. 2
      ClientContext.cpp
  6. 20
      Config.cpp
  7. 17
      Destination.cpp
  8. 2
      Destination.h
  9. 20
      Garlic.cpp
  10. 2
      HTTP.cpp
  11. 10
      HTTPProxy.cpp
  12. 124
      HTTPServer.cpp
  13. 2
      I2CP.cpp
  14. 2
      I2NPProtocol.cpp
  15. 6
      I2PControl.cpp
  16. 12
      LeaseSet.cpp
  17. 4
      Makefile.mingw
  18. 13
      NTCPSession.cpp
  19. 35
      NetDb.cpp
  20. 2
      NetDbRequests.cpp
  21. 2
      Profiling.cpp
  22. 5
      Queue.h
  23. 8
      Reseed.cpp
  24. 20
      RouterContext.cpp
  25. 3
      RouterContext.h
  26. 51
      RouterInfo.cpp
  27. 6
      RouterInfo.h
  28. 4
      SAM.cpp
  29. 2
      SAM.h
  30. 2
      SOCKS.cpp
  31. 42
      SSU.cpp
  32. 44
      SSUData.cpp
  33. 10
      SSUData.h
  34. 9
      SSUSession.cpp
  35. 16
      Streaming.cpp
  36. 8
      TransportSession.h
  37. 12
      Transports.cpp
  38. 2
      Transports.h
  39. 332
      Tunnel.cpp
  40. 2
      Tunnel.h
  41. 2
      TunnelConfig.h
  42. 2
      TunnelGateway.cpp
  43. 29
      TunnelPool.cpp
  44. 17
      UPnP.cpp
  45. 8
      UPnP.h
  46. 29
      Win32/Win32App.cpp
  47. 1
      Win32/Win32App.h
  48. 5
      debian/patches/01-tune-build-opts.patch
  49. 39
      docs/build_notes_android.md
  50. 2
      docs/build_notes_unix.md
  51. 10
      docs/build_notes_windows.md
  52. 4
      docs/configuration.md
  53. 4
      filelist.mk
  54. 159
      util.cpp
  55. 29
      util.h
  56. 2
      version.h

1
.travis.yml

@ -3,7 +3,6 @@ cache:
apt: true apt: true
os: os:
- linux - linux
- osx
sudo: required sudo: required
dist: trusty dist: trusty
addons: addons:

24
AddressBook.cpp

@ -173,7 +173,7 @@ namespace client
return 0; return 0;
} }
for (auto it: addresses) { for (const auto& it: addresses) {
f << it.first << "," << it.second.ToBase32 () << std::endl; f << it.first << "," << it.second.ToBase32 () << std::endl;
num++; num++;
} }
@ -252,7 +252,7 @@ namespace client
} }
LogPrint (eLogError, "Addressbook: subscription download timeout"); LogPrint (eLogError, "Addressbook: subscription download timeout");
m_IsDownloading = false; m_IsDownloading = false;
} }
if (m_Storage) if (m_Storage)
{ {
m_Storage->Save (m_Addresses); m_Storage->Save (m_Addresses);
@ -260,8 +260,6 @@ namespace client
m_Storage = nullptr; m_Storage = nullptr;
} }
m_DefaultSubscription = nullptr; m_DefaultSubscription = nullptr;
for (auto it: m_Subscriptions)
delete it;
m_Subscriptions.clear (); m_Subscriptions.clear ();
} }
@ -403,7 +401,7 @@ namespace client
{ {
getline(f, s); getline(f, s);
if (!s.length()) continue; // skip empty line if (!s.length()) continue; // skip empty line
m_Subscriptions.push_back (new AddressBookSubscription (*this, s)); m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, s));
} }
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
} }
@ -418,7 +416,7 @@ namespace client
{ {
std::map<std::string, i2p::data::IdentHash> localAddresses; std::map<std::string, i2p::data::IdentHash> localAddresses;
m_Storage->LoadLocal (localAddresses); m_Storage->LoadLocal (localAddresses);
for (auto it: localAddresses) for (const auto& it: localAddresses)
{ {
auto dot = it.first.find ('.'); auto dot = it.first.find ('.');
if (dot != std::string::npos) if (dot != std::string::npos)
@ -462,7 +460,7 @@ namespace client
int nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT; int nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT;
if (success) if (success)
{ {
if (m_DefaultSubscription) m_DefaultSubscription.reset (nullptr); if (m_DefaultSubscription) m_DefaultSubscription = nullptr;
if (m_IsLoaded) if (m_IsLoaded)
nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT; nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT;
else else
@ -516,16 +514,17 @@ namespace client
// download it from http://i2p-projekt.i2p/hosts.txt // download it from http://i2p-projekt.i2p/hosts.txt
LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription."); LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription.");
if (!m_DefaultSubscription) if (!m_DefaultSubscription)
m_DefaultSubscription.reset (new AddressBookSubscription (*this, DEFAULT_SUBSCRIPTION_ADDRESS)); m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, DEFAULT_SUBSCRIPTION_ADDRESS);
m_IsDownloading = true; m_IsDownloading = true;
m_DefaultSubscription->CheckUpdates (); std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription));
load_hosts.detach(); // TODO: use join
} }
else if (!m_Subscriptions.empty ()) else if (!m_Subscriptions.empty ())
{ {
// pick random subscription // pick random subscription
auto ind = rand () % m_Subscriptions.size(); auto ind = rand () % m_Subscriptions.size();
m_IsDownloading = true; m_IsDownloading = true;
std::thread load_hosts(&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]); std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_Subscriptions[ind]));
load_hosts.detach(); // TODO: use join load_hosts.detach(); // TODO: use join
} }
} }
@ -659,15 +658,16 @@ namespace client
{ {
std::unique_lock<std::mutex> l(newDataReceivedMutex); std::unique_lock<std::mutex> l(newDataReceivedMutex);
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (m_Ident, i2p::client::context.GetSharedLocalDestination ()->RequestDestination (m_Ident,
[&newDataReceived, &leaseSet](std::shared_ptr<i2p::data::LeaseSet> ls) [&newDataReceived, &leaseSet, &newDataReceivedMutex](std::shared_ptr<i2p::data::LeaseSet> ls)
{ {
leaseSet = ls; leaseSet = ls;
std::unique_lock<std::mutex> l1(newDataReceivedMutex);
newDataReceived.notify_all (); newDataReceived.notify_all ();
}); });
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
{ {
LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired"); LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (m_Ident); i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (m_Ident, false); // don't notify, because we know it already
return false; return false;
} }
} }

4
AddressBook.h

@ -102,8 +102,8 @@ namespace client
std::map<uint32_t, std::string> m_Lookups; // nonce -> address std::map<uint32_t, std::string> m_Lookups; // nonce -> address
AddressBookStorage * m_Storage; AddressBookStorage * m_Storage;
volatile bool m_IsLoaded, m_IsDownloading; volatile bool m_IsLoaded, m_IsDownloading;
std::vector<AddressBookSubscription *> m_Subscriptions; std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
std::unique_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
boost::asio::deadline_timer * m_SubscriptionsUpdateTimer; boost::asio::deadline_timer * m_SubscriptionsUpdateTimer;
}; };

8
BOB.cpp

@ -536,8 +536,8 @@ namespace client
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len) void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: list"); LogPrint (eLogDebug, "BOB: list");
auto& destinations = m_Owner.GetDestinations (); const auto& destinations = m_Owner.GetDestinations ();
for (auto it: destinations) for (const auto& it: destinations)
SendData (it.first.c_str ()); SendData (it.first.c_str ());
SendReplyOK ("Listing done"); SendReplyOK ("Listing done");
} }
@ -619,7 +619,7 @@ namespace client
BOBCommandChannel::~BOBCommandChannel () BOBCommandChannel::~BOBCommandChannel ()
{ {
Stop (); Stop ();
for (auto it: m_Destinations) for (const auto& it: m_Destinations)
delete it.second; delete it.second;
} }
@ -633,7 +633,7 @@ namespace client
void BOBCommandChannel::Stop () void BOBCommandChannel::Stop ()
{ {
m_IsRunning = false; m_IsRunning = false;
for (auto it: m_Destinations) for (auto& it: m_Destinations)
it.second->Stop (); it.second->Stop ();
m_Acceptor.cancel (); m_Acceptor.cancel ();
m_Service.stop (); m_Service.stop ();

2
ClientContext.cpp

@ -194,7 +194,7 @@ namespace client
LogPrint(eLogInfo, "Clients: stopping AddressBook"); LogPrint(eLogInfo, "Clients: stopping AddressBook");
m_AddressBook.Stop (); m_AddressBook.Stop ();
for (auto it: m_Destinations) for (auto& it: m_Destinations)
it.second->Stop (); it.second->Stop ();
m_Destinations.clear (); m_Destinations.clear ();
m_SharedLocalDestination = nullptr; m_SharedLocalDestination = nullptr;

20
Config.cpp

@ -147,12 +147,17 @@ namespace config {
#endif #endif
"Enable or disable elgamal precomputation table") "Enable or disable elgamal precomputation table")
; ;
options_description trust("Trust options"); options_description reseed("Reseed options");
trust.add_options() reseed.add_options()
("trust.enabled", value<bool>()->default_value(false), "enable explicit trust options") ("reseed.file", value<std::string>()->default_value(""), "Path to .su3 file")
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops") ;
("trust.hidden", value<bool>()->default_value(false), "should we hide our router from other routers?");
options_description trust("Trust options");
trust.add_options()
("trust.enabled", value<bool>()->default_value(false), "enable explicit trust options")
("trust.family", value<std::string>()->default_value(""), "Router Familiy to trust for first hops")
("trust.hidden", value<bool>()->default_value(false), "should we hide our router from other routers?");
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
@ -166,7 +171,8 @@ namespace config {
.add(i2pcontrol) .add(i2pcontrol)
.add(upnp) .add(upnp)
.add(precomputation) .add(precomputation)
.add(trust) .add(reseed)
.add(trust)
; ;
} }

17
Destination.cpp

@ -103,7 +103,7 @@ namespace client
{ {
if (m_IsRunning) if (m_IsRunning)
Stop (); Stop ();
for (auto it: m_LeaseSetRequests) for (auto& it: m_LeaseSetRequests)
if (it.second->requestComplete) it.second->requestComplete (nullptr); if (it.second->requestComplete) it.second->requestComplete (nullptr);
m_LeaseSetRequests.clear (); m_LeaseSetRequests.clear ();
if (m_Pool) if (m_Pool)
@ -479,24 +479,25 @@ namespace client
{ {
if (!m_Pool || !IsReady ()) if (!m_Pool || !IsReady ())
{ {
if (requestComplete) requestComplete (nullptr); if (requestComplete)
m_Service.post ([requestComplete](void){requestComplete (nullptr);});
return false; return false;
} }
m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete)); m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete));
return true; return true;
} }
void LeaseSetDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest) void LeaseSetDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify)
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
m_Service.post ([dest, s](void) m_Service.post ([dest, notify, s](void)
{ {
auto it = s->m_LeaseSetRequests.find (dest); auto it = s->m_LeaseSetRequests.find (dest);
if (it != s->m_LeaseSetRequests.end ()) if (it != s->m_LeaseSetRequests.end ())
{ {
auto requestComplete = it->second->requestComplete; auto requestComplete = it->second->requestComplete;
s->m_LeaseSetRequests.erase (it); s->m_LeaseSetRequests.erase (it);
if (requestComplete) requestComplete (nullptr); if (notify && requestComplete) requestComplete (nullptr);
} }
}); });
} }
@ -635,7 +636,7 @@ namespace client
it = m_RemoteLeaseSets.erase (it); it = m_RemoteLeaseSets.erase (it);
} }
else else
it++; ++it;
} }
} }
@ -663,7 +664,7 @@ namespace client
{ {
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis ()); // TODO: m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis ()); // TODO:
m_StreamingDestination->Start (); m_StreamingDestination->Start ();
for (auto it: m_StreamingDestinationsByPorts) for (auto& it: m_StreamingDestinationsByPorts)
it.second->Start (); it.second->Start ();
return true; return true;
} }
@ -677,7 +678,7 @@ namespace client
{ {
m_StreamingDestination->Stop (); m_StreamingDestination->Stop ();
m_StreamingDestination = nullptr; m_StreamingDestination = nullptr;
for (auto it: m_StreamingDestinationsByPorts) for (auto& it: m_StreamingDestinationsByPorts)
it.second->Stop (); it.second->Stop ();
if (m_DatagramDestination) if (m_DatagramDestination)
{ {

2
Destination.h

@ -79,7 +79,7 @@ namespace client
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; }; bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident); std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
void CancelDestinationRequest (const i2p::data::IdentHash& dest); void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet (); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();

20
Garlic.cpp

@ -111,7 +111,7 @@ namespace garlic
it = m_UnconfirmedTagsMsgs.erase (it); it = m_UnconfirmedTagsMsgs.erase (it);
} }
else else
it++; ++it;
} }
} }
@ -123,7 +123,7 @@ namespace garlic
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
it = m_SessionTags.erase (it); it = m_SessionTags.erase (it);
else else
it++; ++it;
} }
CleanupUnconfirmedTags (); CleanupUnconfirmedTags ();
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
@ -144,7 +144,7 @@ namespace garlic
ret = true; ret = true;
} }
else else
it++; ++it;
} }
return ret; return ret;
} }
@ -615,7 +615,7 @@ namespace garlic
it = m_Tags.erase (it); it = m_Tags.erase (it);
} }
else else
it++; ++it;
} }
if (numExpiredTags > 0) if (numExpiredTags > 0)
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ()); LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
@ -631,7 +631,7 @@ namespace garlic
it = m_Sessions.erase (it); it = m_Sessions.erase (it);
} }
else else
it++; ++it;
} }
} }
@ -643,26 +643,26 @@ namespace garlic
void GarlicDestination::DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID) void GarlicDestination::DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID)
{ {
m_DeliveryStatusSessions[msgID] = session; m_DeliveryStatusSessions[msgID] = session;
} }
void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint32_t msgID = bufbe32toh (msg->GetPayload ()); uint32_t msgID = bufbe32toh (msg->GetPayload ());
{ {
auto it = m_DeliveryStatusSessions.find (msgID); auto it = m_DeliveryStatusSessions.find (msgID);
if (it != m_DeliveryStatusSessions.end ()) if (it != m_DeliveryStatusSessions.end ())
{ {
it->second->MessageConfirmed (msgID); it->second->MessageConfirmed (msgID);
m_DeliveryStatusSessions.erase (it); m_DeliveryStatusSessions.erase (it);
LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged"); LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged");
} }
} }
} }
void GarlicDestination::SetLeaseSetUpdated () void GarlicDestination::SetLeaseSetUpdated ()
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
for (auto it: m_Sessions) for (auto& it: m_Sessions)
it.second->SetLeaseSetUpdated (); it.second->SetLeaseSetUpdated ();
} }

2
HTTP.cpp

@ -160,7 +160,7 @@ namespace http {
strsplit(query, tokens, '&'); strsplit(query, tokens, '&');
params.clear(); params.clear();
for (auto it : tokens) { for (const auto& it : tokens) {
std::size_t eq = it.find ('='); std::size_t eq = it.find ('=');
if (eq != std::string::npos) { if (eq != std::string::npos) {
auto e = std::pair<std::string, std::string>(it.substr(0, eq), it.substr(eq + 1)); auto e = std::pair<std::string, std::string>(it.substr(0, eq), it.substr(eq + 1));

10
HTTPProxy.cpp

@ -105,7 +105,7 @@ namespace proxy {
ss << "<p>" << description << "</p>\r\n"; ss << "<p>" << description << "</p>\r\n";
std::string content = ss.str(); std::string content = ss.str();
SendProxyError(content); SendProxyError(content);
} }
void HTTPReqHandler::HostNotFound(std::string & host) { void HTTPReqHandler::HostNotFound(std::string & host) {
std::stringstream ss; std::stringstream ss;
@ -113,13 +113,13 @@ namespace proxy {
<< "<p>Remote host not found in router's addressbook</p>\r\n" << "<p>Remote host not found in router's addressbook</p>\r\n"
<< "<p>You may try to find this host on jumpservices below:</p>\r\n" << "<p>You may try to find this host on jumpservices below:</p>\r\n"
<< "<ul>\r\n"; << "<ul>\r\n";
for (auto & js : jumpservices) { for (const auto& js : jumpservices) {
ss << " <li><a href=\"" << js.second << host << "\">" << js.first << "</a></li>\r\n"; ss << " <li><a href=\"" << js.second << host << "\">" << js.first << "</a></li>\r\n";
} }
ss << "</ul>\r\n"; ss << "</ul>\r\n";
std::string content = ss.str(); std::string content = ss.str();
SendProxyError(content); SendProxyError(content);
} }
void HTTPReqHandler::SendProxyError(std::string & content) void HTTPReqHandler::SendProxyError(std::string & content)
{ {
@ -164,7 +164,7 @@ namespace proxy {
req.del_header("Forwarded"); req.del_header("Forwarded");
/* drop proxy-disclosing headers */ /* drop proxy-disclosing headers */
std::vector<std::string> toErase; std::vector<std::string> toErase;
for (auto it : req.headers) { for (const auto& it : req.headers) {
if (it.first.compare(0, 12, "X-Forwarded-") == 0) { if (it.first.compare(0, 12, "X-Forwarded-") == 0) {
toErase.push_back(it.first); toErase.push_back(it.first);
} else if (it.first.compare(0, 6, "Proxy-") == 0) { } else if (it.first.compare(0, 6, "Proxy-") == 0) {
@ -173,7 +173,7 @@ namespace proxy {
/* allow */ /* allow */
} }
} }
for (auto header : toErase) { for (const auto& header : toErase) {
req.headers.erase(header); req.headers.erase(header);
} }
/* replace headers */ /* replace headers */

124
HTTPServer.cpp

@ -22,6 +22,9 @@
#include "HTTPServer.h" #include "HTTPServer.h"
#include "Daemon.h" #include "Daemon.h"
#include "util.h" #include "util.h"
#ifdef WIN32_APP
#include "Win32/Win32App.h"
#endif
// For image and info // For image and info
#include "version.h" #include "version.h"
@ -65,7 +68,7 @@ namespace http {
const char HTTP_PAGE_TUNNELS[] = "tunnels"; const char HTTP_PAGE_TUNNELS[] = "tunnels";
const char HTTP_PAGE_TRANSIT_TUNNELS[] = "transit_tunnels"; const char HTTP_PAGE_TRANSIT_TUNNELS[] = "transit_tunnels";
const char HTTP_PAGE_TRANSPORTS[] = "transports"; const char HTTP_PAGE_TRANSPORTS[] = "transports";
const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations"; const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations";
const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination"; const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination";
const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions"; const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions";
@ -79,7 +82,7 @@ namespace http {
const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel"; const char HTTP_COMMAND_SHUTDOWN_CANCEL[] = "shutdown_cancel";
const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate"; const char HTTP_COMMAND_SHUTDOWN_NOW[] = "terminate";
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config"; const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
@ -141,12 +144,14 @@ namespace http {
" <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_LEASESETS << "\">Lease Sets</a><br>\r\n" " <a href=\"/?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</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_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n" if (i2p::client::context.GetSAMBridge ())
s << " <a href=\"/?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n";
s <<
"</div>\r\n" "</div>\r\n"
"<div class=right>"; "<div class=right>";
} }
@ -207,7 +212,7 @@ namespace http {
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n"; s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n"; s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ; s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (auto address : i2p::context.GetRouterInfo().GetAddresses()) for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
{ {
switch (address->transportStyle) switch (address->transportStyle)
{ {
@ -236,9 +241,9 @@ namespace http {
size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels(); size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels();
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 ShowLocalDestinations (std::stringstream& s) void ShowLocalDestinations (std::stringstream& s)
@ -277,18 +282,18 @@ namespace http {
it->Print(s); it->Print(s);
ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ());
} }
} }
s << "<br>\r\n"; s << "<br>\r\n";
s << "<b>Tags</b><br>Incoming: " << dest->GetNumIncomingTags () << "<br>Outgoing:<br>" << std::endl; s << "<b>Tags</b><br>Incoming: " << dest->GetNumIncomingTags () << "<br>Outgoing:<br>" << std::endl;
for (auto it: dest->GetSessions ()) for (const auto& it: dest->GetSessions ())
{ {
s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " "; s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " ";
s << it.second->GetNumOutgoingTags () << "<br>" << std::endl; s << it.second->GetNumOutgoingTags () << "<br>" << std::endl;
} }
s << "<br>" << std::endl; s << "<br>" << std::endl;
// s << "<br>\r\n<b>Streams:</b><br>\r\n"; // s << "<br>\r\n<b>Streams:</b><br>\r\n";
// for (auto it: dest->GetStreamingDestination ()->GetStreams ()) // for (auto it: dest->GetStreamingDestination ()->GetStreams ())
// { // {
// s << it.first << "->" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << " "; // s << it.first << "->" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << " ";
// s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; // s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
// s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]"; // s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]";
@ -297,7 +302,7 @@ namespace http {
// s << "[Window:" << it.second->GetWindowSize () << "]"; // s << "[Window:" << it.second->GetWindowSize () << "]";
// s << "[Status:" << (int)it.second->GetStatus () << "]"; // s << "[Status:" << (int)it.second->GetStatus () << "]";
// s << "<br>\r\n"<< std::endl; // s << "<br>\r\n"<< std::endl;
// } // }
s << "<br>\r\n<table><caption>Streams</caption><tr>"; s << "<br>\r\n<table><caption>Streams</caption><tr>";
s << "<th>StreamID</th>"; s << "<th>StreamID</th>";
s << "<th>Destination</th>"; s << "<th>Destination</th>";
@ -311,8 +316,8 @@ namespace http {
s << "<th>Status</th>"; s << "<th>Status</th>";
s << "</tr>"; s << "</tr>";
for (auto it: dest->GetAllStreams ()) for (const auto& it: dest->GetAllStreams ())
{ {
s << "<tr>"; s << "<tr>";
s << "<td>" << it->GetSendStreamID () << "</td>"; s << "<td>" << it->GetSendStreamID () << "</td>";
s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>"; s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>";
@ -326,12 +331,12 @@ namespace http {
s << "<td>" << (int)it->GetStatus () << "</td>"; s << "<td>" << (int)it->GetStatus () << "</td>";
s << "</tr><br>\r\n" << std::endl; s << "</tr><br>\r\n" << std::endl;
} }
} }
} }
void ShowLeasesSets(std::stringstream& s) void ShowLeasesSets(std::stringstream& s)
{ {
s << "<div id='leasesets'>LeaseSets</div><br>"; s << "<div id='leasesets'><b>LeaseSets:</b></div><br>";
// for each lease set // for each lease set
i2p::data::netdb.VisitLeaseSets( i2p::data::netdb.VisitLeaseSets(
[&s](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet) [&s](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
@ -379,7 +384,7 @@ namespace http {
); );
// end for each lease set // end for each lease set
} }
void ShowTunnels (std::stringstream& s) void ShowTunnels (std::stringstream& s)
{ {
s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n"; s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n";
@ -396,7 +401,7 @@ namespace http {
ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ());
} }
s << "<br>\r\n"; s << "<br>\r\n";
} }
void ShowCommands (std::stringstream& s) void ShowCommands (std::stringstream& s)
{ {
@ -406,31 +411,37 @@ namespace http {
//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_DISABLE_TRANSIT << "\">Decline transit tunnels</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "\">Decline transit tunnels</a><br>\r\n";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "\">Accept transit tunnels</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "\">Accept transit tunnels</a><br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
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";
#endif #endif
#ifdef WIN32_APP
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Gracefull shutdown</a><br>\r\n";
#endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "\">Force shutdown</a><br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
{ {
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n"; s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
{ {
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it)) if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
s << it->GetTunnelID () << " "; s << it->GetTunnelID () << " &#8658; ";
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it)) else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
s << " " << it->GetTunnelID (); s << " &#8658; " << it->GetTunnelID ();
else else
s << " " << it->GetTunnelID () << " "; s << " &#8658; " << it->GetTunnelID () << " &#8658; ";
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n"; s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
} }
} }
@ -440,50 +451,50 @@ namespace http {
s << "<b>Transports:</b><br>\r\n<br>\r\n"; s << "<b>Transports:</b><br>\r\n<br>\r\n";
auto ntcpServer = i2p::transport::transports.GetNTCPServer (); auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
if (ntcpServer) if (ntcpServer)
{ {
s << "<b>NTCP</b><br>\r\n"; s << "<b>NTCP</b><br>\r\n";
for (auto it: ntcpServer->GetNTCPSessions ()) for (const auto& it: ntcpServer->GetNTCPSessions ())
{ {
if (it.second && it.second->IsEstablished ()) if (it.second && it.second->IsEstablished ())
{ {
// incoming connection doesn't have remote RI // incoming connection doesn't have remote RI
if (it.second->IsOutgoing ()) s << " "; if (it.second->IsOutgoing ()) s << " &#8658; ";
s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string (); << it.second->GetSocket ().remote_endpoint().address ().to_string ();
if (!it.second->IsOutgoing ()) s << " "; if (!it.second->IsOutgoing ()) s << " &#8658; ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<br>\r\n" << std::endl; s << "<br>\r\n" << std::endl;
} }
} }
} }
auto ssuServer = i2p::transport::transports.GetSSUServer (); auto ssuServer = i2p::transport::transports.GetSSUServer ();
if (ssuServer) if (ssuServer)
{ {
s << "<br>\r\n<b>SSU</b><br>\r\n"; s << "<br>\r\n<b>SSU</b><br>\r\n";
for (auto it: ssuServer->GetSessions ()) for (const auto& it: ssuServer->GetSessions ())
{ {
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << " "; if (it.second->IsOutgoing ()) s << " &#8658; ";
s << endpoint.address ().to_string () << ":" << endpoint.port (); s << endpoint.address ().to_string () << ":" << endpoint.port ();
if (!it.second->IsOutgoing ()) s << " "; if (!it.second->IsOutgoing ()) s << " &#8658; ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it.second->GetRelayTag ()) if (it.second->GetRelayTag ())
s << " [itag:" << it.second->GetRelayTag () << "]"; s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>\r\n" << std::endl; s << "<br>\r\n" << std::endl;
} }
s << "<br>\r\n<b>SSU6</b><br>\r\n"; s << "<br>\r\n<b>SSU6</b><br>\r\n";
for (auto it: ssuServer->GetSessionsV6 ()) for (const auto& it: ssuServer->GetSessionsV6 ())
{ {
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
if (it.second->IsOutgoing ()) s << " "; if (it.second->IsOutgoing ()) s << " &#8658; ";
s << endpoint.address ().to_string () << ":" << endpoint.port (); s << endpoint.address ().to_string () << ":" << endpoint.port ();
if (!it.second->IsOutgoing ()) s << " "; if (!it.second->IsOutgoing ()) s << " &#8658; ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<br>\r\n" << std::endl; s << "<br>\r\n" << std::endl;
} }
} }
} }
void ShowSAMSessions (std::stringstream& s) void ShowSAMSessions (std::stringstream& s)
{ {
auto sam = i2p::client::context.GetSAMBridge (); auto sam = i2p::client::context.GetSAMBridge ();
@ -496,8 +507,8 @@ namespace http {
{ {
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;
} }
} }
void ShowSAMSession (std::stringstream& s, const std::string& id) void ShowSAMSession (std::stringstream& s, const std::string& id)
{ {
@ -517,7 +528,7 @@ namespace http {
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";
for (auto it: session->ListSockets()) for (const auto& it: session->ListSockets())
{ {
switch (it->GetSocketType ()) switch (it->GetSocketType ())
{ {
@ -528,8 +539,8 @@ namespace http {
} }
s << " [" << it->GetSocket ().remote_endpoint() << "]"; s << " [" << it->GetSocket ().remote_endpoint() << "]";
s << "<br>\r\n"; s << "<br>\r\n";
} }
} }
void ShowI2PTunnels (std::stringstream& s) void ShowI2PTunnels (std::stringstream& s)
{ {
@ -538,21 +549,21 @@ namespace http {
{ {
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> &#8656; ";
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;
} }
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n"; s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
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> &#8658; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort (); s << ":" << it.second->GetLocalPort ();
s << "</a><br>\r\n"<< std::endl; s << "</a><br>\r\n"<< std::endl;
} }
} }
HTTPConnection::HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket): HTTPConnection::HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket):
m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0) m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0)
@ -723,6 +734,9 @@ namespace http {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
Daemon.gracefullShutdownInterval = 10*60; Daemon.gracefullShutdownInterval = 10*60;
#endif
#ifdef WIN32_APP
i2p::win32::GracefulShutdown ();
#endif #endif
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
@ -740,7 +754,7 @@ namespace http {
s << "<a href=\"/?page=commands\">Back to commands list</a><br>\r\n"; s << "<a href=\"/?page=commands\">Back to commands list</a><br>\r\n";
s << "<p>You will be redirected in 5 seconds</b>"; s << "<p>You will be redirected in 5 seconds</b>";
res.add_header("Refresh", "5; url=/?page=commands"); res.add_header("Refresh", "5; url=/?page=commands");
} }
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)
{ {
@ -770,12 +784,14 @@ namespace http {
std::string pass; i2p::config::GetOption("http.pass", pass); std::string pass; i2p::config::GetOption("http.pass", pass);
/* generate pass if needed */ /* generate pass if needed */
if (needAuth && pass == "") { if (needAuth && pass == "") {
uint8_t random[16];
char alnum[] = "0123456789" char alnum[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"; "abcdefghijklmnopqrstuvwxyz";
pass.resize(16); pass.resize(sizeof(random));
for (size_t i = 0; i < pass.size(); i++) { RAND_bytes(random, sizeof(random));
pass[i] = alnum[rand() % (sizeof(alnum) - 1)]; for (size_t i = 0; i < sizeof(random); i++) {
pass[i] = alnum[random[i] % (sizeof(alnum) - 1)];
} }
i2p::config::SetOption("http.pass", pass); i2p::config::SetOption("http.pass", pass);
LogPrint(eLogInfo, "HTTPServer: password set to ", pass); LogPrint(eLogInfo, "HTTPServer: password set to ", pass);

2
I2CP.cpp

@ -659,7 +659,7 @@ namespace client
{ {
m_IsRunning = false; m_IsRunning = false;
m_Acceptor.cancel (); m_Acceptor.cancel ();
for (auto it: m_Sessions) for (auto& it: m_Sessions)
it.second->Stop (); it.second->Stop ();
m_Sessions.clear (); m_Sessions.clear ();
m_Service.stop (); m_Service.stop ();

2
I2NPProtocol.cpp

@ -202,7 +202,7 @@ namespace i2p
len += 32; len += 32;
buf[len] = routers.size (); buf[len] = routers.size ();
len++; len++;
for (auto it: routers) for (const auto& it: routers)
{ {
memcpy (buf + len, it, 32); memcpy (buf + len, it, 32);
len += 32; len += 32;

6
I2PControl.cpp

@ -358,7 +358,7 @@ namespace client
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) 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); LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
auto it1 = m_RouterInfoHandlers.find (it->first); auto it1 = m_RouterInfoHandlers.find (it->first);
@ -434,7 +434,7 @@ namespace client
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) 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 << ","; if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
@ -483,7 +483,7 @@ namespace client
// network setting // network setting
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) 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 << ","; if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);

12
LeaseSet.cpp

@ -64,10 +64,10 @@ namespace data
return; return;
} }
// reset existing leases // reset existing leases
if (m_StoreLeases) if (m_StoreLeases)
for (auto it: m_Leases) for (auto& it: m_Leases)
it->isUpdated = false; it->isUpdated = false;
else else
m_Leases.clear (); m_Leases.clear ();
@ -123,7 +123,7 @@ namespace data
m_Leases.erase (it++); m_Leases.erase (it++);
} }
else else
it++; ++it;
} }
} }
@ -167,7 +167,7 @@ namespace data
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
std::vector<std::shared_ptr<const Lease> > leases; std::vector<std::shared_ptr<const Lease> > leases;
for (auto it: m_Leases) for (const auto& it: m_Leases)
{ {
auto endDate = it->endDate; auto endDate = it->endDate;
if (withThreshold) if (withThreshold)
@ -183,7 +183,7 @@ namespace data
bool LeaseSet::HasExpiredLeases () const bool LeaseSet::HasExpiredLeases () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_Leases) for (const auto& it: m_Leases)
if (ts >= it->endDate) return true; if (ts >= it->endDate) return true;
return false; return false;
} }

4
Makefile.mingw

@ -9,7 +9,7 @@ LDFLAGS = -Wl,-rpath,/usr/local/lib \
-L/usr/local/lib -L/usr/local/lib
# UPNP Support # UPNP Support
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
LDLIBS = -Wl,-Bstatic -lminiupnpc LDLIBS = -Wl,-Bstatic -lminiupnpc
endif endif
@ -37,7 +37,7 @@ ifeq ($(USE_WIN32_APP), yes)
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif endif
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),1)
CPU_FLAGS = -maes -DAESNI CPU_FLAGS = -maes -DAESNI
else else
CPU_FLAGS = -msse CPU_FLAGS = -msse

13
NTCPSession.cpp

@ -19,7 +19,8 @@ namespace i2p
namespace transport namespace transport
{ {
NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter): NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter), m_Server (server), m_Socket (m_Server.GetService ()), TransportSession (in_RemoteRouter, NTCP_TERMINATION_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()),
m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_TerminationTimer (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false),
m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_IsSending (false) m_ReceiveBufferOffset (0), m_NextMessage (nullptr), m_IsSending (false)
{ {
@ -665,7 +666,7 @@ namespace transport
{ {
m_IsSending = true; m_IsSending = true;
std::vector<boost::asio::const_buffer> bufs; std::vector<boost::asio::const_buffer> bufs;
for (auto it: msgs) for (const auto& it: msgs)
bufs.push_back (CreateMsgBuffer (it)); bufs.push_back (CreateMsgBuffer (it));
boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (), boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (),
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
@ -715,7 +716,7 @@ namespace transport
{ {
if (m_SendQueue.size () < NTCP_MAX_OUTGOING_QUEUE_SIZE) if (m_SendQueue.size () < NTCP_MAX_OUTGOING_QUEUE_SIZE)
{ {
for (auto it: msgs) for (const auto& it: msgs)
m_SendQueue.push_back (it); m_SendQueue.push_back (it);
} }
else else
@ -731,7 +732,7 @@ namespace transport
void NTCPSession::ScheduleTermination () void NTCPSession::ScheduleTermination ()
{ {
m_TerminationTimer.cancel (); m_TerminationTimer.cancel ();
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT)); m_TerminationTimer.expires_from_now (boost::posix_time::seconds(GetTerminationTimeout ()));
m_TerminationTimer.async_wait (std::bind (&NTCPSession::HandleTerminationTimer, m_TerminationTimer.async_wait (std::bind (&NTCPSession::HandleTerminationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
@ -740,7 +741,7 @@ namespace transport
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
LogPrint (eLogDebug, "NTCP: No activity for ", NTCP_TERMINATION_TIMEOUT, " seconds"); LogPrint (eLogDebug, "NTCP: No activity for ", GetTerminationTimeout (), " seconds");
//Terminate (); //Terminate ();
m_Socket.close ();// invoke Terminate () from HandleReceive m_Socket.close ();// invoke Terminate () from HandleReceive
} }
@ -766,7 +767,7 @@ namespace transport
m_Thread = new std::thread (std::bind (&NTCPServer::Run, this)); m_Thread = new std::thread (std::bind (&NTCPServer::Run, this));
// create acceptors // create acceptors
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (auto address: addresses) for (const auto& address: addresses)
{ {
if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP) if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
{ {

35
NetDb.cpp

@ -14,7 +14,6 @@
#include "RouterContext.h" #include "RouterContext.h"
#include "Garlic.h" #include "Garlic.h"
#include "NetDb.h" #include "NetDb.h"
#include "util.h"
using namespace i2p::transport; using namespace i2p::transport;
@ -52,7 +51,7 @@ namespace data
{ {
if (m_IsRunning) if (m_IsRunning)
{ {
for (auto it: m_RouterInfos) for (auto& it: m_RouterInfos)
it.second->SaveProfile (); it.second->SaveProfile ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
m_RouterInfos.clear (); m_RouterInfos.clear ();
@ -72,7 +71,7 @@ namespace data
void NetDb::Run () void NetDb::Run ()
{ {
uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0; uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
while (m_IsRunning) while (m_IsRunning)
{ {
try try
@ -122,7 +121,11 @@ namespace data
} }
lastSave = ts; lastSave = ts;
} }
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
i2p::context.CleanupDestination ();
lastDestinationCleanup = ts;
}
// if we're in hidden mode don't publish or explore // if we're in hidden mode don't publish or explore
// if (m_HiddenMode) continue; // if (m_HiddenMode) continue;
@ -336,7 +339,7 @@ namespace data
m_LastLoad = i2p::util::GetSecondsSinceEpoch(); m_LastLoad = i2p::util::GetSecondsSinceEpoch();
std::vector<std::string> files; std::vector<std::string> files;
m_Storage.Traverse(files); m_Storage.Traverse(files);
for (auto path : files) for (const auto& path : files)
LoadRouterInfo(path); LoadRouterInfo(path);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)"); LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
@ -354,7 +357,7 @@ namespace data
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
for (auto it: m_RouterInfos) for (auto& it: m_RouterInfos)
{ {
std::string ident = it.second->GetIdentHashBase64(); std::string ident = it.second->GetIdentHashBase64();
std::string path = m_Storage.Path(ident); std::string path = m_Storage.Path(ident);
@ -402,7 +405,7 @@ namespace data
it = m_RouterInfos.erase (it); it = m_RouterInfos.erase (it);
continue; continue;
} }
it++; ++it;
} }
} }
// clean up expired floodfiils // clean up expired floodfiils
@ -412,7 +415,7 @@ namespace data
if ((*it)->IsUnreachable ()) if ((*it)->IsUnreachable ())
it = m_Floodfills.erase (it); it = m_Floodfills.erase (it);
else else
it++; ++it;
} }
} }
} }
@ -898,7 +901,7 @@ namespace data
{ {
uint32_t i = 0; uint32_t i = 0;
std::unique_lock<std::mutex> l(m_RouterInfosMutex); std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it: m_RouterInfos) for (const auto& it: m_RouterInfos)
{ {
if (i >= ind) if (i >= ind)
{ {
@ -930,7 +933,7 @@ namespace data
else else
minMetric.SetMax (); minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills) for (const auto& it: m_Floodfills)
{ {
if (!it->IsUnreachable ()) if (!it->IsUnreachable ())
{ {
@ -961,7 +964,7 @@ namespace data
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash (); if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills) for (const auto& it: m_Floodfills)
{ {
if (!it->IsUnreachable ()) if (!it->IsUnreachable ())
{ {
@ -980,11 +983,11 @@ namespace data
std::vector<IdentHash> res; std::vector<IdentHash> res;
size_t i = 0; size_t i = 0;
for (auto it: sorted) for (const auto& it: sorted)
{ {
if (i < num) if (i < num)
{ {
auto& ident = it.r->GetIdentHash (); const auto& ident = it.r->GetIdentHash ();
if (!excluded.count (ident)) if (!excluded.count (ident))
{ {
res.push_back (ident); res.push_back (ident);
@ -1013,7 +1016,7 @@ namespace data
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax (); minMetric.SetMax ();
// must be called from NetDb thread only // must be called from NetDb thread only
for (auto it: m_RouterInfos) for (const auto& it: m_RouterInfos)
{ {
if (!it.second->IsFloodfill ()) if (!it.second->IsFloodfill ())
{ {
@ -1039,7 +1042,7 @@ namespace data
it = m_LeaseSets.erase (it); it = m_LeaseSets.erase (it);
} }
else else
it++; ++it;
} }
} }
@ -1051,7 +1054,7 @@ namespace data
if (ts > it->second.second + 180) // 3 minutes if (ts > it->second.second + 180) // 3 minutes
it = m_LookupResponses.erase (it); it = m_LookupResponses.erase (it);
else else
it++; ++it;
} }
} }
} }

2
NetDbRequests.cpp

@ -141,7 +141,7 @@ namespace data
if (done) if (done)
it = m_RequestedDestinations.erase (it); it = m_RequestedDestinations.erase (it);
else else
it++; ++it;
} }
} }
} }

2
Profiling.cpp

@ -167,7 +167,7 @@ namespace data
std::vector<std::string> files; std::vector<std::string> files;
m_ProfilesStorage.Traverse(files); m_ProfilesStorage.Traverse(files);
for (auto path: files) { for (const auto& path: files) {
if (stat(path.c_str(), &st) != 0) { if (stat(path.c_str(), &st) != 0) {
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path); LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
continue; continue;

5
Queue.h

@ -7,6 +7,7 @@
#include <thread> #include <thread>
#include <condition_variable> #include <condition_variable>
#include <functional> #include <functional>
#include <utility>
namespace i2p namespace i2p
{ {
@ -20,7 +21,7 @@ namespace util
void Put (Element e) void Put (Element e)
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
m_Queue.push (e); m_Queue.push (std::move(e));
m_NonEmpty.notify_one (); m_NonEmpty.notify_one ();
} }
@ -29,7 +30,7 @@ namespace util
if (!vec.empty ()) if (!vec.empty ())
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
for (auto it: vec) for (const auto& it: vec)
m_Queue.push (it); m_Queue.push (it);
m_NonEmpty.notify_one (); m_NonEmpty.notify_one ();
} }

8
Reseed.cpp

@ -16,6 +16,7 @@
#include "NetDb.h" #include "NetDb.h"
#include "HTTP.h" #include "HTTP.h"
#include "util.h" #include "util.h"
#include "Config.h"
namespace i2p namespace i2p
{ {
@ -51,6 +52,13 @@ namespace data
int Reseeder::ReseedNowSU3 () int Reseeder::ReseedNowSU3 ()
{ {
std::string filename; i2p::config::GetOption("reseed.file", filename);
if (filename.length() > 0) // reseed file is specified
{
auto num = ProcessSU3File (filename.c_str ());
if (num > 0) return num; // success
LogPrint (eLogWarning, "Can't reseed from ", filename, " . Trying from hosts");
}
auto ind = rand () % httpsReseedHostList.size (); auto ind = rand () % httpsReseedHostList.size ();
std::string& reseedHost = httpsReseedHostList[ind]; std::string& reseedHost = httpsReseedHostList[ind];
return ReseedFromSU3 (reseedHost); return ReseedFromSU3 (reseedHost);

20
RouterContext.cpp

@ -112,7 +112,7 @@ namespace i2p
void RouterContext::UpdatePort (int port) void RouterContext::UpdatePort (int port)
{ {
bool updated = false; bool updated = false;
for (auto address : m_RouterInfo.GetAddresses ()) for (auto& address : m_RouterInfo.GetAddresses ())
{ {
if (address->port != port) if (address->port != port)
{ {
@ -127,7 +127,7 @@ namespace i2p
void RouterContext::UpdateAddress (const boost::asio::ip::address& host) void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
{ {
bool updated = false; bool updated = false;
for (auto address : m_RouterInfo.GetAddresses ()) for (auto& address : m_RouterInfo.GetAddresses ())
{ {
if (address->host != host && address->IsCompatible (host)) if (address->host != host && address->IsCompatible (host))
{ {
@ -244,7 +244,7 @@ namespace i2p
m_RouterInfo.SetCaps (i2p::data::RouterInfo::eUnreachable | i2p::data::RouterInfo::eSSUTesting); // LU, B m_RouterInfo.SetCaps (i2p::data::RouterInfo::eUnreachable | i2p::data::RouterInfo::eSSUTesting); // LU, B
// remove NTCP address // remove NTCP address
auto& addresses = m_RouterInfo.GetAddresses (); auto& addresses = m_RouterInfo.GetAddresses ();
for (auto it = addresses.begin (); it != addresses.end (); it++) for (auto it = addresses.begin (); it != addresses.end (); ++it)
{ {
if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP &&
(*it)->host.is_v4 ()) (*it)->host.is_v4 ())
@ -254,7 +254,7 @@ namespace i2p
} }
} }
// delete previous introducers // delete previous introducers
for (auto addr : addresses) for (auto& addr : addresses)
addr->introducers.clear (); addr->introducers.clear ();
// update // update
@ -274,7 +274,7 @@ namespace i2p
// insert NTCP back // insert NTCP back
auto& addresses = m_RouterInfo.GetAddresses (); auto& addresses = m_RouterInfo.GetAddresses ();
for (auto addr : addresses) for (const auto& addr : addresses)
{ {
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU && if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU &&
addr->host.is_v4 ()) addr->host.is_v4 ())
@ -285,7 +285,7 @@ namespace i2p
} }
} }
// delete previous introducers // delete previous introducers
for (auto addr : addresses) for (auto& addr : addresses)
addr->introducers.clear (); addr->introducers.clear ();
// update // update
@ -316,7 +316,7 @@ namespace i2p
bool updated = false, found = false; bool updated = false, found = false;
int port = 0; int port = 0;
auto& addresses = m_RouterInfo.GetAddresses (); auto& addresses = m_RouterInfo.GetAddresses ();
for (auto addr: addresses) for (auto& addr: addresses)
{ {
if (addr->host.is_v6 () && addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP) if (addr->host.is_v6 () && addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
{ {
@ -439,6 +439,12 @@ namespace i2p
std::unique_lock<std::mutex> l(m_GarlicMutex); std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
} }
void RouterContext::CleanupDestination ()
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::CleanupExpiredTags ();
}
uint32_t RouterContext::GetUptime () const uint32_t RouterContext::GetUptime () const
{ {

3
RouterContext.h

@ -71,7 +71,8 @@ namespace i2p
void SetSupportsV4 (bool supportsV4); void SetSupportsV4 (bool supportsV4);
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
void UpdateStats (); void UpdateStats ();
void CleanupDestination (); // garlic destination
// implements LocalDestination // implements LocalDestination
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };

51
RouterInfo.cpp

@ -369,19 +369,19 @@ namespace data
SetProperty ("caps", caps); SetProperty ("caps", caps);
} }
void RouterInfo::WriteToStream (std::ostream& s) void RouterInfo::WriteToStream (std::ostream& s) const
{ {
uint64_t ts = htobe64 (m_Timestamp); uint64_t ts = htobe64 (m_Timestamp);
s.write ((char *)&ts, sizeof (ts)); s.write ((const char *)&ts, sizeof (ts));
// addresses // addresses
uint8_t numAddresses = m_Addresses->size (); uint8_t numAddresses = m_Addresses->size ();
s.write ((char *)&numAddresses, sizeof (numAddresses)); s.write ((char *)&numAddresses, sizeof (numAddresses));
for (auto addr : *m_Addresses) for (const auto& addr_ptr : *m_Addresses)
{ {
Address& address = *addr; const Address& address = *addr_ptr;
s.write ((char *)&address.cost, sizeof (address.cost)); s.write ((const char *)&address.cost, sizeof (address.cost));
s.write ((char *)&address.date, sizeof (address.date)); s.write ((const char *)&address.date, sizeof (address.date));
std::stringstream properties; std::stringstream properties;
if (address.transportStyle == eTransportNTCP) if (address.transportStyle == eTransportNTCP)
WriteString ("NTCP", s); WriteString ("NTCP", s);
@ -410,7 +410,7 @@ namespace data
if (address.introducers.size () > 0) if (address.introducers.size () > 0)
{ {
int i = 0; int i = 0;
for (auto introducer: address.introducers) for (const auto& introducer: address.introducers)
{ {
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties); WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
properties << '='; properties << '=';
@ -419,7 +419,7 @@ namespace data
i++; i++;
} }
i = 0; i = 0;
for (auto introducer: address.introducers) for (const auto& introducer: address.introducers)
{ {
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties); WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
properties << '='; properties << '=';
@ -431,7 +431,7 @@ namespace data
i++; i++;
} }
i = 0; i = 0;
for (auto introducer: address.introducers) for (const auto& introducer: address.introducers)
{ {
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties); WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
properties << '='; properties << '=';
@ -440,7 +440,7 @@ namespace data
i++; i++;
} }
i = 0; i = 0;
for (auto introducer: address.introducers) for (const auto& introducer: address.introducers)
{ {
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties); WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
properties << '='; properties << '=';
@ -482,7 +482,7 @@ namespace data
// properties // properties
std::stringstream properties; std::stringstream properties;
for (auto& p : m_Properties) for (const auto& p : m_Properties)
{ {
WriteString (p.first, properties); WriteString (p.first, properties);
properties << '='; properties << '=';
@ -570,10 +570,10 @@ namespace data
addr->cost = 2; addr->cost = 2;
addr->date = 0; addr->date = 0;
addr->mtu = 0; addr->mtu = 0;
for (auto it: *m_Addresses) // don't insert same address twice for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return; if (*it == *addr) return;
m_Addresses->push_back(addr);
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
m_Addresses->push_back(std::move(addr));
} }
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
@ -586,21 +586,22 @@ namespace data
addr->date = 0; addr->date = 0;
addr->mtu = mtu; addr->mtu = mtu;
memcpy (addr->key, key, 32); memcpy (addr->key, key, 32);
for (auto it: *m_Addresses) // don't insert same address twice for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return; if (*it == *addr) return;
m_Addresses->push_back(addr);
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
m_Caps |= eSSUTesting; m_Addresses->push_back(std::move(addr));
m_Caps |= eSSUIntroducer;
m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer;
} }
bool RouterInfo::AddIntroducer (const Introducer& introducer) bool RouterInfo::AddIntroducer (const Introducer& introducer)
{ {
for (auto addr : *m_Addresses) for (auto& addr : *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{ {
for (auto intro: addr->introducers) for (auto& intro: addr->introducers)
if (intro.iTag == introducer.iTag) return false; // already presented if (intro.iTag == introducer.iTag) return false; // already presented
addr->introducers.push_back (introducer); addr->introducers.push_back (introducer);
return true; return true;
@ -611,16 +612,16 @@ namespace data
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
{ {
for (auto addr: *m_Addresses) for (auto& addr: *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{ {
for (std::vector<Introducer>::iterator it = addr->introducers.begin (); it != addr->introducers.end (); it++) for (auto it = addr->introducers.begin (); it != addr->introducers.end (); ++it)
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
{ {
addr->introducers.erase (it); addr->introducers.erase (it);
return true; return true;
} }
} }
} }
return false; return false;
@ -707,7 +708,7 @@ namespace data
if (addr->host.is_v6 ()) if (addr->host.is_v6 ())
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
else else
it++; ++it;
} }
} }
} }
@ -723,7 +724,7 @@ namespace data
if (addr->host.is_v4 ()) if (addr->host.is_v4 ())
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
else else
it++; ++it;
} }
} }
} }
@ -752,7 +753,7 @@ namespace data
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
{ {
auto addresses = m_Addresses; auto addresses = m_Addresses;
for (auto address : *addresses) for (const auto& address : *addresses)
{ {
if (address->transportStyle == s) if (address->transportStyle == s)
{ {

6
RouterInfo.h

@ -187,9 +187,9 @@ namespace data
void ReadFromFile (); void ReadFromFile ();
void ReadFromStream (std::istream& s); void ReadFromStream (std::istream& s);
void ReadFromBuffer (bool verifySignature); void ReadFromBuffer (bool verifySignature);
void WriteToStream (std::ostream& s); void WriteToStream (std::ostream& s) const;
size_t ReadString (char * str, std::istream& s); static size_t ReadString (char* str, std::istream& s);
void WriteString (const std::string& str, std::ostream& s); static void WriteString (const std::string& str, std::ostream& s);
void ExtractCaps (const char * value); void ExtractCaps (const char * value);
std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
void UpdateCapsProperty (); void UpdateCapsProperty ();

4
SAM.cpp

@ -686,7 +686,7 @@ namespace client
{ {
{ {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
for (auto sock : m_Sockets) { for (auto& sock : m_Sockets) {
sock->CloseStream(); sock->CloseStream();
} }
} }
@ -719,7 +719,7 @@ namespace client
{ {
m_IsRunning = false; m_IsRunning = false;
m_Acceptor.cancel (); m_Acceptor.cancel ();
for (auto it: m_Sessions) for (auto& it: m_Sessions)
it.second->CloseStreams (); it.second->CloseStreams ();
m_Sessions.clear (); m_Sessions.clear ();
m_Service.stop (); m_Service.stop ();

2
SAM.h

@ -154,7 +154,7 @@ namespace client
std::list<std::shared_ptr<SAMSocket> > l; std::list<std::shared_ptr<SAMSocket> > l;
{ {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
for( auto & sock : m_Sockets ) l.push_back(sock); for(const auto& sock : m_Sockets ) l.push_back(sock);
} }
return l; return l;
} }

2
SOCKS.cpp

@ -26,7 +26,7 @@ namespace proxy
{ {
uint8_t size; uint8_t size;
char value[max_socks_hostname_size]; char value[max_socks_hostname_size];
void FromString (std::string str) void FromString (const std::string& str)
{ {
size = str.length(); size = str.length();
if (str.length() > max_socks_hostname_size) size = max_socks_hostname_size; if (str.length() > max_socks_hostname_size) size = max_socks_hostname_size;

42
SSU.cpp

@ -237,9 +237,8 @@ namespace transport
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions) std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
{ {
std::shared_ptr<SSUSession> session; std::shared_ptr<SSUSession> session;
for (auto it1: packets) for (auto& packet: packets)
{ {
auto packet = it1;
try try
{ {
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
@ -431,11 +430,11 @@ namespace transport
void SSUServer::DeleteAllSessions () void SSUServer::DeleteAllSessions ()
{ {
for (auto it: m_Sessions) for (auto& it: m_Sessions)
it.second->Close (); it.second->Close ();
m_Sessions.clear (); m_Sessions.clear ();
for (auto it: m_SessionsV6) for (auto& it: m_SessionsV6)
it.second->Close (); it.second->Close ();
m_SessionsV6.clear (); m_SessionsV6.clear ();
} }
@ -444,7 +443,7 @@ namespace transport
std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only
{ {
std::vector<std::shared_ptr<SSUSession> > filteredSessions; std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_Sessions) for (const auto& s :m_Sessions)
if (filter (s.second)) filteredSessions.push_back (s.second); if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0) if (filteredSessions.size () > 0)
{ {
@ -468,7 +467,7 @@ namespace transport
std::shared_ptr<SSUSession> SSUServer::GetRandomV6Session (Filter filter) // v6 only std::shared_ptr<SSUSession> SSUServer::GetRandomV6Session (Filter filter) // v6 only
{ {
std::vector<std::shared_ptr<SSUSession> > filteredSessions; std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_SessionsV6) for (const auto& s :m_SessionsV6)
if (filter (s.second)) filteredSessions.push_back (s.second); if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0) if (filteredSessions.size () > 0)
{ {
@ -535,7 +534,7 @@ namespace transport
std::list<boost::asio::ip::udp::endpoint> newList; std::list<boost::asio::ip::udp::endpoint> newList;
size_t numIntroducers = 0; size_t numIntroducers = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it :m_Introducers) for (const auto& it : m_Introducers)
{ {
auto session = FindSession (it); auto session = FindSession (it);
if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
@ -552,23 +551,20 @@ namespace transport
{ {
// create new // create new
auto introducers = FindIntroducers (SSU_MAX_NUM_INTRODUCERS); auto introducers = FindIntroducers (SSU_MAX_NUM_INTRODUCERS);
if (introducers.size () > 0) for (const auto& it1: introducers)
{ {
for (auto it1: introducers) const auto& ep = it1->GetRemoteEndpoint ();
i2p::data::RouterInfo::Introducer introducer;
introducer.iHost = ep.address ();
introducer.iPort = ep.port ();
introducer.iTag = it1->GetRelayTag ();
introducer.iKey = it1->GetIntroKey ();
if (i2p::context.AddIntroducer (introducer))
{ {
auto& ep = it1->GetRemoteEndpoint (); newList.push_back (ep);
i2p::data::RouterInfo::Introducer introducer; if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
introducer.iHost = ep.address (); }
introducer.iPort = ep.port (); }
introducer.iTag = it1->GetRelayTag ();
introducer.iKey = it1->GetIntroKey ();
if (i2p::context.AddIntroducer (introducer))
{
newList.push_back (ep);
if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
}
}
}
} }
m_Introducers = newList; m_Introducers = newList;
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS) if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
@ -637,7 +633,7 @@ namespace transport
it = m_PeerTests.erase (it); it = m_PeerTests.erase (it);
} }
else else
it++; ++it;
} }
if (numDeleted > 0) if (numDeleted > 0)
LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired"); LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");

44
SSUData.cpp

@ -25,10 +25,10 @@ namespace transport
} }
SSUData::SSUData (SSUSession& session): SSUData::SSUData (SSUSession& session):
m_Session (session), m_ResendTimer (session.GetService ()), m_DecayTimer (session.GetService ()), m_Session (session), m_ResendTimer (session.GetService ()),
m_IncompleteMessagesCleanupTimer (session.GetService ()), m_IncompleteMessagesCleanupTimer (session.GetService ()),
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE), m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
m_PacketSize (m_MaxPacketSize) m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
{ {
} }
@ -44,7 +44,6 @@ namespace transport
void SSUData::Stop () void SSUData::Stop ()
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_DecayTimer.cancel ();
m_IncompleteMessagesCleanupTimer.cancel (); m_IncompleteMessagesCleanupTimer.cancel ();
} }
@ -233,11 +232,8 @@ namespace transport
{ {
if (!m_ReceivedMessages.count (msgID)) if (!m_ReceivedMessages.count (msgID))
{ {
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES)
m_ReceivedMessages.clear ();
else
ScheduleDecay ();
m_ReceivedMessages.insert (msgID); m_ReceivedMessages.insert (msgID);
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
if (!msg->IsExpired ()) if (!msg->IsExpired ())
m_Handler.PutNextMessage (msg); m_Handler.PutNextMessage (msg);
else else
@ -431,12 +427,12 @@ namespace transport
if (ts >= it->second->nextResendTime) if (ts >= it->second->nextResendTime)
{ {
if (it->second->numResends < MAX_NUM_RESENDS) if (it->second->numResends < MAX_NUM_RESENDS)
{ {
for (auto& f: it->second->fragments) for (auto& f: it->second->fragments)
if (f) if (f)
{ {
try try
{ {
m_Session.Send (f->buf, f->len); // resend m_Session.Send (f->buf, f->len); // resend
numResent++; numResent++;
} }
@ -444,11 +440,11 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU: Can't resend data fragment ", ec.what ()); LogPrint (eLogWarning, "SSU: Can't resend data fragment ", ec.what ());
} }
} }
it->second->numResends++; it->second->numResends++;
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL; it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
it++; ++it;
} }
else else
{ {
@ -457,7 +453,7 @@ namespace transport
} }
} }
else else
it++; ++it;
} }
if (numResent < MAX_OUTGOING_WINDOW_SIZE) if (numResent < MAX_OUTGOING_WINDOW_SIZE)
ScheduleResend (); ScheduleResend ();
@ -469,21 +465,6 @@ namespace transport
} }
} }
void SSUData::ScheduleDecay ()
{
m_DecayTimer.cancel ();
m_DecayTimer.expires_from_now (boost::posix_time::seconds(DECAY_INTERVAL));
auto s = m_Session.shared_from_this();
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleDecayTimer (ecode); });
}
void SSUData::HandleDecayTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
m_ReceivedMessages.clear ();
}
void SSUData::ScheduleIncompleteMessagesCleanup () void SSUData::ScheduleIncompleteMessagesCleanup ()
{ {
m_IncompleteMessagesCleanupTimer.cancel (); m_IncompleteMessagesCleanupTimer.cancel ();
@ -506,8 +487,13 @@ namespace transport
it = m_IncompleteMessages.erase (it); it = m_IncompleteMessages.erase (it);
} }
else else
it++; ++it;
} }
// decay
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
m_ReceivedMessages.clear ();
ScheduleIncompleteMessagesCleanup (); ScheduleIncompleteMessagesCleanup ();
} }
} }

10
SSUData.h

@ -5,7 +5,7 @@
#include <string.h> #include <string.h>
#include <map> #include <map>
#include <vector> #include <vector>
#include <set> #include <unordered_set>
#include <memory> #include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@ -109,9 +109,6 @@ namespace transport
void ScheduleResend (); void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
void ScheduleDecay ();
void HandleDecayTimer (const boost::system::error_code& ecode);
void ScheduleIncompleteMessagesCleanup (); void ScheduleIncompleteMessagesCleanup ();
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode); void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
@ -121,10 +118,11 @@ namespace transport
SSUSession& m_Session; SSUSession& m_Session;
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages; std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
std::map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages; std::map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
std::set<uint32_t> m_ReceivedMessages; std::unordered_set<uint32_t> m_ReceivedMessages;
boost::asio::deadline_timer m_ResendTimer, m_DecayTimer, m_IncompleteMessagesCleanupTimer; boost::asio::deadline_timer m_ResendTimer, m_IncompleteMessagesCleanupTimer;
int m_MaxPacketSize, m_PacketSize; int m_MaxPacketSize, m_PacketSize;
i2p::I2NPMessagesHandler m_Handler; i2p::I2NPMessagesHandler m_Handler;
uint32_t m_LastMessageReceivedTime; // in second
}; };
} }
} }

9
SSUSession.cpp

@ -12,7 +12,8 @@ namespace i2p
namespace transport namespace transport
{ {
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ): TransportSession (router), std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
TransportSession (router, SSU_TERMINATION_TIMEOUT),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Timer (GetService ()), m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Timer (GetService ()),
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false), m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
m_RelayTag (0),m_Data (*this), m_IsDataReceived (false) m_RelayTag (0),m_Data (*this), m_IsDataReceived (false)
@ -882,7 +883,7 @@ namespace transport
void SSUSession::ScheduleTermination () void SSUSession::ScheduleTermination ()
{ {
m_Timer.cancel (); m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(GetTerminationTimeout ()));
m_Timer.async_wait (std::bind (&SSUSession::HandleTerminationTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleTerminationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
@ -891,7 +892,7 @@ namespace transport
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
LogPrint (eLogWarning, "SSU: no activity with ", m_RemoteEndpoint, " for ", SSU_TERMINATION_TIMEOUT, " seconds"); LogPrint (eLogWarning, "SSU: no activity with ", m_RemoteEndpoint, " for ", GetTerminationTimeout (), " seconds");
Failed (); Failed ();
} }
} }
@ -906,7 +907,7 @@ namespace transport
{ {
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
{ {
for (auto it: msgs) for (const auto& it: msgs)
if (it) m_Data.Send (it); if (it) m_Data.Send (it);
} }
} }

16
Streaming.cpp

@ -247,7 +247,7 @@ namespace stream
} }
int nackCount = packet->GetNACKCount (); int nackCount = packet->GetNACKCount ();
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();) for (auto it = m_SentPackets.begin (); it != m_SentPackets.end ();)
{ {
auto seqn = (*it)->GetSeqn (); auto seqn = (*it)->GetSeqn ();
if (seqn <= ackThrough) if (seqn <= ackThrough)
{ {
@ -263,7 +263,7 @@ namespace stream
if (nacked) if (nacked)
{ {
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " NACK"); LogPrint (eLogDebug, "Streaming: Packet ", seqn, " NACK");
it++; ++it;
continue; continue;
} }
} }
@ -412,7 +412,7 @@ namespace stream
} }
bool isEmpty = m_SentPackets.empty (); bool isEmpty = m_SentPackets.empty ();
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: packets) for (auto& it: packets)
{ {
it->sendTime = ts; it->sendTime = ts;
m_SentPackets.insert (it); m_SentPackets.insert (it);
@ -762,7 +762,7 @@ namespace stream
bool updated = false; bool updated = false;
if (expired && m_CurrentRemoteLease) if (expired && m_CurrentRemoteLease)
{ {
for (auto it: leases) for (const auto& it: leases)
if ((it->tunnelGateway == m_CurrentRemoteLease->tunnelGateway) && (it->tunnelID != m_CurrentRemoteLease->tunnelID)) if ((it->tunnelGateway == m_CurrentRemoteLease->tunnelGateway) && (it->tunnelID != m_CurrentRemoteLease->tunnelID))
{ {
m_CurrentRemoteLease = it; m_CurrentRemoteLease = it;
@ -798,7 +798,7 @@ namespace stream
StreamingDestination::~StreamingDestination () StreamingDestination::~StreamingDestination ()
{ {
for (auto it: m_SavedPackets) for (auto& it: m_SavedPackets)
{ {
for (auto it1: it.second) delete it1; for (auto it1: it.second) delete it1;
it.second.clear (); it.second.clear ();
@ -877,7 +877,7 @@ namespace stream
else // follow on packet without SYN else // follow on packet without SYN
{ {
uint32_t receiveStreamID = packet->GetReceiveStreamID (); uint32_t receiveStreamID = packet->GetReceiveStreamID ();
for (auto it: m_Streams) for (auto& it: m_Streams)
if (it.second->GetSendStreamID () == receiveStreamID) if (it.second->GetSendStreamID () == receiveStreamID)
{ {
// found // found
@ -944,7 +944,7 @@ namespace stream
m_Owner->GetService ().post([acceptor, this](void) m_Owner->GetService ().post([acceptor, this](void)
{ {
m_Acceptor = acceptor; m_Acceptor = acceptor;
for (auto it: m_PendingIncomingStreams) for (auto& it: m_PendingIncomingStreams)
if (it->GetStatus () == eStreamStatusOpen) // still open? if (it->GetStatus () == eStreamStatusOpen) // still open?
m_Acceptor (it); m_Acceptor (it);
m_PendingIncomingStreams.clear (); m_PendingIncomingStreams.clear ();
@ -963,7 +963,7 @@ namespace stream
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
LogPrint (eLogWarning, "Streaming: Pending incoming timeout expired"); LogPrint (eLogWarning, "Streaming: Pending incoming timeout expired");
for (auto it: m_PendingIncomingStreams) for (auto& it: m_PendingIncomingStreams)
it->Close (); it->Close ();
m_PendingIncomingStreams.clear (); m_PendingIncomingStreams.clear ();
} }

8
TransportSession.h

@ -53,8 +53,8 @@ namespace transport
{ {
public: public:
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router): TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router) m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout)
{ {
if (router) if (router)
m_RemoteIdentity = router->GetRouterIdentity (); m_RemoteIdentity = router->GetRouterIdentity ();
@ -70,6 +70,9 @@ namespace transport
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
bool IsOutgoing () const { return m_IsOutgoing; }; bool IsOutgoing () const { return m_IsOutgoing; };
int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0; virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
protected: protected:
@ -78,6 +81,7 @@ namespace transport
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
size_t m_NumSentBytes, m_NumReceivedBytes; size_t m_NumSentBytes, m_NumReceivedBytes;
bool m_IsOutgoing; bool m_IsOutgoing;
int m_TerminationTimeout;
}; };
} }
} }

12
Transports.cpp

@ -112,7 +112,7 @@ namespace transport
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
// create acceptors // create acceptors
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (auto address : addresses) for (const auto& address : addresses)
{ {
if (m_NTCPServer == nullptr && enableNTCP) if (m_NTCPServer == nullptr && enableNTCP)
{ {
@ -236,7 +236,7 @@ namespace transport
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{ {
// we send it to ourself // we send it to ourself
for (auto it: msgs) for (auto& it: msgs)
i2p::HandleI2NPMessage (it); i2p::HandleI2NPMessage (it);
return; return;
} }
@ -266,7 +266,7 @@ namespace transport
{ {
if (it->second.delayedMessages.size () < MAX_NUM_DELAYED_MESSAGES) if (it->second.delayedMessages.size () < MAX_NUM_DELAYED_MESSAGES)
{ {
for (auto it1: msgs) for (auto& it1: msgs)
it->second.delayedMessages.push_back (it1); it->second.delayedMessages.push_back (it1);
} }
else else
@ -569,6 +569,8 @@ namespace transport
} }
if (sendDatabaseStore) if (sendDatabaseStore)
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); session->SendI2NPMessages ({ CreateDatabaseStoreMsg () });
else
session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds
it->second.sessions.push_back (session); it->second.sessions.push_back (session);
session->SendI2NPMessages (it->second.delayedMessages); session->SendI2NPMessages (it->second.delayedMessages);
it->second.delayedMessages.clear (); it->second.delayedMessages.clear ();
@ -634,7 +636,7 @@ namespace transport
it = m_Peers.erase (it); it = m_Peers.erase (it);
} }
else else
it++; ++it;
} }
UpdateBandwidth (); // TODO: use separate timer(s) for it UpdateBandwidth (); // TODO: use separate timer(s) for it
if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test if (i2p::context.GetStatus () == eRouterStatusTesting) // if still testing, repeat peer test
@ -656,7 +658,7 @@ namespace transport
{ {
std::lock_guard<std::mutex> lock(m_FamilyMutex); std::lock_guard<std::mutex> lock(m_FamilyMutex);
m_TrustedFamilies.clear(); m_TrustedFamilies.clear();
for ( auto fam : families ) for ( const auto& fam : families )
m_TrustedFamilies.push_back(fam); m_TrustedFamilies.push_back(fam);
} }

2
Transports.h

@ -60,7 +60,7 @@ namespace transport
void Done () void Done ()
{ {
for (auto it: sessions) for (auto& it: sessions)
it->Done (); it->Done ();
} }
}; };

332
Tunnel.cpp

@ -13,19 +13,19 @@
#include "Tunnel.h" #include "Tunnel.h"
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config): Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), 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)
{ {
} }
Tunnel::~Tunnel () Tunnel::~Tunnel ()
{ {
} }
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel) void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
@ -33,7 +33,7 @@ namespace tunnel
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
auto msg = NewI2NPShortMessage (); auto msg = NewI2NPShortMessage ();
*msg->GetPayload () = numRecords; *msg->GetPayload () = numRecords;
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1; msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
// shuffle records // shuffle records
std::vector<int> recordIndicies; std::vector<int> recordIndicies;
@ -56,13 +56,13 @@ namespace tunnel
hop->recordIndex = idx; hop->recordIndex = idx;
i++; i++;
hop = hop->next; hop = hop->next;
} }
// fill up fake records with random data // fill up fake records with random data
for (int i = numHops; i < numRecords; i++) for (int i = numHops; i < numRecords; i++)
{ {
int idx = recordIndicies[i]; int idx = recordIndicies[i];
RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE); RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE);
} }
// decrypt real records // decrypt real records
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
@ -73,31 +73,31 @@ namespace tunnel
// decrypt records after current hop // decrypt records after current hop
TunnelHopConfig * hop1 = hop->next; TunnelHopConfig * hop1 = hop->next;
while (hop1) while (hop1)
{ {
decryption.SetIV (hop->replyIV); decryption.SetIV (hop->replyIV);
uint8_t * record = records + hop1->recordIndex*TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = records + hop1->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
hop1 = hop1->next; hop1 = hop1->next;
} }
hop = hop->prev; hop = hop->prev;
} }
msg->FillI2NPMessageHeader (eI2NPVariableTunnelBuild); msg->FillI2NPMessageHeader (eI2NPVariableTunnelBuild);
// send message // send message
if (outboundTunnel) if (outboundTunnel)
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
else else
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
} }
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
{ {
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records."); LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
TunnelHopConfig * hop = m_Config->GetLastHop (); TunnelHopConfig * hop = m_Config->GetLastHop ();
while (hop) while (hop)
{ {
decryption.SetKey (hop->replyKey); decryption.SetKey (hop->replyKey);
// decrypt records before and including current hop // decrypt records before and including current hop
TunnelHopConfig * hop1 = hop; TunnelHopConfig * hop1 = hop;
@ -105,22 +105,22 @@ namespace tunnel
{ {
auto idx = hop1->recordIndex; auto idx = hop1->recordIndex;
if (idx >= 0 && idx < msg[0]) if (idx >= 0 && idx < msg[0])
{ {
uint8_t * record = msg + 1 + idx*TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = msg + 1 + idx*TUNNEL_BUILD_RECORD_SIZE;
decryption.SetIV (hop->replyIV); decryption.SetIV (hop->replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
} }
else else
LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range"); LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range");
hop1 = hop1->prev; hop1 = hop1->prev;
} }
hop = hop->prev; hop = hop->prev;
} }
bool established = true; bool established = true;
hop = m_Config->GetFirstHop (); hop = m_Config->GetFirstHop ();
while (hop) while (hop)
{ {
const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE; const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET]; uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET];
LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret); LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret);
@ -143,12 +143,12 @@ namespace tunnel
tunnelHop->decryption.SetKeys (hop->layerKey, hop->ivKey); tunnelHop->decryption.SetKeys (hop->layerKey, hop->ivKey);
m_Hops.push_back (std::unique_ptr<TunnelHop>(tunnelHop)); m_Hops.push_back (std::unique_ptr<TunnelHop>(tunnelHop));
hop = hop->prev; hop = hop->prev;
} }
m_Config = nullptr; m_Config = nullptr;
} }
if (established) m_State = eTunnelStateEstablished; if (established) m_State = eTunnelStateEstablished;
return established; return established;
} }
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{ {
@ -158,20 +158,20 @@ namespace tunnel
{ {
it->decryption.Decrypt (inPayload, outPayload); it->decryption.Decrypt (inPayload, outPayload);
inPayload = outPayload; inPayload = outPayload;
} }
} }
void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
LogPrint (eLogWarning, "Tunnel: Can't send I2NP messages without delivery instructions"); LogPrint (eLogWarning, "Tunnel: Can't send I2NP messages without delivery instructions");
} }
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetPeers () const std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetPeers () const
{ {
auto peers = GetInvertedPeers (); auto peers = GetInvertedPeers ();
std::reverse (peers.begin (), peers.end ()); std::reverse (peers.begin (), peers.end ());
return peers; return peers;
} }
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetInvertedPeers () const std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetInvertedPeers () const
{ {
@ -179,54 +179,54 @@ namespace tunnel
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > ret; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > ret;
for (auto& it: m_Hops) for (auto& it: m_Hops)
ret.push_back (it->ident); ret.push_back (it->ident);
return ret; return ret;
} }
void Tunnel::PrintHops (std::stringstream& s) const void Tunnel::PrintHops (std::stringstream& s) const
{ {
for (auto& it: m_Hops) for (auto& it: m_Hops)
{ {
s << " "; s << " &#8658; ";
s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ()); s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ());
} }
} }
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg) void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (msg, newMsg); EncryptTunnelMsg (msg, newMsg);
newMsg->from = shared_from_this (); newMsg->from = shared_from_this ();
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
} }
void InboundTunnel::Print (std::stringstream& s) const void InboundTunnel::Print (std::stringstream& s) const
{ {
PrintHops (s); PrintHops (s);
s << " " << GetTunnelID () << ":me"; s << " &#8658; " << GetTunnelID () << ":me";
} }
ZeroHopsInboundTunnel::ZeroHopsInboundTunnel (): ZeroHopsInboundTunnel::ZeroHopsInboundTunnel ():
InboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()), InboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumReceivedBytes (0) m_NumReceivedBytes (0)
{ {
} }
void ZeroHopsInboundTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void ZeroHopsInboundTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {
m_NumReceivedBytes += msg->GetLength (); m_NumReceivedBytes += msg->GetLength ();
msg->from = shared_from_this (); msg->from = shared_from_this ();
HandleI2NPMessage (msg); HandleI2NPMessage (msg);
} }
} }
void ZeroHopsInboundTunnel::Print (std::stringstream& s) const void ZeroHopsInboundTunnel::Print (std::stringstream& s) const
{ {
s << " " << GetTunnelID () << ":me"; s << " &#8658; " << GetTunnelID () << ":me";
} }
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg) void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
@ -234,28 +234,28 @@ namespace tunnel
{ {
block.hash = gwHash; block.hash = gwHash;
if (gwTunnel) if (gwTunnel)
{ {
block.deliveryType = eDeliveryTypeTunnel; block.deliveryType = eDeliveryTypeTunnel;
block.tunnelID = gwTunnel; block.tunnelID = gwTunnel;
} }
else else
block.deliveryType = eDeliveryTypeRouter; block.deliveryType = eDeliveryTypeRouter;
} }
else else
block.deliveryType = eDeliveryTypeLocal; block.deliveryType = eDeliveryTypeLocal;
block.data = msg; block.data = msg;
SendTunnelDataMsg ({block}); SendTunnelDataMsg ({block});
} }
void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs) void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs)
{ {
std::unique_lock<std::mutex> l(m_SendMutex); std::unique_lock<std::mutex> l(m_SendMutex);
for (auto& it : msgs) for (auto& it : msgs)
m_Gateway.PutTunnelDataMsg (it); m_Gateway.PutTunnelDataMsg (it);
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }
void OutboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void OutboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
LogPrint (eLogError, "Tunnel: incoming message for outbound tunnel ", GetTunnelID ()); LogPrint (eLogError, "Tunnel: incoming message for outbound tunnel ", GetTunnelID ());
@ -265,9 +265,9 @@ namespace tunnel
{ {
s << GetTunnelID () << ":me"; s << GetTunnelID () << ":me";
PrintHops (s); PrintHops (s);
s << " "; s << " &#8658; ";
} }
ZeroHopsOutboundTunnel::ZeroHopsOutboundTunnel (): ZeroHopsOutboundTunnel::ZeroHopsOutboundTunnel ():
OutboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()), OutboundTunnel (std::make_shared<ZeroHopsTunnelConfig> ()),
m_NumSentBytes (0) m_NumSentBytes (0)
@ -286,30 +286,30 @@ namespace tunnel
case eDeliveryTypeTunnel: case eDeliveryTypeTunnel:
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
break; break;
case eDeliveryTypeRouter: case eDeliveryTypeRouter:
i2p::transport::transports.SendMessage (msg.hash, msg.data); i2p::transport::transports.SendMessage (msg.hash, msg.data);
break; break;
default: default:
LogPrint (eLogError, "Tunnel: Unknown delivery type ", (int)msg.deliveryType); LogPrint (eLogError, "Tunnel: Unknown delivery type ", (int)msg.deliveryType);
} }
} }
} }
void ZeroHopsOutboundTunnel::Print (std::stringstream& s) const void ZeroHopsOutboundTunnel::Print (std::stringstream& s) const
{ {
s << GetTunnelID () << ":me "; s << GetTunnelID () << ":me &#8658; ";
} }
Tunnels tunnels; Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
m_NumSuccesiveTunnelCreations (0), m_NumFailedTunnelCreations (0) m_NumSuccesiveTunnelCreations (0), m_NumFailedTunnelCreations (0)
{ {
} }
Tunnels::~Tunnels () Tunnels::~Tunnels ()
{ {
} }
std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID) std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID)
{ {
@ -317,35 +317,35 @@ namespace tunnel
if (it != m_Tunnels.end ()) if (it != m_Tunnels.end ())
return it->second; return it->second;
return nullptr; return nullptr;
} }
std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID) std::shared_ptr<InboundTunnel> Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID)
{ {
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels); return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
} }
std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID) std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID)
{ {
return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels); return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels);
} }
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> Tunnels::GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels) std::shared_ptr<TTunnel> Tunnels::GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels)
{ {
auto it = pendingTunnels.find(replyMsgID); auto it = pendingTunnels.find(replyMsgID);
if (it != pendingTunnels.end () && it->second->GetState () == eTunnelStatePending) if (it != pendingTunnels.end () && it->second->GetState () == eTunnelStatePending)
{ {
it->second->SetState (eTunnelStateBuildReplyReceived); it->second->SetState (eTunnelStateBuildReplyReceived);
return it->second; return it->second;
} }
return nullptr; return nullptr;
} }
std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel () std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel ()
{ {
std::shared_ptr<InboundTunnel> tunnel; std::shared_ptr<InboundTunnel> tunnel;
size_t minReceived = 0; size_t minReceived = 0;
for (auto it : m_InboundTunnels) for (const auto& it : m_InboundTunnels)
{ {
if (!it->IsEstablished ()) continue; if (!it->IsEstablished ()) continue;
if (!tunnel || it->GetNumReceivedBytes () < minReceived) if (!tunnel || it->GetNumReceivedBytes () < minReceived)
@ -353,26 +353,26 @@ namespace tunnel
tunnel = it; tunnel = it;
minReceived = it->GetNumReceivedBytes (); minReceived = it->GetNumReceivedBytes ();
} }
} }
return tunnel; return tunnel;
} }
std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel () std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel ()
{ {
if (m_OutboundTunnels.empty ()) return nullptr; if (m_OutboundTunnels.empty ()) return nullptr;
uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0; uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0;
std::shared_ptr<OutboundTunnel> tunnel; std::shared_ptr<OutboundTunnel> tunnel;
for (auto it: m_OutboundTunnels) for (const auto& it: m_OutboundTunnels)
{ {
if (it->IsEstablished ()) if (it->IsEstablished ())
{ {
tunnel = it; tunnel = it;
i++; i++;
} }
if (i > ind && tunnel) break; if (i > ind && tunnel) break;
} }
return tunnel; return tunnel;
} }
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops, std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels) int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
@ -381,19 +381,19 @@ namespace tunnel
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.push_back (pool); m_Pools.push_back (pool);
return pool; return pool;
} }
void Tunnels::DeleteTunnelPool (std::shared_ptr<TunnelPool> pool) void Tunnels::DeleteTunnelPool (std::shared_ptr<TunnelPool> pool)
{ {
if (pool) if (pool)
{ {
StopTunnelPool (pool); StopTunnelPool (pool);
{ {
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.remove (pool); m_Pools.remove (pool);
} }
} }
} }
void Tunnels::StopTunnelPool (std::shared_ptr<TunnelPool> pool) void Tunnels::StopTunnelPool (std::shared_ptr<TunnelPool> pool)
{ {
@ -401,47 +401,47 @@ namespace tunnel
{ {
pool->SetActive (false); pool->SetActive (false);
pool->DetachTunnels (); pool->DetachTunnels ();
} }
} }
void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel) void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
{ {
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second) if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
m_TransitTunnels.push_back (tunnel); m_TransitTunnels.push_back (tunnel);
else else
LogPrint (eLogError, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " already exists"); LogPrint (eLogError, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " already exists");
} }
void Tunnels::Start () void Tunnels::Start ()
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Tunnels::Run, this)); m_Thread = new std::thread (std::bind (&Tunnels::Run, this));
} }
void Tunnels::Stop () void Tunnels::Stop ()
{ {
m_IsRunning = false; m_IsRunning = false;
m_Queue.WakeUp (); m_Queue.WakeUp ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
} }
void Tunnels::Run () void Tunnels::Run ()
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready
uint64_t lastTs = 0; uint64_t lastTs = 0;
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
if (msg) if (msg)
{ {
uint32_t prevTunnelID = 0, tunnelID = 0; uint32_t prevTunnelID = 0, tunnelID = 0;
std::shared_ptr<TunnelBase> prevTunnel; std::shared_ptr<TunnelBase> prevTunnel;
do do
@ -449,16 +449,16 @@ namespace tunnel
std::shared_ptr<TunnelBase> tunnel; std::shared_ptr<TunnelBase> tunnel;
uint8_t typeID = msg->GetTypeID (); uint8_t typeID = msg->GetTypeID ();
switch (typeID) switch (typeID)
{ {
case eI2NPTunnelData: case eI2NPTunnelData:
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
{ {
tunnelID = bufbe32toh (msg->GetPayload ()); tunnelID = bufbe32toh (msg->GetPayload ());
if (tunnelID == prevTunnelID) if (tunnelID == prevTunnelID)
tunnel = prevTunnel; tunnel = prevTunnel;
else if (prevTunnel) else if (prevTunnel)
prevTunnel->FlushTunnelDataMsgs (); prevTunnel->FlushTunnelDataMsgs ();
if (!tunnel) if (!tunnel)
tunnel = GetTunnel (tunnelID); tunnel = GetTunnel (tunnelID);
if (tunnel) if (tunnel)
@ -472,17 +472,17 @@ namespace tunnel
LogPrint (eLogWarning, "Tunnel: tunnel not found, tunnelID=", tunnelID, " previousTunnelID=", prevTunnelID, " type=", (int)typeID); LogPrint (eLogWarning, "Tunnel: tunnel not found, tunnelID=", tunnelID, " previousTunnelID=", prevTunnelID, " type=", (int)typeID);
break; break;
} }
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
break; break;
default: default:
LogPrint (eLogWarning, "Tunnel: unexpected messsage type ", (int) typeID); LogPrint (eLogWarning, "Tunnel: unexpected messsage type ", (int) typeID);
} }
msg = m_Queue.Get (); msg = m_Queue.Get ();
if (msg) if (msg)
{ {
@ -493,8 +493,8 @@ namespace tunnel
tunnel->FlushTunnelDataMsgs (); tunnel->FlushTunnelDataMsgs ();
} }
while (msg); while (msg);
} }
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastTs >= 15) // manage tunnels every 15 seconds if (ts - lastTs >= 15) // manage tunnels every 15 seconds
{ {
@ -505,9 +505,9 @@ namespace tunnel
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Tunnel: runtime exception: ", ex.what ()); LogPrint (eLogError, "Tunnel: runtime exception: ", ex.what ());
} }
} }
} }
void Tunnels::HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg) void Tunnels::HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg)
{ {
@ -528,7 +528,7 @@ namespace tunnel
msg->len = msg->offset + len; msg->len = msg->offset + len;
auto typeID = msg->GetTypeID (); auto typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "Tunnel: gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID); LogPrint (eLogDebug, "Tunnel: gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply) if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
// transit DatabaseStore my contain new/updated RI // transit DatabaseStore my contain new/updated RI
// or DatabaseSearchReply with new routers // or DatabaseSearchReply with new routers
@ -543,7 +543,7 @@ namespace tunnel
ManageOutboundTunnels (); ManageOutboundTunnels ();
ManageTransitTunnels (); ManageTransitTunnels ();
ManageTunnelPools (); ManageTunnelPools ();
} }
void Tunnels::ManagePendingTunnels () void Tunnels::ManagePendingTunnels ()
{ {
@ -557,7 +557,7 @@ namespace tunnel
// check pending tunnel. delete failed or timeout // check pending tunnel. delete failed or timeout
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();) for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
{ {
auto tunnel = it->second; auto tunnel = it->second;
switch (tunnel->GetState ()) switch (tunnel->GetState ())
{ {
@ -579,14 +579,14 @@ namespace tunnel
profile->TunnelNonReplied (); profile->TunnelNonReplied ();
} }
hop = hop->next; hop = hop->next;
} }
} }
// delete // delete
it = pendingTunnels.erase (it); it = pendingTunnels.erase (it);
m_NumFailedTunnelCreations++; m_NumFailedTunnelCreations++;
} }
else else
it++; ++it;
break; break;
case eTunnelStateBuildFailed: case eTunnelStateBuildFailed:
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted"); LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
@ -595,14 +595,14 @@ namespace tunnel
break; break;
case eTunnelStateBuildReplyReceived: case eTunnelStateBuildReplyReceived:
// intermediate state, will be either established of build failed // intermediate state, will be either established of build failed
it++; ++it;
break; break;
default: default:
// success // success
it = pendingTunnels.erase (it); it = pendingTunnels.erase (it);
m_NumSuccesiveTunnelCreations++; m_NumSuccesiveTunnelCreations++;
} }
} }
} }
void Tunnels::ManageOutboundTunnels () void Tunnels::ManageOutboundTunnels ()
@ -620,26 +620,26 @@ namespace tunnel
pool->TunnelExpired (tunnel); pool->TunnelExpired (tunnel);
// we don't have outbound tunnels in m_Tunnels // we don't have outbound tunnels in m_Tunnels
it = m_OutboundTunnels.erase (it); it = m_OutboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished ()) if (tunnel->IsEstablished ())
{ {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{ {
tunnel->SetIsRecreated (); tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool (); auto pool = tunnel->GetTunnelPool ();
if (pool) if (pool)
pool->RecreateOutboundTunnel (tunnel); pool->RecreateOutboundTunnel (tunnel);
} }
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring); tunnel->SetState (eTunnelStateExpiring);
} }
it++; ++it;
} }
} }
} }
if (m_OutboundTunnels.size () < 5) if (m_OutboundTunnels.size () < 5)
{ {
// trying to create one more oubound tunnel // trying to create one more oubound tunnel
@ -648,12 +648,12 @@ namespace tunnel
if (!inboundTunnel || !router) return; if (!inboundTunnel || !router) return;
LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel"); LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel");
CreateTunnel<OutboundTunnel> ( CreateTunnel<OutboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () }, std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () },
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()) inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())
); );
} }
} }
void Tunnels::ManageInboundTunnels () void Tunnels::ManageInboundTunnels ()
{ {
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
@ -669,26 +669,26 @@ namespace tunnel
pool->TunnelExpired (tunnel); pool->TunnelExpired (tunnel);
m_Tunnels.erase (tunnel->GetTunnelID ()); m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_InboundTunnels.erase (it); it = m_InboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished ()) if (tunnel->IsEstablished ())
{ {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{ {
tunnel->SetIsRecreated (); tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool (); auto pool = tunnel->GetTunnelPool ();
if (pool) if (pool)
pool->RecreateInboundTunnel (tunnel); pool->RecreateInboundTunnel (tunnel);
} }
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring); tunnel->SetState (eTunnelStateExpiring);
} }
it++; it++;
} }
} }
} }
if (m_InboundTunnels.empty ()) if (m_InboundTunnels.empty ())
{ {
@ -702,10 +702,10 @@ namespace tunnel
} }
return; return;
} }
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5) if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5)
{ {
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter (); auto router = i2p::data::netdb.GetRandomRouter ();
if (!router) { if (!router) {
LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel"); LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel");
@ -714,9 +714,9 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnel: creating one hop inbound tunnel"); LogPrint (eLogDebug, "Tunnel: creating one hop inbound tunnel");
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () }) std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
); );
} }
} }
void Tunnels::ManageTransitTunnels () void Tunnels::ManageTransitTunnels ()
{ {
@ -729,36 +729,35 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired"); LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
m_Tunnels.erase (tunnel->GetTunnelID ()); m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_TransitTunnels.erase (it); it = m_TransitTunnels.erase (it);
} }
else else
it++; it++;
} }
} }
void Tunnels::ManageTunnelPools () void Tunnels::ManageTunnelPools ()
{ {
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
for (auto it: m_Pools) for (auto& pool : m_Pools)
{ {
auto pool = it;
if (pool && pool->IsActive ()) if (pool && pool->IsActive ())
{ {
pool->CreateTunnels (); pool->CreateTunnels ();
pool->TestTunnels (); pool->TestTunnels ();
} }
} }
} }
void Tunnels::PostTunnelData (std::shared_ptr<I2NPMessage> msg) void Tunnels::PostTunnelData (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) m_Queue.Put (msg); if (msg) m_Queue.Put (msg);
} }
void Tunnels::PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) void Tunnels::PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{ {
m_Queue.Put (msgs); m_Queue.Put (msgs);
} }
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
@ -768,7 +767,7 @@ namespace tunnel
AddPendingTunnel (replyMsgID, newTunnel); AddPendingTunnel (replyMsgID, newTunnel);
newTunnel->Build (replyMsgID, outboundTunnel); newTunnel->Build (replyMsgID, outboundTunnel);
return newTunnel; return newTunnel;
} }
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
@ -805,20 +804,20 @@ namespace tunnel
pool->TunnelCreated (newTunnel); pool->TunnelCreated (newTunnel);
else else
newTunnel->SetTunnelPool (nullptr); newTunnel->SetTunnelPool (nullptr);
} }
void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel) void Tunnels::AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel)
{ {
if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second) if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second)
{ {
m_InboundTunnels.push_back (newTunnel); m_InboundTunnels.push_back (newTunnel);
auto pool = newTunnel->GetTunnelPool (); auto pool = newTunnel->GetTunnelPool ();
if (!pool) if (!pool)
{ {
// build symmetric outbound tunnel // build symmetric outbound tunnel
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (), CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()), newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
GetNextOutboundTunnel ()); GetNextOutboundTunnel ());
} }
else else
{ {
@ -830,9 +829,9 @@ namespace tunnel
} }
else else
LogPrint (eLogError, "Tunnel: tunnel with id ", newTunnel->GetTunnelID (), " already exists"); LogPrint (eLogError, "Tunnel: tunnel with id ", newTunnel->GetTunnelID (), " already exists");
} }
std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel () std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel ()
{ {
auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> (); auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> ();
@ -840,7 +839,7 @@ namespace tunnel
m_InboundTunnels.push_back (inboundTunnel); m_InboundTunnels.push_back (inboundTunnel);
m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel; m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel;
return inboundTunnel; return inboundTunnel;
} }
std::shared_ptr<ZeroHopsOutboundTunnel> Tunnels::CreateZeroHopsOutboundTunnel () std::shared_ptr<ZeroHopsOutboundTunnel> Tunnels::CreateZeroHopsOutboundTunnel ()
{ {
@ -856,11 +855,11 @@ namespace tunnel
int timeout = 0; int timeout = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
// TODO: possible race condition with I2PControl // TODO: possible race condition with I2PControl
for (auto it: m_TransitTunnels) for (const auto& it : m_TransitTunnels)
{ {
int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts;
if (t > timeout) timeout = t; if (t > timeout) timeout = t;
} }
return timeout; return timeout;
} }
@ -883,4 +882,3 @@ namespace tunnel
} }
} }
} }

2
Tunnel.h

@ -224,7 +224,7 @@ namespace tunnel
std::list<std::shared_ptr<TunnelPool>> m_Pools; std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool; std::shared_ptr<TunnelPool> m_ExploratoryPool;
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
// some stats // some stats
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;

2
TunnelConfig.h

@ -213,7 +213,7 @@ namespace tunnel
void CreatePeers (const Peers& peers) void CreatePeers (const Peers& peers)
{ {
TunnelHopConfig * prev = nullptr; TunnelHopConfig * prev = nullptr;
for (auto it: peers) for (const auto& it: peers)
{ {
auto hop = new TunnelHopConfig (it); auto hop = new TunnelHopConfig (it);
if (prev) if (prev)

2
TunnelGateway.cpp

@ -197,7 +197,7 @@ namespace tunnel
{ {
m_Buffer.CompleteCurrentTunnelDataMessage (); m_Buffer.CompleteCurrentTunnelDataMessage ();
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs (); auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto tunnelMsg : tunnelMsgs) for (auto& tunnelMsg : tunnelMsgs)
{ {
m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg); m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg);
tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData); tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData);

29
TunnelPool.cpp

@ -49,13 +49,13 @@ namespace tunnel
{ {
{ {
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
for (auto it: m_InboundTunnels) for (auto& it: m_InboundTunnels)
it->SetTunnelPool (nullptr); it->SetTunnelPool (nullptr);
m_InboundTunnels.clear (); m_InboundTunnels.clear ();
} }
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (auto it: m_OutboundTunnels) for (auto& it: m_OutboundTunnels)
it->SetTunnelPool (nullptr); it->SetTunnelPool (nullptr);
m_OutboundTunnels.clear (); m_OutboundTunnels.clear ();
} }
@ -78,7 +78,7 @@ namespace tunnel
if (expiredTunnel) if (expiredTunnel)
{ {
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto it: m_Tests) for (auto& it: m_Tests)
if (it.second.second == expiredTunnel) it.second.second = nullptr; if (it.second.second == expiredTunnel) it.second.second = nullptr;
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
@ -101,7 +101,7 @@ namespace tunnel
if (expiredTunnel) if (expiredTunnel)
{ {
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto it: m_Tests) for (auto& it: m_Tests)
if (it.second.first == expiredTunnel) it.second.first = nullptr; if (it.second.first == expiredTunnel) it.second.first = nullptr;
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
@ -114,7 +114,7 @@ namespace tunnel
std::vector<std::shared_ptr<InboundTunnel> > v; std::vector<std::shared_ptr<InboundTunnel> > v;
int i = 0; int i = 0;
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
for (auto it : m_InboundTunnels) for (const auto& it : m_InboundTunnels)
{ {
if (i >= num) break; if (i >= num) break;
if (it->IsEstablished ()) if (it->IsEstablished ())
@ -144,7 +144,7 @@ namespace tunnel
if (tunnels.empty ()) return nullptr; if (tunnels.empty ()) return nullptr;
uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0; uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0;
typename TTunnels::value_type tunnel = nullptr; typename TTunnels::value_type tunnel = nullptr;
for (auto it: tunnels) for (const auto& it: tunnels)
{ {
if (it->IsEstablished () && it != excluded) if (it->IsEstablished () && it != excluded)
{ {
@ -164,7 +164,7 @@ namespace tunnel
if (old) if (old)
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (auto it: m_OutboundTunnels) for (const auto& it: m_OutboundTunnels)
if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ()) if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ())
{ {
tunnel = it; tunnel = it;
@ -182,7 +182,7 @@ namespace tunnel
int num = 0; int num = 0;
{ {
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
for (auto it : m_InboundTunnels) for (const auto& it : m_InboundTunnels)
if (it->IsEstablished ()) num++; if (it->IsEstablished ()) num++;
} }
for (int i = num; i < m_NumInboundTunnels; i++) for (int i = num; i < m_NumInboundTunnels; i++)
@ -191,7 +191,7 @@ namespace tunnel
num = 0; num = 0;
{ {
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (auto it : m_OutboundTunnels) for (const auto& it : m_OutboundTunnels)
if (it->IsEstablished ()) num++; if (it->IsEstablished ()) num++;
} }
for (int i = num; i < m_NumOutboundTunnels; i++) for (int i = num; i < m_NumOutboundTunnels; i++)
@ -203,11 +203,10 @@ namespace tunnel
decltype(m_Tests) tests; decltype(m_Tests) tests;
{ {
std::unique_lock<std::mutex> l(m_TestsMutex); std::unique_lock<std::mutex> l(m_TestsMutex);
tests = m_Tests; tests.swap(m_Tests);
m_Tests.clear ();
} }
for (auto it: tests) for (auto& it: tests)
{ {
LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed"); LogPrint (eLogWarning, "Tunnels: test of tunnel ", it.first, " failed");
// if test failed again with another tunnel we consider it failed // if test failed again with another tunnel we consider it failed
@ -248,12 +247,12 @@ namespace tunnel
if ((*it1)->IsFailed ()) if ((*it1)->IsFailed ())
{ {
failed = true; failed = true;
it1++; ++it1;
} }
if ((*it2)->IsFailed ()) if ((*it2)->IsFailed ())
{ {
failed = true; failed = true;
it2++; ++it2;
} }
if (!failed) if (!failed)
{ {
@ -265,7 +264,7 @@ namespace tunnel
} }
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID)); CreateDeliveryStatusMsg (msgID));
it1++; it2++; ++it1; ++it2;
} }
} }
} }

17
UPnP.cpp

@ -49,7 +49,9 @@ namespace transport
m_IsRunning = true; m_IsRunning = true;
LogPrint(eLogInfo, "UPnP: starting"); LogPrint(eLogInfo, "UPnP: starting");
m_Service.post (std::bind (&UPnP::Discover, this)); m_Service.post (std::bind (&UPnP::Discover, this));
std::unique_lock<std::mutex> l(m_StartedMutex);
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this))); m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum
} }
UPnP::~UPnP () UPnP::~UPnP ()
@ -80,7 +82,12 @@ namespace transport
#else #else
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#endif #endif
{
// notify satrting thread
std::unique_lock<std::mutex> l(m_StartedMutex);
m_Started.notify_all ();
}
int r; int r;
r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
if (r == 1) if (r == 1)
@ -115,8 +122,8 @@ namespace transport
void UPnP::PortMapping () void UPnP::PortMapping ()
{ {
auto a = context.GetRouterInfo().GetAddresses(); const auto& a = context.GetRouterInfo().GetAddresses();
for (auto address : a) for (const auto& address : a)
{ {
if (!address->host.is_v6 ()) if (!address->host.is_v6 ())
TryPortMapping (address); TryPortMapping (address);
@ -132,8 +139,8 @@ namespace transport
void UPnP::CloseMapping () void UPnP::CloseMapping ()
{ {
auto a = context.GetRouterInfo().GetAddresses(); const auto& a = context.GetRouterInfo().GetAddresses();
for (auto address : a) for (const auto& address : a)
{ {
if (!address->host.is_v6 ()) if (!address->host.is_v6 ())
CloseMapping (address); CloseMapping (address);

8
UPnP.h

@ -4,6 +4,8 @@
#ifdef USE_UPNP #ifdef USE_UPNP
#include <string> #include <string>
#include <thread> #include <thread>
#include <condition_variable>
#include <mutex>
#include <memory> #include <memory>
#include <miniupnpc/miniwget.h> #include <miniupnpc/miniwget.h>
@ -13,8 +15,6 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "util.h"
namespace i2p namespace i2p
{ {
namespace transport namespace transport
@ -45,8 +45,10 @@ namespace transport
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started;
std::mutex m_StartedMutex;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
struct UPNPUrls m_upnpUrls; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData; struct IGDdatas m_upnpData;

29
Win32/Win32App.cpp

@ -2,6 +2,7 @@
#include <windows.h> #include <windows.h>
#include <shellapi.h> #include <shellapi.h>
#include "../Config.h" #include "../Config.h"
#include "../RouterContext.h"
#include "../version.h" #include "../version.h"
#include "resource.h" #include "resource.h"
#include "Win32App.h" #include "Win32App.h"
@ -15,10 +16,13 @@
#define ID_EXIT 2001 #define ID_EXIT 2001
#define ID_CONSOLE 2002 #define ID_CONSOLE 2002
#define ID_APP 2003 #define ID_APP 2003
#define ID_GRACEFUL_SHUTDOWN 2004
#define ID_TRAY_ICON 2050 #define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1) #define WM_TRAYICON (WM_USER + 1)
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
namespace i2p namespace i2p
{ {
namespace win32 namespace win32
@ -30,6 +34,7 @@ namespace win32
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, NULL, NULL); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, NULL, NULL);
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
@ -82,6 +87,7 @@ namespace win32
case WM_CLOSE: case WM_CLOSE:
{ {
RemoveTrayIcon (hWnd); RemoveTrayIcon (hWnd);
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
PostQuitMessage (0); PostQuitMessage (0);
break; break;
} }
@ -101,6 +107,12 @@ namespace win32
PostMessage (hWnd, WM_CLOSE, 0, 0); PostMessage (hWnd, WM_CLOSE, 0, 0);
return 0; return 0;
} }
case ID_GRACEFUL_SHUTDOWN:
{
i2p::context.SetAcceptsTunnels (false);
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
return 0;
}
case ID_CONSOLE: case ID_CONSOLE:
{ {
char buf[30]; char buf[30];
@ -167,6 +179,15 @@ namespace win32
} }
break; break;
} }
case WM_TIMER:
{
if (wParam == IDT_GRACEFUL_SHUTDOWN_TIMER)
{
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
return 0;
}
break;
}
} }
return DefWindowProc( hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam);
} }
@ -218,5 +239,13 @@ namespace win32
{ {
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
} }
bool GracefulShutdown ()
{
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0);
return hWnd;
}
} }
} }

1
Win32/Win32App.h

@ -10,6 +10,7 @@ namespace win32
bool StartWin32App (); bool StartWin32App ();
void StopWin32App (); void StopWin32App ();
int RunWin32App (); int RunWin32App ();
bool GracefulShutdown ();
} }
} }
#endif // WIN32APP_H__ #endif // WIN32APP_H__

5
debian/patches/01-tune-build-opts.patch vendored

@ -1,14 +1,15 @@
diff --git a/Makefile b/Makefile diff --git a/Makefile b/Makefile
index fe8ae7e..fc8abda 100644 index 7d04ba0..33ee184 100644
--- a/Makefile --- a/Makefile
+++ b/Makefile +++ b/Makefile
@@ -9,9 +9,9 @@ DEPS := obj/make.dep @@ -9,10 +9,10 @@ DEPS := obj/make.dep
include filelist.mk include filelist.mk
-USE_AESNI := yes -USE_AESNI := yes
+USE_AESNI := no +USE_AESNI := no
USE_STATIC := no USE_STATIC := no
USE_MESHNET := no
-USE_UPNP := no -USE_UPNP := no
+USE_UPNP := yes +USE_UPNP := yes

39
docs/build_notes_android.md

@ -1,6 +1,8 @@
Building on Android Building on Android
=================== ===================
There are two versions: with QT and without QT.
Pre-requesties Pre-requesties
-------------- --------------
@ -8,12 +10,12 @@ You need to install Android SDK, NDK and QT with android support.
- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only) - [SDK](https://developer.android.com/studio/index.html) (choose command line tools only)
- [NDK](https://developer.android.com/ndk/downloads/index.html) - [NDK](https://developer.android.com/ndk/downloads/index.html)
- [QT](https://www.qt.io/download-open-source/). Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run ) - [QT](https://www.qt.io/download-open-source/)(for QT only). Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run )
You also need Java JDK and Ant. You also need Java JDK and Ant.
QT-Creator QT-Creator (for QT only)
---------- ------------------------
Open QT-creator that should be installed with QT. Open QT-creator that should be installed with QT.
Go to Settings/Anndroid and specify correct paths to SDK and NDK. Go to Settings/Anndroid and specify correct paths to SDK and NDK.
If everything is correct you will see two set avaiable: If everything is correct you will see two set avaiable:
@ -30,11 +32,26 @@ git clone https://github.com/PurpleI2P/android-ifaddrs.git
``` ```
Building the app Building the app with QT
---------------- ------------------------
- Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. - Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator
- Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. - Change line MAIN_PATH = /path/to/libraries to an actual path where you put the dependancies to
- Select appropriate project (usually armeabi-v7a) and build. - Select appropriate project (usually armeabi-v7a) and build
- You will find an .apk file in android-build/bin folder. - You will find an .apk file in android-build/bin folder
Building the app without QT
---------------------------
- Change line I2PD_LIBS_PATH in android/jni/Application.mk to an actual path where you put the dependancies to
- Run 'ndk-build -j4' from andorid folder
- Create or edit file 'local.properties'. Place 'sdk.dir=<path to SDK>' and 'ndk.dir=<path to NDK>'
- Run 'ant clean debug'
Creating release .apk
----------------------
In order to create release .apk you must obtain a Java keystore file(.jks). Either you have in already, or you can generate it yourself using keytool, or from one of you existing well-know ceritificates. For example, i2pd release are signed with this [certificate](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/certificates/router/orignal_at_mail.i2p.crt).
Create file 'ant.propeties'
key.store='path to keystore file'
key.alias='alias name'
key.store.password='keystore password'
key.alias.password='alias password'
Run 'ant clean release'

2
docs/build_notes_unix.md

@ -23,7 +23,7 @@ After successfull build i2pd could be installed with:
```bash ```bash
make install make install
``` ```
or you can just use 'make' once you have all dependacies (boost and openssl) installed or you can just use 'make' once you have all dependencies (boost and openssl) installed
```bash ```bash
git clone https://github.com/PurpleI2P/i2pd.git git clone https://github.com/PurpleI2P/i2pd.git

10
docs/build_notes_windows.md

@ -161,15 +161,17 @@ support for this. Unpack client source code in a sibling folder,
e.g. C:\dev\miniupnpc . You may want to remove version number from e.g. C:\dev\miniupnpc . You may want to remove version number from
folder name included in downloaded archive. folder name included in downloaded archive.
Note that you might need to build DLL yourself for 64-bit systems
using msys2 as 64-bit DLLs are not provided by the project.
You can also install it through the MSYS2 You can also install it through the MSYS2
and build with USE_UPNP key. and build with USE_UPNP key.
```bash ```bash
pacman -S mingw-w64-i686-miniupnpc pacman -S mingw-w64-i686-miniupnpc
make USE_UPNP=1 make USE_UPNP=yes
```
or
```bash
pacman -S mingw-x86_64-miniupnpc
make USE_UPNP=yes
``` ```
### Creating Visual Studio project ### Creating Visual Studio project

4
docs/configuration.md

@ -70,7 +70,9 @@ All options below still possible in cmdline, but better write it in config file:
* --upnp.enabled= - Enable or disable UPnP, false by default for CLI and true for GUI (Windows, Android) * --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 * --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default
* --precomputation.elgamal= - Use ElGamal precomputated tables. false for x64 and true for other platforms by default * --precomputation.elgamal= - Use ElGamal precomputated tables. false for x64 and true for other platforms by default
* --reseed.file - Full path to SU3 file to reseed from
* --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default * --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default
@ -109,7 +111,7 @@ tunnels.conf:
# * keys -- our identity, if unset, will be generated on every startup, # * keys -- our identity, if unset, will be generated on every startup,
# if set and file missing, keys will be generated and placed to this file # if set and file missing, keys will be generated and placed to this file
# * address -- local interface to bind # * address -- local interface to bind
# * signaturetype -- signature type for new destination. 0,1 or 7 # * signaturetype -- signature type for new destination. 0 (DSA/SHA1), 1 (EcDSA/SHA256) or 7 (EdDSA/SHA512)
[IRC] [IRC]
type = client type = client
address = 127.0.0.1 address = 127.0.0.1

4
filelist.mk

@ -5,7 +5,7 @@ LIB_SRC = \
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \ Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
util.cpp api.cpp Config.cpp util.cpp api.cpp
LIB_CLIENT_SRC = \ LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \
@ -13,5 +13,5 @@ LIB_CLIENT_SRC = \
# also: Daemon{Linux,Win32}.cpp will be added later # also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = \ DAEMON_SRC = \
HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp Config.cpp i2pd.cpp HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp

159
util.cpp

@ -1,12 +1,7 @@
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <algorithm>
#include <cctype>
#include <functional>
#include <fstream>
#include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
@ -60,158 +55,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
namespace http
{
std::string GetHttpContent (std::istream& response)
{
std::string version, statusMessage;
response >> version; // HTTP version
int status;
response >> status; // status
std::getline (response, statusMessage);
if (status == 200) // OK
{
bool isChunked = false;
std::string header;
while (!response.eof () && header != "\r")
{
std::getline(response, header);
auto colon = header.find (':');
if (colon != std::string::npos)
{
std::string field = header.substr (0, colon);
std::transform(field.begin(), field.end(), field.begin(), ::tolower);
if (field == i2p::util::http::TRANSFER_ENCODING)
isChunked = (header.find ("chunked", colon + 1) != std::string::npos);
}
}
std::stringstream ss;
if (isChunked)
MergeChunkedResponse (response, ss);
else
ss << response.rdbuf();
return ss.str();
}
else
{
LogPrint (eLogError, "HTTPClient: error, server responds ", status);
return "";
}
}
void MergeChunkedResponse (std::istream& response, std::ostream& merged)
{
while (!response.eof ())
{
std::string hexLen;
size_t len;
std::getline (response, hexLen);
std::istringstream iss (hexLen);
iss >> std::hex >> len;
if (!len || len > 10000000L) // 10M
{
LogPrint (eLogError, "Unexpected chunk length ", len);
break;
}
char * buf = new char[len];
response.read (buf, len);
merged.write (buf, len);
delete[] buf;
std::getline (response, hexLen); // read \r\n after chunk
}
}
url::url(const std::string& url_s)
{
portstr_ = "80";
port_ = 80;
user_ = "";
pass_ = "";
parse(url_s);
}
// code for parser tests
//{
// i2p::util::http::url u_0("http://127.0.0.1:7070/asdasd?qqqqqqqqqqqq");
// i2p::util::http::url u_1("http://user:password@site.com:8080/asdasd?qqqqqqqqqqqqq");
// i2p::util::http::url u_2("http://user:password@site.com/asdasd?qqqqqqqqqqqqqq");
// i2p::util::http::url u_3("http://user:@site.com/asdasd?qqqqqqqqqqqqq");
// i2p::util::http::url u_4("http://user@site.com/asdasd?qqqqqqqqqqqq");
// i2p::util::http::url u_5("http://@site.com:800/asdasd?qqqqqqqqqqqq");
// i2p::util::http::url u_6("http://@site.com:err_port/asdasd?qqqqqqqqqqqq");
// i2p::util::http::url u_7("http://user:password@site.com:err_port/asdasd?qqqqqqqqqqqq");
//}
void url::parse(const std::string& url_s)
{
const std::string prot_end("://");
std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(),
prot_end.begin(), prot_end.end());
protocol_.reserve(distance(url_s.begin(), prot_i));
transform(url_s.begin(), prot_i,
back_inserter(protocol_),
std::ptr_fun<int,int>(tolower)); // protocol is icase
if( prot_i == url_s.end() )
return;
advance(prot_i, prot_end.length());
std::string::const_iterator path_i = find(prot_i, url_s.end(), '/');
host_.reserve(distance(prot_i, path_i));
transform(prot_i, path_i,
back_inserter(host_),
std::ptr_fun<int,int>(tolower)); // host is icase
// parse user/password
auto user_pass_i = find(host_.begin(), host_.end(), '@');
if (user_pass_i != host_.end())
{
std::string user_pass = std::string(host_.begin(), user_pass_i);
auto pass_i = find(user_pass.begin(), user_pass.end(), ':');
if (pass_i != user_pass.end())
{
user_ = std::string(user_pass.begin(), pass_i);
pass_ = std::string(pass_i + 1, user_pass.end());
}
else
user_ = user_pass;
host_.assign(user_pass_i + 1, host_.end());
}
// parse port
auto port_i = find(host_.begin(), host_.end(), ':');
if (port_i != host_.end())
{
portstr_ = std::string(port_i + 1, host_.end());
host_.assign(host_.begin(), port_i);
try{
port_ = boost::lexical_cast<decltype(port_)>(portstr_);
}
catch (std::exception e) {
port_ = 80;
}
}
std::string::const_iterator query_i = find(path_i, url_s.end(), '?');
path_.assign(path_i, query_i);
if( query_i != url_s.end() )
++query_i;
query_.assign(query_i, url_s.end());
}
std::string urlDecode(const std::string& data)
{
std::string res(data);
for (size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%',pos+1))
{
char c = strtol(res.substr(pos+1,2).c_str(), NULL, 16);
res.replace(pos,3,1,c);
}
return res;
}
}
namespace net namespace net
{ {
#ifdef WIN32 #ifdef WIN32

29
util.h

@ -22,7 +22,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
/** /**
wrapper arround boost::lexical_cast that "never" fails wrapper arround boost::lexical_cast that "never" fails
*/ */
@ -34,34 +33,6 @@ namespace util
return fallback; return fallback;
} }
} }
namespace http
{
// in (lower case)
const char ETAG[] = "etag"; // ETag
const char LAST_MODIFIED[] = "last-modified"; // Last-Modified
const char TRANSFER_ENCODING[] = "transfer-encoding"; // Transfer-Encoding
const char CONTENT_ENCODING[] = "content-encoding"; // Content-Encoding
// out
const char IF_NONE_MATCH[] = "If-None-Match";
const char IF_MODIFIED_SINCE[] = "If-Modified-Since";
std::string GetHttpContent (std::istream& response);
void MergeChunkedResponse (std::istream& response, std::ostream& merged);
std::string urlDecode(const std::string& data);
struct url {
url(const std::string& url_s); // omitted copy, ==, accessors, ...
private:
void parse(const std::string& url_s);
public:
std::string protocol_, host_, path_, query_;
std::string portstr_;
unsigned int port_;
std::string user_;
std::string pass_;
};
}
namespace net namespace net
{ {

2
version.h

@ -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 8 #define I2PD_VERSION_MINOR 9
#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…
Cancel
Save