Browse Source

Merge pull request #556 from PurpleI2P/openssl

floodfill fixes
pull/580/head
orignal 8 years ago committed by GitHub
parent
commit
03d7330af5
  1. 4
      AddressBook.cpp
  2. 104
      Base.cpp
  3. 117
      Base.h
  4. 11
      ChangeLog
  5. 79
      Config.cpp
  6. 2
      Crypto.h
  7. 226
      DaemonWin32.cpp
  8. 4
      Destination.cpp
  9. 37
      Garlic.cpp
  10. 108
      Gzip.cpp
  11. 44
      Gzip.h
  12. 7
      HTTP.cpp
  13. 2
      HTTP.h
  14. 159
      HTTPProxy.cpp
  15. 25
      HTTPProxy.h
  16. 18
      HTTPServer.cpp
  17. 14
      I2CP.cpp
  18. 16
      I2CP.h
  19. 2
      I2PControl.cpp
  20. 1
      Makefile
  21. 2
      Makefile.homebrew
  22. 8
      Makefile.linux
  23. 94
      Makefile.mingw
  24. 2
      Makefile.osx
  25. 6
      NTCPSession.cpp
  26. 21
      NetDb.cpp
  27. 2
      NetDb.h
  28. 8
      SSU.cpp
  29. 12
      SSUData.cpp
  30. 1
      SSUData.h
  31. 4
      SSUSession.cpp
  32. 45
      Streaming.cpp
  33. 90
      Tag.h
  34. 4
      TransitTunnel.cpp
  35. 29
      Tunnel.cpp
  36. 11
      Tunnel.h
  37. 5
      TunnelConfig.h
  38. 39
      TunnelPool.cpp
  39. 78
      UPnP.cpp
  40. 6
      UPnP.h
  41. 5
      build/CMakeLists.txt
  42. 1
      debian/control
  43. 7
      debian/patches/01-tune-build-opts.patch
  44. 2
      debian/patches/series
  45. 2
      docs/build_notes_windows.md
  46. 8
      docs/configuration.md
  47. 2
      filelist.mk
  48. 1
      qt/i2pd_qt/.gitignore
  49. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  50. 5
      qt/i2pd_qt/i2pd.qrc
  51. 260
      qt/i2pd_qt/i2pd_qt.pro
  52. BIN
      qt/i2pd_qt/images/icon.png
  53. 121
      qt/i2pd_qt/mainwindow.cpp
  54. 34
      qt/i2pd_qt/mainwindow.h
  55. 24
      qt/i2pd_qt/mainwindow.ui
  56. 7
      tests/Makefile
  57. 45
      tests/test-base-64.cpp
  58. 5
      tests/test-http-req.cpp
  59. 2
      tests/test-http-res.cpp

4
AddressBook.cpp

@ -203,7 +203,7 @@ namespace client @@ -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 @@ -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 ();

104
Base.cpp

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
#include <stdlib.h>
#include "Log.h"
#include <string.h>
#include "Base.h"
namespace i2p
@ -284,107 +285,6 @@ namespace data @@ -284,107 +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<uint8_t *>(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;
else
{
LogPrint (eLogError, "Decompression error ", err);
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<uint8_t *>(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)
{
LogPrint (eLogError, "Decompression error ", ret);
inflateEnd (&m_Inflator);
s.setstate(std::ios_base::failbit);
break;
}
else
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<uint8_t *>(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
{
LogPrint (eLogError, "Compression error ", err);
return 0;
}
}
}
}

117
Base.h

