mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-02 11:04:00 +01:00
commit
fc08d15a79
|
@ -842,7 +842,7 @@ namespace client
|
||||||
else
|
else
|
||||||
memset (response + 8, 0, 32); // not found
|
memset (response + 8, 0, 32); // not found
|
||||||
memset (response + 40, 0, 4); // set expiration time to zero
|
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)
|
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,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# 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
|
## [2.10.1] - 2016-11-07
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed some performance issues for Windows and Android
|
- Fixed some performance issues for Windows and Android
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace config {
|
||||||
"https://i2p.mooo.com/netDb/,"
|
"https://i2p.mooo.com/netDb/,"
|
||||||
"https://netdb.i2p2.no/,"
|
"https://netdb.i2p2.no/,"
|
||||||
"https://us.reseed.i2p2.no:444/,"
|
"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://i2p-0.manas.ca:8443/,"
|
||||||
"https://reseed.i2p.vzaws.com:8443/,"
|
"https://reseed.i2p.vzaws.com:8443/,"
|
||||||
"https://download.xxlspeed.com/,"
|
"https://download.xxlspeed.com/,"
|
||||||
|
|
68
Crypto.cpp
68
Crypto.cpp
|
@ -386,44 +386,68 @@ namespace crypto
|
||||||
// HMAC
|
// HMAC
|
||||||
const uint64_t IPAD = 0x3636363636363636;
|
const uint64_t IPAD = 0x3636363636363636;
|
||||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
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)
|
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
|
||||||
// key is 32 bytes
|
// key is 32 bytes
|
||||||
// digest is 16 bytes
|
// digest is 16 bytes
|
||||||
// block size is 64 bytes
|
// block size is 64 bytes
|
||||||
{
|
{
|
||||||
uint64_t buf[256];
|
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
|
// ikeypad
|
||||||
buf[0] = key.GetLL ()[0] ^ IPAD;
|
buf[0] = key.GetLL ()[0] ^ IPAD;
|
||||||
buf[1] = key.GetLL ()[1] ^ IPAD;
|
buf[1] = key.GetLL ()[1] ^ IPAD;
|
||||||
buf[2] = key.GetLL ()[2] ^ IPAD;
|
buf[2] = key.GetLL ()[2] ^ IPAD;
|
||||||
buf[3] = key.GetLL ()[3] ^ IPAD;
|
buf[3] = key.GetLL ()[3] ^ IPAD;
|
||||||
buf[4] = IPAD;
|
buf[4] = IPAD;
|
||||||
buf[5] = IPAD;
|
buf[5] = IPAD;
|
||||||
buf[6] = IPAD;
|
buf[6] = IPAD;
|
||||||
buf[7] = 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
|
// concatenate with msg
|
||||||
memcpy (buf + 8, msg, len);
|
memcpy (buf + 8, msg, len);
|
||||||
// calculate first hash
|
// calculate first hash
|
||||||
uint8_t hash[16]; // MD5
|
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
|
||||||
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);
|
|
||||||
|
|
||||||
// calculate digest
|
// calculate digest
|
||||||
MD5((uint8_t *)buf, 96, digest);
|
MD5((uint8_t *)hash, 96, digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AES
|
// AES
|
||||||
|
|
13
Crypto.h
13
Crypto.h
|
@ -76,7 +76,18 @@ namespace crypto
|
||||||
|
|
||||||
void operator^=(const ChipherBlock& other) // XOR
|
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__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[buf]), %%xmm0 \n"
|
"movups (%[buf]), %%xmm0 \n"
|
||||||
|
|
382
Datagram.cpp
382
Datagram.cpp
|
@ -22,9 +22,9 @@ namespace datagram
|
||||||
{
|
{
|
||||||
m_Sessions.clear();
|
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;
|
auto owner = m_Owner;
|
||||||
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
||||||
uint8_t * buf = v.data();
|
uint8_t * buf = v.data();
|
||||||
|
@ -45,8 +45,7 @@ namespace datagram
|
||||||
owner->Sign (buf1, len, signature);
|
owner->Sign (buf1, len, signature);
|
||||||
|
|
||||||
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
|
||||||
auto session = ObtainSession(ident);
|
ObtainSession(identity)->SendMsg(msg);
|
||||||
session->SendMsg(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,6 +68,8 @@ namespace datagram
|
||||||
|
|
||||||
if (verified)
|
if (verified)
|
||||||
{
|
{
|
||||||
|
auto h = identity.GetIdentHash();
|
||||||
|
ObtainSession(h)->Ack();
|
||||||
auto r = FindReceiver(toPort);
|
auto r = FindReceiver(toPort);
|
||||||
if(r)
|
if(r)
|
||||||
r(identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
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::shared_ptr<DatagramSession> session = nullptr;
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
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()) {
|
if (itr == m_Sessions.end()) {
|
||||||
// not found, create new session
|
// not found, create new session
|
||||||
session = std::make_shared<DatagramSession>(m_Owner, ident);
|
session = std::make_shared<DatagramSession>(m_Owner, identity);
|
||||||
m_Sessions[ident] = session;
|
m_Sessions[identity] = session;
|
||||||
} else {
|
} else {
|
||||||
session = itr->second;
|
session = itr->second;
|
||||||
}
|
}
|
||||||
|
@ -164,13 +165,13 @@ namespace datagram
|
||||||
}
|
}
|
||||||
|
|
||||||
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
|
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
|
||||||
const i2p::data::IdentHash & remoteIdent) :
|
const i2p::data::IdentHash & remoteIdent) :
|
||||||
m_LocalDestination(localDestination),
|
m_LocalDestination(localDestination),
|
||||||
m_RemoteIdentity(remoteIdent),
|
m_RemoteIdent(remoteIdent),
|
||||||
m_LastUse(i2p::util::GetMillisecondsSinceEpoch ()),
|
m_SendQueueTimer(localDestination->GetService())
|
||||||
m_LastPathChange(0),
|
|
||||||
m_LastSuccess(0)
|
|
||||||
{
|
{
|
||||||
|
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
ScheduleFlushSendQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
|
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
|
||||||
|
@ -184,262 +185,149 @@ namespace datagram
|
||||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||||
{
|
{
|
||||||
if(!m_RoutingSession)
|
if(!m_RoutingSession)
|
||||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess);
|
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||||
|
|
||||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||||
if (!routingPath)
|
if (!routingPath)
|
||||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess);
|
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||||
auto lease = routingPath->remoteLease;
|
auto lease = routingPath->remoteLease;
|
||||||
auto tunnel = routingPath->outboundTunnel;
|
auto tunnel = routingPath->outboundTunnel;
|
||||||
if(lease)
|
if(lease)
|
||||||
{
|
{
|
||||||
if(tunnel)
|
if(tunnel)
|
||||||
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess);
|
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||||
else
|
else
|
||||||
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse, m_LastSuccess);
|
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse);
|
||||||
}
|
}
|
||||||
else if(tunnel)
|
else if(tunnel)
|
||||||
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess);
|
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||||
else
|
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)
|
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
|
for (const auto & msg : m_SendQueue)
|
||||||
if(m_RemoteLeaseSet) m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
UpdateLeaseSet(msg);
|
auto m = m_RoutingSession->WrapSingleMessage(msg);
|
||||||
return;
|
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?
|
m_SendQueue.clear();
|
||||||
if(m_RoutingSession)
|
ScheduleFlushSendQueue();
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path)
|
void DatagramSession::ScheduleFlushSendQueue()
|
||||||
{
|
{
|
||||||
if(m_RoutingSession == nullptr && m_RemoteLeaseSet)
|
boost::posix_time::milliseconds dlt(100);
|
||||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
m_SendQueueTimer.expires_from_now(dlt);
|
||||||
if(!m_RoutingSession) return;
|
m_SendQueueTimer.async_wait([&](const boost::system::error_code & ec) { if(ec) return; FlushSendQueue(); });
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
72
Datagram.h
72
Datagram.h
|
@ -31,29 +31,33 @@ namespace datagram
|
||||||
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
|
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
|
||||||
// milliseconds minimum time between path switches
|
// milliseconds minimum time between path switches
|
||||||
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
|
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
|
class DatagramSession
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DatagramSession(i2p::client::ClientDestination * localDestination,
|
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 */
|
/** send an i2np message to remote endpoint for this session */
|
||||||
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
||||||
/** get the last time in milliseconds for when we used this datagram session */
|
/** get the last time in milliseconds for when we used this datagram session */
|
||||||
uint64_t LastActivity() const { return m_LastUse; }
|
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
|
struct Info
|
||||||
{
|
{
|
||||||
std::shared_ptr<const i2p::data::IdentHash> IBGW;
|
std::shared_ptr<const i2p::data::IdentHash> IBGW;
|
||||||
std::shared_ptr<const i2p::data::IdentHash> OBEP;
|
std::shared_ptr<const i2p::data::IdentHash> OBEP;
|
||||||
const uint64_t activity;
|
const uint64_t activity;
|
||||||
const uint64_t success;
|
|
||||||
Info() : IBGW(nullptr), OBEP(nullptr), activity(0), success(0) {}
|
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
|
||||||
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a, const uint64_t s) :
|
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
|
||||||
activity(a),
|
activity(a) {
|
||||||
success(s) {
|
|
||||||
if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
|
if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
|
||||||
else IBGW = nullptr;
|
else IBGW = nullptr;
|
||||||
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
|
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
|
||||||
|
@ -63,44 +67,28 @@ namespace datagram
|
||||||
|
|
||||||
Info GetSessionInfo() const;
|
Info GetSessionInfo() const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** update our routing path we are using, mark that we have changed paths */
|
void FlushSendQueue();
|
||||||
void UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path);
|
void ScheduleFlushSendQueue();
|
||||||
|
|
||||||
/** return true if we should switch routing paths because of path lifetime or timeout otherwise false */
|
void HandleSend(std::shared_ptr<I2NPMessage> msg);
|
||||||
bool ShouldUpdateRoutingPath() const;
|
|
||||||
|
|
||||||
/** return true if we should switch the lease for out routing path otherwise return false */
|
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
|
||||||
bool ShouldSwitchLease() const;
|
|
||||||
|
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
||||||
/** 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();
|
|
||||||
|
|
||||||
/** 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:
|
private:
|
||||||
i2p::client::ClientDestination * m_LocalDestination;
|
i2p::client::ClientDestination * m_LocalDestination;
|
||||||
i2p::data::IdentHash m_RemoteIdentity;
|
i2p::data::IdentHash m_RemoteIdent;
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||||
// Ident hash of IBGW that are invalid
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||||
std::vector<i2p::data::IdentHash> m_InvalidIBGW;
|
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
||||||
uint64_t m_LastUse;
|
boost::asio::deadline_timer m_SendQueueTimer;
|
||||||
uint64_t m_LastPathChange;
|
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
uint64_t m_LastSuccess;
|
uint64_t m_LastUse;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||||
|
@ -112,9 +100,9 @@ namespace datagram
|
||||||
|
|
||||||
|
|
||||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
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 HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||||
|
@ -130,7 +118,7 @@ namespace datagram
|
||||||
|
|
||||||
private:
|
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);
|
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
|
else // duplicate
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
|
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)
|
if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
|
||||||
|
{
|
||||||
|
// something went wrong
|
||||||
m_LeaseSetRequests.erase (ret.first);
|
m_LeaseSetRequests.erase (ret.first);
|
||||||
if (requestComplete) requestComplete (nullptr);
|
if (requestComplete) requestComplete (nullptr);
|
||||||
|
}
|
||||||
|
else if (requestComplete)
|
||||||
|
ret.first->second->requestComplete.push_back (requestComplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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):
|
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
|
||||||
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
|
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
|
||||||
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
|
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
|
||||||
m_LeaseSetUpdateMsgID (0),
|
m_LeaseSetUpdateMsgID (0)
|
||||||
m_ElGamalEncryption (new i2p::crypto::ElGamalEncryption (destination->GetEncryptionPublicKey ()))
|
|
||||||
{
|
{
|
||||||
// create new session tags and session key
|
// create new session tags and session key
|
||||||
RAND_bytes (m_SessionKey, 32);
|
RAND_bytes (m_SessionKey, 32);
|
||||||
|
@ -29,7 +28,7 @@ namespace garlic
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
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);
|
memcpy (m_SessionKey, sessionKey, 32);
|
||||||
m_Encryption.SetKey (m_SessionKey);
|
m_Encryption.SetKey (m_SessionKey);
|
||||||
|
@ -188,7 +187,8 @@ namespace garlic
|
||||||
RAND_bytes (elGamal.preIV, 32); // Pre-IV
|
RAND_bytes (elGamal.preIV, 32); // Pre-IV
|
||||||
uint8_t iv[32]; // IV is first 16 bytes
|
uint8_t iv[32]; // IV is first 16 bytes
|
||||||
SHA256(elGamal.preIV, 32, iv);
|
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);
|
m_Encryption.SetIV (iv);
|
||||||
buf += 514;
|
buf += 514;
|
||||||
len += 514;
|
len += 514;
|
||||||
|
@ -315,7 +315,7 @@ namespace garlic
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
if (isDestination && m_Destination)
|
if (isDestination)
|
||||||
{
|
{
|
||||||
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
|
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
|
||||||
size++;
|
size++;
|
||||||
|
|
2
Garlic.h
2
Garlic.h
|
@ -128,6 +128,7 @@ namespace garlic
|
||||||
|
|
||||||
GarlicDestination * m_Owner;
|
GarlicDestination * m_Owner;
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
||||||
|
|
||||||
i2p::crypto::AESKey m_SessionKey;
|
i2p::crypto::AESKey m_SessionKey;
|
||||||
std::list<SessionTag> m_SessionTags;
|
std::list<SessionTag> m_SessionTags;
|
||||||
int m_NumTags;
|
int m_NumTags;
|
||||||
|
@ -138,7 +139,6 @@ namespace garlic
|
||||||
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
||||||
|
|
||||||
i2p::crypto::CBCEncryption m_Encryption;
|
i2p::crypto::CBCEncryption m_Encryption;
|
||||||
std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption;
|
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
||||||
|
|
||||||
|
|
|
@ -451,26 +451,26 @@ namespace http {
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowCommands (std::stringstream& s)
|
static void ShowCommands (std::stringstream& s, uint32_t token)
|
||||||
{
|
{
|
||||||
/* commands */
|
/* commands */
|
||||||
s << "<b>Router Commands</b><br>\r\n";
|
s << "<b>Router Commands</b><br>\r\n";
|
||||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "\">Run peer test</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
|
||||||
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
|
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
|
||||||
if (i2p::context.AcceptsTunnels ())
|
if (i2p::context.AcceptsTunnels ())
|
||||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_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
|
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 (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
|
||||||
if (Daemon.gracefulShutdownInterval)
|
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
|
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
|
#endif
|
||||||
#ifdef WIN32_APP
|
#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
|
#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)
|
static void ShowTransitTunnels (std::stringstream& s)
|
||||||
|
@ -709,11 +709,15 @@ namespace http {
|
||||||
char b64_creds[64];
|
char b64_creds[64];
|
||||||
std::size_t len = 0;
|
std::size_t len = 0;
|
||||||
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
|
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
|
||||||
b64_creds[len] = '\0';
|
/* if we decoded properly then check credentials */
|
||||||
expected = "Basic ";
|
if(len) {
|
||||||
expected += b64_creds;
|
b64_creds[len] = '\0';
|
||||||
if (provided == expected)
|
expected = "Basic ";
|
||||||
return true;
|
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 ());
|
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
|
||||||
|
@ -752,6 +756,7 @@ namespace http {
|
||||||
SendReply (res, content);
|
SendReply (res, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
||||||
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
|
@ -767,7 +772,20 @@ namespace http {
|
||||||
else if (page == HTTP_PAGE_TUNNELS)
|
else if (page == HTTP_PAGE_TUNNELS)
|
||||||
ShowTunnels (s);
|
ShowTunnels (s);
|
||||||
else if (page == HTTP_PAGE_COMMANDS)
|
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)
|
else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
|
||||||
ShowTransitTunnels (s);
|
ShowTransitTunnels (s);
|
||||||
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
||||||
|
@ -794,13 +812,19 @@ namespace http {
|
||||||
void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
std::string cmd("");
|
|
||||||
URL url;
|
URL url;
|
||||||
|
|
||||||
url.parse(req.uri);
|
url.parse(req.uri);
|
||||||
url.parse_query(params);
|
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)
|
if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
|
||||||
i2p::transport::transports.PeerTest ();
|
i2p::transport::transports.PeerTest ();
|
||||||
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
|
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)
|
||||||
|
|
20
HTTPServer.h
20
HTTPServer.h
|
@ -1,10 +1,20 @@
|
||||||
#ifndef HTTP_SERVER_H__
|
#ifndef HTTP_SERVER_H__
|
||||||
#define HTTP_SERVER_H__
|
#define HTTP_SERVER_H__
|
||||||
|
|
||||||
namespace i2p {
|
#include <inttypes.h>
|
||||||
namespace http {
|
#include <string>
|
||||||
extern const char *itoopieFavicon;
|
#include <memory>
|
||||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
#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>
|
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||||
{
|
{
|
||||||
|
@ -35,6 +45,8 @@ namespace http {
|
||||||
bool needAuth;
|
bool needAuth;
|
||||||
std::string user;
|
std::string user;
|
||||||
std::string pass;
|
std::string pass;
|
||||||
|
|
||||||
|
static std::map<uint32_t, uint32_t> m_Tokens; // token->timestamp in seconds
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPServer
|
class HTTPServer
|
||||||
|
|
|
@ -92,7 +92,9 @@ namespace client
|
||||||
m_Stream->Close ();
|
m_Stream->Close ();
|
||||||
m_Stream.reset ();
|
m_Stream.reset ();
|
||||||
}
|
}
|
||||||
|
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send); // avoid RST
|
||||||
m_Socket->close ();
|
m_Socket->close ();
|
||||||
|
|
||||||
Done(shared_from_this ());
|
Done(shared_from_this ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +109,11 @@ namespace client
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
||||||
Terminate ();
|
Terminate ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -173,11 +177,13 @@ namespace client
|
||||||
{
|
{
|
||||||
if (bytes_transferred > 0)
|
if (bytes_transferred > 0)
|
||||||
Write (m_StreamBuffer, bytes_transferred); // postpone termination
|
Write (m_StreamBuffer, bytes_transferred); // postpone termination
|
||||||
else
|
else if (ecode == boost::asio::error::timed_out && m_Stream->IsOpen ())
|
||||||
|
StreamReceive ();
|
||||||
|
else
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Write (m_StreamBuffer, bytes_transferred);
|
Write (m_StreamBuffer, bytes_transferred);
|
||||||
|
@ -540,9 +546,13 @@ namespace client
|
||||||
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
||||||
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
std::remove_if(m_Sessions.begin(), m_Sessions.end(), [now, delta](const UDPSession * u) -> bool {
|
auto itr = m_Sessions.begin();
|
||||||
return now - u->LastActivity >= delta;
|
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)
|
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 operator^(const IdentHash& key1, const IdentHash& key2)
|
||||||
{
|
{
|
||||||
XORMetric m;
|
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 ();
|
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
|
||||||
m.metric_ll[0] = hash1[0] ^ hash2[0];
|
m.metric_ll[0] = hash1[0] ^ hash2[0];
|
||||||
m.metric_ll[1] = hash1[1] ^ hash2[1];
|
m.metric_ll[1] = hash1[1] ^ hash2[1];
|
||||||
m.metric_ll[2] = hash1[2] ^ hash2[2];
|
m.metric_ll[2] = hash1[2] ^ hash2[2];
|
||||||
m.metric_ll[3] = hash1[3] ^ hash2[3];
|
m.metric_ll[3] = hash1[3] ^ hash2[3];
|
||||||
|
#endif
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace data
|
||||||
if (m_StoreLeases)
|
if (m_StoreLeases)
|
||||||
{
|
{
|
||||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
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;
|
(*ret.first)->isUpdated = true;
|
||||||
// check if lease's gateway is in our netDb
|
// check if lease's gateway is in our netDb
|
||||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -9,10 +9,11 @@ DEPS := obj/make.dep
|
||||||
|
|
||||||
include filelist.mk
|
include filelist.mk
|
||||||
|
|
||||||
USE_AESNI := yes
|
USE_AESNI := yes
|
||||||
USE_STATIC := no
|
USE_AVX := yes
|
||||||
USE_MESHNET := no
|
USE_STATIC := no
|
||||||
USE_UPNP := no
|
USE_MESHNET := no
|
||||||
|
USE_UPNP := no
|
||||||
|
|
||||||
ifeq ($(WEBSOCKETS),1)
|
ifeq ($(WEBSOCKETS),1)
|
||||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
||||||
|
|
|
@ -60,7 +60,14 @@ ifeq ($(USE_AESNI),yes)
|
||||||
ifeq ($(IS_64),1)
|
ifeq ($(IS_64),1)
|
||||||
#check if AES-NI is supported by CPU
|
#check if AES-NI is supported by CPU
|
||||||
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
||||||
CPU_FLAGS = -maes -DAESNI
|
CPU_FLAGS += -maes -DAESNI
|
||||||
endif
|
endif
|
||||||
endif
|
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) !!!
|
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
||||||
ifeq ($(USE_AESNI),1)
|
ifeq ($(USE_AESNI),1)
|
||||||
CPU_FLAGS = -maes -DAESNI
|
CPU_FLAGS += -maes -DAESNI
|
||||||
else
|
else
|
||||||
CPU_FLAGS = -msse
|
CPU_FLAGS += -msse
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_AVX),1)
|
||||||
|
CPU_FLAGS += -mavx
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_ASLR),yes)
|
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
|
#CXXFLAGS = -g -O2 -Wall -std=c++11
|
||||||
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
|
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
|
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
|
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
LDFLAGS += -ldl
|
LDFLAGS += -ldl
|
||||||
CXXFLAGS += -DUSE_UPNP
|
CXXFLAGS += -DUSE_UPNP
|
||||||
endif
|
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)
|
ifeq ($(USE_AESNI),yes)
|
||||||
CXXFLAGS += -maes -DAESNI
|
CXXFLAGS += -maes -DAESNI
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_AVX),yes)
|
||||||
|
CXXFLAGS += -mavx
|
||||||
|
endif
|
||||||
|
|
||||||
# Disabled, since it will be the default make rule. I think its better
|
# 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
|
# to define the default rule in Makefile and not Makefile.<ostype> - torkel
|
||||||
#install: all
|
#install: all
|
||||||
|
|
53
NetDb.cpp
53
NetDb.cpp
|
@ -118,7 +118,6 @@ namespace data
|
||||||
{
|
{
|
||||||
SaveUpdated ();
|
SaveUpdated ();
|
||||||
ManageLeaseSets ();
|
ManageLeaseSets ();
|
||||||
ManageLookupResponses ();
|
|
||||||
}
|
}
|
||||||
lastSave = ts;
|
lastSave = ts;
|
||||||
}
|
}
|
||||||
|
@ -857,33 +856,17 @@ namespace data
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!replyMsg)
|
if (!replyMsg)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
std::set<IdentHash> excludedRouters;
|
||||||
// find or cleate response
|
const uint8_t * exclude_ident = excluded;
|
||||||
std::vector<IdentHash> closestFloodfills;
|
for (int i = 0; i < numExcluded; i++)
|
||||||
bool found = false;
|
{
|
||||||
if (!numExcluded)
|
excludedRouters.insert (exclude_ident);
|
||||||
{
|
exclude_ident += 32;
|
||||||
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 ());
|
|
||||||
}
|
}
|
||||||
|
auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
|
||||||
|
if (closestFloodfills.empty ())
|
||||||
|
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
|
||||||
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -929,7 +912,6 @@ namespace data
|
||||||
|
|
||||||
uint8_t randomHash[32];
|
uint8_t randomHash[32];
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
std::set<const RouterInfo *> floodfills;
|
|
||||||
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
|
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
|
||||||
for (int i = 0; i < numDestinations; i++)
|
for (int i = 0; i < numDestinations; i++)
|
||||||
{
|
{
|
||||||
|
@ -941,9 +923,8 @@ namespace data
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
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 ()))
|
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||||
throughTunnels = false;
|
throughTunnels = false;
|
||||||
if (throughTunnels)
|
if (throughTunnels)
|
||||||
|
@ -1191,17 +1172,5 @@ namespace data
|
||||||
++it;
|
++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 Publish ();
|
||||||
void ManageLeaseSets ();
|
void ManageLeaseSets ();
|
||||||
void ManageRequests ();
|
void ManageRequests ();
|
||||||
void ManageLookupResponses ();
|
|
||||||
|
|
||||||
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
|
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*/
|
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
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 */
|
/** true if in hidden mode */
|
||||||
bool m_HiddenMode;
|
bool m_HiddenMode;
|
||||||
|
|
|
@ -167,19 +167,19 @@ namespace data
|
||||||
{
|
{
|
||||||
uint8_t supportedTransports = 0;
|
uint8_t supportedTransports = 0;
|
||||||
bool isValidAddress = true;
|
bool isValidAddress = true;
|
||||||
Address address;
|
auto address = std::make_shared<Address>();
|
||||||
s.read ((char *)&address.cost, sizeof (address.cost));
|
s.read ((char *)&address->cost, sizeof (address->cost));
|
||||||
s.read ((char *)&address.date, sizeof (address.date));
|
s.read ((char *)&address->date, sizeof (address->date));
|
||||||
char transportStyle[5];
|
char transportStyle[5];
|
||||||
ReadString (transportStyle, 5, s);
|
ReadString (transportStyle, 5, s);
|
||||||
if (!strcmp (transportStyle, "NTCP"))
|
if (!strcmp (transportStyle, "NTCP"))
|
||||||
address.transportStyle = eTransportNTCP;
|
address->transportStyle = eTransportNTCP;
|
||||||
else if (!strcmp (transportStyle, "SSU"))
|
else if (!strcmp (transportStyle, "SSU"))
|
||||||
address.transportStyle = eTransportSSU;
|
address->transportStyle = eTransportSSU;
|
||||||
else
|
else
|
||||||
address.transportStyle = eTransportUnknown;
|
address->transportStyle = eTransportUnknown;
|
||||||
address.port = 0;
|
address->port = 0;
|
||||||
address.mtu = 0;
|
address->mtu = 0;
|
||||||
uint16_t size, r = 0;
|
uint16_t size, r = 0;
|
||||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||||
size = be16toh (size);
|
size = be16toh (size);
|
||||||
|
@ -194,35 +194,35 @@ namespace data
|
||||||
if (!strcmp (key, "host"))
|
if (!strcmp (key, "host"))
|
||||||
{
|
{
|
||||||
boost::system::error_code ecode;
|
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 (ecode)
|
||||||
{
|
{
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address->transportStyle == eTransportNTCP)
|
||||||
{
|
{
|
||||||
supportedTransports |= eNTCPV4; // TODO:
|
supportedTransports |= eNTCPV4; // TODO:
|
||||||
address.addressString = value;
|
address->addressString = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
supportedTransports |= eSSUV4; // TODO:
|
supportedTransports |= eSSUV4; // TODO:
|
||||||
address.addressString = value;
|
address->addressString = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add supported protocol
|
// add supported protocol
|
||||||
if (address.host.is_v4 ())
|
if (address->host.is_v4 ())
|
||||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||||
else
|
else
|
||||||
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp (key, "port"))
|
else if (!strcmp (key, "port"))
|
||||||
address.port = boost::lexical_cast<int>(value);
|
address->port = boost::lexical_cast<int>(value);
|
||||||
else if (!strcmp (key, "mtu"))
|
else if (!strcmp (key, "mtu"))
|
||||||
address.mtu = boost::lexical_cast<int>(value);
|
address->mtu = boost::lexical_cast<int>(value);
|
||||||
else if (!strcmp (key, "key"))
|
else if (!strcmp (key, "key"))
|
||||||
Base64ToByteStream (value, strlen (value), address.key, 32);
|
Base64ToByteStream (value, strlen (value), address->key, 32);
|
||||||
else if (!strcmp (key, "caps"))
|
else if (!strcmp (key, "caps"))
|
||||||
ExtractCaps (value);
|
ExtractCaps (value);
|
||||||
else if (key[0] == 'i')
|
else if (key[0] == 'i')
|
||||||
|
@ -237,9 +237,9 @@ namespace data
|
||||||
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
|
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
|
||||||
if (s) continue; else return;
|
if (s) continue; else return;
|
||||||
}
|
}
|
||||||
if (index >= address.introducers.size ())
|
if (index >= address->introducers.size ())
|
||||||
address.introducers.resize (index + 1);
|
address->introducers.resize (index + 1);
|
||||||
Introducer& introducer = address.introducers.at (index);
|
Introducer& introducer = address->introducers.at (index);
|
||||||
if (!strcmp (key, "ihost"))
|
if (!strcmp (key, "ihost"))
|
||||||
{
|
{
|
||||||
boost::system::error_code ecode;
|
boost::system::error_code ecode;
|
||||||
|
@ -256,7 +256,7 @@ namespace data
|
||||||
}
|
}
|
||||||
if (isValidAddress)
|
if (isValidAddress)
|
||||||
{
|
{
|
||||||
addresses->push_back(std::make_shared<Address>(address));
|
addresses->push_back(address);
|
||||||
m_SupportedTransports |= supportedTransports;
|
m_SupportedTransports |= supportedTransports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
121
SAM.cpp
121
SAM.cpp
|
@ -54,11 +54,7 @@ namespace client
|
||||||
case eSAMSocketTypeAcceptor:
|
case eSAMSocketTypeAcceptor:
|
||||||
{
|
{
|
||||||
if (m_Session)
|
if (m_Session)
|
||||||
{
|
|
||||||
m_Session->DelSocket (shared_from_this ());
|
m_Session->DelSocket (shared_from_this ());
|
||||||
if (m_Session->localDestination)
|
|
||||||
m_Session->localDestination->StopAcceptingStreams ();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -289,6 +285,11 @@ namespace client
|
||||||
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
|
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
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 ())
|
if (m_Session->localDestination->IsReady ())
|
||||||
SendSessionCreateReplyOk ();
|
SendSessionCreateReplyOk ();
|
||||||
|
@ -401,20 +402,25 @@ namespace client
|
||||||
m_Session = m_Owner.FindSession (id);
|
m_Session = m_Owner.FindSession (id);
|
||||||
if (m_Session)
|
if (m_Session)
|
||||||
{
|
{
|
||||||
if (!m_Session->localDestination->IsAcceptingStreams ())
|
m_SocketType = eSAMSocketTypeAcceptor;
|
||||||
{
|
m_Session->AddSocket (shared_from_this ());
|
||||||
m_SocketType = eSAMSocketTypeAcceptor;
|
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
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)
|
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
||||||
|
@ -577,8 +583,8 @@ namespace client
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
s->Receive ();
|
s->Receive ();
|
||||||
else
|
else
|
||||||
s->Terminate ();
|
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),
|
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
|
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination
|
||||||
else
|
else
|
||||||
Terminate ();
|
{
|
||||||
|
auto s = shared_from_this ();
|
||||||
|
m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Terminate ();
|
{
|
||||||
|
auto s = shared_from_this ();
|
||||||
|
m_Owner.GetService ().post ([s] { s->Terminate (); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -653,10 +665,6 @@ namespace client
|
||||||
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
|
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
|
||||||
m_Stream = stream;
|
m_Stream = stream;
|
||||||
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
||||||
auto session = m_Owner.FindSession (m_ID);
|
|
||||||
if (session)
|
|
||||||
session->localDestination->StopAcceptingStreams ();
|
|
||||||
m_SocketType = eSAMSocketTypeStream;
|
|
||||||
if (!m_IsSilent)
|
if (!m_IsSilent)
|
||||||
{
|
{
|
||||||
// get remote peer address
|
// get remote peer address
|
||||||
|
@ -698,26 +706,76 @@ namespace client
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
|
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();
|
if(!stream) return; // fail
|
||||||
i2p::client::context.DeleteLocalDestination (localDestination);
|
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 ()
|
void SAMSession::CloseStreams ()
|
||||||
{
|
{
|
||||||
{
|
m_BacklogPumper.cancel();
|
||||||
|
localDestination->GetService().post([&] () {
|
||||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
||||||
for (auto& sock : m_Sockets) {
|
for (auto& sock : m_Sockets) {
|
||||||
sock->CloseStream();
|
sock->CloseStream();
|
||||||
}
|
}
|
||||||
}
|
for(auto & stream : m_Backlog) {
|
||||||
// XXX: should this be done inside locked parts?
|
stream->Close();
|
||||||
m_Sockets.clear();
|
}
|
||||||
|
m_Sockets.clear();
|
||||||
|
m_Backlog.clear();
|
||||||
|
i2p::client::context.DeleteLocalDestination (localDestination);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMBridge::SAMBridge (const std::string& address, int port):
|
SAMBridge::SAMBridge (const std::string& address, int port):
|
||||||
|
@ -828,8 +886,9 @@ namespace client
|
||||||
auto session = std::make_shared<SAMSession>(localDestination);
|
auto session = std::make_shared<SAMSession>(localDestination);
|
||||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||||
auto ret = m_Sessions.insert (std::make_pair(id, session));
|
auto ret = m_Sessions.insert (std::make_pair(id, session));
|
||||||
if (!ret.second)
|
if (!ret.second) {
|
||||||
LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
|
LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
|
||||||
|
}
|
||||||
return ret.first->second;
|
return ret.first->second;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
19
SAM.h
19
SAM.h
|
@ -20,7 +20,8 @@ namespace client
|
||||||
{
|
{
|
||||||
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
|
const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
|
||||||
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
|
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[] = "HELLO VERSION";
|
||||||
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
|
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
|
||||||
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\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; };
|
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
||||||
SAMSocketType GetSocketType () const { return m_SocketType; };
|
SAMSocketType GetSocketType () const { return m_SocketType; };
|
||||||
|
|
||||||
|
void Accept(std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
@ -134,6 +137,8 @@ namespace client
|
||||||
struct SAMSession
|
struct SAMSession
|
||||||
{
|
{
|
||||||
std::shared_ptr<ClientDestination> localDestination;
|
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::list<std::shared_ptr<SAMSocket> > m_Sockets;
|
||||||
std::mutex m_SocketsMutex;
|
std::mutex m_SocketsMutex;
|
||||||
|
|
||||||
|
@ -158,9 +163,15 @@ namespace client
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMSession (std::shared_ptr<ClientDestination> dest);
|
SAMSession (std::shared_ptr<ClientDestination> dest);
|
||||||
~SAMSession ();
|
|
||||||
|
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 ();
|
void CloseStreams ();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1101,7 +1101,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
// we are Alice
|
// we are Alice
|
||||||
LogPrint (eLogDebug, "SSU: sending peer test");
|
LogPrint (eLogDebug, "SSU: sending peer test");
|
||||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
|
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (i2p::context.SupportsV4 ());
|
||||||
if (!address)
|
if (!address)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||||
|
|
|
@ -116,6 +116,7 @@ namespace tunnel
|
||||||
if (!isFollowOnFragment) // create new incomlete message
|
if (!isFollowOnFragment) // create new incomlete message
|
||||||
{
|
{
|
||||||
m.nextFragmentNum = 1;
|
m.nextFragmentNum = 1;
|
||||||
|
m.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
|
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
|
||||||
if (ret.second)
|
if (ret.second)
|
||||||
HandleOutOfSequenceFragments (msgID, ret.first->second);
|
HandleOutOfSequenceFragments (msgID, ret.first->second);
|
||||||
|
@ -284,6 +285,14 @@ namespace tunnel
|
||||||
else
|
else
|
||||||
++it;
|
++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
|
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
||||||
{
|
{
|
||||||
|
uint64_t receiveTime; // milliseconds since epoch
|
||||||
uint8_t nextFragmentNum;
|
uint8_t nextFragmentNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.10.1"
|
#define I2Pd_ver "2.11.0"
|
||||||
#define I2Pd_Publisher "PurpleI2P"
|
#define I2Pd_Publisher "PurpleI2P"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.purplei2p.i2pd"
|
package="org.purplei2p.i2pd"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="2.10.1">
|
android:versionName="2.11.0">
|
||||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
|
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
|
@ -59,6 +59,7 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
|
||||||
../../TunnelPool.cpp \
|
../../TunnelPool.cpp \
|
||||||
../../Timestamp.cpp \
|
../../Timestamp.cpp \
|
||||||
../../Event.cpp \
|
../../Event.cpp \
|
||||||
|
../../BloomFilter.cpp \
|
||||||
../../util.cpp \
|
../../util.cpp \
|
||||||
../../i2pd.cpp ../../UPnP.cpp
|
../../i2pd.cpp ../../UPnP.cpp
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
||||||
set ( CMAKE_SOURCE_DIR ".." )
|
set ( CMAKE_SOURCE_DIR ".." )
|
||||||
|
|
||||||
set (LIBI2PD_SRC
|
set (LIBI2PD_SRC
|
||||||
|
"${CMAKE_SOURCE_DIR}/BloomFilter.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/Config.cpp"
|
"${CMAKE_SOURCE_DIR}/Config.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/Crypto.cpp"
|
"${CMAKE_SOURCE_DIR}/Crypto.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/Garlic.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
|
i2pd (2.10.1-1) unstable; urgency=low
|
||||||
|
|
||||||
* updated to version 2.10.1
|
* 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
|
diff --git a/Makefile b/Makefile
|
||||||
index b6fc795..abc3ace 100644
|
index bdadfe0..2f71eec 100644
|
||||||
|
|
||||||
--- a/Makefile
|
--- a/Makefile
|
||||||
+++ b/Makefile
|
+++ b/Makefile
|
||||||
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
|
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
|
||||||
|
|
||||||
include filelist.mk
|
include filelist.mk
|
||||||
|
|
||||||
-USE_AESNI := yes
|
-USE_AESNI := yes
|
||||||
+USE_AESNI := no
|
+USE_AESNI := no
|
||||||
USE_STATIC := no
|
-USE_AVX := yes
|
||||||
USE_MESHNET := no
|
+USE_AVX := no
|
||||||
USE_UPNP := no
|
USE_STATIC := no
|
||||||
|
USE_MESHNET := no
|
||||||
|
USE_UPNP := no
|
||||||
|
|
||||||
ifeq ($(WEBSOCKETS),1)
|
ifeq ($(WEBSOCKETS),1)
|
||||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
LIB_SRC = \
|
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 \
|
Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
|
||||||
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
|
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
|
||||||
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?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"/>
|
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
|
||||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
<!-- <application android:hardwareAccelerated="true" -->
|
<!-- <application android:hardwareAccelerated="true" -->
|
||||||
|
|
|
@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
||||||
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
|
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
|
||||||
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
|
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
|
||||||
../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.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 \
|
HEADERS += DaemonQT.h mainwindow.h \
|
||||||
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.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 \
|
../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
|
||||||
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
|
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
|
||||||
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.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
|
FORMS += mainwindow.ui
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 10
|
#define I2PD_VERSION_MINOR 11
|
||||||
#define I2PD_VERSION_MICRO 1
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||||
#define VERSION I2PD_VERSION
|
#define VERSION I2PD_VERSION
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 27
|
#define I2P_VERSION_MICRO 28
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue