diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java
index 8295e9f1..777ca748 100755
--- a/android/src/org/purplei2p/i2pd/I2PDActivity.java
+++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java
@@ -15,6 +15,7 @@ import java.util.TimerTask;
 
 import android.Manifest;
 import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
@@ -25,6 +26,10 @@ import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.res.AssetManager;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Build;
@@ -41,6 +46,7 @@ import android.widget.Toast;
 
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
 
@@ -63,6 +69,7 @@ public class I2PDActivity extends Activity {
 
 	private TextView textView;
 	private boolean assetsCopied;
+	private NetworkStateCallback networkCallback;
 	private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
 	//private ConfigParser parser = new ConfigParser(i2pdpath); // TODO:
 
@@ -116,7 +123,7 @@ public class I2PDActivity extends Activity {
 		daemonStateUpdatedListener.daemonStateUpdate();
 
 		 // request permissions
-		if (Build.VERSION.SDK_INT >= 23) {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 			if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
 				ActivityCompat.requestPermissions(this,
 					new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
@@ -137,6 +144,10 @@ public class I2PDActivity extends Activity {
 		}
 
 		openBatteryOptimizationDialogIfNeeded();
+
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+			registerNetworkCallback();
+		}
 	}
 
 	@Override
@@ -244,7 +255,7 @@ public class I2PDActivity extends Activity {
 	}
 
 	private boolean isBatteryOptimizationsOpenOsDialogApiAvailable() {
-		return android.os.Build.VERSION.SDK_INT >= 23;
+		return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
 	}
 
 	@Override
@@ -631,6 +642,33 @@ public class I2PDActivity extends Activity {
 		return "show_battery_optimization" + (device == null ? "" : device);
 	}
 
+	@TargetApi(Build.VERSION_CODES.M)
+	private void registerNetworkCallback() {
+	ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+	NetworkRequest request = new NetworkRequest.Builder()
+			.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+			.build();
+	networkCallback = new NetworkStateCallback();
+	connectivityManager.registerNetworkCallback(request, networkCallback);
+	}
+
+	@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+	private final class NetworkStateCallback extends ConnectivityManager.NetworkCallback {
+		@Override
+		public void onAvailable(Network network) {
+			super.onAvailable(network);
+			I2PD_JNI.onNetworkStateChanged(true);
+			Log.i(TAG, "NetworkCallback.onAvailable");
+		}
+
+		@Override
+		public void onLost(Network network) {
+			super.onLost(network);
+			I2PD_JNI.onNetworkStateChanged(false);
+			Log.i(TAG, " NetworkCallback.onLost");
+		}
+	}
+
 	private void quit() {
 		try {
 			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp
index b924a108..fc479532 100644
--- a/libi2pd/Config.cpp
+++ b/libi2pd/Config.cpp
@@ -108,8 +108,8 @@ namespace config {
 			("httpproxy.latency.max", value<std::string>()->default_value("0"),       "HTTP proxy max latency for tunnels")
 			("httpproxy.outproxy", value<std::string>()->default_value(""),           "HTTP proxy upstream out proxy url")
 			("httpproxy.addresshelper", value<bool>()->default_value(true),           "Enable or disable addresshelper")
-			("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("1"), "Local destination's LeaseSet type")
-			("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0"), "Local destination's LeaseSet encryption type")
+			("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type")
+			("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
 		;
 
 		options_description socksproxy("SOCKS Proxy options");
@@ -129,8 +129,8 @@ namespace config {
 			("socksproxy.outproxy.enabled", value<bool>()->default_value(false),       "Enable or disable SOCKS outproxy")
 			("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"),  "Upstream outproxy address for SOCKS Proxy")
 			("socksproxy.outproxyport", value<uint16_t>()->default_value(9050),        "Upstream outproxy port for SOCKS Proxy")
-			("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("1"), "Local destination's LeaseSet type")
-			("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0"), "Local destination's LeaseSet encryption type")
+			("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type")
+			("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
 		;
 
 		options_description sam("SAM bridge options");
diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp
index af76ab2b..07c95a7a 100644
--- a/libi2pd/SSU.cpp
+++ b/libi2pd/SSU.cpp
@@ -19,27 +19,25 @@ namespace transport
 {
 
 	SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
-		m_OnlyV6(true), m_IsRunning(false),
-		m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
-		m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
+		m_OnlyV6(true), m_IsRunning(false), m_Thread (nullptr), 
+		m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service),
 		m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
 		m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
 		m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
 		m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
-		m_TerminationTimerV6 (m_ServiceV6)
+		m_TerminationTimerV6 (m_Service)
 	{
 		OpenSocketV6 ();
 	}
 
 	SSUServer::SSUServer (int port):
-		m_OnlyV6(false), m_IsRunning(false),
-		m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
-		m_ReceiversThreadV6 (nullptr), 	m_Work (m_Service), m_WorkV6 (m_ServiceV6),
+		m_OnlyV6(false), m_IsRunning(false), m_Thread (nullptr),
+		m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), 
 		m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
 		m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
 		m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
 		m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
-		m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
+		m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service)
 	{
 		OpenSocket ();
 		if (context.SupportsV6 ())
@@ -98,7 +96,8 @@ namespace transport
 		if (context.SupportsV6 ())
 		{
 			m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
-			m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
+			if (!m_Thread)		
+				m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
 			m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
 			ScheduleTerminationV6 ();
 		}
@@ -114,7 +113,6 @@ namespace transport
 		m_TerminationTimerV6.cancel ();
 		m_Service.stop ();
 		m_Socket.close ();
-		m_ServiceV6.stop ();
 		m_SocketV6.close ();
 		m_ReceiversService.stop ();
 		m_ReceiversServiceV6.stop ();
@@ -136,12 +134,6 @@ namespace transport
 			delete m_ReceiversThreadV6;
 			m_ReceiversThreadV6 = nullptr;
 		}
-		if (m_ThreadV6)
-		{
-			m_ThreadV6->join ();
-			delete m_ThreadV6;
-			m_ThreadV6 = nullptr;
-		}
 	}
 
 	void SSUServer::Run ()
@@ -159,21 +151,6 @@ namespace transport
 		}
 	}
 
-	void SSUServer::RunV6 ()
-	{
-		while (m_IsRunning)
-		{
-			try
-			{
-				m_ServiceV6.run ();
-			}
-			catch (std::exception& ex)
-			{
-				LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
-			}
-		}
-	}
-
 	void SSUServer::RunReceivers ()
 	{
 		while (m_IsRunning)
@@ -358,7 +335,7 @@ namespace transport
 				}
 			}
 
-			m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
+			m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
 			ReceiveV6 ();
 		}
 		else
