Merge branch 'master' of github-meeh420:orignal/i2pd

* 'master' of github-meeh420:orignal/i2pd:
  delete unreachable SSU sessions
  show number sent/received bytes through the status page
  resend
  fixed memory leak
  close connection to first hop of declined tunnel
  process extended data
  handle individaul bitfields ack
  Moving file list to a common one. Still in makefile format, but now with CPP/H as input instead of OBJECTS. Issue #82
  Removing Qt build file. Issue #82
  create inbound tunnel though outbound
  Makefile now detects which file to use (OSX or Linux) Issue #82
  Prepare support for POST/PUT
  close SSU session if not established
  send ack per fragment. temporary disble check for duplicated through IV
  fixed memory leak
  save out-of-sequence fragments
pull/92/head
Meeh 10 years ago
commit 45289891d6

@ -303,6 +303,7 @@ namespace util
s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
if (!outgoing) s << "-->";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<BR>";
}
}
@ -318,13 +319,18 @@ namespace util
if (outgoing) s << "-->";
s << endpoint.address ().to_string () << ":" << endpoint.port ();
if (!outgoing) s << "-->";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << "<BR>";
}
}
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq\">Flibusta</a></p>";
}
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
{
HandleDestinationRequest(address, "GET", "", uri);
}
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& method, const std::string& data, const std::string& uri)
{
i2p::data::IdentHash destination;
std::string fullAddress;
@ -380,7 +386,13 @@ namespace util
m_Stream = i2p::stream::CreateStream (*leaseSet);
if (m_Stream)
{
std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n";
std::string request = method+" " + uri + " HTTP/1.1\n Host:" + fullAddress + "\r\n";
if (!strcmp(method.c_str(), "GET"))
{
// POST/PUT, apply body
request += "\r\n"+ data;
}
LogPrint("HTTP Client Request: ", request);
m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10);
AsyncStreamReceive ();
}

@ -69,7 +69,9 @@ namespace util
protected:
virtual void HandleDestinationRequest(const std::string& address, const std::string& uri);
virtual void HandleDestinationRequest(const std::string& address, const std::string& method, const std::string& data, const std::string& uri);
virtual void RunRequest ();
private:

@ -359,6 +359,7 @@ namespace i2p
else
{
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
i2p::transports.CloseSession (tunnel->GetTunnelConfig ()->GetFirstHop ()->router);
delete tunnel;
}
}

@ -1,38 +1,9 @@
CC = g++
CFLAGS = -g -Wall -std=c++0x
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o obj/SOCKS.o
INCFLAGS =
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
UNAME := $(shell uname -s)
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
CPU_FLAGS = -DAESNI
ifeq ($(UNAME),Darwin)
include Makefile.osx
else
include Makefile.linux
endif
all: obj i2p
i2p: $(OBJECTS:obj/%=obj/%)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj:
mkdir -p obj
clean:
rm -fr obj i2p
.PHONY: all
.PHONY: clean

@ -0,0 +1,33 @@
CC = g++
CFLAGS = -g -Wall -std=c++0x
include filelist.mk
INCFLAGS =
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
CPU_FLAGS = -DAESNI
endif
all: obj i2p
i2p: $(OBJECTS:obj/%=obj/%)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj:
mkdir -p obj
clean:
rm -fr obj i2p
.PHONY: all
.PHONY: clean

@ -1,11 +1,6 @@
CC = clang++
CFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o obj/SOCKS.o
include filelist.mk
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =

@ -21,7 +21,8 @@ namespace ntcp
{
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo):
m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false),
m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr)
m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr),
m_NumSentBytes (0), m_NumReceivedBytes (0)
{
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
}
@ -29,7 +30,6 @@ namespace ntcp
NTCPSession::~NTCPSession ()
{
delete m_DHKeysPair;
delete m_NextMessage;
}
void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey)
@ -403,7 +403,7 @@ namespace ntcp
}
else
{
LogPrint ("Received: ", bytes_transferred);
m_NumReceivedBytes += bytes_transferred;
m_ReceiveBufferOffset += bytes_transferred;
if (m_ReceiveBufferOffset >= 16)
@ -514,7 +514,7 @@ namespace ntcp
}
else
{
LogPrint ("Msg sent: ", bytes_transferred);
m_NumSentBytes += bytes_transferred;
ScheduleTermination (); // reset termination timer
}
}

