Merge pull request #556 from PurpleI2P/openssl

floodfill fixes
This commit is contained in:
orignal 2016-06-30 17:51:26 -04:00 committed by GitHub
commit 03d7330af5
59 changed files with 1067 additions and 891 deletions

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
{ {

View File

@ -1,4 +1,5 @@
#include <thread> #include <thread>
#include <clocale>
#include "Config.h" #include "Config.h"
#include "Daemon.h" #include "Daemon.h"
#include "util.h" #include "util.h"
@ -20,6 +21,7 @@ namespace i2p
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
SetConsoleCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251); SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian");
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;

View File

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

View File

@ -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;
if (from && from->GetTunnelPool ())
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel) // we have send it through an outbound tunnel
{
auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from);
if (from) // received through an inbound tunnel
{
std::shared_ptr<i2p::tunnel::OutboundTunnel> tunnel;
if (from->GetTunnelPool ())
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
else
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
if (tunnel) // we have send it through an outbound tunnel
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
}
else else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); 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;
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; break;
}
default: default:
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
} }

108
Gzip.cpp Normal file
View File

@ -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 Normal file
View File

@ -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__ */

View File

@ -81,7 +81,8 @@ namespace http {
} }
/* user[:pass] */ /* user[:pass] */
pos_c = url.find('@', pos_p); pos_c = url.find('@', pos_p);
if (pos_c != std::string::npos) { std::size_t pos_slash = url.find('/', pos_p);
if (pos_c != std::string::npos && (pos_slash == std::string::npos || pos_slash > pos_c)) {
std::size_t delim = url.find(':', pos_p); std::size_t delim = url.find(':', pos_p);
if (delim != std::string::npos && delim < pos_c) { if (delim != std::string::npos && delim < pos_c) {
user = url.substr(pos_p, delim - pos_p); user = url.substr(pos_p, delim - pos_p);
@ -276,7 +277,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
View File

@ -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 {

View File

@ -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);
response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; /* TODO: don't redirect to webconsole, it's not always work, handle jumpservices here */
boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), i2p::config::GetOption("http.address", url.host);
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); 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());
std::string response = res.to_string();
boost::asio::async_write(*m_sock, boost::asio::buffer(response),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate) void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate)
{ {
m_state = nstate; 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,32 +198,21 @@ 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(' ');
m_request += m_path; m_request += m_path;
@ -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) {
{ LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
if (Kill()) return; HTTPRequestFailed("error when creating the stream, check logs");
LogPrint (eLogInfo, "HTTPProxy: New I2PTunnel connection"); return;
}
if (Kill())
return;
LogPrint (eLogDebug, "HTTPProxy: New I2PTunnel connection");
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream); auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, stream);
GetOwner()->AddHandler (connection); GetOwner()->AddHandler (connection);
connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size()); connection->I2PConnect (reinterpret_cast<const uint8_t*>(m_request.data()), m_request.size());
Done (shared_from_this()); Done (shared_from_this());
} }
else
{
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
HTTPRequestFailed(); // TODO: Send correct error message host unreachable
}
}
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

View File

@ -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

View File

@ -58,6 +58,9 @@ namespace http {
" .tunnel.another { color: #434343; }\r\n" " .tunnel.another { color: #434343; }\r\n"
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" " table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
" .private { background: black; color: black; } .private:hover { background: black; color: white } \r\n"
" .slide p, .slide [type='checkbox']{ display:none; } \r\n"
" .slide [type='checkbox']:checked ~ p { display:block; } \r\n"
"</style>\r\n"; "</style>\r\n";
const char HTTP_PAGE_TUNNELS[] = "tunnels"; const char HTTP_PAGE_TUNNELS[] = "tunnels";
@ -126,8 +129,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 <<
@ -201,6 +208,10 @@ namespace http {
s << numKBytesSent / 1024 / 1024 << " GiB"; s << numKBytesSent / 1024 / 1024 << " GiB";
s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)<br>\r\n";
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n"; s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n<br>\r\n";
s << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
s << "<b>Our external address:</b>" << "<br>\r\n" ; s << "<b>Our external address:</b>" << "<br>\r\n" ;
for (auto address : i2p::context.GetRouterInfo().GetAddresses()) for (auto address : i2p::context.GetRouterInfo().GetAddresses())
{ {
@ -223,6 +234,7 @@ namespace http {
} }
s << address->host.to_string() << ":" << address->port << "<br>\r\n"; s << address->host.to_string() << ":" << address->port << "<br>\r\n";
} }
s << "</p>\r\n</div>\r\n";
s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " "; s << "<br>\r\n<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " "; s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n"; s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
@ -612,7 +624,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);

