From 436621f79f9beead905d5baec39bfd0af4637f38 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Sun, 4 Dec 2016 14:38:57 -0500
Subject: [PATCH 1/7] 2.10.2

---
 android/AndroidManifest.xml | 2 +-
 version.h                   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index afe7e118..9ffb1c13 100755
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -2,7 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="org.purplei2p.i2pd"
       android:versionCode="1"
-      android:versionName="2.10.1">
+      android:versionName="2.10.2">
     <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
 	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
diff --git a/version.h b/version.h
index 9aadf505..ef88cbcb 100644
--- a/version.h
+++ b/version.h
@@ -8,7 +8,7 @@
 
 #define I2PD_VERSION_MAJOR 2
 #define I2PD_VERSION_MINOR 10
-#define I2PD_VERSION_MICRO 1
+#define I2PD_VERSION_MICRO 2
 #define I2PD_VERSION_PATCH 0
 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
 #define VERSION I2PD_VERSION

From 5b8d637f6a3db06e9eed5f72f77bb263bbb7c7ff Mon Sep 17 00:00:00 2001
From: MXPLRS | Kirill <r4sas@users.noreply.github.com>
Date: Mon, 5 Dec 2016 00:21:18 +0300
Subject: [PATCH 2/7] 2.10.2

---
 Win32/installer.iss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Win32/installer.iss b/Win32/installer.iss
index d51ae7f2..047263cc 100644
--- a/Win32/installer.iss
+++ b/Win32/installer.iss
@@ -1,5 +1,5 @@
 #define I2Pd_AppName "i2pd"
-#define I2Pd_ver "2.10.1"
+#define I2Pd_ver "2.10.2"
 #define I2Pd_Publisher "PurpleI2P"
 
 [Setup]

From 3704a4ff470f783960602a8e47bc83891209a039 Mon Sep 17 00:00:00 2001
From: r4sas <atnaguzin@gmail.com>
Date: Mon, 5 Dec 2016 00:31:41 +0300
Subject: [PATCH 3/7] 2.10.2

---
 ChangeLog        | 5 +++++
 debian/changelog | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index dd1bac57..67f076fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,11 @@
 # for this file format description,
 # see https://github.com/olivierlacan/keep-a-changelog
 
+## [2.10.2] - 2016-12-04
+### Fixed
+- Fixes UPnP discovery bug, producing excessive CPU usage
+- Fixes sudden SSU thread stop for Windows. 
+
 ## [2.10.1] - 2016-11-07
 ### Fixed
 - Fixed some performance issues for Windows and Android
diff --git a/debian/changelog b/debian/changelog
index f71b2e4a..6e6a4c09 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+i2pd (2.10.2-1) unstable; urgency=low
+
+  * updated to version 2.10.2
+
+ -- orignal <orignal@i2pmail.org>  Sun, 4 Dec 2016 19:38:30 +0000
+
 i2pd (2.10.1-1) unstable; urgency=low
 
   * updated to version 2.10.1

From 42f70cd55dacc08fc3e8ca03ca5dc78cf7f01c6b Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Mon, 5 Dec 2016 15:45:04 -0500
Subject: [PATCH 4/7] request destination after frist lookup

---
 NetDb.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/NetDb.cpp b/NetDb.cpp
index e75cf217..dc745bbc 100644
--- a/NetDb.cpp
+++ b/NetDb.cpp
@@ -882,7 +882,11 @@ namespace data
 					}
 					closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
 					if (!numExcluded) // save if no excluded
+					{
 						m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ());
+						if (lookupType != DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
+							RequestDestination (ident); // try to request for first time only
+					}
 				}
 				replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
     		}
@@ -1197,7 +1201,7 @@ namespace data
 		auto ts = i2p::util::GetSecondsSinceEpoch ();
 		for (auto it = m_LookupResponses.begin (); it != m_LookupResponses.end ();)
 		{
-			if (ts > it->second.second + 180) // 3 minutes
+			if (ts > it->second.second + 120) // 2 minutes
 				it = m_LookupResponses.erase (it);
 			else
 				++it;

From adf887a06b733b203709683971adb4063c8d9a6b Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Mon, 5 Dec 2016 16:36:51 -0500
Subject: [PATCH 5/7] request destination if we are not closest

---
 NetDb.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NetDb.cpp b/NetDb.cpp
index dc745bbc..53c6f61d 100644
--- a/NetDb.cpp
+++ b/NetDb.cpp
@@ -884,7 +884,7 @@ namespace data
 					if (!numExcluded) // save if no excluded
 					{
 						m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ());
-						if (lookupType != DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
+						if (lookupType != DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP && !closestFloodfills.empty ()) // we are not closest
 							RequestDestination (ident); // try to request for first time only
 					}
 				}

