Browse Source

Merge pull request #391 from PurpleI2P/openssl

new fs
pull/394/head
orignal 9 years ago
parent
commit
dbdc7279c4
  1. 222
      AddressBook.cpp
  2. 3
      AddressBook.h
  3. 14
      Base.cpp
  4. 1
      Base.h
  5. 19
      ClientContext.cpp
  6. 31
      Daemon.cpp
  7. 9
      DaemonLinux.cpp
  8. 44
      Destination.cpp
  9. 158
      FS.cpp
  10. 142
      FS.h
  11. 35
      Family.cpp
  12. 3
      HTTPServer.cpp
  13. 12
      I2PControl.cpp
  14. 3
      I2PControl.h
  15. 236
      NetDb.cpp
  16. 9
      NetDb.h
  17. 178
      Profiling.cpp
  18. 3
      Profiling.h
  19. 26
      Reseed.cpp
  20. 9
      RouterContext.cpp
  21. 5
      RouterInfo.cpp
  22. 3
      RouterInfo.h
  23. 28
      SSUSession.cpp
  24. 5
      SSUSession.h
  25. 12
      api.cpp
  26. 1
      build/CMakeLists.txt
  27. 1
      docs/index.rst
  28. 4
      filelist.mk
  29. 133
      util.cpp
  30. 17
      util.h

222
AddressBook.cpp

