Browse Source

add initial connection timeout for i2ptunnel

pull/940/head
Jeff Becker 7 years ago
parent
commit
1ea6d2016d
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
  1. 328
      libi2pd/Destination.cpp
  2. 25
      libi2pd_client/ClientContext.cpp
  3. 1
      libi2pd_client/ClientContext.h
  4. 134
      libi2pd_client/I2PService.cpp
  5. 24
      libi2pd_client/I2PService.h
  6. 194
      libi2pd_client/I2PTunnel.cpp

328
libi2pd/Destination.cpp

@ -13,8 +13,8 @@ namespace i2p
namespace client namespace client
{ {
LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params): LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params):
m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic), m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic),
m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service),
m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service) m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service)
{ {
int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
@ -83,77 +83,77 @@ namespace client
LeaseSetDestination::~LeaseSetDestination () LeaseSetDestination::~LeaseSetDestination ()
{ {
if (m_IsRunning) if (m_IsRunning)
Stop (); Stop ();
if (m_Pool) if (m_Pool)
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
for (auto& it: m_LeaseSetRequests) for (auto& it: m_LeaseSetRequests)
it.second->Complete (nullptr); it.second->Complete (nullptr);
} }
void LeaseSetDestination::Run () void LeaseSetDestination::Run ()
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
m_Service.run (); m_Service.run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Destination: runtime exception: ", ex.what ()); LogPrint (eLogError, "Destination: runtime exception: ", ex.what ());
} }
} }
} }
bool LeaseSetDestination::Start () bool LeaseSetDestination::Start ()
{ {
if (!m_IsRunning) if (!m_IsRunning)
{ {
LoadTags (); LoadTags ();
m_IsRunning = true; m_IsRunning = true;
m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetLocalDestination (shared_from_this ());
m_Pool->SetActive (true); m_Pool->SetActive (true);
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ()));
return true; return true;
} }
else else
return false; return false;
} }
bool LeaseSetDestination::Stop () bool LeaseSetDestination::Stop ()
{ {
if (m_IsRunning) if (m_IsRunning)
{ {
m_CleanupTimer.cancel (); m_CleanupTimer.cancel ();
m_PublishConfirmationTimer.cancel (); m_PublishConfirmationTimer.cancel ();
m_PublishVerificationTimer.cancel (); m_PublishVerificationTimer.cancel ();
m_IsRunning = false; m_IsRunning = false;
if (m_Pool) if (m_Pool)
{ {
m_Pool->SetLocalDestination (nullptr); m_Pool->SetLocalDestination (nullptr);
i2p::tunnel::tunnels.StopTunnelPool (m_Pool); i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
} }
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
SaveTags (); SaveTags ();
CleanUp (); // GarlicDestination CleanUp (); // GarlicDestination
return true; return true;
} }
else else
return false; return false;
} }
std::shared_ptr<const i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) std::shared_ptr<const i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
{ {
std::shared_ptr<i2p::data::LeaseSet> remoteLS; std::shared_ptr<i2p::data::LeaseSet> remoteLS;
@ -164,7 +164,7 @@ namespace client
remoteLS = it->second; remoteLS = it->second;
} }
if (remoteLS) if (remoteLS)
{ {
if (!remoteLS->IsExpired ()) if (!remoteLS->IsExpired ())
{ {
@ -193,9 +193,9 @@ namespace client
m_RemoteLeaseSets.erase (ident); m_RemoteLeaseSets.erase (ident);
return nullptr; return nullptr;
} }
} }
else else
{ {
auto ls = i2p::data::netdb.FindLeaseSet (ident); auto ls = i2p::data::netdb.FindLeaseSet (ident);
if (ls && !ls->IsExpired ()) if (ls && !ls->IsExpired ())
{ {
@ -203,7 +203,7 @@ namespace client
std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex); std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ident] = ls; m_RemoteLeaseSets[ident] = ls;
return ls; return ls;
} }
} }
return nullptr; return nullptr;
} }
@ -215,11 +215,11 @@ namespace client
UpdateLeaseSet (); UpdateLeaseSet ();
std::lock_guard<std::mutex> l(m_LeaseSetMutex); std::lock_guard<std::mutex> l(m_LeaseSetMutex);
return m_LeaseSet; return m_LeaseSet;
} }
void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet) void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet)
{ {
{ {
std::lock_guard<std::mutex> l(m_LeaseSetMutex); std::lock_guard<std::mutex> l(m_LeaseSetMutex);
m_LeaseSet.reset (newLeaseSet); m_LeaseSet.reset (newLeaseSet);
} }
@ -229,21 +229,21 @@ namespace client
m_PublishVerificationTimer.cancel (); m_PublishVerificationTimer.cancel ();
Publish (); Publish ();
} }
} }
void LeaseSetDestination::UpdateLeaseSet () void LeaseSetDestination::UpdateLeaseSet ()
{ {
int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels
if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum
CreateNewLeaseSet (m_Pool->GetInboundTunnels (numTunnels)); CreateNewLeaseSet (m_Pool->GetInboundTunnels (numTunnels));
} }
bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
struct struct
{ {
uint8_t k[32], t[32]; uint8_t k[32], t[32];
} data; } data;
memcpy (data.k, key, 32); memcpy (data.k, key, 32);
memcpy (data.t, tag, 32); memcpy (data.t, tag, 32);
auto s = shared_from_this (); auto s = shared_from_this ();
@ -256,42 +256,42 @@ namespace client
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
} }
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg));
} }
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET];
switch (typeID) switch (typeID)
{ {
case eI2NPData: case eI2NPData:
HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
break; break;
case eI2NPDeliveryStatus: case eI2NPDeliveryStatus:
// we assume tunnel tests non-encrypted // we assume tunnel tests non-encrypted
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
break; break;
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
break; break;
case eI2NPDatabaseSearchReply: case eI2NPDatabaseSearchReply:
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
break; break;
default: default:
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
} }
} }
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
{ {
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
size_t offset = DATABASE_STORE_HEADER_SIZE; size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken) if (replyToken)
{ {
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore"); LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
offset += 36; offset += 36;
@ -307,8 +307,8 @@ namespace client
{ {
leaseSet = it->second; leaseSet = it->second;
if (leaseSet->IsNewer (buf + offset, len - offset)) if (leaseSet->IsNewer (buf + offset, len - offset))
{ {
leaseSet->Update (buf + offset, len - offset); leaseSet->Update (buf + offset, len - offset);
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key)
LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); LogPrint (eLogDebug, "Destination: Remote LeaseSet updated");
else else
@ -322,7 +322,7 @@ namespace client
LogPrint (eLogDebug, "Destination: Remote LeaseSet is older. Not updated"); LogPrint (eLogDebug, "Destination: Remote LeaseSet is older. Not updated");
} }
else else
{ {
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset); leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset);
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key)
{ {
@ -339,18 +339,18 @@ namespace client
LogPrint (eLogError, "Destination: New remote LeaseSet failed"); LogPrint (eLogError, "Destination: New remote LeaseSet failed");
leaseSet = nullptr; leaseSet = nullptr;
} }
} }
} }
else else
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped"); LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
auto it1 = m_LeaseSetRequests.find (key); auto it1 = m_LeaseSetRequests.find (key);
if (it1 != m_LeaseSetRequests.end ()) if (it1 != m_LeaseSetRequests.end ())
{ {
it1->second->requestTimeoutTimer.cancel (); it1->second->requestTimeoutTimer.cancel ();
if (it1->second) it1->second->Complete (leaseSet); if (it1->second) it1->second->Complete (leaseSet);
m_LeaseSetRequests.erase (it1); m_LeaseSetRequests.erase (it1);
} }
} }
void LeaseSetDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len) void LeaseSetDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len)
@ -364,7 +364,7 @@ namespace client
auto request = it->second; auto request = it->second;
bool found = false; bool found = false;
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
{ {
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
i2p::data::IdentHash peerHash (buf + 33 + i*32); i2p::data::IdentHash peerHash (buf + 33 + i*32);
@ -372,28 +372,28 @@ namespace client
{ {
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
i2p::data::netdb.RequestDestination (peerHash); i2p::data::netdb.RequestDestination (peerHash);
} }
} }
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
if (floodfill) if (floodfill)
{ {
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ()); LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
if (SendLeaseSetRequest (key, floodfill, request)) if (SendLeaseSetRequest (key, floodfill, request))
found = true; found = true;
} }
} }
if (!found) if (!found)
{ {
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills"); LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
request->Complete (nullptr); request->Complete (nullptr);
m_LeaseSetRequests.erase (key); m_LeaseSetRequests.erase (key);
} }
} }
else else
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
} }
void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
@ -405,20 +405,20 @@ namespace client
// schedule verification // schedule verification
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
else else
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
} }
void LeaseSetDestination::SetLeaseSetUpdated () void LeaseSetDestination::SetLeaseSetUpdated ()
{ {
UpdateLeaseSet (); UpdateLeaseSet ();
} }
void LeaseSetDestination::Publish () void LeaseSetDestination::Publish ()
{ {
if (!m_LeaseSet || !m_Pool) if (!m_LeaseSet || !m_Pool)
{ {
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet"); LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
return; return;
@ -435,9 +435,9 @@ namespace client
m_PublishDelayTimer.cancel (); m_PublishDelayTimer.cancel ();
m_PublishDelayTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_MIN_INTERVAL)); m_PublishDelayTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_MIN_INTERVAL));
m_PublishDelayTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishDelayTimer, m_PublishDelayTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishDelayTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
return; return;
} }
auto outbound = m_Pool->GetNextOutboundTunnel (); auto outbound = m_Pool->GetNextOutboundTunnel ();
if (!outbound) if (!outbound)
{ {
@ -450,28 +450,28 @@ namespace client
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels"); LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
return; return;
} }
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills); auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (!floodfill) if (!floodfill)
{ {
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found"); LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
m_ExcludedFloodfills.clear (); m_ExcludedFloodfills.clear ();
return; return;
} }
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound)); auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound));
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
m_LastSubmissionTime = ts; m_LastSubmissionTime = ts;
} }
void LeaseSetDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode) void LeaseSetDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
if (m_PublishReplyToken) if (m_PublishReplyToken)
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again"); LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
@ -484,25 +484,25 @@ namespace client
void LeaseSetDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode) void LeaseSetDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
RequestLeaseSet (GetIdentHash (), RequestLeaseSet (GetIdentHash (),
// "this" added due to bug in gcc 4.7-4.8 // "this" added due to bug in gcc 4.7-4.8
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet) [s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{ {
if (leaseSet) if (leaseSet)
{ {
if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet) if (s->m_LeaseSet && *s->m_LeaseSet == *leaseSet)
{ {
// we got latest LeasetSet // we got latest LeasetSet
LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32()); LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", GetIdentHash().ToBase32());
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
return; return;
} }
else else
LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", GetIdentHash().ToBase32()); LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", GetIdentHash().ToBase32());
} }
else else
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32()); LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", GetIdentHash().ToBase32());
// we have to publish again // we have to publish again
@ -515,16 +515,16 @@ namespace client
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Publish (); Publish ();
} }
bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
{ {
if (!m_Pool || !IsReady ()) if (!m_Pool || !IsReady ())
{ {
if (requestComplete) if (requestComplete)
m_Service.post ([requestComplete](void){requestComplete (nullptr);}); 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;
} }
@ -536,14 +536,14 @@ namespace client
{ {
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; auto requestComplete = it->second;
s->m_LeaseSetRequests.erase (it); s->m_LeaseSetRequests.erase (it);
if (notify && requestComplete) requestComplete->Complete (nullptr); if (notify && requestComplete) requestComplete->Complete (nullptr);
} }
}); });
} }
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete) void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
{ {
std::set<i2p::data::IdentHash> excluded; std::set<i2p::data::IdentHash> excluded;
@ -564,28 +564,28 @@ namespace client
m_LeaseSetRequests.erase (ret.first); m_LeaseSetRequests.erase (ret.first);
if (requestComplete) requestComplete (nullptr); if (requestComplete) requestComplete (nullptr);
} }
} }
else // duplicate else // duplicate
{ {
LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
{ {
// something went wrong // something went wrong
m_LeaseSetRequests.erase (ret.first); m_LeaseSetRequests.erase (ret.first);
if (requestComplete) requestComplete (nullptr); if (requestComplete) requestComplete (nullptr);
} }
else if (requestComplete) else if (requestComplete)
ret.first->second->requestComplete.push_back (requestComplete); ret.first->second->requestComplete.push_back (requestComplete);
} }
} }
else else
{ {
LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found"); LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found");
if (requestComplete) requestComplete (nullptr); if (requestComplete) requestComplete (nullptr);
} }
} }
bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request) std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{ {
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ()) if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
@ -594,36 +594,36 @@ namespace client
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ()) if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
request->outboundTunnel = m_Pool->GetNextOutboundTunnel (); request->outboundTunnel = m_Pool->GetNextOutboundTunnel ();
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found"); if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
if (request->replyTunnel && request->outboundTunnel) if (request->replyTunnel && request->outboundTunnel)
{ {
request->excluded.insert (nextFloodfill->GetIdentHash ()); request->excluded.insert (nextFloodfill->GetIdentHash ());
request->requestTimeoutTimer.cancel (); request->requestTimeoutTimer.cancel ();
uint8_t replyKey[32], replyTag[32]; uint8_t replyKey[32], replyTag[32];
RAND_bytes (replyKey, 32); // random session key RAND_bytes (replyKey, 32); // random session key
RAND_bytes (replyTag, 32); // random session tag RAND_bytes (replyTag, 32); // random session tag
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
auto msg = WrapMessage (nextFloodfill, auto msg = WrapMessage (nextFloodfill,
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, CreateLeaseSetDatabaseLookupMsg (dest, request->excluded,
request->replyTunnel, replyKey, replyTag)); request->replyTunnel, replyKey, replyTag));
request->outboundTunnel->SendTunnelDataMsg ( request->outboundTunnel->SendTunnelDataMsg (
{ {
i2p::tunnel::TunnelMessageBlock i2p::tunnel::TunnelMessageBlock
{ {
i2p::tunnel::eDeliveryTypeRouter, i2p::tunnel::eDeliveryTypeRouter,
nextFloodfill->GetIdentHash (), 0, msg nextFloodfill->GetIdentHash (), 0, msg
} }
}); });
request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT));
request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer, request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer,
shared_from_this (), std::placeholders::_1, dest)); shared_from_this (), std::placeholders::_1, dest));
} }
else else
return false; return false;
return true; return true;
} }
void LeaseSetDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest) void LeaseSetDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest)
{ {
@ -641,26 +641,26 @@ namespace client
{ {
// reset tunnels, because one them might fail // reset tunnels, because one them might fail
it->second->outboundTunnel = nullptr; it->second->outboundTunnel = nullptr;
it->second->replyTunnel = nullptr; it->second->replyTunnel = nullptr;
done = !SendLeaseSetRequest (dest, floodfill, it->second); done = !SendLeaseSetRequest (dest, floodfill, it->second);
} }
else else
done = true; done = true;
} }
else else
{ {
LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds"); LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
done = true; done = true;
} }
if (done) if (done)
{ {
auto requestComplete = it->second; auto requestComplete = it->second;
m_LeaseSetRequests.erase (it); m_LeaseSetRequests.erase (it);
if (requestComplete) requestComplete->Complete (nullptr); if (requestComplete) requestComplete->Complete (nullptr);
} }
} }
} }
} }
void LeaseSetDestination::HandleCleanupTimer (const boost::system::error_code& ecode) void LeaseSetDestination::HandleCleanupTimer (const boost::system::error_code& ecode)
@ -674,7 +674,7 @@ namespace client
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
void LeaseSetDestination::CleanupRemoteLeaseSets () void LeaseSetDestination::CleanupRemoteLeaseSets ()
{ {
@ -686,43 +686,43 @@ namespace client
{ {
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
it = m_RemoteLeaseSets.erase (it); it = m_RemoteLeaseSets.erase (it);
} }
else else
++it; ++it;
} }
} }
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params): ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (isPublic, params), LeaseSetDestination (isPublic, params),
m_Keys (keys), m_DatagramDestination (nullptr), m_RefCounter (0), m_Keys (keys), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(GetService()) m_ReadyChecker(GetService())
{ {
if (isPublic) if (isPublic)
PersistTemporaryKeys (); PersistTemporaryKeys ();
else else
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
if (isPublic) if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
} }
ClientDestination::~ClientDestination () ClientDestination::~ClientDestination ()
{ {
} }
bool ClientDestination::Start () bool ClientDestination::Start ()
{ {
if (LeaseSetDestination::Start ()) if (LeaseSetDestination::Start ())
{ {
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;
} }
else else
return false; return false;
} }
bool ClientDestination::Stop () bool ClientDestination::Stop ()
{ {
if (LeaseSetDestination::Stop ()) if (LeaseSetDestination::Stop ())
@ -732,21 +732,21 @@ namespace client
//m_StreamingDestination->SetOwner (nullptr); //m_StreamingDestination->SetOwner (nullptr);
m_StreamingDestination = nullptr; m_StreamingDestination = nullptr;
for (auto& it: m_StreamingDestinationsByPorts) for (auto& it: m_StreamingDestinationsByPorts)
{ {
it.second->Stop (); it.second->Stop ();
//it.second->SetOwner (nullptr); //it.second->SetOwner (nullptr);
} }
m_StreamingDestinationsByPorts.clear (); m_StreamingDestinationsByPorts.clear ();
if (m_DatagramDestination) if (m_DatagramDestination)
{ {
delete m_DatagramDestination; delete m_DatagramDestination;
m_DatagramDestination = nullptr; m_DatagramDestination = nullptr;
} }
return true; return true;
} }
else else
return false; return false;
} }
#ifdef I2LUA #ifdef I2LUA
void ClientDestination::Ready(ReadyPromise & p) void ClientDestination::Ready(ReadyPromise & p)
@ -773,14 +773,14 @@ namespace client
ScheduleCheckForReady(p); ScheduleCheckForReady(p);
} }
#endif #endif
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
{ {
uint32_t length = bufbe32toh (buf); uint32_t length = bufbe32toh (buf);
buf += 4; buf += 4;
// we assume I2CP payload // we assume I2CP payload
uint16_t fromPort = bufbe16toh (buf + 4), // source uint16_t fromPort = bufbe16toh (buf + 4), // source
toPort = bufbe16toh (buf + 6); // destination toPort = bufbe16toh (buf + 6); // destination
switch (buf[9]) switch (buf[9])
{ {
case PROTOCOL_TYPE_STREAMING: case PROTOCOL_TYPE_STREAMING:
@ -804,14 +804,14 @@ namespace client
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
} }
} }
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
{ {
if (!streamRequestComplete) if (!streamRequestComplete)
{ {
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
return; return;
} }
auto leaseSet = FindLeaseSet (dest); auto leaseSet = FindLeaseSet (dest);
if (leaseSet) if (leaseSet)
streamRequestComplete(CreateStream (leaseSet, port)); streamRequestComplete(CreateStream (leaseSet, port));
@ -837,18 +837,18 @@ namespace client
return nullptr; return nullptr;
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{ {
if (port) if (port)
{ {
auto it = m_StreamingDestinationsByPorts.find (port); auto it = m_StreamingDestinationsByPorts.find (port);
if (it != m_StreamingDestinationsByPorts.end ()) if (it != m_StreamingDestinationsByPorts.end ())
return it->second; return it->second;
} }
// if port is zero or not found, use default destination // if port is zero or not found, use default destination
return m_StreamingDestination; return m_StreamingDestination;
} }
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
@ -860,35 +860,35 @@ namespace client
if (m_StreamingDestination) if (m_StreamingDestination)
m_StreamingDestination->ResetAcceptor (); m_StreamingDestination->ResetAcceptor ();
} }
bool ClientDestination::IsAcceptingStreams () const bool ClientDestination::IsAcceptingStreams () const
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
return m_StreamingDestination->IsAcceptorSet (); return m_StreamingDestination->IsAcceptorSet ();
return false; return false;
} }
void ClientDestination::AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor) void ClientDestination::AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
m_StreamingDestination->AcceptOnce (acceptor); m_StreamingDestination->AcceptOnce (acceptor);
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip) std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
{ {
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip); auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
if (port) if (port)
m_StreamingDestinationsByPorts[port] = dest; m_StreamingDestinationsByPorts[port] = dest;
else // update default else // update default
m_StreamingDestination = dest; m_StreamingDestination = dest;
return dest; return dest;
} }
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination ()
{ {
if (m_DatagramDestination == nullptr) if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ()); m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ());
return m_DatagramDestination; return m_DatagramDestination;
} }
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
@ -898,12 +898,12 @@ namespace client
{ {
for (auto& it: m_StreamingDestination->GetStreams ()) for (auto& it: m_StreamingDestination->GetStreams ())
ret.push_back (it.second); ret.push_back (it.second);
} }
for (auto& it: m_StreamingDestinationsByPorts) for (auto& it: m_StreamingDestinationsByPorts)
for (auto& it1: it.second->GetStreams ()) for (auto& it1: it.second->GetStreams ())
ret.push_back (it1.second); ret.push_back (it1.second);
return ret; return ret;
} }
void ClientDestination::PersistTemporaryKeys () void ClientDestination::PersistTemporaryKeys ()
{ {
@ -927,7 +927,7 @@ namespace client
return; return;
} }
LogPrint(eLogError, "Destinations: Can't save keys to ", path); LogPrint(eLogError, "Destinations: Can't save keys to ", path);
} }
void ClientDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) void ClientDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
{ {
@ -935,7 +935,7 @@ namespace client
// sign // sign
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO
SetLeaseSet (leaseSet); SetLeaseSet (leaseSet);
} }
void ClientDestination::CleanupDestination () void ClientDestination::CleanupDestination ()
{ {

25
libi2pd_client/ClientContext.cpp

@ -48,7 +48,7 @@ namespace client
std::shared_ptr<ClientDestination> localDestination; std::shared_ptr<ClientDestination> localDestination;
bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy); bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy);
if (httproxy) if (httproxy)
{ {
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr);
@ -68,12 +68,12 @@ namespace client
else else
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key"); LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
} }
try try
{ {
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination);
m_HttpProxy->Start(); m_HttpProxy->Start();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
} }
@ -253,7 +253,7 @@ namespace client
void ClientContext::ReloadConfig () void ClientContext::ReloadConfig ()
{ {
// TODO: handle config changes // TODO: handle config changes
/*std::string config; i2p::config::GetOption("conf", config); /*std::string config; i2p::config::GetOption("conf", config);
i2p::config::ParseConfig(config);*/ i2p::config::ParseConfig(config);*/
@ -269,7 +269,7 @@ namespace client
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
for (auto it = m_Destinations.begin (); it != m_Destinations.end ();) for (auto it = m_Destinations.begin (); it != m_Destinations.end ();)
{ {
auto dest = it->second; auto dest = it->second;
if (dest->GetRefCounter () > 0) ++it; // skip if (dest->GetRefCounter () > 0) ++it; // skip
else else
{ {
@ -551,6 +551,13 @@ namespace client
clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint (); clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint ();
} }
uint32_t timeout = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0);
if(timeout)
{
clientTunnel->SetConnectTimeout(timeout);
LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout);
}
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel))); auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel)));
if (ins.second) if (ins.second)
{ {
@ -657,7 +664,7 @@ namespace client
} }
auto ins = m_ServerTunnels.insert (std::make_pair ( auto ins = m_ServerTunnels.insert (std::make_pair (
std::make_pair (localDestination->GetIdentHash (), inPort), std::make_pair (localDestination->GetIdentHash (), inPort),
std::unique_ptr<I2PServerTunnel>(serverTunnel))); std::unique_ptr<I2PServerTunnel>(serverTunnel)));
if (ins.second) if (ins.second)
{ {
serverTunnel->Start (); serverTunnel->Start ();
@ -715,8 +722,8 @@ namespace client
it = c.erase (it); it = c.erase (it);
} }
else else
it++; it++;
} }
} }
template<typename Visitor> template<typename Visitor>

1
libi2pd_client/ClientContext.h

@ -36,6 +36,7 @@ namespace client
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport"; const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels"; const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout";
const char I2P_SERVER_TUNNEL_HOST[] = "host"; const char I2P_SERVER_TUNNEL_HOST[] = "host";
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride"; const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
const char I2P_SERVER_TUNNEL_PORT[] = "port"; const char I2P_SERVER_TUNNEL_PORT[] = "port";

134
libi2pd_client/I2PService.cpp

@ -2,6 +2,7 @@
#include "Identity.h" #include "Identity.h"
#include "ClientContext.h" #include "ClientContext.h"
#include "I2PService.h" #include "I2PService.h"
#include <boost/asio/error.hpp>
namespace i2p namespace i2p
{ {
@ -11,37 +12,101 @@ namespace client
I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination): I2PService::I2PService (std::shared_ptr<ClientDestination> localDestination):
m_LocalDestination (localDestination ? localDestination : m_LocalDestination (localDestination ? localDestination :
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), isUpdated (true) i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)),
m_ReadyTimer(m_LocalDestination->GetService()),
m_ConnectTimeout(0),
isUpdated (true)
{ {
m_LocalDestination->Acquire (); m_LocalDestination->Acquire ();
} }
I2PService::I2PService (i2p::data::SigningKeyType kt): I2PService::I2PService (i2p::data::SigningKeyType kt):
m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt)), m_LocalDestination (i2p::client::context.CreateNewLocalDestination (false, kt)),
m_ReadyTimer(m_LocalDestination->GetService()),
m_ConnectTimeout(0),
isUpdated (true) isUpdated (true)
{ {
m_LocalDestination->Acquire (); m_LocalDestination->Acquire ();
} }
I2PService::~I2PService () I2PService::~I2PService ()
{ {
ClearHandlers (); ClearHandlers ();
if (m_LocalDestination) m_LocalDestination->Release (); if (m_LocalDestination) m_LocalDestination->Release ();
} }
void I2PService::ClearHandlers () void I2PService::ClearHandlers ()
{ {
if(m_ConnectTimeout)
m_ReadyTimer.cancel();
std::unique_lock<std::mutex> l(m_HandlersMutex); std::unique_lock<std::mutex> l(m_HandlersMutex);
for (auto it: m_Handlers) for (auto it: m_Handlers)
it->Terminate (); it->Terminate ();
m_Handlers.clear(); m_Handlers.clear();
} }
void I2PService::SetConnectTimeout(uint32_t timeout)
{
if(timeout && !m_ConnectTimeout)
{
TriggerReadyCheckTimer();
}
else if (m_ConnectTimeout && !timeout)
{
m_ReadyTimer.cancel();
}
m_ConnectTimeout = timeout;
}
void I2PService::AddReadyCallback(ReadyCallback cb)
{
uint32_t now = i2p::util::GetSecondsSinceEpoch();
uint32_t tm = now + m_ConnectTimeout;
LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now);
m_ReadyCallbacks.push_back({cb, tm});
}
void I2PService::TriggerReadyCheckTimer()
{
m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1));
m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_1));
}
void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec)
{
if(ec || m_LocalDestination->IsReady())
{
for(auto & itr : m_ReadyCallbacks)
itr.first(ec);
m_ReadyCallbacks.clear();
}
else if(!m_LocalDestination->IsReady())
{
// expire timed out requests
uint32_t now = i2p::util::GetSecondsSinceEpoch ();
auto itr = m_ReadyCallbacks.begin();
while(itr != m_ReadyCallbacks.end())
{
if(itr->second >= now)
{
itr->first(boost::asio::error::timed_out);
itr = m_ReadyCallbacks.erase(itr);
}
else
++itr;
}
}
if(!ec)
TriggerReadyCheckTimer();
}
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) { void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
assert(streamRequestComplete); assert(streamRequestComplete);
i2p::data::IdentHash identHash; i2p::data::IdentHash identHash;
if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash)) if (i2p::client::context.GetAddressBook ().GetIdentHash (dest, identHash))
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port); {
CreateStream(streamRequestComplete, identHash, port);
}
else else
{ {
LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest); LogPrint (eLogWarning, "I2PService: Remote destination not found: ", dest);
@ -49,6 +114,29 @@ namespace client
} }
} }
void I2PService::CreateStream(StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash & identHash, int port)
{
if(m_ConnectTimeout)
{
if(m_LocalDestination->IsReady())
m_LocalDestination->CreateStream (streamRequestComplete, identHash, port);
else
{
AddReadyCallback([this, streamRequestComplete, identHash, port] (const boost::system::error_code & ec) {
if(ec)
{
LogPrint(eLogWarning, "I2PService::CeateStream() ", ec.message());
streamRequestComplete(nullptr);
}
else
this->m_LocalDestination->CreateStream(streamRequestComplete, identHash, port);
});
}
}
else
m_LocalDestination->CreateStream(streamRequestComplete, identHash, port);
}
TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream) TCPIPPipe::TCPIPPipe(I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> upstream, std::shared_ptr<boost::asio::ip::tcp::socket> downstream) : I2PServiceHandler(owner), m_up(upstream), m_down(downstream)
{ {
boost::asio::socket_base::receive_buffer_size option(TCP_IP_PIPE_BUFFER_SIZE); boost::asio::socket_base::receive_buffer_size option(TCP_IP_PIPE_BUFFER_SIZE);
@ -60,7 +148,7 @@ namespace client
{ {
Terminate(); Terminate();
} }
void TCPIPPipe::Start() void TCPIPPipe::Start()
{ {
AsyncReceiveUpstream(); AsyncReceiveUpstream();
@ -84,7 +172,7 @@ namespace client
} }
Done(shared_from_this()); Done(shared_from_this());
} }
void TCPIPPipe::AsyncReceiveUpstream() void TCPIPPipe::AsyncReceiveUpstream()
{ {
if (m_up) { if (m_up) {
@ -132,12 +220,12 @@ namespace client
shared_from_this(), shared_from_this(),
std::placeholders::_1) std::placeholders::_1)
); );
} else { } else {
LogPrint(eLogError, "TCPIPPipe: downstream write: no socket"); LogPrint(eLogError, "TCPIPPipe: downstream write: no socket");
} }
} }
void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{ {
LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received"); LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received");
@ -162,7 +250,7 @@ namespace client
AsyncReceiveUpstream(); AsyncReceiveUpstream();
} }
} }
void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) { void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
if (ecode) { if (ecode) {
LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message()); LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message());
@ -172,7 +260,7 @@ namespace client
AsyncReceiveDownstream(); AsyncReceiveDownstream();
} }
} }
void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered) void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
{ {
LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received"); LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received");
@ -187,7 +275,7 @@ namespace client
DownstreamWrite(bytes_transfered); DownstreamWrite(bytes_transfered);
} }
} }
void TCPIPAcceptor::Start () void TCPIPAcceptor::Start ()
{ {
m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint)); m_Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), m_LocalEndpoint));
@ -198,10 +286,10 @@ namespace client
void TCPIPAcceptor::Stop () void TCPIPAcceptor::Stop ()
{ {
if (m_Acceptor) if (m_Acceptor)
{ {
m_Acceptor->close(); m_Acceptor->close();
m_Acceptor.reset (nullptr); m_Acceptor.reset (nullptr);
} }
m_Timer.cancel (); m_Timer.cancel ();
ClearHandlers(); ClearHandlers();
} }
@ -219,12 +307,12 @@ namespace client
{ {
LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted"); LogPrint(eLogDebug, "I2PService: ", GetName(), " accepted");
auto handler = CreateHandler(socket); auto handler = CreateHandler(socket);
if (handler) if (handler)
{ {
AddHandler(handler); AddHandler(handler);
handler->Handle(); handler->Handle();
} }
else else
socket->close(); socket->close();
Accept(); Accept();
} }