@ -79,6 +79,9 @@ namespace ntcp
void ServerLogin ();
void SendI2NPMessage (I2NPMessage * msg);
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
protected:
void Terminate ();
@ -142,6 +145,8 @@ namespace ntcp
i2p::I2NPMessage * m_NextMessage;
std::list<i2p::I2NPMessage *> m_DelayedMessages;
size_t m_NextMessageOffset;
size_t m_NumSentBytes, m_NumReceivedBytes;
};
class NTCPClient: public NTCPSession

@ -19,7 +19,8 @@ namespace ssu
const i2p::data::RouterInfo * router, bool peerTest ):
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router),
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown),
m_IsSessionKey (false), m_RelayTag (0), m_Data (*this)
m_IsSessionKey (false), m_RelayTag (0), m_Data (*this),
m_NumSentBytes (0), m_NumReceivedBytes (0)
{
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
}
@ -74,6 +75,7 @@ namespace ssu
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
m_NumReceivedBytes += len;
if (m_State == eSessionStateIntroduced)
{
// HolePunch received
@ -83,11 +85,12 @@ namespace ssu
}
else
{
if (m_State == eSessionStateEstablished)
ScheduleTermination ();
// check for duplicate
/* // check for duplicate
const uint8_t * iv = ((SSUHeader *)buf)->iv;
if (m_ReceivedIVs.count (iv)) return; // duplicate detected
m_ReceivedIVs.insert (iv);
m_ReceivedIVs.insert (iv);*/
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
DecryptSessionKey (buf, len);
@ -652,7 +655,6 @@ namespace ssu
if (m_State != eSessionStateFailed)
{
m_State = eSessionStateFailed;
Close ();
m_Server.DeleteSession (this); // delete this
}
}
@ -822,6 +824,7 @@ namespace ssu
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48);
Send (buf, 48);
LogPrint ("SSU session destoryed sent");
}
}
@ -842,6 +845,7 @@ namespace ssu
void SSUSession::Send (const uint8_t * buf, size_t size)
{
m_NumSentBytes += size;
m_Server.Send (buf, size, m_RemoteEndpoint);
}
@ -910,7 +914,6 @@ namespace ssu
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
{
m_Socket.send_to (boost::asio::buffer (buf, len), to);
LogPrint ("SSU sent ", len, " bytes");
}
void SSUServer::Receive ()
@ -923,7 +926,6 @@ namespace ssu
{
if (!ecode)
{
LogPrint ("SSU received ", bytes_transferred, " bytes");
SSUSession * session = nullptr;
auto it = m_Sessions.find (m_SenderEndpoint);
if (it != m_Sessions.end ())
@ -1020,7 +1022,12 @@ namespace ssu
introducerSession->Introduce (introducer->iTag, introducer->iKey);
}
else
{
LogPrint ("Router is unreachable, but no introducers presented. Ignored");
m_Sessions.erase (remoteEndpoint);
delete session;
session = nullptr;
}
}
}
}

@ -31,7 +31,6 @@ namespace ssu
};
#pragma pack()
const size_t SSU_MTU = 1484;
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
@ -74,6 +73,9 @@ namespace ssu
void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
private:
@ -132,6 +134,7 @@ namespace ssu
std::list<i2p::I2NPMessage *> m_DelayedMessages;
std::set<IV> m_ReceivedIVs;
SSUData m_Data;
size_t m_NumSentBytes, m_NumReceivedBytes;
};
class SSUServer

@ -1,4 +1,7 @@
#include <stdlib.h>
#include <boost/bind.hpp>
#include "Log.h"
#include "Timestamp.h"
#include "SSU.h"
#include "SSUData.h"
@ -7,7 +10,7 @@ namespace i2p
namespace ssu
{
SSUData::SSUData (SSUSession& session):
m_Session (session)
m_Session (session), m_ResendTimer (session.m_Server.GetService ())
{
}
@ -20,10 +23,7 @@ namespace ssu
delete it.second;
}
for (auto it: m_SentMessages)
{
for (auto f: it.second)
delete[] f;
}
delete it.second;
}
void SSUData::ProcessSentMessageAck (uint32_t msgID)
@ -31,19 +31,15 @@ namespace ssu
auto it = m_SentMessages.find (msgID);
if (it != m_SentMessages.end ())
{
// delete all ack-ed message's fragments
for (auto f: it->second)
delete[] f;
delete it->second;
m_SentMessages.erase (it);
if (m_SentMessages.empty ())
m_ResendTimer.cancel ();
}
}
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
{
//uint8_t * start = buf;
uint8_t flag = *buf;
buf++;
LogPrint ("Process SSU data flags=", (int)flag);
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
{
// explicit ACKs
@ -60,13 +56,45 @@ namespace ssu
buf++;
for (int i = 0; i < numBitfields; i++)
{
uint32_t msgID = be32toh (*(uint32_t *)buf);
buf += 4; // msgID
// TODO: process individual Ack bitfields
while (*buf & 0x80) // not last
auto it = m_SentMessages.find (msgID);
// process individual Ack bitfields
bool isNonLast = false;
int fragment = 0;
do
{
uint8_t bitfield = *buf;
isNonLast = bitfield & 0x80;
bitfield &= 0x7F; // clear MSB
if (bitfield && it != m_SentMessages.end ())
{
int numSentFragments = it->second->fragments.size ();
// process bits
uint8_t mask = 0x40;
for (int j = 0; j < 7; j++)
{
if (bitfield & mask)
{
if (fragment < numSentFragments)
{
delete it->second->fragments[fragment];
it->second->fragments[fragment] = nullptr;
}
}
fragment++;
mask >>= 1;
}
}
buf++;
buf++; // last byte
}
while (isNonLast);
}
}
}
void SSUData::ProcessFragments (uint8_t * buf)
{
uint8_t numFragments = *buf; // number of fragments
buf++;
for (int i = 0; i < numFragments; i++)
@ -82,55 +110,80 @@ namespace ssu
bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
// find message with msgID
I2NPMessage * msg = nullptr;
if (fragmentNum > 0) // follow-up fragment
{
IncompleteMessage * incompleteMessage = nullptr;
auto it = m_IncomleteMessages.find (msgID);
if (it != m_IncomleteMessages.end ())
{
if (fragmentNum == it->second->nextFragmentNum)
// message exists
incompleteMessage = it->second;
msg = incompleteMessage->msg;
}
else
{
// create new message
msg = NewI2NPMessage ();
msg->len -= sizeof (I2NPHeaderShort);
incompleteMessage = new IncompleteMessage (msg);
m_IncomleteMessages[msgID] = incompleteMessage;
}
// handle current fragment
if (fragmentNum == incompleteMessage->nextFragmentNum)
{
// expected fragment
msg = it->second->msg;
memcpy (msg->buf + msg->len, buf, fragmentSize);
msg->len += fragmentSize;
it->second->nextFragmentNum++;
incompleteMessage->nextFragmentNum++;
if (!isLast && !incompleteMessage->savedFragments.empty ())
{
// try saved fragments
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
{
auto savedFragment = *it1;
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
{
memcpy (msg->buf + msg->len, savedFragment->buf, savedFragment->len);
msg->len += savedFragment->len;
isLast = savedFragment->isLast;
incompleteMessage->nextFragmentNum++;
incompleteMessage->savedFragments.erase (it1++);
delete savedFragment;
}
else
break;
}
if (isLast)
LogPrint ("Message ", msgID, " complete");
}
}
else if (fragmentNum < it->second->nextFragmentNum)
else
{
if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment
LogPrint ("Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
else
{
// missing fragment
LogPrint ("Missing fragments from ", it->second->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
//TODO
}
if (isLast)
LogPrint ("Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
if (!incompleteMessage->savedFragments.insert (savedFragment).second)
{
if (!msg)
DeleteI2NPMessage (it->second->msg);
delete it->second;
m_IncomleteMessages.erase (it);
}
LogPrint ("Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
delete savedFragment;
}
else
// TODO:
LogPrint ("Unexpected follow-on fragment ", (int)fragmentNum, " of message ", msgID);
}
else // first fragment
{
msg = NewI2NPMessage ();
memcpy (msg->GetSSUHeader (), buf, fragmentSize);
msg->len += fragmentSize - sizeof (I2NPHeaderShort);
isLast = false;
}
if (msg)
{
if (!fragmentNum && !isLast)
m_IncomleteMessages[msgID] = new IncompleteMessage (msg);
if (isLast)
{
// delete incomplete message
delete incompleteMessage;
m_IncomleteMessages.erase (msgID);
// process message
SendMsgAck (msgID);
msg->FromSSU (msgID);
if (m_Session.GetState () == eSessionStateEstablished)
@ -148,11 +201,33 @@ namespace ssu
DeleteI2NPMessage (msg);
}
}
}
else
SendFragmentAck (msgID, fragmentNum);
buf += fragmentSize;
}
}
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
{
//uint8_t * start = buf;
uint8_t flag = *buf;
buf++;
LogPrint ("Process SSU data flags=", (int)flag);
// process acks if presented
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
ProcessAcks (buf, flag);
// extended data if presented
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
{
uint8_t extendedDataSize = *buf;
buf++; // size
LogPrint ("SSU extended data of ", extendedDataSize, " bytes presented");
buf += extendedDataSize;
}
// process data
ProcessFragments (buf);
}
void SSUData::Send (i2p::I2NPMessage * msg)
{
uint32_t msgID = msg->ToSSU ();
@ -162,7 +237,13 @@ namespace ssu
DeleteI2NPMessage (msg);
return;
}
auto fragments = m_SentMessages[msgID];
if (m_SentMessages.empty ()) // schedule resend at first message only
ScheduleResend ();
SentMessage * sentMessage = new SentMessage;
m_SentMessages[msgID] = sentMessage;
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
sentMessage->numResends = 0;
auto& fragments = sentMessage->fragments;
msgID = htobe32 (msgID);
size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength ();
@ -171,8 +252,9 @@ namespace ssu
uint32_t fragmentNum = 0;
while (len > 0)
{
uint8_t * buf = new uint8_t[SSU_MTU + 18];
fragments.push_back (buf);
Fragment * fragment = new Fragment;
uint8_t * buf = fragment->buf;
fragments.push_back (fragment);
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
payload++;
@ -195,6 +277,7 @@ namespace ssu
size += payload - buf;
if (size & 0x0F) // make sure 16 bytes boundary
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
fragment->len = size;
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
@ -228,6 +311,77 @@ namespace ssu
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
m_Session.Send (buf, 48);
}
void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum)
{
if (fragmentNum > 64)
{
LogPrint ("Fragment number ", fragmentNum, " exceeds 64");
return;
}
uint8_t buf[64 + 18];
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
payload++;
*payload = 1; // number of ACK bitfields
payload++;
// one ack
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4;
div_t d = div (fragmentNum, 7);
memset (payload, 0x80, d.quot); // 0x80 means non-last
payload += d.quot;
*payload = 0x40 >> d.rem; // set corresponding bit
payload++;
*payload = 0; // number of fragments
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
m_Session.Send (buf, len);
}
void SSUData::ScheduleResend()
{
m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer,
this, boost::asio::placeholders::error));
}
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
{
if (ts >= it->second->nextResendTime)
{
bool isEmpty = true;
for (auto f: it->second->fragments)
if (f)
{
isEmpty = false;
m_Session.Send (f->buf, f->len); // resend
}
it->second->numResends++;
if (isEmpty || it->second->numResends >= MAX_NUM_RESENDS)
{
delete it->second;
it = m_SentMessages.erase (it);
}
else
it++;
}
else
it++;
}
if (!m_SentMessages.empty ())
ScheduleResend ();
}
}
}
}

