diff --git a/AddressBook.cpp b/AddressBook.cpp index 5e7510a5..3cf2bc56 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -203,7 +203,7 @@ namespace client } //--------------------------------------------------------------------- - AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false), + AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr) { } @@ -215,6 +215,8 @@ namespace client void AddressBook::Start () { + if (!m_Storage) + m_Storage = new AddressBookFilesystemStorage; m_Storage->Init(); LoadHosts (); /* try storage, then hosts.txt, then download */ StartSubscriptions (); diff --git a/Base.cpp b/Base.cpp index 766eaab9..35aae437 100644 --- a/Base.cpp +++ b/Base.cpp @@ -1,4 +1,6 @@ #include +#include + #include "Base.h" namespace i2p @@ -283,99 +285,6 @@ namespace data } return ret; } - - GzipInflator::GzipInflator (): m_IsDirty (false) - { - memset (&m_Inflator, 0, sizeof (m_Inflator)); - inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip - } - - GzipInflator::~GzipInflator () - { - inflateEnd (&m_Inflator); - } - - size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) - { - if (m_IsDirty) inflateReset (&m_Inflator); - m_IsDirty = true; - m_Inflator.next_in = const_cast(in); - m_Inflator.avail_in = inLen; - m_Inflator.next_out = out; - m_Inflator.avail_out = outLen; - int err; - if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) { - return outLen - m_Inflator.avail_out; - } - return 0; - } - - bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s) - { - m_IsDirty = true; - uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE]; - m_Inflator.next_in = const_cast(in); - m_Inflator.avail_in = inLen; - int ret; - do - { - m_Inflator.next_out = out; - m_Inflator.avail_out = GZIP_CHUNK_SIZE; - ret = inflate (&m_Inflator, Z_NO_FLUSH); - if (ret < 0) - { - inflateEnd (&m_Inflator); - s.setstate(std::ios_base::failbit); - break; - } - s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); - } - while (!m_Inflator.avail_out); // more data to read - delete[] out; - return ret == Z_STREAM_END || ret < 0; - } - - void GzipInflator::Inflate (std::istream& in, std::ostream& out) - { - uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE]; - while (!in.eof ()) - { - in.read ((char *)buf, GZIP_CHUNK_SIZE); - Inflate (buf, in.gcount (), out); - } - delete[] buf; - } - - GzipDeflator::GzipDeflator (): m_IsDirty (false) - { - memset (&m_Deflator, 0, sizeof (m_Deflator)); - deflateInit2 (&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip - } - - GzipDeflator::~GzipDeflator () - { - deflateEnd (&m_Deflator); - } - - void GzipDeflator::SetCompressionLevel (int level) - { - deflateParams (&m_Deflator, level, Z_DEFAULT_STRATEGY); - } - - size_t GzipDeflator::Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) - { - if (m_IsDirty) deflateReset (&m_Deflator); - m_IsDirty = true; - m_Deflator.next_in = const_cast(in); - m_Deflator.avail_in = inLen; - m_Deflator.next_out = out; - m_Deflator.avail_out = outLen; - int err; - if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) { - return outLen - m_Deflator.avail_out; - } /* else */ - return 0; - } } } diff --git a/Base.h b/Base.h index 0c38725e..66192d1b 100644 --- a/Base.h +++ b/Base.h @@ -2,15 +2,11 @@ #define BASE_H__ #include -#include #include -#include #include -namespace i2p -{ -namespace data -{ +namespace i2p { +namespace data { 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 ); const char * GetBase32SubstitutionTable (); @@ -23,112 +19,7 @@ namespace data Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes */ size_t Base64EncodingBufferSize(const size_t input_size); - - template - class Tag - { - public: - - Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; - Tag (const Tag& ) = default; -#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it - Tag (Tag&& ) = default; -#endif - Tag () = default; - - Tag& operator= (const Tag& ) = default; -#ifndef _WIN32 - Tag& operator= (Tag&& ) = default; -#endif - - uint8_t * operator()() { return m_Buf; }; - const uint8_t * operator()() const { return m_Buf; }; - - operator uint8_t * () { return m_Buf; }; - operator const uint8_t * () const { return m_Buf; }; - - const uint64_t * GetLL () const { return ll; }; - - bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; - bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; - - bool IsZero () const - { - for (int i = 0; i < sz/8; i++) - if (ll[i]) return false; - return true; - } - - std::string ToBase64 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } - - std::string ToBase32 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } - - void FromBase32 (const std::string& s) - { - i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } - - void FromBase64 (const std::string& s) - { - i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } - - private: - - union // 8 bytes alignment - { - uint8_t m_Buf[sz]; - uint64_t ll[sz/8]; - }; - }; - - const size_t GZIP_CHUNK_SIZE = 16384; - class GzipInflator - { - public: - - GzipInflator (); - ~GzipInflator (); - - size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); - bool Inflate (const uint8_t * in, size_t inLen, std::ostream& s); - // return true when finshed or error, s failbit will be set in case of error - void Inflate (std::istream& in, std::ostream& out); - - private: - - z_stream m_Inflator; - bool m_IsDirty; - }; - - class GzipDeflator - { - public: - - GzipDeflator (); - ~GzipDeflator (); - - void SetCompressionLevel (int level); - size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); - - private: - - z_stream m_Deflator; - bool m_IsDirty; - }; -} -} +} // data +} // i2p #endif diff --git a/Crypto.h b/Crypto.h index 7ce202ce..a66f51b7 100644 --- a/Crypto.h +++ b/Crypto.h @@ -9,7 +9,9 @@ #include #include #include + #include "Base.h" +#include "Tag.h" namespace i2p { diff --git a/DaemonWin32.cpp b/DaemonWin32.cpp index 3afb70ce..6eb43dc0 100644 --- a/DaemonWin32.cpp +++ b/DaemonWin32.cpp @@ -1,113 +1,115 @@ -#include -#include "Config.h" -#include "Daemon.h" -#include "util.h" -#include "Log.h" - -#ifdef _WIN32 - -#include "Win32/Win32Service.h" -#ifdef WIN32_APP -#include "Win32/Win32App.h" -#endif - -namespace i2p -{ - namespace util - { - bool DaemonWin32::init(int argc, char* argv[]) - { - setlocale(LC_CTYPE, ""); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - - if (!Daemon_Singleton::init(argc, argv)) - return false; - - std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); - if (serviceControl == "install") - { - LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); - InstallService( - SERVICE_NAME, // Name of service - SERVICE_DISPLAY_NAME, // Name to display - SERVICE_START_TYPE, // Service start type - SERVICE_DEPENDENCIES, // Dependencies - SERVICE_ACCOUNT, // Service running account - SERVICE_PASSWORD // Password of the account - ); - return false; - } - else if (serviceControl == "remove") - { - LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); - UninstallService(SERVICE_NAME); - return false; - } - +#include +#include +#include "Config.h" +#include "Daemon.h" +#include "util.h" +#include "Log.h" + +#ifdef _WIN32 + +#include "Win32/Win32Service.h" +#ifdef WIN32_APP +#include "Win32/Win32App.h" +#endif + +namespace i2p +{ + namespace util + { + bool DaemonWin32::init(int argc, char* argv[]) + { + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); + + if (!Daemon_Singleton::init(argc, argv)) + return false; + + std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); + if (serviceControl == "install") + { + LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); + InstallService( + SERVICE_NAME, // Name of service + SERVICE_DISPLAY_NAME, // Name to display + SERVICE_START_TYPE, // Service start type + SERVICE_DEPENDENCIES, // Dependencies + SERVICE_ACCOUNT, // Service running account + SERVICE_PASSWORD // Password of the account + ); + return false; + } + else if (serviceControl == "remove") + { + LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); + UninstallService(SERVICE_NAME); + return false; + } + if (isDaemon) - { - LogPrint(eLogDebug, "Daemon: running as service"); - I2PService service(SERVICE_NAME); - if (!I2PService::Run(service)) - { - LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); - return false; - } - return false; - } - else - LogPrint(eLogDebug, "Daemon: running as user"); - - return true; - } - - bool DaemonWin32::start() - { - setlocale(LC_CTYPE, ""); - SetConsoleCP(1251); - SetConsoleOutputCP(1251); - setlocale(LC_ALL, "Russian"); -#ifdef WIN32_APP - if (!i2p::win32::StartWin32App ()) return false; - - // override log - i2p::config::SetOption("log", std::string ("file")); -#endif - bool ret = Daemon_Singleton::start(); - if (ret && i2p::log::Logger().GetLogType() == eLogFile) - { - // TODO: find out where this garbage to console comes from - SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); - SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); - } - bool insomnia; i2p::config::GetOption("insomnia", insomnia); - if (insomnia) - SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); - return ret; - } - - bool DaemonWin32::stop() - { -#ifdef WIN32_APP - i2p::win32::StopWin32App (); -#endif - return Daemon_Singleton::stop(); - } - - void DaemonWin32::run () - { -#ifdef WIN32_APP - i2p::win32::RunWin32App (); -#else - while (running) - { - std::this_thread::sleep_for (std::chrono::seconds(1)); - } - -#endif - } - } -} - -#endif + { + LogPrint(eLogDebug, "Daemon: running as service"); + I2PService service(SERVICE_NAME); + if (!I2PService::Run(service)) + { + LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); + return false; + } + return false; + } + else + LogPrint(eLogDebug, "Daemon: running as user"); + + return true; + } + + bool DaemonWin32::start() + { + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); +#ifdef WIN32_APP + if (!i2p::win32::StartWin32App ()) return false; + + // override log + i2p::config::SetOption("log", std::string ("file")); +#endif + bool ret = Daemon_Singleton::start(); + if (ret && i2p::log::Logger().GetLogType() == eLogFile) + { + // TODO: find out where this garbage to console comes from + SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); + SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); + } + bool insomnia; i2p::config::GetOption("insomnia", insomnia); + if (insomnia) + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); + return ret; + } + + bool DaemonWin32::stop() + { +#ifdef WIN32_APP + i2p::win32::StopWin32App (); +#endif + return Daemon_Singleton::stop(); + } + + void DaemonWin32::run () + { +#ifdef WIN32_APP + i2p::win32::RunWin32App (); +#else + while (running) + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + } + +#endif + } + } +} + +#endif diff --git a/Garlic.cpp b/Garlic.cpp index b092c2fe..17740fae 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -7,6 +7,7 @@ #include "I2NPProtocol.h" #include "Tunnel.h" #include "TunnelPool.h" +#include "Transports.h" #include "Timestamp.h" #include "Log.h" #include "Garlic.h" @@ -514,26 +515,34 @@ namespace garlic buf += 32; uint32_t gwTunnel = bufbe32toh (buf); buf += 4; - std::shared_ptr tunnel; - if (from && from->GetTunnelPool ()) - tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); - if (!tunnel) + auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); + if (from) // received through an inbound tunnel { - tunnel = GetTunnelPool()->GetNextOutboundTunnel(); + std::shared_ptr tunnel; + if (from->GetTunnelPool ()) + tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); + else + LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel"); + if (tunnel) // we have send it through an outbound tunnel + tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); + else + LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); } - if (tunnel) // we have send it through an outbound tunnel - { - auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); - tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); - } - else - LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove given tunnelID=", gwTunnel); + else // received directly + i2p::transport::transports.SendMessage (gwHash, i2p::CreateTunnelGatewayMsg (gwTunnel, msg)); // send directly break; } case eGarlicDeliveryTypeRouter: - LogPrint (eLogWarning, "Garlic: type router not supported"); + { + uint8_t * ident = buf; buf += 32; - break; + if (!from) // received directly + i2p::transport::transports.SendMessage (ident, + CreateI2NPMessage (buf, GetI2NPMessageLength (buf))); + else + LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported"); + break; + } default: LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); } diff --git a/Gzip.cpp b/Gzip.cpp new file mode 100644 index 00000000..da9f06b1 --- /dev/null +++ b/Gzip.cpp @@ -0,0 +1,108 @@ +/* +* 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 +#include /* memset */ +#include + +#include "Gzip.h" + +namespace i2p { +namespace data { + const size_t GZIP_CHUNK_SIZE = 16384; + + GzipInflator::GzipInflator (): m_IsDirty (false) + { + memset (&m_Inflator, 0, sizeof (m_Inflator)); + inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip + } + + GzipInflator::~GzipInflator () + { + inflateEnd (&m_Inflator); + } + + size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) + { + if (m_IsDirty) inflateReset (&m_Inflator); + m_IsDirty = true; + m_Inflator.next_in = const_cast(in); + m_Inflator.avail_in = inLen; + m_Inflator.next_out = out; + m_Inflator.avail_out = outLen; + int err; + if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) { + return outLen - m_Inflator.avail_out; + } + return 0; + } + + void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os) + { + m_IsDirty = true; + uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE]; + m_Inflator.next_in = const_cast(in); + m_Inflator.avail_in = inLen; + int ret; + do { + m_Inflator.next_out = out; + m_Inflator.avail_out = GZIP_CHUNK_SIZE; + ret = inflate (&m_Inflator, Z_NO_FLUSH); + if (ret < 0) { + inflateEnd (&m_Inflator); + os.setstate(std::ios_base::failbit); + break; + } + os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); + } while (!m_Inflator.avail_out); // more data to read + delete[] out; + } + + void GzipInflator::Inflate (std::istream& in, std::ostream& out) + { + uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE]; + while (!in.eof ()) + { + in.read ((char *) buf, GZIP_CHUNK_SIZE); + Inflate (buf, in.gcount (), out); + } + delete[] buf; + } + + GzipDeflator::GzipDeflator (): m_IsDirty (false) + { + memset (&m_Deflator, 0, sizeof (m_Deflator)); + deflateInit2 (&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip + } + + GzipDeflator::~GzipDeflator () + { + deflateEnd (&m_Deflator); + } + + void GzipDeflator::SetCompressionLevel (int level) + { + deflateParams (&m_Deflator, level, Z_DEFAULT_STRATEGY); + } + + size_t GzipDeflator::Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) + { + if (m_IsDirty) deflateReset (&m_Deflator); + m_IsDirty = true; + m_Deflator.next_in = const_cast(in); + m_Deflator.avail_in = inLen; + m_Deflator.next_out = out; + m_Deflator.avail_out = outLen; + int err; + if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) { + return outLen - m_Deflator.avail_out; + } /* else */ + return 0; + } +} // data +} // i2p diff --git a/Gzip.h b/Gzip.h new file mode 100644 index 00000000..35661abe --- /dev/null +++ b/Gzip.h @@ -0,0 +1,44 @@ +#ifndef GZIP_H__ +#define GZIP_H__ + +#include + +namespace i2p { +namespace data { + class GzipInflator + { + public: + + GzipInflator (); + ~GzipInflator (); + + size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); + /** @note @a os failbit will be set in case of error */ + void Inflate (const uint8_t * in, size_t inLen, std::ostream& os); + void Inflate (std::istream& in, std::ostream& out); + + private: + + z_stream m_Inflator; + bool m_IsDirty; + }; + + class GzipDeflator + { + public: + + GzipDeflator (); + ~GzipDeflator (); + + void SetCompressionLevel (int level); + size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); + + private: + + z_stream m_Deflator; + bool m_IsDirty; + }; +} // data +} // i2p + +#endif /* GZIP_H__ */ diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index af914b47..db58d1dc 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -82,13 +82,13 @@ namespace proxy { void HTTPReqHandler::AsyncSockRead() { LogPrint(eLogDebug, "HTTPProxy: async sock read"); - if(m_sock) { - m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), - std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); - } else { + if (!m_sock) { LogPrint(eLogError, "HTTPProxy: no socket for read"); + return; } + m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), + std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), + std::placeholders::_1, std::placeholders::_2)); } void HTTPReqHandler::Terminate() { @@ -335,20 +335,18 @@ namespace proxy { void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr stream) { - if (stream) - { - if (Kill()) return; - LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection"); - auto connection = std::make_shared(GetOwner(), m_sock, stream); - GetOwner()->AddHandler (connection); - connection->I2PConnect (reinterpret_cast(m_request.data()), m_request.size()); - Done(shared_from_this()); - } - else - { + if (!stream) { LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); HTTPRequestFailed("error when creating the stream, check logs"); + return; } + if (Kill()) + return; + LogPrint (eLogDebug, "HTTPProxy: New I2PTunnel connection"); + auto connection = std::make_shared(GetOwner(), m_sock, stream); + GetOwner()->AddHandler (connection); + connection->I2PConnect (reinterpret_cast(m_request.data()), m_request.size()); + Done (shared_from_this()); } HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination): diff --git a/HTTPServer.cpp b/HTTPServer.cpp index f35e02d3..be3b9b58 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -126,8 +126,12 @@ namespace http { s << "\r\n" "\r\n" /* TODO: Add support for locale */ - " \r\n" - " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ + " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ +#if (!defined(WIN32)) + " \r\n" +#else + " \r\n" +#endif " \r\n" " Purple I2P " VERSION " Webconsole\r\n" << cssStyles << diff --git a/Makefile b/Makefile index 025dbbcc..87327e77 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ include filelist.mk USE_AESNI := yes USE_STATIC := no USE_MESHNET := yes +USE_UPNP := no ifeq ($(UNAME),Darwin) DAEMON_SRC += DaemonLinux.cpp diff --git a/Makefile.homebrew b/Makefile.homebrew index 6ce513fe..f57f6495 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -8,7 +8,7 @@ INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -ifeq ($(USE_UPNP),1) +ifeq ($(USE_UPNP),yes) LDFLAGS += -ldl CXXFLAGS += -DUSE_UPNP endif diff --git a/Makefile.linux b/Makefile.linux index 324d9467..1376260a 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -43,7 +43,7 @@ else endif # UPNP Support (miniupnpc 1.5 or 1.6) -ifeq ($(USE_UPNP),1) +ifeq ($(USE_UPNP),yes) LDFLAGS += -lminiupnpc CXXFLAGS += -DUSE_UPNP endif diff --git a/Makefile.mingw b/Makefile.mingw index 682221d1..5cf16bf5 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -9,7 +9,7 @@ LDFLAGS = -Wl,-rpath,/usr/local/lib \ -L/usr/local/lib # UPNP Support -ifeq ($(USE_UPNP),1) +ifeq ($(USE_UPNP),yes) CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB LDLIBS = -Wl,-Bstatic -lminiupnpc endif @@ -37,7 +37,7 @@ ifeq ($(USE_WIN32_APP), yes) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif -ifeq ($(USE_AESNI),1) +ifeq ($(USE_AESNI),yes) CPU_FLAGS = -maes -DAESNI else CPU_FLAGS = -msse diff --git a/Makefile.osx b/Makefile.osx index ef236c9a..f40ce1af 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -5,7 +5,7 @@ INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -ifeq ($(USE_UPNP),1) +ifeq ($(USE_UPNP),yes) LDFLAGS += -ldl CXXFLAGS += -DUSE_UPNP endif diff --git a/NTCPSession.cpp b/NTCPSession.cpp index ae020f5f..953c0707 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -1,6 +1,6 @@ #include #include -#include + #include "I2PEndian.h" #include "Base.h" #include "Crypto.h" @@ -430,7 +430,7 @@ namespace transport } else { - LogPrint (eLogInfo, "NTCP: Server session from ", m_Socket.remote_endpoint (), " connected"); + LogPrint (eLogDebug, "NTCP: Server session from ", m_Socket.remote_endpoint (), " connected"); m_Server.AddNTCPSession (shared_from_this ()); Connected (); @@ -942,7 +942,7 @@ namespace transport { if (ecode) { - LogPrint (eLogError, "NTCP: Connect error: ", ecode.message ()); + LogPrint (eLogError, "NTCP: Can't connect to ", conn->GetSocket ().remote_endpoint (), ": ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); conn->Terminate (); diff --git a/NetDb.cpp b/NetDb.cpp index d2afc50a..937ea830 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -2,7 +2,7 @@ #include #include #include -#include + #include "I2PEndian.h" #include "Base.h" #include "Crypto.h" @@ -671,7 +671,7 @@ namespace data if (!replyMsg) { - LogPrint (eLogWarning, "NetDb: Requested ", key, " not found. ", numExcluded, " excluded"); + LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded"); // find or cleate response std::vector closestFloodfills; bool found = false; diff --git a/NetDb.h b/NetDb.h index 1c062358..823dbb54 100644 --- a/NetDb.h +++ b/NetDb.h @@ -8,7 +8,9 @@ #include #include #include + #include "Base.h" +#include "Gzip.h" #include "FS.h" #include "Queue.h" #include "I2NPProtocol.h" diff --git a/SSU.cpp b/SSU.cpp index edc5b898..4693a4f6 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -253,7 +253,7 @@ namespace transport session = std::make_shared (*this, packet->from); session->WaitForConnect (); (*sessions)[packet->from] = session; - LogPrint (eLogInfo, "SSU: new session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); + LogPrint (eLogDebug, "SSU: new session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); } } session->ProcessNextMessage (packet->buf, packet->len, packet->from); @@ -334,7 +334,7 @@ namespace transport auto session = std::make_shared (*this, remoteEndpoint, router, peerTest); sessions[remoteEndpoint] = session; // connect - LogPrint (eLogInfo, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ", + LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ", remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ()); session->Connect (); } @@ -386,10 +386,10 @@ namespace transport } if (introducerSession) // session found - LogPrint (eLogInfo, "SSU: Session to introducer already exists"); + LogPrint (eLogWarning, "SSU: Session to introducer already exists"); else // create new { - LogPrint (eLogInfo, "SSU: Creating new session to introducer"); + LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); introducerSession = std::make_shared (*this, introducerEndpoint, router); m_Sessions[introducerEndpoint] = introducerSession; diff --git a/SSUData.cpp b/SSUData.cpp index 4ce7451d..2bd65682 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -241,7 +241,7 @@ namespace transport if (!msg->IsExpired ()) m_Handler.PutNextMessage (msg); else - LogPrint (eLogInfo, "SSU: message expired"); + LogPrint (eLogDebug, "SSU: message expired"); } else LogPrint (eLogWarning, "SSU: Message ", msgID, " already received"); diff --git a/SSUSession.cpp b/SSUSession.cpp index ce70d637..9c90ff88 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -814,7 +814,7 @@ namespace transport if (!ecode) { // timeout expired - LogPrint (eLogWarning, "SSU: session was not established after ", SSU_CONNECT_TIMEOUT, " seconds"); + LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds"); Failed (); } } @@ -891,7 +891,7 @@ namespace transport { if (ecode != boost::asio::error::operation_aborted) { - LogPrint (eLogWarning, "SSU: no activity for ", SSU_TERMINATION_TIMEOUT, " seconds"); + LogPrint (eLogWarning, "SSU: no activity with ", m_RemoteEndpoint, " for ", SSU_TERMINATION_TIMEOUT, " seconds"); Failed (); } } diff --git a/Tag.h b/Tag.h new file mode 100644 index 00000000..e3432501 --- /dev/null +++ b/Tag.h @@ -0,0 +1,82 @@ +#ifndef TAG_H__ +#define TAG_H__ + +#include /* memcpy */ + +#include "Base.h" + +namespace i2p { +namespace data { + template + class Tag + { + public: + + Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; + Tag (const Tag& ) = default; +#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it + Tag (Tag&& ) = default; +#endif + Tag () = default; + + Tag& operator= (const Tag& ) = default; +#ifndef _WIN32 + Tag& operator= (Tag&& ) = default; +#endif + + uint8_t * operator()() { return m_Buf; }; + const uint8_t * operator()() const { return m_Buf; }; + + operator uint8_t * () { return m_Buf; }; + operator const uint8_t * () const { return m_Buf; }; + + const uint64_t * GetLL () const { return ll; }; + + bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; + bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; + + bool IsZero () const + { + for (int i = 0; i < sz/8; i++) + if (ll[i]) return false; + return true; + } + + std::string ToBase64 () const + { + char str[sz*2]; + int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); + str[l] = 0; + return std::string (str); + } + + std::string ToBase32 () const + { + char str[sz*2]; + int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); + str[l] = 0; + return std::string (str); + } + + void FromBase32 (const std::string& s) + { + i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + + void FromBase64 (const std::string& s) + { + i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + + private: + + union // 8 bytes alignment + { + uint8_t m_Buf[sz]; + uint64_t ll[sz/8]; + }; + }; +} // data +} // i2p + +#endif /* TAG_H__ */ diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 0d54fc11..dfe01a05 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -92,7 +92,7 @@ namespace tunnel { if (isEndpoint) { - LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created"); + LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created"); return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } else if (isGateway) @@ -102,7 +102,7 @@ namespace tunnel } else { - LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created"); + LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created"); return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } } diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 61e05e83..3f5f599f 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -21,6 +21,7 @@ set (LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/Config.cpp" "${CMAKE_SOURCE_DIR}/Crypto.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp" + "${CMAKE_SOURCE_DIR}/Gzip.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" "${CMAKE_SOURCE_DIR}/Identity.cpp" "${CMAKE_SOURCE_DIR}/LeaseSet.cpp" diff --git a/debian/control b/debian/control index 78906ba4..ac6f5e28 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, + libminiupnpc-dev, libssl-dev Standards-Version: 3.9.3 Homepage: https://github.com/PurpleI2P/i2pd diff --git a/debian/patches/0001-disable-aesni-by-default.patch b/debian/patches/01-tune-build-opts.patch similarity index 55% rename from debian/patches/0001-disable-aesni-by-default.patch rename to debian/patches/01-tune-build-opts.patch index eae44c8b..e0e24408 100644 --- a/debian/patches/0001-disable-aesni-by-default.patch +++ b/debian/patches/01-tune-build-opts.patch @@ -1,13 +1,16 @@ diff --git a/Makefile b/Makefile -index 2e86fd8..c1037af 100644 +index fe8ae7e..fc8abda 100644 --- a/Makefile +++ b/Makefile -@@ -9,7 +9,7 @@ DEPS := obj/make.dep +@@ -9,9 +9,9 @@ DEPS := obj/make.dep include filelist.mk -USE_AESNI := yes +USE_AESNI := no USE_STATIC := no +-USE_UPNP := no ++USE_UPNP := yes ifeq ($(UNAME),Darwin) + DAEMON_SRC += DaemonLinux.cpp diff --git a/debian/patches/series b/debian/patches/series index 1c9d0fbf..972d2a10 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1 @@ -0001-disable-aesni-by-default.patch +01-tune-build-opts.patch diff --git a/filelist.mk b/filelist.mk index 8abf0b4b..d8d74252 100644 --- a/filelist.mk +++ b/filelist.mk @@ -1,5 +1,5 @@ LIB_SRC = \ - Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ + Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \ Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 07e71839..db3f21c8 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../RouterInfo.cpp ../../SAM.cpp ../../Signature.cpp ../../SOCKS.cpp ../../SSU.cpp \ ../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \ ../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \ - ../../TunnelPool.cpp ../../UPnP.cpp ../../util.cpp ../../i2pd.cpp + ../../TunnelPool.cpp ../../UPnP.cpp ../../util.cpp ../../Gzip.cpp ../../i2pd.cpp HEADERS += DaemonQT.h mainwindow.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ @@ -50,7 +50,7 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \ ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \ ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \ - ../../util.h ../../version.h + ../../util.h ../../version.h ..//../Gzip.h ../../Tag.h FORMS += mainwindow.ui diff --git a/tests/Makefile b/tests/Makefile index 957d4632..ef30c631 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,11 +1,14 @@ CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 TESTS = test-http-url test-http-req test-http-res test-http-url_decode \ - test-http-merge_chunked + test-http-merge_chunked test-base-64 all: $(TESTS) run -test-http-%: test-http-%.cpp ../HTTP.cpp +test-http-%: ../HTTP.cpp test-http-%.cpp + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ + +test-base-%: ../Base.cpp test-base-%.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ run: $(TESTS) diff --git a/tests/test-base-64.cpp b/tests/test-base-64.cpp new file mode 100644 index 00000000..d8d0ce2f --- /dev/null +++ b/tests/test-base-64.cpp @@ -0,0 +1,45 @@ +#include +#include + +#include "../Base.h" + +using namespace i2p::data; + +int main() { + const char *in = "test"; + size_t in_len = strlen(in); + char out[16]; + + /* bytes -> b64 */ + assert(ByteStreamToBase64(NULL, 0, NULL, 0) == 0); + assert(ByteStreamToBase64(NULL, 0, out, sizeof(out)) == 0); + + assert(Base64EncodingBufferSize(2) == 4); + assert(Base64EncodingBufferSize(4) == 8); + assert(Base64EncodingBufferSize(6) == 8); + assert(Base64EncodingBufferSize(7) == 12); + assert(Base64EncodingBufferSize(9) == 12); + assert(Base64EncodingBufferSize(10) == 16); + assert(Base64EncodingBufferSize(12) == 16); + assert(Base64EncodingBufferSize(13) == 20); + + assert(ByteStreamToBase64((uint8_t *) in, in_len, out, sizeof(out)) == 8); + assert(memcmp(out, "dGVzdA==", 8) == 0); + + /* b64 -> bytes */ + assert(Base64ToByteStream(NULL, 0, NULL, 0) == 0); + assert(Base64ToByteStream(NULL, 0, (uint8_t *) out, sizeof(out)) == 0); + + in = "dGVzdA=="; /* valid b64 */ + assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 4); + assert(memcmp(out, "test", 4) == 0); + + in = "dGVzdA="; /* invalid b64 : not padded */ + assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); + + in = "dG/z.A=="; /* invalid b64 : char not from alphabet */ +// assert(Base64ToByteStream(in, strlen(in), (uint8_t *) out, sizeof(out)) == 0); +// ^^^ fails, current implementation not checks acceptable symbols + + return 0; +} diff --git a/tests/test-http-req.cpp b/tests/test-http-req.cpp index d5362622..c857ca24 100644 --- a/tests/test-http-req.cpp +++ b/tests/test-http-req.cpp @@ -22,7 +22,6 @@ int main() { assert(req->version == "HTTP/1.0"); assert(req->method == "GET"); assert(req->uri == "/"); - assert(req->host == "inr.i2p"); assert(req->headers.size() == 3); assert(req->headers.count("Host") == 1); assert(req->headers.count("Accept") == 1); @@ -42,7 +41,6 @@ int main() { assert(req->version == "HTTP/1.0"); assert(req->method == "GET"); assert(req->uri == "/"); - assert(req->host == ""); assert(req->headers.size() == 0); delete req; @@ -52,7 +50,7 @@ int main() { "\r\n"; len = strlen(buf); req = new HTTPReq; - assert((ret = req->parse(buf, len)) == -1); /* no host header */ + assert((ret = req->parse(buf, len)) > 0); delete req; /* test: parsing incomplete request */ @@ -76,7 +74,6 @@ int main() { assert((ret = req->parse(buf, len)) == len); /* no host header */ assert(req->method == "GET"); assert(req->uri == "http://inr.i2p"); - assert(req->host == "stats.i2p"); assert(req->headers.size() == 3); assert(req->headers.count("Host") == 1); assert(req->headers.count("Accept") == 1);