Merge branch 'openssl' of https://github.com/purplei2p/i2pd into openssl

This commit is contained in:
Jeff Becker 2018-08-25 14:03:21 -04:00
commit fb26e78ecc
No known key found for this signature in database
GPG key ID: F357B3B42F6F9B05
121 changed files with 5521 additions and 1901 deletions

View file

@ -377,7 +377,7 @@ namespace client
}
numAddresses++;
auto it = m_Addresses.find (name);
if (it != m_Addresses.end ()) // aleady exists ?
if (it != m_Addresses.end ()) // already exists ?
{
if (it->second != ident->GetIdentHash ()) // address changed?
{
@ -755,7 +755,8 @@ namespace client
},
SUBSCRIPTION_REQUEST_TIMEOUT);
std::unique_lock<std::mutex> l(newDataReceivedMutex);
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
// wait 1 more second
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout)
{
LogPrint (eLogError, "Addressbook: subscriptions request timeout expired");
numAttempts++;

View file

@ -362,8 +362,6 @@ namespace client
{
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
m_SharedLocalDestination->Acquire ();
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start ();
}
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
@ -488,8 +486,8 @@ namespace client
{
localDestination = m_SharedLocalDestination;
}
auto clientTunnel = new I2PUDPClientTunnel(name, dest, end, localDestination, destinationPort);
if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr<I2PUDPClientTunnel>(clientTunnel))).second)
auto clientTunnel = std::make_shared<I2PUDPClientTunnel>(name, dest, end, localDestination, destinationPort);
if(m_ClientForwards.insert(std::make_pair(end, clientTunnel)).second)
{
clientTunnel->Start();
}
@ -498,32 +496,36 @@ namespace client
} else {
boost::asio::ip::tcp::endpoint clientEndpoint;
I2PService * clientTunnel = nullptr;
std::shared_ptr<I2PService> clientTunnel;
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
{
// socks proxy
std::string outproxy = section.second.get("outproxy", "");
clientTunnel = new i2p::proxy::SOCKSProxy(name, address, port, !outproxy.emtpy(), outproxy, destinationPort, localDestination);
clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint ();
auto tun = std::make_shared<i2p::proxy::SOCKSProxy>(name, address, port, !outproxy.empty(), outproxy, destinationPort, localDestination);
clientTunnel = tun;
clientEndpoint = tun->GetLocalEndpoint ();
}
else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)
{
// http proxy
std::string outproxy = section.second.get("outproxy", "");
clientTunnel = new i2p::proxy::HTTPProxy(name, address, port, outproxy, localDestination);
clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint ();
auto tun = std::make_shared<i2p::proxy::HTTPProxy>(name, address, port, outproxy, localDestination);
clientTunnel = tun;
clientEndpoint = tun->GetLocalEndpoint ();
}
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
{
// websocks proxy
clientTunnel = new WebSocks(address, port, localDestination);;
clientEndpoint = ((WebSocks*)clientTunnel)->GetLocalEndpoint();
auto tun = std::make_shared<WebSocks>(address, port, localDestination);
clientTunnel = tun;
clientEndpoint = tun->GetLocalEndpoint();
}
else
{
// tcp client
clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint ();
auto tun = std::make_shared<I2PClientTunnel> (name, dest, address, port, localDestination, destinationPort);
clientTunnel = tun;
clientEndpoint = tun->GetLocalEndpoint ();
}
uint32_t timeout = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0);
if(timeout)
@ -532,7 +534,7 @@ namespace client
LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout);
}
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel)));
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel));
if (ins.second)
{
clientTunnel->Start ();
@ -568,7 +570,7 @@ namespace client
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN);
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
@ -589,7 +591,7 @@ namespace client
// TODO: hostnames
auto localAddress = boost::asio::ip::address::from_string(address);
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port);
auto serverTunnel = std::make_shared<I2PUDPServerTunnel>(name, localDestination, localAddress, endpoint, port);
if(!isUniqueLocal)
{
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
@ -600,7 +602,7 @@ namespace client
std::make_pair(
std::make_pair(
localDestination->GetIdentHash(), port),
std::unique_ptr<I2PUDPServerTunnel>(serverTunnel))).second)
serverTunnel)).second)
{
serverTunnel->Start();
LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32());
@ -611,16 +613,14 @@ namespace client
continue;
}
I2PServerTunnel * serverTunnel;
std::shared_ptr<I2PServerTunnel> serverTunnel;
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
serverTunnel = std::make_shared<I2PServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip);
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip);
serverTunnel = std::make_shared<I2PServerTunnelIRC> (name, host, port, localDestination, webircpass, inPort, gzip);
else // regular server tunnel by default
serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip);
serverTunnel = std::make_shared<I2PServerTunnel> (name, host, port, localDestination, inPort, gzip);
LogPrint(eLogInfo, "Clients: Set Max Conns To ", maxConns);
serverTunnel->SetMaxConnsPerMinute(maxConns);
if(!isUniqueLocal)
{
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
@ -643,8 +643,8 @@ namespace client
serverTunnel->SetAccessList (idents);
}
auto ins = m_ServerTunnels.insert (std::make_pair (
std::make_pair (localDestination->GetIdentHash (), inPort),
std::unique_ptr<I2PServerTunnel>(serverTunnel)));
std::make_pair (localDestination->GetIdentHash (), inPort),
serverTunnel));
if (ins.second)
{
serverTunnel->Start ();

View file

@ -113,12 +113,12 @@ namespace client
i2p::proxy::HTTPProxy * m_HttpProxy;
i2p::proxy::SOCKSProxy * m_SocksProxy;
std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
std::map<boost::asio::ip::tcp::endpoint, std::shared_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
std::mutex m_ForwardsMutex;
std::map<boost::asio::ip::udp::endpoint, std::unique_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
SAMBridge * m_SamBridge;
BOBCommandChannel * m_BOBCommandChannel;

View file

@ -219,7 +219,7 @@ namespace proxy {
/* replace headers */
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
/* add headers */
req.AddHeader("Connection", "close"); /* keep-alive conns not supported yet */
req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */
}
/**
@ -387,18 +387,12 @@ namespace proxy {
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
m_ClientRequestURL.schema = "";
m_ClientRequestURL.host = "";
std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for?
m_ClientRequest.uri = m_ClientRequestURL.to_string();
if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ()))
{
// http proxy authorization
std::string s = "basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass);
m_ClientRequest.AddHeader("Proxy-Authorization", s);
}
m_ClientRequest.write(m_ClientRequestBuffer);
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
// assume http if empty schema
if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http")
{
@ -406,7 +400,18 @@ namespace proxy {
if (!m_ProxyURL.port) m_ProxyURL.port = 80;
if (m_ProxyURL.is_i2p())
{
m_send_buf = m_recv_buf;
m_ClientRequest.uri = origURI;
if (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())
{
// remove existing authorization if any
m_ClientRequest.RemoveHeader("Proxy-");
// add own http proxy authorization
std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass);
m_ClientRequest.AddHeader("Proxy-Authorization", s);
}
m_send_buf = m_ClientRequest.to_string();
m_recv_buf.erase(0, m_req_len);
m_send_buf.append(m_recv_buf);
GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port);
}

View file

@ -250,7 +250,7 @@ namespace client
if (handler)
(this->*handler)(m_Payload, m_PayloadLen);
else
LogPrint (eLogError, "I2CP: Unknown I2CP messsage ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]);
LogPrint (eLogError, "I2CP: Unknown I2CP message ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]);
}
void I2CPSession::Terminate ()
@ -398,7 +398,7 @@ namespace client
}
else
{
LogPrint (eLogError, "I2CP: create session signature verification falied");
LogPrint (eLogError, "I2CP: create session signature verification failed");
SendSessionStatusMessage (3); // invalid
}
}
@ -455,16 +455,16 @@ namespace client
LogPrint(eLogError, "I2CP: invalid reconfigure message signature");
}
else
LogPrint(eLogError, "I2CP: mapping size missmatch");
LogPrint(eLogError, "I2CP: mapping size mismatch");
}
else
LogPrint(eLogError, "I2CP: destination missmatch");
LogPrint(eLogError, "I2CP: destination mismatch");
}
else
LogPrint(eLogError, "I2CP: malfromed destination");
}
else
LogPrint(eLogError, "I2CP: session missmatch");
LogPrint(eLogError, "I2CP: session mismatch");
}
else
LogPrint(eLogError, "I2CP: short message");

View file

@ -14,6 +14,7 @@ namespace client
m_LocalDestination (localDestination ? localDestination :
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)),
m_ReadyTimer(m_LocalDestination->GetService()),
m_ReadyTimerTriggered(false),
m_ConnectTimeout(0),
isUpdated (true)
{
@ -47,29 +48,25 @@ namespace client
void I2PService::SetConnectTimeout(uint32_t timeout)
{
if(timeout && !m_ConnectTimeout)
{
TriggerReadyCheckTimer();
}
else if (m_ConnectTimeout && !timeout)
{
m_ReadyTimer.cancel();
}
m_ConnectTimeout = timeout;
}
void I2PService::AddReadyCallback(ReadyCallback cb)
{
uint32_t now = i2p::util::GetSecondsSinceEpoch();
uint32_t tm = now + m_ConnectTimeout;
uint32_t tm = (m_ConnectTimeout) ? now + m_ConnectTimeout : NEVER_TIMES_OUT;
LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now);
m_ReadyCallbacks.push_back({cb, tm});
if (!m_ReadyTimerTriggered) TriggerReadyCheckTimer();
}
void I2PService::TriggerReadyCheckTimer()
{
m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1));
m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_1));
m_ReadyTimerTriggered = true;
}
void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec)
@ -87,7 +84,7 @@ namespace client
auto itr = m_ReadyCallbacks.begin();
while(itr != m_ReadyCallbacks.end())
{
if(itr->second >= now)
if(itr->second != NEVER_TIMES_OUT && now >= itr->second)
{
itr->first(boost::asio::error::timed_out);
itr = m_ReadyCallbacks.erase(itr);
@ -96,8 +93,10 @@ namespace client
++itr;
}
}
if(!ec)
TriggerReadyCheckTimer();
if(!ec && m_ReadyCallbacks.size())
TriggerReadyCheckTimer();
else
m_ReadyTimerTriggered = false;
}
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {

View file

@ -67,8 +67,11 @@ namespace client
std::mutex m_HandlersMutex;
std::vector<std::pair<ReadyCallback, uint32_t> > m_ReadyCallbacks;
boost::asio::deadline_timer m_ReadyTimer;
bool m_ReadyTimerTriggered;
uint32_t m_ConnectTimeout;
const size_t NEVER_TIMES_OUT = 0;
public:
bool isUpdated; // transient, used during reload only
};

View file

@ -280,8 +280,6 @@ namespace client
const char* GetName() { return m_Name.c_str (); }
void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); }
private:
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);

View file

@ -15,8 +15,8 @@ namespace i2p
{
namespace client
{
SAMSocket::SAMSocket (SAMBridge& owner, std::shared_ptr<Socket_t> socket):
m_Owner (owner), m_Socket(socket), m_Timer (m_Owner.GetService ()),
SAMSocket::SAMSocket (SAMBridge& owner):
m_Owner (owner), m_Socket(owner.GetService()), m_Timer (m_Owner.GetService ()),
m_BufferOffset (0),
m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false),
m_IsAccepting (false), m_Stream (nullptr)
@ -25,51 +25,17 @@ namespace client
SAMSocket::~SAMSocket ()
{
if(m_Stream)
{
m_Stream->Close ();
m_Stream.reset ();
}
auto Session = m_Owner.FindSession(m_ID);
switch (m_SocketType)
{
case eSAMSocketTypeSession:
m_Owner.CloseSession (m_ID);
break;
case eSAMSocketTypeStream:
{
if (Session)
Session->DelSocket (this);
break;
}
case eSAMSocketTypeAcceptor:
{
if (Session)
{
Session->DelSocket (this);
if (m_IsAccepting && Session->localDestination)
Session->localDestination->StopAcceptingStreams ();
}
break;
}
default:
;
}
m_SocketType = eSAMSocketTypeTerminated;
if (m_Socket && m_Socket->is_open()) m_Socket->close ();
m_Socket.reset ();
m_Stream = nullptr;
}
void SAMSocket::Terminate (const char* reason)
{
if(m_Stream)
{
m_Stream->Close ();
m_Stream.reset ();
m_Stream->AsyncClose ();
m_Stream = nullptr;
}
auto Session = m_Owner.FindSession(m_ID);
switch (m_SocketType)
{
case eSAMSocketTypeSession:
@ -77,15 +43,12 @@ namespace client
break;
case eSAMSocketTypeStream:
{
if (Session)
Session->DelSocket (this);
break;
}
case eSAMSocketTypeAcceptor:
{
if (Session)
{
Session->DelSocket (this);
if (m_IsAccepting && Session->localDestination)
Session->localDestination->StopAcceptingStreams ();
}
@ -95,16 +58,20 @@ namespace client
;
}
m_SocketType = eSAMSocketTypeTerminated;
if (m_Socket && m_Socket->is_open()) m_Socket->close ();
m_Socket.reset ();
if (m_Socket.is_open ())
{
boost::system::error_code ec;
m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec);
m_Socket.close ();
}
m_Owner.RemoveSocket(shared_from_this());
}
void SAMSocket::ReceiveHandshake ()
{
if(m_Socket)
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
{
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
static bool SAMVersionAcceptable(const std::string & ver)
@ -125,7 +92,7 @@ namespace client
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
{
LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ("SAM: handshake read error");
@ -184,7 +151,7 @@ namespace client
#else
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
#endif
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (),
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (),
std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
@ -199,17 +166,22 @@ namespace client
}
}
bool SAMSocket::IsSession(const std::string & id) const
{
return id == m_ID;
}
void SAMSocket::HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
{
LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ("SAM: handshake reply send error");
}
else if(m_Socket)
else
{
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
std::bind(&SAMSocket::HandleMessage, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
@ -220,7 +192,7 @@ namespace client
LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg);
if (!m_IsSilent)
boost::asio::async_write (*m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, close));
else
@ -235,7 +207,7 @@ namespace client
void SAMSocket::HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close)
{
if (ecode)
{
{
LogPrint (eLogError, "SAM: reply send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ("SAM: reply send error");
@ -252,7 +224,7 @@ namespace client
void SAMSocket::HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
{
LogPrint (eLogError, "SAM: read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ("SAM: read error");
@ -501,7 +473,6 @@ namespace client
if(session)
{
m_SocketType = eSAMSocketTypeStream;
session->AddSocket (shared_from_this ());
m_Stream = session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
m_BufferOffset = 0;
@ -534,7 +505,6 @@ namespace client
if (session)
{
m_SocketType = eSAMSocketTypeAcceptor;
session->AddSocket (shared_from_this ());
if (!session->localDestination->IsAcceptingStreams ())
{
m_IsAccepting = true;
@ -599,7 +569,7 @@ namespace client
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
#else
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
#endif
SendMessageReply (m_Buffer, l, false);
}
@ -704,17 +674,9 @@ namespace client
void SAMSocket::Receive ()
{
if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE)
{
LogPrint (eLogError, "SAM: Buffer is full, terminate");
Terminate ("Buffer is full");
return;
} else if (m_Socket)
m_Socket->async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset),
std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage,
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
else
LogPrint(eLogError, "SAM: receive with no native socket");
m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset),
std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage,
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@ -731,15 +693,12 @@ namespace client
{
bytes_transferred += m_BufferOffset;
m_BufferOffset = 0;
auto s = shared_from_this ();
m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred,
[s](const boost::system::error_code& ecode)
{
if (!ecode)
s->m_Owner.GetService ().post ([s] { s->Receive (); });
else
s->m_Owner.GetService ().post ([s] { s->Terminate ("AsyncSend failed"); });
});
std::bind(&SAMSocket::HandleStreamSend, shared_from_this(), std::placeholders::_1));
}
else
{
Terminate("No Stream Remaining");
}
}
}
@ -766,21 +725,21 @@ namespace client
WriteI2PDataImmediate(buff, len);
}
else // no more data
{
delete [] buff;
Terminate ("no more data");
}
}
}
}
void SAMSocket::WriteI2PDataImmediate(uint8_t * buff, size_t sz)
{
if(m_Socket)
boost::asio::async_write (
*m_Socket,
boost::asio::buffer (buff, sz),
boost::asio::transfer_all(),
std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination
else
LogPrint(eLogError, "SAM: no native socket");
boost::asio::async_write (
m_Socket,
boost::asio::buffer (buff, sz),
boost::asio::transfer_all(),
std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination
}
void SAMSocket::HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff)
@ -790,9 +749,11 @@ namespace client
void SAMSocket::WriteI2PData(size_t sz)
{
uint8_t * sendbuff = new uint8_t[sz];
memcpy(sendbuff, m_StreamBuffer, sz);
WriteI2PDataImmediate(sendbuff, sz);
boost::asio::async_write (
m_Socket,
boost::asio::buffer (m_StreamBuffer, sz),
boost::asio::transfer_all(),
std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}
void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@ -826,7 +787,8 @@ namespace client
{
WriteI2PData(bytes_transferred);
}
I2PReceive();
else
I2PReceive();
}
}
}
@ -858,7 +820,7 @@ namespace client
if (session)
{
// find more pending acceptors
for (auto it: session->ListSockets ())
for (auto & it: m_Owner.ListSockets (m_ID))
if (it->m_SocketType == eSAMSocketTypeAcceptor)
{
it->m_IsAccepting = true;
@ -930,29 +892,30 @@ namespace client
}
}
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
void SAMSocket::HandleStreamSend(const boost::system::error_code & ec)
{
m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this()));
}
SAMSession::SAMSession (SAMBridge & parent, const std::string & id, std::shared_ptr<ClientDestination> dest):
m_Bridge(parent),
localDestination (dest),
UDPEndpoint(nullptr)
UDPEndpoint(nullptr),
Name(id)
{
}
SAMSession::~SAMSession ()
{
CloseStreams();
i2p::client::context.DeleteLocalDestination (localDestination);
}
void SAMSession::CloseStreams ()
{
std::vector<std::shared_ptr<SAMSocket> > socks;
for(const auto & itr : m_Bridge.ListSockets(Name))
{
std::lock_guard<std::mutex> lock(m_SocketsMutex);
for (const auto& sock : m_Sockets) {
socks.push_back(sock);
}
itr->Terminate(nullptr);
}
for (auto & sock : socks ) sock->Terminate("SAMSession::CloseStreams()");
m_Sockets.clear();
}
SAMBridge::SAMBridge (const std::string& address, int port):
@ -1009,12 +972,17 @@ namespace client
void SAMBridge::Accept ()
{
auto native = std::make_shared<boost::asio::ip::tcp::socket>(m_Service);
auto newSocket = std::make_shared<SAMSocket> (*this, native);
m_Acceptor.async_accept (*native, std::bind (&SAMBridge::HandleAccept, this,
auto newSocket = std::make_shared<SAMSocket>(*this);
m_Acceptor.async_accept (newSocket->GetSocket(), std::bind (&SAMBridge::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket)
{
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
m_OpenSockets.remove_if([socket](const std::shared_ptr<SAMSocket> & item) -> bool { return item == socket; });
}
void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
{
if (!ecode)
@ -1024,6 +992,10 @@ namespace client
if (!ec)
{
LogPrint (eLogDebug, "SAM: new connection from ", ep);
{
std::unique_lock<std::mutex> l(m_OpenSocketsMutex);
m_OpenSockets.push_back(socket);
}
socket->ReceiveHandshake ();
}
else
@ -1066,7 +1038,7 @@ namespace client
if (localDestination)
{
localDestination->Acquire ();
auto session = std::make_shared<SAMSession>(localDestination);
auto session = std::make_shared<SAMSession>(*this, id, localDestination);
std::unique_lock<std::mutex> l(m_SessionsMutex);
auto ret = m_Sessions.insert (std::make_pair(id, session));
if (!ret.second)
@ -1105,6 +1077,18 @@ namespace client
return nullptr;
}
std::list<std::shared_ptr<SAMSocket> > SAMBridge::ListSockets(const std::string & id) const
{
std::list<std::shared_ptr<SAMSocket > > list;
{
std::unique_lock<std::mutex> l(m_OpenSocketsMutex);
for (const auto & itr : m_OpenSockets)
if (itr->IsSession(id))
list.push_back(itr);
}
return list;
}
void SAMBridge::SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote)
{
if(remote)
@ -1127,33 +1111,38 @@ namespace client
{
m_DatagramReceiveBuffer[bytes_transferred] = 0;
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
*eol = 0; eol++;
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
if (sessionID)
if(eol)
{
sessionID++;
char * destination = strchr (sessionID, ' ');
if (destination)
*eol = 0; eol++;
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
if (sessionID)
{
*destination = 0; destination++;
auto session = FindSession (sessionID);
if (session)
sessionID++;
char * destination = strchr (sessionID, ' ');
if (destination)
{
i2p::data::IdentityEx dest;
dest.FromBase64 (destination);
session->localDestination->GetDatagramDestination ()->
SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
*destination = 0; destination++;
auto session = FindSession (sessionID);
if (session)
{
i2p::data::IdentityEx dest;
dest.FromBase64 (destination);
session->localDestination->GetDatagramDestination ()->
SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
}
else
LogPrint (eLogError, "SAM: Session ", sessionID, " not found");
}
else
LogPrint (eLogError, "SAM: Session ", sessionID, " not found");
LogPrint (eLogError, "SAM: Missing destination key");
}
else
LogPrint (eLogError, "SAM: Missing destination key");
LogPrint (eLogError, "SAM: Missing sessionID");
}
else
LogPrint (eLogError, "SAM: Missing sessionID");
LogPrint(eLogError, "SAM: invalid datagram");
ReceiveDatagram ();
}
else

View file

@ -82,18 +82,21 @@ namespace client
public:
typedef boost::asio::ip::tcp::socket Socket_t;
SAMSocket (SAMBridge& owner, std::shared_ptr<Socket_t> socket);
SAMSocket (SAMBridge& owner);
~SAMSocket ();
boost::asio::ip::tcp::socket& GetSocket () { return *m_Socket; };
Socket_t& GetSocket () { return m_Socket; };
void ReceiveHandshake ();
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
SAMSocketType GetSocketType () const { return m_SocketType; };
void Terminate (const char* reason);
bool IsSession(const std::string & id) const;
private:
void TerminateClose() { Terminate(nullptr); }
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -128,10 +131,12 @@ namespace client
void WriteI2PDataImmediate(uint8_t * ptr, size_t sz);
void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff);
void HandleStreamSend(const boost::system::error_code & ec);
private:
SAMBridge& m_Owner;
std::shared_ptr<Socket_t> m_Socket;
Socket_t m_Socket;
boost::asio::deadline_timer m_Timer;
char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
size_t m_BufferOffset;
@ -145,34 +150,12 @@ namespace client
struct SAMSession
{
SAMBridge & m_Bridge;
std::shared_ptr<ClientDestination> localDestination;
std::list<std::shared_ptr<SAMSocket> > m_Sockets;
std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint;
std::mutex m_SocketsMutex;
std::string Name;
/** safely add a socket to this session */
void AddSocket(std::shared_ptr<SAMSocket> sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.push_back(sock);
}
/** safely remove a socket from this session */
void DelSocket(SAMSocket * sock) {
std::lock_guard<std::mutex> lock(m_SocketsMutex);
m_Sockets.remove_if([sock](const std::shared_ptr<SAMSocket> s) -> bool { return s.get() == sock; });
}
/** get a list holding a copy of all sam sockets from this session */
std::list<std::shared_ptr<SAMSocket> > ListSockets() {
std::list<std::shared_ptr<SAMSocket> > l;
{
std::lock_guard<std::mutex> lock(m_SocketsMutex);
for(const auto& sock : m_Sockets ) l.push_back(sock);
}
return l;
}
SAMSession (std::shared_ptr<ClientDestination> dest);
SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr<ClientDestination> dest);
~SAMSession ();
void CloseStreams ();
@ -189,14 +172,18 @@ namespace client
void Stop ();
boost::asio::io_service& GetService () { return m_Service; };
std::shared_ptr<SAMSession> CreateSession (const std::string& id, const std::string& destination, // empty string means transient
std::shared_ptr<SAMSession> CreateSession (const std::string& id, const std::string& destination, // empty string means transient
const std::map<std::string, std::string> * params);
void CloseSession (const std::string& id);
std::shared_ptr<SAMSession> FindSession (const std::string& id) const;
std::list<std::shared_ptr<SAMSocket> > ListSockets(const std::string & id) const;
/** send raw data to remote endpoint from our UDP Socket */
void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
private:
void Run ();
@ -217,6 +204,8 @@ namespace client
boost::asio::ip::udp::socket m_DatagramSocket;
mutable std::mutex m_SessionsMutex;
std::map<std::string, std::shared_ptr<SAMSession> > m_Sessions;
mutable std::mutex m_OpenSocketsMutex;
std::list<std::shared_ptr<SAMSocket> > m_OpenSockets;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
public:

View file

@ -84,8 +84,8 @@ namespace proxy
SOCKS5_HOST_UNREACH = 4, // Host unreachable
SOCKS5_CONN_REFUSED = 5, // Connection refused by the peer
SOCKS5_TTL_EXPIRED = 6, // TTL Expired
SOCKS5_CMD_UNSUP = 7, // Command unsuported
SOCKS5_ADDR_UNSUP = 8, // Address type unsuported
SOCKS5_CMD_UNSUP = 7, // Command unsupported
SOCKS5_ADDR_UNSUP = 8, // Address type unsupported
SOCKS4_OK = 90, // No error for SOCKS4
SOCKS4_FAIL = 91, // Failed establishing connecting or not allowed
SOCKS4_IDENTD_MISSING = 92, // Couldn't connect to the identd server