@ -5,11 +5,11 @@
#include <fstream> #include <fstream>
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "Base.h" #include "Base.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "NetDb.h" #include "NetDb.h"
#include "ClientContext.h" #include "ClientContext.h"
@ -19,143 +19,107 @@ namespace i2p
{ {
namespace client namespace client
{ {
// TODO: this is actually proxy class
class AddressBookFilesystemStorage: public AddressBookStorage class AddressBookFilesystemStorage: public AddressBookStorage
{ {
public: private:
i2p::fs::HashedStorage storage;
std::string indexPath;
AddressBookFilesystemStorage (); public:
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") {};
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const; std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const;
void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address); void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
void RemoveAddress (const i2p::data::IdentHash& ident); void RemoveAddress (const i2p::data::IdentHash& ident);
bool Init ();
int Load (std::map<std::string, i2p::data::IdentHash>& addresses); int Load (std::map<std::string, i2p::data::IdentHash>& addresses);
int Save (const std::map<std::string, i2p::data::IdentHash>& addresses); int Save (const std::map<std::string, i2p::data::IdentHash>& addresses);
private:
boost::filesystem::path GetPath () const
{
return i2p::util::filesystem::GetDefaultDataDir() / "addressbook";
}
boost::filesystem::path GetAddressPath (const i2p::data::IdentHash& ident) const
{
auto b32 = ident.ToBase32();
return GetPath () / (std::string ("b") + b32[0]) / (b32 + ".b32");
}
}; };
AddressBookFilesystemStorage::AddressBookFilesystemStorage () bool AddressBookFilesystemStorage::Init()
{ {
auto path = GetPath (); storage.SetPlace(i2p::fs::GetDataDir());
if (!boost::filesystem::exists (path)) indexPath = storage.GetRoot() + i2p::fs::dirSep + "addresses.csv";
{ return storage.Init(i2p::data::GetBase32SubstitutionTable(), 32);
// Create directory is necessary
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Addressbook: failed to create addressbook directory");
}
} }
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
{ {
auto filename = GetAddressPath (ident); std::string filename = storage.Path(ident.ToBase32());
if (!boost::filesystem::exists (filename)) std::ifstream f(filename, std::ifstream::binary);
{ if (!f.is_open ()) {
boost::filesystem::create_directory (filename.parent_path ()); LogPrint(eLogDebug, "Addressbook: Requested, but not found: ", filename);
// try to find in main folder return nullptr;
auto filename1 = GetPath () / (ident.ToBase32 () + ".b32");
if (!boost::filesystem::exists (filename1))
{
boost::system::error_code ec;
boost::filesystem::rename (filename1, filename, ec);
if (ec)
LogPrint (eLogError, "Addresbook: couldn't move file ", ec.message ());
}
else
return nullptr; // address doesn't exist
}
std::ifstream f(filename.string (), std::ifstream::binary);
if (f.is_open ())
{
f.seekg (0,std::ios::end);
size_t len = f.tellg ();
if (len < i2p::data::DEFAULT_IDENTITY_SIZE)
{
LogPrint (eLogError, "Addresbook: File ", filename, " is too short. ", len);
return nullptr;
}
f.seekg(0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
f.read((char *)buf, len);
auto address = std::make_shared<i2p::data::IdentityEx>(buf, len);
delete[] buf;
return address;
} }
else
f.seekg (0,std::ios::end);
size_t len = f.tellg ();
if (len < i2p::data::DEFAULT_IDENTITY_SIZE) {
LogPrint (eLogError, "Addresbook: File ", filename, " is too short: ", len);
return nullptr; return nullptr;
}
f.seekg(0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
f.read((char *)buf, len);
auto address = std::make_shared<i2p::data::IdentityEx>(buf, len);
delete[] buf;
return address;
} }
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
{ {
auto filename = GetAddressPath (address->GetIdentHash ()); std::string path = storage.Path( address->GetIdentHash().ToBase32() );
std::ofstream f (filename.string (), std::ofstream::binary | std::ofstream::out); std::ofstream f (path, std::ofstream::binary | std::ofstream::out);
if (!f.is_open ()) if (!f.is_open ()) {
{ LogPrint (eLogError, "Addresbook: can't open file ", path);
// create subdirectory return;
if (boost::filesystem::create_directory (filename.parent_path ()))
f.open (filename.string (), std::ofstream::binary | std::ofstream::out); // and try to open again
}
if (f.is_open ())
{
size_t len = address->GetFullLen ();
uint8_t * buf = new uint8_t[len];
address->ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
} }
else size_t len = address->GetFullLen ();
LogPrint (eLogError, "Addresbook: can't open file ", filename); uint8_t * buf = new uint8_t[len];
address->ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
} }
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident) void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
{ {
auto filename = GetAddressPath (ident); storage.Remove( ident.ToBase32() );
if (boost::filesystem::exists (filename))
boost::filesystem::remove (filename);
} }
int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses) int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses)
{ {
int num = 0; int num = 0;
auto filename = GetPath () / "addresses.csv"; std::string s;
std::ifstream f (filename.string (), std::ifstream::in); // in text mode std::ifstream f (indexPath, std::ifstream::in); // in text mode
if (f.is_open ())
{
addresses.clear ();
while (!f.eof ())
{
std::string s;
getline(f, s);
if (!s.length())
continue; // skip empty line
size_t pos = s.find(','); if (f.is_open ()) {
if (pos != std::string::npos) LogPrint(eLogInfo, "Addressbook: using index file ", indexPath);
{ } else {
std::string name = s.substr(0, pos++); LogPrint(eLogWarning, "Addressbook: Can't open ", indexPath);
std::string addr = s.substr(pos); return 0;
}
i2p::data::IdentHash ident; addresses.clear ();
ident.FromBase32 (addr); while (!f.eof ()) {
addresses[name] = ident; getline(f, s);
num++; if (!s.length())
} continue; // skip empty line
std::size_t pos = s.find(',');
if (pos != std::string::npos)
{
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
i2p::data::IdentHash ident;
ident.FromBase32 (addr);
addresses[name] = ident;
num++;
} }
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded");
} }
else
LogPrint (eLogWarning, "Addressbook: ", filename, " not found"); LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded from storage");
return num; return num;
} }
@ -167,24 +131,23 @@ namespace client
} }
int num = 0; int num = 0;
auto filename = GetPath () / "addresses.csv"; std::ofstream f (indexPath, std::ofstream::out); // in text mode
std::ofstream f (filename.string (), std::ofstream::out); // in text mode
if (f.is_open ()) if (!f.is_open ()) {
{ LogPrint (eLogWarning, "Addressbook: Can't open ", indexPath);
for (auto it: addresses) return 0;
{
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
} }
else
LogPrint (eLogError, "Addresbook: can't open file ", filename); for (auto it: addresses) {
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
return num; return num;
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
AddressBook::AddressBook (): m_Storage (nullptr), m_IsLoaded (false), m_IsDownloading (false), AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false),
m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr) m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
{ {
} }
@ -196,6 +159,7 @@ namespace client
void AddressBook::Start () void AddressBook::Start ()
{ {
m_Storage->Init();
LoadHosts (); /* try storage, then hosts.txt, then download */ LoadHosts (); /* try storage, then hosts.txt, then download */
StartSubscriptions (); StartSubscriptions ();
} }
@ -235,11 +199,6 @@ namespace client
m_Subscriptions.clear (); m_Subscriptions.clear ();
} }
AddressBookStorage * AddressBook::CreateStorage ()
{
return new AddressBookFilesystemStorage ();
}
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident) bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
{ {
auto pos = address.find(".b32.i2p"); auto pos = address.find(".b32.i2p");
@ -283,8 +242,6 @@ namespace client
{ {
auto ident = std::make_shared<i2p::data::IdentityEx>(); auto ident = std::make_shared<i2p::data::IdentityEx>();
ident->FromBase64 (base64); ident->FromBase64 (base64);
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (ident); m_Storage->AddAddress (ident);
m_Addresses[address] = ident->GetIdentHash (); m_Addresses[address] = ident->GetIdentHash ();
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ())); LogPrint (eLogInfo, "Addressbook: added ", address," -> ", ToAddress(ident->GetIdentHash ()));
@ -292,15 +249,11 @@ namespace client
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address) void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
{ {
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (address); m_Storage->AddAddress (address);
} }
std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetAddress (const std::string& address) std::shared_ptr<const i2p::data::IdentityEx> AddressBook::GetAddress (const std::string& address)
{ {
if (!m_Storage)
m_Storage = CreateStorage ();
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
if (!GetIdentHash (address, ident)) return nullptr; if (!GetIdentHash (address, ident)) return nullptr;
return m_Storage->GetAddress (ident); return m_Storage->GetAddress (ident);
@ -308,16 +261,14 @@ namespace client
void AddressBook::LoadHosts () void AddressBook::LoadHosts ()
{ {
if (!m_Storage)
m_Storage = CreateStorage ();
if (m_Storage->Load (m_Addresses) > 0) if (m_Storage->Load (m_Addresses) > 0)
{ {
m_IsLoaded = true; m_IsLoaded = true;
return; return;
} }
// try hosts.txt first // then try hosts.txt
std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ifstream::in); // in text mode std::ifstream f (i2p::fs::DataDirPath("hosts.txt"), std::ifstream::in); // in text mode
if (f.is_open ()) if (f.is_open ())
{ {
LoadHostsFromStream (f); LoadHostsFromStream (f);
@ -367,7 +318,7 @@ namespace client
{ {
if (!m_Subscriptions.size ()) if (!m_Subscriptions.size ())
{ {
std::ifstream f (i2p::util::filesystem::GetFullPath ("subscriptions.txt").c_str (), std::ifstream::in); // in text mode std::ifstream f (i2p::fs::DataDirPath ("subscriptions.txt"), std::ifstream::in); // in text mode
if (f.is_open ()) if (f.is_open ())
{ {
std::string s; std::string s;
@ -431,7 +382,10 @@ namespace client
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
auto dest = i2p::client::context.GetSharedLocalDestination (); auto dest = i2p::client::context.GetSharedLocalDestination ();
if (!dest) return; if (!dest) {
LogPrint(eLogWarning, "Addressbook: missing local destination, skip subscription update");
return;
}
if (!m_IsDownloading && dest->IsReady ()) if (!m_IsDownloading && dest->IsReady ())
{ {
if (!m_IsLoaded) if (!m_IsLoaded)
@ -495,7 +449,7 @@ namespace client
}); });
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
{ {
LogPrint (eLogError, "Subscription LeaseSet request timeout expired"); LogPrint (eLogError, "Addressbook: Subscription LeaseSet request timeout expired");
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident); i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident);
} }
} }
@ -602,7 +556,7 @@ namespace client
LogPrint (eLogError, "Addressbook: Can't resolve ", u.host_); LogPrint (eLogError, "Addressbook: Can't resolve ", u.host_);
if (!success) if (!success)
LogPrint (eLogError, "Addressbook: download failed"); LogPrint (eLogError, "Addressbook: download hosts.txt from ", m_Link, " failed");
m_Book.DownloadComplete (success); m_Book.DownloadComplete (success);
} }

3
AddressBook.h

@ -10,7 +10,6 @@
#include <memory> #include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Base.h" #include "Base.h"
#include "util.h"
#include "Identity.h" #include "Identity.h"
#include "Log.h" #include "Log.h"
@ -36,6 +35,7 @@ namespace client
virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0; virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0;
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
virtual bool Init () = 0;
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0; virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0; virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
}; };
@ -65,7 +65,6 @@ namespace client
void StartSubscriptions (); void StartSubscriptions ();
void StopSubscriptions (); void StopSubscriptions ();
AddressBookStorage * CreateStorage ();
void LoadHosts (); void LoadHosts ();
void LoadSubscriptions (); void LoadSubscriptions ();

14
Base.cpp

@ -6,6 +6,18 @@ namespace i2p
{ {
namespace data namespace data
{ {
static const char T32[32] = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'k', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 't', 't', 'u', 'v', 'w', 'x',
'y', 'z', '2', '3', '4', '5', '6', '7',
};
const char * GetBase32SubstitutionTable ()
{
return T32;
}
static void iT64Build(void); static void iT64Build(void);
/* /*
@ -16,7 +28,7 @@ namespace data
* Direct Substitution Table * Direct Substitution Table
*/ */
static char T64[64] = { static const char T64[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',

1
Base.h

@ -13,6 +13,7 @@ namespace data
{ {
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable (); const char * GetBase64SubstitutionTable ();
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);

19
ClientContext.cpp

@ -3,7 +3,7 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include "Config.h" #include "Config.h"
#include "util.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "Identity.h" #include "Identity.h"
#include "ClientContext.h" #include "ClientContext.h"
@ -148,10 +148,10 @@ namespace client
m_SharedLocalDestination = nullptr; m_SharedLocalDestination = nullptr;
} }
void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType) void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType)
{ {
std::string fullPath = i2p::util::filesystem::GetFullPath (filename); std::string fullPath = i2p::fs::DataDirPath (filename);
std::ifstream s(fullPath.c_str (), std::ifstream::binary); std::ifstream s(fullPath, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ {
s.seekg (0, std::ios::end); s.seekg (0, std::ios::end);
@ -252,14 +252,17 @@ namespace client
void ClientContext::ReadTunnels () void ClientContext::ReadTunnels ()
{ {
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
std::string pathTunnelsConfigFile = i2p::util::filesystem::GetTunnelsConfigFile().string(); std::string tunConf; i2p::config::GetOption("tunconf", tunConf);
if (tunConf == "")
tunConf = i2p::fs::DataDirPath ("tunnels.cfg");
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
try try
{ {
boost::property_tree::read_ini (pathTunnelsConfigFile, pt); boost::property_tree::read_ini (tunConf, pt);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogWarning, "Clients: Can't read ", pathTunnelsConfigFile, ": ", ex.what ()); LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ());
return; return;
} }
@ -347,7 +350,7 @@ namespace client
numServerTunnels++; numServerTunnels++;
} }
else else
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", pathTunnelsConfigFile); LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", tunConf);
} }
catch (std::exception& ex) catch (std::exception& ex)

31
Daemon.cpp

@ -5,6 +5,7 @@
#include "Config.h" #include "Config.h"
#include "Log.h" #include "Log.h"
#include "FS.h"
#include "Base.h" #include "Base.h"
#include "version.h" #include "version.h"
#include "Transports.h" #include "Transports.h"
@ -14,7 +15,6 @@
#include "Tunnel.h" #include "Tunnel.h"
#include "NetDb.h" #include "NetDb.h"
#include "Garlic.h" #include "Garlic.h"
#include "util.h"
#include "Streaming.h" #include "Streaming.h"
#include "Destination.h" #include "Destination.h"
#include "HTTPServer.h" #include "HTTPServer.h"
@ -63,9 +63,18 @@ namespace i2p
i2p::config::Init(); i2p::config::Init();
i2p::config::ParseCmdline(argc, argv); i2p::config::ParseCmdline(argc, argv);
std::string config = i2p::util::filesystem::GetConfigFile().string(); std::string config; i2p::config::GetOption("conf", config);
std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string(); std::string datadir; i2p::config::GetOption("datadir", datadir);
std::string datadir = i2p::util::filesystem::GetDataDir().string(); i2p::fs::DetectDataDir(datadir, IsService());
i2p::fs::Init();
datadir = i2p::fs::GetDataDir();
if (config == "")
{
config = i2p::fs::DataDirPath("i2p.conf");
// use i2p.cong only if exists
if (!i2p::fs::Exists (config)) config = ""; /* reset */
}
i2p::config::ParseConfig(config); i2p::config::ParseConfig(config);
i2p::config::Finalize(); i2p::config::Finalize();
@ -79,7 +88,6 @@ namespace i2p
LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: tunnels config: ", tunconf);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);
uint16_t port; i2p::config::GetOption("port", port); uint16_t port; i2p::config::GetOption("port", port);
@ -149,18 +157,9 @@ namespace i2p
if (isDaemon && (logs == "" || logs == "stdout")) if (isDaemon && (logs == "" || logs == "stdout"))
logs = "file"; logs = "file";
if (logs == "file") if (logs == "file") {
{
if (logfile == "") if (logfile == "")
{ logfile = i2p::fs::DataDirPath("i2pd.log");
// use autodetect of logfile
logfile = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
logfile.append("/i2pd.log");
#else
logfile.append("\\i2pd.log");
#endif
}
StartLog (logfile); StartLog (logfile);
} else { } else {
// use stdout // use stdout

9
DaemonLinux.cpp

@ -9,8 +9,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "Config.h" #include "Config.h"
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "util.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
@ -55,7 +55,7 @@ namespace i2p
LogPrint(eLogError, "Daemon: could not create process group."); LogPrint(eLogError, "Daemon: could not create process group.");
return false; return false;
} }
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy std::string d = i2p::fs::GetDataDir();
if (chdir(d.c_str()) != 0) if (chdir(d.c_str()) != 0)
{ {
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
@ -75,8 +75,7 @@ namespace i2p
// this code is c-styled and a bit ugly, but we need fd for locking pidfile // this code is c-styled and a bit ugly, but we need fd for locking pidfile
std::string pidfile; i2p::config::GetOption("pidfile", pidfile); std::string pidfile; i2p::config::GetOption("pidfile", pidfile);
if (pidfile == "") { if (pidfile == "") {
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string(); pidfile = i2p::fs::DataDirPath("i2pd.pid");
pidfile.append("/i2pd.pid");
} }
if (pidfile != "") { if (pidfile != "") {
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
@ -115,7 +114,7 @@ namespace i2p
bool DaemonLinux::stop() bool DaemonLinux::stop()
{ {
unlink(pidfile.c_str()); i2p::fs::Remove(pidfile);
return Daemon_Singleton::stop(); return Daemon_Singleton::stop();
} }

44
Destination.cpp

@ -2,8 +2,9 @@
#include <cassert> #include <cassert>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <openssl/rand.h> #include <openssl/rand.h>
#include "Log.h" #include "Log.h"
#include "util.h" #include "FS.h"
#include "Crypto.h" #include "Crypto.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "NetDb.h" #include "NetDb.h"
@ -459,7 +460,8 @@ namespace client
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
RequestLeaseSet (GetIdentHash (), RequestLeaseSet (GetIdentHash (),
[s](std::shared_ptr<i2p::data::LeaseSet> leaseSet) // "this" added due to bug in gcc 4.7-4.8
[s,this](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{ {
if (leaseSet) if (leaseSet)
{ {
@ -751,30 +753,26 @@ namespace client
void ClientDestination::PersistTemporaryKeys () void ClientDestination::PersistTemporaryKeys ()
{ {
auto path = i2p::util::filesystem::GetDefaultDataDir() / "destinations"; std::string ident = GetIdentHash().ToBase32();
auto filename = path / (GetIdentHash ().ToBase32 () + ".dat"); std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat"));
std::ifstream f(filename.string (), std::ifstream::binary); std::ifstream f(path, std::ifstream::binary);
if (f)
{ if (f) {
f.read ((char *)m_EncryptionPublicKey, 256); f.read ((char *)m_EncryptionPublicKey, 256);
f.read ((char *)m_EncryptionPrivateKey, 256); f.read ((char *)m_EncryptionPrivateKey, 256);
return;
} }
if (!f)
{ LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
LogPrint (eLogInfo, "Creating new temporary keys for address ", GetIdentHash ().ToBase32 ()); i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
if (!boost::filesystem::exists (path)) std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
{ if (f1) {
if (!boost::filesystem::create_directory (path)) f1.write ((char *)m_EncryptionPublicKey, 256);
LogPrint (eLogError, "Failed to create destinations directory"); f1.write ((char *)m_EncryptionPrivateKey, 256);
} return;
std::ofstream f1 (filename.string (), std::ofstream::binary | std::ofstream::out);
if (f1)
{
f1.write ((char *)m_EncryptionPublicKey, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256);
}
} }
LogPrint(eLogError, "Destinations: Can't save keys to ", path);
} }
} }
} }

158
FS.cpp

@ -0,0 +1,158 @@
/*
* Copyright (c) 2013-2016, 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
*/
#include <algorithm>
#include <boost/filesystem.hpp>
#ifdef WIN32
#include <shlobj.h>
#endif
#include "Base.h"
#include "FS.h"
#include "Log.h"
namespace i2p {
namespace fs {
std::string appName = "i2pd";
std::string dataDir = "";
#ifdef _WIN32
std::string dirSep = "\\";
#else
std::string dirSep = "/";
#endif
const std::string & GetAppName () {
return appName;
}
void SetAppName (const std::string& name) {
appName = name;
}
const std::string & GetDataDir () {
return dataDir;
}
void DetectDataDir(const std::string & cmdline_param, bool isService) {
if (cmdline_param != "") {
dataDir = cmdline_param;
return;
}
#if defined(WIN32) || defined(_WIN32)
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
dataDir = std::string(localAppData) + "\\" + appName;
return;
#elif defined(MAC_OSX)
char *home = getenv("HOME");
dataDir = (home != NULL && strlen(home) > 0) ? home : "";
dataDir += "/Library/Application Support/" + appName;
return;
#else /* other unix */
char *home = getenv("HOME");
if (isService) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName;
} else {
dataDir = "/tmp/" + appName;
}
return;
#endif
}
bool Init() {
if (boost::filesystem::exists(dataDir))
boost::filesystem::create_directory(dataDir);
std::string destinations = DataDirPath("destinations");
if (boost::filesystem::exists(destinations))
boost::filesystem::create_directory(destinations);
return true;
}
bool ReadDir(const std::string & path, std::vector<std::string> & files) {
if (!boost::filesystem::exists(path))
return false;
boost::filesystem::directory_iterator it(path);
boost::filesystem::directory_iterator end;
for ( ; it != end; it++) {
if (!boost::filesystem::is_regular_file(it->status()))
continue;
files.push_back(it->path().string());
}
return true;
}
bool Exists(const std::string & path) {
return boost::filesystem::exists(path);
}
bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path))
return false;
return boost::filesystem::remove(path);
}
void HashedStorage::SetPlace(const std::string &path) {
root = path + i2p::fs::dirSep + name;
}
bool HashedStorage::Init(const char * chars, size_t count) {
if (!boost::filesystem::exists(root)) {
boost::filesystem::create_directory(root);
}
for (size_t i = 0; i < count; i++) {
auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
if (boost::filesystem::exists(p))
continue;
if (boost::filesystem::create_directory(p))
continue; /* ^ throws exception on failure */
return false;
}
return true;
}
std::string HashedStorage::Path(const std::string & ident) const {
std::string safe_ident = ident;
std::replace(safe_ident.begin(), safe_ident.end(), '/', '-');
std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
std::stringstream t("");
t << this->root << i2p::fs::dirSep;
t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
t << prefix2 << safe_ident << "." << suffix;
return t.str();
}
void HashedStorage::Remove(const std::string & ident) {
std::string path = Path(ident);
if (!boost::filesystem::exists(path))
return;
boost::filesystem::remove(path);
}
void HashedStorage::Traverse(std::vector<std::string> & files) {
boost::filesystem::path p(root);
boost::filesystem::recursive_directory_iterator it(p);
boost::filesystem::recursive_directory_iterator end;
for ( ; it != end; it++) {
if (!boost::filesystem::is_regular_file( it->status() ))
continue;
const std::string & t = it->path().string();
files.push_back(t);
}
}
} // fs
} // i2p

142
FS.h

@ -0,0 +1,142 @@
/*
* Copyright (c) 2013-2016, 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 FS_H__
#define FS_H__
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
namespace i2p {
namespace fs {
extern std::string dirSep;
/**
* @brief Class to work with NetDb & Router profiles
*
* Usage:
*
* const char alphabet[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
* auto h = HashedStorage("name", "y", "z-", ".txt");
* h.SetPlace("/tmp/hs-test");
* h.GetName() -> gives "name"
* h.GetRoot() -> gives "/tmp/hs-test/name"
* h.Init(alphabet, 8); <- creates needed dirs, 8 is size of alphabet
* h.Path("abcd"); <- returns /tmp/hs-test/name/ya/z-abcd.txt
* h.Remove("abcd"); <- removes /tmp/hs-test/name/ya/z-abcd.txt, if it exists
* std::vector<std::string> files;
* h.Traverse(files); <- finds all files in storage and saves in given vector
*/
class HashedStorage {
protected:
std::string root; /**< path to storage with it's name included */
std::string name; /**< name of the storage */
std::string prefix1; /**< hashed directory prefix */
std::string prefix2; /**< prefix of file in storage */
std::string suffix; /**< suffix of file in storage (extension) */
public:
HashedStorage(const char *n, const char *p1, const char *p2, const char *s):
name(n), prefix1(p1), prefix2(p2), suffix(s) {};
/** create subdirs in storage */
bool Init(const char* chars, size_t cnt);
const std::string & GetRoot() const { return this->root; }
const std::string & GetName() const { return this->name; }
/** set directory where to place storage directory */
void SetPlace(const std::string & path);
/** path to file with given ident */
std::string Path(const std::string & ident) const;
/** remove file by ident */
void Remove(const std::string & ident);
/** find all files in storage and store list in provided vector */
void Traverse(std::vector<std::string> & files);
};
/** @brief Returns current application name, default 'i2pd' */
const std::string & GetAppName ();
/** @brief Set applicaton name, affects autodetection of datadir */
void SetAppName (const std::string& name);
/** @brief Returns datadir path */
const std::string & GetDataDir();
/**
* @brief Set datadir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --datadir=<something>
* @param isService Value of cmdline parameter --service
*
* Examples of autodetected paths:
*
* Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd\
* Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd\
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/
* Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/
*/
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/**
* @brief Create subdirectories inside datadir
*/
bool Init();
/**
* @brief Get list of files in directory
* @param path Path to directory
* @param files Vector to store found files
* @return true on success and false if directory not exists
*/
bool ReadDir(const std::string & path, std::vector<std::string> & files);
/**
* @brief Remove file with given path
* @param path Absolute path to file
* @return true on success, false if file not exists, throws exception on error
*/
bool Remove(const std::string & path);
/**
* @brief Check existence of file
* @param path Absolute path to file
* @return true if file exists, false otherwise
*/
bool Exists(const std::string & path);
template<typename T>
void _ExpandPath(std::stringstream & path, T c) {
path << i2p::fs::dirSep << c;
}
template<typename T, typename ... Other>
void _ExpandPath(std::stringstream & path, T c, Other ... other) {
_ExpandPath(path, c);
_ExpandPath(path, other ...);
}
/**
* @brief Get path relative to datadir
*
* Examples (with datadir = "/tmp/i2pd"):
*
* i2p::fs::Path("test") -> '/tmp/i2pd/test'
* i2p::fs::Path("test", "file.txt") -> '/tmp/i2pd/test/file.txt'
*/
template<typename ... Other>
std::string DataDirPath(Other ... components) {
std::stringstream s("");
s << i2p::fs::GetDataDir();
_ExpandPath(s, components ...);
return s.str();
}
} // fs
} // i2p
#endif // /* FS_H__ */

35
Family.cpp

@ -1,7 +1,7 @@
#include <string.h> #include <string.h>
#include "util.h"
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "Crypto.h" #include "Crypto.h"
#include "Family.h" #include "Family.h"
@ -89,21 +89,24 @@ namespace data
void Families::LoadCertificates () void Families::LoadCertificates ()
{ {
boost::filesystem::path familyDir = i2p::util::filesystem::GetCertificatesDir() / "family"; std::string certDir = i2p::fs::DataDirPath("certificates", "family");
std::vector<std::string> files;
if (!boost::filesystem::exists (familyDir)) return;
int numCertificates = 0; int numCertificates = 0;
boost::filesystem::directory_iterator end; // empty
for (boost::filesystem::directory_iterator it (familyDir); it != end; ++it) if (!i2p::fs::ReadDir(certDir, files)) {
{ LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
if (boost::filesystem::is_regular_file (it->status()) && it->path ().extension () == ".crt") return;
{ }
LoadCertificate (it->path ().string ());
numCertificates++; for (const std::string & file : files) {
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
LogPrint(eLogWarning, "Family: ignoring file ", file);
continue;
} }
LoadCertificate (file);
numCertificates++;
} }
if (numCertificates > 0) LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
} }
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident, bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
@ -124,10 +127,10 @@ namespace data
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident) std::string CreateFamilySignature (const std::string& family, const IdentHash& ident)
{ {
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
std::string sig; std::string sig;
auto filename = i2p::util::filesystem::GetDefaultDataDir() / "family" / (family + ".key");
SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ()); SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ());
int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.string ().c_str (), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret) if (ret)
{ {
SSL * ssl = SSL_new (ctx); SSL * ssl = SSL_new (ctx);
@ -163,7 +166,7 @@ namespace data
SSL_free (ssl); SSL_free (ssl);
} }
else else
LogPrint (eLogError, "Family: Can't open keys file ", filename.string ()); LogPrint (eLogError, "Family: Can't open keys file: ", filename);
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
return sig; return sig;
} }

3
HTTPServer.cpp

@ -4,6 +4,7 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "Base.h" #include "Base.h"
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "TransitTunnel.h" #include "TransitTunnel.h"
@ -420,7 +421,7 @@ namespace util
s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)<br>\r\n"; s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)<br>\r\n";
s << "<b>Sent:</b> " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K"; s << "<b>Sent:</b> " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K";
s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)<br>\r\n"; s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)<br>\r\n";
s << "<b>Data path:</b> " << i2p::util::filesystem::GetDataDir().string() << "<br>\r\n<br>\r\n"; s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ; s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
{ {

12
I2PControl.cpp

@ -13,6 +13,7 @@
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#endif #endif
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "Config.h" #include "Config.h"
#include "NetDb.h" #include "NetDb.h"
@ -39,15 +40,12 @@ namespace client
// certificate / keys // certificate / keys
std::string i2pcp_crt; i2p::config::GetOption("i2pcontrol.cert", i2pcp_crt); std::string i2pcp_crt; i2p::config::GetOption("i2pcontrol.cert", i2pcp_crt);
std::string i2pcp_key; i2p::config::GetOption("i2pcontrol.key", i2pcp_key); std::string i2pcp_key; i2p::config::GetOption("i2pcontrol.key", i2pcp_key);
auto path = GetPath ();
// TODO: move this to i2p::fs::expand
if (i2pcp_crt.at(0) != '/') if (i2pcp_crt.at(0) != '/')
i2pcp_crt.insert(0, (path / "/").string()); i2pcp_crt = i2p::fs::DataDirPath(i2pcp_crt);
if (i2pcp_key.at(0) != '/') if (i2pcp_key.at(0) != '/')
i2pcp_key.insert(0, (path / "/").string()); i2pcp_key = i2p::fs::DataDirPath(i2pcp_key);
if (!boost::filesystem::exists (i2pcp_crt) || if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) {
!boost::filesystem::exists (i2pcp_key))
{
LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection"); LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection");
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
} else { } else {

3
I2PControl.h

@ -12,8 +12,6 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/filesystem.hpp>
#include "util.h"
namespace i2p namespace i2p
{ {
@ -52,7 +50,6 @@ namespace client
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf); std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir(); };
void CreateCertificate (const char *crt_path, const char *key_path); void CreateCertificate (const char *crt_path, const char *key_path);
private: private:

236
NetDb.cpp

@ -1,10 +1,10 @@
#include <string.h> #include <string.h>
#include "I2PEndian.h"
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <openssl/rand.h> #include <openssl/rand.h>
#include <zlib.h> #include <zlib.h>
#include "I2PEndian.h"
#include "Base.h" #include "Base.h"
#include "Log.h" #include "Log.h"
#include "Timestamp.h" #include "Timestamp.h"
@ -22,10 +22,9 @@ namespace i2p
{ {
namespace data namespace data
{ {
const char NetDb::m_NetDbPath[] = "netDb";
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr) NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat")
{ {
} }
@ -37,6 +36,9 @@ namespace data
void NetDb::Start () void NetDb::Start ()
{ {
m_Storage.SetPlace(i2p::fs::GetDataDir());
m_Storage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
InitProfilesStorage ();
m_Families.LoadCertificates (); m_Families.LoadCertificates ();
Load (); Load ();
if (m_RouterInfos.size () < 25) // reseed if # of router less than 50 if (m_RouterInfos.size () < 25) // reseed if # of router less than 50
@ -168,6 +170,7 @@ namespace data
{ {
r->Update (buf, len); r->Update (buf, len);
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
// TODO: check if floodfill has been changed
} }
else else
{ {
@ -185,7 +188,7 @@ namespace data
std::unique_lock<std::mutex> l(m_RouterInfosMutex); std::unique_lock<std::mutex> l(m_RouterInfosMutex);
m_RouterInfos[r->GetIdentHash ()] = r; m_RouterInfos[r->GetIdentHash ()] = r;
} }
if (r->IsFloodfill ()) if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
@ -273,30 +276,6 @@ namespace data
return it->second->SetUnreachable (unreachable); return it->second->SetUnreachable (unreachable);
} }
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
bool NetDb::CreateNetDb(boost::filesystem::path directory)
{
LogPrint (eLogInfo, "NetDb: storage directory doesn't exist, trying to create it.");
if (!boost::filesystem::create_directory (directory))
{
LogPrint (eLogError, "NetDb: failed to create directory ", directory);
return false;
}
// list of chars might appear in base64 string
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
for (int i = 0; i < 64; i++)
{
auto p = directory / (std::string ("r") + chars[i]);
if (!boost::filesystem::exists (p) && !boost::filesystem::create_directory (p))
{
LogPrint (eLogError, "NetDb: failed to create directory ", p);
return false;
}
}
return true;
}
void NetDb::Reseed () void NetDb::Reseed ()
{ {
if (!m_Reseeder) if (!m_Reseeder)
@ -311,153 +290,140 @@ namespace data
LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts"); LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts");
} }
void NetDb::Load () bool NetDb::LoadRouterInfo (const std::string & path)
{ {
boost::filesystem::path p(i2p::util::filesystem::GetDataDir() / m_NetDbPath); auto r = std::make_shared<RouterInfo>(path);
if (!boost::filesystem::exists (p)) if (r->GetRouterIdentity () && !r->IsUnreachable () &&
(!r->UsesIntroducer () || m_LastLoad < r->GetTimestamp () + 3600*1000LL)) // 1 hour
{ {
// seems netDb doesn't exist yet r->DeleteBuffer ();
if (!CreateNetDb(p)) return; r->ClearProperties (); // properties are not used for regular routers
m_RouterInfos[r->GetIdentHash ()] = r;
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
m_Floodfills.push_back (r);
} }
else
{
LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid. Delete");
i2p::fs::Remove(path);
}
return true;
}
void NetDb::Load ()
{
// make sure we cleanup netDb from previous attempts // make sure we cleanup netDb from previous attempts
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.clear ();
// load routers now m_LastLoad = i2p::util::GetSecondsSinceEpoch();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); std::vector<std::string> files;
int numRouters = 0; m_Storage.Traverse(files);
boost::filesystem::directory_iterator end; for (auto path : files)
for (boost::filesystem::directory_iterator it (p); it != end; ++it) LoadRouterInfo(path);
{
if (boost::filesystem::is_directory (it->status())) LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
{
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
{
#if BOOST_VERSION > 10500
const std::string& fullPath = it1->path().string();
#else
const std::string& fullPath = it1->path();
#endif
auto r = std::make_shared<RouterInfo>(fullPath);
if (r->GetRouterIdentity () && !r->IsUnreachable () &&
(!r->UsesIntroducer () || ts < r->GetTimestamp () + 3600*1000LL)) // 1 hour
{
r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers
m_RouterInfos[r->GetIdentHash ()] = r;
if (r->IsFloodfill ())
m_Floodfills.push_back (r);
numRouters++;
}
else
{
if (boost::filesystem::exists (fullPath))
boost::filesystem::remove (fullPath);
}
}
}
}
LogPrint (eLogInfo, "NetDb: ", numRouters, " routers loaded (", m_Floodfills.size (), " floodfils)");
} }
void NetDb::SaveUpdated () void NetDb::SaveUpdated ()
{ {
auto GetFilePath = [](const boost::filesystem::path& directory, const RouterInfo * routerInfo) int updatedCount = 0, deletedCount = 0;
{
std::string s(routerInfo->GetIdentHashBase64());
return directory / (std::string("r") + s[0]) / ("routerInfo-" + s + ".dat");
};
boost::filesystem::path fullDirectory (i2p::util::filesystem::GetDataDir() / m_NetDbPath);
int count = 0, deletedCount = 0;
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
for (auto it: m_RouterInfos) for (auto it: m_RouterInfos)
{ {
std::string ident = it.second->GetIdentHashBase64();
std::string path = m_Storage.Path(ident);
if (it.second->IsUpdated ()) if (it.second->IsUpdated ())
{ {
std::string f = GetFilePath(fullDirectory, it.second.get()).string(); it.second->SaveToFile (path);
it.second->SaveToFile (f);
it.second->SetUpdated (false); it.second->SetUpdated (false);
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
it.second->DeleteBuffer (); it.second->DeleteBuffer ();
count++; updatedCount++;
continue;
} }
else // find & mark unreachable routers
if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL)
{ {
// RouterInfo expires after 1 hour if uses introducer // RouterInfo expires after 1 hour if uses introducer
if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hour it.second->SetUnreachable (true);
it.second->SetUnreachable (true); }
else if (total > 75 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes else if (total > 75 && ts > (i2p::context.GetStartupTime () + 600)*1000LL)
{
// routers don't expire if less than 25 or uptime is less than 10 minutes
if (i2p::context.IsFloodfill ())
{ {
if (i2p::context.IsFloodfill ()) if (ts > it.second->GetTimestamp () + 3600*1000LL)
{ { // 1 hour
if (ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hours it.second->SetUnreachable (true);
{ total--;
it.second->SetUnreachable (true);
total--;
}
}
else if (total > 2500)
{
if (ts > it.second->GetTimestamp () + 12*3600*1000LL) // 12 hours
{
it.second->SetUnreachable (true);
total--;
}
} }
else if (total > 300) }
{ else if (total > 2500)
if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours {
{ if (ts > it.second->GetTimestamp () + 12*3600*1000LL) // 12 hours
it.second->SetUnreachable (true);
total--;
}
}
else if (total > 120)
{ {
if (ts > it.second->GetTimestamp () + 72*3600*1000LL) // 72 hours it.second->SetUnreachable (true);
{ total--;
it.second->SetUnreachable (true);
total--;
}
} }
} }
else if (total > 300)
if (it.second->IsUnreachable ())
{ {
total--; if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours
// delete RI file
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ())))
{ {
boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ())); it.second->SetUnreachable (true);
deletedCount++; total--;
} }
// delete from floodfills list }
if (it.second->IsFloodfill ()) else if (total > 120)
{
if (ts > it.second->GetTimestamp () + 72*3600*1000LL)
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); // 72 hours
m_Floodfills.remove (it.second); it.second->SetUnreachable (true);
total--;
} }
} }
} }
}
if (count > 0) if (it.second->IsUnreachable ())
LogPrint (eLogInfo, "NetDb: ", count, " new/updated routers saved"); {
total--;
// delete RI file
m_Storage.Remove(ident);
deletedCount++;
}
} // m_RouterInfos iteration
if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: saved ", updatedCount, " new/updated routers");
if (deletedCount > 0) if (deletedCount > 0)
{ {
LogPrint (eLogDebug, "NetDb: ", deletedCount, " routers deleted"); LogPrint (eLogInfo, "NetDb: deleting ", deletedCount, " unreachable routers");
// clean up RouterInfos table // clean up RouterInfos table
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{ {
if (it->second->IsUnreachable ()) std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{ {
it->second->SaveProfile (); if (it->second->IsUnreachable ())
it = m_RouterInfos.erase (it); {
} it->second->SaveProfile ();
else it = m_RouterInfos.erase (it);
continue;
}
it++; it++;
}
}
// clean up expired floodfiils
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
if ((*it)->IsUnreachable ())
it = m_Floodfills.erase (it);
else
it++;
} }
} }
} }

9
NetDb.h

@ -8,8 +8,8 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <boost/filesystem.hpp>
#include "Base.h" #include "Base.h"
#include "FS.h"
#include "Queue.h" #include "Queue.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@ -24,7 +24,6 @@ namespace i2p
{ {
namespace data namespace data
{ {
class NetDb class NetDb
{ {
public: public:
@ -71,8 +70,8 @@ namespace data
private: private:
bool CreateNetDb(boost::filesystem::path directory);
void Load (); void Load ();
bool LoadRouterInfo (const std::string & path);
void SaveUpdated (); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
@ -92,17 +91,17 @@ namespace data
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
uint64_t m_LastLoad;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
GzipInflator m_Inflator; GzipInflator m_Inflator;
Reseeder * m_Reseeder; Reseeder * m_Reseeder;
Families m_Families; Families m_Families;
i2p::fs::HashedStorage m_Storage;
friend class NetDbRequests; friend class NetDbRequests;
NetDbRequests m_Requests; NetDbRequests m_Requests;
static const char m_NetDbPath[];
}; };
extern NetDb netdb; extern NetDb netdb;

178
Profiling.cpp

@ -1,8 +1,8 @@
#include <boost/filesystem.hpp> #include <sys/stat.h>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include "Base.h" #include "Base.h"
#include "util.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "Profiling.h" #include "Profiling.h"
@ -10,6 +10,8 @@ namespace i2p
{ {
namespace data namespace data
{ {
i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
RouterProfile::RouterProfile (const IdentHash& identHash): RouterProfile::RouterProfile (const IdentHash& identHash):
m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()), m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
@ -44,95 +46,63 @@ namespace data
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage); pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
// save to file // save to file
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY; std::string ident = m_IdentHash.ToBase64 ();
if (!boost::filesystem::exists (path)) std::string path = m_ProfilesStorage.Path(ident);
{
// Create directory is necessary try {
if (!boost::filesystem::create_directory (path)) boost::property_tree::write_ini (path, pt);
{ } catch (std::exception& ex) {
LogPrint (eLogError, "Failed to create directory ", path); /* boost exception verbose enough */
return; LogPrint (eLogError, "Profiling: ", ex.what ());
}
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
for (int i = 0; i < 64; i++)
{
auto path1 = path / (std::string ("p") + chars[i]);
if (!boost::filesystem::exists (path1) && !boost::filesystem::create_directory (path1))
{
LogPrint (eLogError, "Failed to create directory ", path1);
return;
}
}
}
std::string base64 = m_IdentHash.ToBase64 ();
path = path / (std::string ("p") + base64[0]);
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
try
{
boost::property_tree::write_ini (filename.string (), pt);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
} }
} }
void RouterProfile::Load () void RouterProfile::Load ()
{ {
std::string base64 = m_IdentHash.ToBase64 (); std::string ident = m_IdentHash.ToBase64 ();
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY; std::string path = m_ProfilesStorage.Path(ident);
path /= std::string ("p") + base64[0]; boost::property_tree::ptree pt;
auto filename = path / (std::string (PEER_PROFILE_PREFIX) + base64 + ".txt");
if (boost::filesystem::exists (filename)) if (!i2p::fs::Exists(path)) {
{ LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
boost::property_tree::ptree pt; return;
try }
{
boost::property_tree::read_ini (filename.string (), pt); try {
} boost::property_tree::read_ini (path, pt);
catch (std::exception& ex) } catch (std::exception& ex) {
{ /* boost exception verbose enough */
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ()); LogPrint (eLogError, "Profiling: ", ex.what ());
return; return;
} }
try
{ try {
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0) if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t); m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) {
{ try {
try // read participations
{ auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
// read participations m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION); m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0); m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0); } catch (boost::property_tree::ptree_bad_path& ex) {
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION);
}
try
{
// read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE);
}
} }
else try {
*this = RouterProfile (m_IdentHash); // read usage
} auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
catch (std::exception& ex) m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
{ m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
LogPrint (eLogError, "Can't read profile ", base64, " :", ex.what ()); } catch (boost::property_tree::ptree_bad_path& ex) {
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
}
} else {
*this = RouterProfile (m_IdentHash);
} }
} catch (std::exception& ex) {
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
} }
} }
@ -184,31 +154,29 @@ namespace data
return profile; return profile;
} }
void InitProfilesStorage ()
{
m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
}
void DeleteObsoleteProfiles () void DeleteObsoleteProfiles ()
{ {
int num = 0; struct stat st;
auto ts = boost::posix_time::second_clock::local_time(); std::time_t now = std::time(nullptr);
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY);
if (boost::filesystem::exists (p)) std::vector<std::string> files;
{ m_ProfilesStorage.Traverse(files);
boost::filesystem::directory_iterator end; for (auto path: files) {
for (boost::filesystem::directory_iterator it (p); it != end; ++it) if (stat(path.c_str(), &st) != 0) {
{ LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
if (boost::filesystem::is_directory (it->status())) continue;
{ }
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1) if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
{ LogPrint(eLogDebug, "Profiling: removing expired peer profile: ", path);
auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ())); i2p::fs::Remove(path);
if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
{
boost::filesystem::remove (it1->path ());
num++;
}
}
}
} }
} }
LogPrint (eLogInfo, num, " obsolete profiles deleted");
} }
} }
} }

3
Profiling.h

@ -9,8 +9,6 @@ namespace i2p
{ {
namespace data namespace data
{ {
const char PEER_PROFILES_DIRECTORY[] = "peerProfiles";
const char PEER_PROFILE_PREFIX[] = "profile-";
// sections // sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage"; const char PEER_PROFILE_SECTION_USAGE[] = "usage";
@ -62,6 +60,7 @@ namespace data
}; };
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash); std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage ();
void DeleteObsoleteProfiles (); void DeleteObsoleteProfiles ();
} }
} }

26
Reseed.cpp

@ -2,15 +2,16 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/filesystem.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <zlib.h> #include <zlib.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Reseed.h" #include "Reseed.h"
#include "FS.h"
#include "Log.h" #include "Log.h"
#include "Identity.h" #include "Identity.h"
#include "Crypto.h" #include "Crypto.h"
@ -347,23 +348,22 @@ namespace data
void Reseeder::LoadCertificates () void Reseeder::LoadCertificates ()
{ {
boost::filesystem::path reseedDir = i2p::util::filesystem::GetCertificatesDir() / "reseed"; std::string certDir = i2p::fs::DataDirPath("certificates", "reseed");
std::vector<std::string> files;
int numCertificates = 0;
if (!boost::filesystem::exists (reseedDir)) if (!i2p::fs::ReadDir(certDir, files)) {
{ LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir);
LogPrint (eLogWarning, "Reseed: certificates not loaded, ", reseedDir, " doesn't exist");
return; return;
} }
int numCertificates = 0; for (const std::string & file : files) {
boost::filesystem::directory_iterator end; // empty if (file.compare(file.size() - 4, 4, ".crt") != 0) {
for (boost::filesystem::directory_iterator it (reseedDir); it != end; ++it) LogPrint(eLogWarning, "Reseed: ignoring file ", file);
{ continue;
if (boost::filesystem::is_regular_file (it->status()) && it->path ().extension () == ".crt")
{
LoadCertificate (it->path ().string ());
numCertificates++;
} }
LoadCertificate (file);
numCertificates++;
} }
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded"); LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
} }

