mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	Merge remote-tracking branch 'purple/openssl'
This commit is contained in:
		
						commit
						0f9376e959
					
				
					 35 changed files with 952 additions and 229 deletions
				
			
		| 
						 | 
				
			
			@ -159,7 +159,7 @@ namespace client
 | 
			
		|||
 | 
			
		||||
	int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
 | 
			
		||||
	{
 | 
			
		||||
		if (addresses.size() == 0) {
 | 
			
		||||
		if (addresses.empty()) {
 | 
			
		||||
			LogPrint(eLogWarning, "Addressbook: not saving empty addressbook");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										86
									
								
								ChangeLog
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								ChangeLog
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
# for this file format description,
 | 
			
		||||
# see https://github.com/olivierlacan/keep-a-changelog
 | 
			
		||||
 | 
			
		||||
## [2.8.0] - UNRELEASED
 | 
			
		||||
### Changed
 | 
			
		||||
- Proxy refactoring & speedup
 | 
			
		||||
- I2PControl refactoring & fixes (proper jsonrpc responses on errors)
 | 
			
		||||
- boost::regex no more needed
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
- initscripts: added openrc one, in sysv-ish make I2PD_PORT optional
 | 
			
		||||
 | 
			
		||||
## [2.7.0] - 2016-05-18
 | 
			
		||||
### Added
 | 
			
		||||
- Precomputed El-Gamal/DH tables
 | 
			
		||||
- Configurable limit of transit tunnels
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Speed-up of assymetric crypto for non-x64 platforms
 | 
			
		||||
- Refactoring of web-console
 | 
			
		||||
 | 
			
		||||
## [2.6.0] - 2016-03-31
 | 
			
		||||
### Added
 | 
			
		||||
- Gracefull shutdown on SIGINT
 | 
			
		||||
- Numeric bandwidth limits (was: by router class)
 | 
			
		||||
- Jumpservices in web-console
 | 
			
		||||
- Logging to syslog
 | 
			
		||||
- Tray icon for windows application
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Logs refactoring
 | 
			
		||||
- Improved statistics in web-console
 | 
			
		||||
 | 
			
		||||
### Deprecated:
 | 
			
		||||
- Renamed main/tunnels config files (will use old, if found, but emits warning)
 | 
			
		||||
 | 
			
		||||
## [2.5.1] - 2016-03-10
 | 
			
		||||
### Fixed
 | 
			
		||||
- Doesn't create ~/.i2pd dir if missing
 | 
			
		||||
 | 
			
		||||
## [2.5.0] - 2016-03-04
 | 
			
		||||
### Added
 | 
			
		||||
- IRC server tunnels
 | 
			
		||||
- SOCKS outproxy support
 | 
			
		||||
- Support for gzipped addressbook updates
 | 
			
		||||
- Support for router families
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Shared RTT/RTO between streams
 | 
			
		||||
- Filesystem work refactoring
 | 
			
		||||
 | 
			
		||||
## [2.4.0] - 2016-02-03
 | 
			
		||||
### Added
 | 
			
		||||
- X-I2P-* headers for server http-tunnels
 | 
			
		||||
- I2CP options for I2P tunnels
 | 
			
		||||
- Show I2P tunnels in webconsole
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Refactoring of cmdline/config parsing
 | 
			
		||||
 | 
			
		||||
## [2.3.0] - 2016-01-12
 | 
			
		||||
### Added
 | 
			
		||||
- Support for new router bandwidth class codes (P and X)
 | 
			
		||||
- I2PControl supports external webui
 | 
			
		||||
- Added --pidfile and --notransit parameters
 | 
			
		||||
- Ability to specify signature type for i2p tunnel
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Fixed multiple floodfill-related bugs
 | 
			
		||||
- New webconsole layout
 | 
			
		||||
 | 
			
		||||
## [2.2.0] - 2015-12-22
 | 
			
		||||
### Added
 | 
			
		||||
- Ability to connect to router without ip via introducer
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Persist temporary encryption keys for local destinations
 | 
			
		||||
- Performance improvements for EdDSA
 | 
			
		||||
- New addressbook structure
 | 
			
		||||
 | 
			
		||||
## [2.1.0] - 2015-11-12
 | 
			
		||||
### Added
 | 
			
		||||
- Implementation of EdDSA
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- EdDSA is default signature type for new RouterInfos
 | 
			
		||||
| 
						 | 
				
			
			@ -114,6 +114,24 @@ namespace client
 | 
			
		|||
			}
 | 
			
		||||
		} 
 | 
			
		||||
 | 
			
		||||
		// I2CP
 | 
			
		||||
		bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp);
 | 
			
		||||
		if (i2cp) 
 | 
			
		||||
		{
 | 
			
		||||
			std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr);
 | 
			
		||||
			uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort);
 | 
			
		||||
			LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort);
 | 
			
		||||
			try 
 | 
			
		||||
			{
 | 
			
		||||
				m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort);
 | 
			
		||||
			  	m_I2CPServer->Start ();
 | 
			
		||||
			} 
 | 
			
		||||
			catch (std::exception& e) 
 | 
			
		||||
			{
 | 
			
		||||
				LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
 | 
			
		||||
			}
 | 
			
		||||
		} 
 | 
			
		||||
 | 
			
		||||
		m_AddressBook.StartResolvers ();	
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -165,6 +183,14 @@ namespace client
 | 
			
		|||
			m_BOBCommandChannel = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (m_I2CPServer)
 | 
			
		||||
		{
 | 
			
		||||
			LogPrint(eLogInfo, "Clients: stopping I2CP");
 | 
			
		||||
			m_I2CPServer->Stop ();
 | 
			
		||||
			delete m_I2CPServer; 
 | 
			
		||||
			m_I2CPServer = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		LogPrint(eLogInfo, "Clients: stopping AddressBook");
 | 
			
		||||
		m_AddressBook.Stop ();		
 | 
			
		||||
		for (auto it: m_Destinations)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,6 +178,13 @@ namespace config {
 | 
			
		|||
      ("bob.port",            value<uint16_t>()->default_value(2827),                     "BOB listen port")
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
	options_description i2cp("I2CP options");
 | 
			
		||||
    i2cp.add_options()
 | 
			
		||||
      ("i2cp.enabled",        value<bool>()->default_value(false),                        "Enable or disable I2CP")
 | 
			
		||||
      ("i2cp.address",        value<std::string>()->default_value("127.0.0.1"),           "I2CP listen address")
 | 
			
		||||
      ("i2cp.port",            value<uint16_t>()->default_value(7654),                     "I2CP listen port")
 | 
			
		||||
      ;
 | 
			
		||||
 | 
			
		||||
    options_description i2pcontrol("I2PControl options");
 | 
			
		||||
    i2pcontrol.add_options()
 | 
			
		||||
      ("i2pcontrol.enabled",  value<bool>()->default_value(false),                        "Enable or disable I2P Control Protocol")
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +214,7 @@ namespace config {
 | 
			
		|||
      .add(socksproxy)
 | 
			
		||||
      .add(sam)
 | 
			
		||||
      .add(bob)
 | 
			
		||||
	  .add(i2cp)	
 | 
			
		||||
      .add(i2pcontrol)
 | 
			
		||||
	  .add(precomputation) 	  
 | 
			
		||||
      ;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								Config.h
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								Config.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -68,7 +68,7 @@ namespace config {
 | 
			
		|||
   * @param  value Variable where to store option
 | 
			
		||||
   * @return this function returns false if parameter not found
 | 
			
		||||
   *
 | 
			
		||||
   * @example  uint16_t port; GetOption("sam.port", port);
 | 
			
		||||
   * Example: uint16_t port; GetOption("sam.port", port);
 | 
			
		||||
   */
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool GetOption(const char *name, T& value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ namespace config {
 | 
			
		|||
   * @param  value New parameter value
 | 
			
		||||
   * @return true if value set up successful, false otherwise
 | 
			
		||||
   *
 | 
			
		||||
   * @example uint16_t port = 2827; SetOption("bob.port", port);
 | 
			
		||||
   * Example: uint16_t port = 2827; SetOption("bob.port", port);
 | 
			
		||||
   */
 | 
			
		||||
  template<typename T>
 | 
			
		||||
  bool SetOption(const char *name, const T& value) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,10 +45,10 @@ namespace i2p
 | 
			
		|||
#endif	
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
 | 
			
		||||
		Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {}
 | 
			
		||||
		Daemon_Singleton::~Daemon_Singleton() {
 | 
			
		||||
			delete &d;
 | 
			
		||||
		};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool Daemon_Singleton::IsService () const
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								Daemon.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Daemon.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -22,9 +22,7 @@ namespace i2p
 | 
			
		|||
			virtual bool stop();
 | 
			
		||||
			virtual void run () {};
 | 
			
		||||
 | 
			
		||||
			bool isLogging;
 | 
			
		||||
			bool isDaemon;
 | 
			
		||||
 | 
			
		||||
			bool running;
 | 
			
		||||
 | 
			
		||||
		protected:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ namespace i2p
 | 
			
		|||
	{
 | 
			
		||||
		bool DaemonLinux::start()
 | 
			
		||||
		{
 | 
			
		||||
			if (isDaemon == 1)
 | 
			
		||||
			if (isDaemon)
 | 
			
		||||
			{
 | 
			
		||||
				pid_t pid;
 | 
			
		||||
				pid = fork();
 | 
			
		||||
| 
						 | 
				
			
			@ -73,10 +73,10 @@ namespace i2p
 | 
			
		|||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// close stdin/stdout/stderr descriptors
 | 
			
		||||
				freopen("/dev/null", "r", stdin);
 | 
			
		||||
				freopen("/dev/null", "w", stdout);
 | 
			
		||||
				freopen("/dev/null", "w", stderr);
 | 
			
		||||
				// point std{in,out,err} descriptors to /dev/null
 | 
			
		||||
				stdin  = freopen("/dev/null", "r", stdin);
 | 
			
		||||
				stdout = freopen("/dev/null", "w", stdout);
 | 
			
		||||
				stderr = freopen("/dev/null", "w", stderr);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Pidfile
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ namespace i2p
 | 
			
		|||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (isDaemon == 1)
 | 
			
		||||
			if (isDaemon)
 | 
			
		||||
			{
 | 
			
		||||
				LogPrint(eLogDebug, "Daemon: running as service");
 | 
			
		||||
				I2PService service(SERVICE_NAME);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,7 +168,6 @@ namespace client
 | 
			
		|||
			
 | 
			
		||||
			// implements LocalDestination		
 | 
			
		||||
			const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
 | 
			
		||||
			const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
 | 
			
		||||
			std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };			
 | 
			
		||||
 | 
			
		||||
		protected:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								HTTP.cpp
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								HTTP.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -406,11 +406,10 @@ namespace http {
 | 
			
		|||
 | 
			
		||||
  bool MergeChunkedResponse (std::istream& in, std::ostream& out) {
 | 
			
		||||
    std::string hexLen;
 | 
			
		||||
    long int len;
 | 
			
		||||
    while (!in.eof ()) {
 | 
			
		||||
      std::getline (in, hexLen);
 | 
			
		||||
      errno = 0;
 | 
			
		||||
      len = strtoul(hexLen.c_str(), (char **) NULL, 16);
 | 
			
		||||
      long int len = strtoul(hexLen.c_str(), (char **) NULL, 16);
 | 
			
		||||
      if (errno != 0)
 | 
			
		||||
        return false; /* conversion error */
 | 
			
		||||
      if (len == 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								HTTP.h
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								HTTP.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -38,7 +38,7 @@ namespace http {
 | 
			
		|||
     * @brief Tries to parse url from string
 | 
			
		||||
     * @return true on success, false on invalid url
 | 
			
		||||
     */
 | 
			
		||||
    bool parse (const char *str, size_t len = 0);
 | 
			
		||||
    bool parse (const char *str, std::size_t len = 0);
 | 
			
		||||
    bool parse (const std::string& url);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -89,10 +89,12 @@ namespace http {
 | 
			
		|||
    std::string version;
 | 
			
		||||
    std::string status;
 | 
			
		||||
    unsigned short int code;
 | 
			
		||||
    /** simplifies response generation
 | 
			
		||||
     * If this variable is set:
 | 
			
		||||
     * a) Content-Length header will be added if missing
 | 
			
		||||
     * b) contents of body will be included in response
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Simplifies response generation
 | 
			
		||||
     *
 | 
			
		||||
     * If this variable is set, on @a to_string() call:
 | 
			
		||||
     *   * Content-Length header will be added if missing,
 | 
			
		||||
     *   * contents of @a body will be included in generated response
 | 
			
		||||
     */
 | 
			
		||||
    std::string body;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,9 +110,9 @@ namespace http {
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Serialize HTTP response to string
 | 
			
		||||
     * @note If version is set to HTTP/1.1, and Date header is missing,
 | 
			
		||||
     * @note If @a version is set to HTTP/1.1, and Date header is missing,
 | 
			
		||||
     *   it will be generated based on current time and added to headers
 | 
			
		||||
     * @note If body member is set and Content-Length header is missing,
 | 
			
		||||
     * @note If @a body is set and Content-Length header is missing,
 | 
			
		||||
     *   this header will be added, based on body's length
 | 
			
		||||
     */
 | 
			
		||||
    std::string to_string();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										152
									
								
								HTTPServer.cpp
									
										
									
									
									
								
							
							
						
						
									
										152
									
								
								HTTPServer.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -27,156 +27,6 @@
 | 
			
		|||
 | 
			
		||||
namespace i2p {
 | 
			
		||||
namespace http {
 | 
			
		||||
	const char *itoopieImage =
 | 
			
		||||
		"<img alt=\"ICToopie Icon\" src=\"data:image/png;base64,"
 | 
			
		||||
		"iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXM"
 | 
			
		||||
		"AAA3XAAAN1wFCKJt4AAAAB3RJTUUH3ggRChYFXVBoSgAAIABJREFUeNrtnXl8VOX1/9/PvXcmewiQBB"
 | 
			
		||||
		"J2CKsKihQXkCJuiD8VKyptXejXaikWbe1C1dqi0lpr7UvrgihV64ZCXaqCUBEUQVBAAZUl7EtYEkLIP"
 | 
			
		||||
		"pmZ+zy/P+6dySx3JgESkpAcX/MiznLvc8/5POc55zznnAfaqFWTaIXPnAt0AzoBqYAB1AAVwAFgF3Ck"
 | 
			
		||||
		"DQCnBvUHxgEXAMOBLsfw22+BT4ElwGKgrE1ftAwaBswEygFlv+QJvALX2AH8BchrY3HzpF8A+xtA4PU"
 | 
			
		||||
		"BwxZgUhvLmwf9AfA1suBjgaEK+GWbDdA0dAswC0iwhVEvSk5A9smFThmIjFSUroPHC0cr0HYexNxTiH"
 | 
			
		||||
		"aMfBFAiT2e99sA0PiUBXwMnFEfwZ/ZB3n1eTDmTDh3IMKdgoYZoi8CXBCABhioA/uRn3+H+OgreGcFq"
 | 
			
		||||
		"vAoWj15udQ2Oj1tAGgcmgS8WJfgczsif3sd3D4OkZyCZnqPQUWEkKaBlgDbd2PO+gDx5H/B462TZwq4"
 | 
			
		||||
		"zPYc2gDQgPQmcH084Z/eE/nkHYjRw9H8VQ17c02A5ka99j/kb59DHDgSl3cC+BswrQ0AJ04GsB4YFEv"
 | 
			
		||||
		"47VJQr/8eNW4kuv8kKF8jEfXSfOSUf6JVe+PydhEwtg0Ax0/Jtv+dHesLU65EPn0Xmt/XJM+ibn0M8+"
 | 
			
		||||
		"XF6HH4+xVwdhsAjp0Sgb1AB6dxCoH67B+oEaeh+80mVE8GLP0a8+LfI6R05KcA1gFntQHg2GgX0N3pg"
 | 
			
		||||
		"87tkd/NRktPbj7jr/SghkxG7j7k6DEI23O5uLkxWWumwl8WS/i9OmPueQ3RnIQPkJKI2PUq+jkDgs5l"
 | 
			
		||||
		"pGdwEfDPNgDUTQ9hbd5EUfds5PZ/owvRPIHr98Oqp9EvHBITBFOBa9qWgNg0FFjrZO1npKIOvgm61my"
 | 
			
		||||
		"1Vq1d4IbhP0euzo9pE3TAih62ASCCioH2TrNn72vQuUPzF34QBDoqdyLywBHHMa+zwd62BITQX+yZEU"
 | 
			
		||||
		"X/uR+V04TCN9ygFOaafNTbyzHnLsNc9g3S60ca7hjLgYlY9yxajNjFWcBNbRqgltKBUidmTRiFnPcnd"
 | 
			
		||||
		"L9DwEUI0JNgz17k5xuRBYfRvX7I6YD8/mBEr+5o/uoTEHwC6vn3UE+9h9qwwxmAw/oh/3or4qJhaE5j"
 | 
			
		||||
		"fGcF5vUzHH/rtV3dNgBgxfdvcfL1a+YjhIgep6Ej/zYX+eg8tMOlzs/RLQv52M/gujHo/pr6D0bXYG0"
 | 
			
		||||
		"+5iX3II5W1I9Hlw/HnP8Qhimjtce432N+uDoKBAJ4AJje2gHQDjjqNPtn34265ZJwxmkarMnHvOi3iA"
 | 
			
		||||
		"pP/cY/5izkx4/UL2CkaTBvGf6Jfw6L7gXus/aCCy4YcujQoZL8/HzdXrKC4x7UHfXdbLTI+1TXINPHO"
 | 
			
		||||
		"/JbNLUMmoMNMN1J+DkdkLdeGc4cXYO3l+M/ZypaiPAFsHvMmDFFl1122ZoxY8Zsyc7OLgxl7JKv0YZM"
 | 
			
		||||
		"RhquugezJh8zQvjmpEmT9hUWFuYrpc5etmyZsWXLliylVOLs2bPXCyFKA/fauAcxfjr+SLsgORHtjz+"
 | 
			
		||||
		"OuYl1F62c/Dhk3My5F7/vQ1Toa8XjmIHPhRAK2L1w4cIDSimPiqCCgoJdI0aM2EtIptAtl+BTH4VfM/"
 | 
			
		||||
		"SlPkalJ9feIyEhQa5fv36Nik/Fffv2LbHHIwH5v4ejx24uQkLttUNe+1uz8K/CIZUrIxVTLUWGMXAhM"
 | 
			
		||||
		"tFdK/y8vLzNSimzDuGo++67b37oPdY8HS2cwOuZqWECqtm0adNaVT86AhQEftuvK361NAIAC1G/uc4R"
 | 
			
		||||
		"AAo4s7UuAT9xUv+/uQ5l1tSqcE3A/f9GeWwru127dnu2bt3auz7jnzFjxriJEyeuEkIIgDufRjm5boY"
 | 
			
		||||
		"bZn4QHIuYPn367gEDBtTXV2+/atWqI4GlIH8f2uYdhFkCUsG06x1/q2jCBNOmNgKVEwDK/otKctcK10"
 | 
			
		||||
		"hEuS5G+U3LaNq5c2dhz549s4/hPj4hxFEgE6BoHmSkhj+7pmHqlwXvWaaUcmFtR9ebMjMzNxcXF/cHm"
 | 
			
		||||
		"DEJNe2GcIAabjhnCuaXW6KAexCrYKVVaQDH2TW8PzItNXxcK9cjbeGTnZ295xiFD+CaMmWKPwD4uZ9G"
 | 
			
		||||
		"g+7bnbX3vP766w8fq/ABpk2bFrTqV26ytorDjB0v3Oi8H5hje0OtCgCOrJh4ocWoUFqxsXac11xzzXG"
 | 
			
		||||
		"Nefz48cGrLvsWZUSkcBwuq00RHTNmzHFlGFx55ZU5gb93HUQ6cffakTG17oWtDQDnO6n/K8+JUs1s3x"
 | 
			
		||||
		"9cT8WgQYNkHdfdiVUVFEaDBw/2Bf7eVgCROTyGXntfl8t1XBmFOTk5e4O+vxflJOrcXLTUxKjdQgWc0"
 | 
			
		||||
		"9oAcKZT5C+vdzjbBODzhwfqnC722Wef7cnMzNwthOglhEjMzMxct2HDhj1BARtG8CpHK6OF0yWz9u/8"
 | 
			
		||||
		"/PxOAEoppJSlU6ZM2dipU6cCIcSXEyZM2KaUKncaQ3l5eXrQHkhHd/T8vTDydEctcEZrA0CPyDfOykP"
 | 
			
		||||
		"hD2eOlJCdEXxPff7551FFmgsWLDg4atSorsXFxd3t2WQUFxcPGTJkSJeFCxceBti2bVtwoyk1CREpnD"
 | 
			
		||||
		"7dEQGj9IknnvABFBcXl+u6rs+cOXNQYWFhLvC9t956K0/TtIMQvee/fPny4FUHdEcqf/RDmyYM6VN/m"
 | 
			
		||||
		"+hUBUCa05uDutuhkgjdOLRvSFRvyZLIHcODV1xxRaxqHu3yyy/XgKqXXnopKI7enR3EZyLGnGnBwuPx"
 | 
			
		||||
		"dP/666935+Xl7QNSIpYqJYToO3Xq1PWRN3vooYeqA98dOwzNdFislILeOTENwVYDAEeXp1uWNUOi7IJ"
 | 
			
		||||
		"za4VbVFTUafXq1RtCZr+POFnDQIfbb7/962effbZdQDgjT7eyd8IsdB9MqQ09q6FDh3rKysoGOvquSq"
 | 
			
		||||
		"mnnnoqzGpftGjRVxs3buwf+MrE0bFd7JwOxLJjcloLABz3/TukoTktmwkuxPgRwVmohg8fHtQg+/btK"
 | 
			
		||||
		"60r1vD888+PCHXrbr7YWTjXjkHLzggKp59SKl5BUW9gD8CKFSu2jh07tm8AYPdMRCkVGwDtU2Omkbca"
 | 
			
		||||
		"ACThLGhHhvtNeGZqqLEoemVnZx+srKwsGjhwYHo9A04A/L9zUZkZzs/t98D8GfUPjuXn538+ZsyYb0e"
 | 
			
		||||
		"OHNkXq9sInTKQf/kpuowDHU3EvEdGawGA476cz4zN/OwMtNl3WxaCUkoVFRV1Sk1NTZg5c+aeY4k8vv"
 | 
			
		||||
		"w7hN8f+wvD+qH9YzL1iQPI/v37T1y6dOnpAYClJKK+eQ7N74v/Q1PGXAJcrQUAjiyqjJO9oxTcOg7jr"
 | 
			
		||||
		"7eGCSdtzpw5I6ln7eeqf0JaUvwZ7jfhVxMwnrmTuuINQa8By1CVB96AjLS6NUhI0CkKG60FAJVOb+4p"
 | 
			
		||||
		"wtTjjMjvg2k3YCx6GJmUEK3eY1G3LGT+i6hhfev3vH4f/OwK9J2voEYPiS+UIX2Q707HXDsLPSkBrT7"
 | 
			
		||||
		"rx/7imOOoONmCMJoIAMWOAChEF5qThx0+Q8eciV71PuqRNzGffg+xtyiaoalJyAuHwE8vR1w1yioaPZ"
 | 
			
		||||
		"YScSmhayba0sfQjpYhF3yJ2rwXUVqJmdkO47QeyEuGItLSrHzF+qacCQFbC1Ax3NZDJ1sQTbUbmGxrg"
 | 
			
		||||
		"TCZdEzHPPweRn0TOYUAPQHwYe4uRPj8kJwAudmAjoYv2t07YYYJazk67hnngot+g1yyzjE9zDjZy0BT"
 | 
			
		||||
		"bgc7bgXXLEBqIqab1OLJSIbkSzCrvVFayw+4W4sNAFbxZxR9/DWnNB04gHQQPlhl5LQmAKx3evO9ldY"
 | 
			
		||||
		"O4KlK76+KaYqsbG0AWO20BL35CWiJp6bwDRe8sTTmUvxxawOAIytKKtBWf4N5KgLA40EuXR+T5/NbGw"
 | 
			
		||||
		"A+j/XB0/+1agBONZr5flxtqFobAMBqohRF//4IzedvGoY0mvpPRP15Tkz1/3JTjaupAfCvWK7oA68it"
 | 
			
		||||
		"VOol/m8j5HFZTHd7tlNNa7mwOJYcT9VMx+haS2/pb2RiOr8A9ShEsdnWYjVXbRVagCAR2IAUdz+BKbR"
 | 
			
		||||
		"wkNCQsATc5ExhC+AGU06vmbAowSs3rqOa/6GWaiB3WmxJmGlB5lxTUxeb8U61ILWrAFqgEdjgfHSe1C"
 | 
			
		||||
		"Gq2UK30hAjbsvpvAF8KumHmNzmVnTsGLhUXTwCNqND+NvaSDQNXj4VczPN8bUspuABU0+zmbEs93EaK"
 | 
			
		||||
		"H2zU60HlmYZ+WhqRbiHK74DnnTIzEnmMCqjDrU1ONsbhb2GuLkxy97DHX+ac0fBNv2Yw68NW73D59t+"
 | 
			
		||||
		"zQ5NTfjamw8UI76NWLtVqRoxo7hzoP4T7utztYvbqyDrZp+qWpm/KvCSrUeH+sLsz9EDO+PHNANTTYj"
 | 
			
		||||
		"TaAJWL8D84zb0eKlhIfQ97CaSnzVBoBwWgecS5zj2V5fitAE8sJhCGk2/TJmuOHVxcjL7zvm84ausgG"
 | 
			
		||||
		"/rs0GAObOhQ8+QLz8Msp2D+Pa/qMGIz/8M8JtNGETSRfqhzMw3/jkuCeTAO4B/tpmBAJCMFIpXsc63r"
 | 
			
		||||
		"VOJa8J1CvTUD+67OScFhI665evx3/FH9DKqsL4qM7nbDqSIQ9QqK3hm/rwWQBPY5192GoB4BaCuUpxN"
 | 
			
		||||
		"cexNTq0L2r5P8DVyNrAcMGuA6jJT6AWrQnn37WMlT/kKg2UkCh0NHR01vKt+ojP1CrW1XXO0HvA1a0R"
 | 
			
		||||
		"AFcC79ZzPMECzsgPrj4P+e4DDX+CSKAl7RfrMR94BSK7fmbTUT3Ar0QmGULGwK6Ojh+/eoV31XyWiDj"
 | 
			
		||||
		"PtpwY7fJPVQC8BfxACOKWYuaQLccx2ncOZ/o6kam2sUu7h0dTvCFFRmf0Qm6Y7dxXONCvxzTrl9ZtGJ"
 | 
			
		||||
		"anvnkr5pyl8NwCKyoZ7beOkrfzQ91H/fLPNTQKOCin8VdR41wgJbDyA88/1QEwGPiEOgoiu5Erf8r1n"
 | 
			
		||||
		"rMY5K+mJmy8bzI/4W0WBlOp774W+eht4YWZhhtmvYf8cDVKSkSfXNSg7ojeOaiMVLT0ZJQmrPMAj1bC"
 | 
			
		||||
		"7kPIrQVoq7cgF64BUzovKSkkq3uYrAaSp/uPI4Otkmp1O/fidwaOAOZhHZN3SgLgfuDBgBp3KrZIJkl"
 | 
			
		||||
		"N4UbPBXzP54kQfIDms9T9Mm8HI2oFc1DZIZW/moCH30D+4aWGe84cstRVXMJYRmlefCd0rU1sM6fzRL"
 | 
			
		||||
		"xw8R3AM41q05xkwacDn2L1BwqKPEL4YjyXem7mB14fPmIJX0Own0NB5o0dhszNQg+tzFWg/vDSiQ+6P"
 | 
			
		||||
		"e3UBQzjIkbQk66ahxpOVPgAQxio96OXmc9OJxAo2zN4HauZdosHwDXA20RUBIXO/q50lvcztaoD7ZSv"
 | 
			
		||||
		"DgYnkKDW8m1w/HeOR0SWZb++JLwGbzTnmns5oO2hAB9+R2AlkyS70ln0opsaSB8xmAGiI+21GrwoFB5"
 | 
			
		||||
		"qGowhXnxcw2XiEZ6N9RUFPAXc2JIB4Lbdm8siLfcQ4Ysfc7XnOsZ5a/Ai6+EF7qZAL6E0cCKHuvz88A"
 | 
			
		||||
		"JNw4B5n9UCII8e8lf8n2EiMdCRSFVOpfTiFQJBAm6VTpoukbqJiR8TZY+jIYUeSd9jcF3L049bMgBGA"
 | 
			
		||||
		"EvsiJ5ygncG6eoh7q7sRKaswVtvS/o9/ucOXHPCBSj8EZE4F+r9lbWz/xauFQFB2tpFuHHp7pBgYxXV"
 | 
			
		||||
		"nGwy0EV72vlLKNXrMJg3NMb9tUYE1hu2T+uKYeKIUWqY/wUeqcimo1THEPvREHzE58HrTr4SEen7L15"
 | 
			
		||||
		"VO/s7k6UGM6BZppVJJNl0rCuMvKElaYAJwNxYwZoA/VbdVnkeQ81o/1nV6Zx8wJKg8NOTURcNR4SWlB"
 | 
			
		||||
		"s6vLAo1Pi4tFHV+ImQAlzxxfBhS/IC/g3cHE/wncmSM/h1VRop6niEn0Sieo/FQd//l9egTE+EJtNRc"
 | 
			
		||||
		"2oLz9TFjBD+ZlptJoA4QSQBvNqY929ItTizLuFfxAjfs8yoSCNF1RWW0NAQCAo4qCXgVoHzIrexWy/m"
 | 
			
		||||
		"aFBl3j0hOkPovyHG32jORaKaLOCVSALVeKQ7Rum/hkYhxfH6Ec1pCRqgHzA5nvCvZaz3x4yvqcErnFW"
 | 
			
		||||
		"hItA9TUPjOV5P/IgVLstZEGoU3/MNYZD5DouCxt+lZyPbpYX7/oYBL1rHs+gAlzASWWe/p8aY2YJt7J"
 | 
			
		||||
		"YzeFJU4RG96Sb/zr1a5GzX0JTtzcRS/6olAOD78f1AF5OY4KmiWsRaCQPCr6BK/IoHU8qoDNn0UXzKl"
 | 
			
		||||
		"65P+TLMoPzNhGjfH5D/XWmpiySS1Bn016rxnHQAHKRI3sujwefdwV7xPkvkWEaFCXtP7CODBPBcY4+z"
 | 
			
		||||
		"oZaA5+NFq3T0uDo4FOJT+VOo8IO92CLzANuloi45L9pgeGtZ7VoymnOaxPhLJIFHmBX1/qesUu4Ip2g"
 | 
			
		||||
		"jW+PN8HdbCgAgTkJnNR7xBesNZ+FLBAINwYv8J6EKjwgLFMW42S+uQpkR5wYaBrywqPYnFzAM1QRFxl"
 | 
			
		||||
		"vZJQs4GMWLQooJPftaR+drNsYa4OsnY6wNCYAvgHtjgeBv4tmk6Li+InASvBu3WslaV9jMV+ERw9DWM"
 | 
			
		||||
		"VOvRkQaf6YfteDL4DOp0+jXJMbfmhhueyQYXRis5CvRVOq/MQJBD2PFrsMPfRDgVT5xFw+mxArzSqRI"
 | 
			
		||||
		"I1XhgCClrGtI25Yb0A3ZKSt67M8tqLX2hjMkZry/MUlHZyf7HD9zYYQ9/Vd8J2NMGA/WplmLA4C1jMP"
 | 
			
		||||
		"fIx9MAUcpE1P5U6qJiSL02RVevNzFT6rDIgKiFkChdONF0Y0ZjUR44t3ae57DmcJsAt9fR6OcCkfg+U"
 | 
			
		||||
		"JOw9DR+JgVsS7zwskab2OFR39rxwQEhG/3HqZETOa+1AqqRKTW60GuvIfJ1YrwXUKlwq8xfkT0rFm3G"
 | 
			
		||||
		"XPL3tr3z2+CAzgkUr3CO3IHex0/r6Raq8KjAEykWs6aWNb/yy0dAACvAGdBtBleQZW4nftSN7FN1yNS"
 | 
			
		||||
		"6Rdbvn/Y+h+6lAC8+jGyqgYZ6B1gGPDQa7UXGckw5cI4qeq/iCPyRu7mbRaJeJ7HS8yTblx8yCexwp5"
 | 
			
		||||
		"+2546aZHIBiUFbGCwGMIGFfSKrAcaDCgNEbrdKy5hpHcyP/J48XMXD6QWUiycMoSc3ptwAfLBW6wzhT"
 | 
			
		||||
		"In1D7L37mHbuSeTACom7hbefE5tX+NMnrGcaFawRpKKXca4zzghhYLgOD6Hf32UwLuUIE0sJDvJuKmM"
 | 
			
		||||
		"1nmLgr0+gg/8v9Tk5CV1bWnjbzPbGIHnRo+4vcOi8w5vB+qTcsmZVDR1UXKp5Uc+ayKHKxDMlQ95HEX"
 | 
			
		||||
		"8M8WuQTMJe52zi90xA9DPw58twYvuynQNa3W4g8FqF1rJ2JpglDhA5RSftKcfxcGK1gbVhiyrS/mUzl"
 | 
			
		||||
		"0mZZJxv960rtyIPLGduyq54Q7cjKXrgYFwAgeZ26Mh7yXnoYf9YaAoQJEQPjBYI/t5gUEnKzhfzKHzS"
 | 
			
		||||
		"t7oeZ2Y98vO7K/h5viyMJLJx37AUuUOEn5rjp6WDh3eBKHurnoEBiTX4GElOe70PPlLmyvBwgOt0gAf"
 | 
			
		||||
		"AK8wi/FDaDmhrw/i1xm00esQ8kXEDxiFUL2Ddh0gRkf+i8gHu7EnkkZDDg9Ee3yVLo+lE3u9jwyN+Wx"
 | 
			
		||||
		"9/I0CoK/dxjLG7wvKqk6KVogAmji0lQSvA539iuY0I4+d3TgmzpAcLBFAmA01llw07GS2QOa4Gfs51v"
 | 
			
		||||
		"2iwXsls+QIbrSTaym1zYXYriyNUGE8EFAoog+W7BaQVcX3d7uRtdNeRR1dVEYg5ni1/xZSRq/lYSIsK"
 | 
			
		||||
		"U6GbHz2kwFT+YwECiLc8k9LQ4AS4EPQNwMarptC1xvT843gMeplgB3YfIj9sov0LTpZH/lFlo7oCBU+"
 | 
			
		||||
		"EKgBKhfH8SbJJz3cf0WELJ29aP9be2d1eoRSsXPuFcVU6Ias9XgTvbJiLHFTe8yFUaqFiNQ0FJtgPsB"
 | 
			
		||||
		"RY9gHlhoOcvEoFrOEjdRpv5Cd93Axz5d4+IJsqJHD/KASiHANgeEUlCp6DpsJ4UaURGjIFVJ3E/m0Gd"
 | 
			
		||||
		"GNt85gaCMCjGFP/Im800dXWkNpPAEgkQS1Lfkq9/zSJgDtNWLHg9ufiitkPSOiaeTTKIhZr+HjqKAYv"
 | 
			
		||||
		"XTGN+5kgzxfxxVW+ijJZPAdo6I6jFKZp93iKLDaLNmcbEQLITa+kBbKwig9I4O+G/MgGGJVBjCPnNYw"
 | 
			
		||||
		"EEfe5ZXoS2qQH+9FFUl4x68qC5mBOczlNPoRwJuzY9JfcPFOjoJuNjJPrmElfyPzwKuZlixaprGgbKB"
 | 
			
		||||
		"5FZE6C6XgKMmBefuIHGXz/ngTKz0r5tbFAAA3gHtGpCRLuB0+/U4XfTVpMvz2MFWMrTNJJs3vbJTlJa"
 | 
			
		||||
		"h3XGHJQEhKFSKzIALGOYOKstWsOko1rk6qdQ2WjrmtT6T9rIX3UQvutGJTNWJTC2NFBJJUAKBDz8VVI"
 | 
			
		||||
		"rDlMj9HBJb2ckGtigPNYHQZTndkPTAoJCj5NMl4Nnel8XWGdlk+hUFm2vouaSSqldL8a6uJjcOz4WtP"
 | 
			
		||||
		"OfRUmgW8G8QHzJAADzChVHfeYw8A+AfZGiv0V+MI1sD+N3vLH1805AgQ2YLgRTWul/7r9VLuKlfgWqm"
 | 
			
		||||
		"EvpRwpWUcCc1/ALFFBQ/Zq/9eeT3Q1/1ucdJpxNKCfsZMJfB2uVsMDeBWMnSsIe4mk5iMO3Mn5OijaC"
 | 
			
		||||
		"repAj2gIKzUsvRf/7v5A/vxS9x3pLA2ga+UohlLKqdYMbQfFiqvG0mosictERwC4U0LGelxAYlNIZHT"
 | 
			
		||||
		"DRqKELKXTFSy7J+ElAEd7WsiNdSeMA5XQ+Xo1kz6eTTie0BCwgV4xjv3qZwdzMhmBk7zqgEz3FU+xSk"
 | 
			
		||||
		"8gWP6VQ/RGrRChAd16A/s/PLOHfMQV95rPcISVPaAIlVVDgIiLCHP85UijhdLycQRIppAeXdwMvGyhm"
 | 
			
		||||
		"KZmouKAXdOMw15KGP6SPX31ySqup4UU7sh0+VlHP8adgdUlrORpgHPvVJ8BoOwNGBE3Z03Czhz/QWXx"
 | 
			
		||||
		"qFWKJj6nNzX7sJsQXr1hsnTYNo8SDlJJUzT40Mij8qzmAi1QOotjHUUpIohQFpNm3KyWLJLpSzun4aU"
 | 
			
		||||
		"+P4MwMTRb14mYAOfSljH/hxU/HGI8kGUcy3uNo4phEAj+nmq8o5BAmAkEqCWThZxUGVTH7IAis+r+qF"
 | 
			
		||||
		"qcBAjQfxBUhCJ8IooLBKoES8RZ7w5B/xyC0nhmoHpeiCtpBUhJi8mSUYTBL+cVtZuhEuRZBp5CRavYr"
 | 
			
		||||
		"dE5Jju2oRZMynicZ6eCvp1PCJDpwoodNaiGawwCeZDvK0fUTWI2yf9dUdtwJO8ZzgSsi1NsboJLYpv0"
 | 
			
		||||
		"nQvgPno22dyOqqBi1Efjr47D4BWsM0i8GmPG0pLIF7QO89svHsZ+zqZPO2BgRxA54G6SEQIYsG5Y6i3"
 | 
			
		||||
		"XE/RtNKfwGAYBTD5Nr6KLNo0q+ZP//tN7wu3SE2o4amoc6+n2YPh2uGop+9W0BnqlBUbPDy+5Geeq+5"
 | 
			
		||||
		"JLqcH5xSj3X+2PncCz137WpPbkGzwi6jjOEQZW6DvgJML0DHDyI0HOgSqCOjIO1WxFTf4Lr7AtRN90W"
 | 
			
		||||
		"nMOZUVngnkaK4fqAc0iI0AKCdNo3+L0q2E3shpcjTzkAzOMbBTkqGM0YiOjTGfHwFtTi3jBnPaJfGVp"
 | 
			
		||||
		"7N77Jd1rzzdDEwGCMNSzWGzNiduLUz8Ho6tgIVSRVIaDSHTeKup5SALBAsLE2GrgC9ccdlqAPZSB67E"
 | 
			
		||||
		"XMWYt5ur3lcUMvhKlUXiD6F7bqF1HdaPs4brIhYonJaoQOEV5Sgi5gF6yMuHA6+5QDQPDJIh6tfwGs2"
 | 
			
		||||
		"YGcPhqu3w6fPoo41AuhFJmOFziA0WjtrCXQJWLvwN0oRYQq5C+N9ChLt+8pC4C1ayE3t/b/P95sPfz0"
 | 
			
		||||
		"T+BWgbjvPUR5KZLo42Ks0Gg57fFQ0iiDU4BOedh7+2PGB04k0lITtDUUGon4IxzZLqcsAAD2xyh+XeN"
 | 
			
		||||
		"DLP8MuXYtAEVhnnqot7++Eas7wqOCimWUNnjLjEi7xkVCRFQw7ZQGQCxav8FeC28HYEuYpx66ibKaZF"
 | 
			
		||||
		"z17B51rCGw0ohedKV0Ib+Bc/IOBw1LgUGNXa4sGjoY1+IAEGIkQWgihAjODs1eDJJZFzeF6vhIx0MZq"
 | 
			
		||||
		"VE6YSGJeBvIGHRhssIOBen4cJFIDUaEBiht3QB4KfjXUlsEwlacHpKosVVzCnoDLwV7KMHauCECfCm8"
 | 
			
		||||
		"SPkJc0YDlnGASjIAQXYwLhCph3a0bgDU0pwwdahIJBMdDRNFEkspaDBlqQFrHXoXdgFSUZhk8zrF6Mf"
 | 
			
		||||
		"ZD1YDNnOIr+kKKFLxkYKLcnwOu5Gr2wBg0b+i1PFhBN0QgORbulLaQD1ziznM7qDraYbxIweNZHwcoS"
 | 
			
		||||
		"MfUnbMRqEBrGIbi+kEKNz46GTnJRwOb5Nr0xdtAKh1/cJBUI2BH0V7u5Z8Dj70E8ycEVQx116HXUhyQ"
 | 
			
		||||
		"7Zt/HiQQC4GBpJtdGQ1+49B81TxNkWsIc/WYT664wI0SvDhj2oV9kJTM725nRmUjXWapgpzC/uisxMT"
 | 
			
		||||
		"PwbZ7OaH9Dgu5awo5jUSKSMZ8NMHHZBstwHREUmGHXoyMdll8+cHFNOZrLjTaC+FfEA6pp0QkoGfLFx"
 | 
			
		||||
		"IwIdkDypiwgmgE1DYlAxvbsfGVWIdFnVWGHtr8JGDzlEklbSngqP0JbHeO3cGUEARr5OMh2QAeqAF/y"
 | 
			
		||||
		"ulxj7ixyTN5omGhgs/lRhsQqMPB0iinQMHJYso5nOysGoC/HRB0Q6XvYUt7YBzpPDvp5G7gLZEDRAAZ"
 | 
			
		||||
		"U0UwzrjRaFxyF6VsyjiCjTS6Ri2/05YGOko24EVlFFK96Bm6YYXt531I4B9gMcWVx4ayr63AA7hpxwd"
 | 
			
		||||
		"8HIhRxlMeyRuNLx8w2E+IR1JKtauv4+sEDXvR7Eb6SD8X2CdBUAbAJzpOmqLjWupD4rDVFMa3GARJLC"
 | 
			
		||||
		"fXAyS8JBCd2oopgwfJeiU0t6e/9Z33fjJBfQQ004g2YZJID0uG5O0kM814ACSimCF8mEySeEwEiuDAF"
 | 
			
		||||
		"z46IwgwW4CJIBKajgQteYLrJPS/9ZcGN2MT+HlQ6wzBmopGS9dSKAUH4WIei5hVgQuE500jChNcRBJO"
 | 
			
		||||
		"aEF6X76YKAIL1IvwUsxRths1jDJQpJur/UBQB3G5Kij/yBsO6eouTDZaMYAqHJ4x025zfAUFEe/Nz35"
 | 
			
		||||
		"AAABiUlEQVTwUoHAjJppVk5vMpJ0dNwkhC0TGlCJj8OANyIeoDA4iEnnkJZe1sEGbtojqcCHHz8JGCT"
 | 
			
		||||
		"jQqIH+13VYHIAiT8uX4cAi9s0QHxKBKqDccGIM4VIwkMSbhLwY+BGpxrwIzAwcKHZwgv9XQ1evAiq0C"
 | 
			
		||||
		"hH2QEZFZMvafjojIGsg0cC6+yXIkyqo1LCnWgHcc5Fbn0AOA34zjEqeEM9x69C/lVYuwuh28surGNr6"
 | 
			
		||||
		"pOfH6kffWQCabijMv1N/FQgKMVPTdQOX11jfgbrRLBWTgMdATia+pVSncyyMB8JmCQiSUQFtdOJXfMn"
 | 
			
		||||
		"bRrAmcqD1vWpTQLoBexqykE0t3N0noCoLdpTlRQnsSFkS9AABlbCtqL1kKDVJ4TU0sWtzAISWAdptmk"
 | 
			
		||||
		"Am9phNX9QTcwD1cg8K8HqBLYO+FEbAMIpF3gc+AGNv1G1GPgSqzYgkKeTBmTar2ygg22TGHZgqgBYb/"
 | 
			
		||||
		"+mHGvzKrRS0R/yqsZq++6BRshpPMUDQcfzHFrIsqZHhWqasAtHc6b/D3cbSAuGcmWdAAAAAElFTkSuQmCC\" />";
 | 
			
		||||
 | 
			
		||||
	const char *itoopieFavicon =
 | 
			
		||||
		"data:image/png;base64,"
 | 
			
		||||
		"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv"
 | 
			
		||||
| 
						 | 
				
			
			@ -667,7 +517,7 @@ namespace http {
 | 
			
		|||
		i2p::config::GetOption("http.auth", needAuth);
 | 
			
		||||
		i2p::config::GetOption("http.user", user);
 | 
			
		||||
		i2p::config::GetOption("http.pass", pass);
 | 
			
		||||
	};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void HTTPConnection::Receive ()
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@
 | 
			
		|||
 | 
			
		||||
namespace i2p {
 | 
			
		||||
namespace http {
 | 
			
		||||
	extern const char *itoopieImage;
 | 
			
		||||
	extern const char *itoopieFavicon;
 | 
			
		||||
	const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;	
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										369
									
								
								I2CP.cpp
									
										
									
									
									
								
							
							
						
						
									
										369
									
								
								I2CP.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,7 +1,18 @@
 | 
			
		|||
/*
 | 
			
		||||
* 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 <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <openssl/rand.h>
 | 
			
		||||
#include "I2PEndian.h"
 | 
			
		||||
#include "Log.h"
 | 
			
		||||
#include "Timestamp.h"
 | 
			
		||||
#include "LeaseSet.h"
 | 
			
		||||
#include "I2CP.h"
 | 
			
		||||
 | 
			
		||||
namespace i2p
 | 
			
		||||
| 
						 | 
				
			
			@ -14,16 +25,112 @@ namespace client
 | 
			
		|||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
 | 
			
		||||
	{
 | 
			
		||||
		memcpy (m_EncryptionPrivateKey, key, 256);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t length = bufbe32toh (buf);
 | 
			
		||||
		if (length > len - 4) length = len - 4;
 | 
			
		||||
		m_Owner.SendMessagePayloadMessage (buf + 4, length);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) 
 | 
			
		||||
	{
 | 
			
		||||
		i2p::data::LocalLeaseSet ls (m_Identity, m_EncryptionPrivateKey, tunnels); // we don't care about encryption key
 | 
			
		||||
		m_LeaseSetExpirationTime = ls.GetExpirationTime ();
 | 
			
		||||
		uint8_t * leases = ls.GetLeases ();
 | 
			
		||||
		leases[-1] = tunnels.size ();
 | 
			
		||||
		htobe16buf (leases - 3, m_Owner.GetSessionID ());
 | 
			
		||||
		size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
 | 
			
		||||
		m_Owner.SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); 
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		auto ls = new i2p::data::LocalLeaseSet (m_Identity, buf, len);
 | 
			
		||||
		ls->SetExpirationTime (m_LeaseSetExpirationTime);
 | 
			
		||||
		SetLeaseSet (ls);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	void I2CPDestination::SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce)
 | 
			
		||||
	{
 | 
			
		||||
		auto msg = NewI2NPMessage ();
 | 
			
		||||
		uint8_t * buf = msg->GetPayload ();
 | 
			
		||||
		htobe32buf (buf, len);
 | 
			
		||||
		memcpy (buf + 4, payload, len);
 | 
			
		||||
		msg->len += len + 4; 
 | 
			
		||||
		msg->FillI2NPMessageHeader (eI2NPData);
 | 
			
		||||
		auto remote = FindLeaseSet (ident);
 | 
			
		||||
		if (remote)
 | 
			
		||||
			GetService ().post (std::bind (&I2CPDestination::SendMsg, GetSharedFromThis (), msg, remote));
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			auto s = GetSharedFromThis ();
 | 
			
		||||
			RequestDestination (ident,
 | 
			
		||||
				[s, msg, nonce](std::shared_ptr<i2p::data::LeaseSet> ls)
 | 
			
		||||
				{
 | 
			
		||||
					if (ls)
 | 
			
		||||
					{ 
 | 
			
		||||
						bool sent = s->SendMsg (msg, ls);
 | 
			
		||||
						s->m_Owner.SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
						s->m_Owner.SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet);
 | 
			
		||||
				});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool I2CPDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
 | 
			
		||||
	{
 | 
			
		||||
		auto outboundTunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
 | 
			
		||||
		auto leases = remote->GetNonExpiredLeases ();
 | 
			
		||||
		if (!leases.empty () && outboundTunnel)
 | 
			
		||||
		{
 | 
			
		||||
			std::vector<i2p::tunnel::TunnelMessageBlock> msgs;			
 | 
			
		||||
			uint32_t i = rand () % leases.size ();
 | 
			
		||||
			auto garlic = WrapMessage (remote, msg, true);
 | 
			
		||||
			msgs.push_back (i2p::tunnel::TunnelMessageBlock 
 | 
			
		||||
				{ 
 | 
			
		||||
					i2p::tunnel::eDeliveryTypeTunnel,
 | 
			
		||||
					leases[i]->tunnelGateway, leases[i]->tunnelID,
 | 
			
		||||
					garlic
 | 
			
		||||
				});
 | 
			
		||||
			outboundTunnel->SendTunnelDataMsg (msgs);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (outboundTunnel)
 | 
			
		||||
				LogPrint (eLogWarning, "I2CP: Failed to send message. All leases expired");
 | 
			
		||||
			else
 | 
			
		||||
				LogPrint (eLogWarning, "I2CP: Failed to send message. No outbound tunnels");
 | 
			
		||||
			return false;
 | 
			
		||||
		}	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
 | 
			
		||||
		m_Owner (owner), m_Socket (socket), 
 | 
			
		||||
		m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0)
 | 
			
		||||
		m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0),
 | 
			
		||||
		m_MessageID (0)
 | 
			
		||||
	{
 | 
			
		||||
		RAND_bytes ((uint8_t *)&m_SessionID, 2);
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	I2CPSession::~I2CPSession ()
 | 
			
		||||
	{
 | 
			
		||||
		delete[] m_NextMessage;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::Start ()
 | 
			
		||||
	{
 | 
			
		||||
		ReadProtocolByte ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I2CPSession::~I2CPSession ()
 | 
			
		||||
	void I2CPSession::Stop ()
 | 
			
		||||
	{
 | 
			
		||||
		delete[] m_NextMessage;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::ReadProtocolByte ()
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +209,12 @@ namespace client
 | 
			
		|||
 | 
			
		||||
	void I2CPSession::Terminate ()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_Destination)
 | 
			
		||||
		{
 | 
			
		||||
			m_Destination->Stop ();
 | 
			
		||||
			m_Destination = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
		m_Owner.RemoveSession (GetSessionID ());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
 | 
			
		||||
| 
						 | 
				
			
			@ -157,16 +270,258 @@ namespace client
 | 
			
		|||
 | 
			
		||||
	void I2CPSession::CreateSessionMessageHandler (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		// TODO
 | 
			
		||||
		m_Destination = std::make_shared<I2CPDestination>(*this, nullptr, false);
 | 
			
		||||
		auto identity = std::make_shared<i2p::data::IdentityEx>();
 | 
			
		||||
		size_t offset = identity->FromBuffer (buf, len);
 | 
			
		||||
		uint16_t optionsSize = bufbe16toh (buf + offset);
 | 
			
		||||
		offset += 2;
 | 
			
		||||
		// TODO: extract options
 | 
			
		||||
		offset += optionsSize;
 | 
			
		||||
		offset += 8; // date
 | 
			
		||||
		if (identity->Verify (buf, offset, buf + offset)) // signature
 | 
			
		||||
		{	
 | 
			
		||||
			m_Destination = std::make_shared<I2CPDestination>(*this, identity, false);
 | 
			
		||||
			m_Destination->Start ();
 | 
			
		||||
			SendSessionStatusMessage (1); // created
 | 
			
		||||
			LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " created");	
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			LogPrint (eLogError, "I2CP: create session signature verification falied");	
 | 
			
		||||
			SendSessionStatusMessage (3); // invalid
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I2CPServer::I2CPServer (const std::string& interface, int port)
 | 
			
		||||
	void I2CPSession::DestroySessionMessageHandler (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		SendSessionStatusMessage (0); // destroy
 | 
			
		||||
		LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " destroyed");
 | 
			
		||||
		Terminate ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendSessionStatusMessage (uint8_t status)
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t buf[3];
 | 
			
		||||
		htobe16buf (buf, m_SessionID);
 | 
			
		||||
		buf[2] = status;
 | 
			
		||||
		SendI2CPMessage (I2CP_SESSION_STATUS_MESSAGE, buf, 3); 
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status)
 | 
			
		||||
	{
 | 
			
		||||
		uint8_t buf[15];
 | 
			
		||||
		htobe16buf (buf, m_SessionID);
 | 
			
		||||
		htobe32buf (buf + 2, m_MessageID++);
 | 
			
		||||
		buf[6] = (uint8_t)status;
 | 
			
		||||
		memset (buf + 7, 0, 4); // size
 | 
			
		||||
		htobe32buf (buf + 11, nonce);	
 | 
			
		||||
		SendI2CPMessage (I2CP_MESSAGE_STATUS_MESSAGE, buf, 15); 	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		uint16_t sessionID = bufbe16toh (buf);
 | 
			
		||||
		if (sessionID == m_SessionID)
 | 
			
		||||
		{
 | 
			
		||||
			size_t offset = 2;
 | 
			
		||||
			if (m_Destination)
 | 
			
		||||
			{
 | 
			
		||||
				m_Destination->SetEncryptionPrivateKey (buf + offset);
 | 
			
		||||
				offset += 256;
 | 
			
		||||
				m_Destination->LeaseSetCreated (buf + offset, len - offset);
 | 
			
		||||
			}
 | 
			
		||||
		}	
 | 
			
		||||
		else
 | 
			
		||||
			LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		uint16_t sessionID = bufbe16toh (buf);
 | 
			
		||||
		if (sessionID == m_SessionID)
 | 
			
		||||
		{
 | 
			
		||||
			size_t offset = 2;
 | 
			
		||||
			if (m_Destination)
 | 
			
		||||
			{
 | 
			
		||||
				i2p::data::IdentityEx identity;
 | 
			
		||||
				offset += identity.FromBuffer (buf + offset, len - offset);
 | 
			
		||||
				uint32_t payloadLen = bufbe32toh (buf + offset);
 | 
			
		||||
				offset += 4;
 | 
			
		||||
				uint32_t nonce = bufbe32toh (buf + offset + payloadLen);
 | 
			
		||||
				SendMessageStatusMessage (nonce, eI2CPMessageStatusAccepted); // accepted
 | 
			
		||||
				m_Destination->SendMsgTo (buf + offset, payloadLen, identity.GetIdentHash (), nonce);
 | 
			
		||||
			} 
 | 
			
		||||
		}	
 | 
			
		||||
		else
 | 
			
		||||
			LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::HostLookupMessageHandler (const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		uint16_t sessionID = bufbe16toh (buf);
 | 
			
		||||
		if (sessionID == m_SessionID)
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t requestID = bufbe32toh (buf + 2);
 | 
			
		||||
			//uint32_t timeout = bufbe32toh (buf + 6);
 | 
			
		||||
			if (!buf[10]) // request type = 0 (hash)
 | 
			
		||||
			{
 | 
			
		||||
				if (m_Destination)
 | 
			
		||||
				{
 | 
			
		||||
					auto ls = m_Destination->FindLeaseSet (buf + 11);
 | 
			
		||||
					if (ls)
 | 
			
		||||
						SendHostReplyMessage (requestID, ls->GetIdentity ());
 | 
			
		||||
					else
 | 
			
		||||
					{
 | 
			
		||||
						auto s = shared_from_this ();
 | 
			
		||||
						m_Destination->RequestDestination (buf + 11,
 | 
			
		||||
							[s, requestID](std::shared_ptr<i2p::data::LeaseSet> leaseSet)
 | 
			
		||||
							{
 | 
			
		||||
								s->SendHostReplyMessage (requestID, leaseSet ? leaseSet->GetIdentity () : nullptr);
 | 
			
		||||
							});
 | 
			
		||||
					}		
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
					SendHostReplyMessage (requestID, nullptr);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				LogPrint (eLogError, "I2CP: request type ", (int)buf[8], " is not supported");
 | 
			
		||||
				SendHostReplyMessage (requestID, nullptr);
 | 
			
		||||
			}
 | 
			
		||||
		}	
 | 
			
		||||
		else
 | 
			
		||||
			LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity)
 | 
			
		||||
	{
 | 
			
		||||
		if (identity)
 | 
			
		||||
		{
 | 
			
		||||
			size_t l = identity->GetFullLen () + 7;
 | 
			
		||||
			uint8_t * buf = new uint8_t[l];
 | 
			
		||||
			htobe16buf (buf, m_SessionID);
 | 
			
		||||
			htobe32buf (buf + 2, requestID);
 | 
			
		||||
			buf[6] = 0; // result code
 | 
			
		||||
			identity->ToBuffer (buf + 7, l - 7);
 | 
			
		||||
			SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, l); 
 | 
			
		||||
			delete[] buf;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			uint8_t buf[7];
 | 
			
		||||
			htobe16buf (buf, m_SessionID);
 | 
			
		||||
			htobe32buf (buf + 2, requestID);
 | 
			
		||||
			buf[6] = 1; // result code
 | 
			
		||||
			SendI2CPMessage (I2CP_HOST_REPLY_MESSAGE, buf, 7); 
 | 
			
		||||
		}	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPSession::SendMessagePayloadMessage (const uint8_t * payload, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		// we don't use SendI2CPMessage to eliminate additional copy
 | 
			
		||||
		auto l = len + 10 + I2CP_HEADER_SIZE;
 | 
			
		||||
		uint8_t * buf = new uint8_t[l];
 | 
			
		||||
		htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10);
 | 
			
		||||
		buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE;
 | 
			
		||||
		htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID);
 | 
			
		||||
		htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++);
 | 
			
		||||
		htobe32buf (buf + I2CP_HEADER_SIZE + 6, len);		
 | 
			
		||||
		memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len);
 | 
			
		||||
		boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (),
 | 
			
		||||
        	std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), 
 | 
			
		||||
						std::placeholders::_1, std::placeholders::_2, buf));	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I2CPServer::I2CPServer (const std::string& interface, int port):
 | 
			
		||||
		m_IsRunning (false), m_Thread (nullptr),
 | 
			
		||||
		m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port))
 | 
			
		||||
	{
 | 
			
		||||
		memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers));
 | 
			
		||||
		m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler;
 | 
			
		||||
		m_MessagesHandlers[I2CP_CREATE_SESSION_MESSAGE ] = &I2CPSession::CreateSessionMessageHandler;	
 | 
			
		||||
		m_MessagesHandlers[I2CP_CREATE_SESSION_MESSAGE] = &I2CPSession::CreateSessionMessageHandler;
 | 
			
		||||
		m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler;
 | 
			
		||||
		m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler;
 | 
			
		||||
		m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler;
 | 
			
		||||
		m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler;	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	I2CPServer::~I2CPServer ()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_IsRunning)
 | 
			
		||||
			Stop ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::Start ()
 | 
			
		||||
	{
 | 
			
		||||
		Accept ();
 | 
			
		||||
		m_IsRunning = true;
 | 
			
		||||
		m_Thread = new std::thread (std::bind (&I2CPServer::Run, this));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::Stop ()
 | 
			
		||||
	{
 | 
			
		||||
		m_IsRunning = false;
 | 
			
		||||
		m_Acceptor.cancel ();
 | 
			
		||||
		for (auto it: m_Sessions)
 | 
			
		||||
			it.second->Stop ();
 | 
			
		||||
		m_Sessions.clear ();
 | 
			
		||||
		m_Service.stop ();
 | 
			
		||||
		if (m_Thread)
 | 
			
		||||
		{	
 | 
			
		||||
			m_Thread->join (); 
 | 
			
		||||
			delete m_Thread;
 | 
			
		||||
			m_Thread = nullptr;
 | 
			
		||||
		}	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::Run () 
 | 
			
		||||
	{ 
 | 
			
		||||
		while (m_IsRunning)
 | 
			
		||||
		{
 | 
			
		||||
			try
 | 
			
		||||
			{	
 | 
			
		||||
				m_Service.run ();
 | 
			
		||||
			}
 | 
			
		||||
			catch (std::exception& ex)
 | 
			
		||||
			{
 | 
			
		||||
				LogPrint (eLogError, "I2CP: runtime exception: ", ex.what ());
 | 
			
		||||
			}	
 | 
			
		||||
		}	
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::Accept ()
 | 
			
		||||
	{
 | 
			
		||||
		auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
 | 
			
		||||
		m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this,
 | 
			
		||||
			std::placeholders::_1, newSocket));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
 | 
			
		||||
	{
 | 
			
		||||
		if (!ecode && socket)
 | 
			
		||||
		{
 | 
			
		||||
			boost::system::error_code ec;
 | 
			
		||||
			auto ep = socket->remote_endpoint (ec);
 | 
			
		||||
			if (!ec)
 | 
			
		||||
			{	
 | 
			
		||||
				LogPrint (eLogDebug, "I2CP: new connection from ", ep);
 | 
			
		||||
				auto session = std::make_shared<I2CPSession>(*this, socket);
 | 
			
		||||
				m_Sessions[session->GetSessionID ()] = session;
 | 
			
		||||
				session->Start ();
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				LogPrint (eLogError, "I2CP: incoming connection error ", ec.message ());
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			LogPrint (eLogError, "I2CP: accept error: ", ecode.message ());
 | 
			
		||||
 | 
			
		||||
		if (ecode != boost::asio::error::operation_aborted)
 | 
			
		||||
			Accept ();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void I2CPServer::RemoveSession (uint16_t sessionID)
 | 
			
		||||
	{
 | 
			
		||||
		m_Sessions.erase (sessionID);
 | 
			
		||||
	}	
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										89
									
								
								I2CP.h
									
										
									
									
									
								
							
							
						
						
									
										89
									
								
								I2CP.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,9 +1,19 @@
 | 
			
		|||
/*
 | 
			
		||||
* 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 I2CP_H__
 | 
			
		||||
#define I2CP_H__
 | 
			
		||||
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <boost/asio.hpp>
 | 
			
		||||
#include "Destination.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +31,23 @@ namespace client
 | 
			
		|||
	const uint8_t I2CP_GET_DATE_MESSAGE = 32;
 | 
			
		||||
	const uint8_t I2CP_SET_DATE_MESSAGE = 33;
 | 
			
		||||
	const uint8_t I2CP_CREATE_SESSION_MESSAGE = 1;
 | 
			
		||||
	const uint8_t I2CP_SESSION_STATUS_MESSAGE = 20;	
 | 
			
		||||
	const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3;
 | 
			
		||||
	const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37;
 | 
			
		||||
	const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4;	
 | 
			
		||||
	const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5;
 | 
			
		||||
	const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31;
 | 
			
		||||
	const uint8_t I2CP_MESSAGE_STATUS_MESSAGE = 22;	
 | 
			
		||||
	const uint8_t I2CP_HOST_LOOKUP_MESSAGE = 38;
 | 
			
		||||
	const uint8_t I2CP_HOST_REPLY_MESSAGE = 39;		
 | 
			
		||||
 | 
			
		||||
	enum I2CPMessageStatus
 | 
			
		||||
	{
 | 
			
		||||
		eI2CPMessageStatusAccepted = 1,
 | 
			
		||||
		eI2CPMessageStatusGuaranteedSuccess = 4,
 | 
			
		||||
		eI2CPMessageStatusGuaranteedFailure = 5,
 | 
			
		||||
		eI2CPMessageStatusNoLeaseSet = 21
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class I2CPSession;
 | 
			
		||||
	class I2CPDestination: public LeaseSetDestination
 | 
			
		||||
| 
						 | 
				
			
			@ -29,22 +56,32 @@ namespace client
 | 
			
		|||
 | 
			
		||||
			I2CPDestination (I2CPSession& owner, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic);
 | 
			
		||||
 | 
			
		||||
			void SetEncryptionPrivateKey (const uint8_t * key);
 | 
			
		||||
			void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
 | 
			
		||||
			void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
 | 
			
		||||
 | 
			
		||||
		protected:
 | 
			
		||||
 | 
			
		||||
			// implements LocalDestination
 | 
			
		||||
			const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
 | 
			
		||||
			const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
 | 
			
		||||
			std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
 | 
			
		||||
 | 
			
		||||
			// I2CP
 | 
			
		||||
			void HandleDataMessage (const uint8_t * buf, size_t len) { /* TODO */ };
 | 
			
		||||
			void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) { /* TODO */ };
 | 
			
		||||
			void HandleDataMessage (const uint8_t * buf, size_t len);
 | 
			
		||||
			void CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
 | 
			
		||||
			std::shared_ptr<I2CPDestination> GetSharedFromThis ()
 | 
			
		||||
			{ return std::static_pointer_cast<I2CPDestination>(shared_from_this ()); }  
 | 
			
		||||
			bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
 | 
			
		||||
			I2CPSession& m_Owner;
 | 
			
		||||
			std::shared_ptr<const i2p::data::IdentityEx> m_Identity;
 | 
			
		||||
			uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
 | 
			
		||||
			uint8_t m_EncryptionPrivateKey[256];
 | 
			
		||||
			uint64_t m_LeaseSetExpirationTime;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class I2CPServer;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,9 +92,22 @@ namespace client
 | 
			
		|||
			I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
 | 
			
		||||
			~I2CPSession ();
 | 
			
		||||
 | 
			
		||||
			void Start ();
 | 
			
		||||
			void Stop ();
 | 
			
		||||
			uint16_t GetSessionID () const { return m_SessionID; };
 | 
			
		||||
 | 
			
		||||
			// called from I2CPDestination	
 | 
			
		||||
			void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len);
 | 
			
		||||
			void SendMessagePayloadMessage (const uint8_t * payload, size_t len); 		
 | 
			
		||||
			void SendMessageStatusMessage (uint32_t nonce, I2CPMessageStatus status);
 | 
			
		||||
 | 
			
		||||
			// message handlers
 | 
			
		||||
			void GetDateMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
			void CreateSessionMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
			void DestroySessionMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
			void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
			void SendMessageMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
			void HostLookupMessageHandler (const uint8_t * buf, size_t len);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -66,13 +116,14 @@ namespace client
 | 
			
		|||
			void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
 | 
			
		||||
			void HandleNextMessage (const uint8_t * buf);
 | 
			
		||||
			void Terminate ();
 | 
			
		||||
 | 
			
		||||
			void SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len);
 | 
			
		||||
			
 | 
			
		||||
			void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf);
 | 
			
		||||
 | 
			
		||||
			std::string ExtractString (const uint8_t * buf, size_t len);
 | 
			
		||||
			size_t PutString (uint8_t * buf, size_t len, const std::string& str);
 | 
			
		||||
 | 
			
		||||
			void SendSessionStatusMessage (uint8_t status);
 | 
			
		||||
			void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
 | 
			
		||||
			I2CPServer& m_Owner;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +132,8 @@ namespace client
 | 
			
		|||
			size_t m_NextMessageLen, m_NextMessageOffset;
 | 
			
		||||
 | 
			
		||||
			std::shared_ptr<I2CPDestination> m_Destination;
 | 
			
		||||
			uint16_t m_SessionID;
 | 
			
		||||
			uint32_t m_MessageID;
 | 
			
		||||
	};
 | 
			
		||||
	typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -89,10 +142,30 @@ namespace client
 | 
			
		|||
		public:
 | 
			
		||||
 | 
			
		||||
			I2CPServer (const std::string& interface, int port);
 | 
			
		||||
			~I2CPServer ();
 | 
			
		||||
			
 | 
			
		||||
			void Start ();
 | 
			
		||||
			void Stop ();
 | 
			
		||||
			boost::asio::io_service& GetService () { return m_Service; };
 | 
			
		||||
 | 
			
		||||
			void RemoveSession (uint16_t sessionID);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
 | 
			
		||||
			void Run ();
 | 
			
		||||
 | 
			
		||||
			void Accept ();
 | 
			
		||||
			void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
 | 
			
		||||
 | 
			
		||||
		private:
 | 
			
		||||
			
 | 
			
		||||
			 I2CPMessageHandler m_MessagesHandlers[256];
 | 
			
		||||
			I2CPMessageHandler m_MessagesHandlers[256];
 | 
			
		||||
			std::map<uint16_t, std::shared_ptr<I2CPSession> > m_Sessions;
 | 
			
		||||
 | 
			
		||||
			bool m_IsRunning;
 | 
			
		||||
			std::thread * m_Thread;	
 | 
			
		||||
			boost::asio::io_service m_Service;
 | 
			
		||||
			boost::asio::ip::tcp::acceptor m_Acceptor;
 | 
			
		||||
 | 
			
		||||
		public:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@
 | 
			
		|||
#include "ClientContext.h"
 | 
			
		||||
#include "I2PService.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace i2p
 | 
			
		||||
{
 | 
			
		||||
namespace client
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +70,7 @@ namespace client
 | 
			
		|||
															std::bind(&TCPIPPipe::HandleUpstreamReceived, shared_from_this(),
 | 
			
		||||
																				std::placeholders::_1, std::placeholders::_2));
 | 
			
		||||
		} else {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: no upstream socket for read");
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: upstream receive: no socket");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,14 +81,14 @@ namespace client
 | 
			
		|||
															std::bind(&TCPIPPipe::HandleDownstreamReceived, shared_from_this(),
 | 
			
		||||
																				std::placeholders::_1, std::placeholders::_2));
 | 
			
		||||
		} else {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: no downstream socket for read");
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: downstream receive: no socket");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TCPIPPipe::UpstreamWrite(const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_up) {
 | 
			
		||||
			LogPrint(eLogDebug, "TCPIPPipe: write upstream ", (int)len);
 | 
			
		||||
			LogPrint(eLogDebug, "TCPIPPipe: upstream: ", (int) len, " bytes written");
 | 
			
		||||
			boost::asio::async_write(*m_up, boost::asio::buffer(buf, len),
 | 
			
		||||
															 boost::asio::transfer_all(),
 | 
			
		||||
															 std::bind(&TCPIPPipe::HandleUpstreamWrite,
 | 
			
		||||
| 
						 | 
				
			
			@ -97,14 +96,14 @@ namespace client
 | 
			
		|||
																				 std::placeholders::_1)
 | 
			
		||||
															 );
 | 
			
		||||
		} else {
 | 
			
		||||
			LogPrint(eLogError, "tcpip pipe upstream socket null");
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: upstream write: no socket");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void TCPIPPipe::DownstreamWrite(const uint8_t * buf, size_t len)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_down) {
 | 
			
		||||
			LogPrint(eLogDebug, "TCPIPPipe: write downstream ", (int)len);
 | 
			
		||||
			LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) len, " bytes written");
 | 
			
		||||
			boost::asio::async_write(*m_down, boost::asio::buffer(buf, len),
 | 
			
		||||
															 boost::asio::transfer_all(),
 | 
			
		||||
															 std::bind(&TCPIPPipe::HandleDownstreamWrite,
 | 
			
		||||
| 
						 | 
				
			
			@ -112,16 +111,16 @@ namespace client
 | 
			
		|||
																				 std::placeholders::_1)
 | 
			
		||||
															 );
 | 
			
		||||
		} else { 
 | 
			
		||||
			LogPrint(eLogError, "tcpip pipe downstream socket null");
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: downstream write: no socket");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	void TCPIPPipe::HandleDownstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
 | 
			
		||||
	{
 | 
			
		||||
		LogPrint(eLogDebug, "TCPIPPipe downstream got ", (int) bytes_transfered);
 | 
			
		||||
		LogPrint(eLogDebug, "TCPIPPipe: downstream: ", (int) bytes_transfered, " bytes received");
 | 
			
		||||
		if (ecode) {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe Downstream read error:" , ecode.message());
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: downstream read error:" , ecode.message());
 | 
			
		||||
			if (ecode != boost::asio::error::operation_aborted)
 | 
			
		||||
				Terminate();
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +134,7 @@ namespace client
 | 
			
		|||
 | 
			
		||||
	void TCPIPPipe::HandleDownstreamWrite(const boost::system::error_code & ecode) {
 | 
			
		||||
		if (ecode) {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe Downstream write error:" , ecode.message());
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: downstream write error:" , ecode.message());
 | 
			
		||||
			if (ecode != boost::asio::error::operation_aborted)
 | 
			
		||||
				Terminate();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -143,7 +142,7 @@ namespace client
 | 
			
		|||
	
 | 
			
		||||
	void TCPIPPipe::HandleUpstreamWrite(const boost::system::error_code & ecode) {
 | 
			
		||||
		if (ecode) {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe Upstream write error:" , ecode.message());
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: upstream write error:" , ecode.message());
 | 
			
		||||
			if (ecode != boost::asio::error::operation_aborted)
 | 
			
		||||
				Terminate();
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -151,9 +150,9 @@ namespace client
 | 
			
		|||
	
 | 
			
		||||
	void TCPIPPipe::HandleUpstreamReceived(const boost::system::error_code & ecode, std::size_t bytes_transfered)
 | 
			
		||||
	{
 | 
			
		||||
		LogPrint(eLogDebug, "TCPIPPipe upstream got ", (int) bytes_transfered);
 | 
			
		||||
		LogPrint(eLogDebug, "TCPIPPipe: upstream ", (int)bytes_transfered, " bytes received");
 | 
			
		||||
		if (ecode) {
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe Upstream read error:" , ecode.message());
 | 
			
		||||
			LogPrint(eLogError, "TCPIPPipe: upstream read error:" , ecode.message());
 | 
			
		||||
			if (ecode != boost::asio::error::operation_aborted)
 | 
			
		||||
				Terminate();
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -206,6 +205,5 @@ namespace client
 | 
			
		|||
				LogPrint (eLogError, "I2PService: ", GetName(), " closing socket on accept because: ", ecode.message ());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,7 +179,6 @@ namespace data
 | 
			
		|||
 | 
			
		||||
			virtual ~LocalDestination() {};
 | 
			
		||||
			virtual const uint8_t * GetEncryptionPrivateKey () const = 0; 
 | 
			
		||||
			virtual const uint8_t * GetEncryptionPublicKey () const = 0; 
 | 
			
		||||
			virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
 | 
			
		||||
 | 
			
		||||
			const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };  
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -213,6 +213,7 @@ namespace data
 | 
			
		|||
		m_Buffer[offset] = num; 
 | 
			
		||||
		offset++;
 | 
			
		||||
		// leases
 | 
			
		||||
		m_Leases = m_Buffer + offset;
 | 
			
		||||
		auto currentTime = i2p::util::GetMillisecondsSinceEpoch ();
 | 
			
		||||
		for (int i = 0; i < num; i++)
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -231,6 +232,14 @@ namespace data
 | 
			
		|||
		//  we don't sign it yet. must be signed later on
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
 | 
			
		||||
		m_ExpirationTime (0), m_Identity (identity)
 | 
			
		||||
	{
 | 
			
		||||
		m_BufferLen = len;
 | 
			
		||||
		m_Buffer = new uint8_t[m_BufferLen];
 | 
			
		||||
		memcpy (m_Buffer, buf, len);		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool LocalLeaseSet::IsExpired () const
 | 
			
		||||
	{
 | 
			
		||||
		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
#include <inttypes.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "Identity.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -88,14 +89,19 @@ namespace data
 | 
			
		|||
		public:
 | 
			
		||||
 | 
			
		||||
			LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
 | 
			
		||||
			LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len);
 | 
			
		||||
			~LocalLeaseSet () { delete[] m_Buffer; };
 | 
			
		||||
 | 
			
		||||
			const uint8_t * GetBuffer () const { return m_Buffer; };
 | 
			
		||||
			uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); }; 
 | 
			
		||||
			size_t GetBufferLen () const { return m_BufferLen; };	
 | 
			
		||||
			size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); };
 | 
			
		||||
			uint8_t * GetLeases () { return m_Leases; }; 
 | 
			
		||||
			
 | 
			
		||||
			const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
 | 
			
		||||
			bool IsExpired () const;
 | 
			
		||||
			uint64_t GetExpirationTime () const { return m_ExpirationTime; };
 | 
			
		||||
			void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
 | 
			
		||||
			bool operator== (const LeaseSet& other) const 
 | 
			
		||||
			{ return m_BufferLen == other.GetBufferLen ()  && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); }; 
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +110,7 @@ namespace data
 | 
			
		|||
			
 | 
			
		||||
			uint64_t m_ExpirationTime; // in milliseconds
 | 
			
		||||
			std::shared_ptr<const IdentityEx> m_Identity;
 | 
			
		||||
			uint8_t * m_Buffer;
 | 
			
		||||
			uint8_t * m_Buffer, * m_Leases;
 | 
			
		||||
			size_t m_BufferLen;
 | 
			
		||||
	}; 
 | 
			
		||||
}		
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								Log.cpp
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								Log.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -12,7 +12,7 @@ namespace i2p {
 | 
			
		|||
namespace log {
 | 
			
		||||
	Log logger;
 | 
			
		||||
	/**
 | 
			
		||||
	 * @enum Maps our loglevel to their symbolic name
 | 
			
		||||
	 * @brief Maps our loglevel to their symbolic name
 | 
			
		||||
	 */
 | 
			
		||||
	static const char * g_LogLevelStr[eNumLogLevels] =
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ namespace log {
 | 
			
		|||
#endif
 | 
			
		||||
			case eLogFile:
 | 
			
		||||
			case eLogStream:
 | 
			
		||||
				m_LogStream->flush();
 | 
			
		||||
					if (m_LogStream) m_LogStream->flush();
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				/* do nothing */
 | 
			
		||||
| 
						 | 
				
			
			@ -107,10 +107,11 @@ namespace log {
 | 
			
		|||
#endif
 | 
			
		||||
				case eLogFile:
 | 
			
		||||
				case eLogStream:
 | 
			
		||||
					*m_LogStream << TimeAsString(msg->timestamp)
 | 
			
		||||
						<< "@" << short_tid
 | 
			
		||||
						<< "/" << g_LogLevelStr[msg->level]
 | 
			
		||||
						<< " - " << msg->text << std::endl;
 | 
			
		||||
					if (m_LogStream)
 | 
			
		||||
						*m_LogStream << TimeAsString(msg->timestamp)
 | 
			
		||||
							<< "@" << short_tid
 | 
			
		||||
							<< "/" << g_LogLevelStr[msg->level]
 | 
			
		||||
							<< " - " << msg->text << std::endl;
 | 
			
		||||
					break;
 | 
			
		||||
				case eLogStdout:
 | 
			
		||||
				default:
 | 
			
		||||
| 
						 | 
				
			
			@ -130,10 +131,13 @@ namespace log {
 | 
			
		|||
		Process();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void Log::SendTo (const std::string& path) {
 | 
			
		||||
	void Log::SendTo (const std::string& path) 
 | 
			
		||||
	{
 | 
			
		||||
		if (m_LogStream) m_LogStream = nullptr; // close previous	
 | 
			
		||||
		auto flags = std::ofstream::out | std::ofstream::app;
 | 
			
		||||
		auto os = std::make_shared<std::ofstream> (path, flags);
 | 
			
		||||
		if (os->is_open ()) {
 | 
			
		||||
		if (os->is_open ()) 
 | 
			
		||||
		{
 | 
			
		||||
			m_Logfile = path;
 | 
			
		||||
			m_Destination = eLogFile;
 | 
			
		||||
			m_LogStream = os;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								Log.h
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								Log.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -86,7 +86,7 @@ namespace log {
 | 
			
		|||
			LogLevel GetLogLevel () { return m_MinLevel; };
 | 
			
		||||
 | 
			
		||||
			/**
 | 
			
		||||
			 * @brief  Sets minimal alloed level for log messages
 | 
			
		||||
			 * @brief  Sets minimal allowed level for log messages
 | 
			
		||||
			 * @param  level  String with wanted minimal msg level
 | 
			
		||||
			 */
 | 
			
		||||
			void     SetLogLevel (const std::string& level);
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +101,7 @@ namespace log {
 | 
			
		|||
			 * @brief Sets log destination to given output stream
 | 
			
		||||
			 * @param os  Output stream
 | 
			
		||||
			 */
 | 
			
		||||
			void SendTo (std::shared_ptr<std::ostream> s);
 | 
			
		||||
			void SendTo (std::shared_ptr<std::ostream> os);
 | 
			
		||||
 | 
			
		||||
	#ifndef _WIN32
 | 
			
		||||
			/**
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,8 @@ namespace log {
 | 
			
		|||
	};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @struct Log message container
 | 
			
		||||
	 * @struct LogMsg
 | 
			
		||||
	 * @brief Log message container
 | 
			
		||||
	 *
 | 
			
		||||
	 * We creating it somewhere with LogPrint(),
 | 
			
		||||
	 * then put in MsgQueue for later processing.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -76,6 +76,7 @@ $(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
 | 
			
		|||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -rf obj
 | 
			
		||||
	rm -rf docs/generated
 | 
			
		||||
	$(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
 | 
			
		||||
 | 
			
		||||
strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB)
 | 
			
		||||
| 
						 | 
				
			
			@ -86,9 +87,13 @@ dist:
 | 
			
		|||
	git archive --format=tar.gz -9 --worktree-attributes \
 | 
			
		||||
	    --prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
 | 
			
		||||
 | 
			
		||||
doxygen:
 | 
			
		||||
	doxygen -s docs/Doxyfile
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
.PHONY: deps
 | 
			
		||||
.PHONY: doxygen
 | 
			
		||||
.PHONY: dist
 | 
			
		||||
.PHONY: api
 | 
			
		||||
.PHONY: api_client
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
# set defaults instead redefine
 | 
			
		||||
CXXFLAGS ?= -g -Wall
 | 
			
		||||
CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic
 | 
			
		||||
INCFLAGS ?=
 | 
			
		||||
 | 
			
		||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -849,7 +849,8 @@ namespace data
 | 
			
		|||
	template<typename Filter>
 | 
			
		||||
	std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const
 | 
			
		||||
	{
 | 
			
		||||
		if (!m_RouterInfos.size ()) return 0;
 | 
			
		||||
		if (m_RouterInfos.empty())
 | 
			
		||||
			return 0;
 | 
			
		||||
		uint32_t ind = rand () % m_RouterInfos.size ();	
 | 
			
		||||
		for (int j = 0; j < 2; j++)
 | 
			
		||||
		{	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -353,7 +353,7 @@ namespace data
 | 
			
		|||
		if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
 | 
			
		||||
		if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
 | 
			
		||||
 | 
			
		||||
		SetProperty ("caps", caps.c_str ());
 | 
			
		||||
		SetProperty ("caps", caps);
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	void RouterInfo::WriteToStream (std::ostream& s)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -606,7 +606,7 @@ namespace transport
 | 
			
		|||
 | 
			
		||||
	std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
 | 
			
		||||
	{
 | 
			
		||||
		if (!m_Peers.size ()) return nullptr;
 | 
			
		||||
		if (m_Peers.empty ()) return nullptr;
 | 
			
		||||
		std::unique_lock<std::mutex> l(m_PeersMutex);	
 | 
			
		||||
		auto it = m_Peers.begin ();
 | 
			
		||||
		std::advance (it, rand () % m_Peers.size ());	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -358,7 +358,7 @@ namespace tunnel
 | 
			
		|||
	
 | 
			
		||||
	std::shared_ptr<OutboundTunnel> Tunnels::GetNextOutboundTunnel ()
 | 
			
		||||
	{
 | 
			
		||||
		if (!m_OutboundTunnels.size ()) return nullptr;
 | 
			
		||||
		if (m_OutboundTunnels.empty ()) return nullptr;
 | 
			
		||||
		uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0;
 | 
			
		||||
		std::shared_ptr<OutboundTunnel> tunnel;
 | 
			
		||||
		for (auto it: m_OutboundTunnels)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								Tunnel.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Tunnel.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -73,7 +73,7 @@ namespace tunnel
 | 
			
		|||
			
 | 
			
		||||
			bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
 | 
			
		||||
 | 
			
		||||
			virtual void Print (std::stringstream& s) const {};	
 | 
			
		||||
			virtual void Print (std::stringstream&) const {};
 | 
			
		||||
			
 | 
			
		||||
			// implements TunnelBase
 | 
			
		||||
			void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								debian/changelog
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,9 @@
 | 
			
		|||
i2pd (2.7.0-1) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * updated to version 2.7.0/0.9.25
 | 
			
		||||
 | 
			
		||||
 -- hagen <hagen@i2pmail.org>  Wed, 18 May 2016 01:11:04 +0000
 | 
			
		||||
 | 
			
		||||
i2pd (2.2.0-2) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * updated to version 2.2.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								debian/i2pd.openrc
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								debian/i2pd.openrc
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -5,11 +5,9 @@ logfile="/var/log/i2pd.log"
 | 
			
		|||
mainconf="/etc/i2pd/i2pd.conf"
 | 
			
		||||
tunconf="/etc/i2pd/tunnels.conf"
 | 
			
		||||
 | 
			
		||||
. /etc/default/i2pd
 | 
			
		||||
 | 
			
		||||
name="i2pd"
 | 
			
		||||
command="/usr/sbin/i2pd"
 | 
			
		||||
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf"
 | 
			
		||||
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --pidfile=$pidfile"
 | 
			
		||||
description="i2p router written in C++"
 | 
			
		||||
required_dirs="/var/lib/i2pd"
 | 
			
		||||
required_files="$mainconf"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +20,22 @@ depend() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
start_pre() {
 | 
			
		||||
  checkpath -f -o i2pd:adm -w $pidfile
 | 
			
		||||
  checkpath -f -o i2pd:adm -w $logfile
 | 
			
		||||
  if [ -r /etc/default/i2pd ]; then
 | 
			
		||||
    . /etc/default/i2pd
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [ "x$I2PD_ENABLED" != "xyes" ]; then
 | 
			
		||||
    ewarn "i2pd disabled in /etc/default/i2pd"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  checkpath -f -o i2pd:adm $logfile
 | 
			
		||||
  checkpath -f -o i2pd:adm $pidfile
 | 
			
		||||
 | 
			
		||||
  if [ -n "$I2PD_PORT" -a "$I2PD_PORT" -gt 0 ]; then
 | 
			
		||||
    command_args="$command_args --port=$I2PD_PORT"
 | 
			
		||||
  fi
 | 
			
		||||
  if [ -n "$DAEMON_OPTS" ]; then
 | 
			
		||||
    command_args="$command_args $DAEMON_OPTS"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										259
									
								
								docs/Doxyfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								docs/Doxyfile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,259 @@
 | 
			
		|||
DOXYFILE_ENCODING      = UTF-8
 | 
			
		||||
PROJECT_NAME           = "i2pd"
 | 
			
		||||
PROJECT_NUMBER         =
 | 
			
		||||
PROJECT_BRIEF          = "load-balanced unspoofable packet switching network"
 | 
			
		||||
PROJECT_LOGO           =
 | 
			
		||||
OUTPUT_DIRECTORY       = docs/generated
 | 
			
		||||
CREATE_SUBDIRS         = NO
 | 
			
		||||
ALLOW_UNICODE_NAMES    = NO
 | 
			
		||||
OUTPUT_LANGUAGE        = English
 | 
			
		||||
BRIEF_MEMBER_DESC      = YES
 | 
			
		||||
REPEAT_BRIEF           = YES
 | 
			
		||||
ABBREVIATE_BRIEF       =
 | 
			
		||||
ALWAYS_DETAILED_SEC    = NO
 | 
			
		||||
INLINE_INHERITED_MEMB  = NO
 | 
			
		||||
FULL_PATH_NAMES        = YES
 | 
			
		||||
STRIP_FROM_PATH        =
 | 
			
		||||
STRIP_FROM_INC_PATH    =
 | 
			
		||||
SHORT_NAMES            = NO
 | 
			
		||||
JAVADOC_AUTOBRIEF      = NO
 | 
			
		||||
QT_AUTOBRIEF           = NO
 | 
			
		||||
MULTILINE_CPP_IS_BRIEF = NO
 | 
			
		||||
INHERIT_DOCS           = YES
 | 
			
		||||
SEPARATE_MEMBER_PAGES  = NO
 | 
			
		||||
TAB_SIZE               = 4
 | 
			
		||||
ALIASES                =
 | 
			
		||||
TCL_SUBST              =
 | 
			
		||||
OPTIMIZE_OUTPUT_FOR_C  = NO
 | 
			
		||||
OPTIMIZE_OUTPUT_JAVA   = NO
 | 
			
		||||
OPTIMIZE_FOR_FORTRAN   = NO
 | 
			
		||||
OPTIMIZE_OUTPUT_VHDL   = NO
 | 
			
		||||
EXTENSION_MAPPING      =
 | 
			
		||||
MARKDOWN_SUPPORT       = YES
 | 
			
		||||
AUTOLINK_SUPPORT       = YES
 | 
			
		||||
BUILTIN_STL_SUPPORT    = NO
 | 
			
		||||
CPP_CLI_SUPPORT        = NO
 | 
			
		||||
SIP_SUPPORT            = NO
 | 
			
		||||
IDL_PROPERTY_SUPPORT   = YES
 | 
			
		||||
DISTRIBUTE_GROUP_DOC   = NO
 | 
			
		||||
SUBGROUPING            = YES
 | 
			
		||||
INLINE_GROUPED_CLASSES = NO
 | 
			
		||||
INLINE_SIMPLE_STRUCTS  = NO
 | 
			
		||||
TYPEDEF_HIDES_STRUCT   = NO
 | 
			
		||||
LOOKUP_CACHE_SIZE      = 0
 | 
			
		||||
EXTRACT_ALL            = NO
 | 
			
		||||
EXTRACT_PRIVATE        = NO
 | 
			
		||||
EXTRACT_PACKAGE        = NO
 | 
			
		||||
EXTRACT_STATIC         = NO
 | 
			
		||||
EXTRACT_LOCAL_CLASSES  = YES
 | 
			
		||||
EXTRACT_LOCAL_METHODS  = NO
 | 
			
		||||
EXTRACT_ANON_NSPACES   = NO
 | 
			
		||||
HIDE_UNDOC_MEMBERS     = NO
 | 
			
		||||
HIDE_UNDOC_CLASSES     = NO
 | 
			
		||||
HIDE_FRIEND_COMPOUNDS  = NO
 | 
			
		||||
HIDE_IN_BODY_DOCS      = NO
 | 
			
		||||
INTERNAL_DOCS          = NO
 | 
			
		||||
CASE_SENSE_NAMES       = YES
 | 
			
		||||
HIDE_SCOPE_NAMES       = NO
 | 
			
		||||
SHOW_INCLUDE_FILES     = YES
 | 
			
		||||
SHOW_GROUPED_MEMB_INC  = NO
 | 
			
		||||
FORCE_LOCAL_INCLUDES   = NO
 | 
			
		||||
INLINE_INFO            = YES
 | 
			
		||||
SORT_MEMBER_DOCS       = YES
 | 
			
		||||
SORT_BRIEF_DOCS        = NO
 | 
			
		||||
SORT_MEMBERS_CTORS_1ST = NO
 | 
			
		||||
SORT_GROUP_NAMES       = NO
 | 
			
		||||
SORT_BY_SCOPE_NAME     = NO
 | 
			
		||||
STRICT_PROTO_MATCHING  = NO
 | 
			
		||||
GENERATE_TODOLIST      = YES
 | 
			
		||||
GENERATE_TESTLIST      = YES
 | 
			
		||||
GENERATE_BUGLIST       = YES
 | 
			
		||||
GENERATE_DEPRECATEDLIST= YES
 | 
			
		||||
ENABLED_SECTIONS       =
 | 
			
		||||
MAX_INITIALIZER_LINES  = 30
 | 
			
		||||
SHOW_USED_FILES        = YES
 | 
			
		||||
SHOW_FILES             = YES
 | 
			
		||||
SHOW_NAMESPACES        = YES
 | 
			
		||||
FILE_VERSION_FILTER    =
 | 
			
		||||
LAYOUT_FILE            =
 | 
			
		||||
CITE_BIB_FILES         =
 | 
			
		||||
QUIET                  = YES
 | 
			
		||||
WARNINGS               = YES
 | 
			
		||||
WARN_IF_UNDOCUMENTED   = NO
 | 
			
		||||
WARN_IF_DOC_ERROR      = YES
 | 
			
		||||
WARN_NO_PARAMDOC       = NO
 | 
			
		||||
WARN_FORMAT            = "$file:$line: $text"
 | 
			
		||||
WARN_LOGFILE           =
 | 
			
		||||
INPUT                  =
 | 
			
		||||
INPUT_ENCODING         = UTF-8
 | 
			
		||||
FILE_PATTERNS          = *.cpp *.h
 | 
			
		||||
RECURSIVE              = NO
 | 
			
		||||
EXCLUDE                =
 | 
			
		||||
EXCLUDE_SYMLINKS       = NO
 | 
			
		||||
EXCLUDE_PATTERNS       =
 | 
			
		||||
EXCLUDE_SYMBOLS        =
 | 
			
		||||
EXAMPLE_PATH           =
 | 
			
		||||
EXAMPLE_PATTERNS       =
 | 
			
		||||
EXAMPLE_RECURSIVE      = NO
 | 
			
		||||
IMAGE_PATH             =
 | 
			
		||||
INPUT_FILTER           =
 | 
			
		||||
FILTER_PATTERNS        =
 | 
			
		||||
FILTER_SOURCE_FILES    = NO
 | 
			
		||||
FILTER_SOURCE_PATTERNS =
 | 
			
		||||
USE_MDFILE_AS_MAINPAGE =
 | 
			
		||||
SOURCE_BROWSER         = NO
 | 
			
		||||
INLINE_SOURCES         = NO
 | 
			
		||||
STRIP_CODE_COMMENTS    = YES
 | 
			
		||||
REFERENCED_BY_RELATION = NO
 | 
			
		||||
REFERENCES_RELATION    = NO
 | 
			
		||||
REFERENCES_LINK_SOURCE = YES
 | 
			
		||||
SOURCE_TOOLTIPS        = YES
 | 
			
		||||
USE_HTAGS              = NO
 | 
			
		||||
VERBATIM_HEADERS       = NO
 | 
			
		||||
CLANG_ASSISTED_PARSING = NO
 | 
			
		||||
CLANG_OPTIONS          =
 | 
			
		||||
ALPHABETICAL_INDEX     = YES
 | 
			
		||||
COLS_IN_ALPHA_INDEX    = 5
 | 
			
		||||
IGNORE_PREFIX          =
 | 
			
		||||
GENERATE_HTML          = YES
 | 
			
		||||
HTML_OUTPUT            = html
 | 
			
		||||
HTML_FILE_EXTENSION    = .html
 | 
			
		||||
HTML_HEADER            =
 | 
			
		||||
HTML_FOOTER            =
 | 
			
		||||
HTML_STYLESHEET        =
 | 
			
		||||
HTML_EXTRA_STYLESHEET  =
 | 
			
		||||
HTML_EXTRA_FILES       =
 | 
			
		||||
HTML_COLORSTYLE_HUE    = 220
 | 
			
		||||
HTML_COLORSTYLE_SAT    = 100
 | 
			
		||||
HTML_COLORSTYLE_GAMMA  = 80
 | 
			
		||||
HTML_TIMESTAMP         = YES
 | 
			
		||||
HTML_DYNAMIC_SECTIONS  = NO
 | 
			
		||||
HTML_INDEX_NUM_ENTRIES = 100
 | 
			
		||||
GENERATE_DOCSET        = NO
 | 
			
		||||
DOCSET_FEEDNAME        = "Doxygen generated docs"
 | 
			
		||||
DOCSET_BUNDLE_ID       = org.doxygen.Project
 | 
			
		||||
DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
 | 
			
		||||
DOCSET_PUBLISHER_NAME  = Publisher
 | 
			
		||||
GENERATE_HTMLHELP      = NO
 | 
			
		||||
CHM_FILE               =
 | 
			
		||||
HHC_LOCATION           =
 | 
			
		||||
GENERATE_CHI           = NO
 | 
			
		||||
CHM_INDEX_ENCODING     =
 | 
			
		||||
BINARY_TOC             = NO
 | 
			
		||||
TOC_EXPAND             = NO
 | 
			
		||||
GENERATE_QHP           = NO
 | 
			
		||||
QCH_FILE               =
 | 
			
		||||
QHP_NAMESPACE          = org.doxygen.Project
 | 
			
		||||
QHP_VIRTUAL_FOLDER     = doc
 | 
			
		||||
QHP_CUST_FILTER_NAME   =
 | 
			
		||||
QHP_CUST_FILTER_ATTRS  =
 | 
			
		||||
QHP_SECT_FILTER_ATTRS  =
 | 
			
		||||
QHG_LOCATION           =
 | 
			
		||||
GENERATE_ECLIPSEHELP   = NO
 | 
			
		||||
ECLIPSE_DOC_ID         = org.doxygen.Project
 | 
			
		||||
DISABLE_INDEX          = NO
 | 
			
		||||
GENERATE_TREEVIEW      = NO
 | 
			
		||||
ENUM_VALUES_PER_LINE   = 4
 | 
			
		||||
TREEVIEW_WIDTH         = 250
 | 
			
		||||
EXT_LINKS_IN_WINDOW    = NO
 | 
			
		||||
FORMULA_FONTSIZE       = 10
 | 
			
		||||
FORMULA_TRANSPARENT    = YES
 | 
			
		||||
USE_MATHJAX            = NO
 | 
			
		||||
MATHJAX_FORMAT         = HTML-CSS
 | 
			
		||||
MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
 | 
			
		||||
MATHJAX_EXTENSIONS     =
 | 
			
		||||
MATHJAX_CODEFILE       =
 | 
			
		||||
SEARCHENGINE           = YES
 | 
			
		||||
SERVER_BASED_SEARCH    = NO
 | 
			
		||||
EXTERNAL_SEARCH        = NO
 | 
			
		||||
SEARCHENGINE_URL       =
 | 
			
		||||
SEARCHDATA_FILE        = searchdata.xml
 | 
			
		||||
EXTERNAL_SEARCH_ID     =
 | 
			
		||||
EXTRA_SEARCH_MAPPINGS  =
 | 
			
		||||
GENERATE_LATEX         = NO
 | 
			
		||||
LATEX_OUTPUT           = latex
 | 
			
		||||
LATEX_CMD_NAME         = latex
 | 
			
		||||
MAKEINDEX_CMD_NAME     = makeindex
 | 
			
		||||
COMPACT_LATEX          = NO
 | 
			
		||||
PAPER_TYPE             = a4
 | 
			
		||||
EXTRA_PACKAGES         =
 | 
			
		||||
LATEX_HEADER           =
 | 
			
		||||
LATEX_FOOTER           =
 | 
			
		||||
LATEX_EXTRA_FILES      =
 | 
			
		||||
PDF_HYPERLINKS         = YES
 | 
			
		||||
USE_PDFLATEX           = YES
 | 
			
		||||
LATEX_BATCHMODE        = NO
 | 
			
		||||
LATEX_HIDE_INDICES     = NO
 | 
			
		||||
LATEX_SOURCE_CODE      = NO
 | 
			
		||||
LATEX_BIB_STYLE        = plain
 | 
			
		||||
GENERATE_RTF           = NO
 | 
			
		||||
RTF_OUTPUT             = rtf
 | 
			
		||||
COMPACT_RTF            = NO
 | 
			
		||||
RTF_HYPERLINKS         = NO
 | 
			
		||||
RTF_STYLESHEET_FILE    =
 | 
			
		||||
RTF_EXTENSIONS_FILE    =
 | 
			
		||||
GENERATE_MAN           = NO
 | 
			
		||||
MAN_OUTPUT             = man
 | 
			
		||||
MAN_EXTENSION          = .3
 | 
			
		||||
MAN_SUBDIR             =
 | 
			
		||||
MAN_LINKS              = NO
 | 
			
		||||
GENERATE_XML           = NO
 | 
			
		||||
XML_OUTPUT             = xml
 | 
			
		||||
XML_PROGRAMLISTING     = YES
 | 
			
		||||
GENERATE_DOCBOOK       = NO
 | 
			
		||||
DOCBOOK_OUTPUT         = docbook
 | 
			
		||||
DOCBOOK_PROGRAMLISTING = NO
 | 
			
		||||
GENERATE_AUTOGEN_DEF   = NO
 | 
			
		||||
GENERATE_PERLMOD       = NO
 | 
			
		||||
PERLMOD_LATEX          = NO
 | 
			
		||||
PERLMOD_PRETTY         = YES
 | 
			
		||||
PERLMOD_MAKEVAR_PREFIX =
 | 
			
		||||
ENABLE_PREPROCESSING   = YES
 | 
			
		||||
MACRO_EXPANSION        = NO
 | 
			
		||||
EXPAND_ONLY_PREDEF     = NO
 | 
			
		||||
SEARCH_INCLUDES        = YES
 | 
			
		||||
INCLUDE_PATH           =
 | 
			
		||||
INCLUDE_FILE_PATTERNS  =
 | 
			
		||||
PREDEFINED             =
 | 
			
		||||
EXPAND_AS_DEFINED      =
 | 
			
		||||
SKIP_FUNCTION_MACROS   = YES
 | 
			
		||||
TAGFILES               =
 | 
			
		||||
GENERATE_TAGFILE       =
 | 
			
		||||
ALLEXTERNALS           = NO
 | 
			
		||||
EXTERNAL_GROUPS        = YES
 | 
			
		||||
EXTERNAL_PAGES         = YES
 | 
			
		||||
PERL_PATH              = /usr/bin/perl
 | 
			
		||||
CLASS_DIAGRAMS         = YES
 | 
			
		||||
MSCGEN_PATH            =
 | 
			
		||||
DIA_PATH               =
 | 
			
		||||
HIDE_UNDOC_RELATIONS   = YES
 | 
			
		||||
HAVE_DOT               = NO
 | 
			
		||||
DOT_NUM_THREADS        = 0
 | 
			
		||||
DOT_FONTNAME           = Helvetica
 | 
			
		||||
DOT_FONTSIZE           = 10
 | 
			
		||||
DOT_FONTPATH           =
 | 
			
		||||
CLASS_GRAPH            = YES
 | 
			
		||||
COLLABORATION_GRAPH    = YES
 | 
			
		||||
GROUP_GRAPHS           = YES
 | 
			
		||||
UML_LOOK               = NO
 | 
			
		||||
UML_LIMIT_NUM_FIELDS   = 10
 | 
			
		||||
TEMPLATE_RELATIONS     = NO
 | 
			
		||||
INCLUDE_GRAPH          = YES
 | 
			
		||||
INCLUDED_BY_GRAPH      = YES
 | 
			
		||||
CALL_GRAPH             = NO
 | 
			
		||||
CALLER_GRAPH           = NO
 | 
			
		||||
GRAPHICAL_HIERARCHY    = YES
 | 
			
		||||
DIRECTORY_GRAPH        = YES
 | 
			
		||||
DOT_IMAGE_FORMAT       = png
 | 
			
		||||
INTERACTIVE_SVG        = NO
 | 
			
		||||
DOT_PATH               =
 | 
			
		||||
DOTFILE_DIRS           =
 | 
			
		||||
MSCFILE_DIRS           =
 | 
			
		||||
DIAFILE_DIRS           =
 | 
			
		||||
PLANTUML_JAR_PATH      =
 | 
			
		||||
DOT_GRAPH_MAX_NODES    = 50
 | 
			
		||||
MAX_DOT_GRAPH_DEPTH    = 0
 | 
			
		||||
DOT_TRANSPARENT        = NO
 | 
			
		||||
DOT_MULTI_TARGETS      = NO
 | 
			
		||||
GENERATE_LEGEND        = YES
 | 
			
		||||
DOT_CLEANUP            = YES
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								docs/itoopieImage.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/itoopieImage.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 8.5 KiB  | 
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
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
 | 
			
		||||
 | 
			
		||||
all: $(TESTS) run
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								tests/test-http-merge_chunked.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/test-http-merge_chunked.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
#include <cassert>
 | 
			
		||||
#include "../HTTP.h"
 | 
			
		||||
 | 
			
		||||
using namespace i2p::http;
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
  const char *buf =
 | 
			
		||||
    "4\r\n"
 | 
			
		||||
    "HTTP\r\n"
 | 
			
		||||
    "A\r\n"
 | 
			
		||||
    " response \r\n"
 | 
			
		||||
    "E\r\n"
 | 
			
		||||
    "with \r\n"
 | 
			
		||||
    "chunks.\r\n"
 | 
			
		||||
    "0\r\n"
 | 
			
		||||
    "\r\n"
 | 
			
		||||
    ;
 | 
			
		||||
  std::stringstream in(buf);
 | 
			
		||||
  std::stringstream out;
 | 
			
		||||
 | 
			
		||||
  assert(MergeChunkedResponse(in, out) == true);
 | 
			
		||||
  assert(out.str() == "HTTP response with \r\nchunks.");
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue