Browse Source

Merge pull request #455 from PurpleI2P/openssl

recent changes
pull/464/head
orignal 8 years ago
parent
commit
d1de89f387
  1. 120
      AddressBook.cpp
  2. 15
      AddressBook.h
  3. 11
      ClientContext.cpp
  4. 6
      Config.cpp
  5. 62
      Daemon.cpp
  6. 11
      DaemonLinux.cpp
  7. 2
      DaemonWin32.cpp
  8. 21
      HTTPProxy.cpp
  9. 27
      HTTPServer.cpp
  10. 227
      Log.cpp
  11. 258
      Log.h
  12. 182
      Makefile
  13. 87
      Makefile.mingw
  14. 46
      Queue.h
  15. 3
      Streaming.cpp
  16. 6
      api.cpp
  17. 12
      contrib/certificates/family/mca2-i2p.crt
  18. 2
      debian/control
  19. 2
      debian/i2pd.1
  20. 4
      debian/i2pd.links
  21. 2
      docs/build_requirements.md
  22. 20
      docs/configuration.md
  23. 30
      docs/family.md
  24. 140
      docs/i2pd.conf

120
AddressBook.cpp

@ -6,6 +6,7 @@
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <openssl/rand.h>
#include "Base.h" #include "Base.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
@ -218,10 +219,17 @@ namespace client
m_Storage->Init(); m_Storage->Init();
LoadHosts (); /* try storage, then hosts.txt, then download */ LoadHosts (); /* try storage, then hosts.txt, then download */
StartSubscriptions (); StartSubscriptions ();
StartLookups ();
} }
void AddressBook::StartResolvers ()
{
LoadLocal ();
}
void AddressBook::Stop () void AddressBook::Stop ()
{ {
StopLookups ();
StopSubscriptions (); StopSubscriptions ();
if (m_SubscriptionsUpdateTimer) if (m_SubscriptionsUpdateTimer)
{ {
@ -275,7 +283,10 @@ namespace client
return true; return true;
} }
else else
{
LookupAddress (address); // TODO:
return false; return false;
}
} }
} }
// if not .b32 we assume full base64 address // if not .b32 we assume full base64 address
@ -330,7 +341,6 @@ namespace client
LoadHostsFromStream (f); LoadHostsFromStream (f);
m_IsLoaded = true; m_IsLoaded = true;
} }
LoadLocal ();
} }
void AddressBook::LoadHostsFromStream (std::istream& f) void AddressBook::LoadHostsFromStream (std::istream& f)
@ -518,6 +528,94 @@ namespace client
} }
} }
void AddressBook::StartLookups ()
{
auto dest = i2p::client::context.GetSharedLocalDestination ();
if (dest)
{
auto datagram = dest->GetDatagramDestination ();
if (!datagram)
datagram = dest->CreateDatagramDestination ();
datagram->SetReceiver (std::bind (&AddressBook::HandleLookupResponse, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
ADDRESS_RESPONSE_DATAGRAM_PORT);
}
}
void AddressBook::StopLookups ()
{
auto dest = i2p::client::context.GetSharedLocalDestination ();
if (dest)
{
auto datagram = dest->GetDatagramDestination ();
if (datagram)
datagram->ResetReceiver (ADDRESS_RESPONSE_DATAGRAM_PORT);
}
}
void AddressBook::LookupAddress (const std::string& address)
{
const i2p::data::IdentHash * ident = nullptr;
auto dot = address.find ('.');
if (dot != std::string::npos)
ident = FindAddress (address.substr (dot + 1));
if (!ident)
{
LogPrint (eLogError, "AddressBook: Can't find domain for ", address);
return;
}
auto dest = i2p::client::context.GetSharedLocalDestination ();
if (dest)
{
auto datagram = dest->GetDatagramDestination ();
if (datagram)
{
uint32_t nonce;
RAND_bytes ((uint8_t *)&nonce, 4);
{
std::unique_lock<std::mutex> l(m_LookupsMutex);
m_Lookups[nonce] = address;
}
LogPrint (eLogDebug, "AddressBook: Lookup of ", address, " to ", ident->ToBase32 (), " nonce=", nonce);
size_t len = address.length () + 9;
uint8_t * buf = new uint8_t[len];
memset (buf, 0, 4);
htobe32buf (buf + 4, nonce);
buf[8] = address.length ();
memcpy (buf + 9, address.c_str (), address.length ());
datagram->SendDatagramTo (buf, len, *ident, ADDRESS_RESPONSE_DATAGRAM_PORT, ADDRESS_RESOLVER_DATAGRAM_PORT);
delete[] buf;
}
}
}
void AddressBook::HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
{
if (len < 44)
{
LogPrint (eLogError, "AddressBook: Lookup response is too short ", len);
return;
}
uint32_t nonce = bufbe32toh (buf + 4);
LogPrint (eLogDebug, "AddressBook: Lookup response received from ", from.GetIdentHash ().ToBase32 (), " nonce=", nonce);
std::string address;
{
std::unique_lock<std::mutex> l(m_LookupsMutex);
auto it = m_Lookups.find (nonce);
if (it != m_Lookups.end ())
{
address = it->second;
m_Lookups.erase (it);
}
}
if (address.length () > 0)
{
// TODO: verify from
m_Addresses[address] = buf + 8;
}
}
AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link): AddressBookSubscription::AddressBookSubscription (AddressBook& book, const std::string& link):
m_Book (book), m_Link (link) m_Book (book), m_Link (link)
{ {
@ -701,20 +799,31 @@ namespace client
} }
} }
AddressResolver::~AddressResolver ()
{
if (m_LocalDestination)
{
auto datagram = m_LocalDestination->GetDatagramDestination ();
if (datagram)
datagram->ResetReceiver (ADDRESS_RESOLVER_DATAGRAM_PORT);
}
}
void AddressResolver::HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) void AddressResolver::HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
{ {
if (len < 9 || len < buf[8] + 9U) if (len < 9 || len < buf[8] + 9U)
{ {
LogPrint (eLogError, "Address request is too short ", len); LogPrint (eLogError, "AddressBook: Address request is too short ", len);
return; return;
} }
// read requested address // read requested address
uint8_t l = buf[8]; uint8_t l = buf[8];
char address[255]; char address[255];
memcpy (address, buf + 9, l); memcpy (address, buf + 9, l);
address[l] = 0; address[l] = 0;
LogPrint (eLogDebug, "AddressBook: Address request ", address);
// send response // send response
uint8_t response[40]; uint8_t response[44];
memset (response, 0, 4); // reserved memset (response, 0, 4); // reserved
memcpy (response + 4, buf + 4, 4); // nonce memcpy (response + 4, buf + 4, 4); // nonce
auto it = m_LocalAddresses.find (address); // address lookup auto it = m_LocalAddresses.find (address); // address lookup
@ -722,7 +831,8 @@ namespace client
memcpy (response + 8, it->second, 32); // ident memcpy (response + 8, it->second, 32); // ident
else else
memset (response + 8, 0, 32); // not found memset (response + 8, 0, 32); // not found
m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 40, from.GetIdentHash (), toPort, fromPort); memset (response + 40, 0, 4); // set expiration time to zero
m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 44, from.GetIdentHash (), toPort, fromPort);
} }
void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident) void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident)

