Browse Source

Merge branch 'upstream-openssl'

pull/557/head
Jeff Becker 9 years ago
parent
commit
ac59d9e1b6
No known key found for this signature in database
GPG Key ID: AB950234D6EA286B
  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. 37
      Garlic.cpp
  9. 108
      Gzip.cpp
  10. 44
      Gzip.h
  11. 2
      HTTP.cpp
  12. 2
      HTTP.h
  13. 159
      HTTPProxy.cpp
  14. 25
      HTTPProxy.h
  15. 10
      HTTPServer.cpp
  16. 14
      I2CP.cpp
  17. 16
      I2CP.h
  18. 2
      I2PControl.cpp
  19. 1
      Makefile
  20. 2
      Makefile.homebrew
  21. 8
      Makefile.linux
  22. 89
      Makefile.mingw
  23. 2
      Makefile.osx
  24. 6
      NTCPSession.cpp
  25. 4
      NetDb.cpp
  26. 2
      NetDb.h
  27. 8
      SSU.cpp
  28. 12
      SSUData.cpp
  29. 1
      SSUData.h
  30. 4
      SSUSession.cpp
  31. 45
      Streaming.cpp
  32. 90
      Tag.h
  33. 4
      TransitTunnel.cpp
  34. 28
      Tunnel.cpp
  35. 11
      Tunnel.h
  36. 5
      TunnelConfig.h
  37. 21
      TunnelPool.cpp
  38. 78
      UPnP.cpp
  39. 6
      UPnP.h
  40. 5
      build/CMakeLists.txt
  41. 1
      debian/control
  42. 7
      debian/patches/01-tune-build-opts.patch
  43. 2
      debian/patches/series
  44. 26
      debian/tunnels.conf
  45. 7
      docs/build_notes_windows.md
  46. 8
      docs/configuration.md
  47. 33
      docs/i2pd.conf
  48. 2
      filelist.mk
  49. 1
      qt/i2pd_qt/.gitignore
  50. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  51. 5
      qt/i2pd_qt/i2pd.qrc
  52. 260
      qt/i2pd_qt/i2pd_qt.pro
  53. BIN
      qt/i2pd_qt/images/icon.png
  54. 121
      qt/i2pd_qt/mainwindow.cpp
  55. 34
      qt/i2pd_qt/mainwindow.h
  56. 24
      qt/i2pd_qt/mainwindow.ui
  57. 7
      tests/Makefile
  58. 45
      tests/test-base-64.cpp
  59. 5
      tests/test-http-req.cpp
  60. 2
      tests/test-http-res.cpp

4
AddressBook.cpp

@ -203,7 +203,7 @@ namespace client
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false), AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr) m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr)
{ {
} }
@ -215,6 +215,8 @@ namespace client
void AddressBook::Start () void AddressBook::Start ()
{ {
if (!m_Storage)
m_Storage = new AddressBookFilesystemStorage;
m_Storage->Init(); m_Storage->Init();
LoadHosts (); /* try storage, then hosts.txt, then download */ LoadHosts (); /* try storage, then hosts.txt, then download */
StartSubscriptions (); StartSubscriptions ();

104
Base.cpp

@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "Log.h" #include <string.h>
#include "Base.h" #include "Base.h"
namespace i2p namespace i2p
@ -284,107 +285,6 @@ namespace data
} }
return ret; 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 @@
#define BASE_H__ #define BASE_H__
#include <inttypes.h> #include <inttypes.h>
#include <string.h>
#include <string> #include <string>
#include <zlib.h>
#include <iostream> #include <iostream>
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable (); const char * GetBase32SubstitutionTable ();
@ -23,112 +19,7 @@ namespace data
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes 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); size_t Base64EncodingBufferSize(const size_t input_size);
} // data
template<int sz> } // i2p
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;
};
}
}
#endif #endif

11
ChangeLog

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

79
Config.cpp

