1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef TRANSPORT_SESSION_H__
#define TRANSPORT_SESSION_H__
#include <inttypes.h>
#include <string.h>
#include <memory>
#include <vector>
#include <mutex>
#include "Identity.h"
#include "Crypto.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
#include "Timestamp.h"
namespace i2p
{
namespace transport
{
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
template<size_t sz>
class SignedData
{
public:
SignedData (): m_Size(0) {}
SignedData (const SignedData& other)
{
m_Size = other.m_Size;
memcpy (m_Buf, other.m_Buf, m_Size);
}
void Reset ()
{
m_Size = 0;
}
size_t Insert (const uint8_t * buf, size_t len)
{
if (m_Size + len > sz) len = sz - m_Size;
memcpy (m_Buf + m_Size, buf, len);
m_Size += len;
return len;
}
template<typename T>
void Insert (T t)
{
Insert ((const uint8_t *)&t, sizeof (T));
}
bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const
{
return ident->Verify (m_Buf, m_Size, signature);
}
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
{
keys.Sign (m_Buf, m_Size, signature);
}
private:
uint8_t m_Buf[sz];
size_t m_Size;
};
const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds
const int64_t TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL = 10000; // in milliseconds
const uint64_t TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL = 5; // in seconds
class TransportSession
{
public:
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_HandshakeInterval (0),
m_SendQueueSize (0), m_NumSentBytes (0), m_NumReceivedBytes (0),
m_LastBandWidthUpdateNumSentBytes (0), m_LastBandWidthUpdateNumReceivedBytes (0),
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()),
m_LastBandwidthUpdateTimestamp (m_LastActivityTimestamp), m_InBandwidth (0), m_OutBandwidth (0)
{
if (router)
m_RemoteIdentity = router->GetRouterIdentity ();
m_CreationTime = m_LastActivityTimestamp;
}
virtual ~TransportSession () {};
virtual void Done () = 0;
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity ()
{
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
return m_RemoteIdentity;
}
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident)
{
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
m_RemoteIdentity = ident;
}
size_t GetNumSentBytes () const { return m_NumSentBytes; };
void UpdateNumSentBytes (size_t len)
{
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
m_NumSentBytes += len;
UpdateBandwidth ();
}
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void UpdateNumReceivedBytes (size_t len)
{
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
m_NumReceivedBytes += len;
UpdateBandwidth ();
}
size_t GetSendQueueSize () const { return m_SendQueueSize; };
void SetSendQueueSize (size_t s) { m_SendQueueSize = s; };
bool IsOutgoing () const { return m_IsOutgoing; };
bool IsSlow () const { return m_HandshakeInterval > TRANSPORT_SESSION_SLOWNESS_THRESHOLD &&
m_HandshakeInterval < TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL; };
bool IsBandwidthExceeded (bool isHighBandwidth) const
{
auto limit = isHighBandwidth ? i2p::data::HIGH_BANDWIDTH_LIMIT*1024 : i2p::data::LOW_BANDWIDTH_LIMIT*1024; // convert to bytes
return std::max (m_InBandwidth, m_OutBandwidth) > limit;
}
int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const
{
return ts >= m_LastActivityTimestamp + GetTerminationTimeout () ||
ts + GetTerminationTimeout () < m_LastActivityTimestamp;
};
uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
virtual uint32_t GetRelayTag () const { return 0; };
virtual void SendLocalRouterInfo (bool update = false)
{
std::list<std::shared_ptr<I2NPMessage> > msgs{ CreateDatabaseStoreMsg () };
SendI2NPMessages (msgs);
};
virtual void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) = 0;
virtual bool IsEstablished () const = 0;
virtual i2p::data::RouterInfo::SupportedTransports GetTransportType () const = 0;
private:
void UpdateBandwidth ()
{
int64_t interval = m_LastActivityTimestamp - m_LastBandwidthUpdateTimestamp;
if (interval < 0 || interval > 60*10) // 10 minutes
{
// clock was adjusted, copy new values
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
return;
}
if ((uint64_t)interval > TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL)
{
m_OutBandwidth = (m_NumSentBytes - m_LastBandWidthUpdateNumSentBytes)/interval;
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
m_InBandwidth = (m_NumReceivedBytes - m_LastBandWidthUpdateNumReceivedBytes)/interval;
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
}
}
protected:
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
mutable std::mutex m_RemoteIdentityMutex;
bool m_IsOutgoing;
int m_TerminationTimeout;
uint32_t m_CreationTime; // seconds since epoch
int64_t m_HandshakeInterval; // in milliseconds between SessionRequest->SessionCreated or SessionCreated->SessionConfirmed
private:
size_t m_SendQueueSize, m_NumSentBytes, m_NumReceivedBytes,
m_LastBandWidthUpdateNumSentBytes, m_LastBandWidthUpdateNumReceivedBytes;
uint64_t m_LastActivityTimestamp, m_LastBandwidthUpdateTimestamp;
uint32_t m_InBandwidth, m_OutBandwidth;
};
}
}
#endif
|