15
AddressBook.h

@ -18,13 +18,16 @@ namespace i2p
{ {
namespace client namespace client
{ {
const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p/hosts.txt"; const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)
const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes
const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54;
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); } inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
class AddressBookStorage // interface for storage class AddressBookStorage // interface for storage
@ -54,10 +57,12 @@ namespace client
AddressBook (); AddressBook ();
~AddressBook (); ~AddressBook ();
void Start (); void Start ();
void StartResolvers ();
void Stop (); void Stop ();
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident); bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const std::string& address); std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const std::string& address);
const i2p::data::IdentHash * FindAddress (const std::string& address); const i2p::data::IdentHash * FindAddress (const std::string& address);
void LookupAddress (const std::string& address);
void InsertAddress (const std::string& address, const std::string& base64); // for jump service void InsertAddress (const std::string& address, const std::string& base64); // for jump service
void InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address); void InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
@ -80,11 +85,17 @@ namespace client
void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode); void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode);
void StartLookups ();
void StopLookups ();
void HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
private: private:
std::mutex m_AddressBookMutex; std::mutex m_AddressBookMutex;
std::map<std::string, i2p::data::IdentHash> m_Addresses; std::map<std::string, i2p::data::IdentHash> m_Addresses;
std::map<i2p::data::IdentHash, std::shared_ptr<AddressResolver> > m_Resolvers; // local destination->resolver std::map<i2p::data::IdentHash, std::shared_ptr<AddressResolver> > m_Resolvers; // local destination->resolver
std::mutex m_LookupsMutex;
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
AddressBookStorage * m_Storage; AddressBookStorage * m_Storage;
volatile bool m_IsLoaded, m_IsDownloading; volatile bool m_IsLoaded, m_IsDownloading;
std::vector<AddressBookSubscription *> m_Subscriptions; std::vector<AddressBookSubscription *> m_Subscriptions;
@ -111,12 +122,12 @@ namespace client
// m_Etag must be surrounded by "" // m_Etag must be surrounded by ""
}; };
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
class AddressResolver class AddressResolver
{ {
public: public:
AddressResolver (std::shared_ptr<ClientDestination> destination); AddressResolver (std::shared_ptr<ClientDestination> destination);
~AddressResolver ();
void AddAddress (const std::string& name, const i2p::data::IdentHash& ident); void AddAddress (const std::string& name, const i2p::data::IdentHash& ident);
private: private:

11
ClientContext.cpp

@ -96,6 +96,8 @@ namespace client
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
m_BOBCommandChannel->Start (); m_BOBCommandChannel->Start ();
} }
m_AddressBook.StartResolvers ();
} }
void ClientContext::Stop () void ClientContext::Stop ()
@ -259,8 +261,15 @@ namespace client
{ {
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
std::string tunConf; i2p::config::GetOption("tunconf", tunConf); std::string tunConf; i2p::config::GetOption("tunconf", tunConf);
if (tunConf == "") if (tunConf == "") {
// TODO: cleanup this in 2.8.0
tunConf = i2p::fs::DataDirPath ("tunnels.cfg"); tunConf = i2p::fs::DataDirPath ("tunnels.cfg");
if (i2p::fs::Exists(tunConf)) {
LogPrint(eLogWarning, "FS: please rename tunnels.cfg -> tunnels.conf here: ", tunConf);
} else {
tunConf = i2p::fs::DataDirPath ("tunnels.conf");
}
}
LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf); LogPrint(eLogDebug, "FS: tunnels config file: ", tunConf);
try try
{ {

6
Config.cpp

@ -107,10 +107,10 @@ namespace config {
options_description general("General options"); options_description general("General options");
general.add_options() general.add_options()
("help", "Show this message") ("help", "Show this message")
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)") ("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)")
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)") ("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)")
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)") ("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") ("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") ("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")

62
Daemon.cpp

@ -69,27 +69,57 @@ namespace i2p
i2p::fs::Init(); i2p::fs::Init();
datadir = i2p::fs::GetDataDir(); datadir = i2p::fs::GetDataDir();
if (config == "") // TODO: drop old name detection in v2.8.0
if (config == "")
{ {
config = i2p::fs::DataDirPath("i2p.conf"); config = i2p::fs::DataDirPath("i2p.conf");
// use i2p.conf only if exists if (i2p::fs::Exists (config)) {
if (!i2p::fs::Exists (config)) config = ""; /* reset */ LogPrint(eLogWarning, "Daemon: please rename i2p.conf to i2pd.conf here: ", config);
} else {
config = i2p::fs::DataDirPath("i2pd.conf");
if (!i2p::fs::Exists (config)) {
// use i2pd.conf only if exists
config = ""; /* reset */
}
}
} }
i2p::config::ParseConfig(config); i2p::config::ParseConfig(config);
i2p::config::Finalize(); i2p::config::Finalize();
i2p::crypto::InitCrypto ();
i2p::context.Init ();
i2p::config::GetOption("daemon", isDaemon); i2p::config::GetOption("daemon", isDaemon);
// TODO: move log init here std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
/* setup logging */
if (isDaemon && (logs == "" || logs == "stdout"))
logs = "file";
i2p::log::Logger().SetLogLevel(loglevel);
if (logs == "file") {
if (logfile == "")
logfile = i2p::fs::DataDirPath("i2pd.log");
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
i2p::log::Logger().SendTo (logfile);
#ifndef _WIN32
} else if (logs == "syslog") {
LogPrint(eLogInfo, "Log: will send messages to syslog");
i2p::log::Logger().SendTo("i2pd", LOG_DAEMON);
#endif
} else {
// use stdout -- default
}
i2p::log::Logger().Ready();
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: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);
i2p::crypto::InitCrypto ();
i2p::context.Init ();
uint16_t port; i2p::config::GetOption("port", port); uint16_t port; i2p::config::GetOption("port", port);
if (!i2p::config::IsDefault("port")) if (!i2p::config::IsDefault("port"))
{ {
@ -152,23 +182,6 @@ namespace i2p
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
if (isDaemon && (logs == "" || logs == "stdout"))
logs = "file";
if (logs == "file") {
if (logfile == "")
logfile = i2p::fs::DataDirPath("i2pd.log");
StartLog (logfile);
} else {
// use stdout
StartLog ("");
}
SetLogLevel(loglevel);
bool http; i2p::config::GetOption("http.enabled", http); bool http; i2p::config::GetOption("http.enabled", http);
if (http) { if (http) {
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
@ -233,7 +246,6 @@ namespace i2p
d.m_I2PControlService = nullptr; d.m_I2PControlService = nullptr;
} }
i2p::crypto::TerminateCrypto (); i2p::crypto::TerminateCrypto ();
StopLog ();
return true; return true;
} }