24
libi2pd_client/I2PService.h

@ -14,8 +14,10 @@ namespace i2p
namespace client namespace client
{ {
class I2PServiceHandler; class I2PServiceHandler;
class I2PService class I2PService : std::enable_shared_from_this<I2PService>
{ {
public:
typedef std::function<void(const boost::system::error_code &)> ReadyCallback;
public: public:
I2PService (std::shared_ptr<ClientDestination> localDestination = nullptr); I2PService (std::shared_ptr<ClientDestination> localDestination = nullptr);
I2PService (i2p::data::SigningKeyType kt); I2PService (i2p::data::SigningKeyType kt);
@ -33,25 +35,37 @@ namespace client
} }
void ClearHandlers (); void ClearHandlers ();
void SetConnectTimeout(uint32_t timeout);
void AddReadyCallback(ReadyCallback cb);
inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; } inline std::shared_ptr<ClientDestination> GetLocalDestination () { return m_LocalDestination; }
inline std::shared_ptr<const ClientDestination> GetLocalDestination () const { return m_LocalDestination; } inline std::shared_ptr<const ClientDestination> GetLocalDestination () const { return m_LocalDestination; }
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; } inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest) { m_LocalDestination = dest; }
void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0); void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0);
void CreateStream(StreamRequestComplete complete, const i2p::data::IdentHash & ident, int port);
inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); } inline boost::asio::io_service& GetService () { return m_LocalDestination->GetService (); }
virtual void Start () = 0; virtual void Start () = 0;
virtual void Stop () = 0; virtual void Stop () = 0;
virtual const char* GetName() { return "Generic I2P Service"; } virtual const char* GetName() { return "Generic I2P Service"; }
private:
void TriggerReadyCheckTimer();
void HandleReadyCheckTimer(const boost::system::error_code & ec);
private: private:
std::shared_ptr<ClientDestination> m_LocalDestination; std::shared_ptr<ClientDestination> m_LocalDestination;
std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers; std::unordered_set<std::shared_ptr<I2PServiceHandler> > m_Handlers;
std::mutex m_HandlersMutex; std::mutex m_HandlersMutex;
std::vector<std::pair<ReadyCallback, uint32_t> > m_ReadyCallbacks;
boost::asio::deadline_timer m_ReadyTimer;
uint32_t m_ConnectTimeout;
public: public:
bool isUpdated; // transient, used during reload only bool isUpdated; // transient, used during reload only
}; };
/*Simple interface for I2PHandlers, allows detection of finalization amongst other things */ /*Simple interface for I2PHandlers, allows detection of finalization amongst other things */
@ -64,7 +78,7 @@ namespace client
virtual void Handle() {}; //Start handling the socket virtual void Handle() {}; //Start handling the socket
void Terminate () { Kill (); }; void Terminate () { Kill (); };
protected: protected:
// Call when terminating or handing over to avoid race conditions // Call when terminating or handing over to avoid race conditions
inline bool Kill () { return m_Dead.exchange(true); } inline bool Kill () { return m_Dead.exchange(true); }
@ -102,7 +116,7 @@ namespace client
uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE]; uint8_t m_upstream_buf[TCP_IP_PIPE_BUFFER_SIZE], m_downstream_buf[TCP_IP_PIPE_BUFFER_SIZE];
std::shared_ptr<boost::asio::ip::tcp::socket> m_up, m_down; std::shared_ptr<boost::asio::ip::tcp::socket> m_up, m_down;
}; };
/* TODO: support IPv6 too */ /* TODO: support IPv6 too */
//This is a service that listens for connections on the IP network and interacts with I2P //This is a service that listens for connections on the IP network and interacts with I2P
class TCPIPAcceptor: public I2PService class TCPIPAcceptor: public I2PService