@ -26,83 +26,6 @@ namespace config {
options_description m_OptionsDesc; options_description m_OptionsDesc;
variables_map m_Options; 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() { void Init() {
options_description general("General options"); options_description general("General options");
general.add_options() general.add_options()
@ -225,7 +148,7 @@ namespace config {
auto style = boost::program_options::command_line_style::unix_style auto style = boost::program_options::command_line_style::unix_style
| boost::program_options::command_line_style::allow_long_disguise; | boost::program_options::command_line_style::allow_long_disguise;
style &= ~ boost::program_options::command_line_style::allow_guessing; 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) { } catch (boost::program_options::error& e) {
std::cerr << "args: " << e.what() << std::endl; std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

2
Crypto.h

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

226
DaemonWin32.cpp

@ -1,113 +1,115 @@
#include <thread> #include <thread>
#include "Config.h" #include <clocale>
#include "Daemon.h" #include "Config.h"
#include "util.h" #include "Daemon.h"
#include "Log.h" #include "util.h"
#include "Log.h"
#ifdef _WIN32
#ifdef _WIN32
#include "Win32/Win32Service.h"
#ifdef WIN32_APP #include "Win32/Win32Service.h"
#include "Win32/Win32App.h" #ifdef WIN32_APP
#endif #include "Win32/Win32App.h"
#endif
namespace i2p
{ namespace i2p
namespace util {
{ namespace util
bool DaemonWin32::init(int argc, char* argv[]) {
{ bool DaemonWin32::init(int argc, char* argv[])
setlocale(LC_CTYPE, ""); {
SetConsoleCP(1251); setlocale(LC_CTYPE, "");
SetConsoleOutputCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251);
if (!Daemon_Singleton::init(argc, argv)) setlocale(LC_ALL, "Russian");
return false;
if (!Daemon_Singleton::init(argc, argv))
std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); return false;
if (serviceControl == "install")
{ std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl);
LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); if (serviceControl == "install")
InstallService( {
SERVICE_NAME, // Name of service LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service");
SERVICE_DISPLAY_NAME, // Name to display InstallService(
SERVICE_START_TYPE, // Service start type SERVICE_NAME, // Name of service
SERVICE_DEPENDENCIES, // Dependencies SERVICE_DISPLAY_NAME, // Name to display
SERVICE_ACCOUNT, // Service running account SERVICE_START_TYPE, // Service start type
SERVICE_PASSWORD // Password of the account SERVICE_DEPENDENCIES, // Dependencies
); SERVICE_ACCOUNT, // Service running account
return false; SERVICE_PASSWORD // Password of the account
} );
else if (serviceControl == "remove") return false;
{ }
LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); else if (serviceControl == "remove")
UninstallService(SERVICE_NAME); {
return false; LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service");
} UninstallService(SERVICE_NAME);
return false;
}
if (isDaemon) if (isDaemon)
{ {
LogPrint(eLogDebug, "Daemon: running as service"); LogPrint(eLogDebug, "Daemon: running as service");
I2PService service(SERVICE_NAME); I2PService service(SERVICE_NAME);
if (!I2PService::Run(service)) if (!I2PService::Run(service))
{ {
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false; return false;
} }
return false; return false;
} }
else else
LogPrint(eLogDebug, "Daemon: running as user"); LogPrint(eLogDebug, "Daemon: running as user");
return true; return true;
} }
bool DaemonWin32::start() bool DaemonWin32::start()
{ {
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
SetConsoleCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251); SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian"); setlocale(LC_ALL, "Russian");
#ifdef WIN32_APP #ifdef WIN32_APP
if (!i2p::win32::StartWin32App ()) return false; if (!i2p::win32::StartWin32App ()) return false;
// override log // override log
i2p::config::SetOption("log", std::string ("file")); i2p::config::SetOption("log", std::string ("file"));
#endif #endif
bool ret = Daemon_Singleton::start(); bool ret = Daemon_Singleton::start();
if (ret && i2p::log::Logger().GetLogType() == eLogFile) if (ret && i2p::log::Logger().GetLogType() == eLogFile)
{ {
// TODO: find out where this garbage to console comes from // TODO: find out where this garbage to console comes from
SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE);
SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE);
} }
bool insomnia; i2p::config::GetOption("insomnia", insomnia); bool insomnia; i2p::config::GetOption("insomnia", insomnia);
if (insomnia) if (insomnia)
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
return ret; return ret;
} }
bool DaemonWin32::stop() bool DaemonWin32::stop()
{ {
#ifdef WIN32_APP #ifdef WIN32_APP
i2p::win32::StopWin32App (); i2p::win32::StopWin32App ();
#endif #endif
return Daemon_Singleton::stop(); return Daemon_Singleton::stop();
} }
void DaemonWin32::run () void DaemonWin32::run ()
{ {
#ifdef WIN32_APP #ifdef WIN32_APP
i2p::win32::RunWin32App (); i2p::win32::RunWin32App ();
#else #else
while (running) while (running)
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); std::this_thread::sleep_for (std::chrono::seconds(1));
} }
#endif #endif
} }
} }
} }
#endif #endif

37
Garlic.cpp

@ -7,6 +7,7 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "TunnelPool.h" #include "TunnelPool.h"
#include "Transports.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Log.h" #include "Log.h"
#include "Garlic.h" #include "Garlic.h"
@ -514,22 +515,34 @@ namespace garlic
buf += 32; buf += 32;
uint32_t gwTunnel = bufbe32toh (buf); uint32_t gwTunnel = bufbe32toh (buf);
buf += 4; buf += 4;
std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel; auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from);
if (from && from->GetTunnelPool ()) if (from) // received through an inbound tunnel
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); {
if (tunnel) // we have send it through an outbound tunnel std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel;
{ if (from->GetTunnelPool ())
auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); else
} LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
else if (tunnel) // we have send it through an outbound tunnel
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); 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; break;
} }
case eGarlicDeliveryTypeRouter: case eGarlicDeliveryTypeRouter:
LogPrint (eLogWarning, "Garlic: type router not supported"); {
uint8_t * ident = buf;
buf += 32; 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: default:
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
} }

108
Gzip.cpp

@ -0,0 +1,108 @@
/*
* Copyright (c) 2013-2016, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <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 @@
#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__ */

2
HTTP.cpp

@ -280,7 +280,7 @@ namespace http {
return false; return false;
} }
long int HTTPMsg::length() { long int HTTPMsg::content_length() {
unsigned long int length = 0; unsigned long int length = 0;
auto it = headers.find("Content-Length"); auto it = headers.find("Content-Length");
if (it == headers.end()) if (it == headers.end())

2
HTTP.h

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

159
HTTPProxy.cpp

@ -3,6 +3,13 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <string> #include <string>
#include <atomic> #include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h" #include "HTTPProxy.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
@ -14,12 +21,19 @@
#include "Config.h" #include "Config.h"
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p {
{ namespace proxy {
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; 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: private:
enum state enum state
@ -36,10 +50,9 @@ namespace proxy
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void Terminate(); void Terminate();
void AsyncSockRead(); void AsyncSockRead();
void HTTPRequestFailed(/*std::string message*/); void HTTPRequestFailed(const char *message);
void RedirectToJumpService(); void RedirectToJumpService(std::string & host);
void ExtractRequest(); void ExtractRequest();
bool IsI2PAddress();
bool ValidateHTTPRequest(); bool ValidateHTTPRequest();
void HandleJumpServices(); void HandleJumpServices();
bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len); bool CreateHTTPRequest(uint8_t *http_buff, std::size_t len);
@ -59,26 +72,26 @@ namespace proxy
public: 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) I2PServiceHandler(parent), m_sock(sock)
{ EnterState(GET_METHOD); } { EnterState(GET_METHOD); }
~HTTPProxyHandler() { Terminate(); } ~HTTPReqHandler() { Terminate(); }
void Handle () { AsyncSockRead(); } void Handle () { AsyncSockRead(); }
}; };
void HTTPProxyHandler::AsyncSockRead() void HTTPReqHandler::AsyncSockRead()
{ {
LogPrint(eLogDebug, "HTTPProxy: async sock read"); LogPrint(eLogDebug, "HTTPProxy: async sock read");
if(m_sock) { 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 {
LogPrint(eLogError, "HTTPProxy: no socket for read"); 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 (Kill()) return;
if (m_sock) if (m_sock)
{ {
@ -91,30 +104,45 @@ namespace proxy
/* All hope is lost beyond this point */ /* All hope is lost beyond this point */
//TODO: handle this apropriately //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"; i2p::http::HTTPRes res;
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), res.code = 500;
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); 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; i2p::http::HTTPRes res;
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); i2p::http::URL url;
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
/* 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"; std::string response = res.to_string();
boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), boost::asio::async_write(*m_sock, boost::asio::buffer(response),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); 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; m_state = nstate;
} }
void HTTPProxyHandler::ExtractRequest() void HTTPReqHandler::ExtractRequest()
{ {
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
i2p::http::URL url; i2p::http::URL url;
@ -127,18 +155,18 @@ namespace proxy
LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path); 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" ) if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
{ {
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
HTTPRequestFailed(); //TODO: send right stuff HTTPRequestFailed("unsupported HTTP version");
return false; return false;
} }
return true; return true;
} }
void HTTPProxyHandler::HandleJumpServices() void HTTPReqHandler::HandleJumpServices()
{ {
static const char * helpermark1 = "?i2paddresshelper="; static const char * helpermark1 = "?i2paddresshelper=";
static const char * helpermark2 = "&i2paddresshelper="; static const char * helpermark2 = "&i2paddresshelper=";
@ -170,31 +198,20 @@ namespace proxy
m_path.erase(addressHelperPos); m_path.erase(addressHelperPos);
} }
bool HTTPProxyHandler::IsI2PAddress() bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
{
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)
{ {
ExtractRequest(); //TODO: parse earlier ExtractRequest(); //TODO: parse earlier
if (!ValidateHTTPRequest()) return false; if (!ValidateHTTPRequest()) return false;
HandleJumpServices(); HandleJumpServices();
i2p::data::IdentHash identHash; i2p::data::IdentHash identHash;
if (IsI2PAddress ()) if (str_rmatch(m_address, ".i2p"))
{ {
if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){ if (!i2p::client::context.GetAddressBook ().GetIdentHash (m_address, identHash)){
RedirectToJumpService(); RedirectToJumpService(m_address);
return false; return false;
} }
} }
m_request = m_method; m_request = m_method;
m_request.push_back(' '); m_request.push_back(' ');
@ -235,7 +252,7 @@ namespace proxy
return true; 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) while (len > 0)
{ {
@ -269,13 +286,13 @@ namespace proxy
case '\n': EnterState(DONE); break; case '\n': EnterState(DONE); break;
default: default:
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
HTTPRequestFailed(); //TODO: add correct code HTTPRequestFailed("rejected invalid request");
return false; return false;
} }
break; break;
default: default:
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
HTTPRequestFailed(); //TODO: add correct code 500 HTTPRequestFailed("invalid parser state");
return false; return false;
} }
http_buff++; http_buff++;
@ -286,7 +303,7 @@ namespace proxy
return true; 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"); LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
if(ecode) if(ecode)
@ -301,49 +318,45 @@ namespace proxy
if (m_state == DONE) if (m_state == DONE)
{ {
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url); 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); shared_from_this(), std::placeholders::_1), m_address, m_port);
} }
else else
AsyncSockRead(); AsyncSockRead();
} }
} }
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode) void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode)
{ {
if (ecode) if (ecode)
LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ()); LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
Terminate(); Terminate();
} }
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream) void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (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
{
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); 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 ()) 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 @@
#ifndef HTTP_PROXY_H__ #ifndef HTTP_PROXY_H__
#define HTTP_PROXY_H__ #define HTTP_PROXY_H__
#include <memory> namespace i2p {
#include <set> namespace proxy {
#include <boost/asio.hpp> class HTTPProxy: public i2p::client::TCPIPAcceptor
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
namespace i2p
{
namespace proxy
{
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
{ {
public: public:
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr); HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~HTTPProxyServer() {}; ~HTTPProxy() {};
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; } const char* GetName() { return "HTTP Proxy"; }
}; };
} // http
typedef HTTPProxyServer HTTPProxy; } // i2p
}
}
#endif #endif

10
HTTPServer.cpp

@ -126,8 +126,12 @@ namespace http {
s << s <<
"<!DOCTYPE html>\r\n" "<!DOCTYPE html>\r\n"
"<html lang=\"en\">\r\n" /* TODO: Add support for locale */ "<html lang=\"en\">\r\n" /* TODO: Add support for locale */
" <head>\r\n" " <head>\r\n" /* TODO: Find something to parse html/template system. This is horrible. */
" <meta charset=\"UTF-8\">\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" " <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
" <title>Purple I2P " VERSION " Webconsole</title>\r\n" " <title>Purple I2P " VERSION " Webconsole</title>\r\n"
<< cssStyles << << cssStyles <<
@ -612,7 +616,7 @@ namespace http {
HandleCommand (req, res, s); HandleCommand (req, res, s);
} else { } else {
ShowStatus (s); ShowStatus (s);
//res.add_header("Refresh", "5"); res.add_header("Refresh", "10");
} }
ShowPageTail (s); ShowPageTail (s);

14
I2CP.cpp

@ -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_Owner (owner), m_Socket (socket), m_Payload (nullptr),
m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true) m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
{ {
@ -583,7 +583,12 @@ namespace client
I2CPServer::I2CPServer (const std::string& interface, int port): I2CPServer::I2CPServer (const std::string& interface, int port):
m_IsRunning (false), m_Thread (nullptr), 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)); memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers));
m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler;
@ -644,12 +649,13 @@ namespace client
void I2CPServer::Accept () 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, m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this,
std::placeholders::_1, newSocket)); 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) if (!ecode && socket)
{ {

16
I2CP.h

@ -99,7 +99,14 @@ namespace client
{ {
public: 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 (); ~I2CPSession ();
void Start (); void Start ();
@ -144,7 +151,7 @@ namespace client
private: private:
I2CPServer& m_Owner; 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; uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload;
size_t m_PayloadLen; size_t m_PayloadLen;
@ -173,7 +180,8 @@ namespace client
void Run (); void Run ();
void Accept (); 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: private:
@ -183,7 +191,7 @@ namespace client
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor; I2CPSession::proto::acceptor m_Acceptor;
public: public:

2
I2PControl.cpp

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

1
Makefile

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

2
Makefile.homebrew

@ -8,7 +8,7 @@ INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread 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 LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP CXXFLAGS += -DUSE_UPNP
endif endif

8
Makefile.linux

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

89
Makefile.mingw

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

6
NTCPSession.cpp

@ -1,6 +1,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <zlib.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Base.h" #include "Base.h"
#include "Crypto.h" #include "Crypto.h"
@ -430,7 +430,7 @@ namespace transport
} }
else 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 ()); m_Server.AddNTCPSession (shared_from_this ());
Connected (); Connected ();
@ -942,7 +942,7 @@ namespace transport
{ {
if (ecode) 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) if (ecode != boost::asio::error::operation_aborted)
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
conn->Terminate (); conn->Terminate ();

4
NetDb.cpp

@ -2,7 +2,7 @@
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <zlib.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Base.h" #include "Base.h"
#include "Crypto.h" #include "Crypto.h"
@ -671,7 +671,7 @@ namespace data
if (!replyMsg) 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 // find or cleate response
std::vector<IdentHash> closestFloodfills; std::vector<IdentHash> closestFloodfills;
bool found = false; bool found = false;

2
NetDb.h

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

8
SSU.cpp

@ -231,7 +231,7 @@ namespace transport
session = std::make_shared<SSUSession> (*this, packet->from); session = std::make_shared<SSUSession> (*this, packet->from);
session->WaitForConnect (); session->WaitForConnect ();
(*sessions)[packet->from] = session; (*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); session->ProcessNextMessage (packet->buf, packet->len, packet->from);
@ -312,7 +312,7 @@ namespace transport
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest); auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
sessions[remoteEndpoint] = session; sessions[remoteEndpoint] = session;
// connect // 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 ()); remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
session->Connect (); session->Connect ();
} }
@ -364,10 +364,10 @@ namespace transport
} }
if (introducerSession) // session found if (introducerSession) // session found
LogPrint (eLogInfo, "SSU: Session to introducer already exists"); LogPrint (eLogWarning, "SSU: Session to introducer already exists");
else // create new 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); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router); introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession; m_Sessions[introducerEndpoint] = introducerSession;

12
SSUData.cpp

@ -241,7 +241,7 @@ namespace transport
if (!msg->IsExpired ()) if (!msg->IsExpired ())
m_Handler.PutNextMessage (msg); m_Handler.PutNextMessage (msg);
else else
LogPrint (eLogInfo, "SSU: message expired"); LogPrint (eLogDebug, "SSU: message expired");
} }
else else
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received"); LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
@ -425,6 +425,7 @@ namespace transport
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
int numResent = 0;
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();) for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
{ {
if (ts >= it->second->nextResendTime) if (ts >= it->second->nextResendTime)
@ -437,6 +438,7 @@ namespace transport
try try
{ {
m_Session.Send (f->buf, f->len); // resend m_Session.Send (f->buf, f->len); // resend
numResent++;
} }
catch (boost::system::system_error& ec) catch (boost::system::system_error& ec)
{ {
@ -457,7 +459,13 @@ namespace transport
else else
it++; 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
const int DECAY_INTERVAL = 20; // in seconds const int DECAY_INTERVAL = 20; // in seconds
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // 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 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 // data flags
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
const uint8_t DATA_FLAG_WANT_REPLY = 0x04; const uint8_t DATA_FLAG_WANT_REPLY = 0x04;

4
SSUSession.cpp

@ -814,7 +814,7 @@ namespace transport
if (!ecode) if (!ecode)
{ {
// timeout expired // 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 (); Failed ();
} }
} }
@ -891,7 +891,7 @@ namespace transport
{ {
if (ecode != boost::asio::error::operation_aborted) 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 (); Failed ();
} }
} }

45
Streaming.cpp