@ -2,8 +2,11 @@
#define SSU_DATA_H__
#include <inttypes.h>
#include <string.h>
#include <map>
#include <vector>
#include <set>
#include <boost/asio.hpp>
#include "I2NPProtocol.h"
namespace i2p
@ -11,6 +14,9 @@ namespace i2p
namespace ssu
{
const size_t SSU_MTU = 1484;
const int RESEND_INTERVAL = 3; // in seconds
const int MAX_NUM_RESENDS = 5;
// data flags
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
@ -19,6 +25,45 @@ namespace ssu
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
struct Fragment
{
int fragmentNum;
size_t len;
bool isLast;
uint8_t buf[SSU_MTU + 18];
Fragment () = default;
Fragment (int n, const uint8_t * b, int l, bool last):
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
};
struct FragmentCmp
{
bool operator() (const Fragment * f1, const Fragment * f2) const
{
return f1->fragmentNum < f2->fragmentNum;
};
};
struct IncompleteMessage
{
I2NPMessage * msg;
int nextFragmentNum;
std::set<Fragment *, FragmentCmp> savedFragments;
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0) {};
~IncompleteMessage () { for (auto it: savedFragments) { delete it; }; };
};
struct SentMessage
{
std::vector<Fragment *> fragments;
uint32_t nextResendTime; // in seconds
int numResends;
~SentMessage () { for (auto it: fragments) { delete it; }; };
};
class SSUSession;
class SSUData
{
@ -33,21 +78,20 @@ namespace ssu
private:
void SendMsgAck (uint32_t msgID);
void SendFragmentAck (uint32_t msgID, int fragmentNum);
void ProcessAcks (uint8_t *& buf, uint8_t flag);
void ProcessFragments (uint8_t * buf);
void ProcessSentMessageAck (uint32_t msgID);
private:
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
struct IncompleteMessage
{
I2NPMessage * msg;
uint8_t nextFragmentNum;
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (1) {};
};
private:
SSUSession& m_Session;
std::map<uint32_t, IncompleteMessage *> m_IncomleteMessages;
std::map<uint32_t, std::vector<uint8_t *> > m_SentMessages; // msgID -> fragments
std::map<uint32_t, SentMessage *> m_SentMessages;
boost::asio::deadline_timer m_ResendTimer;
};
}
}