@ -2,15 +2,11 @@ @@ -2,15 +2,11 @@
#define BASE_H__
#include <inttypes.h>
#include <string.h>
#include <string>
#include <zlib.h>
#include <iostream>
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 @@ -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<int sz>
class Tag
{
public:
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
Tag (const Tag<sz>& ) = default;
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
Tag (Tag<sz>&& ) = default;
#endif
Tag () = default;
Tag<sz>& operator= (const Tag<sz>& ) = default;
#ifndef _WIN32
Tag<sz>& operator= (Tag<sz>&& ) = 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<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
bool operator< (const Tag<sz>& 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

11
ChangeLog

@ -1,14 +1,23 @@ @@ -1,14 +1,23 @@
# for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog
## [2.8.0] - UNRELEASED
## [2.9.0] - UNRELEASED
### Changed
- Proxy refactoring & speedup
## [2.8.0] - 2016-06-20
### Added
- Basic Android support
- I2CP implementation
- 'doxygen' target
### Changed
- I2PControl refactoring & fixes (proper jsonrpc responses on errors)
- boost::regex no more needed
### Fixed
- initscripts: added openrc one, in sysv-ish make I2PD_PORT optional
- properly close NTCP sessions (memleak)
## [2.7.0] - 2016-05-18
### Added

79
Config.cpp

@ -26,83 +26,6 @@ namespace config { @@ -26,83 +26,6 @@ namespace config {
options_description m_OptionsDesc;
variables_map m_Options;
/* list of renamed options */
std::map<std::string, std::string> remapped_options = {
{ "tunnelscfg", "tunconf" },
{ "v6", "ipv6" },
{ "httpaddress", "http.address" },
{ "httpport", "http.port" },
{ "httpproxyaddress", "httpproxy.address" },
{ "httpproxyport", "httpproxy.port" },
{ "socksproxyaddress", "socksproxy.address" },
{ "socksproxyport", "socksproxy.port" },
{ "samaddress", "sam.address" },
{ "samport", "sam.port" },
{ "bobaddress", "bob.address" },
{ "bobport", "bob.port" },
{ "i2pcontroladdress", "i2pcontrol.address" },
{ "i2pcontroladdress", "i2pcontrol.port" },
{ "proxykeys", "httpproxy.keys" },
};
/* list of options, that loose their argument and become simple switch */
std::set<std::string> boolean_options = {
"daemon", "floodfill", "notransit", "service", "ipv6"
};
/* this function is a solid piece of shit, remove it after 2.6.0 */
std::pair<std::string, std::string> old_syntax_parser(const std::string& s) {
std::string name = "";
std::string value = "";
std::size_t pos = 0;
/* shortcuts -- -h */
if (s.length() == 2 && s.at(0) == '-' && s.at(1) != '-')
return make_pair(s.substr(1), "");
/* old-style -- -log, /log, etc */
if (s.at(0) == '/' || (s.at(0) == '-' && s.at(1) != '-')) {
if ((pos = s.find_first_of("= ")) != std::string::npos) {
name = s.substr(1, pos - 1);
value = s.substr(pos + 1);
} else {
name = s.substr(1, pos);
value = "";
}
if (boolean_options.count(name) > 0 && value != "")
std::cerr << "args: don't give an argument to switch option: " << s << std::endl;
if (m_OptionsDesc.find_nothrow(name, false)) {
std::cerr << "args: option " << s << " style is DEPRECATED, use --" << name << " instead" << std::endl;
return std::make_pair(name, value);
}
if (remapped_options.count(name) > 0) {
name = remapped_options[name];
std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl;
return std::make_pair(name, value);
} /* else */
}
/* long options -- --help */
if (s.substr(0, 2) == "--") {
if ((pos = s.find_first_of("= ")) != std::string::npos) {
name = s.substr(2, pos - 2);
value = s.substr(pos + 1);
} else {
name = s.substr(2, pos);
value = "";
}
if (boolean_options.count(name) > 0 && value != "") {
std::cerr << "args: don't give an argument to switch option: " << s << std::endl;
value = "";
}
if (m_OptionsDesc.find_nothrow(name, false))
return std::make_pair(name, value);
if (remapped_options.count(name) > 0) {
name = remapped_options[name];
std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl;
return std::make_pair(name, value);
} /* else */
}
std::cerr << "args: unknown option -- " << s << std::endl;
return std::make_pair("", "");
}
void Init() {
options_description general("General options");
general.add_options()
@ -225,7 +148,7 @@ namespace config { @@ -225,7 +148,7 @@ namespace config {
auto style = boost::program_options::command_line_style::unix_style
| boost::program_options::command_line_style::allow_long_disguise;
style &= ~ boost::program_options::command_line_style::allow_guessing;
store(parse_command_line(argc, argv, m_OptionsDesc, style, old_syntax_parser), m_Options);
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options);
} catch (boost::program_options::error& e) {
std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE);

2
Crypto.h

@ -9,7 +9,9 @@ @@ -9,7 +9,9 @@
#include <openssl/dsa.h>
#include <openssl/sha.h>
#include <openssl/rand.h>
#include "Base.h"
#include "Tag.h"
namespace i2p
{

226
DaemonWin32.cpp

@ -1,113 +1,115 @@ @@ -1,113 +1,115 @@
#include <thread>
#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 <thread>
#include <clocale>
#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

4
Destination.cpp

@ -31,7 +31,7 @@ namespace client @@ -31,7 +31,7 @@ namespace client
{
int len = i2p::util::lexical_cast<int>(it->second, inboundTunnelLen);
if (len > 0)
if (len >= 0)
{
inboundTunnelLen = len;
}
@ -42,7 +42,7 @@ namespace client @@ -42,7 +42,7 @@ namespace client
{
int len = i2p::util::lexical_cast<int>(it->second, outboundTunnelLen);
if (len > 0)
if (len >= 0)
{
outboundTunnelLen = len;
}

37
Garlic.cpp

@ -7,6 +7,7 @@ @@ -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,22 +515,34 @@ namespace garlic @@ -514,22 +515,34 @@ namespace garlic
buf += 32;
uint32_t gwTunnel = bufbe32toh (buf);
buf += 4;
std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel;
if (from && from->GetTunnelPool ())
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
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");
auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from);
if (from) // received through an inbound tunnel
{
std::shared_ptr<i2p::tunnel::OutboundTunnel> 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");
}
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);
}

108
Gzip.cpp

@ -0,0 +1,108 @@ @@ -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 <inttypes.h>
#include <string.h> /* memset */
#include <iostream>
#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<uint8_t *>(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<uint8_t *>(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<uint8_t *>(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

44
Gzip.h

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
#ifndef GZIP_H__
#define GZIP_H__
#include <zlib.h>
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__ */

7
HTTP.cpp

@ -81,7 +81,8 @@ namespace http { @@ -81,7 +81,8 @@ namespace http {
}
/* user[:pass] */
pos_c = url.find('@', pos_p);
if (pos_c != std::string::npos) {
std::size_t pos_slash = url.find('/', pos_p);
if (pos_c != std::string::npos && (pos_slash == std::string::npos || pos_slash > pos_c)) {
std::size_t delim = url.find(':', pos_p);
if (delim != std::string::npos && delim < pos_c) {
user = url.substr(pos_p, delim - pos_p);
@ -90,7 +91,7 @@ namespace http { @@ -90,7 +91,7 @@ namespace http {
} else {
user = url.substr(pos_p, pos_c - pos_p);
}
pos_p = pos_c + 1;
pos_p = pos_c + 1;
}
/* hostname[:port][/path] */
pos_c = url.find_first_of(":/", pos_p);
@ -276,7 +277,7 @@ namespace http { @@ -276,7 +277,7 @@ namespace http {
return false;
}
long int HTTPMsg::length() {
long int HTTPMsg::content_length() {
unsigned long int length = 0;
auto it = headers.find("Content-Length");
if (it == headers.end())

2
HTTP.h

@ -62,7 +62,7 @@ namespace http { @@ -62,7 +62,7 @@ namespace http {
void del_header(const char *name);
/** @brief Returns declared message length or -1 if unknown */
long int length();
long int content_length();
};
struct HTTPReq : HTTPMsg {

159
HTTPProxy.cpp

@ -3,6 +3,13 @@ @@ -3,6 +3,13 @@
#include <boost/lexical_cast.hpp>
#include <string>
#include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h"
#include "util.h"
#include "Identity.h"
@ -14,12 +21,19 @@ @@ -14,12 +21,19 @@
#include "Config.h"
#include "HTTP.h"
namespace i2p
{
namespace proxy
{
namespace i2p {
namespace proxy {
bool str_rmatch(std::string & str, const char *suffix) {
auto pos = str.rfind (suffix);
if (pos == std::string::npos)
return false; /* not found */
if (str.length() == (pos + std::strlen(suffix)))
return true; /* match */
return false;
}
static const size_t http_buffer_size = 8192;
class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPProxyHandler>
class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPReqHandler>
{
private:
enum state
@ -36,10 +50,9 @@ namespace proxy @@ -36,10 +50,9 @@ namespace proxy
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void Terminate();
void AsyncSockRead();
void HTTPRequestFailed(/*std::string message*/);
void RedirectToJumpService();
void HTTPRequestFailed(const char *message);
void RedirectToJumpService(std::string & host);
void ExtractRequest();
bool IsI2PAddress();
bool ValidateHTTPRequest();
void HandleJumpServices();
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
@ -59,26 +72,26 @@ namespace proxy @@ -59,26 +72,26 @@ namespace proxy
public:
HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock)
{ EnterState(GET_METHOD); }
~HTTPProxyHandler() { Terminate(); }
~HTTPReqHandler() { Terminate(); }
void Handle () { AsyncSockRead(); }
};
void HTTPProxyHandler::AsyncSockRead()
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(&HTTPProxyHandler::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 HTTPProxyHandler::Terminate() {
void HTTPReqHandler::Terminate() {
if (Kill()) return;
if (m_sock)
{
@ -91,30 +104,45 @@ namespace proxy @@ -91,30 +104,45 @@ namespace proxy
/* All hope is lost beyond this point */
//TODO: handle this apropriately
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
void HTTPReqHandler::HTTPRequestFailed(const char *message)
{
static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n\r\n";
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
i2p::http::HTTPRes res;
res.code = 500;
res.add_header("Content-Type", "text/plain");
res.add_header("Connection", "close");
res.body = message;
res.body += "\r\n";
std::string response = res.to_string();
boost::asio::async_write(*m_sock, boost::asio::buffer(response),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
}
void HTTPProxyHandler::RedirectToJumpService(/*HTTPProxyHandler::errTypes error*/)
void HTTPReqHandler::RedirectToJumpService(std::string & host)
{
std::stringstream response;
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
i2p::http::HTTPRes res;
i2p::http::URL url;
/* TODO: don't redirect to webconsole, it's not always work, handle jumpservices here */
i2p::config::GetOption("http.address", url.host);
i2p::config::GetOption("http.port", url.port);
url.path = "/";
url.query = "page=jumpservices&address=";
url.query += host;
res.code = 302; /* redirect */
res.add_header("Location", url.to_string().c_str());
response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n";
boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
std::string response = res.to_string();
boost::asio::async_write(*m_sock, boost::asio::buffer(response),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
}
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate)
void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate)
{
m_state = nstate;
}
void HTTPProxyHandler::ExtractRequest()
void HTTPReqHandler::ExtractRequest()
{
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
i2p::http::URL url;
@ -127,18 +155,18 @@ namespace proxy @@ -127,18 +155,18 @@ namespace proxy
LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path);
}
bool HTTPProxyHandler::ValidateHTTPRequest()
bool HTTPReqHandler::ValidateHTTPRequest()
{
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
{
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
HTTPRequestFailed(); //TODO: send right stuff
HTTPRequestFailed("unsupported HTTP version");
return false;
}
return true;
}
void HTTPProxyHandler::HandleJumpServices()
void HTTPReqHandler::HandleJumpServices()
{
static const char * helpermark1 = "?i2paddresshelper=";
static const char * helpermark2 = "&i2paddresshelper=";
@ -170,31 +198,20 @@ namespace proxy @@ -170,31 +198,20 @@ namespace proxy
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 HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
{
ExtractRequest(); //TODO: parse earlier
if (!ValidateHTTPRequest()) return false;
HandleJumpServices();
i2p::data::IdentHash identHash;
if (IsI2PAddress ())
if (str_rmatch(m_address, ".i2p"))
{
if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){
RedirectToJumpService();
RedirectToJumpService(m_address);
return false;
}
}
m_request = m_method;
m_request.push_back(' ');
@ -235,7 +252,7 @@ namespace proxy @@ -235,7 +252,7 @@ namespace proxy
return true;
}
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len)
bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len)
{
while (len > 0)
{
@ -269,13 +286,13 @@ namespace proxy @@ -269,13 +286,13 @@ namespace proxy
case '\n': EnterState(DONE); break;
default:
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
HTTPRequestFailed(); //TODO: add correct code
HTTPRequestFailed("rejected invalid request");
return false;
}
break;
default:
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
HTTPRequestFailed(); //TODO: add correct code 500
HTTPRequestFailed("invalid parser state");
return false;
}
http_buff++;
@ -286,7 +303,7 @@ namespace proxy @@ -286,7 +303,7 @@ namespace proxy
return true;
}
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
{
LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
if(ecode)
@ -301,49 +318,45 @@ namespace proxy @@ -301,49 +318,45 @@ namespace proxy
if (m_state == DONE)
{
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete,
GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_address, m_port);
}
else
AsyncSockRead();
}
}
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode)
void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode)
{
if (ecode)
LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
Terminate();
}
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{
if (Kill()) return;
LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection");
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
GetOwner()->AddHandler (connection);
connection->I2PConnect (reinterpret_cast<const uint8_t*>(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(); // TODO: Send correct error message host unreachable
HTTPRequestFailed("error when creating the stream, check logs");
return;
}
if (Kill())
return;
LogPrint (eLogDebug, "HTTPProxy: New I2PTunnel connection");
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
GetOwner()->AddHandler (connection);
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
Done (shared_from_this());
}
HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{
}
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxy::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
return std::make_shared<HTTPProxyHandler> (this, socket);
return std::make_shared<HTTPReqHandler> (this, socket);
}
}
}
} // http
} // i2p

25
HTTPProxy.h

@ -1,32 +1,21 @@ @@ -1,32 +1,21 @@
#ifndef HTTP_PROXY_H__
#define HTTP_PROXY_H__
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
namespace i2p
{
namespace proxy
{
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
namespace i2p {
namespace proxy {
class HTTPProxy: public i2p::client::TCPIPAcceptor
{
public:
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~HTTPProxyServer() {};
HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~HTTPProxy() {};
protected:
// Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; }
};
typedef HTTPProxyServer HTTPProxy;
}
}
} // http
} // i2p
#endif

18
HTTPServer.cpp

@ -58,6 +58,9 @@ namespace http { @@ -58,6 +58,9 @@ namespace http {
" .tunnel.another { color: #434343; }\r\n"
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
" .private { background: black; color: black; } .private:hover { background: black; color: white } \r\n"
" .slide p, .slide [type='checkbox']{ display:none; } \r\n"
" .slide [type='checkbox']:checked ~ p { display:block; } \r\n"
"</style>\r\n";
const char HTTP_PAGE_TUNNELS[] = "tunnels";
@ -126,8 +129,12 @@ namespace http { @@ -126,8 +129,12 @@ namespace http {
s <<
"<!DOCTYPE html>\r\n"
"<html lang=\"en\">\r\n" /* TODO: Add support for locale */
" <head>\r\n"
" <meta charset=\"UTF-8\">\r\n" /* TODO: Find something to parse html/template system. This is horrible. */
" <head>\r\n" /* TODO: Find something to parse html/template system. This is horrible. */
#if (!defined(WIN32))
" <meta charset=\"UTF-8\">\r\n"
#else
" <meta charset=\"windows-1251\">\r\n"
#endif
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"
<< cssStyles <<
@ -201,6 +208,10 @@ namespace http { @@ -201,6 +208,10 @@ namespace http {
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 << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (auto address : i2p::context.GetRouterInfo().GetAddresses())
{
@ -223,6 +234,7 @@ namespace http { @@ -223,6 +234,7 @@ namespace http {
}
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
}
s << "</p>\r\n</div>\r\n";
s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
@ -612,7 +624,7 @@ namespace http { @@ -612,7 +624,7 @@ namespace http {
HandleCommand (req, res, s);
} else {
ShowStatus (s);
//res.add_header("Refresh", "5");
res.add_header("Refresh", "10");
}
ShowPageTail (s);

14
I2CP.cpp

@ -114,7 +114,7 @@ namespace client @@ -114,7 +114,7 @@ namespace client
}
}
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
m_Owner (owner), m_Socket (socket), m_Payload (nullptr),
m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
{
@ -583,7 +583,12 @@ namespace client @@ -583,7 +583,12 @@ namespace client
I2CPServer::I2CPServer (const std::string& interface, int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port))
m_Acceptor (m_Service,
#ifdef ANDROID
I2CPSession::proto::endpoint(std::string (1, '\0') + interface)) // leading 0 for abstract address
#else
I2CPSession::proto::endpoint(boost::asio::ip::address::from_string(interface), port))
#endif
{
memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers));
m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler;
@ -644,12 +649,13 @@ namespace client @@ -644,12 +649,13 @@ namespace client
void I2CPServer::Accept ()
{
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
auto newSocket = std::make_shared<I2CPSession::proto::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this,
std::placeholders::_1, newSocket));
}
void I2CPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
void I2CPServer::HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<I2CPSession::proto::socket> socket)
{
if (!ecode && socket)
{

16
I2CP.h

@ -99,7 +99,14 @@ namespace client @@ -99,7 +99,14 @@ namespace client
{
public:
I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
#ifdef ANDROID
typedef boost::asio::local::stream_protocol proto;
#else
typedef boost::asio::ip::tcp proto;
#endif
I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket);
~I2CPSession ();
void Start ();
@ -144,7 +151,7 @@ namespace client @@ -144,7 +151,7 @@ namespace client
private:
I2CPServer& m_Owner;
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
std::shared_ptr<proto::socket> m_Socket;
uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload;
size_t m_PayloadLen;
@ -173,7 +180,8 @@ namespace client @@ -173,7 +180,8 @@ namespace client
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<I2CPSession::proto::socket> socket);
private:
@ -183,7 +191,7 @@ namespace client @@ -183,7 +191,7 @@ namespace client
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
I2CPSession::proto::acceptor m_Acceptor;
public:

2
I2PControl.cpp

@ -205,7 +205,7 @@ namespace client @@ -205,7 +205,7 @@ namespace client
}
/* append to json chunk of data from 1st request */
json.write(buf->begin() + len, bytes_transferred - len);
remains = req.length() - len;
remains = req.content_length() - len;
/* if request has Content-Length header, fetch rest of data and store to json buffer */
while (remains > 0) {
len = ((long int) buf->size() < remains) ? buf->size() : remains;

1
Makefile

@ -11,6 +11,7 @@ include filelist.mk @@ -11,6 +11,7 @@ include filelist.mk
USE_AESNI := yes
USE_STATIC := no
USE_UPNP := no
ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp

2
Makefile.homebrew

@ -8,7 +8,7 @@ INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include @@ -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

8
Makefile.linux

@ -33,18 +33,18 @@ ifeq ($(USE_STATIC),yes) @@ -33,18 +33,18 @@ ifeq ($(USE_STATIC),yes)
LDLIBS += $(LIBDIR)/libboost_date_time.a
LDLIBS += $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_program_options.a
LDLIBS += $(LIBDIR)/libcrypto.a
LDLIBS += $(LIBDIR)/libssl.a
LDLIBS += $(LIBDIR)/libcrypto.a
LDLIBS += $(LIBDIR)/libz.a
LDLIBS += -lpthread -static-libstdc++ -static-libgcc
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt
USE_AESNI := no
else
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif
# UPNP Support (miniupnpc 1.5 or 1.6)
ifeq ($(USE_UPNP),1)
LDFLAGS += -ldl
ifeq ($(USE_UPNP),yes)
LDFLAGS += -lminiupnpc
CXXFLAGS += -DUSE_UPNP
endif

94
Makefile.mingw

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

2
Makefile.osx vendored

@ -5,7 +5,7 @@ INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include @@ -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

6
NTCPSession.cpp

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
#include <string.h>
#include <stdlib.h>
#include <zlib.h>
#include "I2PEndian.h"
#include "Base.h"
#include "Crypto.h"
@ -430,7 +430,7 @@ namespace transport @@ -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 @@ -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 ();

21
NetDb.cpp

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
#include <fstream>
#include <vector>
#include <boost/asio.hpp>
#include <zlib.h>
#include "I2PEndian.h"
#include "Base.h"
#include "Crypto.h"
@ -450,6 +450,12 @@ namespace data @@ -450,6 +450,12 @@ namespace data
}
offset += 32;
}
// we must send reply back before this check
if (ident == i2p::context.GetIdentHash ())
{
LogPrint (eLogError, "NetDb: database store with own RouterInfo received, dropped");
return;
}
size_t payloadOffset = offset;
bool updated = false;
@ -488,11 +494,16 @@ namespace data @@ -488,11 +494,16 @@ namespace data
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
std::set<IdentHash> excluded;
for (int i = 0; i < 3; i++)
excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
excluded.insert (ident); // don't flood back
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill)
transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
{
transports.SendMessage (floodfill->GetIdentHash (), CopyI2NPMessage(floodMsg));
excluded.insert (floodfill->GetIdentHash ());
}
else
break;
}
@ -610,7 +621,7 @@ namespace data @@ -610,7 +621,7 @@ namespace data
uint32_t replyTunnelID = 0;
if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel
{
replyTunnelID = bufbe32toh (buf + 64);
replyTunnelID = bufbe32toh (buf + 65);
excluded += 4;
}
uint16_t numExcluded = bufbe16toh (excluded);
@ -671,7 +682,7 @@ namespace data @@ -671,7 +682,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<IdentHash> closestFloodfills;
bool found = false;

2
NetDb.h

@ -8,7 +8,9 @@ @@ -8,7 +8,9 @@
#include <string>
#include <thread>
#include <mutex>
#include "Base.h"
#include "Gzip.h"
#include "FS.h"
#include "Queue.h"
#include "I2NPProtocol.h"

8
SSU.cpp

@ -231,7 +231,7 @@ namespace transport @@ -231,7 +231,7 @@ namespace transport
session = std::make_shared<SSUSession> (*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);
@ -312,7 +312,7 @@ namespace transport @@ -312,7 +312,7 @@ namespace transport
auto session = std::make_shared<SSUSession> (*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 ();
}
@ -364,10 +364,10 @@ namespace transport @@ -364,10 +364,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<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession;

12
SSUData.cpp

@ -241,7 +241,7 @@ namespace transport @@ -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");
@ -425,6 +425,7 @@ namespace transport @@ -425,6 +425,7 @@ namespace transport
if (ecode != boost::asio::error::operation_aborted)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
int numResent = 0;
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
{
if (ts >= it->second->nextResendTime)
@ -437,6 +438,7 @@ namespace transport @@ -437,6 +438,7 @@ namespace transport
try
{
m_Session.Send (f->buf, f->len); // resend
numResent++;
}
catch (boost::system::system_error& ec)
{
@ -457,7 +459,13 @@ namespace transport @@ -457,7 +459,13 @@ namespace transport
else
it++;
}
ScheduleResend ();
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
ScheduleResend ();
else
{
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
m_Session.Close ();
}
}
}

1
SSUData.h

@ -29,6 +29,7 @@ namespace transport @@ -29,6 +29,7 @@ namespace transport
const int DECAY_INTERVAL = 20; // in seconds
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
const int MAX_OUTGOING_WINDOW_SIZE = 200; // how many unacked message we can store
// data flags
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;

4
SSUSession.cpp

@ -814,7 +814,7 @@ namespace transport @@ -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 @@ -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 ();
}
}

45
Streaming.cpp

@ -87,7 +87,7 @@ namespace stream @@ -87,7 +87,7 @@ namespace stream
return;
}
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn);
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn, " on sSID=", m_SendStreamID);
if (receivedSeqn == m_LastReceivedSequenceNumber + 1)
{
// we have received next in sequence message
@ -129,13 +129,13 @@ namespace stream @@ -129,13 +129,13 @@ namespace stream
if (receivedSeqn <= m_LastReceivedSequenceNumber)
{
// we have received duplicate
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " received");
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " on sSID=", m_SendStreamID);
SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped
}
else
{
LogPrint (eLogWarning, "Streaming: Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
LogPrint (eLogWarning, "Streaming: Missing messages on sSID=", m_SendStreamID, ": from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
// save message and wait for missing message again
SavePacket (packet);
if (m_LastReceivedSequenceNumber >= 0)
@ -183,7 +183,7 @@ namespace stream @@ -183,7 +183,7 @@ namespace stream
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ());
optionData += m_RemoteIdentity->GetFullLen ();
if (!m_RemoteLeaseSet)
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
}
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
@ -263,7 +263,7 @@ namespace stream @@ -263,7 +263,7 @@ namespace stream
uint64_t rtt = ts - sentPacket->sendTime;
m_RTT = (m_RTT*seqn + rtt)/(seqn + 1);
m_RTO = m_RTT*1.5; // TODO: implement it better
LogPrint (eLogDebug, "Packet ", seqn, " acknowledged rtt=", rtt);
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " acknowledged rtt=", rtt);
m_SentPackets.erase (it++);
delete sentPacket;
acknowledged = true;
@ -395,8 +395,11 @@ namespace stream @@ -395,8 +395,11 @@ namespace stream
}
if (packets.size () > 0)
{
m_IsAckSendScheduled = false;
m_AckSendTimer.cancel ();
if (m_SavedPackets.empty ()) // no NACKS
{
m_IsAckSendScheduled = false;
m_AckSendTimer.cancel ();
}
bool isEmpty = m_SentPackets.empty ();
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: packets)
@ -448,7 +451,7 @@ namespace stream @@ -448,7 +451,7 @@ namespace stream
auto seqn = it->GetSeqn ();
if (numNacks + (seqn - nextSeqn) >= 256)
{
LogPrint (eLogError, "Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn);
LogPrint (eLogError, "Streaming: Number of NACKs exceeds 256. seqn=", seqn, " nextSeqn=", nextSeqn);
htobe32buf (packet + 12, nextSeqn); // change ack Through
break;
}
@ -489,7 +492,7 @@ namespace stream @@ -489,7 +492,7 @@ namespace stream
m_Status = eStreamStatusClosing;
Close (); // recursion
if (m_Status == eStreamStatusClosing) //still closing
LogPrint (eLogInfo, "Streaming: Trying to send stream data before closing");
LogPrint (eLogDebug, "Streaming: Trying to send stream data before closing, sSID=", m_SendStreamID);
break;
case eStreamStatusReset:
SendClose ();
@ -511,7 +514,7 @@ namespace stream @@ -511,7 +514,7 @@ namespace stream
m_LocalDestination.DeleteStream (shared_from_this ());
break;
default:
LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status);
LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status, "sSID=", m_SendStreamID);
};
}
@ -543,7 +546,7 @@ namespace stream @@ -543,7 +546,7 @@ namespace stream
p->len = size;
m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p));
LogPrint (eLogDebug, "Streaming: FIN sent");
LogPrint (eLogDebug, "Streaming: FIN sent, sSID=", m_SendStreamID);
}
size_t Stream::ConcatenatePackets (uint8_t * buf, size_t len)
@ -597,7 +600,7 @@ namespace stream @@ -597,7 +600,7 @@ namespace stream
UpdateCurrentRemoteLease ();
if (!m_RemoteLeaseSet)
{
LogPrint (eLogError, "Streaming: Can't send packets, missing remote LeaseSet");
LogPrint (eLogError, "Streaming: Can't send packets, missing remote LeaseSet, sSID=", m_SendStreamID);
return;
}
}
@ -622,7 +625,7 @@ namespace stream @@ -622,7 +625,7 @@ namespace stream
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel)
{
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool");
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool, sSID=", m_SendStreamID);
return;
}
@ -646,7 +649,7 @@ namespace stream @@ -646,7 +649,7 @@ namespace stream
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
}
else
LogPrint (eLogWarning, "Streaming: All leases are expired");
LogPrint (eLogWarning, "Streaming: All leases are expired, sSID=", m_SendStreamID);
}
@ -665,7 +668,7 @@ namespace stream @@ -665,7 +668,7 @@ namespace stream
// check for resend attempts
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
{
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate");
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate, sSID=", m_SendStreamID);
m_Status = eStreamStatusReset;
Close ();
return;
@ -700,13 +703,13 @@ namespace stream @@ -700,13 +703,13 @@ namespace stream
case 4:
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
UpdateCurrentRemoteLease (); // pick another lease
LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream");
LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream with sSID=", m_SendStreamID);
break;
case 3:
// pick another outbound tunnel
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream");
LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream with sSID=", m_SendStreamID);
break;
default: ;
}
@ -722,7 +725,7 @@ namespace stream @@ -722,7 +725,7 @@ namespace stream
{
if (m_LastReceivedSequenceNumber < 0)
{
LogPrint (eLogWarning, "Streaming: SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on, terminate");
LogPrint (eLogWarning, "Streaming: SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on, terminate sSID=", m_SendStreamID);
m_Status = eStreamStatusReset;
Close ();
return;
@ -825,7 +828,7 @@ namespace stream @@ -825,7 +828,7 @@ namespace stream
it->second->HandleNextPacket (packet);
else
{
LogPrint (eLogError, "Streaming: Unknown stream sendStreamID=", sendStreamID);
LogPrint (eLogError, "Streaming: Unknown stream sSID=", sendStreamID);
delete packet;
}
}
@ -841,7 +844,7 @@ namespace stream @@ -841,7 +844,7 @@ namespace stream
auto it = m_SavedPackets.find (receiveStreamID);
if (it != m_SavedPackets.end ())
{
LogPrint (eLogDebug, "Streaming: Processing ", it->second.size (), " saved packets for receiveStreamID=", receiveStreamID);
LogPrint (eLogDebug, "Streaming: Processing ", it->second.size (), " saved packets for rSID=", receiveStreamID);
for (auto it1: it->second)
incomingStream->HandleNextPacket (it1);
m_SavedPackets.erase (it);
@ -860,7 +863,7 @@ namespace stream @@ -860,7 +863,7 @@ namespace stream
m_PendingIncomingTimer.expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
m_PendingIncomingTimer.async_wait (std::bind (&StreamingDestination::HandlePendingIncomingTimer,
shared_from_this (), std::placeholders::_1));
LogPrint (eLogDebug, "Streaming: Pending incoming stream added");
LogPrint (eLogDebug, "Streaming: Pending incoming stream added, rSID=", receiveStreamID);
}
else
{

90
Tag.h

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
/*
* 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 TAG_H__
#define TAG_H__
#include <string.h> /* memcpy */
#include "Base.h"
namespace i2p {
namespace data {
template<int sz>
class Tag
{
public:
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); };
Tag (const Tag<sz>& ) = default;
#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it
Tag (Tag<sz>&& ) = default;
#endif
Tag () = default;
Tag<sz>& operator= (const Tag<sz>& ) = default;
#ifndef _WIN32
Tag<sz>& operator= (Tag<sz>&& ) = 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<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
bool operator< (const Tag<sz>& 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__ */

4
TransitTunnel.cpp

@ -92,7 +92,7 @@ namespace tunnel @@ -92,7 +92,7 @@ namespace tunnel
{
if (isEndpoint)
{
LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created");
LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else if (isGateway)
@ -102,7 +102,7 @@ namespace tunnel @@ -102,7 +102,7 @@ namespace tunnel
}
else
{
LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
}

29
Tunnel.cpp

@ -217,6 +217,7 @@ namespace tunnel @@ -217,6 +217,7 @@ namespace tunnel
if (msg)
{
m_NumReceivedBytes += msg->GetLength ();
msg->from = shared_from_this ();
HandleI2NPMessage (msg);
}
}
@ -768,6 +769,22 @@ namespace tunnel @@ -768,6 +769,22 @@ namespace tunnel
return newTunnel;
}
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{
if (config)
return CreateTunnel<InboundTunnel>(config, outboundTunnel);
else
return CreateZeroHopsInboundTunnel ();
}
std::shared_ptr<OutboundTunnel> Tunnels::CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config)
{
if (config)
return CreateTunnel<OutboundTunnel>(config);
else
return CreateZeroHopsOutboundTunnel ();
}
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel)
{
m_PendingInboundTunnels[replyMsgID] = tunnel;
@ -815,20 +832,22 @@ namespace tunnel @@ -815,20 +832,22 @@ namespace tunnel
}
void Tunnels::CreateZeroHopsInboundTunnel ()
std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel ()
{
auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> ();
inboundTunnel->SetState (eTunnelStateEstablished);
m_InboundTunnels.push_back (inboundTunnel);
m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel;
return inboundTunnel;
}
void Tunnels::CreateZeroHopsOutboundTunnel ()
std::shared_ptr<ZeroHopsOutboundTunnel> Tunnels::CreateZeroHopsOutboundTunnel ()
{
auto outboundTunnel = std::make_shared<ZeroHopsOutboundTunnel> ();
outboundTunnel->SetState (eTunnelStateEstablished);
m_OutboundTunnels.push_back (outboundTunnel);
// we don't insert into m_Tunnels
return outboundTunnel;
}
int Tunnels::GetTransitTunnelsExpirationTimeout ()
@ -861,12 +880,6 @@ namespace tunnel @@ -861,12 +880,6 @@ namespace tunnel
// TODO: locking
return m_OutboundTunnels.size();
}
#ifdef ANDROID_ARM7A
template std::shared_ptr<InboundTunnel> Tunnels::CreateTunnel<InboundTunnel>(std::shared_ptr<TunnelConfig>, std::shared_ptr<OutboundTunnel>);
template std::shared_ptr<OutboundTunnel> Tunnels::CreateTunnel<OutboundTunnel>(std::shared_ptr<TunnelConfig>, std::shared_ptr<OutboundTunnel>);
#endif
}
}