@@ -456,8 +433,7 @@ namespace transport
 			else
 			{
 				boost::asio::ip::udp::endpoint remoteEndpoint (addr, port);
-				auto& s = addr.is_v6 () ? m_ServiceV6 : m_Service;
-				s.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
+				m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
 			}
 		}
 	}
@@ -841,7 +817,7 @@ namespace transport
 					auto session = it.second;
 					if (it.first != session->GetRemoteEndpoint ())
 						LogPrint (eLogWarning, "SSU: remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
-					m_ServiceV6.post ([session]
+					m_Service.post ([session]
 						{
 							LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
 							session->Failed ();
diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h
index 6a79f754..213f379f 100644
--- a/libi2pd/SSU.h
+++ b/libi2pd/SSU.h
@@ -64,7 +64,6 @@ namespace transport
 			void DeleteAllSessions ();
 
 			boost::asio::io_service& GetService () { return m_Service; };
-			boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; };
 			const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
 			void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
 			void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
@@ -82,7 +81,6 @@ namespace transport
 			void OpenSocket ();
 			void OpenSocketV6 ();
 			void Run ();
-			void RunV6 ();
 			void RunReceivers ();
 			void RunReceiversV6 ();
 			void Receive ();
@@ -122,9 +120,9 @@ namespace transport
 
 			bool m_OnlyV6;
 			bool m_IsRunning;
-			std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread, * m_ReceiversThreadV6;
-			boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService, m_ReceiversServiceV6;
-			boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork, m_ReceiversWorkV6;
+			std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
+			boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
+			boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
 			boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
 			boost::asio::ip::udp::socket m_Socket, m_SocketV6;
 			boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer,
diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp
index 9ce6e2e3..860c2be3 100644
--- a/libi2pd/SSUSession.cpp
+++ b/libi2pd/SSUSession.cpp
@@ -49,7 +49,7 @@ namespace transport
 
 	boost::asio::io_service& SSUSession::GetService ()
 	{
-		return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService ();
+		return m_Server.GetService ();
 	}
 
 	void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp
index 4e0aa6a5..c6e90ad2 100644
--- a/libi2pd/Transports.cpp
+++ b/libi2pd/Transports.cpp
@@ -501,7 +501,7 @@ namespace transport
 					{
 						auto addr = router->GetSSUV6Address ();
 						if (addr)
-							m_SSUServer->GetServiceV6 ().post ([this, router, addr]
+							m_SSUServer->GetService ().post ([this, router, addr]
 							{
 								m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false);
 							});
diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp
index 04f50e6f..ab868916 100644
--- a/libi2pd_client/ClientContext.cpp
+++ b/libi2pd_client/ClientContext.cpp
@@ -456,7 +456,7 @@ namespace client
 		options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
 		options[I2CP_PARAM_STREAMING_ANSWER_PINGS] = GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false);
 		options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
-		std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "");
+		std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "" : "0,4");
 		if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType;
 		std::string privKey = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_PRIV_KEY, "");
 		if (privKey.length () > 0) options[I2CP_PARAM_LEASESET_PRIV_KEY] = privKey;
diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp
index 24c2496b..80274d86 100644
--- a/libi2pd_client/I2CP.cpp
+++ b/libi2pd_client/I2CP.cpp
@@ -226,14 +226,13 @@ namespace client
 	}
 		
 	I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
-		m_Owner (owner), m_Socket (socket), m_Payload (nullptr),
-		m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
+		m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF), 
+		m_MessageID (0), m_IsSendAccepted (true)
 	{
 	}
 
 	I2CPSession::~I2CPSession ()
 	{
-		delete[] m_Payload;
 	}
 
 	void I2CPSession::Start ()
@@ -264,6 +263,11 @@ namespace client
 
 	void I2CPSession::ReceiveHeader ()
 	{
+		if (!m_Socket) 
+		{
+			LogPrint (eLogError, "I2CP: Can't receive header");
+			return;
+		}	
 		boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Header, I2CP_HEADER_SIZE),
 			boost::asio::transfer_all (),
 			std::bind (&I2CPSession::HandleReceivedHeader, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@@ -279,10 +283,7 @@ namespace client
 			if (m_PayloadLen > 0)
 			{
 				if (m_PayloadLen <= I2CP_MAX_MESSAGE_LENGTH)
-				{
-					m_Payload = new uint8_t[m_PayloadLen];
 					ReceivePayload ();
-				}
 				else
 				{
 					LogPrint (eLogError, "I2CP: Unexpected payload length ", m_PayloadLen);
@@ -299,6 +300,11 @@ namespace client
 
 	void I2CPSession::ReceivePayload ()
 	{
+		if (!m_Socket) 
+		{	
+			LogPrint (eLogError, "I2CP: Can't receive payload");
+			return;
+		}	
 		boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Payload, m_PayloadLen),
 			boost::asio::transfer_all (),
 			std::bind (&I2CPSession::HandleReceivedPayload, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@@ -311,8 +317,6 @@ namespace client
 		else
 		{
 			HandleMessage ();
-			delete[] m_Payload;
-			m_Payload = nullptr;
 			m_PayloadLen = 0;
 			ReceiveHeader (); // next message
 		}
@@ -345,6 +349,11 @@ namespace client
 
 	void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
 	{
+		if (len > I2CP_MAX_MESSAGE_LENGTH)
+		{
+			LogPrint (eLogError, "I2CP: Message to send is too long ", len);
+			return;
+		}	
 		auto socket = m_Socket;
 		if (socket)
 		{
diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h
index 4c6b7531..c5dc80e7 100644
--- a/libi2pd_client/I2CP.h
+++ b/libi2pd_client/I2CP.h
@@ -179,7 +179,7 @@ namespace client
 
 			I2CPServer& m_Owner;
 			std::shared_ptr<proto::socket> m_Socket;
-			uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload;
+			uint8_t m_Header[I2CP_HEADER_SIZE], m_Payload[I2CP_MAX_MESSAGE_LENGTH];
 			size_t m_PayloadLen;
 
 			std::shared_ptr<I2CPDestination> m_Destination;