@ -263,6 +263,23 @@ namespace i2p
}
}
void Transports::CloseSession (const i2p::data::RouterInfo * router)
{
if (!router) return;
m_Service.post (boost::bind (&Transports::PostCloseSession, this, router));
}
void Transports::PostCloseSession (const i2p::data::RouterInfo * router)
{
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
if (ssuSession) // try SSU first
{
m_SSUServer->DeleteSession (ssuSession);
LogPrint ("SSU session closed");
}
// TODO: delete NTCP
}
void Transports::DetectExternalIP ()
{
for (int i = 0; i < 5; i ++)

@ -63,12 +63,14 @@ namespace i2p
i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router);
private:
void Run ();
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostCloseSession (const i2p::data::RouterInfo * router);
void DetectExternalIP ();

@ -361,10 +361,12 @@ namespace tunnel
void Tunnels::ManageTunnels ()
{
// check pending tunnel. if something is still there, wipe it out
// because it wouldn't be reponded anyway
// because it wouldn't be responded anyway
for (auto& it : m_PendingTunnels)
{
LogPrint ("Pending tunnel build request ", it.first, " has not been responded. Deleted");
if (it.second->GetTunnelConfig ()->GetFirstHop ()->isGateway) // outbound
i2p::transports.CloseSession (it.second->GetTunnelConfig ()->GetFirstHop ()->router);
delete it.second;
}
m_PendingTunnels.clear ();

@ -188,7 +188,7 @@ namespace tunnel
hops.push_back (hop);
}
std::reverse (hops.begin (), hops.end ());
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (new TunnelConfig (hops));
auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (new TunnelConfig (hops), outboundTunnel);
tunnel->SetTunnelPool (this);
}

@ -1,85 +0,0 @@
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
TARGET = ./../../i2pd_qt
QMAKE_CXXFLAGS += -std=c++0x
LIBS += -lcrypto++
LIBS += \
-lboost_system\
-lboost_filesystem\
-lboost_regex\
-lboost_program_options\
-lpthread
SOURCES += \
../LeaseSet.cpp \
../i2p.cpp \
../HTTPServer.cpp \
../HTTPProxy.cpp \
../Garlic.cpp \
../base64.cpp \
../AddressBook.cpp \
../util.cpp \
../UPnP.cpp \
../TunnelPool.cpp \
../TunnelGateway.cpp \
../TunnelEndpoint.cpp \
../Tunnel.cpp \
../Transports.cpp \
../TransitTunnel.cpp \
../Streaming.cpp \
../SSU.cpp \
../RouterInfo.cpp \
../RouterContext.cpp \
../Reseed.cpp \
../NTCPSession.cpp \
../NetDb.cpp \
../Log.cpp \
../Identity.cpp \
../I2NPProtocol.cpp \
../SOCKS.cpp
HEADERS += \
../LeaseSet.h \
../Identity.h \
../HTTPServer.h \
../HTTPProxy.h \
../hmac.h \
../Garlic.h \
../ElGamal.h \
../CryptoConst.h \
../base64.h \
../AddressBook.h \
../util.h \
../UPnP.h \
../TunnelPool.h \
../TunnelGateway.h \
../TunnelEndpoint.h \
../TunnelConfig.h \
../TunnelBase.h \
../Tunnel.h \
../Transports.h \
../TransitTunnel.h \
../Timestamp.h \
../Streaming.h \
../SSU.h \
../RouterInfo.h \
../RouterContext.h \
../Reseed.h \
../Queue.h \
../NTCPSession.h \
../NetDb.h \
../Log.h \
../LittleBigEndian.h \
../I2PEndian.h \
../I2NPProtocol.h \
../SOCKS.h
OTHER_FILES += \
../README.md \
../Makefile \
../LICENSE

@ -0,0 +1,18 @@
CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transports.cpp \
RouterContext.cpp NetDb.cpp LeaseSet.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelGateway.cpp \
TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp Identity.cpp \
SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp i2p.cpp aes.cpp SOCKS.cpp UPnP.cpp \
TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp
H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \
RouterContext.h NetDb.h LeaseSet.h Tunnel.h TunnelEndpoint.h TunnelGateway.h \
TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.h Identity.h \
SSU.h util.h Reseed.h DaemonLinux.h SSUData.h i2p.h aes.h SOCKS.h UPnP.h TunnelPool.h \
HTTPProxy.h AddressBook.h Daemon.h
OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))
Loading…
Cancel
Save