@ -87,7 +87,7 @@ namespace stream
return; return;
} }
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn); LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn, " on sSID=", m_SendStreamID);
if (receivedSeqn == m_LastReceivedSequenceNumber + 1) if (receivedSeqn == m_LastReceivedSequenceNumber + 1)
{ {
// we have received next in sequence message // we have received next in sequence message
@ -129,13 +129,13 @@ namespace stream
if (receivedSeqn <= m_LastReceivedSequenceNumber) if (receivedSeqn <= m_LastReceivedSequenceNumber)
{ {
// we have received duplicate // 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 SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped delete packet; // packet dropped
} }
else 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 // save message and wait for missing message again
SavePacket (packet); SavePacket (packet);
if (m_LastReceivedSequenceNumber >= 0) if (m_LastReceivedSequenceNumber >= 0)
@ -183,7 +183,7 @@ namespace stream
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ()); m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ());
optionData += m_RemoteIdentity->GetFullLen (); optionData += m_RemoteIdentity->GetFullLen ();
if (!m_RemoteLeaseSet) 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) if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
@ -263,7 +263,7 @@ namespace stream
uint64_t rtt = ts - sentPacket->sendTime; uint64_t rtt = ts - sentPacket->sendTime;
m_RTT = (m_RTT*seqn + rtt)/(seqn + 1); m_RTT = (m_RTT*seqn + rtt)/(seqn + 1);
m_RTO = m_RTT*1.5; // TODO: implement it better 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++); m_SentPackets.erase (it++);
delete sentPacket; delete sentPacket;
acknowledged = true; acknowledged = true;
@ -395,8 +395,11 @@ namespace stream
} }
if (packets.size () > 0) if (packets.size () > 0)
{ {
m_IsAckSendScheduled = false; if (m_SavedPackets.empty ()) // no NACKS
m_AckSendTimer.cancel (); {
m_IsAckSendScheduled = false;
m_AckSendTimer.cancel ();
}
bool isEmpty = m_SentPackets.empty (); bool isEmpty = m_SentPackets.empty ();
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: packets) for (auto it: packets)
@ -448,7 +451,7 @@ namespace stream
auto seqn = it->GetSeqn (); auto seqn = it->GetSeqn ();
if (numNacks + (seqn - nextSeqn) >= 256) 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 htobe32buf (packet + 12, nextSeqn); // change ack Through
break; break;
} }
@ -489,7 +492,7 @@ namespace stream
m_Status = eStreamStatusClosing; m_Status = eStreamStatusClosing;
Close (); // recursion Close (); // recursion
if (m_Status == eStreamStatusClosing) //still closing 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; break;
case eStreamStatusReset: case eStreamStatusReset:
SendClose (); SendClose ();
@ -511,7 +514,7 @@ namespace stream
m_LocalDestination.DeleteStream (shared_from_this ()); m_LocalDestination.DeleteStream (shared_from_this ());
break; break;
default: 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
p->len = size; p->len = size;
m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p)); 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) size_t Stream::ConcatenatePackets (uint8_t * buf, size_t len)
@ -597,7 +600,7 @@ namespace stream
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease ();
if (!m_RemoteLeaseSet) 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; return;
} }
} }
@ -622,7 +625,7 @@ namespace stream
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!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; return;
} }
@ -646,7 +649,7 @@ namespace stream
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs); m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
} }
else else
LogPrint (eLogWarning, "Streaming: All leases are expired"); LogPrint (eLogWarning, "Streaming: All leases are expired, sSID=", m_SendStreamID);
} }
@ -665,7 +668,7 @@ namespace stream
// check for resend attempts // check for resend attempts
if (m_NumResendAttempts >= MAX_NUM_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; m_Status = eStreamStatusReset;
Close (); Close ();
return; return;
@ -700,13 +703,13 @@ namespace stream
case 4: case 4:
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
UpdateCurrentRemoteLease (); // pick another lease 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; break;
case 3: case 3:
// pick another outbound tunnel // pick another outbound tunnel
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); 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; break;
default: ; default: ;
} }
@ -722,7 +725,7 @@ namespace stream
{ {
if (m_LastReceivedSequenceNumber < 0) 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; m_Status = eStreamStatusReset;
Close (); Close ();
return; return;
@ -825,7 +828,7 @@ namespace stream
it->second->HandleNextPacket (packet); it->second->HandleNextPacket (packet);
else else
{ {
LogPrint (eLogError, "Streaming: Unknown stream sendStreamID=", sendStreamID); LogPrint (eLogError, "Streaming: Unknown stream sSID=", sendStreamID);
delete packet; delete packet;
} }
} }
@ -841,7 +844,7 @@ namespace stream
auto it = m_SavedPackets.find (receiveStreamID); auto it = m_SavedPackets.find (receiveStreamID);
if (it != m_SavedPackets.end ()) 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) for (auto it1: it->second)
incomingStream->HandleNextPacket (it1); incomingStream->HandleNextPacket (it1);
m_SavedPackets.erase (it); m_SavedPackets.erase (it);
@ -860,7 +863,7 @@ namespace stream
m_PendingIncomingTimer.expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT)); m_PendingIncomingTimer.expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
m_PendingIncomingTimer.async_wait (std::bind (&StreamingDestination::HandlePendingIncomingTimer, m_PendingIncomingTimer.async_wait (std::bind (&StreamingDestination::HandlePendingIncomingTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
LogPrint (eLogDebug, "Streaming: Pending incoming stream added"); LogPrint (eLogDebug, "Streaming: Pending incoming stream added, rSID=", receiveStreamID);
} }
else else
{ {

90
Tag.h

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

28
Tunnel.cpp

@ -768,6 +768,22 @@ namespace tunnel
return newTunnel; return newTunnel;
} }
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{
if (config->IsEmpty ())
return CreateZeroHopsInboundTunnel ();
else
return CreateTunnel<InboundTunnel>(config, outboundTunnel);
}
std::shared_ptr<OutboundTunnel> Tunnels::CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config)
{
if (config->IsEmpty ())
return CreateZeroHopsOutboundTunnel ();
else
return CreateTunnel<OutboundTunnel>(config);
}
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel) void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel)
{ {
m_PendingInboundTunnels[replyMsgID] = tunnel; m_PendingInboundTunnels[replyMsgID] = tunnel;
@ -815,20 +831,22 @@ namespace tunnel
} }
void Tunnels::CreateZeroHopsInboundTunnel () std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel ()
{ {
auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> (); auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> ();
inboundTunnel->SetState (eTunnelStateEstablished); inboundTunnel->SetState (eTunnelStateEstablished);
m_InboundTunnels.push_back (inboundTunnel); m_InboundTunnels.push_back (inboundTunnel);
m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel; m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel;
return inboundTunnel;
} }
void Tunnels::CreateZeroHopsOutboundTunnel () std::shared_ptr<ZeroHopsOutboundTunnel> Tunnels::CreateZeroHopsOutboundTunnel ()
{ {
auto outboundTunnel = std::make_shared<ZeroHopsOutboundTunnel> (); auto outboundTunnel = std::make_shared<ZeroHopsOutboundTunnel> ();
outboundTunnel->SetState (eTunnelStateEstablished); outboundTunnel->SetState (eTunnelStateEstablished);
m_OutboundTunnels.push_back (outboundTunnel); m_OutboundTunnels.push_back (outboundTunnel);
// we don't insert into m_Tunnels // we don't insert into m_Tunnels
return outboundTunnel;
} }
int Tunnels::GetTransitTunnelsExpirationTimeout () int Tunnels::GetTransitTunnelsExpirationTimeout ()
@ -861,12 +879,6 @@ namespace tunnel
// TODO: locking // TODO: locking
return m_OutboundTunnels.size(); 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
void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel); void AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel);
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel); void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> 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 (std::shared_ptr<I2NPMessage> msg);
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); 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<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops, std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
@ -189,6 +189,9 @@ namespace tunnel
private: private:
template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels); std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
@ -204,8 +207,8 @@ namespace tunnel
void ManagePendingTunnels (PendingTunnels& pendingTunnels); void ManagePendingTunnels (PendingTunnels& pendingTunnels);
void ManageTunnelPools (); void ManageTunnelPools ();
void CreateZeroHopsInboundTunnel (); std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
void CreateZeroHopsOutboundTunnel (); std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
private: private:

5
TunnelConfig.h

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

21
TunnelPool.cpp

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

78
UPnP.cpp