11
DaemonLinux.cpp

@ -19,7 +19,7 @@ void handle_signal(int sig)
{ {
case SIGHUP: case SIGHUP:
LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log..."); LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log...");
ReopenLogFile (); i2p::log::Logger().Reopen ();
break; break;
case SIGABRT: case SIGABRT:
case SIGTERM: case SIGTERM:
@ -64,12 +64,9 @@ namespace i2p
} }
// close stdin/stdout/stderr descriptors // close stdin/stdout/stderr descriptors
::close (0); freopen("/dev/null", "r", stdin);
::open ("/dev/null", O_RDWR); freopen("/dev/null", "w", stdout);
::close (1); freopen("/dev/null", "w", stderr);
::open ("/dev/null", O_RDWR);
::close (2);
::open ("/dev/null", O_RDWR);
} }
// Pidfile // Pidfile

2
DaemonWin32.cpp

@ -75,7 +75,7 @@ namespace i2p
i2p::config::SetOption("log", std::string ("file")); i2p::config::SetOption("log", std::string ("file"));
#endif #endif
bool ret = Daemon_Singleton::start(); bool ret = Daemon_Singleton::start();
if (ret && IsLogToFile ()) if (ret && i2p::log::Logger().GetLogType() == eLogFile)
{ {
// TODO: find out where this garbage to console comes from // TODO: find out where this garbage to console comes from
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);

21
HTTPProxy.cpp

@ -39,6 +39,7 @@ namespace proxy
void HTTPRequestFailed(/*std::string message*/); void HTTPRequestFailed(/*std::string message*/);
void RedirectToJumpService(); void RedirectToJumpService();
void ExtractRequest(); void ExtractRequest();
bool IsI2PAddress();
bool ValidateHTTPRequest(); bool ValidateHTTPRequest();
void HandleJumpServices(); void HandleJumpServices();
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
@ -176,6 +177,16 @@ namespace proxy
m_path.erase(addressHelperPos); m_path.erase(addressHelperPos);
} }
bool HTTPProxyHandler::IsI2PAddress()
{
auto pos = m_address.rfind (".i2p");
if (pos != std::string::npos && (pos+4) == m_address.length ())
{
return true;
}
return false;
}
bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
{ {
ExtractRequest(); //TODO: parse earlier ExtractRequest(); //TODO: parse earlier
@ -183,10 +194,14 @@ namespace proxy
HandleJumpServices(); HandleJumpServices();
i2p::data::IdentHash identHash; i2p::data::IdentHash identHash;
if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){ if (IsI2PAddress ())
RedirectToJumpService(); {
return false; if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){
RedirectToJumpService();
return false;
}
} }
m_request = m_method; m_request = m_method;
m_request.push_back(' '); m_request.push_back(' ');

27
HTTPServer.cpp

@ -421,10 +421,25 @@ namespace util
} }
s << "<br>\r\n"; s << "<br>\r\n";
s << "<b>Tunnel creation success rate:</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n"; s << "<b>Tunnel creation success rate:</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
s << "<b>Received:</b> " << i2p::transport::transports.GetTotalReceivedBytes ()/1000 << "K"; s << "<b>Received:</b> ";
s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)<br>\r\n"; s << std::fixed << std::setprecision(2);
s << "<b>Sent:</b> " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K"; auto numKBytesReceived = (double) i2p::transport::transports.GetTotalReceivedBytes () / 1024;
s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)<br>\r\n"; if (numKBytesReceived < 1024)
s << numKBytesReceived << " KiB";
else if (numKBytesReceived < 1024 * 1024)
s << numKBytesReceived / 1024 << " MiB";
else
s << numKBytesReceived / 1024 / 1024 << " GiB";
s << " (" << (double) i2p::transport::transports.GetInBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << "<b>Sent:</b> ";
auto numKBytesSent = (double) i2p::transport::transports.GetTotalSentBytes () / 1024;
if (numKBytesSent < 1024)
s << numKBytesSent << " KiB";
else if (numKBytesSent < 1024 * 1024)
s << numKBytesSent / 1024 << " MiB";
else
s << numKBytesSent / 1024 / 1024 << " GiB";
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<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())
@ -510,8 +525,8 @@ namespace util
s << "<input type=\"hidden\" name=\"jumpservices\">"; s << "<input type=\"hidden\" name=\"jumpservices\">";
s << "<input type=\"text\" value=\"" << address << "\" name=\"address\"> </form><br>\r\n"; s << "<input type=\"text\" value=\"" << address << "\" name=\"address\"> </form><br>\r\n";
s << "<b>Jump services for " << address << "</b>"; s << "<b>Jump services for " << address << "</b>";
s << "<ul><li><a href=\"http://inr.i2p/search/?q=" << address << "\">inr.i2p jump service</a> <br>\r\n"; s << "<ul><li><a href=\"http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/search/?q=" << address << "\">inr.i2p jump service</a> <br>\r\n";
s << "<li><a href=\"http://stats.i2p/cgi-bin/jump.cgi?a=" << address << "\">stats.i2p jump service</a></ul>"; s << "<li><a href=\"http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a=" << address << "\">stats.i2p jump service</a></ul>";
} }
void HTTPConnection::ShowLocalDestinations (std::stringstream& s) void HTTPConnection::ShowLocalDestinations (std::stringstream& s)

227
Log.cpp

@ -1,86 +1,167 @@
#include <boost/date_time/posix_time/posix_time.hpp> /*
* 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 "Log.h" #include "Log.h"
Log * g_Log = nullptr; namespace i2p {
namespace log {
Log logger;
/**
* @enum Maps our loglevel to their symbolic name
*/
static const char * g_LogLevelStr[eNumLogLevels] =
{
"error", // eLogError
"warn", // eLogWarn
"info", // eLogInfo
"debug" // eLogDebug
};
static const char * g_LogLevelStr[eNumLogLevels] = #ifndef _WIN32
{ /**
"error", // eLogError * @brief Maps our log levels to syslog one
"warn", // eLogWarning * @return syslog priority LOG_*, as defined in syslog.h
"info", // eLogInfo */
"debug" // eLogDebug static inline int GetSyslogPrio (enum LogLevel l) {
}; int priority = LOG_DEBUG;
switch (l) {
case eLogError : priority = LOG_ERR; break;
case eLogWarning : priority = LOG_WARNING; break;
case eLogInfo : priority = LOG_INFO; break;
case eLogDebug : priority = LOG_DEBUG; break;
default : priority = LOG_DEBUG; break;
}
return priority;
}
#endif
void LogMsg::Process() Log::Log():
{ m_Destination(eLogStdout), m_MinLevel(eLogInfo),
auto stream = log ? log->GetLogStream () : nullptr; m_LogStream (nullptr), m_Logfile(""), m_IsReady(false)
auto& output = stream ? *stream : std::cout; {
if (log) }
output << log->GetTimestamp ();
else
output << boost::posix_time::second_clock::local_time().time_of_day ();
output << "/" << g_LogLevelStr[level] << " - ";
output << s.str();
}
const std::string& Log::GetTimestamp () Log::~Log ()
{
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
auto ts = std::chrono::monotonic_clock::now ();
#else
auto ts = std::chrono::steady_clock::now ();
#endif
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
{ {
m_LastTimestampUpdate = ts; switch (m_Destination) {
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ()); #ifndef _WIN32
} case eLogSyslog :
return m_Timestamp; closelog();
} break;
#endif
case eLogFile:
case eLogStream:
m_LogStream->flush();
break;
default:
/* do nothing */
break;
}
Process();
}
void Log::Flush () void Log::SetLogLevel (const std::string& level) {
{ if (level == "error") { m_MinLevel = eLogError; }
if (m_LogStream) else if (level == "warn") { m_MinLevel = eLogWarning; }
m_LogStream->flush(); else if (level == "info") { m_MinLevel = eLogInfo; }
} else if (level == "debug") { m_MinLevel = eLogDebug; }
else {
LogPrint(eLogError, "Log: unknown loglevel: ", level);
return;
}
LogPrint(eLogInfo, "Log: min messages level set to ", level);
}
const char * Log::TimeAsString(std::time_t t) {
if (t != m_LastTimestamp) {
strftime(m_LastDateTime, sizeof(m_LastDateTime), "%H:%M:%S", localtime(&t));
m_LastTimestamp = t;
}
return m_LastDateTime;
}
void Log::SetLogFile (const std::string& fullFilePath, bool truncate) /**
{ * @note This function better to be run in separate thread due to disk i/o.
m_FullFilePath = fullFilePath; * Unfortunately, with current startup process with late fork() this
auto mode = std::ofstream::out | std::ofstream::binary; * will give us nothing but pain. Maybe later. See in NetDb as example.
mode |= truncate ? std::ofstream::trunc : std::ofstream::app; */
auto logFile = std::make_shared<std::ofstream> (fullFilePath, mode); void Log::Process() {
if (logFile->is_open ()) std::unique_lock<std::mutex> l(m_OutputLock);
{ std::hash<std::thread::id> hasher;
SetLogStream (logFile); unsigned short short_tid;
LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath); while (1) {
} auto msg = m_Queue.GetNextWithTimeout (1);
} if (!msg)
break;
short_tid = (short) (hasher(msg->tid) % 1000);
switch (m_Destination) {
#ifndef _WIN32
case eLogSyslog:
syslog(GetSyslogPrio(msg->level), "[%03u] %s", short_tid, msg->text.c_str());
break;
#endif
case eLogFile:
case eLogStream:
*m_LogStream << TimeAsString(msg->timestamp)
<< "@" << short_tid
<< "/" << g_LogLevelStr[msg->level]
<< " - " << msg->text << std::endl;
break;
case eLogStdout:
default:
std::cout << TimeAsString(msg->timestamp)
<< "@" << short_tid
<< "/" << g_LogLevelStr[msg->level]
<< " - " << msg->text << std::endl;
break;
} // switch
} // while
}
void Log::ReopenLogFile () void Log::Append(std::shared_ptr<i2p::log::LogMsg> & msg) {
{ m_Queue.Put(msg);
if (m_FullFilePath.length () > 0) if (!m_IsReady)
{ return;
SetLogFile (m_FullFilePath, false); // don't truncate Process();
LogPrint(eLogInfo, "Log: file ", m_FullFilePath, " reopen");
} }
}
void Log::SendTo (const std::string& path) {
auto flags = std::ofstream::out | std::ofstream::app;
auto os = std::make_shared<std::ofstream> (path, flags);
if (os->is_open ()) {
m_Logfile = path;
m_Destination = eLogFile;
m_LogStream = os;
return;
}
LogPrint(eLogError, "Log: can't open file ", path);
}
void Log::SetLogLevel (const std::string& level) void Log::SendTo (std::shared_ptr<std::ostream> os) {
{ m_Destination = eLogStream;
if (level == "error") { m_MinLevel = eLogError; } m_LogStream = os;
else if (level == "warn") { m_MinLevel = eLogWarning; } }
else if (level == "info") { m_MinLevel = eLogInfo; }
else if (level == "debug") { m_MinLevel = eLogDebug; }
else {
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
return;
}
LogPrint(eLogInfo, "Log: min msg level set to ", level);
}
void Log::SetLogStream (std::shared_ptr<std::ostream> logStream) #ifndef _WIN32
{ void Log::SendTo(const char *name, int facility) {
m_LogStream = logStream; m_Destination = eLogSyslog;
} m_LogStream = nullptr;
openlog(name, LOG_CONS | LOG_PID, facility);
}
#endif
void Log::Reopen() {
if (m_Destination == eLogFile)
SendTo(m_Logfile);
}
Log & Logger() {
return logger;
}
} // log
} // i2p

258
Log.h

