Browse Source

Merge pull request #843 from majestrate/obep-ibgw

Allow point to point client tunnels to use OB tunnels that share OBEP and IBGW of remote destination
pull/844/head
orignal 8 years ago committed by GitHub
parent
commit
36ea6c13df
  1. 22
      ClientContext.cpp
  2. 5
      ClientContext.h
  3. 3
      Datagram.h
  4. 4
      Destination.h
  5. 113
      MatchedDestination.cpp
  6. 36
      MatchedDestination.h
  7. 34
      TunnelPool.cpp
  8. 25
      TunnelPool.h
  9. 1
      build/CMakeLists.txt
  10. 3
      filelist.mk

22
ClientContext.cpp

@ -10,6 +10,7 @@
#include "ClientContext.h" #include "ClientContext.h"
#include "SOCKS.h" #include "SOCKS.h"
#include "WebSocks.h" #include "WebSocks.h"
#include "MatchedDestination.h"
namespace i2p namespace i2p
{ {
@ -308,7 +309,7 @@ namespace client
} }
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
const std::map<std::string, std::string> * params) const std::map<std::string, std::string> * params)
{ {
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params); auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
@ -318,6 +319,16 @@ namespace client
return localDestination; return localDestination;
} }
std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
{
MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params);
auto localDestination = std::shared_ptr<ClientDestination>(cl);
std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start ();
return localDestination;
}
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination) void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
{ {
if (!destination) return; if (!destination) return;
@ -440,6 +451,7 @@ namespace client
dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION); dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION);
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT); int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
// optional params // optional params
bool matchTunnels = section.second.get(I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false);
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, ""); std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
@ -456,9 +468,15 @@ namespace client
{ {
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
if (!localDestination) if (!localDestination)
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options); {
if(matchTunnels)
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
else
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
}
} }
} }
if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) { if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) {
// udp client // udp client
// TODO: hostnames // TODO: hostnames

5
ClientContext.h

@ -35,6 +35,7 @@ namespace client
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys"; const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport"; const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
const char I2P_SERVER_TUNNEL_HOST[] = "host"; const char I2P_SERVER_TUNNEL_HOST[] = "host";
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride"; const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
const char I2P_SERVER_TUNNEL_PORT[] = "port"; const char I2P_SERVER_TUNNEL_PORT[] = "port";
@ -47,6 +48,7 @@ namespace client
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address"; const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal"; const char I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL[] = "enableuniquelocal";
class ClientContext class ClientContext
{ {
public: public:
@ -63,7 +65,8 @@ namespace client
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1, std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
const std::map<std::string, std::string> * params = nullptr); // transient const std::map<std::string, std::string> * params = nullptr); // transient
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr); const std::map<std::string, std::string> * params = nullptr);
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination); void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const; std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);

3
Datagram.h

@ -103,7 +103,7 @@ namespace datagram
public: public:
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);
@ -147,4 +147,3 @@ namespace datagram
} }
#endif #endif

4
Destination.h

@ -175,8 +175,8 @@ namespace client
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr); ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
~ClientDestination (); ~ClientDestination ();
bool Start (); virtual bool Start ();
bool Stop (); virtual bool Stop ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };

113
MatchedDestination.cpp

@ -0,0 +1,113 @@
#include "MatchedDestination.h"
#include "Log.h"
#include "ClientContext.h"
namespace i2p
{
namespace client
{
MatchedTunnelDestination::MatchedTunnelDestination(const i2p::data::PrivateKeys & keys, const std::string & remoteName, const std::map<std::string, std::string> * params)
: ClientDestination(keys, false, params),
m_RemoteName(remoteName) {}
void MatchedTunnelDestination::ResolveCurrentLeaseSet()
{
if(i2p::client::context.GetAddressBook().GetIdentHash(m_RemoteName, m_RemoteIdent))
{
auto ls = FindLeaseSet(m_RemoteIdent);
if(ls)
{
HandleFoundCurrentLeaseSet(ls);
}
else
RequestDestination(m_RemoteIdent, std::bind(&MatchedTunnelDestination::HandleFoundCurrentLeaseSet, this, std::placeholders::_1));
}
else
LogPrint(eLogWarning, "Destination: failed to resolve ", m_RemoteName);
}
void MatchedTunnelDestination::HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls)
{
if(ls)
{
LogPrint(eLogDebug, "Destination: resolved remote lease set for ", m_RemoteName);
m_RemoteLeaseSet = ls;
}
else
{
m_ResolveTimer->expires_from_now(boost::posix_time::seconds(1));
m_ResolveTimer->async_wait([&](const boost::system::error_code & ec) {
if(!ec) ResolveCurrentLeaseSet();
});
}
}
bool MatchedTunnelDestination::Start()
{
if(ClientDestination::Start())
{
m_ResolveTimer = std::make_shared<boost::asio::deadline_timer>(GetService());
GetTunnelPool()->SetCustomPeerSelector(this);
ResolveCurrentLeaseSet();
return true;
}
else
return false;
}
bool MatchedTunnelDestination::Stop()
{
if(ClientDestination::Stop())
{
if(m_ResolveTimer)
m_ResolveTimer->cancel();
return true;
}
else
return false;
}
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
{
auto pool = GetTunnelPool();
if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound, std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1)))
return false;
// more here for outbound tunnels
if(!inbound && m_RemoteLeaseSet)
{
if(m_RemoteLeaseSet->IsExpired())
{
ResolveCurrentLeaseSet();
}
if(m_RemoteLeaseSet && !m_RemoteLeaseSet->IsExpired())
{
// remote lease set is good
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases();
// pick lease
std::shared_ptr<i2p::data::RouterInfo> obep;
while(!obep && leases.size() > 0) {
auto idx = rand() % leases.size();
auto lease = leases[idx];
obep = i2p::data::netdb.FindRouter(lease->tunnelGateway);
leases.erase(leases.begin()+idx);
}
if(obep) {
path.push_back(obep->GetRouterIdentity());
LogPrint(eLogDebug, "Destination: found OBEP matching IBGW");
} else
LogPrint(eLogWarning, "Destination: could not find proper IBGW for matched outbound tunnel");
}
}
return true;
}
bool MatchedTunnelDestination::OnBuildResult(const i2p::tunnel::Path & path, bool inbound, i2p::tunnel::TunnelBuildResult result)
{
return true;
}
}
}

36
MatchedDestination.h

@ -0,0 +1,36 @@
#ifndef MATCHED_DESTINATION_H_
#define MATCHED_DESTINATION_H_
#include "Destination.h"
#include <string>
namespace i2p
{
namespace client
{
/**
client tunnel that uses same OBEP as IBGW of each remote lease for a remote destination
*/
class MatchedTunnelDestination : public ClientDestination, public i2p::tunnel::ITunnelPeerSelector
{
public:
MatchedTunnelDestination(const i2p::data::PrivateKeys& keys, const std::string & remoteName, const std::map<std::string, std::string> * params = nullptr);
bool Start();
bool Stop();
bool SelectPeers(i2p::tunnel::Path & peers, int hops, bool inbound);
bool OnBuildResult(const i2p::tunnel::Path & peers, bool inbound, i2p::tunnel::TunnelBuildResult result);
private:
void ResolveCurrentLeaseSet();
void HandleFoundCurrentLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> ls);
private:
std::string m_RemoteName;
i2p::data::IdentHash m_RemoteIdent;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<boost::asio::deadline_timer> m_ResolveTimer;
};
}
}
#endif

34
TunnelPool.cpp

@ -372,20 +372,8 @@ namespace tunnel
return hop; return hop;
} }
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound) bool StandardSelectPeers(Path & peers, int numHops, bool inbound, SelectHopFunc nextHop)
{ {
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
// peers is empty
if (numHops <= 0) return true;
// custom peer selector in use ?
{
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
}
// explicit peers in use
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
auto prevHop = i2p::context.GetSharedRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo ();
if(i2p::transport::transports.RoutesRestricted()) if(i2p::transport::transports.RoutesRestricted())
{ {
@ -408,7 +396,7 @@ namespace tunnel
for(int i = 0; i < numHops; i++ ) for(int i = 0; i < numHops; i++ )
{ {
auto hop = SelectNextHop (prevHop); auto hop = nextHop (prevHop);
if (!hop) if (!hop)
{ {
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
@ -420,6 +408,22 @@ namespace tunnel
return true; return true;
} }
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
{
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
// peers is empty
if (numHops <= 0) return true;
// custom peer selector in use ?
{
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
}
// explicit peers in use
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
return StandardSelectPeers(peers, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, std::placeholders::_1));
}
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound) bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
{ {
int size = m_ExplicitPeers->size (); int size = m_ExplicitPeers->size ();
@ -535,7 +539,7 @@ namespace tunnel
tunnel->SetTunnelPool (shared_from_this ()); tunnel->SetTunnelPool (shared_from_this ());
} }
void TunnelPool::SetCustomPeerSelector(TunnelPeerSelector selector) void TunnelPool::SetCustomPeerSelector(ITunnelPeerSelector * selector)
{ {
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
m_CustomPeerSelector = selector; m_CustomPeerSelector = selector;

25
TunnelPool.h

@ -30,17 +30,21 @@ namespace tunnel
eBuildResultTimeout // tunnel build timed out eBuildResultTimeout // tunnel build timed out
}; };
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
typedef std::vector<Peer> Path;
/** interface for custom tunnel peer selection algorithm */ /** interface for custom tunnel peer selection algorithm */
struct ITunnelPeerSelector struct ITunnelPeerSelector
{ {
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer; virtual ~ITunnelPeerSelector() {};
typedef std::vector<Peer> TunnelPath; virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
virtual bool OnBuildResult(const Path & peers, bool isInbound, TunnelBuildResult result) = 0;
virtual bool SelectPeers(TunnelPath & peers, int hops, bool isInbound) = 0;
virtual bool OnBuildResult(TunnelPath & peers, bool isInbound, TunnelBuildResult result) = 0;
}; };
typedef std::shared_ptr<ITunnelPeerSelector> TunnelPeerSelector;
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>)> SelectHopFunc;
// standard peer selection algorithm
bool StandardSelectPeers(Path & path, int hops, bool inbound, SelectHopFunc nextHop);
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
{ {
@ -75,7 +79,7 @@ namespace tunnel
int GetNumInboundTunnels () const { return m_NumInboundTunnels; }; int GetNumInboundTunnels () const { return m_NumInboundTunnels; };
int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; }; int GetNumOutboundTunnels () const { return m_NumOutboundTunnels; };
void SetCustomPeerSelector(TunnelPeerSelector selector); void SetCustomPeerSelector(ITunnelPeerSelector * selector);
void UnsetCustomPeerSelector(); void UnsetCustomPeerSelector();
bool HasCustomPeerSelector(); bool HasCustomPeerSelector();
@ -91,6 +95,9 @@ namespace tunnel
void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result); void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result);
// for overriding tunnel peer selection
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
private: private:
void CreateInboundTunnel (); void CreateInboundTunnel ();
@ -98,7 +105,6 @@ namespace tunnel
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel); void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound); bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound); bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& hops, bool isInbound);
@ -115,7 +121,7 @@ namespace tunnel
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests; std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
bool m_IsActive; bool m_IsActive;
std::mutex m_CustomPeerSelectorMutex; std::mutex m_CustomPeerSelectorMutex;
TunnelPeerSelector m_CustomPeerSelector; ITunnelPeerSelector * m_CustomPeerSelector;
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
@ -131,4 +137,3 @@ namespace tunnel
} }
#endif #endif

1
build/CMakeLists.txt

@ -92,6 +92,7 @@ set (CLIENT_SRC
"${CMAKE_SOURCE_DIR}/AddressBook.cpp" "${CMAKE_SOURCE_DIR}/AddressBook.cpp"
"${CMAKE_SOURCE_DIR}/BOB.cpp" "${CMAKE_SOURCE_DIR}/BOB.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp" "${CMAKE_SOURCE_DIR}/ClientContext.cpp"
"${CMAKE_SOURCE_DIR}/MatchedDestination.cpp"
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/I2PService.cpp" "${CMAKE_SOURCE_DIR}/I2PService.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp"

3
filelist.mk

@ -8,10 +8,9 @@ LIB_SRC = \
Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp
LIB_CLIENT_SRC = \ LIB_CLIENT_SRC = \
AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp
# also: Daemon{Linux,Win32}.cpp will be added later # also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = \ DAEMON_SRC = \
HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp

Loading…
Cancel
Save