View File

@ -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
View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -6,10 +6,15 @@ 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)
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
LDLIBS = -Wl,-Bstatic -lminiupnpc
endif
LDLIBS += \
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \
@ -32,12 +37,7 @@ ifeq ($(USE_WIN32_APP), yes)
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif endif
# UPNP Support ifeq ($(USE_AESNI),yes)
ifeq ($(USE_UPNP),1)
CXXFLAGS += -DUSE_UPNP
endif
ifeq ($(USE_AESNI),1)
CPU_FLAGS = -maes -DAESNI CPU_FLAGS = -maes -DAESNI
else else
CPU_FLAGS = -msse CPU_FLAGS = -msse

View File

@ -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

View File

@ -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 ();

View File

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

View File

@ -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"

View File

@ -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;

View File

@ -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++;
} }
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
ScheduleResend (); ScheduleResend ();
else
{
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
m_Session.Close ();
}
} }
} }

View File

@ -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;

View File

@ -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 ();
} }
} }

View File

@ -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;
@ -394,9 +394,12 @@ namespace stream
} }
} }
if (packets.size () > 0) if (packets.size () > 0)
{
if (m_SavedPackets.empty ()) // no NACKS
{ {
m_IsAckSendScheduled = false; m_IsAckSendScheduled = false;
m_AckSendTimer.cancel (); 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 Normal file
View File

@ -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__ */

View File

@ -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);
} }
} }

View File

@ -217,6 +217,7 @@ namespace tunnel
if (msg) if (msg)
{ {
m_NumReceivedBytes += msg->GetLength (); m_NumReceivedBytes += msg->GetLength ();
msg->from = shared_from_this ();
HandleI2NPMessage (msg); HandleI2NPMessage (msg);
} }
} }
@ -768,6 +769,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)
return CreateTunnel<InboundTunnel>(config, outboundTunnel);
else
return CreateZeroHopsInboundTunnel ();
}
std::shared_ptr<OutboundTunnel> Tunnels::CreateOutboundTunnel (std::shared_ptr<TunnelConfig> config)
{
if (config)
return CreateTunnel<OutboundTunnel>(config);
else
return CreateZeroHopsOutboundTunnel ();
}
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel) void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel)
{ {
m_PendingInboundTunnels[replyMsgID] = tunnel; m_PendingInboundTunnels[replyMsgID] = tunnel;
@ -815,20 +832,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 +880,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
} }
} }

View File

@ -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:

View File

@ -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

View File

@ -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 ();
@ -388,10 +389,17 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnels: Creating destination inbound tunnel..."); LogPrint (eLogDebug, "Tunnels: Creating destination inbound tunnel...");
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
if (SelectPeers (peers, true)) if (SelectPeers (peers, true))
{
std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0)
{ {
std::reverse (peers.begin (), peers.end ()); std::reverse (peers.begin (), peers.end ());
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig> (peers), outboundTunnel); config = std::make_shared<TunnelConfig> (peers);
}
auto tunnel = tunnels.CreateInboundTunnel (config, 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 +411,12 @@ 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); std::shared_ptr<TunnelConfig> config;
if (m_NumInboundHops > 0) config = std::make_shared<TunnelConfig>(tunnel->GetPeers ());
auto newTunnel = tunnels.CreateInboundTunnel (config, outboundTunnel);
newTunnel->SetTunnelPool (shared_from_this()); newTunnel->SetTunnelPool (shared_from_this());
if (newTunnel->IsEstablished ()) // zero hops
TunnelCreated (newTunnel);
} }
void TunnelPool::CreateOutboundTunnel () void TunnelPool::CreateOutboundTunnel ()
@ -418,9 +430,13 @@ 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> ( std::shared_ptr<TunnelConfig> config;
std::make_shared<TunnelConfig> (peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())); if (m_NumOutboundHops > 0)
config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto tunnel = tunnels.CreateOutboundTunnel (config);
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 +453,13 @@ 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> ( std::shared_ptr<TunnelConfig> config;
std::make_shared<TunnelConfig> (tunnel->GetPeers (), if (m_NumOutboundHops > 0)
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())); config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ());
auto newTunnel = tunnels.CreateOutboundTunnel (config);
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 +468,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 ());
} }
} }