9
RouterContext.cpp

@ -5,6 +5,7 @@
#include "Timestamp.h" #include "Timestamp.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "NetDb.h" #include "NetDb.h"
#include "FS.h"
#include "util.h" #include "util.h"
#include "version.h" #include "version.h"
#include "Log.h" #include "Log.h"
@ -65,7 +66,7 @@ namespace i2p
void RouterContext::UpdateRouterInfo () void RouterContext::UpdateRouterInfo ()
{ {
m_RouterInfo.CreateBuffer (m_Keys); m_RouterInfo.CreateBuffer (m_Keys);
m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO)); m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
} }
@ -310,7 +311,7 @@ namespace i2p
bool RouterContext::Load () bool RouterContext::Load ()
{ {
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ifstream::in); std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
if (!fk.is_open ()) return false; if (!fk.is_open ()) return false;
fk.seekg (0, std::ios::end); fk.seekg (0, std::ios::end);
size_t len = fk.tellg(); size_t len = fk.tellg();
@ -330,7 +331,7 @@ namespace i2p
delete[] buf; delete[] buf;
} }
i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); // TODO
m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.SetRouterIdentity (GetIdentity ());
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION); m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
@ -349,7 +350,7 @@ namespace i2p
void RouterContext::SaveKeys () void RouterContext::SaveKeys ()
{ {
// save in the same format as .dat files // save in the same format as .dat files
std::ofstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ofstream::binary | std::ofstream::out); std::ofstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ofstream::binary | std::ofstream::out);
size_t len = m_Keys.GetFullLen (); size_t len = m_Keys.GetFullLen ();
uint8_t * buf = new uint8_t[len]; uint8_t * buf = new uint8_t[len];
m_Keys.ToBuffer (buf, len); m_Keys.ToBuffer (buf, len);