From 59681398cbcef1fcfb48736c7fb3f01ff92f8122 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Mon, 5 Dec 2016 18:39:01 -0500
Subject: [PATCH 6/7] don't store lookup replies anymore

---
 NetDb.cpp | 53 ++++++++++-------------------------------------------
 NetDb.h   |  4 +---
 2 files changed, 11 insertions(+), 46 deletions(-)

diff --git a/NetDb.cpp b/NetDb.cpp
index 53c6f61d..a1f0fcb7 100644
--- a/NetDb.cpp
+++ b/NetDb.cpp
@@ -118,7 +118,6 @@ namespace data
 					{
 						SaveUpdated ();
 						ManageLeaseSets ();
-						ManageLookupResponses ();
 					}	
 					lastSave = ts;
 				}
@@ -857,37 +856,17 @@ namespace data
 			}
 			
 			if (!replyMsg)
-			{
-				LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
-				// find or cleate response
-				std::vector<IdentHash> 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<IdentHash> excludedRouters;
-					const uint8_t * exclude_ident = excluded;
-					for (int i = 0; i < numExcluded; i++)
-					{
-						excludedRouters.insert (exclude_ident);
-						exclude_ident += 32;
-					}
-					closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
-					if (!numExcluded) // save if no excluded
-					{
-						m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ());
-						if (lookupType != DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP && !closestFloodfills.empty ()) // we are not closest
-							RequestDestination (ident); // try to request for first time only
-					}
+			{		
+				std::set<IdentHash> excludedRouters;
+				const uint8_t * exclude_ident = excluded;
+				for (int i = 0; i < numExcluded; i++)
+				{
+					excludedRouters.insert (exclude_ident);
+					exclude_ident += 32;
 				}
+				auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
+				if (closestFloodfills.empty ())
+					LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
 				replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
     		}
 		}
@@ -1195,17 +1174,5 @@ 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 + 120) // 2 minutes
-				it = m_LookupResponses.erase (it);
-			else
-				++it;
-		}
-	}
 }
 }
diff --git a/NetDb.h b/NetDb.h
index 954cc74e..0a05c143 100644
--- a/NetDb.h
+++ b/NetDb.h
@@ -112,7 +112,6 @@ namespace data
 			void Publish ();
 			void ManageLeaseSets ();
 			void ManageRequests ();
-			void ManageLookupResponses ();
 
 		void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
 		
@@ -143,8 +142,7 @@ namespace data
 
 		/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
 		std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
-		
-			std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp)
+				
 
       /** true if in hidden mode */
       bool m_HiddenMode;

From 381f6b184e6ad3e71270d3465518c01956720df9 Mon Sep 17 00:00:00 2001
From: orignal <i2porignal@yandex.ru>
Date: Tue, 6 Dec 2016 16:23:52 -0500
Subject: [PATCH 7/7] clean up incomplete messages

---
 TunnelEndpoint.cpp | 9 +++++++++
 TunnelEndpoint.h   | 1 +
 2 files changed, 10 insertions(+)

diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp
index 23cf16f3..b4ddc109 100644
--- a/TunnelEndpoint.cpp
+++ b/TunnelEndpoint.cpp
@@ -116,6 +116,7 @@ namespace tunnel
 						if (!isFollowOnFragment) // create new incomlete message
 						{
 							m.nextFragmentNum = 1;
+							m.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
 							auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
 							if (ret.second)
 								HandleOutOfSequenceFragments (msgID, ret.first->second);
@@ -284,6 +285,14 @@ namespace tunnel
 			else
 				++it;
 		}
+		// incomplete messages
+		for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
+		{
+			if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
+				it = m_IncompleteMessages.erase (it);
+			else
+				++it;
+		}
 	}	
 }		
 }
diff --git a/TunnelEndpoint.h b/TunnelEndpoint.h
index 60c4fc0a..e13ced34 100644
--- a/TunnelEndpoint.h
+++ b/TunnelEndpoint.h
@@ -15,6 +15,7 @@ namespace tunnel
 	{	
 		struct TunnelMessageBlockEx: public TunnelMessageBlock
 		{
+			uint64_t receiveTime; // milliseconds since epoch
 			uint8_t nextFragmentNum;
 		};