@ -1,15 +1,27 @@
/*
* 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 LOG_H__ #ifndef LOG_H__
#define LOG_H__ #define LOG_H__
#include <ctime>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream>
#include <fstream> #include <fstream>
#include <functional> #include <sstream>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include "Queue.h" #include "Queue.h"
#ifndef _WIN32
#include <syslog.h>
#endif
enum LogLevel enum LogLevel
{ {
eLogError = 0, eLogError = 0,
@ -19,130 +31,156 @@ enum LogLevel
eNumLogLevels eNumLogLevels
}; };
class Log; enum LogType {
struct LogMsg eLogStdout = 0,
{ eLogStream,
std::stringstream s; eLogFile,
Log * log; #ifndef _WIN32
LogLevel level; eLogSyslog,
#endif
LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
void Process();
};
class Log: public i2p::util::MsgQueue<LogMsg>
{
public:
Log () { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () {};
void SetLogFile (const std::string& fullFilePath, bool truncate = true);
void ReopenLogFile ();
void SetLogLevel (const std::string& level);
void SetLogStream (std::shared_ptr<std::ostream> logStream);
std::shared_ptr<std::ostream> GetLogStream () const { return m_LogStream; };
const std::string& GetTimestamp ();
LogLevel GetLogLevel () { return m_MinLevel; };
const std::string& GetFullFilePath () const { return m_FullFilePath; };
private:
void Flush ();
private:
std::string m_FullFilePath; // empty if stream
std::shared_ptr<std::ostream> m_LogStream;
enum LogLevel m_MinLevel;
std::string m_Timestamp;
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) // gcc 4.6
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
#else
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
#endif
}; };
extern Log * g_Log; namespace i2p {
namespace log {
inline void StartLog (const std::string& fullFilePath) struct LogMsg; /* forward declaration */
{
if (!g_Log)
{
auto log = new Log ();
if (fullFilePath.length () > 0)
log->SetLogFile (fullFilePath);
g_Log = log;
}
}
inline void StartLog (std::shared_ptr<std::ostream> s)
{
if (!g_Log)
{
auto log = new Log ();
if (s)
log->SetLogStream (s);
g_Log = log;
}
}
inline void StopLog () class Log
{
if (g_Log)
{ {
auto log = g_Log; private:
g_Log = nullptr;
log->Stop (); enum LogType m_Destination;
delete log; enum LogLevel m_MinLevel;
} std::shared_ptr<std::ostream> m_LogStream;
} std::string m_Logfile;
std::time_t m_LastTimestamp;
inline void SetLogLevel (const std::string& level) char m_LastDateTime[64];
{ i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue;
if (g_Log) volatile bool m_IsReady;
g_Log->SetLogLevel(level); mutable std::mutex m_OutputLock;
}
private:
inline void ReopenLogFile ()
{ /** prevent making copies */
if (g_Log) Log (const Log &);
g_Log->ReopenLogFile (); const Log& operator=(const Log&);
}
/**
inline bool IsLogToFile () * @brief process stored messages in queue
{ */
return g_Log ? !g_Log->GetFullFilePath ().empty () : false; void Process ();
}
/**
* @brief Makes formatted string from unix timestamp
* @param ts Second since epoch
*
* This function internally caches the result for last provided value
*/
const char * TimeAsString(std::time_t ts);
public:
Log ();
~Log ();
LogType GetLogType () { return m_Destination; };
LogLevel GetLogLevel () { return m_MinLevel; };
/**
* @brief Sets minimal alloed level for log messages
* @param level String with wanted minimal msg level
*/
void SetLogLevel (const std::string& level);
/**
* @brief Sets log destination to logfile
* @param path Path to logfile
*/
void SendTo (const std::string &path);
/**
* @brief Sets log destination to given output stream
* @param os Output stream
*/
void SendTo (std::shared_ptr<std::ostream> s);
#ifndef _WIN32
/**
* @brief Sets log destination to syslog
* @param name Wanted program name
* @param facility Wanted log category
*/
void SendTo (const char *name, int facility);
#endif
/**
* @brief Format log message and write to output stream/syslog
* @param msg Pointer to processed message
*/
void Append(std::shared_ptr<i2p::log::LogMsg> &);
/** @brief Allow log output */
void Ready() { m_IsReady = true; }
/** @brief Flushes the output log stream */
void Flush();
/** @brief Reopen log file */
void Reopen();
};
/**
* @struct Log message container
*
* We creating it somewhere with LogPrint(),
* then put in MsgQueue for later processing.
*/
struct LogMsg {
std::time_t timestamp;
std::string text; /**< message text as single string */
LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {};
};
Log & Logger();
} // log
} // i2p
/** internal usage only -- folding args array to single string */
template<typename TValue> template<typename TValue>
void LogPrint (std::stringstream& s, TValue arg) void LogPrint (std::stringstream& s, TValue arg)
{ {
s << arg; s << arg;
} }
/** internal usage only -- folding args array to single string */
template<typename TValue, typename... TArgs> template<typename TValue, typename... TArgs>
void LogPrint (std::stringstream& s, TValue arg, TArgs... args) void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
{ {
LogPrint (s, arg); LogPrint (s, arg);
LogPrint (s, args...); LogPrint (s, args...);
} }
/**
* @brief Create log message and send it to queue
* @param level Message level (eLogError, eLogInfo, ...)
* @param args Array of message parts
*/
template<typename... TArgs> template<typename... TArgs>
void LogPrint (LogLevel level, TArgs... args) void LogPrint (LogLevel level, TArgs... args)
{ {
if (g_Log && level > g_Log->GetLogLevel ()) i2p::log::Log &log = i2p::log::Logger();
if (level > log.GetLogLevel ())
return; return;
LogMsg * msg = new LogMsg (g_Log, level);
LogPrint (msg->s, args...); // fold message to single string
msg->s << std::endl; std::stringstream ss("");
if (g_Log) { LogPrint (ss, args ...);
g_Log->Put (msg);
} else { auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
msg->Process (); msg->tid = std::this_thread::get_id();
delete msg; log.Append(msg);
}
} }
#endif #endif // LOG_H__

182
Makefile