11
Tunnel.h

@ -176,10 +176,10 @@ namespace tunnel @@ -176,10 +176,10 @@ namespace tunnel
void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
std::shared_ptr<InboundTunnel> CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel);
std::shared_ptr<OutboundTunnel> CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config);
void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
@ -189,6 +189,9 @@ namespace tunnel @@ -189,6 +189,9 @@ namespace tunnel
private:
template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
@ -204,8 +207,8 @@ namespace tunnel @@ -204,8 +207,8 @@ namespace tunnel
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
void ManageTunnelPools ();
void CreateZeroHopsInboundTunnel ();
void CreateZeroHopsOutboundTunnel ();
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
private:

5
TunnelConfig.h

@ -159,6 +159,11 @@ namespace tunnel @@ -159,6 +159,11 @@ namespace tunnel
return num;
}
bool IsEmpty () const
{
return !m_FirstHop;
}
virtual bool IsInbound () const { return m_FirstHop->isGateway; }
virtual uint32_t GetTunnelID () const

39
TunnelPool.cpp

@ -329,8 +329,9 @@ namespace tunnel @@ -329,8 +329,9 @@ namespace tunnel
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers, bool isInbound)
{
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);
auto prevHop = i2p::context.GetSharedRouterInfo ();
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
if (numHops <= 0) return true; // peers is empty
auto prevHop = i2p::context.GetSharedRouterInfo ();
if (i2p::transport::transports.GetNumPeers () > 25)
{
auto r = i2p::transport::transports.GetRandomPeer ();
@ -389,9 +390,16 @@ namespace tunnel @@ -389,9 +390,16 @@ namespace tunnel
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, true))
{
std::reverse (peers.begin (), peers.end ());
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig> (peers), outboundTunnel);
std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0)
{
std::reverse (peers.begin (), peers.end ());
config = std::make_shared<TunnelConfig> (peers);
}
auto tunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
tunnel->SetTunnelPool (shared_from_this ());
if (tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel);
}
else
LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available");
@ -403,8 +411,12 @@ namespace tunnel @@ -403,8 +411,12 @@ namespace tunnel
if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel...");
auto newTunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(tunnel->GetPeers ()), outboundTunnel);
std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0) config = std::make_shared<TunnelConfig>(tunnel->GetPeers ());
auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
newTunnel->SetTunnelPool (shared_from_this());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
}
void TunnelPool::CreateOutboundTunnel ()
@ -418,9 +430,13 @@ namespace tunnel @@ -418,9 +430,13 @@ namespace tunnel
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, false))
{
auto tunnel = tunnels.CreateTunnel<OutboundTunnel> (
std::make_shared<TunnelConfig> (peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()));
std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0)
config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto tunnel = tunnels.CreateOutboundTunnel (config);
tunnel->SetTunnelPool (shared_from_this ());
if (tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel);
}
else
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available");
@ -437,10 +453,13 @@ namespace tunnel @@ -437,10 +453,13 @@ namespace tunnel
if (inboundTunnel)
{
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
auto newTunnel = tunnels.CreateTunnel<OutboundTunnel> (
std::make_shared<TunnelConfig> (tunnel->GetPeers (),
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()));
std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0)
config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto newTunnel = tunnels.CreateOutboundTunnel (config);
newTunnel->SetTunnelPool (shared_from_this ());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
}
else
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");
@ -449,7 +468,7 @@ namespace tunnel @@ -449,7 +468,7 @@ namespace tunnel
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
{
LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel...");
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers ()), outboundTunnel);
auto tunnel = tunnels.CreateInboundTunnel (std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers ()), outboundTunnel);
tunnel->SetTunnelPool (shared_from_this ());
}
}