@ -6,13 +6,6 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#ifdef _WIN32
#include <windows.h>
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#endif
#include "Log.h" #include "Log.h"
#include "RouterContext.h" #include "RouterContext.h"
@ -24,32 +17,11 @@
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.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 i2p
{ {
namespace transport namespace transport
{ {
UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false) UPnP::UPnP () : m_Thread (nullptr)
{ {
} }
@ -65,33 +37,6 @@ namespace transport
void UPnP::Start() void UPnP::Start()
{ {
if (!m_IsModuleLoaded) {
#ifdef MAC_OSX
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
m_Module = LoadLibrary ("miniupnpc.dll"); // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip
#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)); m_Thread = new std::thread (std::bind (&UPnP::Run, this));
} }
@ -123,16 +68,16 @@ namespace transport
{ {
int nerror = 0; int nerror = 0;
#if MINIUPNPC_API_VERSION >= 14 #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 #else
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#endif #endif
int r; 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) 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) if(r != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r); LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
@ -171,7 +116,7 @@ namespace transport
std::string strDesc = "I2Pd"; std::string strDesc = "I2Pd";
try { try {
for (;;) { 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) if (r!=UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
@ -208,20 +153,15 @@ namespace transport
strType = "UDP"; strType = "UDP";
} }
int r = 0; 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"); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
} }
void UPnP::Close () void UPnP::Close ()
{ {
freeUPNPDevlistFunc (m_Devlist); freeUPNPDevlist (m_Devlist);
m_Devlist = 0; m_Devlist = 0;
FreeUPNPUrlsFunc (&m_upnpUrls); FreeUPNPUrls (&m_upnpUrls);
#ifndef _WIN32
dlclose (m_Module);
#else
FreeLibrary (m_Module);
#endif
} }
} }

6
UPnP.h

@ -48,12 +48,6 @@ namespace transport
struct UPNPDev * m_Devlist = 0; struct UPNPDev * m_Devlist = 0;
char m_NetworkAddr[64]; char m_NetworkAddr[64];
char m_externalIPAddress[40]; 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
"${CMAKE_SOURCE_DIR}/Config.cpp" "${CMAKE_SOURCE_DIR}/Config.cpp"
"${CMAKE_SOURCE_DIR}/Crypto.cpp" "${CMAKE_SOURCE_DIR}/Crypto.cpp"
"${CMAKE_SOURCE_DIR}/Garlic.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp"
"${CMAKE_SOURCE_DIR}/Gzip.cpp"
"${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp"
"${CMAKE_SOURCE_DIR}/Identity.cpp" "${CMAKE_SOURCE_DIR}/Identity.cpp"
"${CMAKE_SOURCE_DIR}/LeaseSet.cpp" "${CMAKE_SOURCE_DIR}/LeaseSet.cpp"
@ -338,6 +339,10 @@ if (WITH_BINARY)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" ) set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" )
endif () 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 # 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) list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*") 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~),
libboost-date-time-dev, libboost-date-time-dev,
libboost-filesystem-dev, libboost-filesystem-dev,
libboost-program-options-dev, libboost-program-options-dev,
libminiupnpc-dev,
libssl-dev libssl-dev
Standards-Version: 3.9.3 Standards-Version: 3.9.3
Homepage: https://github.com/PurpleI2P/i2pd 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 @@
diff --git a/Makefile b/Makefile diff --git a/Makefile b/Makefile
index 2e86fd8..c1037af 100644 index fe8ae7e..fc8abda 100644
--- a/Makefile --- a/Makefile
+++ b/Makefile +++ b/Makefile
@@ -9,7 +9,7 @@ DEPS := obj/make.dep @@ -9,9 +9,9 @@ DEPS := obj/make.dep
include filelist.mk include filelist.mk
-USE_AESNI := yes -USE_AESNI := yes
+USE_AESNI := no +USE_AESNI := no
USE_STATIC := no USE_STATIC := no
-USE_UPNP := no
+USE_UPNP := yes
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp

2
debian/patches/series vendored

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

26
debian/tunnels.conf vendored

@ -1,7 +1,33 @@
[IRC] [IRC]
type = client type = client
address = 127.0.0.1
port = 6668 port = 6668
destination = irc.postman.i2p destination = irc.postman.i2p
destinationport = 6667
keys = irc-keys.dat keys = irc-keys.dat
#[SMTP]
#type = client
#address = 127.0.0.1
#port = 7659
#destination = smtp.postman.i2p
#destinationport = 25
#keys = smtp-keys.dat
#[POP3]
#type = client
#address = 127.0.0.1
#port = 7660
#destination = pop.postman.i2p
#destinationport = 110
#keys = pop3-keys.dat
#[MTN]
#type = client
#address = 127.0.0.1
#port = 8998
#destination = mtn.i2p-projekt.i2p
#destinationport = 4691
#keys = mtn-keys.dat
# see more examples in /usr/share/doc/i2pd/configuration.md.gz # see more examples in /usr/share/doc/i2pd/configuration.md.gz

7
docs/build_notes_windows.md

@ -164,6 +164,13 @@ folder name included in downloaded archive.
Note that you might need to build DLL yourself for 64-bit systems Note that you might need to build DLL yourself for 64-bit systems
using msys2 as 64-bit DLLs are not provided by the project. using msys2 as 64-bit DLLs are not provided by the project.
You can also install it through the MSYS2
and build with USE_UPNP key.
```bash
pacman -S mingw-w64-i686-miniupnpc
make USE_UPNP=1
```
### Creating Visual Studio project ### Creating Visual Studio project

8
docs/configuration.md

@ -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) * --http.pass= - Password for basic auth (default: random, see logs)
* --httpproxy.address= - The address to listen on (HTTP Proxy) * --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.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --httpproxy.enabled= - If HTTP proxy is enabled. true by default * --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:
* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified * --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --bob.enabled= - If BOB is enabled. false by default * --bob.enabled= - If BOB is enabled. false by default
* --i2cp.address= - The address to listen on * --i2cp.address= - The address to listen on or an abstract address for Android LocalSocket
* --i2cp.port= - Port of I2CP server. Usually 7654. IPCP is off if not specified * --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't requeire I2CP * --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.address= - The address to listen on (I2P control service)
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified

33
docs/i2pd.conf