@ -1,91 +1,91 @@
UNAME := $(shell uname -s) UNAME := $(shell uname -s)
SHLIB := libi2pd.so SHLIB := libi2pd.so
ARLIB := libi2pd.a ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a ARLIB_CLIENT := libi2pdclient.a
I2PD := i2pd I2PD := i2pd
GREP := fgrep GREP := fgrep
DEPS := obj/make.dep DEPS := obj/make.dep
include filelist.mk include filelist.mk
USE_AESNI := yes USE_AESNI := yes
USE_STATIC := no USE_STATIC := no
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp DAEMON_SRC += DaemonLinux.cpp
include Makefile.osx include Makefile.osx
else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1) else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
DAEMON_SRC += DaemonLinux.cpp DAEMON_SRC += DaemonLinux.cpp
include Makefile.bsd include Makefile.bsd
else ifeq ($(UNAME),Linux) else ifeq ($(UNAME),Linux)
DAEMON_SRC += DaemonLinux.cpp DAEMON_SRC += DaemonLinux.cpp
include Makefile.linux include Makefile.linux
else # win32 mingw else # win32 mingw
DAEMON_SRC += DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp DAEMON_SRC += DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp
include Makefile.mingw include Makefile.mingw
endif endif
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
mk_obj_dir: mk_obj_dir:
@mkdir -p obj @mkdir -p obj
@mkdir -p obj/Win32 @mkdir -p obj/Win32
api: mk_obj_dir $(SHLIB) $(ARLIB) api: mk_obj_dir $(SHLIB) $(ARLIB)
api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time ## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build. ## **without** overwriting the CXXFLAGS which we need in order to build.
## For example, when adding 'hardening flags' to the build ## For example, when adding 'hardening flags' to the build
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## -std=c++11. If you want to remove this variable please do so in a way that allows setting
## custom FLAGS to work at build-time. ## custom FLAGS to work at build-time.
deps: mk_obj_dir deps: mk_obj_dir
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
obj/%.o: %.cpp obj/%.o: %.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run # '-' is 'ignore if missing' on first run
-include $(DEPS) -include $(DEPS)
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS) $(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS)
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) $(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ifneq ($(USE_STATIC),yes) ifneq ($(USE_STATIC),yes)
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
endif endif
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) $(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) $(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
ar -r $@ $^ ar -r $@ $^
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) $(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
ar -r $@ $^ ar -r $@ $^
clean: clean:
rm -rf obj rm -rf obj
$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) $(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
strip $^ strip $^
LATEST_TAG=$(shell git describe --tags --abbrev=0 master) LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl)
dist: dist:
git archive --format=tar.gz -9 --worktree-attributes \ git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz --prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
.PHONY: all .PHONY: all
.PHONY: clean .PHONY: clean
.PHONY: deps .PHONY: deps
.PHONY: dist .PHONY: dist
.PHONY: api .PHONY: api
.PHONY: api_client .PHONY: api_client
.PHONY: mk_obj_dir .PHONY: mk_obj_dir

87
Makefile.mingw

@ -1,44 +1,43 @@
USE_WIN32_APP=yes USE_WIN32_APP=yes
CXX = g++ CXX = g++
WINDRES = windres WINDRES = windres
CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
NEEDED_CXXFLAGS = -std=c++11 NEEDED_CXXFLAGS = -std=c++11
BOOST_SUFFIX = -mt BOOST_SUFFIX = -mt
INCFLAGS = -I/usr/include/ -I/usr/local/include/ INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib \ LDFLAGS = -Wl,-rpath,/usr/local/lib \
-L/usr/local/lib \ -L/usr/local/lib \
-L/c/dev/openssl \ -L/c/dev/openssl \
-L/c/dev/boost/lib -L/c/dev/boost/lib
LDLIBS = \ LDLIBS = \
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_regex$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \
-Wl,-Bstatic -lssl \ -Wl,-Bstatic -lssl \
-Wl,-Bstatic -lcrypto \ -Wl,-Bstatic -lcrypto \
-Wl,-Bstatic -lz \ -Wl,-Bstatic -lz \
-Wl,-Bstatic -lwsock32 \ -Wl,-Bstatic -lwsock32 \
-Wl,-Bstatic -lws2_32 \ -Wl,-Bstatic -lws2_32 \
-Wl,-Bstatic -lgdi32 \ -Wl,-Bstatic -lgdi32 \
-Wl,-Bstatic -liphlpapi \ -Wl,-Bstatic -liphlpapi \
-static-libgcc -static-libstdc++ \ -static-libgcc -static-libstdc++ \
-Wl,-Bstatic -lstdc++ \ -Wl,-Bstatic -lstdc++ \
-Wl,-Bstatic -lpthread -Wl,-Bstatic -lpthread
ifeq ($(USE_WIN32_APP), yes) ifeq ($(USE_WIN32_APP), yes)
CXXFLAGS += -DWIN32_APP CXXFLAGS += -DWIN32_APP
LDFLAGS += -mwindows -s LDFLAGS += -mwindows -s
DAEMON_RC += Win32/Resource.rc DAEMON_RC += Win32/Resource.rc
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif endif
ifeq ($(USE_AESNI),1) ifeq ($(USE_AESNI),1)
CPU_FLAGS = -maes -DAESNI CPU_FLAGS = -maes -DAESNI
else else
CPU_FLAGS = -msse CPU_FLAGS = -msse
endif endif
obj/%.o : %.rc obj/%.o : %.rc
$(WINDRES) -i $< -o $@ $(WINDRES) -i $< -o $@

46
Queue.h

@ -117,52 +117,6 @@ namespace util
std::mutex m_QueueMutex; std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty; std::condition_variable m_NonEmpty;
}; };
template<class Msg>
class MsgQueue: public Queue<Msg *>
{
public:
typedef std::function<void()> OnEmpty;
MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
~MsgQueue () { Stop (); };
void Stop()
{
if (m_IsRunning)
{
m_IsRunning = false;
Queue<Msg *>::WakeUp ();
m_Thread.join();
}
}
void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; };
private:
void Run ()
{
while (m_IsRunning)
{
while (auto msg = Queue<Msg *>::Get ())
{
msg->Process ();
delete msg;
}
if (m_OnEmpty != nullptr)
m_OnEmpty ();
if (m_IsRunning)
Queue<Msg *>::Wait ();
}
}
private:
volatile bool m_IsRunning;
OnEmpty m_OnEmpty;
std::thread m_Thread;
};
} }
} }

3
Streaming.cpp

@ -162,7 +162,8 @@ namespace stream
void Stream::SavePacket (Packet * packet) void Stream::SavePacket (Packet * packet)
{ {
m_SavedPackets.insert (packet); if (!m_SavedPackets.insert (packet).second)
delete packet;
} }
void Stream::ProcessPacket (Packet * packet) void Stream::ProcessPacket (Packet * packet)

6
api.cpp

