1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
/*
* Copyright (c) 2013-2025, 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 ADDRESS_BOOK_H__
#define ADDRESS_BOOK_H__
#include <string.h>
#include <string>
#include <string_view>
#include <map>
#include <vector>
#include <iostream>
#include <mutex>
#include <future>
#include <memory>
#include <boost/asio.hpp>
#include "Base.h"
#include "Identity.h"
#include "Log.h"
#include "Destination.h"
#include "LeaseSet.h"
namespace i2p
{
namespace client
{
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)
const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes
const int CONTINIOUS_SUBSCRIPTION_MAX_NUM_RETRIES = 10; // then update timeout
const int SUBSCRIPTION_REQUEST_TIMEOUT = 120; //in seconds
const int ADDRESS_CACHE_EXPIRATION_TIMEOUT = 710; // in seconds
const int ADDRESS_CACHE_UPDATE_INTERVAL = 76; // in seconds
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54;
const size_t B33_ADDRESS_THRESHOLD = 52; // characters
struct Address
{
enum { eAddressIndentHash, eAddressBlindedPublicKey, eAddressInvalid } addressType;
i2p::data::IdentHash identHash;
std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey;
Address (std::string_view b32);
Address (const i2p::data::IdentHash& hash);
bool IsIdentHash () const { return addressType == eAddressIndentHash; };
bool IsValid () const { return addressType != eAddressInvalid; };
};
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
class AddressBookStorage // interface for storage
{
public:
typedef std::map<std::string, std::shared_ptr<Address>, std::less<> > Addresses;
virtual ~AddressBookStorage () {};
virtual std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) = 0;
virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0;
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
virtual void CleanUpCache () = 0;
virtual bool Init () = 0;
virtual int Load (Addresses& addresses) = 0;
virtual int LoadLocal (Addresses& addresses) = 0;
virtual int Save (const Addresses& addresses) = 0;
virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0;
virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0;
virtual void ResetEtags () = 0;
};
class AddressBookSubscription;
class AddressResolver;
class AddressBook
{
public:
AddressBook ();
~AddressBook ();
void Start ();
void StartResolvers ();
void Stop ();
std::shared_ptr<const Address> GetAddress (std::string_view address);
std::shared_ptr<const i2p::data::IdentityEx> GetFullAddress (const std::string& address);
std::shared_ptr<const Address> FindAddress (std::string_view address);
void LookupAddress (std::string_view address);
void InsertAddress (const std::string& address, const std::string& jump); // for jump links
void InsertFullAddress (std::shared_ptr<const i2p::data::IdentityEx> address);
bool RecordExists (const std::string& address, const std::string& jump);
bool LoadHostsFromStream (std::istream& f, bool is_update);
void DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified);
//This method returns the ".b32.i2p" address
std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); }
std::string ToAddress(std::shared_ptr<const i2p::data::IdentityEx> ident) { return ToAddress(ident->GetIdentHash ()); }
bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified);
bool IsEnabled () const { return m_IsEnabled; }
private:
void StartSubscriptions ();
void StopSubscriptions ();
void LoadHosts ();
void LoadSubscriptions ();
void LoadLocal ();
void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode);
void StartLookups ();
void StopLookups ();
void HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void ScheduleCacheUpdate ();
private:
std::mutex m_AddressBookMutex;
AddressBookStorage::Addresses m_Addresses;
std::map<i2p::data::IdentHash, std::shared_ptr<AddressResolver> > m_Resolvers; // local destination->resolver
std::mutex m_LookupsMutex;
std::map<uint32_t, std::string> m_Lookups; // nonce -> address
AddressBookStorage * m_Storage;
volatile bool m_IsLoaded;
std::future<void> m_Downloading;
int m_NumRetries;
std::vector<std::shared_ptr<AddressBookSubscription> > m_Subscriptions;
std::shared_ptr<AddressBookSubscription> m_DefaultSubscription; // in case if we don't know any addresses yet
std::unique_ptr<boost::asio::deadline_timer> m_SubscriptionsUpdateTimer, m_AddressCacheUpdateTimer;
bool m_IsEnabled;
};
class AddressBookSubscription
{
public:
AddressBookSubscription (AddressBook& book, std::string_view link);
void CheckUpdates ();
private:
bool MakeRequest ();
private:
AddressBook& m_Book;
std::string m_Link, m_Etag, m_LastModified;
i2p::data::IdentHash m_Ident;
// m_Etag must be surrounded by ""
};
class AddressResolver
{
public:
AddressResolver (std::shared_ptr<ClientDestination> destination);
~AddressResolver ();
void AddAddress (const std::string& name, const i2p::data::IdentHash& ident);
private:
void HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
private:
std::shared_ptr<ClientDestination> m_LocalDestination;
std::map<std::string, i2p::data::IdentHash> m_LocalAddresses;
};
}
}
#endif
|