@ -42,14 +42,18 @@
## Port to listen for connections ## Port to listen for connections
## By default i2pd picks random port. You MUST pick a random number too, ## By default i2pd picks random port. You MUST pick a random number too,
## don't just uncomment this ## don't just uncomment this
# port = 4321 # port = 4567
## Enable communication through ipv4
ipv4 = true
## Enable communication through ipv6 ## Enable communication through ipv6
ipv6 = true ipv6 = false
## Bandwidth configuration ## Bandwidth configuration
## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited ## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - to 2048Kbs/sec,
## Default is P for floodfill, L for regular node ## X - unlimited
## Default is X for floodfill, L for regular node
# bandwidth = L # bandwidth = L
## Router will not accept transit tunnels at startup ## Router will not accept transit tunnels at startup
@ -58,6 +62,15 @@ ipv6 = true
## Router will be floodfill ## Router will be floodfill
# floodfill = true # floodfill = true
[limits]
## Maximum active transit sessions (default:2500)
# transittunnels = 2500
[precomputation]
## Enable or disable elgamal precomputation table
## By default, enabled on i386 hosts
# elgamal = true
[http] [http]
## Uncomment and set to 'false' to disable Web Console ## Uncomment and set to 'false' to disable Web Console
# enabled = true # enabled = true
@ -78,10 +91,11 @@ port = 4444
## Uncomment and set to 'false' to disable SOCKS Proxy ## Uncomment and set to 'false' to disable SOCKS Proxy
# enabled = true # enabled = true
## Address and port service will listen on ## Address and port service will listen on
# address = 127.0.0.1 address = 127.0.0.1
# port = 4447 port = 4447
## Optional keys file for proxy local destination ## Optional keys file for proxy local destination
# keys = socks-proxy-keys.dat # keys = socks-proxy-keys.dat
## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Socks outproxy. Example below is set to use Tor for all connections except i2p
## Address and port of outproxy ## Address and port of outproxy
# outproxy = 127.0.0.1 # outproxy = 127.0.0.1
@ -101,6 +115,13 @@ port = 4444
# address = 127.0.0.1 # address = 127.0.0.1
# port = 2827 # port = 2827
[i2cp]
## Uncomment and set to 'true' to enable I2CP protocol
# enabled = false
## Address and port service will listen on
# address = 127.0.0.1
# port = 7654
[i2pcontrol] [i2pcontrol]
## Uncomment and set to 'true' to enable I2PControl protocol ## Uncomment and set to 'true' to enable I2PControl protocol
# enabled = false # enabled = false

2
filelist.mk

@ -1,5 +1,5 @@
LIB_SRC = \ 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 \ Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \ Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \

1
qt/i2pd_qt/.gitignore vendored

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

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?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"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

5
qt/i2pd_qt/i2pd.qrc