@ -40,9 +40,10 @@ namespace api
void StartI2P (std::shared_ptr<std::ostream> logStream) void StartI2P (std::shared_ptr<std::ostream> logStream)
{ {
if (logStream) if (logStream)
StartLog (logStream); i2p::log::Logger().SendTo (logStream);
else else
StartLog (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log")); i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
i2p::log::Logger().Ready();
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");
@ -60,7 +61,6 @@ namespace api
i2p::transport::transports.Stop(); i2p::transport::transports.Stop();
LogPrint(eLogInfo, "API: stopping NetDB"); LogPrint(eLogInfo, "API: stopping NetDB");
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
StopLog ();
} }
void RunPeerTest () void RunPeerTest ()

12
contrib/certificates/family/mca2-i2p.crt

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBwTCCAWigAwIBAgIJAOZBC10+/38EMAkGByqGSM49BAEwZzELMAkGA1UEBhMC
QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
dHMgUHR5IEx0ZDEgMB4GA1UEAwwXbWNhMi1pMnAuZmFtaWx5LmkycC5uZXQwHhcN
MTYwMzI4MjIwMjMxWhcNMjYwMzI2MjIwMjMxWjBnMQswCQYDVQQGEwJBVTETMBEG
A1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg
THRkMSAwHgYDVQQDDBdtY2EyLWkycC5mYW1pbHkuaTJwLm5ldDBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABNNyfzJr/rMSUeWliVBbJHRF2+qMypOlHEZ9m1nNATVX
64OhuyuVCmbF9R3oDkcZZJQQK1ovXd/EsbAIWDI8K/gwCQYHKoZIzj0EAQNIADBF
AiEApmv2tvMwzlvPjHJG1/5aXOSjYWw2s4ETeGt4abWPQkACIBbF3RuCHuzg+KN8
N0n9hAJztAqhRCdG3hilxF4fbVLp
-----END CERTIFICATE-----

2
debian/control vendored

@ -3,7 +3,7 @@ Section: net
Priority: extra Priority: extra
Maintainer: hagen <hagen@i2pmail.org> Maintainer: hagen <hagen@i2pmail.org>
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~),
gcc (>= 4.6) | clang (>= 3.3), gcc (>= 4.7) | clang (>= 3.3),
libboost-regex-dev, libboost-regex-dev,
libboost-system-dev (>= 1.46), libboost-system-dev (>= 1.46),
libboost-date-time-dev, libboost-date-time-dev,

2
debian/i2pd.1 vendored

@ -68,7 +68,7 @@ Port of BOB command channel. Usually \fI2827\fR. BOB will not be enabled if this
Port of I2P control service. Usually \fI7650\fR. I2PControl will not be enabled if this is not set. (default: unset) Port of I2P control service. Usually \fI7650\fR. I2PControl will not be enabled if this is not set. (default: unset)
.TP .TP
\fB\-\-conf=\fR \fB\-\-conf=\fR
Config file (default: \fI~/.i2pd/i2p.conf\fR or \fI/var/lib/i2pd/i2p.conf\fR) Config file (default: \fI~/.i2pd/i2pd.conf\fR or \fI/var/lib/i2pd/i2pd.conf\fR)
This parameter will be silently ignored if the specified config file does not exist. This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file. Options specified on the command line take precedence over those in the config file.

4
debian/i2pd.links vendored

@ -1,4 +1,4 @@
etc/i2pd/i2pd.conf var/lib/i2pd/i2p.conf etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf
etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.cfg etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf
etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt
usr/share/i2pd/certificates var/lib/i2pd/certificates usr/share/i2pd/certificates var/lib/i2pd/certificates

2
docs/build_requirements.md

@ -4,7 +4,7 @@ Build requirements
Linux/FreeBSD/OSX Linux/FreeBSD/OSX
----------------- -----------------
GCC 4.8 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC. GCC 4.7 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC.
Windows Windows
------- -------

20
docs/configuration.md

@ -4,10 +4,13 @@ i2pd configuration
Command line options Command line options
-------------------- --------------------
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) Options specified on the command line take precedence over those in the config file.
If you are upgrading your very old router (< 2.3.0) see also [this](config_opts_after_2.3.0.md) page.
* --help - Show builtin help message (default value of option will be shown in braces)
* --conf= - Config file (default: ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)
This parameter will be silently ignored if the specified config file does not exist. This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file. * --tunconf= - Tunnels config file (default: ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)
* --tunconf= - Tunnels config file (default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)
* --pidfile= - Where to write pidfile (dont write by default) * --pidfile= - Where to write pidfile (dont write by default)
* --log= - Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility) * --log= - Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)
* --logfile= - Path to logfile (default - autodetect) * --logfile= - Path to logfile (default - autodetect)
@ -24,6 +27,8 @@ Command line options
* --family= - Name of a family, router belongs to * --family= - Name of a family, router belongs to
* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") * --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove")
All options below still possible in cmdline, but better write it in config file:
* --http.address= - The address to listen on (HTTP server) * --http.address= - The address to listen on (HTTP server)
* --http.port= - The port to listen on (HTTP server) * --http.port= - The port to listen on (HTTP server)
@ -60,7 +65,7 @@ All command-line parameters are allowed as keys, but note for those which contai
For example: For example:
i2p.conf: i2pd.conf:
# comment # comment
log = true log = true
@ -69,11 +74,13 @@ i2p.conf:
[httpproxy] [httpproxy]
port = 4444 port = 4444
# ^^ this will be --httproxy.port= in cmdline # ^^ this will be --httproxy.port= in cmdline
# another one # another comment
[sam] [sam]
enabled = true enabled = true
tunnels.cfg (filename of this config is subject of change): See also commented config with examples of all options in ``docs/i2pd.conf``.
tunnels.conf:
# outgoing tunnel sample, to remote service # outgoing tunnel sample, to remote service
# mandatory parameters: # mandatory parameters:
@ -107,6 +114,7 @@ tunnels.cfg (filename of this config is subject of change):
host = 127.0.0.1 host = 127.0.0.1
port = 80 port = 80
keys = site-keys.dat keys = site-keys.dat
#
[IRC-SERVER] [IRC-SERVER]
type = server type = server
host = 127.0.0.1 host = 127.0.0.1

30
docs/family.md

@ -6,27 +6,31 @@ There are two possibilities: create new family or joing to existing.
New family New family
----------- -----------
You must create family self-signed certificate and key. You must create family self-signed certificate and key.
The only key type supposted is prime256v1. The only key type supposted is prime256v1.
Use the following list of commands: Use the following list of commands:
openssl ecparam -name prime256v1 -genkey -out <your family name>.key
openssl req -new -key <your family name>.key -out <your family name>.csr
touch v3.ext
openssl x509 -req -days 3650 -in <your family name>.csr -signkey <your family name>.key -out <your family name>.crt -extfile v3.ext
specify <your family name>.family.i2p.net for CN. openssl ecparam -name prime256v1 -genkey -out <your family name>.key
openssl req -new -key <your family name>.key -out <your family name>.csr
touch v3.ext
openssl x509 -req -days 3650 -in <your family name>.csr -signkey <your family name>.key -out <your family name>.crt -extfile v3.ext
Specify <your family name>.family.i2p.net for CN (Common Name) when requested.
Once you are done with it place <your family name>.key and <your family name>.crt to <ip2d data>/family folder (for exmple ~/.i2pd/family). Once you are done with it place <your-family-name>.key and <your-family-name>.crt to <ip2d data>/family folder (for exmple ~/.i2pd/family).
You should provide these two files to other members joining your family. You should provide these two files to other members joining your family.
If you want to register you family and let I2P network recorgnize it, create pull request for you .crt file into contrib/certificate/family. If you want to register you family and let I2P network recorgnize it, create pull request for you .crt file into contrib/certificate/family.
It will appear in i2pd and I2P next releases packages. Don't place .key file, it must be shared betwwen you family members only. It will appear in i2pd and I2P next releases packages. Dont place .key file, it must be shared between you family members only.
How to join existing family
---------------------------
Join existing family Once you and that family agree to do it, they must give you .key and .crt file and you must place in <i2pd datadir>/certificates/family/ folder.
--------------------
Once you and that family agree to do it, they must give you .key and .crt file and you must place to <ip2d data>/family folder.
Publish your family Publish your family
------------------ -------------------
Run i2pd with parameter 'family=<your family name>', make sure you have <your family name>.key and <your family name>.crt in your 'family' folder.
If everything is set properly, you router.info will contain two new fields: 'family' and 'family.sig'.
Run i2pd with parameter 'family=<your-family-name>', make sure you have <your-family-name>.key and <your-family-name>.crt in your 'family' folder.
If everything is set properly, you router.info will contain two new fields: 'family' and 'family.sig'.
Otherwise your router will complain on startup with log messages starting with "Family:" prefix and severity 'warn' or 'error'.

140
docs/i2pd.conf

@ -6,106 +6,104 @@
## that begin with just "#" are disabled commands: you can enable them ## that begin with just "#" are disabled commands: you can enable them
## by removing the "#" symbol. ## by removing the "#" symbol.
## Tunnels config file ## Tunnels config file
## Default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg ## Default: ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf
#tunconf = /var/lib/i2pd/tunnels.cfg # tunconf = /var/lib/i2pd/tunnels.conf
## Where to write pidfile (don't write by default) ## Where to write pidfile (don't write by default)
#pidfile = /var/run/i2pd.pid # pidfile = /var/run/i2pd.pid
## Logging configuration section ## Logging configuration section
## By default logs go to stdout with level info ## By default logs go to stdout with level 'info' and higher
## ##
## Logs destination (stdout, file) ## Logs destination (valid values: stdout, file, syslog)
#log = file ## * stdout - print log entries to stdout
## * file - log entries to a file
## * syslog - use syslog, see man 3 syslog
# log = file
## Path to logfile (default - autodetect) ## Path to logfile (default - autodetect)
#logfile = /var/log/i2pd.log # logfile = /var/log/i2pd.log
## Log messages above this level (debug, *info, warn, error) ## Log messages above this level (debug, *info, warn, error)
#loglevel = info # loglevel = info
## Path to storage of i2pd data (RI, keys, peer profiles, ...) ## Path to storage of i2pd data (RI, keys, peer profiles, ...)
## Default: ~/.i2pd or /var/lib/i2pd ## Default: ~/.i2pd or /var/lib/i2pd
#datadir = /var/lib/i2pd # datadir = /var/lib/i2pd
## Daemon mode. Router will go to background after start ## Daemon mode. Router will go to background after start
#daemon # daemon = true
## Run as a service. Router will use system folders like ‘/var/lib/i2pd’ ## Run as a service. Router will use system folders like ‘/var/lib/i2pd’
#service # service = true
## External IP address to listen for connections ## External IP address to listen for connections
## By default i2pd sets IP automatically ## By default i2pd sets IP automatically
#host = 1.2.3.4 # host = 1.2.3.4
## Port to listen for connections ## Port to listen for connections
## By default i2pd picks random port. You MUST pick a random number too, ## By default i2pd picks random port. You MUST pick a random number too,
## don't just uncomment this ## don't just uncomment this
#port = 4321 # port = 4321
##Enable communication through ipv6
ipv6 ## Enable communication through ipv6
ipv6 = true
## Bandwidth configuration ## Bandwidth configuration
## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited ## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited
## Default is P for floodfill, L for regular node ## Default is P for floodfill, L for regular node
#bandwidth = L # bandwidth = L
## Router will not accept transit tunnels at startup ## Router will not accept transit tunnels at startup
#notransit # notransit = true
## Router will be floodfill ## Router will be floodfill
#floodfill # floodfill = true
## Section for Web Console
## By default it's available at 127.0.0.1:7070 even if it's not configured
[http] [http]
## The address to listen on ## Uncomment and set to 'false' to disable Web Console
address = 127.0.0.1 # enabled = true
## The port to listen on ## Address and port service will listen on
port = 7070 address = 127.0.0.1
port = 7070
## Section for HTTP proxy
## By default it's available at 127.0.0.1:4444 even if it's not configured
[httpproxy] [httpproxy]
## The address to listen on ## Uncomment and set to 'false' to disable HTTP Proxy
address = 127.0.0.1 # enabled = true
## The port to listen on ## Address and port service will listen on
port = 4444 # address = 127.0.0.1
# port = 4444
## Optional keys file for proxy local destination ## Optional keys file for proxy local destination
#keys = http-proxy-keys.dat # keys = http-proxy-keys.dat
## Uncomment if you want to disable HTTP proxy
#enabled=false [socksproxy]
## Uncomment and set to 'false' to disable SOCKS Proxy
## Section for Socks proxy # enabled = true
## By default it's available at 127.0.0.1:4447 even if it's not configured ## Address and port service will listen on
#[socksproxy] # address = 127.0.0.1
## The address to listen on # port = 4447
#address = 127.0.0.1
## The port to listen on
#port = 4447
## Optional keys file for proxy local destination ## Optional keys file for proxy local destination
#keys = socks-proxy-keys.dat # keys = socks-proxy-keys.dat
## Uncomment if you want to disable Socks proxy
#enabled=false
## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Socks outproxy. Example below is set to use Tor for all connections except i2p
## Address of outproxy ## Address and port of outproxy
#outproxy = 127.0.0.1 # outproxy = 127.0.0.1
## Outproxy remote port # outproxyport = 9050
#outproxyport = 9050
[sam]
## Section for SAM bridge ## Uncomment and set to 'true' to enable SAM Bridge
#[sam] # enabled = false
## The address to listen on ## Address and port service will listen on
#address = 127.0.0.1 # address = 127.0.0.1
## Port of SAM bridge # port = 7656
#port = 7656
[bob]
## Section for BOB command channel ## Uncomment and set to 'true' to enable BOB command channel
#[bob] # enabled = false
## The address to listen on ## Address and port service will listen on
#address = 127.0.0.1 # address = 127.0.0.1
## Port of BOB command channel. Usually 2827. BOB is off if not specified # port = 2827
#port = 2827
[i2pcontrol]
## Section for I2PControl protocol ## Uncomment and set to 'true' to enable I2PControl protocol
#[i2pcontrol] # enabled = false
## The address to listen on ## Address and port service will listen on
#address = 127.0.0.1 # address = 127.0.0.1
## Port of I2P control service # port = 7650
#port = 7650

Loading…
Cancel
Save