mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 13:27:17 +01:00
commit
fc08d15a79
|
@ -842,7 +842,7 @@ namespace client
|
|||
else
|
||||
memset (response + 8, 0, 32); // not found
|
||||
memset (response + 40, 0, 4); // set expiration time to zero
|
||||
m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 44, from.GetIdentHash (), toPort, fromPort);
|
||||
m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 44, from.GetIdentHash(), toPort, fromPort);
|
||||
}
|
||||
|
||||
void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident)
|
||||
|
|
69
BloomFilter.cpp
Normal file
69
BloomFilter.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "BloomFilter.h"
|
||||
#include "I2PEndian.h"
|
||||
#include <array>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
/** @brief decaying bloom filter implementation */
|
||||
class DecayingBloomFilter : public IBloomFilter
|
||||
{
|
||||
public:
|
||||
|
||||
DecayingBloomFilter(const std::size_t size)
|
||||
{
|
||||
m_Size = size;
|
||||
m_Data = new uint8_t[size];
|
||||
}
|
||||
|
||||
/** @brief implements IBloomFilter::~IBloomFilter */
|
||||
~DecayingBloomFilter()
|
||||
{
|
||||
delete [] m_Data;
|
||||
}
|
||||
|
||||
/** @brief implements IBloomFilter::Add */
|
||||
bool Add(const uint8_t * data, std::size_t len)
|
||||
{
|
||||
std::size_t idx;
|
||||
uint8_t mask;
|
||||
Get(data, len, idx, mask);
|
||||
if(m_Data[idx] & mask) return false; // filter hit
|
||||
m_Data[idx] |= mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief implements IBloomFilter::Decay */
|
||||
void Decay()
|
||||
{
|
||||
// reset bloom filter buffer
|
||||
memset(m_Data, 0, m_Size);
|
||||
}
|
||||
|
||||
private:
|
||||
/** @brief get bit index for for data */
|
||||
void Get(const uint8_t * data, std::size_t len, std::size_t & idx, uint8_t & bm)
|
||||
{
|
||||
bm = 1;
|
||||
uint8_t digest[32];
|
||||
// TODO: use blake2 because it's faster
|
||||
SHA256(data, len, digest);
|
||||
uint64_t i = buf64toh(digest);
|
||||
idx = i % m_Size;
|
||||
bm <<= (i % 8);
|
||||
}
|
||||
|
||||
uint8_t * m_Data;
|
||||
std::size_t m_Size;
|
||||
};
|
||||
|
||||
|
||||
BloomFilterPtr BloomFilter(std::size_t capacity)
|
||||
{
|
||||
return std::make_shared<DecayingBloomFilter>(capacity);
|
||||
}
|
||||
}
|
||||
}
|
31
BloomFilter.h
Normal file
31
BloomFilter.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef BLOOM_FILTER_H_
|
||||
#define BLOOM_FILTER_H_
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
|
||||
/** @brief interface for bloom filter */
|
||||
struct IBloomFilter
|
||||
{
|
||||
|
||||
/** @brief destructor */
|
||||
virtual ~IBloomFilter() {};
|
||||
/** @brief add entry to bloom filter, return false if filter hit otherwise return true */
|
||||
virtual bool Add(const uint8_t * data, std::size_t len) = 0;
|
||||
/** @brief optionally decay old entries */
|
||||
virtual void Decay() = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IBloomFilter> BloomFilterPtr;
|
||||
|
||||
/** @brief create bloom filter */
|
||||
BloomFilterPtr BloomFilter(std::size_t capacity = 1024 * 8);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
23
ChangeLog
23
ChangeLog
|
@ -1,6 +1,29 @@
|
|||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.11.0] - 2016-12-18
|
||||
### Added
|
||||
- Websockets support
|
||||
- Reseed through a floodfill
|
||||
- Tunnel configuration for HTTP and SOCKS proxy
|
||||
- Zero-hops tunnels for destinations
|
||||
- Multiple acceptors for SAM
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- DHT uses AVX if applicable
|
||||
- New logo
|
||||
- LeaseSet lookups
|
||||
### Fixed
|
||||
- HTTP Proxy connection reset for Windows
|
||||
- Crash upon SAM session termination
|
||||
- Can't connect to a destination for a longer time after restart
|
||||
- Mass packet loss for UDP tunnels
|
||||
|
||||
## [2.10.2] - 2016-12-04
|
||||
### Fixed
|
||||
- Fixes UPnP discovery bug, producing excessive CPU usage
|
||||
- Fixes sudden SSU thread stop for Windows.
|
||||
|
||||
## [2.10.1] - 2016-11-07
|
||||
### Fixed
|
||||
- Fixed some performance issues for Windows and Android
|
||||
|
|
|
@ -171,7 +171,7 @@ namespace config {
|
|||
"https://i2p.mooo.com/netDb/,"
|
||||
"https://netdb.i2p2.no/,"
|
||||
"https://us.reseed.i2p2.no:444/,"
|
||||
"https://uk.reseed.i2p2.no:444/,"
|
||||
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
||||
"https://i2p-0.manas.ca:8443/,"
|
||||
"https://reseed.i2p.vzaws.com:8443/,"
|
||||
"https://download.xxlspeed.com/,"
|
||||
|
|
68
Crypto.cpp
68
Crypto.cpp
|
@ -386,44 +386,68 @@ namespace crypto
|
|||
// HMAC
|
||||
const uint64_t IPAD = 0x3636363636363636;
|
||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
||||
|
||||
|
||||
#if defined(__AVX__)
|
||||
static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD };
|
||||
static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD };
|
||||
#endif
|
||||
|
||||
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
||||
// key is 32 bytes
|
||||
// digest is 16 bytes
|
||||
// block size is 64 bytes
|
||||
{
|
||||
uint64_t buf[256];
|
||||
uint64_t hash[12]; // 96 bytes
|
||||
#if defined(__AVX__) // for AVX
|
||||
__asm__
|
||||
(
|
||||
"vmovups %[key], %%ymm0 \n"
|
||||
"vmovups %[ipad], %%ymm1 \n"
|
||||
"vmovups %%ymm1, 32(%[buf]) \n"
|
||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
||||
"vmovups %%ymm1, (%[buf]) \n"
|
||||
"vmovups %[opad], %%ymm1 \n"
|
||||
"vmovups %%ymm1, 32(%[hash]) \n"
|
||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
||||
"vmovups %%ymm1, (%[hash]) \n"
|
||||
"vzeroall \n" // end of AVX
|
||||
"movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
|
||||
:
|
||||
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
|
||||
[buf]"r"(buf), [hash]"r"(hash)
|
||||
: "memory", "%xmm0" // TODO: change to %ymm0 later
|
||||
);
|
||||
#else
|
||||
// ikeypad
|
||||
buf[0] = key.GetLL ()[0] ^ IPAD;
|
||||
buf[1] = key.GetLL ()[1] ^ IPAD;
|
||||
buf[2] = key.GetLL ()[2] ^ IPAD;
|
||||
buf[3] = key.GetLL ()[3] ^ IPAD;
|
||||
buf[4] = IPAD;
|
||||
buf[5] = IPAD;
|
||||
buf[6] = IPAD;
|
||||
buf[7] = IPAD;
|
||||
buf[4] = IPAD;
|
||||
buf[5] = IPAD;
|
||||
buf[6] = IPAD;
|
||||
buf[7] = IPAD;
|
||||
// okeypad
|
||||
hash[0] = key.GetLL ()[0] ^ OPAD;
|
||||
hash[1] = key.GetLL ()[1] ^ OPAD;
|
||||
hash[2] = key.GetLL ()[2] ^ OPAD;
|
||||
hash[3] = key.GetLL ()[3] ^ OPAD;
|
||||
hash[4] = OPAD;
|
||||
hash[5] = OPAD;
|
||||
hash[6] = OPAD;
|
||||
hash[7] = OPAD;
|
||||
// fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||
memset (hash + 10, 0, 16);
|
||||
#endif
|
||||
|
||||
// concatenate with msg
|
||||
memcpy (buf + 8, msg, len);
|
||||
// calculate first hash
|
||||
uint8_t hash[16]; // MD5
|
||||
MD5((uint8_t *)buf, len + 64, hash);
|
||||
|
||||
// okeypad
|
||||
buf[0] = key.GetLL ()[0] ^ OPAD;
|
||||
buf[1] = key.GetLL ()[1] ^ OPAD;
|
||||
buf[2] = key.GetLL ()[2] ^ OPAD;
|
||||
buf[3] = key.GetLL ()[3] ^ OPAD;
|
||||
buf[4] = OPAD;
|
||||
buf[5] = OPAD;
|
||||
buf[6] = OPAD;
|
||||
buf[7] = OPAD;
|
||||
// copy first hash after okeypad
|
||||
memcpy (buf + 8, hash, 16);
|
||||
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||
memset (buf + 10, 0, 16);
|
||||
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
|
||||
|
||||
// calculate digest
|
||||
MD5((uint8_t *)buf, 96, digest);
|
||||
MD5((uint8_t *)hash, 96, digest);
|
||||
}
|
||||
|
||||
// AES
|
||||
|
|
13
Crypto.h
13
Crypto.h
|
@ -76,7 +76,18 @@ namespace crypto
|
|||
|
||||
void operator^=(const ChipherBlock& other) // XOR
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__SSE__) // for Intel x84 or with SSE
|
||||
#if defined(__AVX__) // AVX
|
||||
__asm__
|
||||
(
|
||||
"vmovups (%[buf]), %%xmm0 \n"
|
||||
"vmovups (%[other]), %%xmm1 \n"
|
||||
"vxorps %%xmm0, %%xmm1, %%xmm0 \n"
|
||||
"vmovups %%xmm0, (%[buf]) \n"
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
#elif defined(__SSE__) // SSE
|
||||
__asm__
|
||||
(
|
||||
"movups (%[buf]), %%xmm0 \n"
|
||||
|
|
382
Datagram.cpp
382
Datagram.cpp
|
@ -22,9 +22,9 @@ namespace datagram
|
|||
{
|
||||
m_Sessions.clear();
|
||||
}
|
||||
|
||||
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
|
||||
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
auto owner = m_Owner;
|
||||
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
||||
uint8_t * buf = v.data();
|
||||
|
@ -45,8 +45,7 @@ namespace datagram
|
|||
owner->Sign (buf1, len, signature);
|
||||
|
||||
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
||||
auto session = ObtainSession(ident);
|
||||
session->SendMsg(msg);
|
||||
ObtainSession(identity)->SendMsg(msg);
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,6 +68,8 @@ namespace datagram
|
|||
|
||||
if (verified)
|
||||
{
|
||||
auto h = identity.GetIdentHash();
|
||||
ObtainSession(h)->Ack();
|
||||
auto r = FindReceiver(toPort);
|
||||
if(r)
|
||||
r(identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||
|
@ -138,15 +139,15 @@ namespace datagram
|
|||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & ident)
|
||||
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity)
|
||||
{
|
||||
std::shared_ptr<DatagramSession> session = nullptr;
|
||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
||||
auto itr = m_Sessions.find(ident);
|
||||
auto itr = m_Sessions.find(identity);
|
||||
if (itr == m_Sessions.end()) {
|
||||
// not found, create new session
|
||||
session = std::make_shared<DatagramSession>(m_Owner, ident);
|
||||
m_Sessions[ident] = session;
|
||||
session = std::make_shared<DatagramSession>(m_Owner, identity);
|
||||
m_Sessions[identity] = session;
|
||||
} else {
|
||||
session = itr->second;
|
||||
}
|
||||
|
@ -164,13 +165,13 @@ namespace datagram
|
|||
}
|
||||
|
||||
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
|
||||
const i2p::data::IdentHash & remoteIdent) :
|
||||
const i2p::data::IdentHash & remoteIdent) :
|
||||
m_LocalDestination(localDestination),
|
||||
m_RemoteIdentity(remoteIdent),
|
||||
m_LastUse(i2p::util::GetMillisecondsSinceEpoch ()),
|
||||
m_LastPathChange(0),
|
||||
m_LastSuccess(0)
|
||||
m_RemoteIdent(remoteIdent),
|
||||
m_SendQueueTimer(localDestination->GetService())
|
||||
{
|
||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
ScheduleFlushSendQueue();
|
||||
}
|
||||
|
||||
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
|
||||
|
@ -184,262 +185,149 @@ namespace datagram
|
|||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||
{
|
||||
if(!m_RoutingSession)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
|
||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||
if (!routingPath)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
auto lease = routingPath->remoteLease;
|
||||
auto tunnel = routingPath->outboundTunnel;
|
||||
if(lease)
|
||||
{
|
||||
if(tunnel)
|
||||
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||
else
|
||||
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse);
|
||||
}
|
||||
else if(tunnel)
|
||||
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||
else
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess);
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
}
|
||||
|
||||
void DatagramSession::Ack()
|
||||
{
|
||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
|
||||
auto path = GetSharedRoutingPath();
|
||||
if(path)
|
||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
||||
{
|
||||
if(!m_RoutingSession) {
|
||||
if(!m_RemoteLeaseSet) {
|
||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
}
|
||||
if(!m_RemoteLeaseSet) {
|
||||
// no remote lease set
|
||||
m_LocalDestination->RequestDestination(m_RemoteIdent, std::bind(&DatagramSession::HandleLeaseSetUpdated, this, std::placeholders::_1));
|
||||
return nullptr;
|
||||
}
|
||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
||||
}
|
||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||
if(path) {
|
||||
if (m_CurrentOutboundTunnel && !m_CurrentOutboundTunnel->IsEstablished()) {
|
||||
// bad outbound tunnel, switch outbound tunnel
|
||||
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
|
||||
path->outboundTunnel = m_CurrentOutboundTunnel;
|
||||
}
|
||||
if(m_CurrentRemoteLease && ! m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
||||
// bad lease, switch to next one
|
||||
if(m_RemoteLeaseSet) {
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&](const i2p::data::Lease& l) -> bool {
|
||||
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway || l.endDate <= m_CurrentRemoteLease->endDate;
|
||||
});
|
||||
auto sz = ls.size();
|
||||
if (sz) {
|
||||
auto idx = rand() % sz;
|
||||
m_CurrentRemoteLease = ls[idx];
|
||||
}
|
||||
} else {
|
||||
// no remote lease set?
|
||||
LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32());
|
||||
}
|
||||
path->remoteLease = m_CurrentRemoteLease;
|
||||
}
|
||||
} else {
|
||||
// no current path, make one
|
||||
path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
|
||||
// switch outbound tunnel if bad
|
||||
if(m_CurrentOutboundTunnel == nullptr || ! m_CurrentOutboundTunnel->IsEstablished()) {
|
||||
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
|
||||
}
|
||||
// switch lease if bad
|
||||
if(m_CurrentRemoteLease == nullptr || m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
||||
if(!m_RemoteLeaseSet) {
|
||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
}
|
||||
if(m_RemoteLeaseSet) {
|
||||
// pick random next good lease
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&] (const i2p::data::Lease & l) -> bool {
|
||||
if(m_CurrentRemoteLease)
|
||||
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway;
|
||||
return false;
|
||||
});
|
||||
auto sz = ls.size();
|
||||
if(sz) {
|
||||
auto idx = rand() % sz;
|
||||
m_CurrentRemoteLease = ls[idx];
|
||||
}
|
||||
} else {
|
||||
// no remote lease set currently, bail
|
||||
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
path->outboundTunnel = m_CurrentOutboundTunnel;
|
||||
path->remoteLease = m_CurrentRemoteLease;
|
||||
m_RoutingSession->SetSharedRoutingPath(path);
|
||||
}
|
||||
return path;
|
||||
|
||||
}
|
||||
|
||||
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if(!ls) return;
|
||||
// only update lease set if found and newer than previous lease set
|
||||
uint64_t oldExpire = 0;
|
||||
if(m_RemoteLeaseSet) oldExpire = m_RemoteLeaseSet->GetExpirationTime();
|
||||
if(ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
|
||||
}
|
||||
|
||||
void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if(!m_RoutingSession)
|
||||
m_SendQueue.push_back(msg);
|
||||
// flush queue right away if full
|
||||
if(m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) FlushSendQueue();
|
||||
}
|
||||
|
||||
void DatagramSession::FlushSendQueue ()
|
||||
{
|
||||
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> send;
|
||||
auto routingPath = GetSharedRoutingPath();
|
||||
// if we don't have a routing path we will drop all queued messages
|
||||
if(routingPath && routingPath->outboundTunnel && routingPath->remoteLease)
|
||||
{
|
||||
// try to get one
|
||||
if(m_RemoteLeaseSet) m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
||||
else
|
||||
for (const auto & msg : m_SendQueue)
|
||||
{
|
||||
UpdateLeaseSet(msg);
|
||||
return;
|
||||
auto m = m_RoutingSession->WrapSingleMessage(msg);
|
||||
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
|
||||
}
|
||||
routingPath->outboundTunnel->SendTunnelDataMsg(send);
|
||||
}
|
||||
// do we have a routing session?
|
||||
if(m_RoutingSession)
|
||||
{
|
||||
// should we switch paths?
|
||||
if(ShouldUpdateRoutingPath ())
|
||||
{
|
||||
LogPrint(eLogDebug, "DatagramSession: try getting new routing path");
|
||||
// try switching paths
|
||||
auto path = GetNextRoutingPath();
|
||||
if(path)
|
||||
UpdateRoutingPath (path);
|
||||
else
|
||||
ResetRoutingPath();
|
||||
}
|
||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath ();
|
||||
// make sure we have a routing path
|
||||
if (routingPath)
|
||||
{
|
||||
auto outboundTunnel = routingPath->outboundTunnel;
|
||||
if (outboundTunnel)
|
||||
{
|
||||
if(outboundTunnel->IsEstablished())
|
||||
{
|
||||
m_LastSuccess = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
// we have a routing path and routing session and the outbound tunnel we are using is good
|
||||
// wrap message with routing session and send down routing path's outbound tunnel wrapped for the IBGW
|
||||
auto m = m_RoutingSession->WrapSingleMessage(msg);
|
||||
routingPath->outboundTunnel->SendTunnelDataMsg({i2p::tunnel::TunnelMessageBlock{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID,
|
||||
m
|
||||
}});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto now = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
// if this path looks dead reset the routing path since we didn't seem to be able to get a path in time
|
||||
if (m_LastPathChange && now - m_LastPathChange >= DATAGRAM_SESSION_PATH_TIMEOUT ) ResetRoutingPath();
|
||||
UpdateLeaseSet(msg);
|
||||
|
||||
m_SendQueue.clear();
|
||||
ScheduleFlushSendQueue();
|
||||
}
|
||||
|
||||
void DatagramSession::UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path)
|
||||
void DatagramSession::ScheduleFlushSendQueue()
|
||||
{
|
||||
if(m_RoutingSession == nullptr && m_RemoteLeaseSet)
|
||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
||||
if(!m_RoutingSession) return;
|
||||
// set routing path and update time we last updated the routing path
|
||||
m_RoutingSession->SetSharedRoutingPath (path);
|
||||
m_LastPathChange = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
bool DatagramSession::ShouldUpdateRoutingPath() const
|
||||
{
|
||||
bool dead = m_RoutingSession == nullptr || m_RoutingSession->GetSharedRoutingPath () == nullptr;
|
||||
auto now = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
// we need to rotate paths becuase the routing path is too old
|
||||
// if (now - m_LastPathChange >= DATAGRAM_SESSION_PATH_SWITCH_INTERVAL) return true;
|
||||
// too fast switching paths
|
||||
if (now - m_LastPathChange < DATAGRAM_SESSION_PATH_MIN_LIFETIME ) return false;
|
||||
// our path looks dead so we need to rotate paths
|
||||
if (now - m_LastSuccess >= DATAGRAM_SESSION_PATH_TIMEOUT) return !dead;
|
||||
// if we have a routing session and routing path we don't need to switch paths
|
||||
return dead;
|
||||
}
|
||||
|
||||
|
||||
bool DatagramSession::ShouldSwitchLease() const
|
||||
{
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> routingPath = nullptr;
|
||||
std::shared_ptr<const i2p::data::Lease> currentLease = nullptr;
|
||||
if(m_RoutingSession)
|
||||
routingPath = m_RoutingSession->GetSharedRoutingPath ();
|
||||
if(routingPath)
|
||||
currentLease = routingPath->remoteLease;
|
||||
if(currentLease) // if we have a lease return true if it's about to expire otherwise return false
|
||||
return currentLease->ExpiresWithin( DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW, DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE );
|
||||
// we have no current lease, we should switch
|
||||
return currentLease == nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetNextRoutingPath()
|
||||
{
|
||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel = nullptr;
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> routingPath = nullptr;
|
||||
// get existing routing path if we have one
|
||||
if(m_RoutingSession)
|
||||
routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||
// do we have an existing outbound tunnel and routing path?
|
||||
if(routingPath && routingPath->outboundTunnel)
|
||||
{
|
||||
// is the outbound tunnel we are using good?
|
||||
if (routingPath->outboundTunnel->IsEstablished())
|
||||
{
|
||||
// ya so let's stick with it
|
||||
outboundTunnel = routingPath->outboundTunnel;
|
||||
}
|
||||
else
|
||||
outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(routingPath->outboundTunnel); // no so we'll switch outbound tunnels
|
||||
}
|
||||
// do we have an outbound tunnel that works already ?
|
||||
if(!outboundTunnel)
|
||||
outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(); // no, let's get a new outbound tunnel as we probably just started
|
||||
|
||||
if(outboundTunnel)
|
||||
{
|
||||
std::shared_ptr<const i2p::data::Lease> lease = nullptr;
|
||||
// should we switch leases ?
|
||||
if (ShouldSwitchLease ())
|
||||
{
|
||||
// yes, get next available lease
|
||||
lease = GetNextLease();
|
||||
}
|
||||
else if (routingPath)
|
||||
{
|
||||
if(routingPath->remoteLease)
|
||||
{
|
||||
if(routingPath->remoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW, DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE))
|
||||
lease = GetNextLease();
|
||||
else
|
||||
lease = routingPath->remoteLease;
|
||||
}
|
||||
}
|
||||
else
|
||||
lease = GetNextLease();
|
||||
if(lease)
|
||||
{
|
||||
// we have a valid lease to use and an outbound tunnel
|
||||
// create new routing path
|
||||
uint32_t now = i2p::util::GetSecondsSinceEpoch();
|
||||
routingPath = std::make_shared<i2p::garlic::GarlicRoutingPath>(i2p::garlic::GarlicRoutingPath{
|
||||
outboundTunnel,
|
||||
lease,
|
||||
0,
|
||||
now,
|
||||
0
|
||||
});
|
||||
}
|
||||
else // we don't have a new routing path to give
|
||||
routingPath = nullptr;
|
||||
}
|
||||
return routingPath;
|
||||
}
|
||||
|
||||
void DatagramSession::ResetRoutingPath()
|
||||
{
|
||||
if(m_RoutingSession)
|
||||
{
|
||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||
if(routingPath && routingPath->remoteLease) // we have a remote lease already specified and a routing path
|
||||
{
|
||||
// get outbound tunnel on this path
|
||||
auto outboundTunnel = routingPath->outboundTunnel;
|
||||
// is this outbound tunnel there and established
|
||||
if (outboundTunnel && outboundTunnel->IsEstablished())
|
||||
m_InvalidIBGW.push_back(routingPath->remoteLease->tunnelGateway); // yes, let's mark remote lease as dead because the outbound tunnel seems fine
|
||||
}
|
||||
// reset the routing path
|
||||
UpdateRoutingPath(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::Lease> DatagramSession::GetNextLease()
|
||||
{
|
||||
auto now = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
std::shared_ptr<const i2p::data::Lease> next = nullptr;
|
||||
if(m_RemoteLeaseSet)
|
||||
{
|
||||
std::vector<i2p::data::IdentHash> exclude;
|
||||
for(const auto & ident : m_InvalidIBGW)
|
||||
exclude.push_back(ident);
|
||||
// find get all leases that are not in our ban list and are not going to expire within our lease set handover window + fudge
|
||||
auto leases = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding( [&exclude, now] (const i2p::data::Lease & l) -> bool {
|
||||
if(exclude.size())
|
||||
{
|
||||
auto end = std::end(exclude);
|
||||
return std::find_if(exclude.begin(), end, [l, now] ( const i2p::data::IdentHash & ident) -> bool {
|
||||
return ident == l.tunnelGateway;
|
||||
}) != end;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
});
|
||||
if(leases.size())
|
||||
{
|
||||
// pick random valid next lease
|
||||
uint32_t idx = rand() % leases.size();
|
||||
next = leases[idx];
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "DatagramDestination: no leases to use");
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
void DatagramSession::UpdateLeaseSet(std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
LogPrint(eLogInfo, "DatagramSession: updating lease set");
|
||||
m_LocalDestination->RequestDestination(m_RemoteIdentity, std::bind(&DatagramSession::HandleGotLeaseSet, this, std::placeholders::_1, msg));
|
||||
}
|
||||
|
||||
void DatagramSession::HandleGotLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> remoteIdent, std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if(remoteIdent)
|
||||
{
|
||||
// update routing session
|
||||
if(m_RoutingSession)
|
||||
m_RoutingSession = nullptr;
|
||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(remoteIdent, true);
|
||||
// clear invalid IBGW as we have a new lease set
|
||||
m_InvalidIBGW.clear();
|
||||
m_RemoteLeaseSet = remoteIdent;
|
||||
// update routing path
|
||||
auto path = GetNextRoutingPath();
|
||||
if (path)
|
||||
UpdateRoutingPath(path);
|
||||
else
|
||||
ResetRoutingPath();
|
||||
// send the message that was queued if it was provided
|
||||
if(msg)
|
||||
HandleSend(msg);
|
||||
}
|
||||
boost::posix_time::milliseconds dlt(100);
|
||||
m_SendQueueTimer.expires_from_now(dlt);
|
||||
m_SendQueueTimer.async_wait([&](const boost::system::error_code & ec) { if(ec) return; FlushSendQueue(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
72
Datagram.h
72
Datagram.h
|
@ -31,29 +31,33 @@ namespace datagram
|
|||
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
|
||||
// milliseconds minimum time between path switches
|
||||
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
||||
// max 64 messages buffered in send queue for each datagram session
|
||||
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
||||
|
||||
class DatagramSession
|
||||
{
|
||||
public:
|
||||
DatagramSession(i2p::client::ClientDestination * localDestination,
|
||||
const i2p::data::IdentHash & remoteIdent);
|
||||
const i2p::data::IdentHash & remoteIdent);
|
||||
|
||||
|
||||
/** @brief ack the garlic routing path */
|
||||
void Ack();
|
||||
|
||||
/** send an i2np message to remote endpoint for this session */
|
||||
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
||||
/** get the last time in milliseconds for when we used this datagram session */
|
||||
uint64_t LastActivity() const { return m_LastUse; }
|
||||
/** get the last time in milliseconds when we successfully sent data */
|
||||
uint64_t LastSuccess() const { return m_LastSuccess; }
|
||||
|
||||
struct Info
|
||||
{
|
||||
std::shared_ptr<const i2p::data::IdentHash> IBGW;
|
||||
std::shared_ptr<const i2p::data::IdentHash> OBEP;
|
||||
const uint64_t activity;
|
||||
const uint64_t success;
|
||||
Info() : IBGW(nullptr), OBEP(nullptr), activity(0), success(0) {}
|
||||
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a, const uint64_t s) :
|
||||
activity(a),
|
||||
success(s) {
|
||||
|
||||
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
|
||||
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
|
||||
activity(a) {
|
||||
if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
|
||||
else IBGW = nullptr;
|
||||
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
|
||||
|
@ -63,44 +67,28 @@ namespace datagram
|
|||
|
||||
Info GetSessionInfo() const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** update our routing path we are using, mark that we have changed paths */
|
||||
void UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path);
|
||||
void FlushSendQueue();
|
||||
void ScheduleFlushSendQueue();
|
||||
|
||||
/** return true if we should switch routing paths because of path lifetime or timeout otherwise false */
|
||||
bool ShouldUpdateRoutingPath() const;
|
||||
void HandleSend(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
/** return true if we should switch the lease for out routing path otherwise return false */
|
||||
bool ShouldSwitchLease() const;
|
||||
|
||||
/** get next usable routing path, try reusing outbound tunnels */
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetNextRoutingPath();
|
||||
/**
|
||||
* mark current routing path as invalid and clear it
|
||||
* if the outbound tunnel we were using was okay don't use the IBGW in the routing path's lease next time
|
||||
*/
|
||||
void ResetRoutingPath();
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
|
||||
|
||||
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
||||
|
||||
/** get next usable lease, does not fetch or update if expired or have no lease set */
|
||||
std::shared_ptr<const i2p::data::Lease> GetNextLease();
|
||||
|
||||
void HandleSend(std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleGotLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> remoteIdent,
|
||||
std::shared_ptr<I2NPMessage> msg);
|
||||
void UpdateLeaseSet(std::shared_ptr<I2NPMessage> msg=nullptr);
|
||||
|
||||
private:
|
||||
i2p::client::ClientDestination * m_LocalDestination;
|
||||
i2p::data::IdentHash m_RemoteIdentity;
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||
// Ident hash of IBGW that are invalid
|
||||
std::vector<i2p::data::IdentHash> m_InvalidIBGW;
|
||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||
uint64_t m_LastUse;
|
||||
uint64_t m_LastPathChange;
|
||||
uint64_t m_LastSuccess;
|
||||
i2p::data::IdentHash m_RemoteIdent;
|
||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
|
||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
||||
boost::asio::deadline_timer m_SendQueueTimer;
|
||||
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
uint64_t m_LastUse;
|
||||
|
||||
};
|
||||
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
|
@ -112,9 +100,9 @@ namespace datagram
|
|||
|
||||
|
||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
||||
~DatagramDestination ();
|
||||
~DatagramDestination ();
|
||||
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
|
@ -130,7 +118,7 @@ namespace datagram
|
|||
|
||||
private:
|
||||
|
||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
|
||||
|
|
|
@ -544,11 +544,14 @@ namespace client
|
|||
else // duplicate
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
|
||||
// TODO: implement it properly
|
||||
//ret.first->second->requestComplete.push_back (requestComplete);
|
||||
if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
|
||||
{
|
||||
// something went wrong
|
||||
m_LeaseSetRequests.erase (ret.first);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
}
|
||||
else if (requestComplete)
|
||||
ret.first->second->requestComplete.push_back (requestComplete);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
10
Garlic.cpp
10
Garlic.cpp
|
@ -20,8 +20,7 @@ namespace garlic
|
|||
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
|
||||
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
|
||||
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
|
||||
m_LeaseSetUpdateMsgID (0),
|
||||
m_ElGamalEncryption (new i2p::crypto::ElGamalEncryption (destination->GetEncryptionPublicKey ()))
|
||||
m_LeaseSetUpdateMsgID (0)
|
||||
{
|
||||
// create new session tags and session key
|
||||
RAND_bytes (m_SessionKey, 32);
|
||||
|
@ -29,7 +28,7 @@ namespace garlic
|
|||
}
|
||||
|
||||
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
||||
m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
|
||||
m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
|
||||
{
|
||||
memcpy (m_SessionKey, sessionKey, 32);
|
||||
m_Encryption.SetKey (m_SessionKey);
|
||||
|
@ -188,7 +187,8 @@ namespace garlic
|
|||
RAND_bytes (elGamal.preIV, 32); // Pre-IV
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(elGamal.preIV, 32, iv);
|
||||
m_ElGamalEncryption->Encrypt ((uint8_t *)&elGamal, buf, true);
|
||||
i2p::crypto::ElGamalEncryption elGamalEncryption (m_Destination->GetEncryptionPublicKey ());
|
||||
elGamalEncryption.Encrypt ((uint8_t *)&elGamal, buf, true);
|
||||
m_Encryption.SetIV (iv);
|
||||
buf += 514;
|
||||
len += 514;
|
||||
|
@ -315,7 +315,7 @@ namespace garlic
|
|||
{
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
||||
size_t size = 0;
|
||||
if (isDestination && m_Destination)
|
||||
if (isDestination)
|
||||
{
|
||||
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
|
||||
size++;
|
||||
|
|
2
Garlic.h
2
Garlic.h
|
@ -128,6 +128,7 @@ namespace garlic
|
|||
|
||||
GarlicDestination * m_Owner;
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
||||
|
||||
i2p::crypto::AESKey m_SessionKey;
|
||||
std::list<SessionTag> m_SessionTags;
|
||||
int m_NumTags;
|
||||
|
@ -138,7 +139,6 @@ namespace garlic
|
|||
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
||||
|
||||
i2p::crypto::CBCEncryption m_Encryption;
|
||||
std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption;
|
||||
|
||||
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
||||
|
||||
|
|
|
@ -451,26 +451,26 @@ namespace http {
|
|||
s << "<br>\r\n";
|
||||
}
|
||||
|
||||
static void ShowCommands (std::stringstream& s)
|
||||
static void ShowCommands (std::stringstream& s, uint32_t token)
|
||||
{
|
||||
/* commands */
|
||||
s << "<b>Router Commands</b><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "\">Run peer test</a><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
|
||||
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
|
||||
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 << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
|
||||
else
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "\">Accept transit tunnels</a><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
|
||||
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
|
||||
if (Daemon.gracefulShutdownInterval)
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "\">Cancel graceful shutdown</a><br>";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
|
||||
else
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Start graceful shutdown</a><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
|
||||
#endif
|
||||
#ifdef WIN32_APP
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Graceful shutdown</a><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
|
||||
#endif
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "\">Force shutdown</a><br>\r\n";
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
|
||||
}
|
||||
|
||||
static void ShowTransitTunnels (std::stringstream& s)
|
||||
|
@ -709,11 +709,15 @@ namespace http {
|
|||
char b64_creds[64];
|
||||
std::size_t len = 0;
|
||||
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
|
||||
b64_creds[len] = '\0';
|
||||
expected = "Basic ";
|
||||
expected += b64_creds;
|
||||
if (provided == expected)
|
||||
return true;
|
||||
/* if we decoded properly then check credentials */
|
||||
if(len) {
|
||||
b64_creds[len] = '\0';
|
||||
expected = "Basic ";
|
||||
expected += b64_creds;
|
||||
return expected == provided;
|
||||
}
|
||||
/** we decoded wrong so it's not a correct login credential */
|
||||
return false;
|
||||
}
|
||||
|
||||
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
|
||||
|
@ -752,6 +756,7 @@ namespace http {
|
|||
SendReply (res, content);
|
||||
}
|
||||
|
||||
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
||||
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
|
@ -767,7 +772,20 @@ namespace http {
|
|||
else if (page == HTTP_PAGE_TUNNELS)
|
||||
ShowTunnels (s);
|
||||
else if (page == HTTP_PAGE_COMMANDS)
|
||||
ShowCommands (s);
|
||||
{
|
||||
uint32_t token;
|
||||
RAND_bytes ((uint8_t *)&token, 4);
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
|
||||
{
|
||||
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
|
||||
it = m_Tokens.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
m_Tokens[token] = ts;
|
||||
ShowCommands (s, token);
|
||||
}
|
||||
else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
|
||||
ShowTransitTunnels (s);
|
||||
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
||||
|
@ -794,13 +812,19 @@ namespace http {
|
|||
void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||
{
|
||||
std::map<std::string, std::string> params;
|
||||
std::string cmd("");
|
||||
URL url;
|
||||
|
||||
url.parse(req.uri);
|
||||
url.parse_query(params);
|
||||
cmd = params["cmd"];
|
||||
|
||||
std::string token = params["token"];
|
||||
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
|
||||
{
|
||||
ShowError(s, "Invalid token");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cmd = params["cmd"];
|
||||
if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
|
||||
i2p::transport::transports.PeerTest ();
|
||||
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
|
||||
|
|
20
HTTPServer.h
20
HTTPServer.h
|
@ -1,10 +1,20 @@
|
|||
#ifndef HTTP_SERVER_H__
|
||||
#define HTTP_SERVER_H__
|
||||
|
||||
namespace i2p {
|
||||
namespace http {
|
||||
extern const char *itoopieFavicon;
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <boost/asio.hpp>
|
||||
#include "HTTP.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
|
||||
|
||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||
{
|
||||
|
@ -35,6 +45,8 @@ namespace http {
|
|||
bool needAuth;
|
||||
std::string user;
|
||||
std::string pass;
|
||||
|
||||
static std::map<uint32_t, uint32_t> m_Tokens; // token->timestamp in seconds
|
||||
};
|
||||
|
||||
class HTTPServer
|
||||
|
|
|
@ -92,7 +92,9 @@ namespace client
|
|||
m_Stream->Close ();
|
||||
m_Stream.reset ();
|
||||
}
|
||||
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send); // avoid RST
|
||||
m_Socket->close ();
|
||||
|
||||
Done(shared_from_this ());
|
||||
}
|
||||
|
||||
|
@ -107,9 +109,11 @@ namespace client
|
|||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -173,11 +177,13 @@ namespace client
|
|||
{
|
||||
if (bytes_transferred > 0)
|
||||
Write (m_StreamBuffer, bytes_transferred); // postpone termination
|
||||
else
|
||||
else if (ecode == boost::asio::error::timed_out && m_Stream->IsOpen ())
|
||||
StreamReceive ();
|
||||
else
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
Terminate ();
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
Write (m_StreamBuffer, bytes_transferred);
|
||||
|
@ -540,9 +546,13 @@ namespace client
|
|||
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
||||
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
||||
std::remove_if(m_Sessions.begin(), m_Sessions.end(), [now, delta](const UDPSession * u) -> bool {
|
||||
return now - u->LastActivity >= delta;
|
||||
});
|
||||
auto itr = m_Sessions.begin();
|
||||
while(itr != m_Sessions.end()) {
|
||||
if(now - (*itr)->LastActivity >= delta )
|
||||
itr = m_Sessions.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
UDPSession * I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)
|
||||
|
|
14
Identity.cpp
14
Identity.cpp
|
@ -593,11 +593,25 @@ namespace data
|
|||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
|
||||
{
|
||||
XORMetric m;
|
||||
#if defined(__AVX__) // for AVX
|
||||
__asm__
|
||||
(
|
||||
"vmovups %1, %%ymm0 \n"
|
||||
"vmovups %2, %%ymm1 \n"
|
||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
||||
"vmovups %%ymm1, %0 \n"
|
||||
: "=m"(*m.metric)
|
||||
: "m"(*key1), "m"(*key2)
|
||||
: "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler
|
||||
);
|
||||
#else
|
||||
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
|
||||
m.metric_ll[0] = hash1[0] ^ hash2[0];
|
||||
m.metric_ll[1] = hash1[1] ^ hash2[1];
|
||||
m.metric_ll[2] = hash1[2] ^ hash2[2];
|
||||
m.metric_ll[3] = hash1[3] ^ hash2[3];
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace data
|
|||
if (m_StoreLeases)
|
||||
{
|
||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
||||
if (!ret.second) *(*ret.first) = lease; // update existing
|
||||
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
|
||||
(*ret.first)->isUpdated = true;
|
||||
// check if lease's gateway is in our netDb
|
||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||
|
|
9
Makefile
9
Makefile
|
@ -9,10 +9,11 @@ DEPS := obj/make.dep
|
|||
|
||||
include filelist.mk
|
||||
|
||||
USE_AESNI := yes
|
||||
USE_STATIC := no
|
||||
USE_MESHNET := no
|
||||
USE_UPNP := no
|
||||
USE_AESNI := yes
|
||||
USE_AVX := yes
|
||||
USE_STATIC := no
|
||||
USE_MESHNET := no
|
||||
USE_UPNP := no
|
||||
|
||||
ifeq ($(WEBSOCKETS),1)
|
||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
||||
|
|
|
@ -60,7 +60,14 @@ ifeq ($(USE_AESNI),yes)
|
|||
ifeq ($(IS_64),1)
|
||||
#check if AES-NI is supported by CPU
|
||||
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
||||
CPU_FLAGS = -maes -DAESNI
|
||||
CPU_FLAGS += -maes -DAESNI
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),yes)
|
||||
#check if AVX supported by CPU
|
||||
ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0)
|
||||
CPU_FLAGS += -mavx
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -39,9 +39,13 @@ endif
|
|||
|
||||
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
||||
ifeq ($(USE_AESNI),1)
|
||||
CPU_FLAGS = -maes -DAESNI
|
||||
CPU_FLAGS += -maes -DAESNI
|
||||
else
|
||||
CPU_FLAGS = -msse
|
||||
CPU_FLAGS += -msse
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),1)
|
||||
CPU_FLAGS += -mavx
|
||||
endif
|
||||
|
||||
ifeq ($(USE_ASLR),yes)
|
||||
|
|
13
Makefile.osx
13
Makefile.osx
|
@ -3,21 +3,26 @@ CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
|
|||
#CXXFLAGS = -g -O2 -Wall -std=c++11
|
||||
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz -lcrypto -lssl /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||
else
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
LDFLAGS += -ldl
|
||||
CXXFLAGS += -DUSE_UPNP
|
||||
endif
|
||||
|
||||
# OSX Notes
|
||||
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
|
||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
CXXFLAGS += -maes -DAESNI
|
||||
endif
|
||||
|
||||
ifeq ($(USE_AVX),yes)
|
||||
CXXFLAGS += -mavx
|
||||
endif
|
||||
|
||||
# Disabled, since it will be the default make rule. I think its better
|
||||
# to define the default rule in Makefile and not Makefile.<ostype> - torkel
|
||||
#install: all
|
||||
|
|
53
NetDb.cpp
53
NetDb.cpp
|
@ -118,7 +118,6 @@ namespace data
|
|||
{
|
||||
SaveUpdated ();
|
||||
ManageLeaseSets ();
|
||||
ManageLookupResponses ();
|
||||
}
|
||||
lastSave = ts;
|
||||
}
|
||||
|
@ -857,33 +856,17 @@ namespace data
|
|||
}
|
||||
|
||||
if (!replyMsg)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
||||
// find or cleate response
|
||||
std::vector<IdentHash> closestFloodfills;
|
||||
bool found = false;
|
||||
if (!numExcluded)
|
||||
{
|
||||
auto it = m_LookupResponses.find (ident);
|
||||
if (it != m_LookupResponses.end ())
|
||||
{
|
||||
closestFloodfills = it->second.first;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
std::set<IdentHash> excludedRouters;
|
||||
const uint8_t * exclude_ident = excluded;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
excludedRouters.insert (exclude_ident);
|
||||
exclude_ident += 32;
|
||||
}
|
||||
closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
|
||||
if (!numExcluded) // save if no excluded
|
||||
m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ());
|
||||
{
|
||||
std::set<IdentHash> excludedRouters;
|
||||
const uint8_t * exclude_ident = excluded;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
excludedRouters.insert (exclude_ident);
|
||||
exclude_ident += 32;
|
||||
}
|
||||
auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
|
||||
if (closestFloodfills.empty ())
|
||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
||||
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
||||
}
|
||||
}
|
||||
|
@ -929,7 +912,6 @@ namespace data
|
|||
|
||||
uint8_t randomHash[32];
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
std::set<const RouterInfo *> floodfills;
|
||||
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
|
||||
for (int i = 0; i < numDestinations; i++)
|
||||
{
|
||||
|
@ -941,9 +923,8 @@ namespace data
|
|||
return;
|
||||
}
|
||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||
if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once
|
||||
if (floodfill)
|
||||
{
|
||||
floodfills.insert (floodfill.get ());
|
||||
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||
throughTunnels = false;
|
||||
if (throughTunnels)
|
||||
|
@ -1191,17 +1172,5 @@ namespace data
|
|||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::ManageLookupResponses ()
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_LookupResponses.begin (); it != m_LookupResponses.end ();)
|
||||
{
|
||||
if (ts > it->second.second + 180) // 3 minutes
|
||||
it = m_LookupResponses.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
NetDb.h
4
NetDb.h
|
@ -112,7 +112,6 @@ namespace data
|
|||
void Publish ();
|
||||
void ManageLeaseSets ();
|
||||
void ManageRequests ();
|
||||
void ManageLookupResponses ();
|
||||
|
||||
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
|
||||
|
||||
|
@ -143,8 +142,7 @@ namespace data
|
|||
|
||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||
|
||||
std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp)
|
||||
|
||||
|
||||
/** true if in hidden mode */
|
||||
bool m_HiddenMode;
|
||||
|
|
|
@ -167,19 +167,19 @@ namespace data
|
|||
{
|
||||
uint8_t supportedTransports = 0;
|
||||
bool isValidAddress = true;
|
||||
Address address;
|
||||
s.read ((char *)&address.cost, sizeof (address.cost));
|
||||
s.read ((char *)&address.date, sizeof (address.date));
|
||||
auto address = std::make_shared<Address>();
|
||||
s.read ((char *)&address->cost, sizeof (address->cost));
|
||||
s.read ((char *)&address->date, sizeof (address->date));
|
||||
char transportStyle[5];
|
||||
ReadString (transportStyle, 5, s);
|
||||
if (!strcmp (transportStyle, "NTCP"))
|
||||
address.transportStyle = eTransportNTCP;
|
||||
address->transportStyle = eTransportNTCP;
|
||||
else if (!strcmp (transportStyle, "SSU"))
|
||||
address.transportStyle = eTransportSSU;
|
||||
address->transportStyle = eTransportSSU;
|
||||
else
|
||||
address.transportStyle = eTransportUnknown;
|
||||
address.port = 0;
|
||||
address.mtu = 0;
|
||||
address->transportStyle = eTransportUnknown;
|
||||
address->port = 0;
|
||||
address->mtu = 0;
|
||||
uint16_t size, r = 0;
|
||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||
size = be16toh (size);
|
||||
|
@ -194,35 +194,35 @@ namespace data
|
|||
if (!strcmp (key, "host"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
address.host = boost::asio::ip::address::from_string (value, ecode);
|
||||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||
if (ecode)
|
||||
{
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
if (address->transportStyle == eTransportNTCP)
|
||||
{
|
||||
supportedTransports |= eNTCPV4; // TODO:
|
||||
address.addressString = value;
|
||||
address->addressString = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
supportedTransports |= eSSUV4; // TODO:
|
||||
address.addressString = value;
|
||||
address->addressString = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add supported protocol
|
||||
if (address.host.is_v4 ())
|
||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||
if (address->host.is_v4 ())
|
||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||
else
|
||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "port"))
|
||||
address.port = boost::lexical_cast<int>(value);
|
||||
address->port = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "mtu"))
|
||||
address.mtu = boost::lexical_cast<int>(value);
|
||||
address->mtu = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "key"))
|
||||
Base64ToByteStream (value, strlen (value), address.key, 32);
|
||||
Base64ToByteStream (value, strlen (value), address->key, 32);
|
||||
else if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
else if (key[0] == 'i')
|
||||
|
@ -237,9 +237,9 @@ namespace data
|
|||
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
|
||||
if (s) continue; else return;
|
||||
}
|
||||
if (index >= address.introducers.size ())
|
||||
address.introducers.resize (index + 1);
|
||||
Introducer& introducer = address.introducers.at (index);
|
||||
if (index >= address->introducers.size ())
|
||||
address->introducers.resize (index + 1);
|
||||
Introducer& introducer = address->introducers.at (index);
|
||||
if (!strcmp (key, "ihost"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
|
@ -256,7 +256,7 @@ namespace data
|
|||
}
|
||||
if (isValidAddress)
|
||||
{
|
||||
addresses->push_back(std::make_shared<Address>(address));
|
||||
addresses->push_back(address);
|
||||
m_SupportedTransports |= supportedTransports;
|
||||
}
|
||||
}
|
||||
|
|
121
SAM.cpp
121
SAM.cpp
|
@ -54,11 +54,7 @@ namespace client
|
|||
case eSAMSocketTypeAcceptor:
|
||||
{
|
||||
if (m_Session)
|
||||
{
|
||||
m_Session->DelSocket (shared_from_this ());
|
||||
if (m_Session->localDestination)
|
||||
m_Session->localDestination->StopAcceptingStreams ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -289,6 +285,11 @@ namespace client
|
|||
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||
}
|
||||
else
|
||||
{
|
||||
// start accepting streams because we're not a datagram session
|
||||
m_Session->localDestination->AcceptStreams (std::bind (&SAMSession::AcceptI2P, m_Session, std::placeholders::_1));
|
||||
}
|
||||
|
||||
if (m_Session->localDestination->IsReady ())
|
||||
SendSessionCreateReplyOk ();
|
||||
|
@ -401,20 +402,25 @@ namespace client
|
|||
m_Session = m_Owner.FindSession (id);
|
||||
if (m_Session)
|
||||
{
|
||||
if (!m_Session->localDestination->IsAcceptingStreams ())
|
||||
{
|
||||
m_SocketType = eSAMSocketTypeAcceptor;
|
||||
m_Session->AddSocket (shared_from_this ());
|
||||
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
|
||||
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||
}
|
||||
else
|
||||
SendMessageReply (SAM_STREAM_STATUS_I2P_ERROR, strlen(SAM_STREAM_STATUS_I2P_ERROR), true);
|
||||
m_SocketType = eSAMSocketTypeAcceptor;
|
||||
m_Session->AddSocket (shared_from_this ());
|
||||
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||
}
|
||||
else
|
||||
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||
}
|
||||
|
||||
void SAMSocket::Accept(std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
if(stream) {
|
||||
m_SocketType = eSAMSocketTypeStream;
|
||||
HandleI2PAccept(stream);
|
||||
} else {
|
||||
SendMessageReply (SAM_STREAM_STATUS_I2P_ERROR, strlen(SAM_STREAM_STATUS_I2P_ERROR), true);
|
||||
auto s = shared_from_this ();
|
||||
m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||
}
|
||||
}
|
||||
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
||||
|
@ -577,8 +583,8 @@ namespace client
|
|||
{
|
||||
if (!ecode)
|
||||
s->Receive ();
|
||||
else
|
||||
s->Terminate ();
|
||||
else
|
||||
s->m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -622,10 +628,16 @@ namespace client
|
|||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
|
||||
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination
|
||||
else
|
||||
Terminate ();
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||
}
|
||||
}
|
||||
else
|
||||
Terminate ();
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -653,10 +665,6 @@ namespace client
|
|||
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
|
||||
m_Stream = stream;
|
||||
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
||||
auto session = m_Owner.FindSession (m_ID);
|
||||
if (session)
|
||||
session->localDestination->StopAcceptingStreams ();
|
||||
m_SocketType = eSAMSocketTypeStream;
|
||||
if (!m_IsSilent)
|
||||
{
|
||||
// get remote peer address
|
||||
|
@ -698,26 +706,76 @@ namespace client
|
|||
}
|
||||
|
||||
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
|
||||
localDestination (dest)
|
||||
localDestination (dest),
|
||||
m_BacklogPumper(dest->GetService())
|
||||
{
|
||||
PumpBacklog();
|
||||
}
|
||||
|
||||
SAMSession::~SAMSession ()
|
||||
|
||||
void SAMSession::AcceptI2P(std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
CloseStreams();
|
||||
i2p::client::context.DeleteLocalDestination (localDestination);
|
||||
if(!stream) return; // fail
|
||||
std::unique_lock<std::mutex> lock(m_SocketsMutex);
|
||||
if(m_Backlog.size() > SAM_MAX_ACCEPT_BACKLOG) {
|
||||
stream->Close();
|
||||
return;
|
||||
}
|
||||
m_Backlog.push_back(stream);
|
||||
}
|
||||
|
||||
void SAMSession::PumpBacklog()
|
||||
{
|
||||
// pump backlog every 100ms
|
||||
boost::posix_time::milliseconds dlt(100);
|
||||
m_BacklogPumper.expires_from_now(dlt);
|
||||
m_BacklogPumper.async_wait(std::bind(&SAMSession::HandlePumpBacklog, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
std::shared_ptr<SAMSocket> SAMSession::FindAcceptor()
|
||||
{
|
||||
for (auto & sock : m_Sockets) {
|
||||
auto t = sock->GetSocketType();
|
||||
if(t == eSAMSocketTypeAcceptor) {
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SAMSession::HandlePumpBacklog(const boost::system::error_code & ec)
|
||||
{
|
||||
if(ec) return;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_SocketsMutex);
|
||||
auto itr = m_Backlog.begin();
|
||||
while(itr != m_Backlog.end()) {
|
||||
auto sock = FindAcceptor();
|
||||
if (sock) {
|
||||
sock->Accept(*itr);
|
||||
itr = m_Backlog.erase(itr);
|
||||
} else {
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
PumpBacklog();
|
||||
}
|
||||
|
||||
void SAMSession::CloseStreams ()
|
||||
{
|
||||
{
|
||||
m_BacklogPumper.cancel();
|
||||
localDestination->GetService().post([&] () {
|
||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
||||
for (auto& sock : m_Sockets) {
|
||||
sock->CloseStream();
|
||||
}
|
||||
}
|
||||
// XXX: should this be done inside locked parts?
|
||||
m_Sockets.clear();
|
||||
for(auto & stream : m_Backlog) {
|
||||
stream->Close();
|
||||
}
|
||||
m_Sockets.clear();
|
||||
m_Backlog.clear();
|
||||
i2p::client::context.DeleteLocalDestination (localDestination);
|
||||
});
|
||||
}
|
||||
|
||||
SAMBridge::SAMBridge (const std::string& address, int port):
|
||||
|
@ -828,8 +886,9 @@ namespace client
|
|||
auto session = std::make_shared<SAMSession>(localDestination);
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
auto ret = m_Sessions.insert (std::make_pair(id, session));
|
||||
if (!ret.second)
|
||||
if (!ret.second) {
|
||||
LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
|
||||
}
|
||||
return ret.first->second;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
19
SAM.h
19
SAM.h
|
@ -20,7 +20,8 @@ namespace client
|
|||
{
|
||||
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
|
||||
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
|
||||
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
|
||||
const int SAM_MAX_ACCEPT_BACKLOG = 50;
|
||||
const char SAM_HANDSHAKE[] = "HELLO VERSION";
|
||||
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
|
||||
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
|
||||
|
@ -84,6 +85,8 @@ namespace client
|
|||
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
||||
SAMSocketType GetSocketType () const { return m_SocketType; };
|
||||
|
||||
void Accept(std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
private:
|
||||
|
||||
void Terminate ();
|
||||
|
@ -134,6 +137,8 @@ namespace client
|
|||
struct SAMSession
|
||||
{
|
||||
std::shared_ptr<ClientDestination> localDestination;
|
||||
boost::asio::deadline_timer m_BacklogPumper;
|
||||
std::list<std::shared_ptr<i2p::stream::Stream> > m_Backlog;
|
||||
std::list<std::shared_ptr<SAMSocket> > m_Sockets;
|
||||
std::mutex m_SocketsMutex;
|
||||
|
||||
|
@ -158,9 +163,15 @@ namespace client
|
|||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
SAMSession (std::shared_ptr<ClientDestination> dest);
|
||||
~SAMSession ();
|
||||
|
||||
SAMSession (std::shared_ptr<ClientDestination> dest);
|
||||
|
||||
void AcceptI2P(std::shared_ptr<i2p::stream::Stream> stream);
|
||||
|
||||
std::shared_ptr<SAMSocket> FindAcceptor();
|
||||
|
||||
void PumpBacklog();
|
||||
void HandlePumpBacklog(const boost::system::error_code & ec);
|
||||
|
||||
void CloseStreams ();
|
||||
};
|
||||
|
|
|
@ -1101,7 +1101,7 @@ namespace transport
|
|||
{
|
||||
// we are Alice
|
||||
LogPrint (eLogDebug, "SSU: sending peer test");
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (i2p::context.SupportsV4 ());
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace tunnel
|
|||
if (!isFollowOnFragment) // create new incomlete message
|
||||
{
|
||||
m.nextFragmentNum = 1;
|
||||
m.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
|
||||
if (ret.second)
|
||||
HandleOutOfSequenceFragments (msgID, ret.first->second);
|
||||
|
@ -284,6 +285,14 @@ namespace tunnel
|
|||
else
|
||||
++it;
|
||||
}
|
||||
// incomplete messages
|
||||
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
||||
{
|
||||
if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace tunnel
|
|||
{
|
||||
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
||||
{
|
||||
uint64_t receiveTime; // milliseconds since epoch
|
||||
uint8_t nextFragmentNum;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define I2Pd_AppName "i2pd"
|
||||
#define I2Pd_ver "2.10.1"
|
||||
#define I2Pd_ver "2.11.0"
|
||||
#define I2Pd_Publisher "PurpleI2P"
|
||||
|
||||
[Setup]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.purplei2p.i2pd"
|
||||
android:versionCode="1"
|
||||
android:versionName="2.10.1">
|
||||
android:versionName="2.11.0">
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
|
|
@ -59,6 +59,7 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
|
|||
../../TunnelPool.cpp \
|
||||
../../Timestamp.cpp \
|
||||
../../Event.cpp \
|
||||
../../BloomFilter.cpp \
|
||||
../../util.cpp \
|
||||
../../i2pd.cpp ../../UPnP.cpp
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
|||
set ( CMAKE_SOURCE_DIR ".." )
|
||||
|
||||
set (LIBI2PD_SRC
|
||||
"${CMAKE_SOURCE_DIR}/BloomFilter.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Config.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Crypto.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/Garlic.cpp"
|
||||
|
|
12
debian/changelog
vendored
12
debian/changelog
vendored
|
@ -1,3 +1,15 @@
|
|||
i2pd (2.11.0-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.11.0/0.9.28
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sun, 18 Dec 2016 21:01:30 +0000
|
||||
|
||||
i2pd (2.10.2-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.10.2
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sun, 4 Dec 2016 19:38:30 +0000
|
||||
|
||||
i2pd (2.10.1-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.10.1
|
||||
|
|
16
debian/patches/01-tune-build-opts.patch
vendored
16
debian/patches/01-tune-build-opts.patch
vendored
|
@ -1,16 +1,18 @@
|
|||
diff --git a/Makefile b/Makefile
|
||||
index b6fc795..abc3ace 100644
|
||||
index bdadfe0..2f71eec 100644
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
|
||||
|
||||
include filelist.mk
|
||||
|
||||
-USE_AESNI := yes
|
||||
+USE_AESNI := no
|
||||
USE_STATIC := no
|
||||
USE_MESHNET := no
|
||||
USE_UPNP := no
|
||||
-USE_AESNI := yes
|
||||
+USE_AESNI := no
|
||||
-USE_AVX := yes
|
||||
+USE_AVX := no
|
||||
USE_STATIC := no
|
||||
USE_MESHNET := no
|
||||
USE_UPNP := no
|
||||
|
||||
ifeq ($(WEBSOCKETS),1)
|
||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
LIB_SRC = \
|
||||
Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \
|
||||
BloomFilter.cpp Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \
|
||||
Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
|
||||
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
|
||||
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="2" android:installLocation="auto">
|
||||
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.11.0" android:versionCode="2" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<!-- <application android:hardwareAccelerated="true" -->
|
||||
|
|
|
@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
|
||||
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
|
||||
../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \
|
||||
../../Event.cpp ../../i2pd.cpp
|
||||
../../Event.cpp ../../BloomFiler.cpp ../../i2pd.cpp
|
||||
|
||||
HEADERS += DaemonQT.h mainwindow.h \
|
||||
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
|
||||
|
@ -50,7 +50,8 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||
../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
|
||||
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
|
||||
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
|
||||
../../util.h ../../version.h ../../Gzip.h ../../Tag.h ../../Event.h
|
||||
../../util.h ../../version.h ../../Gzip.h ../../Tag.h \
|
||||
../../BloomFiler.h ../../Event.h
|
||||
|
||||
FORMS += mainwindow.ui
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||
|
||||
#define I2PD_VERSION_MAJOR 2
|
||||
#define I2PD_VERSION_MINOR 10
|
||||
#define I2PD_VERSION_MICRO 1
|
||||
#define I2PD_VERSION_MINOR 11
|
||||
#define I2PD_VERSION_MICRO 0
|
||||
#define I2PD_VERSION_PATCH 0
|
||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||
#define VERSION I2PD_VERSION
|
||||
|
@ -21,7 +21,7 @@
|
|||
|
||||
#define I2P_VERSION_MAJOR 0
|
||||
#define I2P_VERSION_MINOR 9
|
||||
#define I2P_VERSION_MICRO 27
|
||||
#define I2P_VERSION_MICRO 28
|
||||
#define I2P_VERSION_PATCH 0
|
||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||
|
||||
|
|
Loading…
Reference in a new issue