@ -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 @@
#------------------------------------------------- QT += core gui
#
# Project created by QtCreator 2016-06-14T04:53:04
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = i2pd_qt TARGET = i2pd_qt
TEMPLATE = app TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11 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/Boost-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/OpenSSL-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 # git clone https://github.com/PurpleI2P/android-ifaddrs.git
# change to your own
BOOST_PATH = /mnt/media/android/Boost-for-Android-Prebuilt BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt
OPENSSL_PATH = /mnt/media/android/OpenSSL-for-Android-Prebuilt OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt
IFADDRS_PATH = /mnt/media/android/android-ifaddrs MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt
IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs
# Steps in Android SDK manager: # Steps in Android SDK manager:
# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html # 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html
# 2) Check API 11 # 2) Check API 11
# Finally, click Install. # Finally, click Install.
SOURCES += DaemonQT.cpp\ SOURCES += DaemonQT.cpp mainwindow.cpp \
mainwindow.cpp \ ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \
../../HTTPServer.cpp ../../I2PControl.cpp ../../UPnP.cpp ../../Daemon.cpp ../../Config.cpp \ ../../AddressBook.cpp ../../api.cpp ../../Base.cpp ../../BOB.cpp ../../ClientContext.cpp \
../../AddressBook.cpp \ ../../Crypto.cpp ../../Datagram.cpp ../../Destination.cpp ../../Family.cpp ../../FS.cpp \
../../api.cpp \ ../../Garlic.cpp ../../HTTP.cpp ../../HTTPProxy.cpp ../../I2CP.cpp ../../I2NPProtocol.cpp \
../../Base.cpp \ ../../I2PEndian.cpp ../../I2PService.cpp ../../I2PTunnel.cpp ../../Identity.cpp \
../../BOB.cpp \ ../../LeaseSet.cpp ../../Log.cpp ../../NetDb.cpp ../../NetDbRequests.cpp \
../../ClientContext.cpp \ ../../NTCPSession.cpp ../../Profiling.cpp ../../Reseed.cpp ../../RouterContext.cpp \
../../Crypto.cpp \ ../../RouterInfo.cpp ../../SAM.cpp ../../Signature.cpp ../../SOCKS.cpp ../../SSU.cpp \
../../Datagram.cpp \ ../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
../../Destination.cpp \ ../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
../../Family.cpp \ ../../TunnelPool.cpp ../../UPnP.cpp ../../util.cpp ../../Gzip.cpp ../../i2pd.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
HEADERS += DaemonQT.h mainwindow.h \ HEADERS += DaemonQT.h mainwindow.h \
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
../../AddressBook.h \ ../../AddressBook.h ../../api.h ../../Base.h ../../BOB.h ../../ClientContext.h \
../../api.h \ ../../Crypto.h ../../Datagram.h ../../Destination.h ../../Family.h ../../FS.h \
../../Base.h \ ../../Garlic.h ../../HTTP.h ../../HTTPProxy.h ../../I2CP.h ../../I2NPProtocol.h \
../../BOB.h \ ../../I2PEndian.h ../../I2PService.h ../../I2PTunnel.h ../../Identity.h ../../LeaseSet.h \
../../ClientContext.h \ ../../LittleBigEndian.h ../../Log.h ../../NetDb.h ../../NetDbRequests.h ../../NTCPSession.h \
../../Crypto.h \ ../../Profiling.h ../../Queue.h ../../Reseed.h ../../RouterContext.h ../../RouterInfo.h \
../../Datagram.h \ ../../SAM.h ../../Signature.h ../../SOCKS.h ../../SSU.h ../../SSUData.h ../../SSUSession.h \
../../Destination.h \ ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
../../Family.h \ ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
../../FS.h \ ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
../../Garlic.h \ ../../util.h ../../version.h ..//../Gzip.h ../../Tag.h
../../HTTP.h \
../../HTTPProxy.h \ FORMS += mainwindow.ui
../../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
CONFIG += mobility CONFIG += mobility
MOBILITY = MOBILITY =
LIBS += -lz LIBS += -lz
android { android {
message("Using Android settings") message("Using Android settings")
DEFINES += ANDROID=1 DEFINES += ANDROID=1
DEFINES += __ANDROID__ DEFINES += __ANDROID__
INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$OPENSSL_PATH/openssl-1.0.2/include \ INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$IFADDRS_PATH $$OPENSSL_PATH/openssl-1.0.2/include \
DISTFILES += \ $$MINIUPNP_PATH/miniupnp-2.0/include \
android/AndroidManifest.xml $$IFADDRS_PATH
DISTFILES += android/AndroidManifest.xml
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
equals(ANDROID_TARGET_ARCH, armeabi-v7a){
SOURCES += $$IFADDRS_PATH/ifaddrs.c
DEFINES += ANDROID_ARM7A HEADERS += $$IFADDRS_PATH/ifaddrs.h
# http://stackoverflow.com/a/30235934/529442 equals(ANDROID_TARGET_ARCH, armeabi-v7a){
LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ DEFINES += ANDROID_ARM7A
-lboost_system-gcc-mt-1_53 \ # http://stackoverflow.com/a/30235934/529442
-lboost_date_time-gcc-mt-1_53 \ LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
-lboost_filesystem-gcc-mt-1_53 \ -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_program_options-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$$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 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 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 \ 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 $$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 \ equals(ANDROID_TARGET_ARCH, x86){
-lboost_system-gcc-mt-1_53 \ # http://stackoverflow.com/a/30235934/529442
-lboost_date_time-gcc-mt-1_53 \ LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
-lboost_filesystem-gcc-mt-1_53 \ -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_program_options-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$$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 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
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 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 { linux:!android {
message("Using Linux settings") message("Using Linux settings")
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread 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 @@
#include "mainwindow.h" #include "mainwindow.h"
//#include "ui_mainwindow.h" //#include "ui_mainwindow.h"
#include <QMessageBox> #include <QMessageBox>
#include <QTimer>
#include "../../RouterContext.h"
#ifndef ANDROID
#include <QtDebug>
#endif
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)/*, QMainWindow(parent)/*,
ui(new Ui::MainWindow)*/ ui(new Ui::MainWindow)*/
#ifndef ANDROID
,
quitting(false)
#endif
{ {
//ui->setupUi(this); //ui->setupUi(this);
if (objectName().isEmpty()) if (objectName().isEmpty())
@ -22,27 +31,129 @@ MainWindow::MainWindow(QWidget *parent) :
verticalLayout1->setContentsMargins(0, 0, 0, 0); verticalLayout1->setContentsMargins(0, 0, 0, 0);
quitButton = new QPushButton(verticalLayoutWidget); quitButton = new QPushButton(verticalLayoutWidget);
quitButton->setObjectName(QStringLiteral("quitButton")); quitButton->setObjectName(QStringLiteral("quitButton"));
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy.setHorizontalStretch(0); sizePolicy.setHorizontalStretch(1);
sizePolicy.setVerticalStretch(0); //sizePolicy.setVerticalStretch(1);
sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth()); sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth());
quitButton->setSizePolicy(sizePolicy); quitButton->setSizePolicy(sizePolicy);
verticalLayout1->addWidget(quitButton); 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); setCentralWidget(centralWidget);
setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0)); setWindowTitle(QApplication::translate("MainWindow", "i2pd", 0));
quitButton->setText(QApplication::translate("MainWindow", "Quit", 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(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); //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() { void MainWindow::handleQuitButton() {
qDebug("Quit pressed. Hiding the main window"); 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(); close();
qDebug("Performing quit");
QApplication::instance()->quit(); QApplication::instance()->quit();
} }

34
qt/i2pd_qt/mainwindow.h

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

24
qt/i2pd_qt/mainwindow.ui

@ -37,6 +37,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="gracefulShutdownButton">
<property name="text">
<string>Graceful Quit</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -60,8 +67,25 @@
</hint> </hint>
</hints> </hints>
</connection> </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> </connections>
<slots> <slots>
<slot>handleQuitButton()</slot> <slot>handleQuitButton()</slot>
<slot>handleGracefulQuitButton()</slot>
</slots> </slots>
</ui> </ui>

7
tests/Makefile

@ -1,11 +1,14 @@
CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 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 \ 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 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 $@ $^ $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
run: $(TESTS) run: $(TESTS)

45
tests/test-base-64.cpp

@ -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() {
assert(req->version == "HTTP/1.0"); assert(req->version == "HTTP/1.0");
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "/"); assert(req->uri == "/");
assert(req->host == "inr.i2p");
assert(req->headers.size() == 3); assert(req->headers.size() == 3);
assert(req->headers.count("Host") == 1); assert(req->headers.count("Host") == 1);
assert(req->headers.count("Accept") == 1); assert(req->headers.count("Accept") == 1);
@ -42,7 +41,6 @@ int main() {
assert(req->version == "HTTP/1.0"); assert(req->version == "HTTP/1.0");
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "/"); assert(req->uri == "/");
assert(req->host == "");
assert(req->headers.size() == 0); assert(req->headers.size() == 0);
delete req; delete req;
@ -52,7 +50,7 @@ int main() {
"\r\n"; "\r\n";
len = strlen(buf); len = strlen(buf);
req = new HTTPReq; req = new HTTPReq;
assert((ret = req->parse(buf, len)) == -1); /* no host header */ assert((ret = req->parse(buf, len)) > 0);
delete req; delete req;
/* test: parsing incomplete request */ /* test: parsing incomplete request */
@ -76,7 +74,6 @@ int main() {
assert((ret = req->parse(buf, len)) == len); /* no host header */ assert((ret = req->parse(buf, len)) == len); /* no host header */
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "http://inr.i2p"); assert(req->uri == "http://inr.i2p");
assert(req->host == "stats.i2p");
assert(req->headers.size() == 3); assert(req->headers.size() == 3);
assert(req->headers.count("Host") == 1); assert(req->headers.count("Host") == 1);
assert(req->headers.count("Accept") == 1); assert(req->headers.count("Accept") == 1);

2
tests/test-http-res.cpp

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

Loading…
Cancel
Save