78
UPnP.cpp

@ -6,13 +6,6 @@ @@ -6,13 +6,6 @@
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#ifdef _WIN32
#include <windows.h>
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#endif
#include "Log.h"
#include "RouterContext.h"
@ -24,32 +17,11 @@ @@ -24,32 +17,11 @@
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
// These are per-process and are safe to reuse for all threads
decltype(upnpDiscover) *upnpDiscoverFunc;
decltype(UPNP_AddPortMapping) *UPNP_AddPortMappingFunc;
decltype(UPNP_GetValidIGD) *UPNP_GetValidIGDFunc;
decltype(UPNP_GetExternalIPAddress) *UPNP_GetExternalIPAddressFunc;
decltype(UPNP_DeletePortMapping) *UPNP_DeletePortMappingFunc;
decltype(freeUPNPDevlist) *freeUPNPDevlistFunc;
decltype(FreeUPNPUrls) *FreeUPNPUrlsFunc;
// Nice approach http://stackoverflow.com/a/21517513/673826
template<class M, typename F>
F GetKnownProcAddressImpl(M hmod, const char *name, F) {
auto proc = reinterpret_cast<F>(dlsym(hmod, name));
if (!proc) {
LogPrint(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?");
}
return proc;
}
#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func);
namespace i2p
{
namespace transport
{
UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false)
UPnP::UPnP () : m_Thread (nullptr)
{
}
@ -65,33 +37,6 @@ namespace transport @@ -65,33 +37,6 @@ namespace transport
void UPnP::Start()
{
if (!m_IsModuleLoaded) {
#ifdef MAC_OSX
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
m_Module = LoadLibrary ("libminiupnpc.dll"); // from MSYS2
#else
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
#endif
if (m_Module == NULL)
{
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
return;
}
else
{
upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover);
UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD);
UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress);
UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping);
UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping);
freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist);
FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls);
if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc &&
UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc)
m_IsModuleLoaded = true;
}
}
m_Thread = new std::thread (std::bind (&UPnP::Run, this));
}
@ -123,16 +68,16 @@ namespace transport @@ -123,16 +68,16 @@ namespace transport
{
int nerror = 0;
#if MINIUPNPC_API_VERSION >= 14
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#else
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#endif
int r;
r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
if (r == 1)
{
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS)
{
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
@ -171,7 +116,7 @@ namespace transport @@ -171,7 +116,7 @@ namespace transport
std::string strDesc = "I2Pd";
try {
for (;;) {
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
if (r!=UPNPCOMMAND_SUCCESS)
{
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
@ -208,20 +153,15 @@ namespace transport @@ -208,20 +153,15 @@ namespace transport
strType = "UDP";
}
int r = 0;
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
}
void UPnP::Close ()
{
freeUPNPDevlistFunc (m_Devlist);
freeUPNPDevlist (m_Devlist);
m_Devlist = 0;
FreeUPNPUrlsFunc (&m_upnpUrls);
#ifndef _WIN32
dlclose (m_Module);
#else
FreeLibrary (m_Module);
#endif
FreeUPNPUrls (&m_upnpUrls);
}
}

6
UPnP.h

@ -48,12 +48,6 @@ namespace transport @@ -48,12 +48,6 @@ namespace transport
struct UPNPDev * m_Devlist = 0;
char m_NetworkAddr[64];
char m_externalIPAddress[40];
bool m_IsModuleLoaded;
#ifndef _WIN32
void *m_Module;
#else
HINSTANCE m_Module;
#endif
};
}
}