5
RouterInfo.cpp

@ -629,11 +629,6 @@ namespace data
m_Properties.erase (key); m_Properties.erase (key);
} }
bool RouterInfo::IsFloodfill () const
{
return m_Caps & Caps::eFloodfill;
}
bool RouterInfo::IsNTCP (bool v4only) const bool RouterInfo::IsNTCP (bool v4only) const
{ {
if (v4only) if (v4only)

3
RouterInfo.h

@ -128,7 +128,8 @@ namespace data
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
void DeleteProperty (const std::string& key); // called from RouterContext only void DeleteProperty (const std::string& key); // called from RouterContext only
void ClearProperties () { m_Properties.clear (); }; void ClearProperties () { m_Properties.clear (); };
bool IsFloodfill () const; bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
bool IsReachable () const { return m_Caps & Caps::eReachable; };
bool IsNTCP (bool v4only = true) const; bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const; bool IsSSU (bool v4only = true) const;
bool IsV6 () const; bool IsV6 () const;

28
SSUSession.cpp

@ -157,7 +157,7 @@ namespace transport
ProcessData (buf + headerSize, len - headerSize); ProcessData (buf + headerSize, len - headerSize);
break; break;
case PAYLOAD_TYPE_SESSION_REQUEST: case PAYLOAD_TYPE_SESSION_REQUEST:
ProcessSessionRequest (buf + headerSize, len - headerSize, senderEndpoint); ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
break; break;
case PAYLOAD_TYPE_SESSION_CREATED: case PAYLOAD_TYPE_SESSION_CREATED:
ProcessSessionCreated (buf, len); // buf with header ProcessSessionCreated (buf, len); // buf with header
@ -196,11 +196,29 @@ namespace transport
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{ {
LogPrint (eLogDebug, "SSU message: session request"); LogPrint (eLogDebug, "SSU message: session request");
bool sendRelayTag = true;
auto headerSize = sizeof (SSUHeader);
if (((SSUHeader *)buf)->IsExtendedOptions ())
{
uint8_t extendedOptionsLen = buf[headerSize];
headerSize++;
if (extendedOptionsLen >= 3) // options are presented
{
uint16_t flags = bufbe16toh (buf + headerSize);
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
}
headerSize += extendedOptionsLen;
}
if (headerSize >= len)
{
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
return;
}
m_RemoteEndpoint = senderEndpoint; m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair) if (!m_DHKeysPair)
m_DHKeysPair = transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
CreateAESandMacKey (buf); CreateAESandMacKey (buf + headerSize);
SendSessionCreated (buf); SendSessionCreated (buf + headerSize, sendRelayTag);
} }
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
@ -357,7 +375,7 @@ namespace transport
m_Server.Send (buf, 96, m_RemoteEndpoint); m_Server.Send (buf, 96, m_RemoteEndpoint);
} }
void SSUSession::SendSessionCreated (const uint8_t * x) void SSUSession::SendSessionCreated (const uint8_t * x, bool sendRelayTag)
{ {
auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only
@ -401,7 +419,7 @@ namespace transport
s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6 s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6
s.Insert<uint16_t> (htobe16 (address->port)); // our port s.Insert<uint16_t> (htobe16 (address->port)); // our port
uint32_t relayTag = 0; uint32_t relayTag = 0;
if (i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ()) if (sendRelayTag && i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ())
{ {
RAND_bytes((uint8_t *)&relayTag, 4); RAND_bytes((uint8_t *)&relayTag, 4);
if (!relayTag) relayTag = 1; if (!relayTag) relayTag = 1;

5
SSUSession.h

@ -39,6 +39,9 @@ namespace transport
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7; const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8; const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
// extended options
const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
enum SessionState enum SessionState
{ {
eSessionStateUnknown, eSessionStateUnknown,
@ -101,7 +104,7 @@ namespace transport
void SendSessionRequest (); void SendSessionRequest ();
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce); void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
void ProcessSessionCreated (uint8_t * buf, size_t len); void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x); void SendSessionCreated (const uint8_t * x, bool sendRelayTag = true);
void ProcessSessionConfirmed (const uint8_t * buf, size_t len); void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);

12
api.cpp

@ -9,7 +9,7 @@
#include "Identity.h" #include "Identity.h"
#include "Destination.h" #include "Destination.h"
#include "Crypto.h" #include "Crypto.h"
#include "util.h" #include "FS.h"
#include "api.h" #include "api.h"
namespace i2p namespace i2p
@ -18,10 +18,16 @@ namespace api
{ {
void InitI2P (int argc, char* argv[], const char * appName) void InitI2P (int argc, char* argv[], const char * appName)
{ {
i2p::util::filesystem::SetAppName (appName);
i2p::config::Init (); i2p::config::Init ();
i2p::config::ParseCmdline (argc, argv); i2p::config::ParseCmdline (argc, argv);
i2p::config::Finalize (); i2p::config::Finalize ();
std::string datadir; i2p::config::GetOption("datadir", datadir);
i2p::fs::SetAppName (appName);
i2p::fs::DetectDataDir(datadir, false);
i2p::fs::Init();
i2p::crypto::InitCrypto (); i2p::crypto::InitCrypto ();
i2p::context.Init (); i2p::context.Init ();
} }
@ -36,7 +42,7 @@ namespace api
if (logStream) if (logStream)
StartLog (logStream); StartLog (logStream);
else else
StartLog (i2p::util::filesystem::GetFullPath (i2p::util::filesystem::GetAppName () + ".log")); StartLog (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
LogPrint(eLogInfo, "API: starting NetDB"); LogPrint(eLogInfo, "API: starting NetDB");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
LogPrint(eLogInfo, "API: starting Transports"); LogPrint(eLogInfo, "API: starting Transports");

1
build/CMakeLists.txt

@ -23,6 +23,7 @@ set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp"
"${CMAKE_SOURCE_DIR}/Identity.cpp" "${CMAKE_SOURCE_DIR}/Identity.cpp"
"${CMAKE_SOURCE_DIR}/LeaseSet.cpp" "${CMAKE_SOURCE_DIR}/LeaseSet.cpp"
"${CMAKE_SOURCE_DIR}/FS.cpp"
"${CMAKE_SOURCE_DIR}/Log.cpp" "${CMAKE_SOURCE_DIR}/Log.cpp"
"${CMAKE_SOURCE_DIR}/NTCPSession.cpp" "${CMAKE_SOURCE_DIR}/NTCPSession.cpp"
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp" "${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"

1
docs/index.rst

@ -26,4 +26,5 @@ Contents:
build_notes_unix build_notes_unix
build_notes_windows build_notes_windows
configuration configuration
family

4
filelist.mk

@ -4,8 +4,8 @@ LIB_SRC = \
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 \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
Destination.cpp Base.cpp I2PEndian.cpp Config.cpp Family.cpp util.cpp \ Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
api.cpp util.cpp api.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 \

133
util.cpp

@ -6,13 +6,7 @@
#include <fstream> #include <fstream>
#include <set> #include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/algorithm/string.hpp>
#include "Config.h" #include "Config.h"
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
@ -67,131 +61,6 @@ namespace i2p
{ {
namespace util namespace util
{ {
namespace filesystem
{
std::string appName ("i2pd");
void SetAppName (const std::string& name)
{
appName = name;
}
std::string GetAppName ()
{
return appName;
}
const boost::filesystem::path &GetDataDir()
{
static boost::filesystem::path path;
// TODO: datadir parameter is useless because GetDataDir is called before OptionParser
// and mapArgs is not initialized yet
/*
std::string datadir; i2p::config::GetOption("datadir", datadir);
if (datadir != "")
path = boost::filesystem::system_complete(datadir);
else */
path = GetDefaultDataDir();
if (!boost::filesystem::exists( path ))
{
// Create data directory
if (!boost::filesystem::create_directory( path ))
{
LogPrint(eLogError, "FS: Failed to create data directory!");
path = "";
return path;
}
}
if (!boost::filesystem::is_directory(path))
path = GetDefaultDataDir();
return path;
}
std::string GetFullPath (const std::string& filename)
{
std::string fullPath = GetDataDir ().string ();
#ifndef _WIN32
fullPath.append ("/");
#else
fullPath.append ("\\");
#endif
fullPath.append (filename);
return fullPath;
}
boost::filesystem::path GetConfigFile()
{
std::string config; i2p::config::GetOption("conf", config);
if (config != "") {
/* config file set with cmdline */
boost::filesystem::path path(config);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("i2p.conf");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
}
boost::filesystem::path GetTunnelsConfigFile()
{
std::string tunconf; i2p::config::GetOption("tunconf", tunconf);
if (tunconf != "") {
/* config file set with cmdline */
boost::filesystem::path path(tunconf);
return path;
}
/* else - try autodetect */
boost::filesystem::path path("tunnels.cfg");
path = GetDataDir() / path;
if (!boost::filesystem::exists(path))
path = ""; /* reset */
return path;
}
boost::filesystem::path GetDefaultDataDir()
{
// Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd
// Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd
// Mac: ~/Library/Application Support/i2pd
// Unix: ~/.i2pd or /var/lib/i2pd is system=1
#ifdef WIN32
// Windows
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
return boost::filesystem::path(std::string(localAppData) + "\\" + appName);
#else /* UNIX */
bool service; i2p::config::GetOption("service", service);
if (service) // use system folder
return boost::filesystem::path(std::string ("/var/lib/") + appName);
boost::filesystem::path pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pathRet = boost::filesystem::path("/");
else
pathRet = boost::filesystem::path(pszHome);
#ifdef MAC_OSX
// Mac
pathRet /= "Library/Application Support";
boost::filesystem::create_directory(pathRet);
return pathRet / appName;
#else /* Other Unix */
// Unix
return pathRet / (std::string (".") + appName);
#endif
#endif /* UNIX */
}
boost::filesystem::path GetCertificatesDir()
{
return GetDataDir () / "certificates";
}
}
namespace http namespace http
{ {
std::string GetHttpContent (std::istream& response) std::string GetHttpContent (std::istream& response)
@ -212,7 +81,7 @@ namespace http
if (colon != std::string::npos) if (colon != std::string::npos)
{ {
std::string field = header.substr (0, colon); std::string field = header.substr (0, colon);
boost::to_lower (field); std::transform(field.begin(), field.end(), field.begin(), ::tolower);
if (field == i2p::util::http::TRANSFER_ENCODING) if (field == i2p::util::http::TRANSFER_ENCODING)
isChunked = (header.find ("chunked", colon + 1) != std::string::npos); isChunked = (header.find ("chunked", colon + 1) != std::string::npos);
} }

17
util.h

@ -5,28 +5,11 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
namespace i2p namespace i2p
{ {
namespace util namespace util
{ {
namespace filesystem
{
void SetAppName (const std::string& name);
std::string GetAppName ();
const boost::filesystem::path &GetDataDir();
std::string GetFullPath (const std::string& filename);
boost::filesystem::path GetDefaultDataDir();
boost::filesystem::path GetConfigFile();
boost::filesystem::path GetTunnelsConfigFile();
boost::filesystem::path GetCertificatesDir();
}
namespace http namespace http
{ {
// in (lower case) // in (lower case)

Loading…
Cancel
Save