diff --git a/AddressBook.cpp b/AddressBook.cpp index 3b3f85b4..f972d48f 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -24,7 +24,7 @@ namespace client { private: i2p::fs::HashedStorage storage; - std::string indexPath; + std::string etagsPath, indexPath, localPath; public: AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") {}; @@ -34,14 +34,34 @@ namespace client bool Init (); int Load (std::map& addresses); + int LoadLocal (std::map& addresses); int Save (const std::map& addresses); + + void SaveEtag (const i2p::data::IdentHash& subsciption, const std::string& etag, const std::string& lastModified); + bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified); + + private: + + int LoadFromFile (const std::string& filename, std::map& addresses); // returns -1 if can't open file, otherwise number of records + }; bool AddressBookFilesystemStorage::Init() - { + { storage.SetPlace(i2p::fs::GetDataDir()); - indexPath = storage.GetRoot() + i2p::fs::dirSep + "addresses.csv"; - return storage.Init(i2p::data::GetBase32SubstitutionTable(), 32); + // init storage + if (storage.Init(i2p::data::GetBase32SubstitutionTable(), 32)) + { + // init ETags + etagsPath = i2p::fs::StorageRootPath (storage, "etags"); + if (!i2p::fs::Exists (etagsPath)) + i2p::fs::CreateDirectory (etagsPath); + // init address files + indexPath = i2p::fs::StorageRootPath (storage, "addresses.csv"); + localPath = i2p::fs::StorageRootPath (storage, "local.csv"); + return true; + } + return false; } std::shared_ptr AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const @@ -87,24 +107,18 @@ namespace client storage.Remove( ident.ToBase32() ); } - int AddressBookFilesystemStorage::Load (std::map& addresses) + int AddressBookFilesystemStorage::LoadFromFile (const std::string& filename, std::map& addresses) { int num = 0; - std::string s; - std::ifstream f (indexPath, std::ifstream::in); // in text mode - - if (f.is_open ()) { - LogPrint(eLogInfo, "Addressbook: using index file ", indexPath); - } else { - LogPrint(eLogWarning, "Addressbook: Can't open ", indexPath); - return 0; - } + std::ifstream f (filename, std::ifstream::in); // in text mode + if (!f) return -1; addresses.clear (); - while (!f.eof ()) { + while (!f.eof ()) + { + std::string s; getline(f, s); - if (!s.length()) - continue; // skip empty line + if (!s.length()) continue; // skip empty line std::size_t pos = s.find(','); if (pos != std::string::npos) @@ -118,8 +132,28 @@ namespace client num++; } } + return num; + } + int AddressBookFilesystemStorage::Load (std::map& addresses) + { + int num = LoadFromFile (indexPath, addresses); + if (num < 0) + { + LogPrint(eLogWarning, "Addressbook: Can't open ", indexPath); + return 0; + } + LogPrint(eLogInfo, "Addressbook: using index file ", indexPath); LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded from storage"); + + return num; + } + + int AddressBookFilesystemStorage::LoadLocal (std::map& addresses) + { + int num = LoadFromFile (localPath, addresses); + if (num < 0) return 0; + LogPrint (eLogInfo, "Addressbook: ", num, " local addresses loaded"); return num; } @@ -146,6 +180,28 @@ namespace client return num; } + void AddressBookFilesystemStorage::SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) + { + std::string fname = etagsPath + i2p::fs::dirSep + subscription.ToBase32 () + ".txt"; + std::ofstream f (fname, std::ofstream::out | std::ofstream::trunc); + if (f) + { + f << etag << std::endl; + f<< lastModified << std::endl; + } + } + + bool AddressBookFilesystemStorage::GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) + { + std::string fname = etagsPath + i2p::fs::dirSep + subscription.ToBase32 () + ".txt"; + std::ifstream f (fname, std::ofstream::in); + if (!f || f.eof ()) return false; + std::getline (f, etag); + if (f.eof ()) return false; + std::getline (f, lastModified); + return true; + } + //--------------------------------------------------------------------- AddressBook::AddressBook (): m_Storage(new AddressBookFilesystemStorage), m_IsLoaded (false), m_IsDownloading (false), m_DefaultSubscription (nullptr), m_SubscriptionsUpdateTimer (nullptr) @@ -274,6 +330,7 @@ namespace client LoadHostsFromStream (f); m_IsLoaded = true; } + LoadLocal (); } void AddressBook::LoadHostsFromStream (std::istream& f) @@ -337,7 +394,49 @@ namespace client LogPrint (eLogError, "Addressbook: subscriptions already loaded"); } - void AddressBook::DownloadComplete (bool success) + void AddressBook::LoadLocal () + { + std::map localAddresses; + m_Storage->LoadLocal (localAddresses); + for (auto it: localAddresses) + { + auto dot = it.first.find ('.'); + if (dot != std::string::npos) + { + auto domain = it.first.substr (dot + 1); + auto it1 = m_Addresses.find (domain); // find domain in our addressbook + if (it1 != m_Addresses.end ()) + { + auto dest = context.FindLocalDestination (it1->second); + if (dest) + { + // address is ours + std::shared_ptr resolver; + auto it2 = m_Resolvers.find (it1->second); + if (it2 != m_Resolvers.end ()) + resolver = it2->second; // resolver exists + else + { + // create new resolver + resolver = std::make_shared(dest); + m_Resolvers.insert (std::make_pair(it1->second, resolver)); + } + resolver->AddAddress (it.first, it.second); + } + } + } + } + } + + bool AddressBook::GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) + { + if (m_Storage) + return m_Storage->GetEtag (subscription, etag, lastModified); + else + return false; + } + + void AddressBook::DownloadComplete (bool success, const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) { m_IsDownloading = false; int nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT; @@ -348,6 +447,7 @@ namespace client nextUpdateTimeout = CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT; else m_IsLoaded = true; + if (m_Storage) m_Storage->SaveEtag (subscription, etag, lastModified); } if (m_SubscriptionsUpdateTimer) { @@ -438,6 +538,12 @@ namespace client i2p::data::IdentHash ident; if (m_Book.GetIdentHash (u.host_, ident)) { + if (!m_Etag.length ()) + { + // load ETag + m_Book.GetEtag (ident, m_Etag, m_LastModified); + LogPrint (eLogInfo, "Addressbook: set ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); + } std::condition_variable newDataReceived; std::mutex newDataReceivedMutex; auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident); @@ -468,7 +574,7 @@ namespace client << "X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n" << "Connection: close\r\n"; if (m_Etag.length () > 0) // etag - request << i2p::util::http::IF_NONE_MATCH << ": \"" << m_Etag << "\"\r\n"; + request << i2p::util::http::IF_NONE_MATCH << ": " << m_Etag << "\r\n"; if (m_LastModified.length () > 0) // if-modfief-since request << i2p::util::http::IF_MODIFIED_SINCE << ": " << m_LastModified << "\r\n"; request << "\r\n"; // end of header @@ -529,7 +635,7 @@ namespace client !header.compare (colon + 1, std::string::npos, "x-i2p-gzip"); } } - LogPrint (eLogInfo, "Addressbook: ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); + LogPrint (eLogInfo, "Addressbook: received ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); if (!response.eof ()) { success = true; @@ -561,7 +667,7 @@ namespace client if (!success) LogPrint (eLogError, "Addressbook: download hosts.txt from ", m_Link, " failed"); - m_Book.DownloadComplete (success); + m_Book.DownloadComplete (success, ident, m_Etag, m_LastModified); } bool AddressBookSubscription::ProcessResponse (std::stringstream& s, bool isGzip) @@ -580,6 +686,50 @@ namespace client m_Book.LoadHostsFromStream (s); return true; } + + AddressResolver::AddressResolver (std::shared_ptr destination): + m_LocalDestination (destination) + { + if (m_LocalDestination) + { + auto datagram = m_LocalDestination->GetDatagramDestination (); + if (!datagram) + datagram = m_LocalDestination->CreateDatagramDestination (); + datagram->SetReceiver (std::bind (&AddressResolver::HandleRequest, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + ADDRESS_RESOLVER_DATAGRAM_PORT); + } + } + + void AddressResolver::HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + if (len < 9 || len < buf[8] + 9U) + { + LogPrint (eLogError, "Address request is too short ", len); + return; + } + // read requested address + uint8_t l = buf[8]; + char address[255]; + memcpy (address, buf + 9, l); + address[l] = 0; + // send response + uint8_t response[40]; + memset (response, 0, 4); // reserved + memcpy (response + 4, buf + 4, 4); // nonce + auto it = m_LocalAddresses.find (address); // address lookup + if (it != m_LocalAddresses.end ()) + memcpy (response + 8, it->second, 32); // ident + else + memset (response + 8, 0, 32); // not found + m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 40, from.GetIdentHash (), toPort, fromPort); + } + + void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident) + { + m_LocalAddresses[name] = ident; + } + } } diff --git a/AddressBook.h b/AddressBook.h index 46df12d0..436e7c8b 100644 --- a/AddressBook.h +++ b/AddressBook.h @@ -12,6 +12,7 @@ #include "Base.h" #include "Identity.h" #include "Log.h" +#include "Destination.h" namespace i2p { @@ -23,7 +24,7 @@ namespace client const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second - + inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); } class AddressBookStorage // interface for storage @@ -37,10 +38,15 @@ namespace client virtual bool Init () = 0; virtual int Load (std::map& addresses) = 0; + virtual int LoadLocal (std::map& addresses) = 0; virtual int Save (const std::map& 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; }; class AddressBookSubscription; + class AddressResolver; class AddressBook { public: @@ -56,10 +62,13 @@ namespace client void InsertAddress (std::shared_ptr address); void LoadHostsFromStream (std::istream& f); - void DownloadComplete (bool success); + 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 ident) { return ToAddress(ident->GetIdentHash ()); } + + bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified); + private: void StartSubscriptions (); @@ -67,6 +76,7 @@ namespace client void LoadHosts (); void LoadSubscriptions (); + void LoadLocal (); void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode); @@ -74,6 +84,7 @@ namespace client std::mutex m_AddressBookMutex; std::map m_Addresses; + std::map > m_Resolvers; // local destination->resolver AddressBookStorage * m_Storage; volatile bool m_IsLoaded, m_IsDownloading; std::vector m_Subscriptions; @@ -97,6 +108,25 @@ namespace client AddressBook& m_Book; std::string m_Link, m_Etag, m_LastModified; + // m_Etag must be surrounded by "" + }; + + const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53; + class AddressResolver + { + public: + + AddressResolver (std::shared_ptr destination); + 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 m_LocalDestination; + std::map m_LocalAddresses; }; } } diff --git a/Base.cpp b/Base.cpp index e894b694..e0b6af07 100644 --- a/Base.cpp +++ b/Base.cpp @@ -8,8 +8,8 @@ namespace data { static const char T32[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'k', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 't', 't', 'u', 'v', 'w', 'x', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7', }; diff --git a/Config.cpp b/Config.cpp index 15c8ad67..caec7e20 100644 --- a/Config.cpp +++ b/Config.cpp @@ -126,6 +126,7 @@ namespace config { #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") + ("close", value()->default_value("ask"), "On close action") // minimize, exit, ask TODO: add custom validator or something #endif ; diff --git a/Daemon.cpp b/Daemon.cpp index f301ee3a..7f96b470 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -72,7 +72,7 @@ namespace i2p if (config == "") { config = i2p::fs::DataDirPath("i2p.conf"); - // use i2p.cong only if exists + // use i2p.conf only if exists if (!i2p::fs::Exists (config)) config = ""; /* reset */ } diff --git a/FS.cpp b/FS.cpp index 19963195..380ab2e5 100644 --- a/FS.cpp +++ b/FS.cpp @@ -102,6 +102,13 @@ namespace fs { return boost::filesystem::remove(path); } + bool CreateDirectory (const std::string& path) + { + if (boost::filesystem::exists(path) && + boost::filesystem::is_directory (boost::filesystem::status (path))) return true; + return boost::filesystem::create_directory(path); + } + void HashedStorage::SetPlace(const std::string &path) { root = path + i2p::fs::dirSep + name; } diff --git a/FS.h b/FS.h index 833258b9..0437ccf9 100644 --- a/FS.h +++ b/FS.h @@ -48,8 +48,8 @@ namespace fs { /** create subdirs in storage */ bool Init(const char* chars, size_t cnt); - const std::string & GetRoot() const { return this->root; } - const std::string & GetName() const { return this->name; } + const std::string & GetRoot() const { return root; } + const std::string & GetName() const { return name; } /** set directory where to place storage directory */ void SetPlace(const std::string & path); /** path to file with given ident */ @@ -108,6 +108,8 @@ namespace fs { * @return true if file exists, false otherwise */ bool Exists(const std::string & path); + + bool CreateDirectory (const std::string& path); template void _ExpandPath(std::stringstream & path, T c) { @@ -136,6 +138,17 @@ namespace fs { return s.str(); } + + template + std::string StorageRootPath (const Storage& storage, Filename... filenames) + { + std::stringstream s(""); + s << storage.GetRoot (); + _ExpandPath(s, filenames...); + + return s.str(); + } + } // fs } // i2p diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 160c27f6..6e835d21 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -204,7 +204,7 @@ namespace proxy if (eol) { *eol = 0; eol++; - if (strncmp ((const char *)http_buff, "Referer", 7)) // strip out referer + if (strncmp ((const char *)http_buff, "Referer", 7) && strncmp ((const char *)http_buff, "Connection", 10)) // strip out referer and connection { if (!strncmp ((const char *)http_buff, "User-Agent", 10)) // replace UserAgent m_request.append("User-Agent: MYOB/6.66 (AN/ON)"); diff --git a/HTTPServer.cpp b/HTTPServer.cpp index ddfa6478..9ffa0599 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -427,18 +427,18 @@ namespace util s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n
\r\n"; s << "Our external address:" << "
\r\n" ; - for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) + for (auto address : i2p::context.GetRouterInfo().GetAddresses()) { - switch (address.transportStyle) + switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: - if (address.host.is_v6 ()) + if (address->host.is_v6 ()) s << "NTCP6  "; else s << "NTCP  "; break; case i2p::data::RouterInfo::eTransportSSU: - if (address.host.is_v6 ()) + if (address->host.is_v6 ()) s << "SSU6     "; else s << "SSU     "; @@ -446,7 +446,7 @@ namespace util default: s << "Unknown  "; } - s << address.host.to_string() << ":" << address.port << "
\r\n"; + s << address->host.to_string() << ":" << address->port << "
\r\n"; } s << "
\r\nRouters: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 2584f584..a7832335 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -93,9 +93,7 @@ namespace transport m_DHKeysPair = nullptr; - SendTimeSyncMessage (); - m_SendQueue.push_back (CreateDatabaseStoreMsg ()); // we tell immediately who we are - + SendTimeSyncMessage (); transports.PeerConnected (shared_from_this ()); } @@ -761,15 +759,15 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&NTCPServer::Run, this)); // create acceptors - auto addresses = context.GetRouterInfo ().GetAddresses (); - for (auto& address : addresses) + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (auto address: addresses) { - if (address.transportStyle == i2p::data::RouterInfo::eTransportNTCP && address.host.is_v4 ()) + if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && address->host.is_v4 ()) { m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, - boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); - LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address.port); + LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port); auto conn = std::make_shared(*this); m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1)); @@ -779,10 +777,10 @@ namespace transport m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true)); - m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port)); + m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); m_NTCPV6Acceptor->listen (); - LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address.port); + LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port); auto conn = std::make_shared (*this); m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1)); diff --git a/NetDb.cpp b/NetDb.cpp index eb1380de..857381d8 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -118,6 +118,7 @@ namespace data { SaveUpdated (); ManageLeaseSets (); + ManageLookupResponses (); } lastSave = ts; } @@ -671,13 +672,31 @@ namespace data if (!replyMsg) { LogPrint (eLogWarning, "NetDb: Requested ", key, " not found. ", numExcluded, " excluded"); - std::set excludedRouters; - for (int i = 0; i < numExcluded; i++) - { - excludedRouters.insert (excluded); - excluded += 32; + // find or cleate response + std::vector closestFloodfills; + bool found = false; + if (!numExcluded) + { + auto it = m_LookupResponses.find (ident); + if (it != m_LookupResponses.end ()) + { + closestFloodfills = it->second.first; + found = true; + } + } + if (!found) + { + std::set excludedRouters; + for (int i = 0; i < numExcluded; i++) + { + excludedRouters.insert (excluded); + excluded += 32; + } + closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true); + if (!numExcluded) // save if no excluded + m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ()); } - replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters, true)); + replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills); } } @@ -972,5 +991,17 @@ namespace data it++; } } + + void NetDb::ManageLookupResponses () + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_LookupResponses.begin (); it != m_LookupResponses.end ();) + { + if (ts > it->second.second + 180) // 3 minutes + it = m_LookupResponses.erase (it); + else + it++; + } + } } } diff --git a/NetDb.h b/NetDb.h index 536ff644..1c062358 100644 --- a/NetDb.h +++ b/NetDb.h @@ -84,6 +84,7 @@ namespace data void Publish (); void ManageLeaseSets (); void ManageRequests (); + void ManageLookupResponses (); template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -108,6 +109,8 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + + std::map, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) }; extern NetDb netdb; diff --git a/Reseed.cpp b/Reseed.cpp index 380babb5..caac8071 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -26,13 +26,12 @@ namespace data static std::vector httpsReseedHostList = { "https://reseed.i2p-projekt.de/", // Only HTTPS - //"https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v3) support "https://i2p.mooo.com/netDb/", "https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required "https://us.reseed.i2p2.no:444/", "https://uk.reseed.i2p2.no:444/", - "https://www.torontocrypto.org:8443/", - "https://i2p-0.manas.ca:8443/" + "https://i2p.manas.ca:8443/", + "https://i2p-0.manas.ca:8443/", "https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support "https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support "https://download.xxlspeed.com/" // Only HTTPS and SU3 (v3) support diff --git a/RouterContext.cpp b/RouterContext.cpp index b3774d89..dc08ede3 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -92,11 +92,11 @@ namespace i2p void RouterContext::UpdatePort (int port) { bool updated = false; - for (auto& address : m_RouterInfo.GetAddresses ()) + for (auto address : m_RouterInfo.GetAddresses ()) { - if (address.port != port) + if (address->port != port) { - address.port = port; + address->port = port; updated = true; } } @@ -107,11 +107,11 @@ namespace i2p void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; - for (auto& address : m_RouterInfo.GetAddresses ()) + for (auto address : m_RouterInfo.GetAddresses ()) { - if (address.host != host && address.IsCompatible (host)) + if (address->host != host && address->IsCompatible (host)) { - address.host = host; + address->host = host; updated = true; } } @@ -206,15 +206,15 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (size_t i = 0; i < addresses.size (); i++) { - if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportNTCP) { addresses.erase (addresses.begin () + i); break; } } // delete previous introducers - for (auto& addr : addresses) - addr.introducers.clear (); + for (auto addr : addresses) + addr->introducers.clear (); // update UpdateRouterInfo (); @@ -235,16 +235,16 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (size_t i = 0; i < addresses.size (); i++) { - if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU) + if (addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportSSU) { // insert NTCP address with host/port from SSU - m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port); + m_RouterInfo.AddNTCPAddress (addresses[i]->host.to_string ().c_str (), addresses[i]->port); break; } } // delete previous introducers - for (auto& addr : addresses) - addr.introducers.clear (); + for (auto addr : addresses) + addr->introducers.clear (); // update UpdateRouterInfo (); @@ -264,19 +264,19 @@ namespace i2p bool updated = false, found = false; int port = 0; auto& addresses = m_RouterInfo.GetAddresses (); - for (auto& addr : addresses) + for (auto addr: addresses) { - if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (addr->host.is_v6 () && addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP) { - if (addr.host != host) + if (addr->host != host) { - addr.host = host; + addr->host = host; updated = true; } found = true; } else - port = addr.port; + port = addr->port; } if (!found) { diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 84768201..e9285d54 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -232,7 +232,7 @@ namespace data } if (isValidAddress) { - m_Addresses.push_back(address); + m_Addresses.push_back(std::make_shared
(address)); m_SupportedTransports |= supportedTransports; } } @@ -359,8 +359,9 @@ namespace data // addresses uint8_t numAddresses = m_Addresses.size (); s.write ((char *)&numAddresses, sizeof (numAddresses)); - for (auto& address : m_Addresses) + for (auto addr : m_Addresses) { + Address& address = *addr; s.write ((char *)&address.cost, sizeof (address.cost)); s.write ((char *)&address.date, sizeof (address.date)); std::stringstream properties; @@ -543,46 +544,46 @@ namespace data void RouterInfo::AddNTCPAddress (const char * host, int port) { - Address addr; - addr.host = boost::asio::ip::address::from_string (host); - addr.port = port; - addr.transportStyle = eTransportNTCP; - addr.cost = 2; - addr.date = 0; - addr.mtu = 0; + auto addr = std::make_shared
(); + addr->host = boost::asio::ip::address::from_string (host); + addr->port = port; + addr->transportStyle = eTransportNTCP; + addr->cost = 2; + addr->date = 0; + addr->mtu = 0; for (auto it: m_Addresses) // don't insert same address twice - if (it == addr) return; + if (*it == *addr) return; m_Addresses.push_back(addr); - m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4; + m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) { - Address addr; - addr.host = boost::asio::ip::address::from_string (host); - addr.port = port; - addr.transportStyle = eTransportSSU; - addr.cost = 10; // NTCP should have priority over SSU - addr.date = 0; - addr.mtu = mtu; - memcpy (addr.key, key, 32); + auto addr = std::make_shared
(); + addr->host = boost::asio::ip::address::from_string (host); + addr->port = port; + addr->transportStyle = eTransportSSU; + addr->cost = 10; // NTCP should have priority over SSU + addr->date = 0; + addr->mtu = mtu; + memcpy (addr->key, key, 32); for (auto it: m_Addresses) // don't insert same address twice - if (it == addr) return; + if (*it == *addr) return; m_Addresses.push_back(addr); - m_SupportedTransports |= addr.host.is_v6 () ? eSSUV6 : eSSUV4; + m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; m_Caps |= eSSUTesting; m_Caps |= eSSUIntroducer; } bool RouterInfo::AddIntroducer (const Introducer& introducer) { - for (auto& addr : m_Addresses) + for (auto addr : m_Addresses) { - if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto intro: addr.introducers) + for (auto intro: addr->introducers) if (intro.iTag == introducer.iTag) return false; // already presented - addr.introducers.push_back (introducer); + addr->introducers.push_back (introducer); return true; } } @@ -591,14 +592,14 @@ namespace data bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) { - for (auto& addr : m_Addresses) + for (auto addr: m_Addresses) { - if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (std::vector::iterator it = addr.introducers.begin (); it != addr.introducers.end (); it++) + for (std::vector::iterator it = addr->introducers.begin (); it != addr->introducers.end (); it++) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { - addr.introducers.erase (it); + addr->introducers.erase (it); return true; } } @@ -664,8 +665,8 @@ namespace data m_SupportedTransports &= ~eNTCPV6; for (size_t i = 0; i < m_Addresses.size (); i++) { - if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP && - m_Addresses[i].host.is_v6 ()) + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportNTCP && + m_Addresses[i]->host.is_v6 ()) { m_Addresses.erase (m_Addresses.begin () + i); break; @@ -676,8 +677,8 @@ namespace data m_SupportedTransports &= ~eSSUV6; for (size_t i = 0; i < m_Addresses.size (); i++) { - if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU && - m_Addresses[i].host.is_v6 ()) + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportSSU && + m_Addresses[i]->host.is_v6 ()) { m_Addresses.erase (m_Addresses.begin () + i); break; @@ -691,29 +692,29 @@ namespace data return m_Caps & Caps::eUnreachable; // non-reachable } - const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const + std::shared_ptr RouterInfo::GetNTCPAddress (bool v4only) const { return GetAddress (eTransportNTCP, v4only); } - const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const + std::shared_ptr RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress (eTransportSSU, v4only); } - const RouterInfo::Address * RouterInfo::GetSSUV6Address () const + std::shared_ptr RouterInfo::GetSSUV6Address () const { return GetAddress (eTransportSSU, false, true); } - const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const + std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const { - for (auto& address : m_Addresses) + for (auto address : m_Addresses) { - if (address.transportStyle == s) + if (address->transportStyle == s) { - if ((!v4only || address.host.is_v4 ()) && (!v6only || address.host.is_v6 ())) - return &address; + if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ())) + return address; } } return nullptr; diff --git a/RouterInfo.h b/RouterInfo.h index c0ef2131..69607d4b 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -116,10 +116,10 @@ namespace data void SetRouterIdentity (std::shared_ptr identity); std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; uint64_t GetTimestamp () const { return m_Timestamp; }; - std::vector
& GetAddresses () { return m_Addresses; }; - const Address * GetNTCPAddress (bool v4only = true) const; - const Address * GetSSUAddress (bool v4only = true) const; - const Address * GetSSUV6Address () const; + std::vector >& GetAddresses () { return m_Addresses; }; + std::shared_ptr GetNTCPAddress (bool v4only = true) const; + std::shared_ptr GetSSUAddress (bool v4only = true) const; + std::shared_ptr GetSSUV6Address () const; void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); @@ -182,7 +182,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void ExtractCaps (const char * value); - const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; + std::shared_ptr GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; void UpdateCapsProperty (); private: @@ -192,7 +192,7 @@ namespace data uint8_t * m_Buffer; size_t m_BufferLen; uint64_t m_Timestamp; - std::vector
m_Addresses; + std::vector > m_Addresses; std::map m_Properties; bool m_IsUpdated, m_IsUnreachable; uint8_t m_SupportedTransports, m_Caps; diff --git a/SSUSession.cpp b/SSUSession.cpp index 1fa29475..aa534c56 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -855,7 +855,6 @@ namespace transport m_DHKeysPair = nullptr; m_SignedData = nullptr; m_Data.Start (); - m_Data.Send (CreateDatabaseStoreMsg ()); transports.PeerConnected (shared_from_this ()); if (m_IsPeerTest) SendPeerTest (); diff --git a/Transports.cpp b/Transports.cpp index 5fcce0fc..2127b646 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -112,8 +112,8 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); // create acceptors - auto addresses = context.GetRouterInfo ().GetAddresses (); - for (auto& address : addresses) + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (auto address : addresses) { if (!m_NTCPServer) { @@ -121,12 +121,12 @@ namespace transport m_NTCPServer->Start (); } - if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ()) + if (address->transportStyle == RouterInfo::eTransportSSU && address->host.is_v4 ()) { if (!m_SSUServer) { - m_SSUServer = new SSUServer (address.port); - LogPrint (eLogInfo, "Transports: Start listening UDP port ", address.port); + m_SSUServer = new SSUServer (address->port); + LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); m_SSUServer->Start (); DetectExternalIP (); } @@ -378,13 +378,18 @@ namespace transport { auto address = (*it).endpoint ().address (); LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); - auto addr = peer.router->GetNTCPAddress (); - if (addr) + if (address.is_v4 () || context.SupportsV6 ()) { - auto s = std::make_shared (*m_NTCPServer, peer.router); - m_NTCPServer->Connect (address, addr->port, s); - return; + auto addr = peer.router->GetNTCPAddress (); // TODO: take one we requested + if (addr) + { + auto s = std::make_shared (*m_NTCPServer, peer.router); + m_NTCPServer->Connect (address, addr->port, s); + return; + } } + else + LogPrint (eLogInfo, "Can't connect to NTCP ", address, " ipv6 is not supported"); } LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ()); std::unique_lock l(m_PeersMutex); @@ -411,12 +416,17 @@ namespace transport { auto address = (*it).endpoint ().address (); LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); - auto addr = peer.router->GetSSUAddress (!context.SupportsV6 ());; - if (addr) + if (address.is_v4 () || context.SupportsV6 ()) { - m_SSUServer->CreateSession (peer.router, address, addr->port); - return; + auto addr = peer.router->GetSSUAddress (); // TODO: take one we requested + if (addr) + { + m_SSUServer->CreateSession (peer.router, address, addr->port); + return; + } } + else + LogPrint (eLogInfo, "Can't connect to SSU ", address, " ipv6 is not supported"); } LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ()); std::unique_lock l(m_PeersMutex); @@ -505,12 +515,24 @@ namespace transport auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { + bool sendDatabaseStore = true; + if (it->second.delayedMessages.size () > 0) + { + // check if first message is our DatabaseStore (publishing) + auto firstMsg = it->second.delayedMessages[0]; + if (firstMsg && firstMsg->GetTypeID () == eI2NPDatabaseStore && + i2p::data::IdentHash(firstMsg->GetPayload () + DATABASE_STORE_KEY_OFFSET) == i2p::context.GetIdentHash ()) + sendDatabaseStore = false; // we have it in the list already + } + if (sendDatabaseStore) + session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); it->second.sessions.push_back (session); session->SendI2NPMessages (it->second.delayedMessages); it->second.delayedMessages.clear (); } else // incoming connection { + session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore std::unique_lock l(m_PeersMutex); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} })); } diff --git a/UPnP.cpp b/UPnP.cpp index c4e5e04c..fea2ff9e 100644 --- a/UPnP.cpp +++ b/UPnP.cpp @@ -101,19 +101,19 @@ namespace transport void UPnP::Run () { - std::vector a = context.GetRouterInfo().GetAddresses(); - for (auto& address : a) + const std::vector > a = context.GetRouterInfo().GetAddresses(); + for (auto address : a) { - if (!address.host.is_v6 ()) + if (!address->host.is_v6 ()) { Discover (); - if (address.transportStyle == data::RouterInfo::eTransportSSU ) + if (address->transportStyle == data::RouterInfo::eTransportSSU ) { - TryPortMapping (I2P_UPNP_UDP, address.port); + TryPortMapping (I2P_UPNP_UDP, address->port); } - else if (address.transportStyle == data::RouterInfo::eTransportNTCP ) + else if (address->transportStyle == data::RouterInfo::eTransportNTCP ) { - TryPortMapping (I2P_UPNP_TCP, address.port); + TryPortMapping (I2P_UPNP_TCP, address->port); } } } diff --git a/UPnP.h b/UPnP.h index 1a7b55c5..32c42118 100644 --- a/UPnP.h +++ b/UPnP.h @@ -58,6 +58,5 @@ namespace transport } } -#endif - -#endif +#endif // USE_UPNP +#endif // __UPNP_H__ diff --git a/Win32/Anke_2200px.jpg b/Win32/Anke_2200px.jpg new file mode 100644 index 00000000..1c5b0f31 Binary files /dev/null and b/Win32/Anke_2200px.jpg differ diff --git a/Win32/Anke_700px.bmp b/Win32/Anke_700px.bmp new file mode 100644 index 00000000..f63cccbb Binary files /dev/null and b/Win32/Anke_700px.bmp differ diff --git a/Win32/Resource.rc b/Win32/Resource.rc index e10ec496..bdc532e9 100644 --- a/Win32/Resource.rc +++ b/Win32/Resource.rc @@ -52,7 +52,11 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -MAINICON ICON "ictoopie.ico" +//MAINICON ICON "ictoopie.ico" +MAINICON ICON "anke.ico" + +MASCOT BITMAP "Anke_700px.bmp" + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index cd9a8f34..81a3ba48 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -2,8 +2,14 @@ #include #include #include "../Config.h" +#include "../version.h" #include "resource.h" #include "Win32App.h" +#include + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif #define ID_ABOUT 2000 #define ID_EXIT 2001 @@ -85,7 +91,9 @@ namespace win32 { case ID_ABOUT: { - MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK ); + std::stringstream text; + text << "Version: " << I2PD_VERSION << " " << CODENAME; + MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); return 0; } case ID_EXIT: @@ -98,7 +106,7 @@ namespace win32 char buf[30]; std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); - std::snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort); + snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort); ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL); return 0; } @@ -119,6 +127,29 @@ namespace win32 ShowWindow(hWnd, SW_HIDE); return 0; } + case SC_CLOSE: + { + std::string close; i2p::config::GetOption("close", close); + if (0 == close.compare("ask")) + switch(::MessageBox(hWnd, "Would you like to minimize instead of exiting?" + " You can add 'close' configuration option. Valid values are: ask, minimize, exit.", + "Minimize instead of exiting?", MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1)) + { + case IDYES: close = "minimize"; break; + case IDNO: close = "exit"; break; + default: return 0; + } + if (0 == close.compare("minimize")) + { + ShowWindow(hWnd, SW_HIDE); + return 0; + } + if (0 != close.compare("exit")) + { + ::MessageBox(hWnd, close.c_str(), "Unknown close action in config", MB_OK | MB_ICONWARNING); + return 0; + } + } } } case WM_TRAYICON: @@ -136,6 +167,19 @@ namespace win32 } break; } + case WM_PAINT: + { + PAINTSTRUCT ps; + auto hDC = BeginPaint (hWnd, &ps); + auto mascot = LoadBitmap (GetModuleHandle(NULL), MAKEINTRESOURCE (MASCOT)); + auto mascotDC = CreateCompatibleDC (hDC); + SelectObject (mascotDC, mascot); + BitBlt (hDC, 0,0, 533, 700, mascotDC, 0, 0, SRCCOPY); + DeleteDC (mascotDC); + DeleteObject (mascot); + EndPaint (hWnd, &ps); + break; + } } return DefWindowProc( hWnd, uMsg, wParam, lParam); } @@ -164,7 +208,7 @@ namespace win32 wclx.lpszClassName = I2PD_WIN32_CLASSNAME; RegisterClassEx (&wclx); // create new window - if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW, 100, 100, 250, 150, NULL, NULL, hInst, NULL)) + if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW, 100, 100, 549, 738, NULL, NULL, hInst, NULL)) { MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); return false; diff --git a/Win32/anke.ico b/Win32/anke.ico new file mode 100644 index 00000000..509177bb Binary files /dev/null and b/Win32/anke.ico differ diff --git a/Win32/resource.h b/Win32/resource.h index a8309c8b..f37fce46 100644 --- a/Win32/resource.h +++ b/Win32/resource.h @@ -3,6 +3,7 @@ // Used by Resource.rc // #define MAINICON 101 +#define MASCOT 201 // Next default values for new objects // diff --git a/docs/build_notes_cross.md b/docs/build_notes_cross.md new file mode 100644 index 00000000..d819ba34 --- /dev/null +++ b/docs/build_notes_cross.md @@ -0,0 +1,75 @@ +Cross compilation notes +======================= + +Static 64 bit windows binary on Ubuntu 15.10 (Wily Werewolf) +--------------------------------------------------------------------- + +Install cross compiler and friends +```sh +sudo apt-get install g++-mingw-w64-x86-64 +``` +Default is to use Win32 threading model which lacks std::mutex and such. So we change defaults +```sh +sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix +``` +From now on we assume we have everything in `~/dev/`. Get Boost sources unpacked into `~/dev/boost_1_60_0/` +and change directory to it. +Now add out cross compiler configuration. Warning: the following will wipe out whatever you had in there. +```sh +echo "using gcc : mingw : x86_64-w64-mingw32-g++ ;" > ~/user-config.jam +``` +Proceed with building Boost normal way, but let's define dedicated staging directory +```sh +./bootstrap.sh +./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \ + --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time \ + --stagedir=stage-mingw-64 +cd .. +``` +Now we get & build OpenSSL +```sh +git clone https://github.com/openssl/openssl +cd openssl +git checkout OpenSSL_1_0_2g +./Configure mingw64 no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 \ + no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp \ + --prefix=~/dev/stage --cross-compile-prefix=x86_64-w64-mingw32- +make depend +make +make install +cd .. +``` +and Zlib +```sh +git clone https://github.com/madler/zlib +cd zlib +git checkout v1.2.8 +CC=x86_64-w64-mingw32-gcc CFLAGS=-O3 ./configure --static --64 --prefix=~/dev/stage +make +make install +cd .. +``` +Now we prepare cross toolchain hint file for CMake, let's name it `~/dev/toolchain-mingw.cmake` +```cmake +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) +SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +``` +Download miniupnpc, unpack, and symlink it into `~/dev/miniupnpc/`. +Finally, we can build i2pd with all that goodness +```sh +git clone https://github.com/PurpleI2P/i2pd +mkdir i2pd-mingw-64-build +cd i2pd-mingw-64-build +BOOST_ROOT=~/dev/boost_1_60_0 cmake -G 'Unix Makefiles' ~/dev/i2pd/build -DBUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=~/dev/toolchain-mingw.cmake -DWITH_AESNI=ON -DWITH_UPNP=ON -DWITH_STATIC=ON \ + -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=~/dev/i2pd-mingw-64-static \ + -DZLIB_ROOT=~/dev/stage -DBOOST_LIBRARYDIR:PATH=~/dev/boost_1_60_0/stage-mingw-64/lib \ + -DOPENSSL_ROOT_DIR:PATH=~/dev/stage +make +x86_64-w64-mingw32-strip i2pd.exe +``` +By now, you should have a release build with stripped symbols. diff --git a/docs/build_requirements.md b/docs/build_requirements.md index 3f523a80..ec4aa180 100644 --- a/docs/build_requirements.md +++ b/docs/build_requirements.md @@ -4,7 +4,7 @@ Build requirements Linux/FreeBSD/OSX ----------------- -GCC 4.6 or newer, Boost 1.46 or newer, openssl, zlib. Clang can be used instead of GCC. +GCC 4.8 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC. Windows ------- diff --git a/docs/configuration.md b/docs/configuration.md index 79f95f10..46e5092c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -17,9 +17,9 @@ Command line options * --port= - The port to listen on * --daemon - Router will go to background after start * --service - Router will use system folders like '/var/lib/i2pd' -* --ipv6 - Enable communication through ipv6 -* --notransit - Router will not accept transit tunnels at startup -* --floodfill - Router will be floodfill +* --ipv6 - Enable communication through ipv6. false by default +* --notransit - Router will not accept transit tunnels at startup. false by default +* --floodfill - Router will be floodfill. false by default * --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited * --family= - Name of a family, router belongs to * --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") @@ -30,21 +30,26 @@ Command line options * --httpproxy.address= - The address to listen on (HTTP Proxy) * --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default * --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) +* --httpproxy.enabled= - If HTTP proxy is enabled. true by default * --socksproxy.address= - The address to listen on (SOCKS Proxy) * --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default * --socksproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) -* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there +* --socksproxy.enabled= - If SOCKS proxy is enabled. true by default +* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there * --socksproxy.outproxyport= - Outproxy remote port * --sam.address= - The address to listen on (SAM bridge) * --sam.port= - Port of SAM bridge. Usually 7656. SAM is off if not specified +* --sam.enabled= - If SAM is enabled. false by default * --bob.address= - The address to listen on (BOB command channel) * --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified +* --sam.enabled= - If BOB is enabled. false by default * --i2pcontrol.address= - The address to listen on (I2P control service) * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified +* --i2pcontrol.enabled= - If I2P control is enabled. false by default Config files ------------ @@ -58,15 +63,15 @@ For example: i2p.conf: # comment - log = yes - ipv6 = yes + log = true + ipv6 = true # settings for specific module [httpproxy] port = 4444 # ^^ this will be --httproxy.port= in cmdline # another one [sam] - enabled = yes + enabled = true tunnels.cfg (filename of this config is subject of change): diff --git a/docs/i2pd.conf b/docs/i2pd.conf new file mode 100644 index 00000000..32c524ca --- /dev/null +++ b/docs/i2pd.conf @@ -0,0 +1,111 @@ +## Configuration file for a typical i2pd user +## See https://i2pd.readthedocs.org/en/latest/configuration.html +## for more options you can use in this file. + +## Lines that begin with "## " try to explain what's going on. Lines +## that begin with just "#" are disabled commands: you can enable them +## by removing the "#" symbol. + +## Tunnels config file +## Default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg +#tunconf = /var/lib/i2pd/tunnels.cfg + +## Where to write pidfile (don't write by default) +#pidfile = /var/run/i2pd.pid + +## Logging configuration section +## By default logs go to stdout with level info +## +## Logs destination (stdout, file) +#log = file +## Path to logfile (default - autodetect) +#logfile = /var/log/i2pd.log +## Log messages above this level (debug, *info, warn, error) +#loglevel = info + +## Path to storage of i2pd data (RI, keys, peer profiles, ...) +## Default: ~/.i2pd or /var/lib/i2pd +#datadir = /var/lib/i2pd + +## Daemon mode. Router will go to background after start +#daemon +## Run as a service. Router will use system folders like ‘/var/lib/i2pd’ +#service + +## External IP address to listen for connections +## By default i2pd sets IP automatically +#host = 1.2.3.4 +## Port to listen for connections +## By default i2pd picks random port. You MUST pick a random number too, +## don't just uncomment this +#port = 4321 +##Enable communication through ipv6 +ipv6 +## Bandwidth configuration +## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited +## Default is P for floodfill, L for regular node +#bandwidth = L + +## Router will not accept transit tunnels at startup +#notransit + +## Router will be floodfill +#floodfill + +## Section for Web Console +## By default it's available at 127.0.0.1:7070 even if it's not configured +[http] +## The address to listen on +address = 127.0.0.1 +## The port to listen on +port = 7070 + +## Section for HTTP proxy +## By default it's available at 127.0.0.1:4444 even if it's not configured +[httpproxy] +## The address to listen on +address = 127.0.0.1 +## The port to listen on +port = 4444 +## Optional keys file for proxy local destination +#keys = http-proxy-keys.dat +## Uncomment if you want to disable HTTP proxy +#enabled=false + +## Section for Socks proxy +## By default it's available at 127.0.0.1:4447 even if it's not configured +#[socksproxy] +## The address to listen on +#address = 127.0.0.1 +## The port to listen on +#port = 4447 +## Optional keys file for proxy local destination +#keys = socks-proxy-keys.dat +## Uncomment if you want to disable Socks proxy +#enabled=false +## Socks outproxy. Example below is set to use Tor for all connections except i2p +## Address of outproxy +#outproxy = 127.0.0.1 +## Outproxy remote port +#outproxyport = 9050 + +## Section for SAM bridge +#[sam] +## The address to listen on +#address = 127.0.0.1 +## Port of SAM bridge +#port = 7656 + +## Section for BOB command channel +#[bob] +## The address to listen on +#address = 127.0.0.1 +## Port of BOB command channel. Usually 2827. BOB is off if not specified +#port = 2827 + +## Section for I2PControl protocol +#[i2pcontrol] +## The address to listen on +#address = 127.0.0.1 +## Port of I2P control service +#port = 7650 diff --git a/util.cpp b/util.cpp index bd77e682..5230f55f 100644 --- a/util.cpp +++ b/util.cpp @@ -106,11 +106,15 @@ namespace http while (!response.eof ()) { std::string hexLen; - int len; + size_t len; std::getline (response, hexLen); std::istringstream iss (hexLen); iss >> std::hex >> len; - if (!len) break; + if (!len || len > 10000000L) // 10M + { + LogPrint (eLogError, "Unexpected chunk length ", len); + break; + } char * buf = new char[len]; response.read (buf, len); merged.write (buf, len); diff --git a/version.h b/version.h index 244096b7..e7414de3 100644 --- a/version.h +++ b/version.h @@ -16,7 +16,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 24 +#define I2P_VERSION_MICRO 25 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)