5
build/CMakeLists.txt

@ -21,6 +21,7 @@ set (LIBI2PD_SRC @@ -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"
@ -338,6 +339,10 @@ if (WITH_BINARY) @@ -338,6 +339,10 @@ if (WITH_BINARY)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" )
endif ()
if (WITH_UPNP)
target_link_libraries("${PROJECT_NAME}" "miniupnpc")
endif ()
# FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")

1
debian/control vendored

@ -8,6 +8,7 @@ Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~), @@ -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

7
debian/patches/0001-disable-aesni-by-default.patch → debian/patches/01-tune-build-opts.patch vendored

@ -1,13 +1,16 @@ @@ -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

2
debian/patches/series vendored

@ -1 +1 @@ @@ -1 +1 @@
0001-disable-aesni-by-default.patch
01-tune-build-opts.patch

2
docs/build_notes_windows.md

@ -172,8 +172,6 @@ pacman -S mingw-w64-i686-miniupnpc @@ -172,8 +172,6 @@ pacman -S mingw-w64-i686-miniupnpc
make USE_UPNP=1
```
It requires libminiupnpc.dll from /mingw32/bin
### Creating Visual Studio project
Start CMake GUI, navigate to i2pd directory, choose building directory, e.g. ./out, and configure options.

8
docs/configuration.md

@ -41,7 +41,7 @@ All options below still possible in cmdline, but better write it in config file: @@ -41,7 +41,7 @@ All options below still possible in cmdline, but better write it in config file:
* --http.pass= - Password for basic auth (default: random, see logs)
* --httpproxy.address= - The address to listen on (HTTP Proxy)
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default
* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --httpproxy.enabled= - If HTTP proxy is enabled. true by default
@ -60,9 +60,9 @@ All options below still possible in cmdline, but better write it in config file: @@ -60,9 +60,9 @@ All options below still possible in cmdline, but better write it in config file:
* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --bob.enabled= - If BOB is enabled. false by default
* --i2cp.address= - The address to listen on
* --i2cp.port= - Port of I2CP server. Usually 7654. IPCP is off if not specified
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't requeire I2CP
* --i2cp.address= - The address to listen on or an abstract address for Android LocalSocket
* --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP
* --i2pcontrol.address= - The address to listen on (I2P control service)
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified

2
filelist.mk

@ -1,5 +1,5 @@ @@ -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 \

1
qt/i2pd_qt/.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
i2pd_qt.pro.user*

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="1" android:installLocation="auto">
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" -->

5
qt/i2pd_qt/i2pd.qrc

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>images/icon.png</file>
</qresource>
</RCC>

260
qt/i2pd_qt/i2pd_qt.pro

@ -1,192 +1,128 @@ @@ -1,192 +1,128 @@
#-------------------------------------------------
#
# Project created by QtCreator 2016-06-14T04:53:04
#
#-------------------------------------------------
QT += core gui
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = i2pd_qt
TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11
DEFINES += USE_UPNP
# change to your own path, where you will store all needed libraries with 'git clone' commands below.
MAIN_PATH = /path/to/libraries
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
# change to your own
BOOST_PATH = /mnt/media/android/Boost-for-Android-Prebuilt
OPENSSL_PATH = /mnt/media/android/OpenSSL-for-Android-Prebuilt
IFADDRS_PATH = /mnt/media/android/android-ifaddrs
BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt
OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt
MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt
IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs
# Steps in Android SDK manager:
# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html
# 2) Check API 11
# Finally, click Install.
SOURCES += DaemonQT.cpp\
mainwindow.cpp \
../../HTTPServer.cpp ../../I2PControl.cpp ../../UPnP.cpp ../../Daemon.cpp ../../Config.cpp \
../../AddressBook.cpp \
../../api.cpp \
../../Base.cpp \
../../BOB.cpp \
../../ClientContext.cpp \
../../Crypto.cpp \
../../Datagram.cpp \
../../Destination.cpp \
../../Family.cpp \
../../FS.cpp \
../../Garlic.cpp \
../../HTTP.cpp \
../../HTTPProxy.cpp \
../../I2CP.cpp \
../../I2NPProtocol.cpp \
../../I2PEndian.cpp \
../../I2PService.cpp \
../../I2PTunnel.cpp \
../../Identity.cpp \
../../LeaseSet.cpp \
../../Log.cpp \
../../NetDb.cpp \
../../NetDbRequests.cpp \
../../NTCPSession.cpp \
../../Profiling.cpp \
../../Reseed.cpp \
../../RouterContext.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 \
../../util.cpp \
../../i2pd.cpp \
$$IFADDRS_PATH/ifaddrs.c
SOURCES += DaemonQT.cpp mainwindow.cpp \
../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \
../../AddressBook.cpp ../../api.cpp ../../Base.cpp ../../BOB.cpp ../../ClientContext.cpp \
../../Crypto.cpp ../../Datagram.cpp ../../Destination.cpp ../../Family.cpp ../../FS.cpp \
../../Garlic.cpp ../../HTTP.cpp ../../HTTPProxy.cpp ../../I2CP.cpp ../../I2NPProtocol.cpp \
../../I2PEndian.cpp ../../I2PService.cpp ../../I2PTunnel.cpp ../../Identity.cpp \
../../LeaseSet.cpp ../../Log.cpp ../../NetDb.cpp ../../NetDbRequests.cpp \
../../NTCPSession.cpp ../../Profiling.cpp ../../Reseed.cpp ../../RouterContext.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 ../../Gzip.cpp ../../i2pd.cpp
HEADERS += DaemonQT.h mainwindow.h \
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
../../AddressBook.h \
../../api.h \
../../Base.h \
../../BOB.h \
../../ClientContext.h \
../../Crypto.h \
../../Datagram.h \
../../Destination.h \
../../Family.h \
../../FS.h \
../../Garlic.h \
../../HTTP.h \
../../HTTPProxy.h \
../../I2CP.h \
../../I2NPProtocol.h \
../../I2PEndian.h \
../../I2PService.h \
../../I2PTunnel.h \
../../Identity.h \
../../LeaseSet.h \
../../LittleBigEndian.h \
../../Log.h \
../../NetDb.h \
../../NetDbRequests.h \
../../NTCPSession.h \
../../Profiling.h \
../../Queue.h \
../../Reseed.h \
../../RouterContext.h \
../../RouterInfo.h \
../../SAM.h \
../../Signature.h \
../../SOCKS.h \
../../SSU.h \
../../SSUData.h \
../../SSUSession.h \
../../Streaming.h \
../../Timestamp.h \
../../TransitTunnel.h \
../../Transports.h \
../../TransportSession.h \
../../Tunnel.h \
../../TunnelBase.h \
../../TunnelConfig.h \
../../TunnelEndpoint.h \
../../TunnelGateway.h \
../../TunnelPool.h \
../../util.h \
../../version.h \
$$IFADDRS_PATH/ifaddrs.h
FORMS += mainwindow.ui
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
../../AddressBook.h ../../api.h ../../Base.h ../../BOB.h ../../ClientContext.h \
../../Crypto.h ../../Datagram.h ../../Destination.h ../../Family.h ../../FS.h \
../../Garlic.h ../../HTTP.h ../../HTTPProxy.h ../../I2CP.h ../../I2NPProtocol.h \
../../I2PEndian.h ../../I2PService.h ../../I2PTunnel.h ../../Identity.h ../../LeaseSet.h \
../../LittleBigEndian.h ../../Log.h ../../NetDb.h ../../NetDbRequests.h ../../NTCPSession.h \
../../Profiling.h ../../Queue.h ../../Reseed.h ../../RouterContext.h ../../RouterInfo.h \
../../SAM.h ../../Signature.h ../../SOCKS.h ../../SSU.h ../../SSUData.h ../../SSUSession.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 ..//../Gzip.h ../../Tag.h
FORMS += mainwindow.ui
CONFIG += mobility
MOBILITY =
MOBILITY =
LIBS += -lz
android {
message("Using Android settings")
DEFINES += ANDROID=1
DEFINES += __ANDROID__
INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$OPENSSL_PATH/openssl-1.0.2/include \
$$IFADDRS_PATH
DISTFILES += \
android/AndroidManifest.xml
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
equals(ANDROID_TARGET_ARCH, armeabi-v7a){
DEFINES += ANDROID_ARM7A
# http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
-lboost_system-gcc-mt-1_53 \
-lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \
-lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so
}
equals(ANDROID_TARGET_ARCH, x86){
# http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
-lboost_system-gcc-mt-1_53 \
-lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \
-lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so
}
message("Using Android settings")
DEFINES += ANDROID=1
DEFINES += __ANDROID__
INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$OPENSSL_PATH/openssl-1.0.2/include \
$$MINIUPNP_PATH/miniupnp-2.0/include \
$$IFADDRS_PATH
DISTFILES += android/AndroidManifest.xml
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
SOURCES += $$IFADDRS_PATH/ifaddrs.c
HEADERS += $$IFADDRS_PATH/ifaddrs.h
equals(ANDROID_TARGET_ARCH, armeabi-v7a){
DEFINES += ANDROID_ARM7A
# http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
-lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \
-L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \
$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so
}
equals(ANDROID_TARGET_ARCH, x86){
# http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
-lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \
-L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \
$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so
}
}
linux:!android {
message("Using Linux settings")
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
message("Using Linux settings")
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc
}
!android:!symbian:!maemo5:!simulator {
message("Build with a system tray icon")
# see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince*
#sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images
RESOURCES = i2pd.qrc
QT += xml
#INSTALLS += sources
}

BIN
qt/i2pd_qt/images/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

121
qt/i2pd_qt/mainwindow.cpp

@ -1,10 +1,19 @@ @@ -1,10 +1,19 @@
#include "mainwindow.h"
//#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QTimer>
#include "../../RouterContext.h"
#ifndef ANDROID
#include <QtDebug>
#endif
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)/*,
ui(new Ui::MainWindow)*/
#ifndef ANDROID
,
quitting(false)
#endif
{
//ui->setupUi(this);
if (objectName().isEmpty())
@ -22,27 +31,129 @@ MainWindow::MainWindow(QWidget *parent) : @@ -22,27 +31,129 @@ MainWindow::MainWindow(QWidget *parent) :
verticalLayout1->setContentsMargins(0, 0, 0, 0);
quitButton = new QPushButton(verticalLayoutWidget);
quitButton->setObjectName(QStringLiteral("quitButton"));
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy.setHorizontalStretch(1);
//sizePolicy.setVerticalStretch(1);
sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth());
quitButton->setSizePolicy(sizePolicy);
verticalLayout1->addWidget(quitButton);
gracefulQuitButton = new QPushButton(verticalLayoutWidget);
gracefulQuitButton->setObjectName(QStringLiteral("gracefulQuitButton"));
QSizePolicy sizePolicy2(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy2.setHorizontalStretch(1);
//sizePolicy2.setVerticalStretch(1);
sizePolicy2.setHeightForWidth(gracefulQuitButton->sizePolicy().hasHeightForWidth());
gracefulQuitButton->setSizePolicy(sizePolicy2);
verticalLayout1->addWidget(gracefulQuitButton);
setCentralWidget(centralWidget);
setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0));
setWindowTitle(QApplication::translate("MainWindow", "i2pd", 0));
quitButton->setText(QApplication::translate("MainWindow", "Quit", 0));
gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful Quit", 0));
#ifndef ANDROID
createActions();
createTrayIcon();
#endif
QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton()));
QObject::connect(gracefulQuitButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton()));
#ifndef ANDROID
QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
setIcon();
trayIcon->show();
#endif
//QMetaObject::connectSlotsByName(this);
}
#ifndef ANDROID
void MainWindow::createActions() {
toggleWindowVisibleAction = new QAction(tr("&Toggle the window"), this);
connect(toggleWindowVisibleAction, SIGNAL(triggered()), this, SLOT(toggleVisibilitySlot()));
//quitAction = new QAction(tr("&Quit"), this);
//connect(quitAction, SIGNAL(triggered()), QApplication::instance(), SLOT(quit()));
}
void MainWindow::toggleVisibilitySlot() {
setVisible(!isVisible());
}
void MainWindow::createTrayIcon() {
trayIconMenu = new QMenu(this);
trayIconMenu->addAction(toggleWindowVisibleAction);
//trayIconMenu->addSeparator();
//trayIconMenu->addAction(quitAction);
trayIcon = new QSystemTrayIcon(this);
trayIcon->setContextMenu(trayIconMenu);
}
void MainWindow::setIcon() {
QIcon icon(":/images/icon.png");
trayIcon->setIcon(icon);
setWindowIcon(icon);
trayIcon->setToolTip(QApplication::translate("MainWindow", "i2pd", 0));
}
void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) {
switch (reason) {
case QSystemTrayIcon::Trigger:
case QSystemTrayIcon::DoubleClick:
case QSystemTrayIcon::MiddleClick:
setVisible(!isVisible());
break;
default:
qDebug() << "MainWindow::iconActivated(): unknown reason: " << reason << endl;
break;
}
}
void MainWindow::closeEvent(QCloseEvent *event) {
if(quitting){ QMainWindow::closeEvent(event); return; }
if (trayIcon->isVisible()) {
QMessageBox::information(this, tr("i2pd"),
tr("The program will keep running in the "
"system tray. To gracefully terminate the program, "
"choose <b>Graceful Quit</b> at the main i2pd window."));
hide();
event->ignore();
}
}
#endif
void MainWindow::handleQuitButton() {
qDebug("Quit pressed. Hiding the main window");
#ifndef ANDROID
quitting=true;
#endif
close();
QApplication::instance()->quit();
}
void MainWindow::handleGracefulQuitButton() {
qDebug("Graceful Quit pressed.");
gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0));
gracefulQuitButton->setEnabled(false);
gracefulQuitButton->adjustSize();
verticalLayoutWidget->adjustSize();
i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels
QTimer::singleShot(10*60*1000/*millis*/, this, SLOT(handleGracefulQuitTimerEvent()));
}
void MainWindow::handleGracefulQuitTimerEvent() {
qDebug("Hiding the main window");
#ifndef ANDROID
quitting=true;
#endif
close();
qDebug("Performing quit");
QApplication::instance()->quit();
}

34
qt/i2pd_qt/mainwindow.h

@ -12,6 +12,11 @@ @@ -12,6 +12,11 @@
#include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
#ifndef ANDROID
#include <QSystemTrayIcon>
#include <QCloseEvent>
#include <QMenu>
#endif
namespace Ui {
class MainWindow;
@ -25,14 +30,43 @@ public: @@ -25,14 +30,43 @@ public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//#ifndef ANDROID
// void setVisible(bool visible);
//#endif
private slots:
void handleQuitButton();
void handleGracefulQuitButton();
void handleGracefulQuitTimerEvent();
#ifndef ANDROID
void setIcon();
void iconActivated(QSystemTrayIcon::ActivationReason reason);
void toggleVisibilitySlot();
#endif
private:
#ifndef ANDROID
void createActions();
void createTrayIcon();
#endif
QWidget *centralWidget;
QWidget *verticalLayoutWidget;
QVBoxLayout *verticalLayout1;
QPushButton *quitButton;
QPushButton *gracefulQuitButton;
#ifndef ANDROID
bool quitting;
QAction *toggleWindowVisibleAction;
QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
#endif
protected:
#ifndef ANDROID
void closeEvent(QCloseEvent *event);
#endif
};
#endif // MAINWINDOW_H

24
qt/i2pd_qt/mainwindow.ui

@ -37,6 +37,13 @@ @@ -37,6 +37,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="gracefulShutdownButton">
<property name="text">
<string>Graceful Quit</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -60,8 +67,25 @@ @@ -60,8 +67,25 @@
</hint>
</hints>
</connection>
<connection>
<sender>gracefulShutdownButton</sender>
<signal>released()</signal>
<receiver>MainWindow</receiver>
<slot>handleGracefulQuitButton()</slot>
<hints>
<hint type="sourcelabel">
<x>395</x>
<y>319</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>239</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>handleQuitButton()</slot>
<slot>handleGracefulQuitButton()</slot>
</slots>
</ui>

7
tests/Makefile

@ -1,11 +1,14 @@ @@ -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)

45
tests/test-base-64.cpp

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
#include <cassert>
#include <string.h>
#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;
}

5
tests/test-http-req.cpp

@ -22,7 +22,6 @@ int main() { @@ -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() { @@ -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() { @@ -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() { @@ -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);

2
tests/test-http-res.cpp

@ -29,7 +29,7 @@ int main() { @@ -29,7 +29,7 @@ int main() {
assert(res->headers.find("Server")->second == "nginx/1.2.1");
assert(res->headers.find("Content-Length")->second == "536");
assert(res->is_chunked() == false);
assert(res->length() == 536);
assert(res->content_length() == 536);
delete res;
/* test: building request */

Loading…
Cancel
Save