194
libi2pd_client/I2PTunnel.cpp

@ -14,19 +14,19 @@ namespace client
static void I2PTunnelSetSocketOptions(std::shared_ptr<boost::asio::ip::tcp::socket> socket) static void I2PTunnelSetSocketOptions(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
if (socket && socket->is_open()) if (socket && socket->is_open())
{ {
boost::asio::socket_base::receive_buffer_size option(I2P_TUNNEL_CONNECTION_BUFFER_SIZE); boost::asio::socket_base::receive_buffer_size option(I2P_TUNNEL_CONNECTION_BUFFER_SIZE);
socket->set_option(option); socket->set_option(option);
} }
} }
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket, I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port): std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
m_IsQuiet (true) m_IsQuiet (true)
{ {
m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port); m_Stream = GetOwner()->GetLocalDestination ()->CreateStream (leaseSet, port);
} }
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream): std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
@ -44,15 +44,15 @@ namespace client
I2PTunnelConnection::~I2PTunnelConnection () I2PTunnelConnection::~I2PTunnelConnection ()
{ {
} }
void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len) void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
{ {
if (m_Stream) if (m_Stream)
{ {
if (msg) if (msg)
m_Stream->Send (msg, len); // connect and send m_Stream->Send (msg, len); // connect and send
else else
m_Stream->Send (m_Buffer, 0); // connect m_Stream->Send (m_Buffer, 0); // connect
} }
StreamReceive (); StreamReceive ();
@ -68,11 +68,11 @@ namespace client
boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes); boost::asio::ip::address ourIP = boost::asio::ip::address_v4 (bytes);
return ourIP; return ourIP;
} }
static void MapToLoopback(const std::shared_ptr<boost::asio::ip::tcp::socket> & sock, const i2p::data::IdentHash & addr) static void MapToLoopback(const std::shared_ptr<boost::asio::ip::tcp::socket> & sock, const i2p::data::IdentHash & addr)
{ {
// bind to 127.x.x.x address // bind to 127.x.x.x address
// where x.x.x are first three bytes from ident // where x.x.x are first three bytes from ident
auto ourIP = GetLoopbackAddressFor(addr); auto ourIP = GetLoopbackAddressFor(addr);
sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0)); sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0));
@ -82,7 +82,7 @@ namespace client
void I2PTunnelConnection::Connect (bool isUniqueLocal) void I2PTunnelConnection::Connect (bool isUniqueLocal)
{ {
I2PTunnelSetSocketOptions(m_Socket); I2PTunnelSetSocketOptions(m_Socket);
if (m_Socket) if (m_Socket)
{ {
#ifdef __linux__ #ifdef __linux__
if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () && if (isUniqueLocal && m_RemoteEndpoint.address ().is_v4 () &&
@ -96,8 +96,8 @@ namespace client
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect, m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
void I2PTunnelConnection::Terminate () void I2PTunnelConnection::Terminate ()
{ {
if (Kill()) return; if (Kill()) return;
@ -105,21 +105,21 @@ namespace client
{ {
m_Stream->Close (); m_Stream->Close ();
m_Stream.reset (); m_Stream.reset ();
} }
boost::system::error_code ec; boost::system::error_code ec;
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); // avoid RST
m_Socket->close (); m_Socket->close ();
Done(shared_from_this ()); Done(shared_from_this ());
} }
void I2PTunnelConnection::Receive () void I2PTunnelConnection::Receive ()
{ {
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (), std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} }
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (ecode) if (ecode)
@ -131,9 +131,9 @@ namespace client
} }
} }
else else
{ {
if (m_Stream) if (m_Stream)
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
m_Stream->AsyncSend (m_Buffer, bytes_transferred, m_Stream->AsyncSend (m_Buffer, bytes_transferred,
[s](const boost::system::error_code& ecode) [s](const boost::system::error_code& ecode)
@ -143,9 +143,9 @@ namespace client
else else
s->Terminate (); s->Terminate ();
}); });
} }
} }
} }
void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode) void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
{ {
@ -165,12 +165,12 @@ namespace client
{ {
if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew || if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew ||
m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular
{ {
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (), std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2), std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE); I2P_TUNNEL_CONNECTION_MAX_IDLE);
} }
else // closed by peer else // closed by peer
{ {
// get remaning data // get remaning data
@ -178,10 +178,10 @@ namespace client
if (len > 0) // still some data if (len > 0) // still some data
Write (m_StreamBuffer, len); Write (m_StreamBuffer, len);
else // no more data else // no more data
Terminate (); Terminate ();
} }
} }
} }
void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) void I2PTunnelConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
@ -231,8 +231,8 @@ namespace client
memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
} }
HandleStreamReceive (boost::system::error_code (), dest.size ()); HandleStreamReceive (boost::system::error_code (), dest.size ());
} }
Receive (); Receive ();
} }
} }
@ -253,20 +253,20 @@ namespace client
{ {
if (line == "\r") endOfHeader = true; if (line == "\r") endOfHeader = true;
else else
{ {
if (!m_ConnectionSent && !line.compare(0, 10, "Connection")) if (!m_ConnectionSent && !line.compare(0, 10, "Connection"))
{ {
m_OutHeader << "Connection: close\r\n"; m_OutHeader << "Connection: close\r\n";
m_ConnectionSent = true; m_ConnectionSent = true;
} }
else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection")) else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection"))
{ {
m_OutHeader << "Proxy-Connection: close\r\n"; m_OutHeader << "Proxy-Connection: close\r\n";
m_ProxyConnectionSent = true; m_ProxyConnectionSent = true;
} }
else else
m_OutHeader << line << "\n"; m_OutHeader << line << "\n";
} }
} }
else else
break; break;
@ -283,10 +283,10 @@ namespace client
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
} }
} }
} }
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host): const boost::asio::ip::tcp::endpoint& target, const std::string& host):
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ()) I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ())
{ {
@ -297,7 +297,7 @@ namespace client
if (m_HeaderSent) if (m_HeaderSent)
I2PTunnelConnection::Write (buf, len); I2PTunnelConnection::Write (buf, len);
else else
{ {
m_InHeader.clear (); m_InHeader.clear ();
m_InHeader.write ((const char *)buf, len); m_InHeader.write ((const char *)buf, len);
std::string line; std::string line;
@ -309,12 +309,12 @@ namespace client
{ {
if (line == "\r") endOfHeader = true; if (line == "\r") endOfHeader = true;
else else
{ {
if (m_Host.length () > 0 && line.find ("Host:") != std::string::npos) if (m_Host.length () > 0 && line.find ("Host:") != std::string::npos)
m_OutHeader << "Host: " << m_Host << "\r\n"; // override host m_OutHeader << "Host: " << m_Host << "\r\n"; // override host
else else
m_OutHeader << line << "\n"; m_OutHeader << line << "\n";
} }
} }
else else
break; break;
@ -335,13 +335,13 @@ namespace client
m_HeaderSent = true; m_HeaderSent = true;
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
} }
} }
} }
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass):
I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()), I2PTunnelConnection (owner, stream, socket, target), m_From (stream->GetRemoteIdentity ()),
m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass) m_NeedsWebIrc (webircpass.length() ? true : false), m_WebircPass (webircpass)
{ {
} }
@ -349,7 +349,7 @@ namespace client
void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len) void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len)
{ {
m_OutPacket.str (""); m_OutPacket.str ("");
if (m_NeedsWebIrc) if (m_NeedsWebIrc)
{ {
m_NeedsWebIrc = false; m_NeedsWebIrc = false;
m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl; m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " " << GetSocket ()->local_endpoint ().address () << std::endl;
@ -357,12 +357,12 @@ namespace client
m_InPacket.clear (); m_InPacket.clear ();
m_InPacket.write ((const char *)buf, len); m_InPacket.write ((const char *)buf, len);
while (!m_InPacket.eof () && !m_InPacket.fail ()) while (!m_InPacket.eof () && !m_InPacket.fail ())
{ {
std::string line; std::string line;
std::getline (m_InPacket, line); std::getline (m_InPacket, line);
if (line.length () == 0 && m_InPacket.eof ()) if (line.length () == 0 && m_InPacket.eof ())
m_InPacket.str (""); m_InPacket.str ("");
auto pos = line.find ("USER"); auto pos = line.find ("USER");
if (!pos) // start of line if (!pos) // start of line
@ -375,7 +375,7 @@ namespace client
m_OutPacket << line.substr (0, pos); m_OutPacket << line.substr (0, pos);
m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()); m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ());
m_OutPacket << line.substr (nextpos) << '\n'; m_OutPacket << line.substr (nextpos) << '\n';
} }
else else
m_OutPacket << line << '\n'; m_OutPacket << line << '\n';
} }
@ -389,7 +389,7 @@ namespace client
public: public:
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination, I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket): int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
I2PServiceHandler(parent), m_DestinationIdentHash(destination), I2PServiceHandler(parent), m_DestinationIdentHash(destination),
m_DestinationPort (destinationPort), m_Socket(socket) {}; m_DestinationPort (destinationPort), m_Socket(socket) {};
void Handle(); void Handle();
void Terminate(); void Terminate();
@ -402,8 +402,8 @@ namespace client
void I2PClientTunnelHandler::Handle() void I2PClientTunnelHandler::Handle()
{ {
GetOwner()->GetLocalDestination ()->CreateStream ( GetOwner()->CreateStream (
std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), std::bind (&I2PClientTunnelHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1),
m_DestinationIdentHash, m_DestinationPort); m_DestinationIdentHash, m_DestinationPort);
} }
@ -436,12 +436,12 @@ namespace client
Done(shared_from_this()); Done(shared_from_this());
} }
I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination, I2PClientTunnel::I2PClientTunnel (const std::string& name, const std::string& destination,
const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort): const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination), TCPIPAcceptor (address, port, localDestination), m_Name (name), m_Destination (destination),
m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort) m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
{ {
} }
void I2PClientTunnel::Start () void I2PClientTunnel::Start ()
{ {
@ -480,8 +480,8 @@ namespace client
return nullptr; return nullptr;
} }
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip): int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
{ {
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip); m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip);
@ -489,10 +489,10 @@ namespace client
void I2PServerTunnel::Start () void I2PServerTunnel::Start ()
{ {
m_Endpoint.port (m_Port); m_Endpoint.port (m_Port);
boost::system::error_code ec; boost::system::error_code ec;
auto addr = boost::asio::ip::address::from_string (m_Address, ec); auto addr = boost::asio::ip::address::from_string (m_Address, ec);
if (!ec) if (!ec)
{ {
m_Endpoint.address (addr); m_Endpoint.address (addr);
Accept (); Accept ();
@ -500,27 +500,27 @@ namespace client
else else
{ {
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ()); auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""), resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""),
std::bind (&I2PServerTunnel::HandleResolve, this, std::bind (&I2PServerTunnel::HandleResolve, this,
std::placeholders::_1, std::placeholders::_2, resolver)); std::placeholders::_1, std::placeholders::_2, resolver));
} }
} }
void I2PServerTunnel::Stop () void I2PServerTunnel::Stop ()
{ {
ClearHandlers (); ClearHandlers ();
} }
void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver) std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
{ {
if (!ecode) if (!ecode)
{ {
auto addr = (*it).endpoint ().address (); auto addr = (*it).endpoint ().address ();
LogPrint (eLogInfo, "I2PTunnel: server tunnel ", (*it).host_name (), " has been resolved to ", addr); LogPrint (eLogInfo, "I2PTunnel: server tunnel ", (*it).host_name (), " has been resolved to ", addr);
m_Endpoint.address (addr); m_Endpoint.address (addr);
Accept (); Accept ();
} }
else else
LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ()); LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ());
} }
@ -528,7 +528,7 @@ namespace client
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList) void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
{ {
m_AccessList = accessList; m_AccessList = accessList;
m_IsAccessList = true; m_IsAccessList = true;
} }
void I2PServerTunnel::Accept () void I2PServerTunnel::Accept ()
@ -536,7 +536,7 @@ namespace client
if (m_PortDestination) if (m_PortDestination)
m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); m_PortDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
auto localDestination = GetLocalDestination (); auto localDestination = GetLocalDestination ();
if (localDestination) if (localDestination)
{ {
if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet
@ -549,7 +549,7 @@ namespace client
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream) void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {
if (m_IsAccessList) if (m_IsAccessList)
{ {
if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ())) if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ()))
@ -563,31 +563,31 @@ namespace client
auto conn = CreateI2PConnection (stream); auto conn = CreateI2PConnection (stream);
AddHandler (conn); AddHandler (conn);
conn->Connect (m_IsUniqueLocal); conn->Connect (m_IsUniqueLocal);
} }
} }
std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream) std::shared_ptr<I2PTunnelConnection> I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{ {
return std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ()); return std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
} }
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address, I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int port, std::shared_ptr<ClientDestination> localDestination,
const std::string& host, int inport, bool gzip): const std::string& host, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip), I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_Host (host) m_Host (host)
{ {
} }
std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream) std::shared_ptr<I2PTunnelConnection> I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{ {
return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream, return std::make_shared<I2PServerTunnelConnectionHTTP> (this, stream,
std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host); std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), m_Host);
} }
I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address, I2PServerTunnelIRC::I2PServerTunnelIRC (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int port, std::shared_ptr<ClientDestination> localDestination,
const std::string& webircpass, int inport, bool gzip): const std::string& webircpass, int inport, bool gzip):
I2PServerTunnel (name, address, port, localDestination, inport, gzip), I2PServerTunnel (name, address, port, localDestination, inport, gzip),
m_WebircPass (webircpass) m_WebircPass (webircpass)
@ -631,7 +631,7 @@ namespace client
m_Sessions.erase(port); m_Sessions.erase(port);
} }
} }
UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) UDPSessionPtr I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)
{ {
auto ih = from.GetIdentHash(); auto ih = from.GetIdentHash();
@ -646,12 +646,12 @@ namespace client
} }
boost::asio::ip::address addr; boost::asio::ip::address addr;
/** create new udp session */ /** create new udp session */
if(m_IsUniqueLocal && m_LocalAddress.is_loopback()) if(m_IsUniqueLocal && m_LocalAddress.is_loopback())
{ {
auto ident = from.GetIdentHash(); auto ident = from.GetIdentHash();
addr = GetLoopbackAddressFor(ident); addr = GetLoopbackAddressFor(ident);
} }
else else
addr = m_LocalAddress; addr = m_LocalAddress;
boost::asio::ip::udp::endpoint ep(addr, 0); boost::asio::ip::udp::endpoint ep(addr, 0);
m_Sessions.push_back(std::make_shared<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); m_Sessions.push_back(std::make_shared<UDPSession>(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort));
@ -680,7 +680,7 @@ namespace client
IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU), IPSocket.async_receive_from(boost::asio::buffer(m_Buffer, I2P_UDP_MAX_MTU),
FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2)); FromEndpoint, std::bind(&UDPSession::HandleReceived, this, std::placeholders::_1, std::placeholders::_2));
} }
void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len) void UDPSession::HandleReceived(const boost::system::error_code & ecode, std::size_t len)
{ {
if(!ecode) if(!ecode)
@ -694,8 +694,8 @@ namespace client
} }
} }
I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination, I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) : boost::asio::ip::address localAddress, boost::asio::ip::udp::endpoint forwardTo, uint16_t port) :
m_IsUniqueLocal(true), m_IsUniqueLocal(true),
@ -713,7 +713,7 @@ namespace client
{ {
auto dgram = m_LocalDest->GetDatagramDestination(); auto dgram = m_LocalDest->GetDatagramDestination();
if (dgram) dgram->ResetReceiver(); if (dgram) dgram->ResetReceiver();
LogPrint(eLogInfo, "UDPServer: done"); LogPrint(eLogInfo, "UDPServer: done");
} }
@ -742,7 +742,7 @@ namespace client
} }
return sessions; return sessions;
} }
I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest,
boost::asio::ip::udp::endpoint localEndpoint, boost::asio::ip::udp::endpoint localEndpoint,
std::shared_ptr<i2p::client::ClientDestination> localDestination, std::shared_ptr<i2p::client::ClientDestination> localDestination,
@ -764,8 +764,8 @@ namespace client
std::placeholders::_5)); std::placeholders::_5));
} }
void I2PUDPClientTunnel::Start() { void I2PUDPClientTunnel::Start() {
m_LocalDest->Start(); m_LocalDest->Start();
if (m_ResolveThread == nullptr) if (m_ResolveThread == nullptr)
@ -803,14 +803,14 @@ namespace client
m_Sessions[remotePort].second = i2p::util::GetMillisecondsSinceEpoch(); m_Sessions[remotePort].second = i2p::util::GetMillisecondsSinceEpoch();
RecvFromLocal(); RecvFromLocal();
} }
std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions() std::vector<std::shared_ptr<DatagramSessionInfo> > I2PUDPClientTunnel::GetSessions()
{ {
// TODO: implement // TODO: implement
std::vector<std::shared_ptr<DatagramSessionInfo> > infos; std::vector<std::shared_ptr<DatagramSessionInfo> > infos;
return infos; return infos;
} }
void I2PUDPClientTunnel::TryResolving() { void I2PUDPClientTunnel::TryResolving() {
LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
i2p::data::IdentHash * h = new i2p::data::IdentHash; i2p::data::IdentHash * h = new i2p::data::IdentHash;
@ -846,11 +846,11 @@ namespace client
} }
} }
else else
LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort); LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort);
} }
else else
LogPrint(eLogWarning, "UDP Client: unwarrented traffic from ", from.GetIdentHash().ToBase32()); LogPrint(eLogWarning, "UDP Client: unwarrented traffic from ", from.GetIdentHash().ToBase32());
} }
I2PUDPClientTunnel::~I2PUDPClientTunnel() { I2PUDPClientTunnel::~I2PUDPClientTunnel() {
@ -858,7 +858,7 @@ namespace client
if (dgram) dgram->ResetReceiver(); if (dgram) dgram->ResetReceiver();
m_Sessions.clear(); m_Sessions.clear();
if(m_LocalSocket.is_open()) if(m_LocalSocket.is_open())
m_LocalSocket.close(); m_LocalSocket.close();

Loading…
Cancel
Save