View File

@ -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 ("libminiupnpc.dll"); // from MSYS2
#else
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
#endif
if (m_Module == NULL)
{
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
return;
}
else
{
upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover);
UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD);
UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress);
UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping);
UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping);
freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist);
FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls);
if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc &&
UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc)
m_IsModuleLoaded = true;
}
}
m_Thread = new std::thread (std::bind (&UPnP::Run, this)); 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
View File

@ -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
}; };
} }
} }

View File

@ -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
View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -41,7 +41,7 @@ All options below still possible in cmdline, but better write it in config file:
* --http.pass= - Password for basic auth (default: random, see logs) * --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

View File

@ -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 Normal file
View File

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

View File

@ -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 Normal file
View File

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

View File

@ -1,9 +1,3 @@
#-------------------------------------------------
#
# Project created by QtCreator 2016-06-14T04:53:04
#
#-------------------------------------------------
QT += core gui QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
@ -11,120 +5,52 @@ 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 \
../../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 FORMS += mainwindow.ui
@ -138,42 +64,43 @@ 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 \ INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$OPENSSL_PATH/openssl-1.0.2/include \ $$OPENSSL_PATH/openssl-1.0.2/include \
$$MINIUPNP_PATH/miniupnp-2.0/include \
$$IFADDRS_PATH $$IFADDRS_PATH
DISTFILES += \ DISTFILES += android/AndroidManifest.xml
android/AndroidManifest.xml
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
SOURCES += $$IFADDRS_PATH/ifaddrs.c
HEADERS += $$IFADDRS_PATH/ifaddrs.h
equals(ANDROID_TARGET_ARCH, armeabi-v7a){ equals(ANDROID_TARGET_ARCH, armeabi-v7a){
DEFINES += ANDROID_ARM7A DEFINES += ANDROID_ARM7A
# http://stackoverflow.com/a/30235934/529442 # http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
-lboost_system-gcc-mt-1_53 \ -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_date_time-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \ -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \
-lboost_program_options-gcc-mt-1_53 \ -L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc
-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.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){ equals(ANDROID_TARGET_ARCH, x86){
# http://stackoverflow.com/a/30235934/529442 # http://stackoverflow.com/a/30235934/529442
LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
-lboost_system-gcc-mt-1_53 \ -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \
-lboost_date_time-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \ -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \
-lboost_program_options-gcc-mt-1_53 \ -L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc
-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a
@ -181,12 +108,21 @@ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.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 \ 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 $$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 Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -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,30 +31,132 @@ 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(); close();
QApplication::instance()->quit(); QApplication::instance()->quit();
} }
void MainWindow::handleGracefulQuitButton() {
qDebug("Graceful Quit pressed.");
gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0));
gracefulQuitButton->setEnabled(false);
gracefulQuitButton->adjustSize();
verticalLayoutWidget->adjustSize();
i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels
QTimer::singleShot(10*60*1000/*millis*/, this, SLOT(handleGracefulQuitTimerEvent()));
}
void MainWindow::handleGracefulQuitTimerEvent() {
qDebug("Hiding the main window");
#ifndef ANDROID
quitting=true;
#endif
close();
qDebug("Performing quit");
QApplication::instance()->quit();
}
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
qDebug("Destroying main window"); qDebug("Destroying main window");

View File

@ -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

View File

@ -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>

View File

@ -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 Normal file
View File

@ -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;
}

View File

@ -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);

View File

@ -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 */