diff -Nru i2pd-0.9.0/AddressBook.cpp i2pd-0.10.0/AddressBook.cpp --- i2pd-0.9.0/AddressBook.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/AddressBook.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -460,18 +460,15 @@ auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident); if (!leaseSet) { - bool found = false; std::unique_lock l(newDataReceivedMutex); i2p::client::context.GetSharedLocalDestination ()->RequestDestination (ident, - [&newDataReceived, &found](bool success) + [&newDataReceived, &leaseSet](std::shared_ptr ls) { - found = success; + leaseSet = ls; newDataReceived.notify_all (); }); if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) LogPrint (eLogError, "Subscription LeseseSet request timeout expired"); - if (found) - leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident); } if (leaseSet) { diff -Nru i2pd-0.9.0/aes.cpp i2pd-0.10.0/aes.cpp --- i2pd-0.9.0/aes.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/aes.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -280,74 +280,76 @@ #endif } - void TunnelEncryption::Encrypt (uint8_t * payload) + void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) { #ifdef AESNI __asm__ ( // encrypt IV - "movups (%[payload]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" EncryptAES256(sched_iv) "movaps %%xmm0, %%xmm1 \n" // double IV encryption EncryptAES256(sched_iv) - "movups %%xmm0, (%[payload]) \n" + "movups %%xmm0, (%[out]) \n" // encrypt data, IV is xmm1 "1: \n" - "add $16, %[payload] \n" - "movups (%[payload]), %%xmm0 \n" + "add $16, %[in] \n" + "add $16, %[out] \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched_l) "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[payload]) \n" + "movups %%xmm0, (%[out]) \n" "dec %[num] \n" "jnz 1b \n" : : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()), - [payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes + [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "cc", "memory" ); #else - m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv - m_LayerEncryption.SetIV (payload); - m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data - m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv + m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv + m_LayerEncryption.SetIV (out); + m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv #endif } - void TunnelDecryption::Decrypt (uint8_t * payload) + void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) { #ifdef AESNI __asm__ ( // decrypt IV - "movups (%[payload]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" DecryptAES256(sched_iv) "movaps %%xmm0, %%xmm1 \n" // double IV encryption DecryptAES256(sched_iv) - "movups %%xmm0, (%[payload]) \n" + "movups %%xmm0, (%[out]) \n" // decrypt data, IV is xmm1 "1: \n" - "add $16, %[payload] \n" - "movups (%[payload]), %%xmm0 \n" + "add $16, %[in] \n" + "add $16, %[out] \n" + "movups (%[in]), %%xmm0 \n" "movaps %%xmm0, %%xmm2 \n" DecryptAES256(sched_l) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[payload]) \n" + "movups %%xmm0, (%[out]) \n" "movaps %%xmm2, %%xmm1 \n" "dec %[num] \n" "jnz 1b \n" : : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()), - [payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes + [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); #else - m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv - m_LayerDecryption.SetIV (payload); - m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data - m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv + m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv + m_LayerDecryption.SetIV (out); + m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv #endif } } diff -Nru i2pd-0.9.0/aes.h i2pd-0.10.0/aes.h --- i2pd-0.9.0/aes.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/aes.h 2015-07-06 16:11:17.000000000 +0000 @@ -185,7 +185,7 @@ m_IVEncryption.SetKey (ivKey); } - void Encrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data) + void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data) private: @@ -207,7 +207,7 @@ m_IVDecryption.SetKey (ivKey); } - void Decrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data) + void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data) private: diff -Nru i2pd-0.9.0/BOB.cpp i2pd-0.10.0/BOB.cpp --- i2pd-0.9.0/BOB.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/BOB.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -33,27 +33,22 @@ void BOBI2PInboundTunnel::Accept () { - auto receiver = new AddressReceiver (); - receiver->socket = new boost::asio::ip::tcp::socket (GetService ()); + auto receiver = std::make_shared (); + receiver->socket = std::make_shared (GetService ()); m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this, std::placeholders::_1, receiver)); } - void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver) + void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr receiver) { if (!ecode) { Accept (); ReceiveAddress (receiver); } - else - { - delete receiver->socket; - delete receiver; - } } - void BOBI2PInboundTunnel::ReceiveAddress (AddressReceiver * receiver) + void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr receiver) { receiver->socket->async_read_some (boost::asio::buffer( receiver->buffer + receiver->bufferOffset, @@ -63,14 +58,10 @@ } void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, - AddressReceiver * receiver) + std::shared_ptr receiver) { if (ecode) - { LogPrint ("BOB inbound tunnel read error: ", ecode.message ()); - delete receiver->socket; - delete receiver; - } else { receiver->bufferOffset += bytes_transferred; @@ -86,8 +77,6 @@ if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident)) { LogPrint (eLogError, "BOB address ", receiver->buffer, " not found"); - delete receiver->socket; - delete receiver; return; } auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident); @@ -96,46 +85,32 @@ else GetLocalDestination ()->RequestDestination (ident, std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete, - this, std::placeholders::_1, receiver, ident)); + this, std::placeholders::_1, receiver)); } else { if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE) ReceiveAddress (receiver); else - { LogPrint ("BOB missing inbound address "); - delete receiver->socket; - delete receiver; - } } } } - void BOBI2PInboundTunnel::HandleDestinationRequestComplete (bool success, AddressReceiver * receiver, i2p::data::IdentHash ident) + void BOBI2PInboundTunnel::HandleDestinationRequestComplete (std::shared_ptr leaseSet, std::shared_ptr receiver) { - if (success) - { - auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident); - if (leaseSet) - { - CreateConnection (receiver, leaseSet); - return; - } - else - LogPrint ("LeaseSet for BOB inbound destination not found"); - } - delete receiver->socket; - delete receiver; + if (leaseSet) + CreateConnection (receiver, leaseSet); + else + LogPrint ("LeaseSet for BOB inbound destination not found"); } - void BOBI2PInboundTunnel::CreateConnection (AddressReceiver * receiver, std::shared_ptr leaseSet) + void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr receiver, std::shared_ptr leaseSet) { LogPrint ("New BOB inbound connection"); auto connection = std::make_shared(this, receiver->socket, leaseSet); AddHandler (connection); connection->I2PConnect (receiver->data, receiver->dataLen); - delete receiver; } BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port, @@ -167,7 +142,7 @@ { if (stream) { - auto conn = std::make_shared (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint, m_IsQuiet); + auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), m_Endpoint, m_IsQuiet); AddHandler (conn); conn->Connect (); } @@ -493,13 +468,29 @@ void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: lookup ", operand); - i2p::data::IdentityEx addr; - if (!context.GetAddressBook ().GetAddress (operand, addr)) + i2p::data::IdentHash ident; + if (!context.GetAddressBook ().GetIdentHash (operand, ident) || !m_CurrentDestination) { SendReplyError ("Address Not found"); return; - } - SendReplyOK (addr.ToBase64 ().c_str ()); + } + auto localDestination = m_CurrentDestination->GetLocalDestination (); + auto leaseSet = localDestination->FindLeaseSet (ident); + if (leaseSet) + SendReplyOK (leaseSet->GetIdentity ().ToBase64 ().c_str ()); + else + { + auto s = shared_from_this (); + localDestination->RequestDestination (ident, + [s](std::shared_ptr ls) + { + if (ls) + s->SendReplyOK (ls->GetIdentity ().ToBase64 ().c_str ()); + else + s->SendReplyError ("LeaseSet Not found"); + } + ); + } } void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len) diff -Nru i2pd-0.9.0/BOB.h i2pd-0.10.0/BOB.h --- i2pd-0.9.0/BOB.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/BOB.h 2015-07-06 16:11:17.000000000 +0000 @@ -57,9 +57,9 @@ { struct AddressReceiver { - boost::asio::ip::tcp::socket * socket; + std::shared_ptr socket; char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address - uint8_t * data; + uint8_t * data; // pointer to buffer size_t dataLen, bufferOffset; AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {}; @@ -76,15 +76,15 @@ private: void Accept (); - void HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver); + void HandleAccept (const boost::system::error_code& ecode, std::shared_ptr receiver); - void ReceiveAddress (AddressReceiver * receiver); + void ReceiveAddress (std::shared_ptr receiver); void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, - AddressReceiver * receiver); + std::shared_ptr receiver); - void HandleDestinationRequestComplete (bool success, AddressReceiver * receiver, i2p::data::IdentHash ident); + void HandleDestinationRequestComplete (std::shared_ptr leaseSet, std::shared_ptr receiver); - void CreateConnection (AddressReceiver * receiver, std::shared_ptr leaseSet); + void CreateConnection (std::shared_ptr receiver, std::shared_ptr leaseSet); private: @@ -127,6 +127,7 @@ void CreateInboundTunnel (int port); void CreateOutboundTunnel (const std::string& address, int port, bool quiet); const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); }; + std::shared_ptr GetLocalDestination () const { return m_LocalDestination; }; private: diff -Nru i2pd-0.9.0/build/autotools/Makefile.in i2pd-0.10.0/build/autotools/Makefile.in --- i2pd-0.9.0/build/autotools/Makefile.in 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/build/autotools/Makefile.in 2015-07-06 16:11:17.000000000 +0000 @@ -116,7 +116,7 @@ aes.$(OBJEXT) base64.$(OBJEXT) i2p.$(OBJEXT) util.$(OBJEXT) \ SAM.$(OBJEXT) Destination.$(OBJEXT) ClientContext.$(OBJEXT) \ Datagram.$(OBJEXT) SSUSession.$(OBJEXT) BOB.$(OBJEXT) \ - I2PControl.$(OBJEXT) Profiling.$(OBJEXT) + I2PControl.$(OBJEXT) Profiling.$(OBJEXT) Signature.$(OBJEXT) i2p_OBJECTS = $(am_i2p_OBJECTS) i2p_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) @@ -328,7 +328,8 @@ TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \ base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \ ClientContext.cpp DataFram.cpp SSUSession.cpp BOB.cpp \ - I2PControl.cpp Profiling.cpp \ + I2PControl.cpp Profiling.cpp Signature.cpp \ + NetDbRequests.cpp \ \ AddressBook.h CryptoConst.h Daemon.h ElGamal.h \ Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \ @@ -341,7 +342,7 @@ TunnelPool.h UPnP.h aes.h base64.h config.h hmac.h \ util.h version.h Destination.h ClientContext.h \ TransportSession.h Datagram.h SSUSession.h BOB.h \ - I2PControl.h Profiling.h + I2PControl.h Profiling.h NetDbRequests.h AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \ @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \ @@ -493,6 +494,9 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientContext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Datagram.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSUSession.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Profiling.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Signature.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetDbRequests.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff -Nru i2pd-0.9.0/build/BUILD_NOTES.md i2pd-0.10.0/build/BUILD_NOTES.md --- i2pd-0.9.0/build/BUILD_NOTES.md 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/build/BUILD_NOTES.md 2015-07-06 16:11:17.000000000 +0000 @@ -24,6 +24,7 @@ * libboost-program-options-dev * libboost-regex-dev * libboost-system-dev +* libboost-date-time-dev * libcrypto++-dev FreeBSD diff -Nru i2pd-0.9.0/build/CMakeLists.txt i2pd-0.10.0/build/CMakeLists.txt --- i2pd-0.9.0/build/CMakeLists.txt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/build/CMakeLists.txt 2015-07-06 16:11:17.000000000 +0000 @@ -1,4 +1,4 @@ -cmake_minimum_required ( VERSION 2.8.5 ) +cmake_minimum_required ( VERSION 2.8.12 ) project ( "i2pd" ) # configurale options @@ -7,6 +7,8 @@ option(WITH_LIBRARY "Build library" ON) option(WITH_BINARY "Build binary" ON) option(WITH_STATIC "Static build" OFF) +option(WITH_UPNP "Include support for UPnP client" OFF) +option(WITH_PCH "Use precompiled header" OFF) # paths set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) @@ -21,6 +23,7 @@ "${CMAKE_SOURCE_DIR}/LeaseSet.cpp" "${CMAKE_SOURCE_DIR}/Log.cpp" "${CMAKE_SOURCE_DIR}/NTCPSession.cpp" + "${CMAKE_SOURCE_DIR}/NetDbRequests.cpp" "${CMAKE_SOURCE_DIR}/NetDb.cpp" "${CMAKE_SOURCE_DIR}/Profiling.cpp" "${CMAKE_SOURCE_DIR}/Reseed.cpp" @@ -40,9 +43,17 @@ "${CMAKE_SOURCE_DIR}/aes.cpp" "${CMAKE_SOURCE_DIR}/base64.cpp" "${CMAKE_SOURCE_DIR}/util.cpp" - "${CMAKE_SOURCE_DIR}/Datagram.cpp" + "${CMAKE_SOURCE_DIR}/Datagram.cpp" + "${CMAKE_SOURCE_DIR}/Signature.cpp" + "${CMAKE_SOURCE_DIR}/UPnP.cpp" ) +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + list (APPEND COMMON_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp") +endif () + +add_library(common ${COMMON_SRC}) + set (DAEMON_SRC "${CMAKE_SOURCE_DIR}/BOB.cpp" "${CMAKE_SOURCE_DIR}/ClientContext.cpp" @@ -54,10 +65,16 @@ "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SOCKS.cpp" - "${CMAKE_SOURCE_DIR}/UPnP.cpp" "${CMAKE_SOURCE_DIR}/i2p.cpp" ) +if (WITH_UPNP) + add_definitions(-DUSE_UPNP) + if (NOT MSVC) + set(DL_LIB ${CMAKE_DL_LIBS}) + endif () +endif () + set (LIBRARY_SRC "${CMAKE_SOURCE_DIR}/api.cpp" ) @@ -69,14 +86,19 @@ source_group ("Source Files" FILES ${COMMON_SRC} ${DAEMON_SRC} ${LIBRARY_SRC}) # Default build is Debug -if (CMAKE_BUILD_TYPE STREQUAL "Release") - add_definitions( "-pedantic" ) -else () +if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif () # compiler flags customization (by vendor) -add_definitions ( "-Wall -Wextra -fPIC" ) +if (NOT MSVC) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch" ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" ) + # TODO: The following is incompatible with static build and enabled hardening for OpenWRT. + # Multiple definitions of __stack_chk_fail (libssp & libc) + set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections" ) + set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above +endif () # check for c++11 support include(CheckCXXCompilerFlag) @@ -86,7 +108,7 @@ add_definitions( "-std=c++11" ) elseif (CXX0X_SUPPORTED) # gcc 4.6 add_definitions( "-std=c++0x" ) -else () +elseif (NOT MSVC) message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?") endif () @@ -113,6 +135,7 @@ list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp") elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp") + list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp") endif () if (WITH_AESNI) @@ -120,9 +143,71 @@ endif() # libraries +# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826 +# use imported Threads::Threads instead +set(THREADS_PREFER_PTHREAD_FLAG ON) find_package ( Threads REQUIRED ) +if(THREADS_HAVE_PTHREAD_ARG) # compile time flag + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") +endif() + +if (WITH_STATIC) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_RUNTIME ON) + if (WIN32) + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace + # Note that you might need to rebuild Crypto++ + foreach(flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif(${flag_var} MATCHES "/MD") + endforeach(flag_var) + else () + set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + endif () + set(BUILD_SHARED_LIBS OFF) + if (${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*") + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" ) + # set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" ) + set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel" ) + endif () +else() + if (NOT WIN32) + # TODO: Consider separate compilation for COMMON_SRC for library. + # No need in -fPIC overhead for binary if not interested in library + # HINT: revert c266cff CMakeLists.txt: compilation speed up + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" ) + endif () + add_definitions(-DBOOST_ALL_DYN_LINK) +endif () + +if (WITH_PCH) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + add_library(stdafx STATIC "${CMAKE_SOURCE_DIR}/stdafx.cpp") + if(MSVC) + target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm135) + add_custom_command(TARGET stdafx POST_BUILD + COMMAND xcopy /y stdafx.dir\\$\\*.pdb common.dir\\$\\ + COMMAND xcopy /y stdafx.dir\\$\\*.pdb i2pd-bin.dir\\$\\ + COMMAND xcopy /y stdafx.dir\\$\\*.pdb i2pd.dir\\$\\ + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + target_compile_options(common PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$/stdafx.pch") + else() + string(TOUPPER ${CMAKE_BUILD_TYPE} BTU) + get_directory_property(DEFS DEFINITIONS) + string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}") + add_custom_command(TARGET stdafx PRE_BUILD + COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h + ) + target_compile_options(common PRIVATE -include stdafx.h) + endif() + target_link_libraries(common stdafx) +endif() -find_package ( Boost COMPONENTS system filesystem regex program_options REQUIRED ) +find_package ( Boost COMPONENTS system filesystem regex program_options date_time thread chrono REQUIRED ) if(NOT DEFINED Boost_INCLUDE_DIRS) message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") endif() @@ -132,8 +217,13 @@ message(SEND_ERROR "Could not find Crypto++. Please download and install it first!") endif() +find_package ( MiniUPnPc ) +if (NOT ${MINIUPNPC_FOUND}) + set(WITH_UPNP OFF) +endif() + # load includes -include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR} "${CMAKE_SOURCE_DIR}/..") +include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR} ) # show summary message(STATUS "---------------------------------------") @@ -148,30 +238,62 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " BINARY : ${WITH_BINARY}") message(STATUS " STATIC BUILD : ${WITH_STATIC}") +message(STATUS " UPnP : ${WITH_UPNP}") +message(STATUS " PCH : ${WITH_PCH}") message(STATUS "---------------------------------------") #Handle paths nicely include(GNUInstallDirs) if (WITH_BINARY) - add_executable ( "${PROJECT_NAME}-bin" ${COMMON_SRC} ${DAEMON_SRC}) + add_executable ( "${PROJECT_NAME}-bin" ${DAEMON_SRC} ) + if(NOT MSVC) # FIXME: incremental linker file name (.ilk) collision for dll & exe set_target_properties("${PROJECT_NAME}-bin" PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") + if (WITH_STATIC) + set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-static" ) + endif () + endif() + + if (WITH_PCH) + if (MSVC) + target_compile_options("${PROJECT_NAME}-bin" PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$/stdafx.pch") + else() + target_compile_options("${PROJECT_NAME}-bin" PRIVATE -include stdafx.h) + endif() + endif() if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-z relro -z now" ) endif () - if (WITH_STATIC) - set(BUILD_SHARED_LIBS OFF) - set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-static" ) - endif () - - target_link_libraries( "${PROJECT_NAME}-bin" ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) + # FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04 + list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES) + if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*") + list(REMOVE_AT Boost_LIBRARIES -1) + endif() + target_link_libraries( "${PROJECT_NAME}-bin" common ${DL_LIB} ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) install(TARGETS "${PROJECT_NAME}-bin" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) + if (MSVC) + install(FILES $ DESTINATION "bin" CONFIGURATIONS DEBUG) + endif () endif () if (WITH_LIBRARY) - add_library(${PROJECT_NAME} SHARED ${COMMON_SRC} ${LIBRARY_SRC}) - install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) + if (MSVC) + # FIXME: DLL would not have any symbols unless we use __declspec(dllexport) through out the code + add_library(${PROJECT_NAME} STATIC ${LIBRARY_SRC}) + else () + add_library(${PROJECT_NAME} ${LIBRARY_SRC}) + target_link_libraries( ${PROJECT_NAME} common ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES}) + endif () + if (WITH_PCH) + if (MSVC) + add_dependencies(${PROJECT_NAME} stdafx) + target_compile_options(${PROJECT_NAME} PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$/stdafx.pch") + else() + target_compile_options(${PROJECT_NAME} PRIVATE -include stdafx.h) + endif() + endif() + install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif () diff -Nru i2pd-0.9.0/build/cmake_modules/FindCryptoPP.cmake i2pd-0.10.0/build/cmake_modules/FindCryptoPP.cmake --- i2pd-0.9.0/build/cmake_modules/FindCryptoPP.cmake 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/build/cmake_modules/FindCryptoPP.cmake 2015-07-06 16:11:17.000000000 +0000 @@ -4,14 +4,14 @@ set(CRYPTO++_FOUND TRUE) else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES) - find_path(CRYPTO++_INCLUDE_DIR cryptlib.h - /usr/include/crypto++ - /usr/include/cryptopp - /usr/local/include/crypto++ - /usr/local/include/cryptopp - /opt/local/include/crypto++ - /opt/local/include/cryptopp + find_path(CRYPTO++_INCLUDE_DIR cryptopp/cryptlib.h + /usr/include + /usr/local/include $ENV{SystemDrive}/Crypto++/include + $ENV{CRYPTOPP} + $ENV{CRYPTOPP}/.. + $ENV{CRYPTOPP}/include + ${PROJECT_SOURCE_DIR}/../.. ) find_library(CRYPTO++_LIBRARIES NAMES cryptopp @@ -20,8 +20,34 @@ /usr/local/lib /opt/local/lib $ENV{SystemDrive}/Crypto++/lib + $ENV{CRYPTOPP}/lib ) + if(MSVC AND NOT CRYPTO++_LIBRARIES) # Give a chance for MSVC multiconfig + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(PLATFORM x64) + else() + set(PLATFORM Win32) + endif() + find_library(CRYPTO++_LIBRARIES_RELEASE NAMES cryptlib cryptopp + HINTS + ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Release + PATHS + $ENV{CRYPTOPP}/Win32/Output/Release + ) + find_library(CRYPTO++_LIBRARIES_DEBUG NAMES cryptlib cryptopp + HINTS + ${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Debug + PATHS + $ENV{CRYPTOPP}/Win32/Output/Debug + ) + set(CRYPTO++_LIBRARIES + debug ${CRYPTO++_LIBRARIES_DEBUG} + optimized ${CRYPTO++_LIBRARIES_RELEASE} + CACHE PATH "Path to Crypto++ library" FORCE + ) + endif() + if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES) set(CRYPTO++_FOUND TRUE) message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}") diff -Nru i2pd-0.9.0/build/cmake_modules/FindMiniUPnPc.cmake i2pd-0.10.0/build/cmake_modules/FindMiniUPnPc.cmake --- i2pd-0.9.0/build/cmake_modules/FindMiniUPnPc.cmake 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/build/cmake_modules/FindMiniUPnPc.cmake 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,25 @@ +# - Find MINIUPNPC + +if(MINIUPNPC_INCLUDE_DIR) + set(MINIUPNPC_FOUND TRUE) + +else() + find_path(MINIUPNPC_INCLUDE_DIR miniupnpc.h + /usr/include/miniupnpc + /usr/local/include/miniupnpc + /opt/local/include/miniupnpc + $ENV{SystemDrive}/miniupnpc + ${PROJECT_SOURCE_DIR}/../../miniupnpc + ) + + if(MINIUPNPC_INCLUDE_DIR) + set(MINIUPNPC_FOUND TRUE) + message(STATUS "Found MiniUPnP headers: ${MINIUPNPC_INCLUDE_DIR}") + else() + set(MINIUPNPC_FOUND FALSE) + message(STATUS "MiniUPnP not found.") + endif() + + mark_as_advanced(MINIUPNPC_INCLUDE_DIR) + +endif() diff -Nru i2pd-0.9.0/ClientContext.cpp i2pd-0.10.0/ClientContext.cpp --- i2pd-0.9.0/ClientContext.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/ClientContext.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -295,7 +295,7 @@ LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists"); numClientTunnels++; } - else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER) + else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP) { // mandatory params std::string host = section.second.get (I2P_SERVER_TUNNEL_HOST); @@ -306,7 +306,7 @@ std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); auto localDestination = LoadLocalDestination (keys, true); - auto serverTunnel = new I2PServerTunnel (host, port, localDestination, inPort); + I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort); if (accessList.length () > 0) { std::set idents; diff -Nru i2pd-0.9.0/ClientContext.h i2pd-0.10.0/ClientContext.h --- i2pd-0.9.0/ClientContext.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/ClientContext.h 2015-07-06 16:11:17.000000000 +0000 @@ -20,6 +20,7 @@ const char I2P_TUNNELS_SECTION_TYPE[] = "type"; const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; + const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http"; const char I2P_CLIENT_TUNNEL_PORT[] = "port"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; const char I2P_CLIENT_TUNNEL_KEYS[] = "keys"; diff -Nru i2pd-0.9.0/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt i2pd-0.10.0/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt --- i2pd-0.9.0/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2zCCApOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBCMR8wHQYDVQQDExZpMnAt -bmV0ZGIuaW5ub3ZhdGlvLm5vMRIwEAYDVQQKEwlJbm5vdmF0aW8xCzAJBgNVBAYT -Ak5PMCIYDzIwMTQwMTIxMDUzMzMxWhgPMjAyNDAxMTkwNTMzMzFaMEIxHzAdBgNV -BAMTFmkycC1uZXRkYi5pbm5vdmF0aW8ubm8xEjAQBgNVBAoTCUlubm92YXRpbzEL -MAkGA1UEBhMCTk8wggFSMA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQC9WVet -EFeKAHmwgTUxJ/bRI4Gtjke3uj897eeZ15Y0SiqdHzypsEIWtXqx4G3W801xZzhv -UiAculvwRY4kpv3DnQE4sNTzbkAlvC6z4+CpFM2mhZ7o+YmozrIsNmQNCsvlxqJV -AD1mzqTFl/OB7LVtLmpSSd36IQFGmsh24XXa4pVH33e+NCZIGsdVwGsa4GoRuC9a -s/DiLI+x6zYRoY9cfOF2DuuOfKNMjSl65QUe4uHZCsRTb1q08NnPIidEFHr94kZH -Hph+MQs6MUVK1eT4yYt084S3cEWmWBQZVyAvWQ9q8EW+MoniOM7bBG2Bn9wu2F5x -kAKWTYfKSStW5CKSox9VSoopiUAtEIqhwgFGTISqhQyfOfyY97X2M47wvyWsl6dE -NxTgdvLD/o24rejBAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwIQYDVR0RBBowGIIW -aTJwLW5ldGRiLmlubm92YXRpby5ubzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNV -HQ8BAf8EBQMDByAAMB0GA1UdDgQWBBTaTuBpTAinNiT9PfKNRdIn3HrwxTANBgkq -hkiG9w0BAQsFAAOCATEAsYtojwAHiFwUqvCMIMJa5YN0Ms/QpjqZiENuGBpxvmVF -WVImX4s8K/qoBAKED8uKcRbMQd0FeDea7kMisJt5cblDzYuSv6wfeLXYkaT8/9H2 -X1pXhO/eghJ2U42RTgBkaW3mCI8ohk/GehU4tEXnbWRPHt6XDoSYDJdf2X8BPcgB -ZE10owLCw9c80QTuU+LCvbt8/F2USyNplUrogJGThzxrxZvxjGq6EcDj0iA0RRoG -5CUNrCB+JgFc+4bagI3E5B0skk/wn3Nl7mM8/Nf8b1QENmc8eYBZx2InA9769DHL -tNxzvE+OeMNlKy4M9WvLieIh6KmpYhHBG8ubJT8X+bZpJkh4rH6RzVYiXeCpX2iL -eoeSriGO0+8CJTBRbd5cXYd/COT0iAomMTelhcGVTA== ------END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/ieb9oopo.mooo.com2.crt i2pd-0.10.0/contrib/certificates/ssl/ieb9oopo.mooo.com2.crt --- i2pd-0.9.0/contrib/certificates/ssl/ieb9oopo.mooo.com2.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/ieb9oopo.mooo.com2.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIESzCCAzOgAwIBAgIJAKII1waVnWddMA0GCSqGSIb3DQEBCwUAMIG7MQswCQYD -VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll -Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG -A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u -Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDExMjIx -MzQzNThaFw0yMDA1MTQxMzQzNThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR -aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow -GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v -by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB -FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAMhcnkSifOMw5bd66UlvYVsc42H22Nuy64qhtJHtggofrwBooF38kRCBVFL8 -9Xjzr0xsSshvO6p7E+CEUtA8v55l5vNbUTAvGP9WmzeZyZuCFg9Heo3orNMbIK7m -ppwKhwh6tFEIEpUTz/+xF5NRt0+CqcS4aNHuH3JPwNugfTBuSa86GeSaqL7K4eEZ -bZXqQ16Onvi0yyMqRJDp/ijRFxr2eKGPWb55kuRSET9PxVhlgRKULZkr39Dh9q1c -wb9lAMLMRZIzPVnyvC9jWkIqSDl5bkAAto0n1Jkw92rRp6EVKgSLA/4vl9wTb6xf -WfT5cs7pykAE0WXBr9TqpS3okncCAwEAAaNQME4wHQYDVR0OBBYEFGeEOHhWiKwZ -TGbc7uuK3DD7YjYZMB8GA1UdIwQYMBaAFGeEOHhWiKwZTGbc7uuK3DD7YjYZMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAzRA/0OpJtCO4kQkTn/hux9 -dRi9T6B54Xav5jG53iAPLTeMxsaLkvweh2pZ3kvEUrQhvW0JF8QBrHTsgxzb4Wd6 -FNDHSgJbZv3uCjFtWeuUh+GTG1k9uwgNIEnx7J9Vp0JCi4ezi/HMNI7c+LjinM9f -hrAzclkeRPLYg645DkxckLyDUbrc9v1qWFoTpezXSBPO7n3Wk4sCytdoA1FkTdXh -RF4BWCl/3uOxcrn0TqoC9vCh8RcxnllOiOO5j4+PQ1Z6NkQ/5oRCK/jjaWc3Lr6/ -FicOZJe29BVnrPGynqe0Ky1o+kTdXFflKowfr7g8dwn8k9YavjtGbl1ZSHeuMF8= ------END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/ieb9oopo.mooo.com.crt i2pd-0.10.0/contrib/certificates/ssl/ieb9oopo.mooo.com.crt --- i2pd-0.9.0/contrib/certificates/ssl/ieb9oopo.mooo.com.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/ieb9oopo.mooo.com.crt 2015-07-06 16:11:17.000000000 +0000 @@ -1,25 +1,25 @@ -----BEGIN CERTIFICATE----- -MIIESzCCAzOgAwIBAgIJALGqvElYEEqyMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD +MIIESzCCAzOgAwIBAgIJAKII1waVnWddMA0GCSqGSIb3DQEBCwUAMIG7MQswCQYD VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u -Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDA0MTMx -NDI3MThaFw0zNDA0MDgxNDI3MThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR +Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDExMjIx +MzQzNThaFw0yMDA1MTQxMzQzNThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAN1CusoQ3OxJFTytbVMe7LPY8lnR7GIIQt5eCs0XTLl3ECclET1KLRo1c8Mv -vj5AwDRvL3Kw/oeDS+QvSRhgxG3lJ8i0soWDC/1LIX1NS/ZXG7hbycZ7YqAovCxU -958WPjUios73sAWUJrI8BbWFTYPWBB5lbyTaCooxtf6k7yB+CSwZnstEP/lbPNkf -Iupj+9B18ba21D2kQqZXyQRLX02d/rXq963BSkPX14Dxa7abw4lgDltvh2CzcoQH -VbQh3eGfPIIQGfvAAVEGsoy9fFt+xOUxp3KO7Y1VMKzegWqa2vBtWK+2nhpHfswq -eaE1qeVh12cG5kaVNP0o0hOUxkECAwEAAaNQME4wHQYDVR0OBBYEFIQ5U4EKfr0t -4L+RFe/RBFcDVoijMB8GA1UdIwQYMBaAFIQ5U4EKfr0t4L+RFe/RBFcDVoijMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGlNHzxF9tbS/Xr8jGpSdRLm -oIIoTr7+dIfFIy2TMAow0+gx1qEtWASUYIwbCP5mdMfhUjL8POfSwtTvgjw3LMoM -2zsGBvgGWs6VJbMPAgkgfsyjdJTM/IOiJtze6degn2bdZvAr1XiInLGMRMko7WyE -QQ1WJPcTUt8rNYVaCkq3CYioIlkb/C6M6ObHGSia0kwoZa6grD3CNUCa/c/dlFKO -E06qN72fsYihp0ghHkBaCxb+YfYpIAPIpfuuTSGkVYyjpY0a8EQ1JlzbJctQkX5r -sd9jfHsrZriAGCzdsL/diG8bUi9Yex/G0ip8GGEuHs5e2bJ6+7O/mPlL6SL/0tI= +ggEBAMhcnkSifOMw5bd66UlvYVsc42H22Nuy64qhtJHtggofrwBooF38kRCBVFL8 +9Xjzr0xsSshvO6p7E+CEUtA8v55l5vNbUTAvGP9WmzeZyZuCFg9Heo3orNMbIK7m +ppwKhwh6tFEIEpUTz/+xF5NRt0+CqcS4aNHuH3JPwNugfTBuSa86GeSaqL7K4eEZ +bZXqQ16Onvi0yyMqRJDp/ijRFxr2eKGPWb55kuRSET9PxVhlgRKULZkr39Dh9q1c +wb9lAMLMRZIzPVnyvC9jWkIqSDl5bkAAto0n1Jkw92rRp6EVKgSLA/4vl9wTb6xf +WfT5cs7pykAE0WXBr9TqpS3okncCAwEAAaNQME4wHQYDVR0OBBYEFGeEOHhWiKwZ +TGbc7uuK3DD7YjYZMB8GA1UdIwQYMBaAFGeEOHhWiKwZTGbc7uuK3DD7YjYZMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAzRA/0OpJtCO4kQkTn/hux9 +dRi9T6B54Xav5jG53iAPLTeMxsaLkvweh2pZ3kvEUrQhvW0JF8QBrHTsgxzb4Wd6 +FNDHSgJbZv3uCjFtWeuUh+GTG1k9uwgNIEnx7J9Vp0JCi4ezi/HMNI7c+LjinM9f +hrAzclkeRPLYg645DkxckLyDUbrc9v1qWFoTpezXSBPO7n3Wk4sCytdoA1FkTdXh +RF4BWCl/3uOxcrn0TqoC9vCh8RcxnllOiOO5j4+PQ1Z6NkQ/5oRCK/jjaWc3Lr6/ +FicOZJe29BVnrPGynqe0Ky1o+kTdXFflKowfr7g8dwn8k9YavjtGbl1ZSHeuMF8= -----END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/jp.reseed.i2p2.no.crt i2pd-0.10.0/contrib/certificates/ssl/jp.reseed.i2p2.no.crt --- i2pd-0.9.0/contrib/certificates/ssl/jp.reseed.i2p2.no.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/jp.reseed.i2p2.no.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFqTCCA5GgAwIBAgIJAPsJOCng4aEOMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV -BAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwD -STJQMRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJw -Mi5ubzAeFw0xNDA2MjgyMDQ3MThaFw0yNDA2MjUyMDQ3MThaMGsxCzAJBgNVBAYT -Ak5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwDSTJQ -MRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJwMi5u -bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlZBIbb4MHqLPpUy298 -PG5z7RFo4bO7CxW2LO8DgE93KNbdkZuYpt6KcAW/gkDfKCiXTxDjyqmzZeBeIbcS -ea96jFc/pTknkiiSm9NX4ATcyRwvKXn6DR/iOiofP3G/sEkxgIdv3BgEYsF5jPQY -KefG0Jvl612cIX+1jC3lRRePYPUZnWxIuokXglLApeyhNzTK/KHIsLzR+56ScltM -pwGlroTky5ekPx4ZnJCxI+qFXWcgqdoNixPUkOtceYm7u5gd1D+mQDuCB5zfB+Pw -Iy9BTARot9M3fMrcRRVfEIGWwN1+bRnZvr0A/sqYMUqGPiUVOMi/mzyqZVQ14CGy -0idRhUKdOb/HNSmcep0Jwp0cP+VD/nCNU4JLptTLdErpTJrmDn+zkuQPPSMTzTWg -Fh3ktRsJ5zKfrnrBGxeKbciZgRkVHyWpv3+0AgbD8C3HvDj4qpkIO6D2gf+TREyM -frDXN6luqkThQcUFv+huMaL3Iul2doYqw5YPAdel6/cCD12n/FoEj5UJ47O/77DA -ITYfKCFRKDh/Ew7Ih3bH66uNaUUp+a0Sd6fNXLmWWr7gcn5B5CvrXhjPPror+Xyz -EZVByPTTfU1BkMQuxv20GG65M9g9wtXrD79N8di2wOfr4EG5i6L9ZvNTThwgWGGd -9f745WCnPL/ulLT9Glnlfk01AgMBAAGjUDBOMB0GA1UdDgQWBBR5Ed38JID7+JwB -hpOLi1Xt1ORyoTAfBgNVHSMEGDAWgBR5Ed38JID7+JwBhpOLi1Xt1ORyoTAMBgNV -HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBRT/ourx4xT0n/qHF1vy8Ii02v -Hg5lHmzmiVn/3/S4q+t4HrOF6MSjjvVzVNk6JIIYb3+hwGUO31OLNZX60JfSMW+C -ffPiaNDLm/xE4yt4B/QZZDs0kv0RMjGau6k2XJPGvxVNl6LhM6LLvzMEtOGzBr0J -Ai4ZU+WqHk3nnXYHbg7C7Iuu8CT8tBpkaeW/VEN82dcLEulHFxA5Ia6HlwqrgvIW -w77oaOhOh5LKkdS8uHx4OUP8Mv25H2cMBblUdubbeqREyOGRGTkVXfRekD8K95ol -PfT9PhnhUXKRaSwy0nRqvRMiwk/CyIJTbMMflDET1P785diSvtJP0fOhkev9Uprz -FvLsPUTvANUz+vd2KJiLuGbR/d/LaJm18vdWx13vKVO60TBnyFQDS4RZbeuNp73v -x5fPTmiiPZYZj13m2xyes7SXJqhVbms0F39soThpuYrjCaHXyFgqah27+9Ivmbhu -EefPgLmkOx3v0kSfXdJYdji/mrKxERmqT1L34U6M32tCoSbjO7lakAV2opisbHEw -EehCuI83cGp/m3z8yjMoWV8Z4VoB+qMzxzgrXc5C2lxYAT4JggAV2SGcY9MszETI -/S7y5UypV4rutyJvHFrlJZKtp2B7Xi8N8n2NG1WGppYh9UShbFhDaVIMQpjZokAg -MHk7ixe0rSbnHcNF8g== ------END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/netdb.i2p2.no2.crt i2pd-0.10.0/contrib/certificates/ssl/netdb.i2p2.no2.crt --- i2pd-0.9.0/contrib/certificates/ssl/netdb.i2p2.no2.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/netdb.i2p2.no2.crt 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID1TCCAr2gAwIBAgIJAOd9wIt+w/I5MA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD -VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD -STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq -hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTQxMjA2MjM1OTM1WhcNMjAw -NTI4MjM1OTM1WjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV -BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u -ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtRtAALMImh0G0X+AtMpJNBa -HduNkg5t+0juitKRboXXAp5k7yN9qnimlBxlAicNb+QubcDuL+WV91NKz43dd6Xp -SAewqMFRPUAki8uYzoh+hQEfzyd3NmadUKquYZsYwomhHnraOmLZLbxD6ED3FEwl -hGBJwYnhyMZUCgB5+DEEHg8RdLz+H0bMrwz3e7/0lMtH6lM1lIHz0KBULWLp7Om0 -sk3rmmhPUIXqfoY8X3vClI74o0KcslMVaF4rt3lAHdoi3lwA6Qbdqq9nC9rPWHUS -USQQ/MKsNfDTGsHkbW2l0VgNvJkw92DwHTXSJrsEqgkdV/B1hHxCKgL44c/CbwID -AQABo1AwTjAdBgNVHQ4EFgQUCkebDZE05yKMbXORa6gO+aLdCscwHwYDVR0jBBgw -FoAUCkebDZE05yKMbXORa6gO+aLdCscwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B -AQsFAAOCAQEAfHO0g5M//X5xDIuXGCeqQMUrF3r1N45a+0kqo2b/rd9USueNGrJl -KE7MfDgShy2d4strZ1m0M4StW0RlUUZ4V4FYwzcknF6VXbOQK3BTrAeOwuxsrHoT -abrMZ36ABYur5WakOYtPyQ5oXFUAIpGBe9LH7q3XLegSOfftvc2xdJ+VK0n4MEfY -GfaRGMNW/pxGYLWvao3soOJMtp6cQ5KIYGuX92DMon/UgPBqEygeUj7aIqjhRss0 -b0dUZQyHccAG+e5NeTF2ifHCEh2rZY18VGxPL7KLrCQigu5lif1TTv5CDO5rKrHl -TuTOsnooMxUH4ThIVI9cxXk6bzRMehLghA== ------END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/netdb.i2p2.no.crt i2pd-0.10.0/contrib/certificates/ssl/netdb.i2p2.no.crt --- i2pd-0.9.0/contrib/certificates/ssl/netdb.i2p2.no.crt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/netdb.i2p2.no.crt 2015-07-06 16:11:17.000000000 +0000 @@ -1,18 +1,23 @@ -----BEGIN CERTIFICATE----- -MIIC0DCCAjmgAwIBAgIJANdBFbakbhhOMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD +MIID1TCCAr2gAwIBAgIJAOd9wIt+w/I5MA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq -hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTIxMDIzMDExMjIyWhcNMTkx -MDIyMDExMjIyWjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV +hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTQxMjA2MjM1OTM1WhcNMjAw +NTI4MjM1OTM1WjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u -ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCDvmjTpff6/XpiNuqoa9ZEKMlyq1o -kas9fHwnZax/0QTM3xusSQQ9DzeVMSx1ueYxhTZ6VLmE1mTr0aIndzugxGK/g85H -Y+cUl3nw7+5gLPMCUrKAXqQokE3mYxSNY3AUeend7nmHvm9iciw4+Sa2+6ROvQQy -kD31CEN6/I04rwIDAQABo1AwTjAdBgNVHQ4EFgQUV83dJhEcLbfJ+uh+MDYNPdah -RoQwHwYDVR0jBBgwFoAUV83dJhEcLbfJ+uh+MDYNPdahRoQwDAYDVR0TBAUwAwEB -/zANBgkqhkiG9w0BAQUFAAOBgQBQQlJym7mUMUM2ryKu20z2PSUzFyq5U4rWHeo3 -elbNaTsFBwi+Ot/Lg/A5I4V8gywH1fBTG5bYKDUYvWohz1qIg66G57B1zT1zK9yh -Byz9go44M3y1/kXXSsJlY9llG9DDicr1y6LfldwZJ5zFAd3iiB8D8UadP5YLqb7v -wb1F1g== +ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtRtAALMImh0G0X+AtMpJNBa +HduNkg5t+0juitKRboXXAp5k7yN9qnimlBxlAicNb+QubcDuL+WV91NKz43dd6Xp +SAewqMFRPUAki8uYzoh+hQEfzyd3NmadUKquYZsYwomhHnraOmLZLbxD6ED3FEwl +hGBJwYnhyMZUCgB5+DEEHg8RdLz+H0bMrwz3e7/0lMtH6lM1lIHz0KBULWLp7Om0 +sk3rmmhPUIXqfoY8X3vClI74o0KcslMVaF4rt3lAHdoi3lwA6Qbdqq9nC9rPWHUS +USQQ/MKsNfDTGsHkbW2l0VgNvJkw92DwHTXSJrsEqgkdV/B1hHxCKgL44c/CbwID +AQABo1AwTjAdBgNVHQ4EFgQUCkebDZE05yKMbXORa6gO+aLdCscwHwYDVR0jBBgw +FoAUCkebDZE05yKMbXORa6gO+aLdCscwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAfHO0g5M//X5xDIuXGCeqQMUrF3r1N45a+0kqo2b/rd9USueNGrJl +KE7MfDgShy2d4strZ1m0M4StW0RlUUZ4V4FYwzcknF6VXbOQK3BTrAeOwuxsrHoT +abrMZ36ABYur5WakOYtPyQ5oXFUAIpGBe9LH7q3XLegSOfftvc2xdJ+VK0n4MEfY +GfaRGMNW/pxGYLWvao3soOJMtp6cQ5KIYGuX92DMon/UgPBqEygeUj7aIqjhRss0 +b0dUZQyHccAG+e5NeTF2ifHCEh2rZY18VGxPL7KLrCQigu5lif1TTv5CDO5rKrHl +TuTOsnooMxUH4ThIVI9cxXk6bzRMehLghA== -----END CERTIFICATE----- diff -Nru i2pd-0.9.0/contrib/certificates/ssl/netdb.rows.io.crt i2pd-0.10.0/contrib/certificates/ssl/netdb.rows.io.crt --- i2pd-0.9.0/contrib/certificates/ssl/netdb.rows.io.crt 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/contrib/certificates/ssl/netdb.rows.io.crt 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFszCCA52gAwIBAgIRALWZzF745GPT8GVUcZ0RMg0wCwYJKoZIhvcNAQELMG0x +CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK +BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMRYwFAYDVQQDEw1u +ZXRkYi5yb3dzLmlvMB4XDTE0MTIyMDE2NDIwNVoXDTE2MTIxOTE2NDIwNVowbTEL +MAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoG +A1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxFjAUBgNVBAMTDW5l +dGRiLnJvd3MuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCTZyJF +Im9pnc7OO5DfQy4SuotUztO5BJX7xniTqD4fKLQQXzZFeT4XHrkDste8TsTzUfxt +CWDEBH3af5cpnwWMT28rlRw2DlPr+LnAgt7VjFXdhFZr1N5VfNlTI1K3OiZ/DRlB +92CoTypyx4ebNfLtZfh+TPLOdg5UqROpHIrybsUj2IaG3IpGHJK8FuH79b/X5oVI +FlDZJs5QsJEARzq2QMJd6fnNqkCBSSjNpeL7TtDar9EKa6+O7s351kH8MVFNSogB +F0Hqu8LYaRC1L1JCz5lsOYKepp3MMIOdDOhy+FTd8NuNZXYkUTdTNI4dB6w4Z6o+ +xlnHEPpezIAAlPXLiupvlEi0om69/TMS+pLDBLAOlCZ2YaXS18UrSbmYYlekg40J +nEeALt8ZdsU/is7Q6SJZ3UltFIPCuMD+ixvaIvakkhNiqEWPxdg0XxAK1ZJYFup+ +2aVtPLQIzWePkG/VbdA5cxQKNtRwOgvCoKIE29nUbxuq2PCmMhLAfXHeieSzP5c7 +Q8A23qX94hwCIePj1YA9uNtStjECfVS1wjyXV4M1tTFUdSJv4aVtFjtya7PY+6SG +Srz11SqBWSqyJ/C14Su0QY/HquglzMRnkJ49Scwb+79hl7kPslO1iIgPLE5S2fIW +ZwJ/4AgGb6BZT8XPEYYANEA5y7KGanYNo8KdYwIDAQABo1IwUDAOBgNVHQ8BAf8E +BAMCAKQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAYBgNV +HREEETAPgg1uZXRkYi5yb3dzLmlvMAsGCSqGSIb3DQEBCwOCAgEAMjQSHPR/p9If +mJA1y489D1NB2CxfwO+CgAIs9HA7OsdneQBZTldMgBHoQGifkpD1uSl8DHoZqnJ8 +wo5YWcT1rYkP+V1jGfZj92VvfQL0/R4G4hWdQwYY0CcXN8ixS36UDQVSFKb4zvNG +j9iIN57WToEmxp5noHguKrpViwhXCMCpAXr3ZIv/Fd+QACNEXuvdZgbtwfOTPLKh +ZlkUPgVHiQopeQnZhZCT3aLZ5lndrUtWlQYiGN/OolVyRie+ysuxjRR4L5brt4Rz +hrwFBswbQZlgxJ3Nod9/wEdEJWP4+X69ggzOkBB+PgpOFpuDlJxNTcPA/WFIlsm0 +CzCv/o8Vg+MMWFPMwEZrk6UQXXACr1AEF+MUnZq3o5JaLvHoUcikewbZPcTCNvDp +nqT1RN9vq/MGdlRfPJkF028IXPz7T9DXXPXhJvv+FAfnOkREeUYpzBIftyYf92ol +l63z0FooVUTKWYPvFFgl5ShNnINTMVXPCZp8j7myLGSLOAFFwiaL1OtvftgxXfzC +B7Qj42SNhFUrHmO9fH3H2ptm/iW/Xe5eqgeb6MVGQ/eQJpdp0AvpDa50/AYNt1Iq +CcMKmBgzUezrIN24XXW/LZwazlc7I8e5RzgbEgXEDBZu21TApTKlmOqEYle8294W +fWThMdwk1kTrWxLooiVrS5A1hXqADqE= +-----END CERTIFICATE----- diff -Nru i2pd-0.9.0/Daemon.cpp i2pd-0.10.0/Daemon.cpp --- i2pd-0.9.0/Daemon.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Daemon.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -18,11 +18,6 @@ #include "HTTPServer.h" #include "ClientContext.h" -#ifdef USE_UPNP -#include "UPnP.h" -#endif - - namespace i2p { namespace util @@ -122,10 +117,6 @@ LogPrint("Tunnels started"); i2p::client::context.Start (); LogPrint("Client started"); -#ifdef USE_UPNP - i2p::UPnP::upnpc.Start(); - LogPrint("UPnP module loaded"); -#endif return true; } @@ -142,9 +133,7 @@ LogPrint("NetDB stopped"); d.httpServer->Stop(); LogPrint("HTTP Server stopped"); -#ifdef USE_UPNP - i2p::UPnP::upnpc.Stop(); -#endif + StopLog (); delete d.httpServer; d.httpServer = nullptr; diff -Nru i2pd-0.9.0/DaemonLinux.cpp i2pd-0.10.0/DaemonLinux.cpp --- i2pd-0.9.0/DaemonLinux.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/DaemonLinux.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -62,7 +62,8 @@ LogPrint("Error, could not create process group."); return false; } - chdir(i2p::util::filesystem::GetDataDir().string().c_str()); + std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy + chdir(d.c_str()); // close stdin/stdout/stderr descriptors ::close (0); diff -Nru i2pd-0.9.0/Datagram.cpp i2pd-0.10.0/Datagram.cpp --- i2pd-0.9.0/Datagram.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Datagram.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -16,7 +16,7 @@ m_Owner (owner), m_Receiver (nullptr) { } - + void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort) { uint8_t buf[MAX_DATAGRAM_SIZE]; @@ -41,22 +41,15 @@ if (remote) m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote)); else - m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, - this, std::placeholders::_1, msg, ident)); + m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg)); } - void DatagramDestination::HandleLeaseSetRequestComplete (bool success, I2NPMessage * msg, i2p::data::IdentHash ident) + void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr remote, I2NPMessage * msg) { - if (success) - { - auto remote = m_Owner.FindLeaseSet (ident); - if (remote) - { - SendMsg (msg, remote); - return; - } - } - DeleteI2NPMessage (msg); + if (remote) + SendMsg (msg, remote); + else + DeleteI2NPMessage (msg); } void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr remote) @@ -67,7 +60,7 @@ { std::vector msgs; uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); - auto garlic = m_Owner.WrapMessage (remote, msg, true); + auto garlic = m_Owner.WrapMessage (remote, ToSharedI2NPMessage (msg), true); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, @@ -105,7 +98,10 @@ if (verified) { - if (m_Receiver != nullptr) + auto it = m_ReceiversByPorts.find (toPort); + if (it != m_ReceiversByPorts.end ()) + it->second (identity, fromPort, toPort, buf + headerLen, len -headerLen); + else if (m_Receiver != nullptr) m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen); else LogPrint (eLogWarning, "Receiver for datagram is not set"); @@ -147,7 +143,7 @@ htobe16buf (buf + 6, toPort); // destination port buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol msg->len += size + 4; - FillI2NPMessageHeader (msg, eI2NPData); + msg->FillI2NPMessageHeader (eI2NPData); return msg; } } diff -Nru i2pd-0.9.0/Datagram.h i2pd-0.10.0/Datagram.h --- i2pd-0.9.0/Datagram.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Datagram.h 2015-07-06 16:11:17.000000000 +0000 @@ -4,6 +4,7 @@ #include #include #include +#include #include "Identity.h" #include "LeaseSet.h" #include "I2NPProtocol.h" @@ -32,9 +33,12 @@ void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void ResetReceiver () { m_Receiver = nullptr; }; + void SetReceiver (const Receiver& receiver, uint16_t port) { m_ReceiversByPorts[port] = receiver; }; + void ResetReceiver (uint16_t port) { m_ReceiversByPorts.erase (port); }; + private: - void HandleLeaseSetRequestComplete (bool success, I2NPMessage * msg, i2p::data::IdentHash ident); + void HandleLeaseSetRequestComplete (std::shared_ptr leaseSet, I2NPMessage * msg); I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendMsg (I2NPMessage * msg, std::shared_ptr remote); @@ -43,7 +47,8 @@ private: i2p::client::ClientDestination& m_Owner; - Receiver m_Receiver; + Receiver m_Receiver; // default + std::map m_ReceiversByPorts; }; } } diff -Nru i2pd-0.9.0/debian/changelog i2pd-0.10.0/debian/changelog --- i2pd-0.9.0/debian/changelog 2015-04-01 17:43:13.000000000 +0000 +++ i2pd-0.10.0/debian/changelog 2015-07-06 18:54:23.000000000 +0000 @@ -1,3 +1,186 @@ +i2pd (0.10.0-1~utopic+1) utopic; urgency=medium + + * Upload to PPA + + -- Kill Your TV Mon, 06 Jul 2015 18:54:13 +0000 + +i2pd (0.10.0-1) unstable; urgency=medium + + [ orignal ] + * count tunnel acceptance ratio for peer selection + * moved encryption/decryption to TlsCipher + * AES256 cipher template + * use SendFinished + * RSA_WITH_AES_256_CBC_SHA support + * https://netdb.rows.io:444/ added + * fixed typo + * RC4_SHA cipher suite + * Update README.md + * fixed crash if can't connect to a reseed + * fixed race condition + * fixed crash if no routers available + * set datagram receiver per port + * fixed memory leak + * select tunnel from TunnelPool rather than from LeaseSet for DeliveryStatus + * fixed race condition + * 4 tags for LeaseSet request + * lookup always takes full address from LeaseSet + * use shared_ptr for socket in I2PTunnelConnection + * use shared_ptr for AddressReceiver + * pass LeaseSet to callback of RequestDestination + * made Encrypt const + * use shared_ptr for local LeaseSet + * use shared_ptr for CreateDatabaseStore + * use unique_ptr for ElGamalEncryption + + [ Robert Foss ] + * Fixed memory leak: delete -> delete[] + + [ orignal ] + * fixed null pointer exception + * variable length buffer for LeaseSet + * validate leaseset for zero leases + * initial code for Ed25519 added + * multiplication by integer + * IsOnCurve added + * Decode point + * EdDSA signature type added + * fixed crash + * EdDSA signer added + * NetDb/NetDbRequests split + * implemented AsyncSend + * use AsyncSend + * send and handle RESET flag + * fixed crash + * show windows size and connection status + * show local destination for SAM sessions + * fixed infinite loop + * GetClosestFloodfills added + * reduced CPU load at floodfill + * reduced log file size + + [ 7histle ] + * Fix for #179 + + [ orignal ] + * delete obsolete profiles + * check database lookup type + * check for zero ident + * don't send reset message due problem at other side + * always check profile for peer selection + * check profile for high bandwidth peer selection only + * version 0.9.19 + * fixed potential memory leak + * some cleanup + * re-create tunnel before expiration + * router don't expire if less than 75 + * double RTO after every resend attempt + * check outbound tunnles for readiness + * select next lease with same gateway if possible + * try to pick an outbound tunnel with same endpoint instead expired + * recreate tunnel after 9.5 minutes + * fixed potential memory leak + * changed some profiling parameters + * uin32_t for elapsed time + * check garlic clove length + + [ Kill Your TV ] + * reseed certificate updates + + [ orignal ] + * check profile only once + * select first hop from existing connections if applicable + * handle tunnels quantity params + * Update README.md + * don't recalculate timestamp for each log message + * moved UPnP instance to Transports. Use actual port from RouterContext + * pass TunnelConfig as shared_ptr + * fixed build errors for gcc 4.6 + * created paired inbound tunnel after outbound + * rewrite tunnel path inversion code + * fixed log crash at shutdown + + [ David ] + * typo: Gralic -> Garlic + + [ orignal ] + * check for I2NP message buffer boudary + * use shared_ptr for NetDb's I2NPMessages + + [ ipslot ] + * Update Log.cpp + + [ orignal ] + * excluded dead reseeds + * check length of garlic message + * http server tunnel added + * use random msg_id for I2NP messages + * I2PTunnelConnectionHTTP added + * use addresses in server tunnel configuration + * catch HTTP header of HTTP server tunnel connection + * replace Host: for server http tunnels + * version 0.9.20 + * fixed bug with zero-size clove + * additional statistics for profiling + * skip missing sections + * don't pick node for 5 minutes if declined + * select first hop for inbound tunnel from connected peers + * support multiple transport sessions to the same peer + * very hash in one pass + * changed profiling algorithm + * fixed race condition + * handle explicitPeers I2CP parameter + * reduce CPU usage + * verify adler checksum + * use share_ptr for garlic messages + * more generic queue + * pass I2NP as shared_ptr to netDB + * pass I2NP message to transport session as shared_ptr + * send I2NP messages as shared_ptr + * create shared I2NP tunnel message in OBGW + * use shared_ptr for direct DatabaseLookup message + * use shared_ptr for outbound tunnel build messages + * use shared_ptr for transit tunnel participant + * use shared_ptr for I2NP messages through tunnels + + [ Mikhail Titov ] + * Rearrange eol removal for handshake + * Materialize temporary string obtained from boost path + * Use static for now while returning HTTP 500 error + + [ orignal ] + * fixed build error + * use shared_ptr for all incoming I2NP messages + * different in and out buffers for tunnel encryption + * use shared_ptr for garlic messages + * shared_ptr for lookup messages + * deleted deprecated SendMessage + * use shared_ptr for DeliverStatus + + [ Mikhail Titov ] + * Check for invalid SAM destination + + [ orignal ] + * different input anf output I2NP message for tunnel encryption + * pass const I2NP message to HandleTunnelDataMsg + * random non-zero padding + * don't copy transit DatabaseStore + * handle DeliveryStatus garlic clove directly + * use shared flood message + * fixed race condition + * copy shared_ptr + * temporary fix of crash + * some cleanup + * move FillI2NPMessageHeader into I2NPMessage + * const I2NP messages + * don't send DatabaseStore until time sync complete + * check for buffer size + + [ Kill Your TV ] + * New Release Version + + -- Kill Your TV Mon, 06 Jul 2015 16:49:12 +0000 + i2pd (0.9.0-1~utopic+1) utopic; urgency=medium * Building for Utopic diff -Nru i2pd-0.9.0/Destination.cpp i2pd-0.10.0/Destination.cpp --- i2pd-0.9.0/Destination.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Destination.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -16,12 +16,15 @@ ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_Keys (keys), m_LeaseSet (nullptr), m_IsPublic (isPublic), m_PublishReplyToken (0), + m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0), m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service) { i2p::crypto::GenerateElGamalKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; + int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY; + int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; + std::shared_ptr > explicitPeers; if (params) { auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); @@ -44,8 +47,44 @@ LogPrint (eLogInfo, "Outbound tunnel length set to ", len); } } + it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY); + if (it != params->end ()) + { + int quantity = boost::lexical_cast(it->second); + if (quantity > 0) + { + inboundTunnelsQuantity = quantity; + LogPrint (eLogInfo, "Inbound tunnels quantity set to ", quantity); + } + } + it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY); + if (it != params->end ()) + { + int quantity = boost::lexical_cast(it->second); + if (quantity > 0) + { + outboundTunnelsQuantity = quantity; + LogPrint (eLogInfo, "Outbound tunnels quantity set to ", quantity); + } + } + it = params->find (I2CP_PARAM_EXPLICIT_PEERS); + if (it != params->end ()) + { + explicitPeers = std::make_shared >(); + std::stringstream ss(it->second); + std::string b64; + while (std::getline (ss, b64, ',')) + { + i2p::data::IdentHash ident; + ident.FromBase64 (b64); + explicitPeers->push_back (ident); + } + LogPrint (eLogInfo, "Explicit peers set to ", it->second); + } } - m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen); + m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity); + if (explicitPeers) + m_Pool->SetExplicitPeers (explicitPeers); if (m_IsPublic) LogPrint (eLogInfo, "Local address ", i2p::client::GetB32Address(GetIdentHash()), " created"); m_StreamingDestination = std::make_shared (*this); // TODO: @@ -148,7 +187,7 @@ return nullptr; } - const i2p::data::LeaseSet * ClientDestination::GetLeaseSet () + std::shared_ptr ClientDestination::GetLeaseSet () { if (!m_Pool) return nullptr; if (!m_LeaseSet) @@ -158,15 +197,7 @@ void ClientDestination::UpdateLeaseSet () { - auto newLeaseSet = new i2p::data::LeaseSet (*m_Pool); - if (!m_LeaseSet) - m_LeaseSet = newLeaseSet; - else - { - // TODO: implement it better - *m_LeaseSet = *newLeaseSet; - delete newLeaseSet; - } + m_LeaseSet.reset (new i2p::data::LeaseSet (*m_Pool)); } bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) @@ -184,12 +215,12 @@ return true; } - void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg) + void ClientDestination::ProcessGarlicMessage (std::shared_ptr msg) { m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg)); } - void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) + void ClientDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg)); } @@ -202,6 +233,10 @@ case eI2NPData: HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); break; + case eI2NPDeliveryStatus: + // we assume tunnel tests non-encrypted + HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); + break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); break; @@ -222,19 +257,37 @@ LogPrint (eLogInfo, "Reply token is ignored for DatabaseStore"); offset += 36; } + std::shared_ptr leaseSet; if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet { LogPrint (eLogDebug, "Remote LeaseSet"); auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET); if (it != m_RemoteLeaseSets.end ()) { - it->second->Update (buf + offset, len - offset); - LogPrint (eLogDebug, "Remote LeaseSet updated"); + leaseSet = it->second; + leaseSet->Update (buf + offset, len - offset); + if (leaseSet->IsValid ()) + LogPrint (eLogDebug, "Remote LeaseSet updated"); + else + { + LogPrint (eLogDebug, "Remote LeaseSet update failed"); + m_RemoteLeaseSets.erase (it); + leaseSet = nullptr; + } } else { - LogPrint (eLogDebug, "New remote LeaseSet added"); - m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = std::make_shared (buf + offset, len - offset); + leaseSet = std::make_shared (buf + offset, len - offset); + if (leaseSet->IsValid ()) + { + LogPrint (eLogDebug, "New remote LeaseSet added"); + m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet; + } + else + { + LogPrint (eLogError, "New remote LeaseSet verification failed"); + leaseSet = nullptr; + } } } else @@ -244,7 +297,7 @@ if (it1 != m_LeaseSetRequests.end ()) { it1->second->requestTimeoutTimer.cancel (); - if (it1->second->requestComplete) it1->second->requestComplete (true); + if (it1->second->requestComplete) it1->second->requestComplete (leaseSet); delete it1->second; m_LeaseSetRequests.erase (it1); } @@ -285,7 +338,7 @@ LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills"); if (!found) { - if (request->requestComplete) request->requestComplete (false); + if (request->requestComplete) request->requestComplete (nullptr); delete request; m_LeaseSetRequests.erase (key); } @@ -294,7 +347,7 @@ LogPrint ("Request for ", key.ToBase64 (), " not found"); } - void ClientDestination::HandleDeliveryStatusMessage (I2NPMessage * msg) + void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); if (msgID == m_PublishReplyToken) @@ -302,7 +355,6 @@ LogPrint (eLogDebug, "Publishing confirmed"); m_ExcludedFloodfills.clear (); m_PublishReplyToken = 0; - i2p::DeleteI2NPMessage (msg); } else i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); @@ -345,7 +397,7 @@ m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); m_PublishReplyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); - auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)); + auto msg = WrapMessage (floodfill, ToSharedI2NPMessage (i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken))); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer, this, std::placeholders::_1)); @@ -404,18 +456,12 @@ else { RequestDestination (dest, - [this, streamRequestComplete, dest, port](bool success) + [this, streamRequestComplete, port](std::shared_ptr ls) { - if (!success) - streamRequestComplete (nullptr); + if (ls) + streamRequestComplete(CreateStream (ls, port)); else - { - auto leaseSet = FindLeaseSet (dest); - if (leaseSet) - streamRequestComplete(CreateStream (leaseSet, port)); - else - streamRequestComplete (nullptr); - } + streamRequestComplete (nullptr); }); } } @@ -501,7 +547,7 @@ if (!SendLeaseSetRequest (dest, floodfill, request)) { // request failed - if (request->requestComplete) request->requestComplete (false); + if (request->requestComplete) request->requestComplete (nullptr); delete request; m_LeaseSetRequests.erase (dest); } @@ -510,7 +556,7 @@ { LogPrint (eLogError, "Request of ", dest.ToBase64 (), " is pending already"); // TODO: queue up requests - if (request->requestComplete) request->requestComplete (false); + if (request->requestComplete) request->requestComplete (nullptr); delete request; } } @@ -539,9 +585,9 @@ rnd.GenerateBlock (replyTag, 32); // random session tag AddSessionKey (replyKey, replyTag); - I2NPMessage * msg = WrapMessage (nextFloodfill, - CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, - replyTunnel.get (), replyKey, replyTag)); + auto msg = WrapMessage (nextFloodfill, + ToSharedI2NPMessage (CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, + replyTunnel.get (), replyKey, replyTag))); outboundTunnel->SendTunnelDataMsg ( { i2p::tunnel::TunnelMessageBlock diff -Nru i2pd-0.9.0/Destination.h i2pd-0.10.0/Destination.h --- i2pd-0.9.0/Destination.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Destination.h 2015-07-06 16:11:17.000000000 +0000 @@ -36,13 +36,19 @@ const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3; const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length"; const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3; + const char I2CP_PARAM_INBOUND_TUNNELS_QUANTITY[] = "inbound.quantity"; + const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5; + const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity"; + const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5; + const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers"; const int STREAM_REQUEST_TIMEOUT = 60; //in seconds typedef std::function stream)> StreamRequestComplete; class ClientDestination: public i2p::garlic::GarlicDestination { - typedef std::function RequestComplete; + typedef std::function leaseSet)> RequestComplete; + // leaseSet = nullptr means not found struct LeaseSetRequest { LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {}; @@ -63,7 +69,7 @@ bool IsRunning () const { return m_IsRunning; }; boost::asio::io_service& GetService () { return m_Service; }; std::shared_ptr GetTunnelPool () { return m_Pool; }; - bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases (); }; + bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases () && m_Pool->GetOutboundTunnels ().size () > 0; }; std::shared_ptr FindLeaseSet (const i2p::data::IdentHash& ident); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); @@ -87,13 +93,14 @@ const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; // implements GarlicDestination - const i2p::data::LeaseSet * GetLeaseSet (); + std::shared_ptr GetLeaseSet (); + std::shared_ptr GetTunnelPool () const { return m_Pool; } void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); // override GarlicDestination bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); - void ProcessGarlicMessage (I2NPMessage * msg); - void ProcessDeliveryStatusMessage (I2NPMessage * msg); + void ProcessGarlicMessage (std::shared_ptr msg); + void ProcessDeliveryStatusMessage (std::shared_ptr msg); void SetLeaseSetUpdated (); // I2CP @@ -107,7 +114,7 @@ void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); - void HandleDeliveryStatusMessage (I2NPMessage * msg); + void HandleDeliveryStatusMessage (std::shared_ptr msg); void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, LeaseSetRequest * request); @@ -127,7 +134,7 @@ std::map m_LeaseSetRequests; std::shared_ptr m_Pool; - i2p::data::LeaseSet * m_LeaseSet; + std::shared_ptr m_LeaseSet; bool m_IsPublic; uint32_t m_PublishReplyToken; std::set m_ExcludedFloodfills; // for publishing diff -Nru i2pd-0.9.0/ElGamal.h i2pd-0.10.0/ElGamal.h --- i2pd-0.9.0/ElGamal.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/ElGamal.h 2015-07-06 16:11:17.000000000 +0000 @@ -26,7 +26,7 @@ b1 = a_exp_b_mod_c (y, k, elgp); } - void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) + void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const { // calculate b = b1*m mod p uint8_t m[255]; @@ -60,15 +60,13 @@ { CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256), b(zeroPadding? encrypted + 258 :encrypted + 256, 256); - uint8_t m[255], hash[32]; + uint8_t m[255]; a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255); - CryptoPP::SHA256().CalculateDigest(hash, m+33, 222); - for (int i = 0; i < 32; i++) - if (hash[i] != m[i+1]) - { - LogPrint ("ElGamal decrypt hash doesn't match"); - return false; - } + if (!CryptoPP::SHA256().VerifyDigest (m + 1, m + 33, 222)) + { + LogPrint ("ElGamal decrypt hash doesn't match"); + return false; + } memcpy (data, m + 33, 222); return true; } diff -Nru i2pd-0.9.0/filelist.mk i2pd-0.10.0/filelist.mk --- i2pd-0.9.0/filelist.mk 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/filelist.mk 2015-07-06 16:11:17.000000000 +0000 @@ -1,9 +1,10 @@ COMMON_SRC = \ CryptoConst.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ - Log.cpp NTCPSession.cpp NetDb.cpp Profiling.cpp Reseed.cpp RouterContext.cpp \ - RouterInfo.cpp SSU.cpp SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp \ - TransitTunnel.cpp Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp \ - TunnelGateway.cpp Destination.cpp UPnP.cpp util.cpp aes.cpp base64.cpp + Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \ + Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \ + SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ + Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \ + Destination.cpp UPnP.cpp util.cpp aes.cpp base64.cpp ifeq ($(UNAME),Darwin) diff -Nru i2pd-0.9.0/Garlic.cpp i2pd-0.10.0/Garlic.cpp --- i2pd-0.9.0/Garlic.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Garlic.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -15,9 +15,9 @@ namespace garlic { GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, - std::shared_ptr destination, int numTags): + std::shared_ptr destination, int numTags, bool attachLeaseSet): m_Owner (owner), m_Destination (destination), m_NumTags (numTags), - m_LeaseSetUpdateStatus (numTags > 0 ? eLeaseSetUpdated : eLeaseSetUpToDate) + m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend) { // create new session tags and session key m_Rnd.GenerateBlock (m_SessionKey, 32); @@ -25,7 +25,7 @@ } GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): - m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetUpToDate) + m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend) { memcpy (m_SessionKey, sessionKey, 32); m_Encryption.SetKey (m_SessionKey); @@ -107,9 +107,9 @@ return !m_SessionTags.empty () || m_UnconfirmedTagsMsgs.empty (); } - I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg) + std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) { - I2NPMessage * m = NewI2NPMessage (); + auto m = ToSharedI2NPMessage(NewI2NPMessage ()); m->Align (12); // in order to get buf aligned to 16 (12 + 4) size_t len = 0; uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length @@ -164,12 +164,10 @@ len += 32; } // AES block - len += CreateAESBlock (buf, msg); + len += CreateAESBlock (buf, msg.get ()); // TODO htobe32buf (m->GetPayload (), len); m->len += len + 4; - FillI2NPMessageHeader (m, eI2NPGarlic); - if (msg) - DeleteI2NPMessage (msg); + m->FillI2NPMessageHeader (eI2NPGarlic); return m; } @@ -225,9 +223,10 @@ if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated { // clove is DeliveryStatus - size += CreateDeliveryStatusClove (payload + size, msgID); - if (size > 0) // successive? + auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID); + if (cloveSize > 0) // successive? { + size += cloveSize; (*numCloves)++; if (newTags) // new tags created m_UnconfirmedTagsMsgs[msgID] = newTags; @@ -297,19 +296,18 @@ size_t size = 0; if (m_Owner) { - auto leases = m_Owner->GetLeaseSet ()->GetNonExpiredLeases (); - if (!leases.empty ()) + auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel (); + if (inboundTunnel) { buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel size++; - uint32_t i = m_Rnd.GenerateWord32 (0, leases.size () - 1); // hash and tunnelID sequence is reversed for Garlic - memcpy (buf + size, leases[i].tunnelGateway, 32); // To Hash + memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash size += 32; - htobe32buf (buf + size, leases[i].tunnelID); // tunnelID + htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID size += 4; // create msg - I2NPMessage * msg = CreateDeliveryStatusMsg (msgID); + auto msg = CreateDeliveryStatusMsg (msgID); if (m_Owner) { //encrypt @@ -322,7 +320,6 @@ } memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); - DeleteI2NPMessage (msg); // fill clove uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec htobe32buf (buf + size, m_Rnd.GenerateWord32 ()); // CloveID @@ -333,7 +330,7 @@ size += 3; } else - LogPrint ("All tunnels of local LeaseSet expired"); + LogPrint (eLogError, "No inbound tunnels in the pool for DeliveryStatus"); } else LogPrint ("Missing local LeaseSet"); @@ -362,27 +359,37 @@ return true; } - void GarlicDestination::HandleGarlicMessage (I2NPMessage * msg) + void GarlicDestination::HandleGarlicMessage (std::shared_ptr msg) { uint8_t * buf = msg->GetPayload (); uint32_t length = bufbe32toh (buf); + if (length > msg->GetLength ()) + { + LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ()); + return; + } buf += 4; // length auto it = m_Tags.find (SessionTag(buf)); if (it != m_Tags.end ()) { // tag found. Use AES - uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, buf, 32); - it->second->SetIV (iv); - it->second->Decrypt (buf + 32, length - 32, buf + 32); - HandleAESBlock (buf + 32, length - 32, it->second, msg->from); - m_Tags.erase (it); // tag might be used only once + if (length >= 32) + { + uint8_t iv[32]; // IV is first 16 bytes + CryptoPP::SHA256().CalculateDigest(iv, buf, 32); + it->second->SetIV (iv); + it->second->Decrypt (buf + 32, length - 32, buf + 32); + HandleAESBlock (buf + 32, length - 32, it->second, msg->from); + } + else + LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes"); + m_Tags.erase (it); // tag might be used only once } else { // tag not found. Use ElGamal ElGamalBlock elGamal; - if (i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true)) + if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true)) { auto decryption = std::make_shared(); decryption->SetKey (elGamal.sessionKey); @@ -393,9 +400,8 @@ HandleAESBlock (buf + 514, length - 514, decryption, msg->from); } else - LogPrint ("Failed to decrypt garlic"); + LogPrint (eLogError, "Failed to decrypt garlic"); } - DeleteI2NPMessage (msg); // cleanup expired tags uint32_t ts = i2p::util::GetSecondsSinceEpoch (); @@ -462,6 +468,7 @@ void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr from) { + const uint8_t * buf1 = buf; int numCloves = buf[0]; LogPrint (numCloves," cloves"); buf++; @@ -501,7 +508,7 @@ tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); if (tunnel) // we have send it through an outbound tunnel { - I2NPMessage * msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); + auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); } else @@ -519,26 +526,23 @@ buf += 4; // CloveID buf += 8; // Date buf += 3; // Certificate + if (buf - buf1 > (int)len) + { + LogPrint (eLogError, "Garlic clove is too long"); + break; + } } } - I2NPMessage * GarlicDestination::WrapMessage (std::shared_ptr destination, - I2NPMessage * msg, bool attachLeaseSet) + std::shared_ptr GarlicDestination::WrapMessage (std::shared_ptr destination, + std::shared_ptr msg, bool attachLeaseSet) { - if (attachLeaseSet) // we should maintain this session - { - auto session = GetRoutingSession (destination, 32); // 32 tags by default - return session->WrapSingleMessage (msg); - } - else // one time session - { - GarlicRoutingSession session (this, destination, 0); // don't use tag if no LeaseSet - return session.WrapSingleMessage (msg); - } + auto session = GetRoutingSession (destination, attachLeaseSet); // 32 tags by default + return session->WrapSingleMessage (msg); } std::shared_ptr GarlicDestination::GetRoutingSession ( - std::shared_ptr destination, int numTags) + std::shared_ptr destination, bool attachLeaseSet) { auto it = m_Sessions.find (destination->GetIdentHash ()); std::shared_ptr session; @@ -546,7 +550,8 @@ session = it->second; if (!session) { - session = std::make_shared (this, destination, numTags); + session = std::make_shared (this, destination, + attachLeaseSet ? 40 : 4, attachLeaseSet); // 40 tags for connections and 4 for LS requests std::unique_lock l(m_SessionsMutex); m_Sessions[destination->GetIdentHash ()] = session; } @@ -578,7 +583,7 @@ m_CreatedSessions[msgID] = session; } - void GarlicDestination::HandleDeliveryStatusMessage (I2NPMessage * msg) + void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload ()); { @@ -590,7 +595,6 @@ LogPrint (eLogInfo, "Garlic message ", msgID, " acknowledged"); } } - DeleteI2NPMessage (msg); } void GarlicDestination::SetLeaseSetUpdated () @@ -600,12 +604,12 @@ it.second->SetLeaseSetUpdated (); } - void GarlicDestination::ProcessGarlicMessage (I2NPMessage * msg) + void GarlicDestination::ProcessGarlicMessage (std::shared_ptr msg) { HandleGarlicMessage (msg); } - void GarlicDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) + void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { HandleDeliveryStatusMessage (msg); } diff -Nru i2pd-0.9.0/Garlic.h i2pd-0.10.0/Garlic.h --- i2pd-0.9.0/Garlic.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Garlic.h 2015-07-06 16:11:17.000000000 +0000 @@ -61,7 +61,8 @@ { eLeaseSetUpToDate = 0, eLeaseSetUpdated, - eLeaseSetSubmitted + eLeaseSetSubmitted, + eLeaseSetDoNotSend }; struct UnconfirmedTags @@ -75,14 +76,18 @@ public: - GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, int numTags); + GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, + int numTags, bool attachLeaseSet); GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption ~GarlicRoutingSession (); - I2NPMessage * WrapSingleMessage (I2NPMessage * msg); + std::shared_ptr WrapSingleMessage (std::shared_ptr msg); void MessageConfirmed (uint32_t msgID); bool CleanupExpiredTags (); // returns true if something left - void SetLeaseSetUpdated () { m_LeaseSetUpdateStatus = eLeaseSetUpdated; }; + void SetLeaseSetUpdated () + { + if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; + }; private: @@ -110,7 +115,7 @@ i2p::crypto::CBCEncryption m_Encryption; CryptoPP::AutoSeededRandomPool m_Rnd; }; - + class GarlicDestination: public i2p::data::LocalDestination { public: @@ -118,27 +123,28 @@ GarlicDestination (): m_LastTagsCleanupTime (0) {}; ~GarlicDestination (); - std::shared_ptr GetRoutingSession (std::shared_ptr destination, int numTags); + std::shared_ptr GetRoutingSession (std::shared_ptr destination, bool attachLeaseSet); void CleanupRoutingSessions (); void RemoveCreatedSession (uint32_t msgID); - I2NPMessage * WrapMessage (std::shared_ptr destination, - I2NPMessage * msg, bool attachLeaseSet = false); + std::shared_ptr WrapMessage (std::shared_ptr destination, + std::shared_ptr msg, bool attachLeaseSet = false); void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (std::shared_ptr session, uint32_t msgID); - virtual void ProcessGarlicMessage (I2NPMessage * msg); - virtual void ProcessDeliveryStatusMessage (I2NPMessage * msg); + virtual void ProcessGarlicMessage (std::shared_ptr msg); + virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); virtual void SetLeaseSetUpdated (); - virtual const i2p::data::LeaseSet * GetLeaseSet () = 0; // TODO + virtual std::shared_ptr GetLeaseSet () = 0; // TODO + virtual std::shared_ptr GetTunnelPool () const = 0; virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; protected: - void HandleGarlicMessage (I2NPMessage * msg); - void HandleDeliveryStatusMessage (I2NPMessage * msg); + void HandleGarlicMessage (std::shared_ptr msg); + void HandleDeliveryStatusMessage (std::shared_ptr msg); private: diff -Nru i2pd-0.9.0/HTTPProxy.cpp i2pd-0.10.0/HTTPProxy.cpp --- i2pd-0.9.0/HTTPProxy.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/HTTPProxy.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -44,7 +44,7 @@ void HandleStreamRequestComplete (std::shared_ptr stream); uint8_t m_http_buff[http_buffer_size]; - boost::asio::ip::tcp::socket * m_sock; + std::shared_ptr m_sock; std::string m_request; //Data left to be sent std::string m_url; //URL std::string m_method; //Method @@ -56,7 +56,7 @@ public: - HTTPProxyHandler(HTTPProxyServer * parent, boost::asio::ip::tcp::socket * sock) : + HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr sock) : I2PServiceHandler(parent), m_sock(sock) { EnterState(GET_METHOD); } ~HTTPProxyHandler() { Terminate(); } @@ -77,10 +77,10 @@ void HTTPProxyHandler::Terminate() { if (Kill()) return; - if (m_sock) { + if (m_sock) + { LogPrint(eLogDebug,"--- HTTP Proxy close sock"); m_sock->close(); - delete m_sock; m_sock = nullptr; } Done(shared_from_this()); @@ -90,7 +90,7 @@ //TODO: handle this apropriately void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/) { - std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n"; + static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n"; boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } @@ -290,7 +290,7 @@ { } - std::shared_ptr HTTPProxyServer::CreateHandler(boost::asio::ip::tcp::socket * socket) + std::shared_ptr HTTPProxyServer::CreateHandler(std::shared_ptr socket) { return std::make_shared (this, socket); } diff -Nru i2pd-0.9.0/HTTPProxy.h i2pd-0.10.0/HTTPProxy.h --- i2pd-0.9.0/HTTPProxy.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/HTTPProxy.h 2015-07-06 16:11:17.000000000 +0000 @@ -21,7 +21,7 @@ protected: // Implements TCPIPAcceptor - std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "HTTP Proxy"; } }; diff -Nru i2pd-0.9.0/HTTPServer.cpp i2pd-0.10.0/HTTPServer.cpp --- i2pd-0.9.0/HTTPServer.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/HTTPServer.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -526,15 +526,14 @@ { m_Stream.reset (); m_Stream = nullptr; - // delete this }); } void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), - boost::bind(&HTTPConnection::HandleReceive, this, - boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + std::bind(&HTTPConnection::HandleReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); } void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -831,17 +830,17 @@ { for (auto& it: i2p::client::context.GetDestinations ()) { - std::string b32 = it.first.ToBase32 (); + auto ident = it.second->GetIdentHash ();; s << ""; - s << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetIdentHash()) << "
" << std::endl; + s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">"; + s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; } } void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s) { i2p::data::IdentHash ident; - i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), ident, 32); + ident.FromBase32 (b32); auto dest = i2p::client::context.FindLocalDestination (ident); if (dest) { @@ -879,7 +878,9 @@ s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]"; s << "[buf:" << it.second->GetSendBufferSize () << "]"; - s << "[RTT:" << it.second->GetRTT () << "]"; + s << "[RTT:" << it.second->GetRTT () << "]"; + s << "[Window:" << it.second->GetWindowSize () << "]"; + s << "[Status:" << (int)it.second->GetStatus () << "]"; s << "
"<< std::endl; } } @@ -907,6 +908,11 @@ auto session = sam->FindSession (id); if (session) { + auto& ident = session->localDestination->GetIdentHash(); + s << ""; + s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; + s << "Streams:
"; for (auto it: session->sockets) { switch (it->GetSocketType ()) @@ -968,8 +974,8 @@ m_BufferLen = len; i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination); m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT)); - m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout, - this, boost::asio::placeholders::error, destination, port, m_Buffer, m_BufferLen)); + m_Timer.async_wait (std::bind (&HTTPConnection::HandleDestinationRequestTimeout, + shared_from_this (), std::placeholders::_1, destination, port, m_Buffer, m_BufferLen)); } } @@ -1002,8 +1008,8 @@ { if (m_Stream) m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), - boost::bind (&HTTPConnection::HandleStreamReceive, this, - boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), + std::bind (&HTTPConnection::HandleStreamReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2), 45); // 45 seconds timeout } @@ -1012,7 +1018,7 @@ if (!ecode) { boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), - boost::bind (&HTTPConnection::HandleWrite, this, boost::asio::placeholders::error)); + std::bind (&HTTPConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } else { @@ -1033,8 +1039,7 @@ m_Reply.headers[1].value = "text/html"; boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), - boost::bind (&HTTPConnection::HandleWriteReply, this, - boost::asio::placeholders::error)); + std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); } HTTPServer::HTTPServer (int port): @@ -1085,14 +1090,15 @@ { if (!ecode) { - CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket); + CreateConnection(m_NewSocket); Accept (); } } void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) { - new HTTPConnection (m_NewSocket); + auto conn = std::make_shared (m_NewSocket); + conn->Receive (); } } } diff -Nru i2pd-0.9.0/HTTPServer.h i2pd-0.10.0/HTTPServer.h --- i2pd-0.9.0/HTTPServer.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/HTTPServer.h 2015-07-06 16:11:17.000000000 +0000 @@ -15,7 +15,7 @@ { const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds - class HTTPConnection + class HTTPConnection: public std::enable_shared_from_this { protected: @@ -48,13 +48,13 @@ HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Timer (socket->get_io_service ()), - m_Stream (nullptr), m_BufferLen (0) { Receive (); }; - virtual ~HTTPConnection() { delete m_Socket; } - + m_Stream (nullptr), m_BufferLen (0) {}; + ~HTTPConnection() { delete m_Socket; } + void Receive (); + private: void Terminate (); - void Receive (); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void AsyncStreamReceive (); void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); diff -Nru i2pd-0.9.0/I2NPProtocol.cpp i2pd-0.10.0/I2NPProtocol.cpp --- i2pd-0.9.0/I2NPProtocol.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2NPProtocol.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -36,51 +36,58 @@ delete msg; } - static std::atomic I2NPmsgID(0); // TODO: create class - void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID) + std::shared_ptr ToSharedI2NPMessage (I2NPMessage * msg) { - msg->SetTypeID (msgType); + return std::shared_ptr(msg, DeleteI2NPMessage); + } + + void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID) + { + SetTypeID (msgType); if (replyMsgID) // for tunnel creation - msg->SetMsgID (replyMsgID); - else - { - msg->SetMsgID (I2NPmsgID); - I2NPmsgID++; - } - msg->SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number - msg->UpdateSize (); - msg->UpdateChks (); + SetMsgID (replyMsgID); + else + SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); + SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number + UpdateSize (); + UpdateChks (); } - void RenewI2NPMessageHeader (I2NPMessage * msg) + void I2NPMessage::RenewI2NPMessageHeader () { - if (msg) - { - msg->SetMsgID (I2NPmsgID); - I2NPmsgID++; - msg->SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); - } + SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); + SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); } I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID) { I2NPMessage * msg = NewI2NPMessage (len); - memcpy (msg->GetPayload (), buf, len); - msg->len += len; - FillI2NPMessageHeader (msg, msgType, replyMsgID); + if (msg->len + len < msg->maxLen) + { + memcpy (msg->GetPayload (), buf, len); + msg->len += len; + } + else + LogPrint (eLogError, "I2NP message length ", len, " exceeds max length"); + msg->FillI2NPMessageHeader (msgType, replyMsgID); return msg; } - I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from) + std::shared_ptr CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from) { I2NPMessage * msg = NewI2NPMessage (); - memcpy (msg->GetBuffer (), buf, len); - msg->len = msg->offset + len; - msg->from = from; - return msg; + if (msg->offset + len < msg->maxLen) + { + memcpy (msg->GetBuffer (), buf, len); + msg->len = msg->offset + len; + msg->from = from; + } + else + LogPrint (eLogError, "I2NP message length ", len, " exceeds max length"); + return ToSharedI2NPMessage(msg); } - I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) + std::shared_ptr CreateDeliveryStatusMsg (uint32_t msgID) { I2NPMessage * m = NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); @@ -95,14 +102,14 @@ htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2 } m->len += DELIVERY_STATUS_SIZE; - FillI2NPMessageHeader (m, eI2NPDeliveryStatus); - return m; + m->FillI2NPMessageHeader (eI2NPDeliveryStatus); + return ToSharedI2NPMessage (m); } I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory, std::set * excludedPeers) { - I2NPMessage * m = NewI2NPShortMessage (); + I2NPMessage * m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); memcpy (buf, key, 32); // key buf += 32; @@ -140,7 +147,7 @@ } m->len += (buf - m->GetPayload ()); - FillI2NPMessageHeader (m, eI2NPDatabaseLookup); + m->FillI2NPMessageHeader (eI2NPDatabaseLookup); return m; } @@ -148,7 +155,8 @@ const std::set& excludedFloodfills, const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag) { - I2NPMessage * m = NewI2NPShortMessage (); + int cnt = excludedFloodfills.size (); + I2NPMessage * m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); memcpy (buf, dest, 32); // key buf += 32; @@ -159,7 +167,6 @@ buf += 5; // excluded - int cnt = excludedFloodfills.size (); htobe16buf (buf, cnt); buf += 2; if (cnt > 0) @@ -177,11 +184,9 @@ buf += 65; m->len += (buf - m->GetPayload ()); - FillI2NPMessageHeader (m, eI2NPDatabaseLookup); + m->FillI2NPMessageHeader (eI2NPDatabaseLookup); return m; - } - - + } I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers) @@ -201,14 +206,14 @@ memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32); len += 32; m->len += len; - FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply); + m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply); return m; } - I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router, uint32_t replyToken) + I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr router, uint32_t replyToken) { if (!router) // we send own RouterInfo - router = &context.GetRouterInfo (); + router = context.GetSharedRouterInfo (); I2NPMessage * m = NewI2NPShortMessage (); uint8_t * payload = m->GetPayload (); @@ -231,16 +236,24 @@ auto size = compressor.MaxRetrievable (); htobe16buf (buf, size); // size buf += 2; - // TODO: check if size doesn't exceed buffer - compressor.Get (buf, size); - buf += size; m->len += (buf - payload); // payload size - FillI2NPMessageHeader (m, eI2NPDatabaseStore); + if (m->len + size > m->maxLen) + { + LogPrint (eLogInfo, "DatabaseStore message size is not enough for ", m->len + size); + auto newMsg = NewI2NPMessage (); + *newMsg = *m; + DeleteI2NPMessage (m); + m = newMsg; + buf = m->buf + m->len; + } + compressor.Get (buf, size); + m->len += size; + m->FillI2NPMessageHeader (eI2NPDatabaseStore); return m; } - I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet, uint32_t replyToken) + I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken) { if (!leaseSet) return nullptr; I2NPMessage * m = NewI2NPShortMessage (); @@ -265,7 +278,7 @@ memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ()); size += leaseSet->GetBufferLen (); m->len += size; - FillI2NPMessageHeader (m, eI2NPDatabaseStore); + m->FillI2NPMessageHeader (eI2NPDatabaseStore); return m; } @@ -348,14 +361,14 @@ { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), eI2NPVariableTunnelBuildReply, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)))); } else transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + ToSharedI2NPMessage (CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)))); } } } @@ -369,14 +382,14 @@ { // so we send it to reply tunnel transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), eI2NPTunnelBuildReply, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)))); } else transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateI2NPMessage (eI2NPTunnelBuild, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + ToSharedI2NPMessage (CreateI2NPMessage (eI2NPTunnelBuild, buf, len, + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)))); } } @@ -409,7 +422,7 @@ I2NPMessage * msg = NewI2NPShortMessage (); memcpy (msg->GetPayload (), buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE); msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; - FillI2NPMessageHeader (msg, eI2NPTunnelData); + msg->FillI2NPMessageHeader (eI2NPTunnelData); return msg; } @@ -419,9 +432,16 @@ memcpy (msg->GetPayload () + 4, payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4); htobe32buf (msg->GetPayload (), tunnelID); msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; - FillI2NPMessageHeader (msg, eI2NPTunnelData); + msg->FillI2NPMessageHeader (eI2NPTunnelData); return msg; } + + std::shared_ptr CreateEmptyTunnelDataMsg () + { + I2NPMessage * msg = NewI2NPShortMessage (); + msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; + return ToSharedI2NPMessage (msg); + } I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len) { @@ -431,11 +451,11 @@ htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); memcpy (payload + TUNNEL_GATEWAY_HEADER_SIZE, buf, len); msg->len += TUNNEL_GATEWAY_HEADER_SIZE + len; - FillI2NPMessageHeader (msg, eI2NPTunnelGateway); + msg->FillI2NPMessageHeader (eI2NPTunnelGateway); return msg; } - I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg) + std::shared_ptr CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr msg) { if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE) { @@ -446,14 +466,13 @@ htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE); msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len; - FillI2NPMessageHeader (msg, eI2NPTunnelGateway); + msg->FillI2NPMessageHeader (eI2NPTunnelGateway); return msg; } else { I2NPMessage * msg1 = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ()); - DeleteI2NPMessage (msg); - return msg1; + return ToSharedI2NPMessage (msg1); } } @@ -466,13 +485,13 @@ msg->len += gatewayMsgOffset; memcpy (msg->GetPayload (), buf, len); msg->len += len; - FillI2NPMessageHeader (msg, msgType, replyMsgID); // create content message + msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message len = msg->GetLength (); msg->offset -= gatewayMsgOffset; uint8_t * payload = msg->GetPayload (); htobe32buf (payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); - FillI2NPMessageHeader (msg, eI2NPTunnelGateway); // gateway message + msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message return msg; } @@ -512,7 +531,7 @@ } } - void HandleI2NPMessage (I2NPMessage * msg) + void HandleI2NPMessage (std::shared_ptr msg) { if (msg) { @@ -527,20 +546,19 @@ i2p::tunnel::tunnels.PostTunnelData (msg); break; case eI2NPGarlic: + { LogPrint ("Garlic"); if (msg->from) { if (msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg); else - { LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore"); - DeleteI2NPMessage (msg); - } } else i2p::context.ProcessGarlicMessage (msg); - break; + break; + } case eI2NPDatabaseStore: case eI2NPDatabaseSearchReply: case eI2NPDatabaseLookup: @@ -548,12 +566,14 @@ i2p::data::netdb.PostI2NPMsg (msg); break; case eI2NPDeliveryStatus: + { LogPrint ("DeliveryStatus"); if (msg->from && msg->from->GetTunnelPool ()) msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg); else i2p::context.ProcessDeliveryStatusMessage (msg); - break; + break; + } case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuildReply: case eI2NPTunnelBuild: @@ -563,7 +583,6 @@ break; default: HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); - DeleteI2NPMessage (msg); } } } @@ -573,7 +592,7 @@ Flush (); } - void I2NPMessagesHandler::PutNextMessage (I2NPMessage * msg) + void I2NPMessagesHandler::PutNextMessage (std::shared_ptr msg) { if (msg) { diff -Nru i2pd-0.9.0/I2NPProtocol.h i2pd-0.10.0/I2NPProtocol.h --- i2pd-0.9.0/I2NPProtocol.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2NPProtocol.h 2015-07-06 16:11:17.000000000 +0000 @@ -138,6 +138,7 @@ // payload uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; }; + const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; }; uint8_t * GetBuffer () { return buf + offset; }; const uint8_t * GetBuffer () const { return buf + offset; }; size_t GetLength () const { return len - offset; }; @@ -183,6 +184,9 @@ len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); } + + void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0); + void RenewI2NPMessageHeader (); }; template @@ -196,12 +200,12 @@ I2NPMessage * NewI2NPShortMessage (); I2NPMessage * NewI2NPMessage (size_t len); void DeleteI2NPMessage (I2NPMessage * msg); - void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0); - void RenewI2NPMessageHeader (I2NPMessage * msg); + std::shared_ptr ToSharedI2NPMessage (I2NPMessage * msg); + I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0); - I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from = nullptr); + std::shared_ptr CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from = nullptr); - I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID); + std::shared_ptr CreateDeliveryStatusMsg (uint32_t msgID); I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, std::set * excludedPeers = nullptr); I2NPMessage * CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, @@ -209,8 +213,8 @@ const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag); I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers); - I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router = nullptr, uint32_t replyToken = 0); - I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet, uint32_t replyToken = 0); + I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr router = nullptr, uint32_t replyToken = 0); + I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); @@ -219,27 +223,28 @@ I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf); I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload); + std::shared_ptr CreateEmptyTunnelDataMsg (); I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len); I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); - I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg); + std::shared_ptr CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr msg); size_t GetI2NPMessageLength (const uint8_t * msg); void HandleI2NPMessage (uint8_t * msg, size_t len); - void HandleI2NPMessage (I2NPMessage * msg); + void HandleI2NPMessage (std::shared_ptr msg); class I2NPMessagesHandler { public: ~I2NPMessagesHandler (); - void PutNextMessage (I2NPMessage * msg); + void PutNextMessage (std::shared_ptr msg); void Flush (); private: - std::vector m_TunnelMsgs, m_TunnelGatewayMsgs; + std::vector > m_TunnelMsgs, m_TunnelGatewayMsgs; }; } diff -Nru i2pd-0.9.0/I2PService.cpp i2pd-0.10.0/I2PService.cpp --- i2pd-0.9.0/I2PService.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2PService.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -48,31 +48,30 @@ void TCPIPAcceptor::Accept () { - auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); + auto newSocket = std::make_shared (GetService ()); m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this, std::placeholders::_1, newSocket)); } - void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) + void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr socket) { if (!ecode) { LogPrint(eLogDebug,"--- ",GetName()," accepted"); auto handler = CreateHandler(socket); - if (handler) { + if (handler) + { AddHandler(handler); handler->Handle(); - } else { + } + else socket->close(); - delete socket; - } Accept(); } else { if (ecode != boost::asio::error::operation_aborted) LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ()); - delete socket; } } diff -Nru i2pd-0.9.0/I2PService.h i2pd-0.10.0/I2PService.h --- i2pd-0.9.0/I2PService.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2PService.h 2015-07-06 16:11:17.000000000 +0000 @@ -95,11 +95,11 @@ //If you override this make sure you call it from the children void Stop (); protected: - virtual std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket) = 0; + virtual std::shared_ptr CreateHandler(std::shared_ptr socket) = 0; virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } private: void Accept(); - void HandleAccept(const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::deadline_timer m_Timer; }; diff -Nru i2pd-0.9.0/I2PTunnel.cpp i2pd-0.10.0/I2PTunnel.cpp --- i2pd-0.9.0/I2PTunnel.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2PTunnel.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -9,7 +9,7 @@ { namespace client { - I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, + I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr leaseSet, int port): I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) @@ -18,14 +18,14 @@ } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, - boost::asio::ip::tcp::socket * socket, std::shared_ptr stream): + std::shared_ptr socket, std::shared_ptr stream): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) { } I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, - boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): + std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), m_RemoteEndpoint (target), m_IsQuiet (quiet) { @@ -85,8 +85,17 @@ else { if (m_Stream) - m_Stream->Send (m_Buffer, bytes_transferred); - Receive (); + { + auto s = shared_from_this (); + m_Stream->AsyncSend (m_Buffer, bytes_transferred, + [s](const boost::system::error_code& ecode) + { + if (!ecode) + s->Receive (); + else + s->Terminate (); + }); + } } } @@ -120,10 +129,13 @@ Terminate (); } else - { - boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), - std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); - } + Write (m_StreamBuffer, bytes_transferred); + } + + void I2PTunnelConnection::Write (const uint8_t * buf, size_t len) + { + m_Socket->async_send (boost::asio::buffer (buf, len), + std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1)); } void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode) @@ -150,12 +162,53 @@ } } + I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& host): + I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false) + { + } + + void I2PTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len) + { + if (m_HeaderSent) + I2PTunnelConnection::Write (buf, len); + else + { + m_InHeader.clear (); + m_InHeader.write ((const char *)buf, len); + std::string line; + bool endOfHeader = false; + while (!endOfHeader) + { + std::getline(m_InHeader, line); + if (!m_InHeader.fail ()) + { + if (line.find ("Host:") != std::string::npos) + m_OutHeader << "Host: " << m_Host << "\r\n"; + else + m_OutHeader << line << "\n"; + if (line == "\r") endOfHeader = true; + } + else + break; + } + + if (endOfHeader) + { + m_OutHeader << m_InHeader.str (); // data right after header + m_HeaderSent = true; + I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); + } + } + } + /* This handler tries to stablish a connection with the desired server and dies if it fails to do so */ class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this { public: I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination, - int destinationPort, boost::asio::ip::tcp::socket * socket): + int destinationPort, std::shared_ptr socket): I2PServiceHandler(parent), m_DestinationIdentHash(destination), m_DestinationPort (destinationPort), m_Socket(socket) {}; void Handle(); @@ -164,7 +217,7 @@ void HandleStreamRequestComplete (std::shared_ptr stream); i2p::data::IdentHash m_DestinationIdentHash; int m_DestinationPort; - boost::asio::ip::tcp::socket * m_Socket; + std::shared_ptr m_Socket; }; void I2PClientTunnelHandler::Handle() @@ -198,7 +251,6 @@ if (m_Socket) { m_Socket->close(); - delete m_Socket; m_Socket = nullptr; } Done(shared_from_this()); @@ -236,7 +288,7 @@ return m_DestinationIdentHash; } - std::shared_ptr I2PClientTunnel::CreateHandler(boost::asio::ip::tcp::socket * socket) + std::shared_ptr I2PClientTunnel::CreateHandler(std::shared_ptr socket) { const i2p::data::IdentHash *identHash = GetIdentHash(); if (identHash) @@ -247,14 +299,28 @@ I2PServerTunnel::I2PServerTunnel (const std::string& address, int port, std::shared_ptr localDestination, int inport): - I2PService (localDestination), m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsAccessList (false) + I2PService (localDestination), m_Address (address), m_Port (port), m_IsAccessList (false) { m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port); } void I2PServerTunnel::Start () { - Accept (); + m_Endpoint.port (m_Port); + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string (m_Address, ec); + if (!ec) + { + m_Endpoint.address (addr); + Accept (); + } + else + { + auto resolver = std::make_shared(GetService ()); + resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""), + std::bind (&I2PServerTunnel::HandleResolve, this, + std::placeholders::_1, std::placeholders::_2, resolver)); + } } void I2PServerTunnel::Stop () @@ -262,6 +328,20 @@ ClearHandlers (); } + void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, + std::shared_ptr resolver) + { + if (!ecode) + { + auto addr = (*it).endpoint ().address (); + LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr); + m_Endpoint.address (addr); + Accept (); + } + else + LogPrint (eLogError, "Unable to resolve server tunnel address: ", ecode.message ()); + } + void I2PServerTunnel::SetAccessList (const std::set& accessList) { m_AccessList = accessList; @@ -296,10 +376,27 @@ return; } } - auto conn = std::make_shared (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint); - AddHandler (conn); - conn->Connect (); + CreateI2PConnection (stream); } } + + void I2PServerTunnel::CreateI2PConnection (std::shared_ptr stream) + { + auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint ()); + AddHandler (conn); + conn->Connect (); + } + + I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& address, int port, std::shared_ptr localDestination, int inport): + I2PServerTunnel (address, port, localDestination, inport) + { + } + + void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr stream) + { + auto conn = std::make_shared (this, stream, std::make_shared (GetService ()), GetEndpoint (), GetAddress ()); + AddHandler (conn); + conn->Connect (); + } } } diff -Nru i2pd-0.9.0/I2PTunnel.h i2pd-0.10.0/I2PTunnel.h --- i2pd-0.9.0/I2PTunnel.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/I2PTunnel.h 2015-07-06 16:11:17.000000000 +0000 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "Identity.h" #include "Destination.h" @@ -24,22 +25,23 @@ { public: - I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, + I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, std::shared_ptr leaseSet, int port = 0); // to I2P - I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, - std::shared_ptr stream); // to I2P using simplified API :) - I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, boost::asio::ip::tcp::socket * socket, + I2PTunnelConnection (I2PService * owner, std::shared_ptr socket, + std::shared_ptr stream); // to I2P using simplified API + I2PTunnelConnection (I2PService * owner, std::shared_ptr stream, std::shared_ptr socket, const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P ~I2PTunnelConnection (); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); void Connect (); - private: + protected: void Terminate (); void Receive (); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + virtual void Write (const uint8_t * buf, size_t len); // can be overloaded void HandleWrite (const boost::system::error_code& ecode); void StreamReceive (); @@ -49,18 +51,37 @@ private: uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; - std::unique_ptr m_Socket; + std::shared_ptr m_Socket; std::shared_ptr m_Stream; boost::asio::ip::tcp::endpoint m_RemoteEndpoint; bool m_IsQuiet; // don't send destination }; + class I2PTunnelConnectionHTTP: public I2PTunnelConnection + { + public: + + I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr stream, + std::shared_ptr socket, + const boost::asio::ip::tcp::endpoint& target, const std::string& host); + + protected: + + void Write (const uint8_t * buf, size_t len); + + private: + + std::string m_Host; + std::stringstream m_InHeader, m_OutHeader; + bool m_HeaderSent; + }; + class I2PClientTunnel: public TCPIPAcceptor { protected: // Implements TCPIPAcceptor - std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "I2P Client Tunnel"; } public: @@ -92,18 +113,40 @@ void SetAccessList (const std::set& accessList); + const std::string& GetAddress() const { return m_Address; } + int GetPort () const { return m_Port; }; + const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; } + private: + void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, + std::shared_ptr resolver); + void Accept (); void HandleAccept (std::shared_ptr stream); + virtual void CreateI2PConnection (std::shared_ptr stream); private: + std::string m_Address; + int m_Port; boost::asio::ip::tcp::endpoint m_Endpoint; std::shared_ptr m_PortDestination; std::set m_AccessList; bool m_IsAccessList; }; + + class I2PServerTunnelHTTP: public I2PServerTunnel + { + public: + + I2PServerTunnelHTTP (const std::string& address, int port, + std::shared_ptr localDestination, int inport = 0); + + private: + + void CreateI2PConnection (std::shared_ptr stream); + }; } } diff -Nru i2pd-0.9.0/Identity.cpp i2pd-0.10.0/Identity.cpp --- i2pd-0.9.0/Identity.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Identity.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -94,7 +94,14 @@ excessBuf = new uint8_t[excessLen]; memcpy (excessBuf, signingKey + 128, excessLen); break; - } + } + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + { + size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 + i2p::context.GetRandomNumberGenerator ().GenerateBlock (m_StandardIdentity.signingKey, padding); + memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); + break; + } default: LogPrint ("Signing key type ", (int)type, " is not supported"); } @@ -344,7 +351,13 @@ memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types m_Verifier = new i2p::crypto:: RSASHA5124096Verifier (signingKey); break; - } + } + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + { + size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 + m_Verifier = new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding); + break; + } default: LogPrint ("Signing key type ", (int)keyType, " is not supported"); } @@ -457,6 +470,9 @@ case SIGNING_KEY_TYPE_RSA_SHA512_4096: m_Signer = new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey); break; + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + m_Signer = new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey); + break; default: LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported"); } diff -Nru i2pd-0.9.0/Identity.h i2pd-0.10.0/Identity.h --- i2pd-0.9.0/Identity.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Identity.h 2015-07-06 16:11:17.000000000 +0000 @@ -4,6 +4,7 @@ #include #include #include +#include #include "base64.h" #include "ElGamal.h" #include "Signature.h" @@ -40,6 +41,13 @@ bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; + bool IsZero () const + { + for (int i = 0; i < sz/8; i++) + if (ll[i]) return false; + return true; + } + std::string ToBase64 () const { char str[sz*2]; @@ -61,6 +69,11 @@ i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); } + void FromBase64 (const std::string& s) + { + i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + private: union // 8 bytes alignment @@ -116,6 +129,7 @@ const uint16_t SIGNING_KEY_TYPE_RSA_SHA256_2048 = 4; const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5; const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6; + const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7; typedef uint16_t SigningKeyType; typedef uint16_t CryptoKeyType; @@ -219,23 +233,23 @@ { public: - RoutingDestination (): m_ElGamalEncryption (nullptr) {}; - virtual ~RoutingDestination () { delete m_ElGamalEncryption; }; + RoutingDestination () {}; + virtual ~RoutingDestination () {}; virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual bool IsDestination () const = 0; // for garlic - i2p::crypto::ElGamalEncryption * GetElGamalEncryption () const + std::unique_ptr& GetElGamalEncryption () const { if (!m_ElGamalEncryption) - m_ElGamalEncryption = new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()); + m_ElGamalEncryption.reset (new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ())); return m_ElGamalEncryption; } private: - mutable i2p::crypto::ElGamalEncryption * m_ElGamalEncryption; // use lazy initialization + mutable std::unique_ptr m_ElGamalEncryption; // use lazy initialization }; class LocalDestination diff -Nru i2pd-0.9.0/LeaseSet.cpp i2pd-0.10.0/LeaseSet.cpp --- i2pd-0.9.0/LeaseSet.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/LeaseSet.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -14,23 +14,29 @@ namespace data { - LeaseSet::LeaseSet (const uint8_t * buf, int len) + LeaseSet::LeaseSet (const uint8_t * buf, size_t len): + m_IsValid (true) { + m_Buffer = new uint8_t[len]; memcpy (m_Buffer, buf, len); m_BufferLen = len; ReadFromBuffer (); } - LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool) + LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool): + m_IsValid (true) { // header const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination (); if (!localDestination) { + m_Buffer = nullptr; m_BufferLen = 0; + m_IsValid = false; LogPrint (eLogError, "Destination for local LeaseSet doesn't exist"); return; } + m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE]; m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256); m_BufferLen += 256; @@ -62,9 +68,15 @@ ReadFromBuffer (); } - void LeaseSet::Update (const uint8_t * buf, int len) + void LeaseSet::Update (const uint8_t * buf, size_t len) { m_Leases.clear (); + if (len > m_BufferLen) + { + auto oldBuffer = m_Buffer; + m_Buffer = new uint8_t[len]; + delete[] oldBuffer; + } memcpy (m_Buffer, buf, len); m_BufferLen = len; ReadFromBuffer (); @@ -79,6 +91,7 @@ uint8_t num = m_Buffer[size]; size++; // num LogPrint ("LeaseSet num=", (int)num); + if (!num) m_IsValid = false; // process leases const uint8_t * leases = m_Buffer + size; @@ -97,14 +110,17 @@ if (!netdb.FindRouter (lease.tunnelGateway)) { // if not found request it - LogPrint ("Lease's tunnel gateway not found. Requested"); + LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested"); netdb.RequestDestination (lease.tunnelGateway); } } // verify if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases)) - LogPrint ("LeaseSet verification failed"); + { + LogPrint (eLogWarning, "LeaseSet verification failed"); + m_IsValid = false; + } } const std::vector LeaseSet::GetNonExpiredLeases (bool withThreshold) const diff -Nru i2pd-0.9.0/LeaseSet.h i2pd-0.10.0/LeaseSet.h --- i2pd-0.9.0/LeaseSet.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/LeaseSet.h 2015-07-06 16:11:17.000000000 +0000 @@ -36,15 +36,15 @@ { public: - LeaseSet (const uint8_t * buf, int len); - LeaseSet (const LeaseSet& ) = default; + LeaseSet (const uint8_t * buf, size_t len); LeaseSet (const i2p::tunnel::TunnelPool& pool); - LeaseSet& operator=(const LeaseSet& ) = default; - void Update (const uint8_t * buf, int len); + ~LeaseSet () { delete[] m_Buffer; }; + void Update (const uint8_t * buf, size_t len); const IdentityEx& GetIdentity () const { return m_Identity; }; const uint8_t * GetBuffer () const { return m_Buffer; }; size_t GetBufferLen () const { return m_BufferLen; }; + bool IsValid () const { return m_IsValid; }; // implements RoutingDestination const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); }; @@ -61,10 +61,11 @@ private: + bool m_IsValid; std::vector m_Leases; IdentityEx m_Identity; uint8_t m_EncryptionKey[256]; - uint8_t m_Buffer[MAX_LS_BUFFER_SIZE]; + uint8_t * m_Buffer; size_t m_BufferLen; }; } diff -Nru i2pd-0.9.0/Log.cpp i2pd-0.10.0/Log.cpp --- i2pd-0.9.0/Log.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Log.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -1,5 +1,5 @@ -#include "Log.h" #include +#include "Log.h" Log * g_Log = nullptr; @@ -13,11 +13,30 @@ void LogMsg::Process() { - output << boost::posix_time::second_clock::local_time().time_of_day () << - "/" << g_LogLevelStr[level] << " - "; + auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr; + if (log) + output << log->GetTimestamp (); + else + output << boost::posix_time::second_clock::local_time().time_of_day (); + output << "/" << g_LogLevelStr[level] << " - "; output << s.str(); } +const std::string& Log::GetTimestamp () +{ +#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) + auto ts = std::chrono::monotonic_clock::now (); +#else + auto ts = std::chrono::steady_clock::now (); +#endif + if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second + { + m_LastTimestampUpdate = ts; + m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ()); + } + return m_Timestamp; +} + void Log::Flush () { if (m_LogStream) diff -Nru i2pd-0.9.0/Log.h i2pd-0.10.0/Log.h --- i2pd-0.9.0/Log.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Log.h 2015-07-06 16:11:17.000000000 +0000 @@ -6,6 +6,7 @@ #include #include #include +#include #include "Queue.h" enum LogLevel @@ -17,13 +18,14 @@ eNumLogLevels }; +class Log; struct LogMsg { std::stringstream s; - std::ostream& output; + Log * log; LogLevel level; - LogMsg (std::ostream& o = std::cout, LogLevel l = eLogInfo): output (o), level (l) {}; + LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {}; void Process(); }; @@ -38,6 +40,7 @@ void SetLogFile (const std::string& fullFilePath); void SetLogStream (std::ostream * logStream); std::ostream * GetLogStream () const { return m_LogStream; }; + const std::string& GetTimestamp (); private: @@ -46,6 +49,12 @@ private: std::ostream * m_LogStream; + std::string m_Timestamp; +#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6 + std::chrono::monotonic_clock::time_point m_LastTimestampUpdate; +#else + std::chrono::steady_clock::time_point m_LastTimestampUpdate; +#endif }; extern Log * g_Log; @@ -54,9 +63,10 @@ { if (!g_Log) { - g_Log = new Log (); + auto log = new Log (); if (fullFilePath.length () > 0) - g_Log->SetLogFile (fullFilePath); + log->SetLogFile (fullFilePath); + g_Log = log; } } @@ -64,9 +74,10 @@ { if (!g_Log) { - g_Log = new Log (); + auto log = new Log (); if (s) - g_Log->SetLogStream (s); + log->SetLogStream (s); + g_Log = log; } } @@ -74,8 +85,10 @@ { if (g_Log) { - delete g_Log; + auto log = g_Log; g_Log = nullptr; + log->Stop (); + delete log; } } @@ -95,8 +108,7 @@ template void LogPrint (LogLevel level, TArgs... args) { - LogMsg * msg = (g_Log && g_Log->GetLogStream ()) ? new LogMsg (*g_Log->GetLogStream (), level) : - new LogMsg (std::cout, level); + LogMsg * msg = new LogMsg (g_Log, level); LogPrint (msg->s, args...); msg->s << std::endl; if (g_Log) diff -Nru i2pd-0.9.0/Makefile.linux i2pd-0.10.0/Makefile.linux --- i2pd-0.9.0/Makefile.linux 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Makefile.linux 2015-07-06 16:11:17.000000000 +0000 @@ -8,15 +8,17 @@ ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FLAGS to work at build-time. -# detect proper flag for c++11 support by gcc +# detect proper flag for c++11 support by compilers CXXVER := $(shell $(CXX) -dumpversion) -ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # >= 4.10 +ifeq ($(shell expr match $(CXX) 'clang'),5) + NEEDED_CXXFLAGS += -std=c++11 +else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 NEEDED_CXXFLAGS += -std=c++11 else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7 NEEDED_CXXFLAGS += -std=c++11 else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 NEEDED_CXXFLAGS += -std=c++0x -else ifeq ($(shell expr match $(CXX) 'clang'),5) +else ifeq ($(shell expr match ${CXXVER} "5\.[0-9]"),3) # gcc >= 5.0 NEEDED_CXXFLAGS += -std=c++11 else # not supported $(error Compiler too old) diff -Nru i2pd-0.9.0/NetDb.cpp i2pd-0.10.0/NetDb.cpp --- i2pd-0.9.0/NetDb.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/NetDb.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -21,54 +21,7 @@ { namespace data { - I2NPMessage * RequestedDestination::CreateRequestMessage (std::shared_ptr router, - std::shared_ptr replyTunnel) - { - I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, - replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, - &m_ExcludedPeers); - m_ExcludedPeers.insert (router->GetIdentHash ()); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); - return msg; - } - - I2NPMessage * RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) - { - I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, - i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); - m_ExcludedPeers.insert (floodfill); - m_CreationTime = i2p::util::GetSecondsSinceEpoch (); - return msg; - } - - void RequestedDestination::ClearExcludedPeers () - { - m_ExcludedPeers.clear (); - } - - void RequestedDestination::Success (std::shared_ptr r) - { - if (m_RequestComplete) - { - m_RequestComplete (r); - m_RequestComplete = nullptr; - } - } - - void RequestedDestination::Fail () - { - if (m_RequestComplete) - { - m_RequestComplete (nullptr); - m_RequestComplete = nullptr; - } - } - -#ifndef _WIN32 - const char NetDb::m_NetDbPath[] = "/netDb"; -#else - const char NetDb::m_NetDbPath[] = "\\netDb"; -#endif + const char NetDb::m_NetDbPath[] = "netDb"; NetDb netdb; NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr) @@ -83,8 +36,8 @@ void NetDb::Start () { - Load (m_NetDbPath); - if (m_RouterInfos.size () < 50) // reseed if # of router less than 50 + Load (); + if (m_RouterInfos.size () < 25) // reseed if # of router less than 50 { // try SU3 first Reseed (); @@ -94,11 +47,11 @@ { // if still not enough download .dat files int reseedRetries = 0; - while (m_RouterInfos.size () < 50 && reseedRetries < 10) + while (m_RouterInfos.size () < 25 && reseedRetries < 5) { m_Reseeder->reseedNow(); reseedRetries++; - Load (m_NetDbPath); + Load (); } } } @@ -108,19 +61,24 @@ void NetDb::Stop () { - for (auto it: m_RouterInfos) - it.second->SaveProfile (); - m_RouterInfos.clear (); - if (m_Thread) + if (m_IsRunning) { - m_IsRunning = false; - m_Queue.WakeUp (); - m_Thread->join (); - delete m_Thread; - m_Thread = 0; - } - m_LeaseSets.clear(); - m_RequestedDestinations.clear (); + for (auto it: m_RouterInfos) + it.second->SaveProfile (); + DeleteObsoleteProfiles (); + m_RouterInfos.clear (); + m_Floodfills.clear (); + if (m_Thread) + { + m_IsRunning = false; + m_Queue.WakeUp (); + m_Thread->join (); + delete m_Thread; + m_Thread = 0; + } + m_LeaseSets.clear(); + m_Requests.Stop (); + } } void NetDb::Run () @@ -130,7 +88,7 @@ { try { - I2NPMessage * msg = m_Queue.GetNextWithTimeout (15000); // 15 sec + auto msg = m_Queue.GetNextWithTimeout (15000); // 15 sec if (msg) { int numMsgs = 0; @@ -151,8 +109,8 @@ HandleDatabaseLookupMsg (msg); break; default: // WTF? - LogPrint ("NetDb: unexpected message type ", msg->GetTypeID ()); - i2p::HandleI2NPMessage (msg); + LogPrint (eLogError, "NetDb: unexpected message type ", msg->GetTypeID ()); + //i2p::HandleI2NPMessage (msg); } if (numMsgs > 100) break; msg = m_Queue.Get (); @@ -164,14 +122,14 @@ uint64_t ts = i2p::util::GetSecondsSinceEpoch (); if (ts - lastManageRequest >= 15) // manage requests every 15 seconds { - ManageRequests (); + m_Requests.ManageRequests (); lastManageRequest = ts; } if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute { if (lastSave) { - SaveUpdated (m_NetDbPath); + SaveUpdated (); ManageLeaseSets (); } lastSave = ts; @@ -189,7 +147,7 @@ numRouters = 800/numRouters; if (numRouters < 1) numRouters = 1; if (numRouters > 9) numRouters = 9; - ManageRequests (); + m_Requests.ManageRequests (); Explore (numRouters); lastExploratory = ts; } @@ -234,13 +192,7 @@ } } // take care about requested destination - auto it = m_RequestedDestinations.find (ident); - if (it != m_RequestedDestinations.end ()) - { - it->second->Success (r); - std::unique_lock l(m_RequestedDestinationsMutex); - m_RequestedDestinations.erase (it); - } + m_Requests.RequestComplete (ident, r); } void NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, @@ -252,12 +204,24 @@ if (it != m_LeaseSets.end ()) { it->second->Update (buf, len); - LogPrint ("LeaseSet updated"); + if (it->second->IsValid ()) + LogPrint (eLogInfo, "LeaseSet updated"); + else + { + LogPrint (eLogInfo, "LeaseSet update failed"); + m_LeaseSets.erase (it); + } } else { - LogPrint ("New LeaseSet added"); - m_LeaseSets[ident] = std::make_shared (buf, len); + auto leaseSet = std::make_shared (buf, len); + if (leaseSet->IsValid ()) + { + LogPrint (eLogInfo, "New LeaseSet added"); + m_LeaseSets[ident] = leaseSet; + } + else + LogPrint (eLogError, "New LeaseSet validation failed"); } } } @@ -327,10 +291,9 @@ LogPrint (eLogWarning, "Failed to reseed after 10 attempts"); } - void NetDb::Load (const char * directory) + void NetDb::Load () { - boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); - p /= (directory); + boost::filesystem::path p(i2p::util::filesystem::GetDataDir() / m_NetDbPath); if (!boost::filesystem::exists (p)) { // seems netDb doesn't exist yet @@ -377,27 +340,15 @@ LogPrint (m_Floodfills.size (), " floodfills loaded"); } - void NetDb::SaveUpdated (const char * directory) + void NetDb::SaveUpdated () { - auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo) + auto GetFilePath = [](const boost::filesystem::path& directory, const RouterInfo * routerInfo) { -#ifndef _WIN32 - return std::string (directory) + "/r" + - routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" + -#else - return std::string (directory) + "\\r" + - routerInfo->GetIdentHashBase64 ()[0] + "\\routerInfo-" + -#endif - routerInfo->GetIdentHashBase64 () + ".dat"; + std::string s(routerInfo->GetIdentHashBase64()); + return directory / (std::string("r") + s[0]) / ("routerInfo-" + s + ".dat"); }; - boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); - p /= (directory); -#if BOOST_VERSION > 10500 - const char * fullDirectory = p.string().c_str (); -#else - const char * fullDirectory = p.c_str (); -#endif + boost::filesystem::path fullDirectory (i2p::util::filesystem::GetDataDir() / m_NetDbPath); int count = 0, deletedCount = 0; auto total = m_RouterInfos.size (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); @@ -405,7 +356,8 @@ { if (it.second->IsUpdated ()) { - it.second->SaveToFile (GetFilePath(fullDirectory, it.second.get ())); + std::string f = GetFilePath(fullDirectory, it.second.get()).string(); + it.second->SaveToFile (f); it.second->SetUpdated (false); it.second->SetUnreachable (false); it.second->DeleteBuffer (); @@ -416,22 +368,31 @@ // RouterInfo expires after 1 hour if uses introducer if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hour it.second->SetUnreachable (true); - else if (total > 25 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes + else if (total > 75 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes { if (i2p::context.IsFloodfill ()) { if (ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hours + { it.second->SetUnreachable (true); + total--; + } } else if (total > 300) { if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours + { it.second->SetUnreachable (true); + total--; + } } else if (total > 120) { if (ts > it.second->GetTimestamp () + 72*3600*1000LL) // 72 hours + { it.second->SetUnreachable (true); + total--; + } } } @@ -475,35 +436,33 @@ void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete) { - // request RouterInfo directly - auto dest = new RequestedDestination (destination, false); // non-exploratory - dest->SetRequestComplete (requestComplete); - { - std::unique_lock l(m_RequestedDestinationsMutex); - if (!m_RequestedDestinations.insert (std::make_pair (destination, - std::unique_ptr (dest))).second) // not inserted - { - LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already"); - return; - } + auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory + if (!dest) + { + LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already"); + return; } - + auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); if (floodfill) transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); else { LogPrint (eLogError, "No floodfills found"); - dest->Fail (); - std::unique_lock l(m_RequestedDestinationsMutex); - m_RequestedDestinations.erase (destination); + m_Requests.RequestComplete (destination, nullptr); } } - void NetDb::HandleDatabaseStoreMsg (I2NPMessage * m) + void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m) { const uint8_t * buf = m->GetPayload (); size_t len = m->GetSize (); + IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET); + if (ident.IsZero ()) + { + LogPrint (eLogError, "Database store with zero ident. Dropped"); + return; + } uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); size_t offset = DATABASE_STORE_HEADER_SIZE; if (replyToken) @@ -520,32 +479,26 @@ if (outbound) outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus); else - { LogPrint (eLogError, "No outbound tunnels for DatabaseStore reply found"); - DeleteI2NPMessage (deliveryStatus); - } } offset += 32; if (context.IsFloodfill ()) { // flood it + auto floodMsg = ToSharedI2NPMessage (NewI2NPShortMessage ()); + uint8_t * payload = floodMsg->GetPayload (); + memcpy (payload, buf, 33); // key + type + htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token + memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset); + floodMsg->len += DATABASE_STORE_HEADER_SIZE + len -offset; + floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore); std::set excluded; for (int i = 0; i < 3; i++) { - auto floodfill = GetClosestFloodfill (buf + DATABASE_STORE_KEY_OFFSET, excluded); + auto floodfill = GetClosestFloodfill (ident, excluded); if (floodfill) - { - excluded.insert (floodfill->GetIdentHash ()); - auto floodMsg = NewI2NPShortMessage (); - uint8_t * payload = floodMsg->GetPayload (); - memcpy (payload, buf, 33); // key + type - htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token - memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset); - floodMsg->len += DATABASE_STORE_HEADER_SIZE + len -offset; - FillI2NPMessageHeader (floodMsg, eI2NPDatabaseStore); transports.SendMessage (floodfill->GetIdentHash (), floodMsg); - } } } } @@ -553,7 +506,7 @@ if (buf[DATABASE_STORE_TYPE_OFFSET]) // type { LogPrint ("LeaseSet"); - AddLeaseSet (buf + DATABASE_STORE_KEY_OFFSET, buf + offset, len - offset, m->from); + AddLeaseSet (ident, buf + offset, len - offset, m->from); } else { @@ -563,7 +516,6 @@ if (size > 2048 || size > len - offset) { LogPrint ("Invalid RouterInfo length ", (int)size); - i2p::DeleteI2NPMessage (m); return; } try @@ -576,7 +528,7 @@ if (uncomressedSize <= 2048) { decompressor.Get (uncompressed, uncomressedSize); - AddRouterInfo (buf + DATABASE_STORE_KEY_OFFSET, uncompressed, uncomressedSize); + AddRouterInfo (ident, uncompressed, uncomressedSize); } else LogPrint ("Invalid RouterInfo uncomressed length ", (int)uncomressedSize); @@ -586,21 +538,20 @@ LogPrint (eLogError, "DatabaseStore: ", ex.what ()); } } - i2p::DeleteI2NPMessage (m); } - void NetDb::HandleDatabaseSearchReplyMsg (I2NPMessage * msg) + void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr msg) { - uint8_t * buf = msg->GetPayload (); + const uint8_t * buf = msg->GetPayload (); char key[48]; int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); key[l] = 0; int num = buf[32]; // num LogPrint ("DatabaseSearchReply for ", key, " num=", num); - auto it = m_RequestedDestinations.find (IdentHash (buf)); - if (it != m_RequestedDestinations.end ()) + IdentHash ident (buf); + auto dest = m_Requests.FindRequest (ident); + if (dest) { - auto& dest = it->second; bool deleteDest = true; if (num > 0) { @@ -624,7 +575,7 @@ { i2p::tunnel::eDeliveryTypeRouter, nextFloodfill->GetIdentHash (), 0, - CreateDatabaseStoreMsg () + ToSharedI2NPMessage (CreateDatabaseStoreMsg ()) }); // request destination @@ -647,18 +598,12 @@ } if (deleteDest) - { // no more requests for the destinationation. delete it - it->second->Fail (); - m_RequestedDestinations.erase (it); - } + m_Requests.RequestComplete (ident, nullptr); } else - { // no more requests for detination possible. delete it - it->second->Fail (); - m_RequestedDestinations.erase (it); - } + m_Requests.RequestComplete (ident, nullptr); } else LogPrint ("Requested destination for ", key, " not found"); @@ -666,7 +611,7 @@ // try responses for (int i = 0; i < num; i++) { - uint8_t * router = buf + 33 + i*32; + const uint8_t * router = buf + 33 + i*32; char peerHash[48]; int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48); peerHash[l1] = 0; @@ -682,20 +627,24 @@ else LogPrint ("Bayan"); } - - i2p::DeleteI2NPMessage (msg); } - void NetDb::HandleDatabaseLookupMsg (I2NPMessage * msg) + void NetDb::HandleDatabaseLookupMsg (std::shared_ptr msg) { - uint8_t * buf = msg->GetPayload (); + const uint8_t * buf = msg->GetPayload (); + IdentHash ident (buf); + if (ident.IsZero ()) + { + LogPrint (eLogError, "DatabaseLookup for zero ident. Ignored"); + return; + } char key[48]; int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); key[l] = 0; uint8_t flag = buf[64]; LogPrint ("DatabaseLookup for ", key, " recieved flags=", (int)flag); uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK; - uint8_t * excluded = buf + 65; + const uint8_t * excluded = buf + 65; uint32_t replyTunnelID = 0; if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel { @@ -710,7 +659,7 @@ numExcluded = 0; // TODO: } - I2NPMessage * replyMsg = nullptr; + std::shared_ptr replyMsg; if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP) { LogPrint ("Exploratory close to ", key, " ", numExcluded, " excluded"); @@ -723,55 +672,51 @@ std::vector routers; for (int i = 0; i < 3; i++) { - auto r = GetClosestNonFloodfill (buf, excludedRouters); + auto r = GetClosestNonFloodfill (ident, excludedRouters); if (r) { routers.push_back (r->GetIdentHash ()); excludedRouters.insert (r->GetIdentHash ()); } } - replyMsg = CreateDatabaseSearchReply (buf, routers); + replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, routers)); } else { - auto router = FindRouter (buf); - if (router) - { - LogPrint ("Requested RouterInfo ", key, " found"); - router->LoadBuffer (); - if (router->GetBuffer ()) - replyMsg = CreateDatabaseStoreMsg (router.get ()); + if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP || + lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP) + { + auto router = FindRouter (ident); + if (router) + { + LogPrint ("Requested RouterInfo ", key, " found"); + router->LoadBuffer (); + if (router->GetBuffer ()) + replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (router)); + } } - - if (!replyMsg) + + if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP || + lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)) { - auto leaseSet = FindLeaseSet (buf); + auto leaseSet = FindLeaseSet (ident); if (leaseSet) // we don't send back our LeaseSets { LogPrint ("Requested LeaseSet ", key, " found"); - replyMsg = CreateDatabaseStoreMsg (leaseSet.get ()); + replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (leaseSet)); } } + if (!replyMsg) { LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded"); - std::set excludedRouters; + std::set excludedRouters; for (int i = 0; i < numExcluded; i++) { excludedRouters.insert (excluded); excluded += 32; - } - std::vector routers; - for (int i = 0; i < 3; i++) - { - auto floodfill = GetClosestFloodfill (buf, excludedRouters); - if (floodfill) - { - routers.push_back (floodfill->GetIdentHash ()); - excludedRouters.insert (floodfill->GetIdentHash ()); - } - } - replyMsg = CreateDatabaseSearchReply (buf, routers); + } + replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters))); } } @@ -782,11 +727,11 @@ // encryption might be used though tunnel only if (flag & DATABASE_LOOKUP_ENCYPTION_FLAG) // encrypted reply requested { - uint8_t * sessionKey = excluded; + const uint8_t * sessionKey = excluded; uint8_t numTags = sessionKey[32]; if (numTags > 0) { - uint8_t * sessionTag = sessionKey + 33; // take first tag + const uint8_t * sessionTag = sessionKey + 33; // take first tag i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag); replyMsg = garlic.WrapSingleMessage (replyMsg); } @@ -801,7 +746,6 @@ else transports.SendMessage (buf+32, replyMsg); } - i2p::DeleteI2NPMessage (msg); } void NetDb::Explore (int numDestinations) @@ -820,15 +764,11 @@ for (int i = 0; i < numDestinations; i++) { rnd.GenerateBlock (randomHash, 32); - auto dest = new RequestedDestination (randomHash, true); // exploratory - { - std::unique_lock l(m_RequestedDestinationsMutex); - if (!m_RequestedDestinations.insert (std::make_pair (randomHash, - std::unique_ptr (dest))).second) // not inserted - { - LogPrint (eLogWarning, "Exploratory destination is requested already"); - return; - } + auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory + if (!dest) + { + LogPrint (eLogWarning, "Exploratory destination is requested already"); + return; } auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once @@ -842,7 +782,7 @@ { i2p::tunnel::eDeliveryTypeRouter, floodfill->GetIdentHash (), 0, - CreateDatabaseStoreMsg () // tell floodfill about us + ToSharedI2NPMessage (CreateDatabaseStoreMsg ()) // tell floodfill about us }); msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -855,10 +795,7 @@ i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); } else - { - std::unique_lock l(m_RequestedDestinationsMutex); - m_RequestedDestinations.erase (dest->GetDestination ()); - } + m_Requests.RequestComplete (randomHash, nullptr); } if (throughTunnels && msgs.size () > 0) outbound->SendTunnelDataMsg (msgs); @@ -874,7 +811,7 @@ { uint32_t replyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation (), ". reply token=", replyToken); - transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ((RouterInfo *)nullptr, replyToken)); + transports.SendMessage (floodfill->GetIdentHash (), ToSharedI2NPMessage (CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken))); excluded.insert (floodfill->GetIdentHash ()); } } @@ -923,7 +860,8 @@ [compatibleWith](std::shared_ptr router)->bool { return !router->IsHidden () && router != compatibleWith && - router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth); + router->IsCompatible (*compatibleWith) && + (router->GetCaps () & RouterInfo::eHighBandwidth); }); } @@ -952,7 +890,7 @@ return nullptr; // seems we have too few routers } - void NetDb::PostI2NPMsg (I2NPMessage * msg) + void NetDb::PostI2NPMsg (std::shared_ptr msg) { if (msg) m_Queue.Put (msg); } @@ -967,10 +905,10 @@ std::unique_lock l(m_FloodfillsMutex); for (auto it: m_Floodfills) { - if (!it->IsUnreachable () && !excluded.count (it->GetIdentHash ())) + if (!it->IsUnreachable ()) { XORMetric m = destKey ^ it->GetIdentHash (); - if (m < minMetric) + if (m < minMetric && !excluded.count (it->GetIdentHash ())) { minMetric = m; r = it; @@ -980,6 +918,55 @@ return r; } + std::vector NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num, + std::set& excluded) const + { + struct Sorted + { + std::shared_ptr r; + XORMetric metric; + bool operator< (const Sorted& other) const { return metric < other.metric; }; + }; + + std::set sorted; + IdentHash destKey = CreateRoutingKey (destination); + { + std::unique_lock l(m_FloodfillsMutex); + for (auto it: m_Floodfills) + { + if (!it->IsUnreachable ()) + { + XORMetric m = destKey ^ it->GetIdentHash (); + if (sorted.size () < num) + sorted.insert ({it, m}); + else if (m < sorted.rbegin ()->metric) + { + sorted.insert ({it, m}); + sorted.erase (std::prev (sorted.end ())); + } + } + } + } + + std::vector res; + size_t i = 0; + for (auto it: sorted) + { + if (i < num) + { + auto& ident = it.r->GetIdentHash (); + if (!excluded.count (ident)) + { + res.push_back (ident); + i++; + } + } + else + break; + } + return res; + } + std::shared_ptr NetDb::GetClosestNonFloodfill (const IdentHash& destination, const std::set& excluded) const { @@ -990,10 +977,10 @@ // must be called from NetDb thread only for (auto it: m_RouterInfos) { - if (!it.second->IsFloodfill () && !excluded.count (it.first)) + if (!it.second->IsFloodfill ()) { XORMetric m = destKey ^ it.first; - if (m < minMetric) + if (m < minMetric && !excluded.count (it.first)) { minMetric = m; r = it.second; @@ -1016,53 +1003,5 @@ it++; } } - - void NetDb::ManageRequests () - { - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - std::unique_lock l(m_RequestedDestinationsMutex); - for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) - { - auto& dest = it->second; - bool done = false; - if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute - { - if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds - { - auto count = dest->GetExcludedPeers ().size (); - if (!dest->IsExploratory () && count < 7) - { - auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); - auto outbound = pool->GetNextOutboundTunnel (); - auto inbound = pool->GetNextInboundTunnel (); - auto nextFloodfill = GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); - if (nextFloodfill && outbound && inbound) - outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0, - dest->CreateRequestMessage (nextFloodfill, inbound)); - else - { - done = true; - if (!inbound) LogPrint (eLogWarning, "No inbound tunnels"); - if (!outbound) LogPrint (eLogWarning, "No outbound tunnels"); - if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills"); - } - } - else - { - if (!dest->IsExploratory ()) - LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); - done = true; - } - } - } - else // delete obsolete request - done = true; - - if (done) - it = m_RequestedDestinations.erase (it); - else - it++; - } - } } } diff -Nru i2pd-0.9.0/NetDb.h i2pd-0.10.0/NetDb.h --- i2pd-0.9.0/NetDb.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/NetDb.h 2015-07-06 16:11:17.000000000 +0000 @@ -16,44 +16,12 @@ #include "Tunnel.h" #include "TunnelPool.h" #include "Reseed.h" +#include "NetDbRequests.h" namespace i2p { namespace data { - class RequestedDestination - { - public: - - typedef std::function)> RequestComplete; - - RequestedDestination (const IdentHash& destination, bool isExploratory = false): - m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {}; - ~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); }; - - const IdentHash& GetDestination () const { return m_Destination; }; - int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; - const std::set& GetExcludedPeers () { return m_ExcludedPeers; }; - void ClearExcludedPeers (); - bool IsExploratory () const { return m_IsExploratory; }; - bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; - uint64_t GetCreationTime () const { return m_CreationTime; }; - I2NPMessage * CreateRequestMessage (std::shared_ptr, std::shared_ptr replyTunnel); - I2NPMessage * CreateRequestMessage (const IdentHash& floodfill); - - void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; }; - bool IsRequestComplete () const { return m_RequestComplete != nullptr; }; - void Success (std::shared_ptr r); - void Fail (); - - private: - - IdentHash m_Destination; - bool m_IsExploratory; - std::set m_ExcludedPeers; - uint64_t m_CreationTime; - RequestComplete m_RequestComplete; - }; class NetDb { @@ -73,9 +41,9 @@ void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); - void HandleDatabaseStoreMsg (I2NPMessage * msg); - void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); - void HandleDatabaseLookupMsg (I2NPMessage * msg); + void HandleDatabaseStoreMsg (std::shared_ptr msg); + void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); + void HandleDatabaseLookupMsg (std::shared_ptr msg); std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith) const; @@ -83,14 +51,16 @@ std::shared_ptr GetRandomPeerTestRouter () const; std::shared_ptr GetRandomIntroducer () const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; + std::vector GetClosestFloodfills (const IdentHash& destination, size_t num, + std::set& excluded) const; std::shared_ptr GetClosestNonFloodfill (const IdentHash& destination, const std::set& excluded) const; void SetUnreachable (const IdentHash& ident, bool unreachable); - void PostI2NPMsg (I2NPMessage * msg); + void PostI2NPMsg (std::shared_ptr msg); void Reseed (); - // for web interface and stats + // for web interface int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumFloodfills () const { return m_Floodfills.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); }; @@ -98,8 +68,8 @@ private: bool CreateNetDb(boost::filesystem::path directory); - void Load (const char * directory); - void SaveUpdated (const char * directory); + void Load (); + void SaveUpdated (); void Run (); // exploratory thread void Explore (int numDestinations); void Publish (); @@ -116,15 +86,16 @@ std::map > m_RouterInfos; mutable std::mutex m_FloodfillsMutex; std::list > m_Floodfills; - std::mutex m_RequestedDestinationsMutex; - std::map > m_RequestedDestinations; bool m_IsRunning; std::thread * m_Thread; - i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg + i2p::util::Queue > m_Queue; // of I2NPDatabaseStoreMsg Reseeder * m_Reseeder; + friend class NetDbRequests; + NetDbRequests m_Requests; + static const char m_NetDbPath[]; }; diff -Nru i2pd-0.9.0/NetDbRequests.cpp i2pd-0.10.0/NetDbRequests.cpp --- i2pd-0.9.0/NetDbRequests.cpp 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/NetDbRequests.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,149 @@ +#include "Log.h" +#include "I2NPProtocol.h" +#include "Transports.h" +#include "NetDb.h" +#include "NetDbRequests.h" + +namespace i2p +{ +namespace data +{ + std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, + std::shared_ptr replyTunnel) + { + I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, + &m_ExcludedPeers); + m_ExcludedPeers.insert (router->GetIdentHash ()); + m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + return ToSharedI2NPMessage (msg); + } + + std::shared_ptr RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) + { + I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); + m_ExcludedPeers.insert (floodfill); + m_CreationTime = i2p::util::GetSecondsSinceEpoch (); + return ToSharedI2NPMessage (msg); + } + + void RequestedDestination::ClearExcludedPeers () + { + m_ExcludedPeers.clear (); + } + + void RequestedDestination::Success (std::shared_ptr r) + { + if (m_RequestComplete) + { + m_RequestComplete (r); + m_RequestComplete = nullptr; + } + } + + void RequestedDestination::Fail () + { + if (m_RequestComplete) + { + m_RequestComplete (nullptr); + m_RequestComplete = nullptr; + } + } + + void NetDbRequests::Start () + { + } + + void NetDbRequests::Stop () + { + m_RequestedDestinations.clear (); + } + + + std::shared_ptr NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete) + { + // request RouterInfo directly + auto dest = std::make_shared (destination, isExploratory); + dest->SetRequestComplete (requestComplete); + { + std::unique_lock l(m_RequestedDestinationsMutex); + if (!m_RequestedDestinations.insert (std::make_pair (destination, + std::shared_ptr (dest))).second) // not inserted + return nullptr; + } + return dest; + } + + void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr r) + { + auto it = m_RequestedDestinations.find (ident); + if (it != m_RequestedDestinations.end ()) + { + if (r) + it->second->Success (r); + else + it->second->Fail (); + std::unique_lock l(m_RequestedDestinationsMutex); + m_RequestedDestinations.erase (it); + } + } + + std::shared_ptr NetDbRequests::FindRequest (const IdentHash& ident) const + { + auto it = m_RequestedDestinations.find (ident); + if (it != m_RequestedDestinations.end ()) + return it->second; + return nullptr; + } + + void NetDbRequests::ManageRequests () + { + uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + std::unique_lock l(m_RequestedDestinationsMutex); + for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) + { + auto& dest = it->second; + bool done = false; + if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute + { + if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds + { + auto count = dest->GetExcludedPeers ().size (); + if (!dest->IsExploratory () && count < 7) + { + auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); + auto outbound = pool->GetNextOutboundTunnel (); + auto inbound = pool->GetNextInboundTunnel (); + auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); + if (nextFloodfill && outbound && inbound) + outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0, + dest->CreateRequestMessage (nextFloodfill, inbound)); + else + { + done = true; + if (!inbound) LogPrint (eLogWarning, "No inbound tunnels"); + if (!outbound) LogPrint (eLogWarning, "No outbound tunnels"); + if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills"); + } + } + else + { + if (!dest->IsExploratory ()) + LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); + done = true; + } + } + } + else // delete obsolete request + done = true; + + if (done) + it = m_RequestedDestinations.erase (it); + else + it++; + } + } +} +} + diff -Nru i2pd-0.9.0/NetDbRequests.h i2pd-0.10.0/NetDbRequests.h --- i2pd-0.9.0/NetDbRequests.h 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/NetDbRequests.h 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,69 @@ +#ifndef NETDB_REQUESTS_H__ +#define NETDB_REQUESTS_H__ + +#include +#include +#include +#include "Identity.h" +#include "RouterInfo.h" + +namespace i2p +{ +namespace data +{ + class RequestedDestination + { + public: + + typedef std::function)> RequestComplete; + + RequestedDestination (const IdentHash& destination, bool isExploratory = false): + m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {}; + ~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); }; + + const IdentHash& GetDestination () const { return m_Destination; }; + int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; + const std::set& GetExcludedPeers () { return m_ExcludedPeers; }; + void ClearExcludedPeers (); + bool IsExploratory () const { return m_IsExploratory; }; + bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; + uint64_t GetCreationTime () const { return m_CreationTime; }; + std::shared_ptr CreateRequestMessage (std::shared_ptr, std::shared_ptr replyTunnel); + std::shared_ptr CreateRequestMessage (const IdentHash& floodfill); + + void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; }; + bool IsRequestComplete () const { return m_RequestComplete != nullptr; }; + void Success (std::shared_ptr r); + void Fail (); + + private: + + IdentHash m_Destination; + bool m_IsExploratory; + std::set m_ExcludedPeers; + uint64_t m_CreationTime; + RequestComplete m_RequestComplete; + }; + + class NetDbRequests + { + public: + + void Start (); + void Stop (); + + std::shared_ptr CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr); + void RequestComplete (const IdentHash& ident, std::shared_ptr r); + std::shared_ptr FindRequest (const IdentHash& ident) const; + void ManageRequests (); + + private: + + std::mutex m_RequestedDestinationsMutex; + std::map > m_RequestedDestinations; + }; +} +} + +#endif + diff -Nru i2pd-0.9.0/NTCPSession.cpp i2pd-0.10.0/NTCPSession.cpp --- i2pd-0.9.0/NTCPSession.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/NTCPSession.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -2,6 +2,7 @@ #include #include "I2PEndian.h" #include +#include #include "base64.h" #include "Log.h" #include "Timestamp.h" @@ -82,14 +83,8 @@ m_Socket.close (); transports.PeerDisconnected (shared_from_this ()); m_Server.RemoveNTCPSession (shared_from_this ()); - for (auto it: m_SendQueue) - DeleteI2NPMessage (it); m_SendQueue.clear (); - if (m_NextMessage) - { - i2p::DeleteI2NPMessage (m_NextMessage); - m_NextMessage = nullptr; - } + m_NextMessage = nullptr; m_TerminationTimer.cancel (); LogPrint (eLogInfo, "NTCP session terminated"); } @@ -106,7 +101,7 @@ m_DHKeysPair = nullptr; SendTimeSyncMessage (); - PostI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are + m_SendQueue.push_back (ToSharedI2NPMessage(CreateDatabaseStoreMsg ())); // we tell immediately who we are transports.PeerConnected (shared_from_this ()); } @@ -565,7 +560,8 @@ LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size"); return false; } - m_NextMessage = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage (); + auto msg = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage (); + m_NextMessage = ToSharedI2NPMessage (msg); memcpy (m_NextMessage->buf, buf, 16); m_NextMessageOffset = 16; m_NextMessage->offset = 2; // size field @@ -587,20 +583,23 @@ if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum { // we have a complete I2NP message - m_Handler.PutNextMessage (m_NextMessage); + if (CryptoPP::Adler32().VerifyDigest (m_NextMessage->buf + m_NextMessageOffset - 4, m_NextMessage->buf, m_NextMessageOffset - 4)) + m_Handler.PutNextMessage (m_NextMessage); + else + LogPrint (eLogWarning, "Incorrect adler checksum of NTCP message. Dropped"); m_NextMessage = nullptr; } return true; } - void NTCPSession::Send (i2p::I2NPMessage * msg) + void NTCPSession::Send (std::shared_ptr msg) { m_IsSending = true; boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (), - std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector{ msg })); + std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector >{ msg })); } - boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (I2NPMessage * msg) + boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr msg) { uint8_t * sendBuffer; int len; @@ -609,10 +608,7 @@ { // regular I2NP if (msg->offset < 2) - { - LogPrint (eLogError, "Malformed I2NP message"); - i2p::DeleteI2NPMessage (msg); - } + LogPrint (eLogError, "Malformed I2NP message"); // TODO: sendBuffer = msg->GetBuffer () - 2; len = msg->GetLength (); htobe16buf (sendBuffer, len); @@ -629,7 +625,7 @@ int padding = 0; if (rem > 0) padding = 16 - rem; // TODO: fill padding - m_Adler.CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding); + CryptoPP::Adler32().CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding); int l = len + padding + 6; m_Encryption.Encrypt(sendBuffer, l, sendBuffer); @@ -637,7 +633,7 @@ } - void NTCPSession::Send (const std::vector& msgs) + void NTCPSession::Send (const std::vector >& msgs) { m_IsSending = true; std::vector bufs; @@ -647,11 +643,9 @@ std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); } - void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector msgs) + void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs) { m_IsSending = false; - for (auto it: msgs) - if (it) i2p::DeleteI2NPMessage (it); if (ecode) { LogPrint (eLogWarning, "Couldn't send msgs: ", ecode.message ()); @@ -679,40 +673,15 @@ Send (nullptr); } - void NTCPSession::SendI2NPMessage (I2NPMessage * msg) - { - m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessage, shared_from_this (), msg)); - } - - void NTCPSession::PostI2NPMessage (I2NPMessage * msg) - { - if (msg) - { - if (m_IsTerminated) - { - DeleteI2NPMessage (msg); - return; - } - if (m_IsSending) - m_SendQueue.push_back (msg); - else - Send (msg); - } - } - void NTCPSession::SendI2NPMessages (const std::vector& msgs) + void NTCPSession::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs)); } - void NTCPSession::PostI2NPMessages (std::vector msgs) + void NTCPSession::PostI2NPMessages (std::vector > msgs) { - if (m_IsTerminated) - { - for (auto it: msgs) - DeleteI2NPMessage (it); - return; - } + if (m_IsTerminated) return; if (m_IsSending) { for (auto it: msgs) diff -Nru i2pd-0.9.0/NTCPSession.h i2pd-0.10.0/NTCPSession.h --- i2pd-0.9.0/NTCPSession.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/NTCPSession.h 2015-07-06 16:11:17.000000000 +0000 @@ -9,7 +9,6 @@ #include #include #include -#include #include "aes.h" #include "Identity.h" #include "RouterInfo.h" @@ -62,13 +61,11 @@ void ClientLogin (); void ServerLogin (); - void SendI2NPMessage (I2NPMessage * msg); - void SendI2NPMessages (const std::vector& msgs); + void SendI2NPMessages (const std::vector >& msgs); private: - void PostI2NPMessage (I2NPMessage * msg); - void PostI2NPMessages (std::vector msgs); + void PostI2NPMessages (std::vector > msgs); void Connected (); void SendTimeSyncMessage (); void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; } @@ -97,10 +94,10 @@ void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); bool DecryptNextBlock (const uint8_t * encrypted); - void Send (i2p::I2NPMessage * msg); - boost::asio::const_buffers_1 CreateMsgBuffer (I2NPMessage * msg); - void Send (const std::vector& msgs); - void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector msgs); + void Send (std::shared_ptr msg); + boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr msg); + void Send (const std::vector >& msgs); + void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs); // timer @@ -116,7 +113,6 @@ i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCEncryption m_Encryption; - CryptoPP::Adler32 m_Adler; struct Establisher { @@ -128,12 +124,12 @@ i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer; int m_ReceiveBufferOffset; - i2p::I2NPMessage * m_NextMessage; + std::shared_ptr m_NextMessage; size_t m_NextMessageOffset; i2p::I2NPMessagesHandler m_Handler; bool m_IsSending; - std::vector m_SendQueue; + std::vector > m_SendQueue; boost::asio::ip::address m_ConnectedFrom; // for ban }; diff -Nru i2pd-0.9.0/Profiling.cpp i2pd-0.10.0/Profiling.cpp --- i2pd-0.9.0/Profiling.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Profiling.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -11,14 +11,19 @@ { RouterProfile::RouterProfile (const IdentHash& identHash): m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()), - m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), - m_NumTunnelsNonReplied (0) + m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), + m_NumTimesTaken (0), m_NumTimesRejected (0) { } + boost::posix_time::ptime RouterProfile::GetTime () const + { + return boost::posix_time::second_clock::local_time(); + } + void RouterProfile::UpdateTime () { - m_LastUpdateTime = boost::posix_time::second_clock::local_time(); + m_LastUpdateTime = GetTime (); } void RouterProfile::Save () @@ -28,11 +33,15 @@ participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed); participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined); participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied); + boost::property_tree::ptree usage; + usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken); + usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected); // fill property tree boost::property_tree::ptree pt; pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime)); pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation); - + pt.put_child (PEER_PROFILE_SECTION_USAGE, usage); + // save to file auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY; if (!boost::filesystem::exists (path)) @@ -90,11 +99,34 @@ auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); if (t.length () > 0) m_LastUpdateTime = boost::posix_time::time_from_string (t); - // read participations - auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION); - m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0); - m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0); - m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); + if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) + { + try + { + // read participations + auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION); + m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0); + m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0); + m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); + } + catch (boost::property_tree::ptree_bad_path& ex) + { + LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION); + } + try + { + // read usage + auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE); + m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0); + m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0); + } + catch (boost::property_tree::ptree_bad_path& ex) + { + LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE); + } + } + else + *this = RouterProfile (m_IdentHash); } catch (std::exception& ex) { @@ -105,11 +137,11 @@ void RouterProfile::TunnelBuildResponse (uint8_t ret) { + UpdateTime (); if (ret > 0) m_NumTunnelsDeclined++; else m_NumTunnelsAgreed++; - UpdateTime (); } void RouterProfile::TunnelNonReplied () @@ -117,6 +149,32 @@ m_NumTunnelsNonReplied++; UpdateTime (); } + + bool RouterProfile::IsLowPartcipationRate () const + { + return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate + } + + bool RouterProfile::IsLowReplyRate () const + { + auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined; + return m_NumTunnelsNonReplied > 10*(total + 1); + } + + bool RouterProfile::IsBad () + { + auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/; + if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1)) + { + // reset profile + m_NumTunnelsAgreed = 0; + m_NumTunnelsDeclined = 0; + m_NumTunnelsNonReplied = 0; + isBad = false; + } + if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++; + return isBad; + } std::shared_ptr GetRouterProfile (const IdentHash& identHash) { @@ -124,5 +182,32 @@ profile->Load (); // if possible return profile; } + + void DeleteObsoleteProfiles () + { + int num = 0; + auto ts = boost::posix_time::second_clock::local_time(); + boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY); + if (boost::filesystem::exists (p)) + { + boost::filesystem::directory_iterator end; + for (boost::filesystem::directory_iterator it (p); it != end; ++it) + { + if (boost::filesystem::is_directory (it->status())) + { + for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1) + { + auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ())); + if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT) + { + boost::filesystem::remove (it1->path ()); + num++; + } + } + } + } + } + LogPrint (eLogInfo, num, " obsolete profiles deleted"); + } } -} \ No newline at end of file +} diff -Nru i2pd-0.9.0/Profiling.h i2pd-0.10.0/Profiling.h --- i2pd-0.9.0/Profiling.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Profiling.h 2015-07-06 16:11:17.000000000 +0000 @@ -13,29 +13,40 @@ const char PEER_PROFILE_PREFIX[] = "profile-"; // sections const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; + const char PEER_PROFILE_SECTION_USAGE[] = "usage"; // params const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed"; const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined"; const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied"; + const char PEER_PROFILE_USAGE_TAKEN[] = "taken"; + const char PEER_PROFILE_USAGE_REJECTED[] = "rejected"; + + const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days) class RouterProfile { public: RouterProfile (const IdentHash& identHash); + RouterProfile& operator= (const RouterProfile& ) = default; void Save (); void Load (); - bool IsBad () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; + bool IsBad (); void TunnelBuildResponse (uint8_t ret); void TunnelNonReplied (); private: + boost::posix_time::ptime GetTime () const; void UpdateTime (); + + bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; + bool IsLowPartcipationRate () const; + bool IsLowReplyRate () const; private: @@ -45,9 +56,13 @@ uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsDeclined; uint32_t m_NumTunnelsNonReplied; + // usage + uint32_t m_NumTimesTaken; + uint32_t m_NumTimesRejected; }; std::shared_ptr GetRouterProfile (const IdentHash& identHash); + void DeleteObsoleteProfiles (); } } diff -Nru i2pd-0.9.0/Queue.h i2pd-0.10.0/Queue.h --- i2pd-0.9.0/Queue.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Queue.h 2015-07-06 16:11:17.000000000 +0000 @@ -17,14 +17,14 @@ { public: - void Put (Element * e) + void Put (Element e) { std::unique_lock l(m_QueueMutex); m_Queue.push (e); m_NonEmpty.notify_one (); } - void Put (const std::vector& vec) + void Put (const std::vector& vec) { if (!vec.empty ()) { @@ -35,10 +35,10 @@ } } - Element * GetNext () + Element GetNext () { std::unique_lock l(m_QueueMutex); - Element * el = GetNonThreadSafe (); + auto el = GetNonThreadSafe (); if (!el) { m_NonEmpty.wait (l); @@ -47,10 +47,10 @@ return el; } - Element * GetNextWithTimeout (int usec) + Element GetNextWithTimeout (int usec) { std::unique_lock l(m_QueueMutex); - Element * el = GetNonThreadSafe (); + auto el = GetNonThreadSafe (); if (!el) { m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec)); @@ -85,13 +85,13 @@ void WakeUp () { m_NonEmpty.notify_all (); }; - Element * Get () + Element Get () { std::unique_lock l(m_QueueMutex); return GetNonThreadSafe (); } - Element * Peek () + Element Peek () { std::unique_lock l(m_QueueMutex); return GetNonThreadSafe (true); @@ -99,11 +99,11 @@ private: - Element * GetNonThreadSafe (bool peek = false) + Element GetNonThreadSafe (bool peek = false) { if (!m_Queue.empty ()) { - Element * el = m_Queue.front (); + auto el = m_Queue.front (); if (!peek) m_Queue.pop (); return el; @@ -113,13 +113,13 @@ private: - std::queue m_Queue; + std::queue m_Queue; std::mutex m_QueueMutex; std::condition_variable m_NonEmpty; }; template - class MsgQueue: public Queue + class MsgQueue: public Queue { public: @@ -132,7 +132,7 @@ if (m_IsRunning) { m_IsRunning = false; - Queue::WakeUp (); + Queue::WakeUp (); m_Thread.join(); } } @@ -145,7 +145,7 @@ { while (m_IsRunning) { - while (Msg * msg = Queue::Get ()) + while (auto msg = Queue::Get ()) { msg->Process (); delete msg; @@ -153,7 +153,7 @@ if (m_OnEmpty != nullptr) m_OnEmpty (); if (m_IsRunning) - Queue::Wait (); + Queue::Wait (); } } diff -Nru i2pd-0.9.0/README.md i2pd-0.10.0/README.md --- i2pd-0.9.0/README.md 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/README.md 2015-07-06 16:11:17.000000000 +0000 @@ -9,6 +9,12 @@ This project is licensed under the BSD 3-clause license, which can be found in the file LICENSE in the root of the project source code. +Donations +--------- + +BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY +LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59 + Requirements for Linux/FreeBSD/OSX ---------------------------------- @@ -104,21 +110,34 @@ tunnels.cfg (filename of this config is subject of change): - ; outgoing tunnel, to remote service - [tunnel1] - type = client ; mandatory - port = ; mandatory, bind our side of tunnel to this local port - keys = ; optional - destination = ; mandatory - destinationport = ; optional, port of remote i2p service - - ; incoming tunnel, for local service(s) - [tunnel2] - type = server ; mandatory - host = ; mandatory, hostname of our i2p service - keys = ; mandatory, hostname keys - port = ; mandatory, forward incoming connections from i2p to this port - inport = ; optional, i2p service port - accesslist = [,] ; optional, comma-separated list of i2p idents, allowed to connect to service - -Note: '' type is a string like or + ; outgoing tunnel sample, to remote service + ; mandatory parameters: + ; * type -- always "client" + ; * port -- local port to listen to + ; * destination -- i2p hostname + ; optional parameters (may be omitted) + ; * keys -- our identity, if unset, will be generated on every startup, + ; if set and file missing, keys will be generated and placed to this file + [IRC] + type = client + port = 6668 + destination = irc.echelon.i2p + keys = irc-keys.dat + + ; incoming tunnel sample, for local service + ; mandatory parameters: + ; * type -- always "server" + ; * host -- ip address of our service + ; * port -- port of our service + ; * keys -- file with LeaseSet of address in i2p + ; optional parameters (may be omitted) + ; * inport -- optional, i2p service port, if unset - the same as 'port' + ; * accesslist -- comma-separated list of i2p addresses, allowed to connect + ; every address is b32 without '.b32.i2p' part + [LOCALSITE] + type = server + host = 127.0.0.1 + port = 80 + keys = site-keys.dat + inport = 81 + accesslist = [,] diff -Nru i2pd-0.9.0/Reseed.cpp i2pd-0.10.0/Reseed.cpp --- i2pd-0.9.0/Reseed.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Reseed.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -9,6 +9,8 @@ #include #include #include +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include #include "I2PEndian.h" #include "Reseed.h" #include "Log.h" @@ -24,22 +26,19 @@ { static std::vector httpReseedHostList = { - // "http://193.150.121.66/netDb/", // unstable - // "http://us.reseed.i2p2.no/", // misconfigured, not serving reseed data - // "http://jp.reseed.i2p2.no/", // Really outdated RIs "http://netdb.i2p2.no/", // only SU3 (v2) support - "http://i2p.mooo.com/netDb/", - "http://uk.reseed.i2p2.no/", - "http://i2p-netdb.innovatio.no/" + "http://i2p-netdb.innovatio.no/", + "http://193.150.121.66/netDb/" }; - //TODO: Remember to add custom port support. Not all serves on 443 static std::vector httpsReseedHostList = { // "https://193.150.121.66/netDb/", // unstable // "https://i2p-netdb.innovatio.no/",// Vuln to POODLE "https://netdb.i2p2.no/", // Only SU3 (v2) support "https://reseed.i2p-projekt.de/", // Only HTTPS - "https://cowpuncher.drollette.com/netdb/", // Only HTTPS and SU3 (v2) support -- will move to a new location + //"https://cowpuncher.drollette.com/netdb/", // returns error + "https://netdb.rows.io:444/", + "https://uk.reseed.i2p2.no:444/" // following hosts are fine but don't support AES256 /*"https://i2p.mooo.com/netDb/", "https://link.mx24.eu/", // Only HTTPS and SU3 (v2) support @@ -494,43 +493,160 @@ std::string Reseeder::HttpsRequest (const std::string& address) { i2p::util::http::url u(address); - TlsSession session (u.host_, 443); + if (u.port_ == 80) u.port_ = 443; + TlsSession session (u.host_, u.port_); - // send request - std::stringstream ss; - ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ - << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; - session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); - - // read response - std::stringstream rs; - while (session.Receive (rs)) - ; - return i2p::util::http::GetHttpContent (rs); + if (session.IsEstablished ()) + { + // send request + std::stringstream ss; + ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); + + // read response + std::stringstream rs; + while (session.Receive (rs)) + ; + return i2p::util::http::GetHttpContent (rs); + } + else + return ""; } +//------------------------------------------------------------- + + template + class TlsCipherMAC: public TlsCipher + { + public: + + TlsCipherMAC (const uint8_t * keys): m_Seqn (0) + { + memcpy (m_MacKey, keys, Hash::DIGESTSIZE); + } + + void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) + { + uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) + htobe64buf (header, m_Seqn); + header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 + htobe16buf (header + 11, len); + CryptoPP::HMAC hmac (m_MacKey, Hash::DIGESTSIZE); + hmac.Update (header, 13); + hmac.Update (buf, len); + hmac.Final (mac); + m_Seqn++; + } + + private: + + uint64_t m_Seqn; + uint8_t m_MacKey[Hash::DIGESTSIZE]; // client + }; + + template + class TlsCipher_AES_256_CBC: public TlsCipherMAC + { + public: + + TlsCipher_AES_256_CBC (const uint8_t * keys): TlsCipherMAC (keys) + { + m_Encryption.SetKey (keys + 2*Hash::DIGESTSIZE); + m_Decryption.SetKey (keys + 2*Hash::DIGESTSIZE + 32); + } + + size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) + { + size_t size = 0; + m_Rnd.GenerateBlock (out, 16); // iv + size += 16; + m_Encryption.SetIV (out); + memcpy (out + size, in, len); + size += len; + memcpy (out + size, mac, Hash::DIGESTSIZE); + size += Hash::DIGESTSIZE; + uint8_t paddingSize = size + 1; + paddingSize &= 0x0F; // %16 + if (paddingSize > 0) paddingSize = 16 - paddingSize; + memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size + size += paddingSize + 1; + m_Encryption.Encrypt (out + 16, size - 16, out + 16); + return size; + } + + size_t Decrypt (uint8_t * buf, size_t len) // payload is buf + 16 + { + m_Decryption.SetIV (buf); + m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); + return len - 16 - Hash::DIGESTSIZE - buf[len -1] - 1; // IV(16), mac(32 or 20) and padding + } + + size_t GetIVSize () const { return 16; }; + + private: + + CryptoPP::AutoSeededRandomPool m_Rnd; + i2p::crypto::CBCEncryption m_Encryption; + i2p::crypto::CBCDecryption m_Decryption; + }; + + + class TlsCipher_RC4_SHA: public TlsCipherMAC + { + public: + + TlsCipher_RC4_SHA (const uint8_t * keys): TlsCipherMAC (keys) + { + m_Encryption.SetKey (keys + 40, 16); // 20 + 20 + m_Decryption.SetKey (keys + 56, 16); // 20 + 20 + 16 + } + + size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) + { + memcpy (out, in, len); + memcpy (out + len, mac, 20); + m_Encryption.ProcessData (out, out, len + 20); + return len + 20; + } + + size_t Decrypt (uint8_t * buf, size_t len) + { + m_Decryption.ProcessData (buf, buf, len); + return len - 20; + } + + private: + + CryptoPP::Weak1::ARC4 m_Encryption, m_Decryption; + }; + + TlsSession::TlsSession (const std::string& host, int port): - m_Seqn (0) + m_IsEstablished (false), m_Cipher (nullptr) { m_Site.connect(host, boost::lexical_cast(port)); if (m_Site.good ()) - { Handshake (); - } else LogPrint (eLogError, "Can't connect to ", host, ":", port); } + TlsSession::~TlsSession () + { + delete m_Cipher; + } + void TlsSession::Handshake () { static uint8_t clientHello[] = { 0x16, // handshake 0x03, 0x03, // version (TLS 1.2) - 0x00, 0x2F, // length of handshake + 0x00, 0x33, // length of handshake // handshake 0x01, // handshake type (client hello) - 0x00, 0x00, 0x2B, // length of handshake payload + 0x00, 0x00, 0x2F, // length of handshake payload // client hello 0x03, 0x03, // highest version supported (TLS 1.2) 0x45, 0xFA, 0x01, 0x19, 0x74, 0x55, 0x18, 0x36, @@ -538,8 +654,10 @@ 0xEC, 0x37, 0x11, 0x93, 0x16, 0xF4, 0x66, 0x00, 0x12, 0x67, 0xAB, 0xBA, 0xFF, 0x29, 0x13, 0x9E, // 32 random bytes 0x00, // session id length - 0x00, 0x02, // chiper suites length + 0x00, 0x06, // chiper suites length 0x00, 0x3D, // RSA_WITH_AES_256_CBC_SHA256 + 0x00, 0x35, // RSA_WITH_AES_256_CBC_SHA + 0x00, 0x05, // RSA_WITH_RC4_128_SHA 0x01, // compression methods length 0x00, // no compression 0x00, 0x00 // extensions length @@ -552,18 +670,6 @@ 0x00, 0x01, // length 0x01 // type }; - - static uint8_t finished[] = - { - 0x16, // handshake - 0x03, 0x03, // version (TLS 1.2) - 0x00, 0x50, // length of handshake (80 bytes) - // handshake (encrypted) - // unencrypted context - // 0x14 handshake type (finished) - // 0x00, 0x00, 0x0C length of handshake payload - // 12 bytes of verified data - }; // send ClientHello m_Site.write ((char *)clientHello, sizeof (clientHello)); @@ -584,7 +690,12 @@ memcpy (serverRandom, serverHello + 6, 32); else LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); - delete[] serverHello; + uint8_t sessionIDLen = serverHello[38]; // 6 + 32 + char * cipherSuite = serverHello + 39 + sessionIDLen; + if (cipherSuite[1] == 0x3D || cipherSuite[1] == 0x35 || cipherSuite[1] == 0x05) + m_IsEstablished = true; + else + LogPrint (eLogError, "Unsupported cipher ", (int)cipherSuite[0], ",", (int)cipherSuite[1]); // read Certificate m_Site.read ((char *)&type, 1); m_Site.read ((char *)&version, 2); @@ -602,7 +713,6 @@ publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); else LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); - delete[] certificate; // read ServerHelloDone m_Site.read ((char *)&type, 1); m_Site.read ((char *)&version, 2); @@ -613,18 +723,18 @@ m_FinishedHash.Update ((uint8_t *)serverHelloDone, length); if (serverHelloDone[0] != 0x0E) // handshake type hello done LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); - delete[] serverHelloDone; // our turn now // generate secret key uint8_t secret[48]; secret[0] = 3; secret[1] = 3; // version - m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes + CryptoPP::AutoSeededRandomPool rnd; + rnd.GenerateBlock (secret + 2, 46); // 46 random bytes // encrypt RSA CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key) uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length htobe16buf (encrypted, encryptedLen); // first two bytes means length - encryptor.Encrypt (m_Rnd, secret, 48, encrypted + 2); + encryptor.Encrypt (rnd, secret, 48, encrypted + 2); // send ClientKeyExchange // 0x10 - handshake type "client key exchange" SendHandshakeMsg (0x10, encrypted, encryptedLen + 2); @@ -632,30 +742,35 @@ // send ChangeCipherSpecs m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); // calculate master secret - uint8_t masterSecret[48], random[64]; + uint8_t random[64]; memcpy (random, clientHello + 11, 32); memcpy (random + 32, serverRandom, 32); - PRF (secret, "master secret", random, 64, 48, masterSecret); - // expand master secret - uint8_t keys[128]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32) + PRF (secret, "master secret", random, 64, 48, m_MasterSecret); + // create keys memcpy (random, serverRandom, 32); - memcpy (random + 32, clientHello + 11, 32); - PRF (masterSecret, "key expansion", random, 64, 128, keys); - memcpy (m_MacKey, keys, 32); - m_Encryption.SetKey (keys + 64); - m_Decryption.SetKey (keys + 96); - + memcpy (random + 32, clientHello + 11, 32); + uint8_t keys[128]; // clientMACKey(32 or 20), serverMACKey(32 or 20), clientKey(32), serverKey(32) + PRF (m_MasterSecret, "key expansion", random, 64, 128, keys); + // create cipher + if (cipherSuite[1] == 0x3D) + { + LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA256"); + m_Cipher = new TlsCipher_AES_256_CBC (keys); + } + else if (cipherSuite[1] == 0x35) + { + LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA"); + m_Cipher = new TlsCipher_AES_256_CBC (keys); + } + else + { + // TODO: + if (cipherSuite[1] == 0x05) + LogPrint (eLogInfo, "Chiper suite is RSA_WITH_RC4_128_SHA"); + m_Cipher = new TlsCipher_RC4_SHA (keys); + } // send finished - uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; - finishedPayload[0] = 0x14; // handshake type (finished) - finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes - m_FinishedHash.Final (finishedHashDigest); - PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); - uint8_t mac[32]; - CalculateMAC (0x16, finishedPayload, 16, mac); - Encrypt (finishedPayload, 16, mac, encryptedPayload); - m_Site.write ((char *)finished, sizeof (finished)); - m_Site.write ((char *)encryptedPayload, 80); + SendFinishedMsg (); // read ChangeCipherSpecs uint8_t changeCipherSpecs1[6]; m_Site.read ((char *)changeCipherSpecs1, 6); @@ -666,7 +781,12 @@ length = be16toh (length); char * finished1 = new char[length]; m_Site.read (finished1, length); + m_Cipher->Decrypt ((uint8_t *)finished1, length); // for streaming ciphers delete[] finished1; + + delete[] serverHello; + delete[] certificate; + delete[] serverHelloDone; } void TlsSession::SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len) @@ -685,6 +805,33 @@ m_FinishedHash.Update (data, len); } + void TlsSession::SendFinishedMsg () + { + // 0x16 handshake + // 0x03, 0x03 version (TLS 1.2) + // 2 bytes length of handshake (80 or 64 bytes) + // handshake (encrypted) + // unencrypted context + // 0x14 handshake type (finished) + // 0x00, 0x00, 0x0C length of handshake payload + // 12 bytes of verified data + + uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; + finishedPayload[0] = 0x14; // handshake type (finished) + finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes + m_FinishedHash.Final (finishedHashDigest); + PRF (m_MasterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); + uint8_t mac[32]; + m_Cipher->CalculateMAC (0x16, finishedPayload, 16, mac); + size_t encryptedPayloadSize = m_Cipher->Encrypt (finishedPayload, 16, mac, encryptedPayload); + uint8_t finished[5]; + finished[0] = 0x16; // handshake + finished[1] = 0x03; finished[2] = 0x03; // version is always TLS 1.2 (3,3) + htobe16buf (finished + 3, encryptedPayloadSize); // length of payload + m_Site.write ((char *)finished, sizeof (finished)); + m_Site.write ((char *)encryptedPayload, encryptedPayloadSize); + } + void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, size_t len, uint8_t * buf) { @@ -709,45 +856,6 @@ } } - size_t TlsSession::Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) - { - size_t size = 0; - m_Rnd.GenerateBlock (out, 16); // iv - size += 16; - m_Encryption.SetIV (out); - memcpy (out + size, in, len); - size += len; - memcpy (out + size, mac, 32); - size += 32; - uint8_t paddingSize = len + 1; - paddingSize &= 0x0F; // %16 - if (paddingSize > 0) paddingSize = 16 - paddingSize; - memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size - size += paddingSize + 1; - m_Encryption.Encrypt (out + 16, size - 16, out + 16); - return size; - } - - size_t TlsSession::Decrypt (uint8_t * buf, size_t len) - { - m_Decryption.SetIV (buf); - m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); - return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding - } - - void TlsSession::CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) - { - uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) - htobe64buf (header, m_Seqn); - header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 - htobe16buf (header + 11, len); - CryptoPP::HMAC hmac (m_MacKey, 32); - hmac.Update (header, 13); - hmac.Update (buf, len); - hmac.Final (mac); - m_Seqn++; - } - CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) { CryptoPP::ByteQueue queue; @@ -797,8 +905,8 @@ out[0] = 0x17; // application data out[1] = 0x03; out[2] = 0x03; // version uint8_t mac[32]; - CalculateMAC (0x17, buf, len, mac); - size_t encryptedLen = Encrypt (buf, len, mac, out + 5); + m_Cipher->CalculateMAC (0x17, buf, len, mac); + size_t encryptedLen = m_Cipher->Encrypt (buf, len, mac, out + 5); htobe16buf (out + 3, encryptedLen); m_Site.write ((char *)out, encryptedLen + 5); delete[] out; @@ -814,8 +922,8 @@ length = be16toh (length); uint8_t * buf = new uint8_t[length]; m_Site.read ((char *)buf, length); - size_t decryptedLen = Decrypt (buf, length); - rs.write ((char *)buf + 16, decryptedLen); + size_t decryptedLen = m_Cipher->Decrypt (buf, length); + rs.write ((char *)buf + m_Cipher->GetIVSize (), decryptedLen); delete[] buf; return true; } diff -Nru i2pd-0.9.0/Reseed.h i2pd-0.10.0/Reseed.h --- i2pd-0.9.0/Reseed.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Reseed.h 2015-07-06 16:11:17.000000000 +0000 @@ -47,34 +47,47 @@ std::map m_SigningKeys; }; + + class TlsCipher + { + public: + + virtual ~TlsCipher () {}; + + virtual void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) = 0; + virtual size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) = 0; + virtual size_t Decrypt (uint8_t * buf, size_t len) = 0; + virtual size_t GetIVSize () const { return 0; }; // override for AES + }; + + class TlsSession { public: TlsSession (const std::string& host, int port); + ~TlsSession (); void Send (const uint8_t * buf, size_t len); bool Receive (std::ostream& rs); - + bool IsEstablished () const { return m_IsEstablished; }; + private: void Handshake (); void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len); + void SendFinishedMsg (); CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); + void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, size_t len, uint8_t * buf); - void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac); - size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out); - size_t Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16 private: - uint64_t m_Seqn; + bool m_IsEstablished; boost::asio::ip::tcp::iostream m_Site; CryptoPP::SHA256 m_FinishedHash; - CryptoPP::AutoSeededRandomPool m_Rnd; - i2p::crypto::CBCEncryption m_Encryption; - i2p::crypto::CBCDecryption m_Decryption; - uint8_t m_MacKey[32]; // client + uint8_t m_MasterSecret[64]; // actual size is 48, but must be multiple of 32 + TlsCipher * m_Cipher; }; } } diff -Nru i2pd-0.9.0/RouterContext.cpp i2pd-0.10.0/RouterContext.cpp --- i2pd-0.9.0/RouterContext.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/RouterContext.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -289,11 +289,28 @@ fk.write ((char *)&keys, sizeof (keys)); } + std::shared_ptr RouterContext::GetTunnelPool () const + { + return i2p::tunnel::tunnels.GetExploratoryPool (); + } + void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); } + void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) + { + std::unique_lock l(m_GarlicMutex); + i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); + } + + void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) + { + std::unique_lock l(m_GarlicMutex); + i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); + } + uint32_t RouterContext::GetUptime () const { return i2p::util::GetSecondsSinceEpoch () - m_StartupTime; diff -Nru i2pd-0.9.0/RouterContext.h i2pd-0.10.0/RouterContext.h --- i2pd-0.9.0/RouterContext.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/RouterContext.h 2015-07-06 16:11:17.000000000 +0000 @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -72,8 +73,13 @@ void SetLeaseSetUpdated () {}; // implements GarlicDestination - const i2p::data::LeaseSet * GetLeaseSet () { return nullptr; }; + std::shared_ptr GetLeaseSet () { return nullptr; }; + std::shared_ptr GetTunnelPool () const; void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); + + // override GarlicDestination + void ProcessGarlicMessage (std::shared_ptr msg); + void ProcessDeliveryStatusMessage (std::shared_ptr msg); private: @@ -92,6 +98,7 @@ bool m_AcceptsTunnels, m_IsFloodfill; uint64_t m_StartupTime; // in seconds since epoch RouterStatus m_Status; + std::mutex m_GarlicMutex; }; extern RouterContext context; diff -Nru i2pd-0.9.0/RouterInfo.cpp i2pd-0.10.0/RouterInfo.cpp --- i2pd-0.9.0/RouterInfo.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/RouterInfo.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -36,7 +36,7 @@ RouterInfo::~RouterInfo () { - delete m_Buffer; + delete[] m_Buffer; } void RouterInfo::Update (const uint8_t * buf, int len) @@ -447,10 +447,13 @@ if (m_Buffer) { std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); - f.write ((char *)m_Buffer, m_BufferLen); - } + if (f.is_open ()) + f.write ((char *)m_Buffer, m_BufferLen); + else + LogPrint(eLogError, "Can't save RouterInfo to ", fullPath); + } else - LogPrint (eLogError, "Can't save to file"); + LogPrint (eLogError, "Can't save RouterInfo m_Buffer==NULL"); } size_t RouterInfo::ReadString (char * str, std::istream& s) diff -Nru i2pd-0.9.0/RouterInfo.h i2pd-0.10.0/RouterInfo.h --- i2pd-0.9.0/RouterInfo.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/RouterInfo.h 2015-07-06 16:11:17.000000000 +0000 @@ -142,7 +142,7 @@ void SaveProfile () { if (m_Profile) m_Profile->Save (); }; void Update (const uint8_t * buf, int len); - void DeleteBuffer () { delete m_Buffer; m_Buffer = nullptr; }; + void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; // implements RoutingDestination const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); }; diff -Nru i2pd-0.9.0/SAM.cpp i2pd-0.10.0/SAM.cpp --- i2pd-0.9.0/SAM.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SAM.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -85,6 +85,9 @@ else { m_Buffer[bytes_transferred] = 0; + char * eol = (char *)memchr (m_Buffer, '\n', bytes_transferred); + if (eol) + *eol = 0; LogPrint ("SAM handshake ", m_Buffer); char * separator = strchr (m_Buffer, ' '); if (separator) @@ -340,19 +343,24 @@ if (m_Session) { i2p::data::IdentityEx dest; - dest.FromBase64 (destination); - context.GetAddressBook ().InsertAddress (dest); - auto leaseSet = m_Session->localDestination->FindLeaseSet (dest.GetIdentHash ()); - if (leaseSet) - Connect (leaseSet); - else + size_t len = dest.FromBase64(destination); + if (len > 0) { - m_Session->localDestination->RequestDestination (dest.GetIdentHash (), - std::bind (&SAMSocket::HandleConnectLeaseSetRequestComplete, - shared_from_this (), std::placeholders::_1, dest.GetIdentHash ())); + context.GetAddressBook().InsertAddress(dest); + auto leaseSet = m_Session->localDestination->FindLeaseSet(dest.GetIdentHash()); + if (leaseSet) + Connect(leaseSet); + else + { + m_Session->localDestination->RequestDestination(dest.GetIdentHash(), + std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, + shared_from_this(), std::placeholders::_1)); + } } + else + SendMessageReply(SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), true); } - else + else SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); } @@ -366,11 +374,8 @@ SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); } - void SAMSocket::HandleConnectLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident) + void SAMSocket::HandleConnectLeaseSetRequestComplete (std::shared_ptr leaseSet) { - std::shared_ptr leaseSet; - if (success) - leaseSet = m_Session->localDestination->FindLeaseSet (ident); if (leaseSet) Connect (leaseSet); else @@ -486,11 +491,8 @@ } } - void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident) + void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, i2p::data::IdentHash ident) { - std::shared_ptr leaseSet; - if (success) - leaseSet = m_Session->localDestination->FindLeaseSet (ident); if (leaseSet) { context.GetAddressBook ().InsertAddress (leaseSet->GetIdentity ()); @@ -564,8 +566,17 @@ else { if (m_Stream) - m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred); - Receive (); + { + auto s = shared_from_this (); + m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred, + [s](const boost::system::error_code& ecode) + { + if (!ecode) + s->Receive (); + else + s->Terminate (); + }); + } } } diff -Nru i2pd-0.9.0/SAM.h i2pd-0.10.0/SAM.h --- i2pd-0.9.0/SAM.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SAM.h 2015-07-06 16:11:17.000000000 +0000 @@ -28,6 +28,7 @@ const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n"; const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n"; const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n"; + const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n"; const char SAM_STREAM_CONNECT[] = "STREAM CONNECT"; const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n"; const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n"; @@ -109,9 +110,9 @@ void ExtractParams (char * buf, std::map& params); void Connect (std::shared_ptr remote); - void HandleConnectLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident); + void HandleConnectLeaseSetRequestComplete (std::shared_ptr leaseSet); void SendNamingLookupReply (const i2p::data::IdentityEx& identity); - void HandleNamingLookupLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident); + void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, i2p::data::IdentHash ident); void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode); void SendSessionCreateReplyOk (); diff -Nru i2pd-0.9.0/Signature.cpp i2pd-0.10.0/Signature.cpp --- i2pd-0.9.0/Signature.cpp 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/Signature.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,121 @@ +#include +#include +#include +#include "Log.h" +#include "Signature.h" + +namespace i2p +{ +namespace crypto +{ + class Ed25519 + { + public: + + Ed25519 () + { + q = CryptoPP::Integer::Power2 (255) - CryptoPP::Integer (19); // 2^255-19 + l = CryptoPP::Integer::Power2 (252) + CryptoPP::Integer ("27742317777372353535851937790883648493"); + // 2^252 + 27742317777372353535851937790883648493 + d = CryptoPP::Integer (-121665) * CryptoPP::Integer (121666).InverseMod (q); // -121665/121666 + I = a_exp_b_mod_c (CryptoPP::Integer::Two (), (q - CryptoPP::Integer::One ()).DividedBy (4), q); + B = DecodePoint (CryptoPP::Integer (4)*CryptoPP::Integer (5).InverseMod (q)); + } + + CryptoPP::ECP::Point DecodePublicKey (const uint8_t * key) const + { + return DecodePoint (CryptoPP::Integer (key, 32)); + } + + CryptoPP::ECP::Point GeneratePublicKey (const uint8_t * privateKey) const + { + return Mul (B, CryptoPP::Integer (privateKey, 32)); + } + + private: + + CryptoPP::ECP::Point Sum (const CryptoPP::ECP::Point& p1, const CryptoPP::ECP::Point& p2) const + { + CryptoPP::Integer m = d*p1.x*p2.x*p1.y*p2.y, + x = a_times_b_mod_c (p1.x*p2.y + p2.x*p1.y, (CryptoPP::Integer::One() + m).InverseMod (q), q), + y = a_times_b_mod_c (p1.y*p2.y + p1.x*p2.x, (CryptoPP::Integer::One() - m).InverseMod (q), q); + return CryptoPP::ECP::Point {x, y}; + } + + CryptoPP::ECP::Point Mul (const CryptoPP::ECP::Point& p, const CryptoPP::Integer& e) const + { + CryptoPP::ECP::Point res {0, 1}; + if (!e.IsZero ()) + { + auto bitCount = e.BitCount (); + for (int i = bitCount - 1; i >= 0; i--) + { + res = Sum (res, res); + if (e.GetBit (i)) res = Sum (res, p); + } + } + return res; + } + + bool IsOnCurve (const CryptoPP::ECP::Point& p) const + { + auto x2 = p.x.Squared(), y2 = p.y.Squared (); + return (y2 - x2 - CryptoPP::Integer::One() - d*x2*y2).Modulo (q).IsZero (); + } + + CryptoPP::Integer RecoverX (const CryptoPP::Integer& y) const + { + auto y2 = y.Squared (); + auto xx = (y2 - CryptoPP::Integer::One())*(d*y2 + CryptoPP::Integer::One()).InverseMod (q); + auto x = a_exp_b_mod_c (xx, (q + CryptoPP::Integer (3)).DividedBy (8), q); + if (!(x.Squared () - xx).Modulo (q).IsZero ()) + x = a_times_b_mod_c (x, I, q); + if (x.IsOdd ()) x = q - x; + return x; + } + + CryptoPP::ECP::Point DecodePoint (const CryptoPP::Integer& y) const + { + auto x = RecoverX (y); + CryptoPP::ECP::Point p {x, y}; + if (!IsOnCurve (p)) + { + LogPrint (eLogError, "Decoded point is not on 25519"); + return CryptoPP::ECP::Point {0, 1}; + } + return p; + } + + private: + + CryptoPP::Integer q, l, d, I; + CryptoPP::ECP::Point B; // base point + }; + + static std::unique_ptr g_Ed25519; + std::unique_ptr& GetEd25519 () + { + if (!g_Ed25519) + g_Ed25519.reset (new Ed25519 ()); + return g_Ed25519; + } + + + EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey): + m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey)) + { + } + + bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + return true; // TODO: + } + + void EDDSA25519Signer::Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const + { + // TODO + } +} +} + + diff -Nru i2pd-0.9.0/Signature.h i2pd-0.10.0/Signature.h --- i2pd-0.9.0/Signature.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Signature.h 2015-07-06 16:11:17.000000000 +0000 @@ -410,6 +410,34 @@ { } }; + + // EdDSA + const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; + const size_t EDDSA25519_SIGNATURE_LENGTH = 64; + const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; + class EDDSA25519Verifier: public Verifier + { + public: + + EDDSA25519Verifier (const uint8_t * signingKey); + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + + size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; }; + size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; }; + + private: + + CryptoPP::ECP::Point m_PublicKey; + }; + + class EDDSA25519Signer: public Signer + { + public: + + EDDSA25519Signer (const uint8_t * signingPrivateKey) {}; + + void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const; + }; } } diff -Nru i2pd-0.9.0/SOCKS.cpp i2pd-0.10.0/SOCKS.cpp --- i2pd-0.9.0/SOCKS.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SOCKS.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -118,7 +118,7 @@ void HandleStreamRequestComplete (std::shared_ptr stream); uint8_t m_sock_buff[socks_buffer_size]; - boost::asio::ip::tcp::socket * m_sock; + std::shared_ptr m_sock; std::shared_ptr m_stream; uint8_t *m_remaining_data; //Data left to be sent uint8_t m_response[7+max_socks_hostname_size]; @@ -135,7 +135,7 @@ state m_state; public: - SOCKSHandler(SOCKSServer * parent, boost::asio::ip::tcp::socket * sock) : + SOCKSHandler(SOCKSServer * parent, std::shared_ptr sock) : I2PServiceHandler(parent), m_sock(sock), m_stream(nullptr), m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4) { m_address.ip = 0; EnterState(GET_SOCKSV); } @@ -161,7 +161,6 @@ { LogPrint(eLogDebug,"--- SOCKS close sock"); m_sock->close(); - delete m_sock; m_sock = nullptr; } if (m_stream) @@ -566,7 +565,7 @@ { } - std::shared_ptr SOCKSServer::CreateHandler(boost::asio::ip::tcp::socket * socket) + std::shared_ptr SOCKSServer::CreateHandler(std::shared_ptr socket) { return std::make_shared (this, socket); } diff -Nru i2pd-0.9.0/SOCKS.h i2pd-0.10.0/SOCKS.h --- i2pd-0.9.0/SOCKS.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SOCKS.h 2015-07-06 16:11:17.000000000 +0000 @@ -20,7 +20,7 @@ protected: // Implements TCPIPAcceptor - std::shared_ptr CreateHandler(boost::asio::ip::tcp::socket * socket); + std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "SOCKS"; } }; diff -Nru i2pd-0.9.0/SSU.cpp i2pd-0.10.0/SSU.cpp --- i2pd-0.9.0/SSU.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SSU.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -217,24 +217,33 @@ for (auto it1: packets) { auto packet = it1; - if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous - { - if (session) session->FlushData (); - auto it = m_Sessions.find (packet->from); - if (it != m_Sessions.end ()) - session = it->second; - if (!session) + try + { + if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous { - session = std::make_shared (*this, packet->from); - session->WaitForConnect (); + if (session) session->FlushData (); + auto it = m_Sessions.find (packet->from); + if (it != m_Sessions.end ()) + session = it->second; + if (!session) { - std::unique_lock l(m_SessionsMutex); - m_Sessions[packet->from] = session; - } - LogPrint ("New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); + session = std::make_shared (*this, packet->from); + session->WaitForConnect (); + { + std::unique_lock l(m_SessionsMutex); + m_Sessions[packet->from] = session; + } + LogPrint (eLogInfo, "New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); + } } - } - session->ProcessNextMessage (packet->buf, packet->len, packet->from); + session->ProcessNextMessage (packet->buf, packet->len, packet->from); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ()); + if (session) session->FlushData (); + session = nullptr; + } delete packet; } if (session) session->FlushData (); diff -Nru i2pd-0.9.0/SSUData.cpp i2pd-0.10.0/SSUData.cpp --- i2pd-0.9.0/SSUData.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SSUData.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -15,9 +15,8 @@ if (msg->len + fragmentSize > msg->maxLen) { LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough"); - I2NPMessage * newMsg = NewI2NPMessage (); + auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ()); *newMsg = *msg; - DeleteI2NPMessage (msg); msg = newMsg; } memcpy (msg->buf + msg->len, fragment, fragmentSize); @@ -174,7 +173,7 @@ if (it == m_IncompleteMessages.end ()) { // create new message - auto msg = NewI2NPShortMessage (); + auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ()); msg->len -= I2NP_SHORT_HEADER_SIZE; it = m_IncompleteMessages.insert (std::make_pair (msgID, std::unique_ptr(new IncompleteMessage (msg)))).first; @@ -244,10 +243,7 @@ m_Handler.PutNextMessage (msg); } else - { LogPrint (eLogWarning, "SSU message ", msgID, " already received"); - i2p::DeleteI2NPMessage (msg); - } } else { @@ -259,7 +255,6 @@ } else LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ()); - DeleteI2NPMessage (msg); } } else @@ -294,13 +289,12 @@ ProcessFragments (buf); } - void SSUData::Send (i2p::I2NPMessage * msg) + void SSUData::Send (std::shared_ptr msg) { uint32_t msgID = msg->ToSSU (); if (m_SentMessages.count (msgID) > 0) { LogPrint (eLogWarning, "SSU message ", msgID, " already sent"); - DeleteI2NPMessage (msg); return; } if (m_SentMessages.empty ()) // schedule resend at first message only @@ -368,7 +362,6 @@ len = 0; fragmentNum++; } - DeleteI2NPMessage (msg); } void SSUData::SendMsgAck (uint32_t msgID) diff -Nru i2pd-0.9.0/SSUData.h i2pd-0.10.0/SSUData.h --- i2pd-0.9.0/SSUData.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SSUData.h 2015-07-06 16:11:17.000000000 +0000 @@ -59,13 +59,12 @@ struct IncompleteMessage { - I2NPMessage * msg; + std::shared_ptr msg; int nextFragmentNum; uint32_t lastFragmentInsertTime; // in seconds std::set, FragmentCmp> savedFragments; - IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; - ~IncompleteMessage () { if (msg) DeleteI2NPMessage (msg); }; + IncompleteMessage (std::shared_ptr m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); }; @@ -89,7 +88,7 @@ void ProcessMessage (uint8_t * buf, size_t len); void FlushReceivedMessage (); - void Send (i2p::I2NPMessage * msg); + void Send (std::shared_ptr msg); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); diff -Nru i2pd-0.9.0/SSUSession.cpp i2pd-0.10.0/SSUSession.cpp --- i2pd-0.9.0/SSUSession.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SSUSession.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -783,7 +783,7 @@ m_DHKeysPair = nullptr; } m_Data.Start (); - m_Data.Send (CreateDatabaseStoreMsg ()); + m_Data.Send (ToSharedI2NPMessage(CreateDatabaseStoreMsg ())); transports.PeerConnected (shared_from_this ()); if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ())) SendPeerTest (); @@ -832,39 +832,18 @@ } } - void SSUSession::SendI2NPMessage (I2NPMessage * msg) - { - GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg)); - } - - void SSUSession::PostI2NPMessage (I2NPMessage * msg) - { - if (msg) - { - if (m_State == eSessionStateEstablished) - m_Data.Send (msg); - else - DeleteI2NPMessage (msg); - } - } - - void SSUSession::SendI2NPMessages (const std::vector& msgs) + void SSUSession::SendI2NPMessages (const std::vector >& msgs) { GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs)); } - void SSUSession::PostI2NPMessages (std::vector msgs) + void SSUSession::PostI2NPMessages (std::vector > msgs) { if (m_State == eSessionStateEstablished) { for (auto it: msgs) if (it) m_Data.Send (it); } - else - { - for (auto it: msgs) - DeleteI2NPMessage (it); - } } void SSUSession::ProcessData (uint8_t * buf, size_t len) diff -Nru i2pd-0.9.0/SSUSession.h i2pd-0.10.0/SSUSession.h --- i2pd-0.9.0/SSUSession.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/SSUSession.h 2015-07-06 16:11:17.000000000 +0000 @@ -76,8 +76,7 @@ void Done (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; - void SendI2NPMessage (I2NPMessage * msg); - void SendI2NPMessages (const std::vector& msgs); + void SendI2NPMessages (const std::vector >& msgs); void SendPeerTest (); // Alice SessionState GetState () const { return m_State; }; @@ -95,8 +94,7 @@ boost::asio::io_service& GetService (); void CreateAESandMacKey (const uint8_t * pubKey); - void PostI2NPMessage (I2NPMessage * msg); - void PostI2NPMessages (std::vector msgs); + void PostI2NPMessages (std::vector > msgs); void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); diff -Nru i2pd-0.9.0/stdafx.cpp i2pd-0.10.0/stdafx.cpp --- i2pd-0.9.0/stdafx.cpp 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/stdafx.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1 @@ +#include "stdafx.h" diff -Nru i2pd-0.9.0/stdafx.h i2pd-0.10.0/stdafx.h --- i2pd-0.9.0/stdafx.h 1970-01-01 00:00:00.000000000 +0000 +++ i2pd-0.10.0/stdafx.h 2015-07-06 16:11:17.000000000 +0000 @@ -0,0 +1,67 @@ +#ifndef STDAFX_H__ +#define STDAFX_H__ + +#include +#include +#include +#include +#include + +#include // TODO: replace with cstring and std:: through out +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff -Nru i2pd-0.9.0/Streaming.cpp i2pd-0.10.0/Streaming.cpp --- i2pd-0.9.0/Streaming.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Streaming.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -22,7 +22,7 @@ { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); m_RemoteIdentity = remote->GetIdentity (); - UpdateCurrentRemoteLease (); + m_CurrentRemoteLease.endDate = 0; } Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): @@ -61,6 +61,12 @@ m_AckSendTimer.cancel (); m_ReceiveTimer.cancel (); m_ResendTimer.cancel (); + if (m_SendHandler) + { + auto handler = m_SendHandler; + m_SendHandler = nullptr; + handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); + } } void Stream::HandleNextPacket (Packet * packet) @@ -217,9 +223,9 @@ m_LastReceivedSequenceNumber = receivedSeqn; - if (flags & PACKET_FLAG_CLOSE) + if (flags & (PACKET_FLAG_CLOSE | PACKET_FLAG_RESET)) { - LogPrint (eLogInfo, "Closed"); + LogPrint (eLogInfo, (flags & PACKET_FLAG_RESET) ? "Reset" : "Closed"); m_Status = eStreamStatusReset; Close (); } @@ -299,6 +305,15 @@ return len; } + void Stream::AsyncSend (const uint8_t * buf, size_t len, SendHandler handler) + { + if (m_SendHandler) + handler (boost::asio::error::make_error_code (boost::asio::error::in_progress)); + else + m_SendHandler = handler; + Send (buf, len); + } + void Stream::SendBuffer () { int numMsgs = m_WindowSize - m_SentPackets.size (); @@ -367,6 +382,11 @@ packets.push_back (p); numMsgs--; } + if (m_SendBuffer.eof () && m_SendHandler) + { + m_SendHandler (boost::system::error_code ()); + m_SendHandler = nullptr; + } } if (packets.size () > 0) { @@ -467,7 +487,7 @@ LogPrint (eLogInfo, "Trying to send stream data before closing"); break; case eStreamStatusReset: - SendClose (); + SendClose (); Terminate (); m_LocalDestination.DeleteStream (shared_from_this ()); break; @@ -577,7 +597,7 @@ } } if (!m_CurrentOutboundTunnel || !m_CurrentOutboundTunnel->IsEstablished ()) - m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNextOutboundTunnel (); + m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); if (!m_CurrentOutboundTunnel) { LogPrint (eLogError, "No outbound tunnels in the pool"); @@ -586,7 +606,7 @@ auto ts = i2p::util::GetMillisecondsSinceEpoch (); if (ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000) - UpdateCurrentRemoteLease (); + UpdateCurrentRemoteLease (true); if (ts < m_CurrentRemoteLease.endDate) { std::vector msgs; @@ -645,6 +665,7 @@ if (packets.size () > 0) { m_NumResendAttempts++; + m_RTO *= 2; switch (m_NumResendAttempts) { case 1: // congesion avoidance @@ -652,9 +673,10 @@ if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; break; case 2: + m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time + // no break here case 4: UpdateCurrentRemoteLease (); // pick another lease - m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change LogPrint (eLogWarning, "Another remote lease has been selected for stream"); break; case 3: @@ -687,7 +709,7 @@ } } - void Stream::UpdateCurrentRemoteLease () + void Stream::UpdateCurrentRemoteLease (bool expired) { if (!m_RemoteLeaseSet) { @@ -702,16 +724,31 @@ auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); // try without threshold first if (leases.empty ()) { + expired = false; m_LocalDestination.GetOwner ().RequestDestination (m_RemoteIdentity.GetIdentHash ()); // time to re-request leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold } if (!leases.empty ()) { - uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); - if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID) - // make sure we don't select previous - i = (i + 1) % leases.size (); // if so, pick next - m_CurrentRemoteLease = leases[i]; + bool updated = false; + if (expired) + { + for (auto it: leases) + if ((it.tunnelGateway == m_CurrentRemoteLease.tunnelGateway) && (it.tunnelID != m_CurrentRemoteLease.tunnelID)) + { + m_CurrentRemoteLease = it; + updated = true; + break; + } + } + if (!updated) + { + uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); + if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID) + // make sure we don't select previous + i = (i + 1) % leases.size (); // if so, pick next + m_CurrentRemoteLease = leases[i]; + } } else { @@ -724,9 +761,9 @@ m_CurrentRemoteLease.endDate = 0; } - I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len) + std::shared_ptr Stream::CreateDataMessage (const uint8_t * payload, size_t len) { - I2NPMessage * msg = NewI2NPShortMessage (); + auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ()); CryptoPP::Gzip compressor; if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL); @@ -743,7 +780,7 @@ htobe16buf (buf + 6, m_Port); // destination port buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol msg->len += size + 4; - FillI2NPMessageHeader (msg, eI2NPData); + msg->FillI2NPMessageHeader (eI2NPData); return msg; } diff -Nru i2pd-0.9.0/Streaming.h i2pd-0.10.0/Streaming.h --- i2pd-0.9.0/Streaming.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Streaming.h 2015-07-06 16:11:17.000000000 +0000 @@ -85,7 +85,7 @@ enum StreamStatus { - eStreamStatusNew, + eStreamStatusNew = 0, eStreamStatusOpen, eStreamStatusReset, eStreamStatusClosing, @@ -97,6 +97,8 @@ { public: + typedef std::function SendHandler; + Stream (boost::asio::io_service& service, StreamingDestination& local, std::shared_ptr remote, int port = 0); // outgoing Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming @@ -106,12 +108,14 @@ uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; std::shared_ptr GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; }; - bool IsOpen () const { return m_Status == eStreamStatusOpen; }; + bool IsOpen () const { return m_Status == eStreamStatusOpen; }; bool IsEstablished () const { return m_SendStreamID; }; + StreamStatus GetStatus () const { return m_Status; }; StreamingDestination& GetLocalDestination () { return m_LocalDestination; }; void HandleNextPacket (Packet * packet); size_t Send (const uint8_t * buf, size_t len); + void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler); template void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); @@ -143,7 +147,7 @@ void ProcessAck (Packet * packet); size_t ConcatenatePackets (uint8_t * buf, size_t len); - void UpdateCurrentRemoteLease (); + void UpdateCurrentRemoteLease (bool expired = false); template void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler); @@ -152,7 +156,7 @@ void HandleResendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode); - I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len); + std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len); private: @@ -179,6 +183,7 @@ int m_WindowSize, m_RTT, m_RTO; uint64_t m_LastWindowSizeIncreaseTime; int m_NumResendAttempts; + SendHandler m_SendHandler; }; class StreamingDestination @@ -228,20 +233,18 @@ template void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout) { - if (!m_ReceiveQueue.empty ()) - { - auto s = shared_from_this(); - m_Service.post ([=](void) { s->HandleReceiveTimer ( - boost::asio::error::make_error_code (boost::asio::error::operation_aborted), - buffer, handler); }); - } - else + auto s = shared_from_this(); + m_Service.post ([=](void) { - m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); - auto s = shared_from_this(); - m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) - { s->HandleReceiveTimer (ecode, buffer, handler); }); - } + if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset) + s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler); + else + { + s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); + s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) + { s->HandleReceiveTimer (ecode, buffer, handler); }); + } + }); } template diff -Nru i2pd-0.9.0/TransitTunnel.cpp i2pd-0.10.0/TransitTunnel.cpp --- i2pd-0.9.0/TransitTunnel.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TransitTunnel.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -20,50 +20,49 @@ m_Encryption.SetKeys (layerKey, ivKey); } - void TransitTunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) + void TransitTunnel::EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) { - m_Encryption.Encrypt (tunnelMsg->GetPayload () + 4); + m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4); } TransitTunnelParticipant::~TransitTunnelParticipant () { - for (auto it: m_TunnelDataMsgs) - i2p::DeleteI2NPMessage (it); } - void TransitTunnelParticipant::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) + void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr tunnelMsg) { - EncryptTunnelMsg (tunnelMsg); + auto newMsg = CreateEmptyTunnelDataMsg (); + EncryptTunnelMsg (tunnelMsg, newMsg); m_NumTransmittedBytes += tunnelMsg->GetLength (); - htobe32buf (tunnelMsg->GetPayload (), GetNextTunnelID ()); - FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); - m_TunnelDataMsgs.push_back (tunnelMsg); + htobe32buf (newMsg->GetPayload (), GetNextTunnelID ()); + newMsg->FillI2NPMessageHeader (eI2NPTunnelData); + m_TunnelDataMsgs.push_back (newMsg); } void TransitTunnelParticipant::FlushTunnelDataMsgs () { if (!m_TunnelDataMsgs.empty ()) { - LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", m_TunnelDataMsgs.size ()); + auto num = m_TunnelDataMsgs.size (); + if (num > 1) + LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num); i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); m_TunnelDataMsgs.clear (); } } - void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) + void TransitTunnel::SendTunnelDataMsg (std::shared_ptr msg) { LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID); - i2p::DeleteI2NPMessage (msg); } - void TransitTunnel::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) + void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr tunnelMsg) { LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID); - DeleteI2NPMessage (tunnelMsg); } - void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) + void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr msg) { TunnelMessageBlock block; block.deliveryType = eDeliveryTypeLocal; @@ -78,12 +77,13 @@ m_Gateway.SendBuffer (); } - void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) + void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr tunnelMsg) { - EncryptTunnelMsg (tunnelMsg); + auto newMsg = CreateEmptyTunnelDataMsg (); + EncryptTunnelMsg (tunnelMsg, newMsg); LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ()); - m_Endpoint.HandleDecryptedTunnelDataMsg (tunnelMsg); + m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID, diff -Nru i2pd-0.9.0/TransitTunnel.h i2pd-0.10.0/TransitTunnel.h --- i2pd-0.9.0/TransitTunnel.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TransitTunnel.h 2015-07-06 16:11:17.000000000 +0000 @@ -4,6 +4,7 @@ #include #include #include +#include #include "aes.h" #include "I2NPProtocol.h" #include "TunnelEndpoint.h" @@ -27,9 +28,9 @@ uint32_t GetTunnelID () const { return m_TunnelID; }; // implements TunnelBase - void SendTunnelDataMsg (i2p::I2NPMessage * msg); - void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); - void EncryptTunnelMsg (I2NPMessage * tunnelMsg); + void SendTunnelDataMsg (std::shared_ptr msg); + void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); + void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); uint32_t GetNextTunnelID () const { return m_NextTunnelID; }; const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; }; @@ -53,13 +54,13 @@ ~TransitTunnelParticipant (); size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; - void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); + void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); void FlushTunnelDataMsgs (); private: size_t m_NumTransmittedBytes; - std::vector m_TunnelDataMsgs; + std::vector > m_TunnelDataMsgs; }; class TransitTunnelGateway: public TransitTunnel @@ -72,7 +73,7 @@ TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), m_Gateway(this) {}; - void SendTunnelDataMsg (i2p::I2NPMessage * msg); + void SendTunnelDataMsg (std::shared_ptr msg); void FlushTunnelDataMsgs (); size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; @@ -92,7 +93,7 @@ TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), m_Endpoint (false) {}; // transit endpoint is always outbound - void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); + void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } private: diff -Nru i2pd-0.9.0/Transports.cpp i2pd-0.10.0/Transports.cpp --- i2pd-0.9.0/Transports.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Transports.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -109,6 +109,10 @@ void Transports::Start () { +#ifdef USE_UPNP + m_UPnP.Start (); + LogPrint(eLogInfo, "UPnP started"); +#endif m_DHKeysPairSupplier.Start (); m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); @@ -141,6 +145,10 @@ void Transports::Stop () { +#ifdef USE_UPNP + m_UPnP.Stop (); + LogPrint(eLogInfo, "UPnP stopped"); +#endif m_PeerCleanupTimer.cancel (); m_Peers.clear (); if (m_SSUServer) @@ -205,44 +213,17 @@ return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT; } - void Transports::SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg) + void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) { - m_Service.post (std::bind (&Transports::PostMessage, this, ident, msg)); + SendMessages (ident, std::vector > {msg }); } - void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector& msgs) + void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs) { m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs)); } - - void Transports::PostMessage (i2p::data::IdentHash ident, i2p::I2NPMessage * msg) - { - if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) - { - // we send it to ourself - i2p::HandleI2NPMessage (msg); - return; - } - auto it = m_Peers.find (ident); - if (it == m_Peers.end ()) - { - auto r = netdb.FindRouter (ident); - it = m_Peers.insert (std::pair(ident, { 0, r, nullptr, - i2p::util::GetSecondsSinceEpoch () })).first; - if (!ConnectToPeer (ident, it->second)) - { - DeleteI2NPMessage (msg); - return; - } - } - if (it->second.session) - it->second.session->SendI2NPMessage (msg); - else - it->second.delayedMessages.push_back (msg); - } - - void Transports::PostMessages (i2p::data::IdentHash ident, std::vector msgs) + void Transports::PostMessages (i2p::data::IdentHash ident, std::vector > msgs) { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) { @@ -254,18 +235,22 @@ auto it = m_Peers.find (ident); if (it == m_Peers.end ()) { - auto r = netdb.FindRouter (ident); - it = m_Peers.insert (std::pair(ident, { 0, r, nullptr, - i2p::util::GetSecondsSinceEpoch () })).first; - if (!ConnectToPeer (ident, it->second)) - { - for (auto it1: msgs) - DeleteI2NPMessage (it1); - return; - } + bool connected = false; + try + { + auto r = netdb.FindRouter (ident); + it = m_Peers.insert (std::pair(ident, { 0, r, {}, + i2p::util::GetSecondsSinceEpoch () })).first; + connected = ConnectToPeer (ident, it->second); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "Transports::PostMessages ", ex.what ()); + } + if (!connected) return; } - if (it->second.session) - it->second.session->SendI2NPMessages (msgs); + if (!it->second.sessions.empty ()) + it->second.sessions.front ()->SendI2NPMessages (msgs); else { for (auto it1: msgs) @@ -319,7 +304,7 @@ } } LogPrint (eLogError, "No NTCP and SSU addresses available"); - if (peer.session) peer.session->Done (); + peer.Done (); m_Peers.erase (ident); return false; } @@ -446,20 +431,12 @@ auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { - if (!it->second.session) - { - it->second.session = session; - session->SendI2NPMessages (it->second.delayedMessages); - it->second.delayedMessages.clear (); - } - else - { - LogPrint (eLogError, "Session for ", ident.ToBase64 ().substr (0, 4), " already exists"); - session->Done (); - } + it->second.sessions.push_back (session); + session->SendI2NPMessages (it->second.delayedMessages); + it->second.delayedMessages.clear (); } else // incoming connection - m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, session, i2p::util::GetSecondsSinceEpoch () })); + m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch () })); }); } @@ -469,12 +446,16 @@ { auto ident = session->GetRemoteIdentity ().GetIdentHash (); auto it = m_Peers.find (ident); - if (it != m_Peers.end () && (!it->second.session || it->second.session == session)) + if (it != m_Peers.end ()) { - if (it->second.delayedMessages.size () > 0) - ConnectToPeer (ident, it->second); - else - m_Peers.erase (it); + it->second.sessions.remove (session); + if (it->second.sessions.empty ()) // TODO: why? + { + if (it->second.delayedMessages.size () > 0) + ConnectToPeer (ident, it->second); + else + m_Peers.erase (it); + } } }); } @@ -492,7 +473,7 @@ auto ts = i2p::util::GetSecondsSinceEpoch (); for (auto it = m_Peers.begin (); it != m_Peers.end (); ) { - if (!it->second.session && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) + if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) { LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); it = m_Peers.erase (it); @@ -507,6 +488,14 @@ m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); } } + + std::shared_ptr Transports::GetRandomPeer () const + { + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + auto it = m_Peers.begin (); + std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1)); + return it != m_Peers.end () ? it->second.router : nullptr; + } } } diff -Nru i2pd-0.9.0/TransportSession.h i2pd-0.10.0/TransportSession.h --- i2pd-0.9.0/TransportSession.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TransportSession.h 2015-07-06 16:11:17.000000000 +0000 @@ -71,8 +71,7 @@ size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; - virtual void SendI2NPMessage (I2NPMessage * msg) = 0; - virtual void SendI2NPMessages (const std::vector& msgs) = 0; + virtual void SendI2NPMessages (const std::vector >& msgs) = 0; protected: diff -Nru i2pd-0.9.0/Transports.h i2pd-0.10.0/Transports.h --- i2pd-0.9.0/Transports.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Transports.h 2015-07-06 16:11:17.000000000 +0000 @@ -20,6 +20,10 @@ #include "I2NPProtocol.h" #include "Identity.h" +#ifdef USE_UPNP +#include "UPnP.h" +#endif + namespace i2p { namespace transport @@ -56,14 +60,14 @@ { int numAttempts; std::shared_ptr router; - std::shared_ptr session; + std::list > sessions; uint64_t creationTime; - std::vector delayedMessages; + std::vector > delayedMessages; - ~Peer () + void Done () { - for (auto it :delayedMessages) - i2p::DeleteI2NPMessage (it); + for (auto it: sessions) + it->Done (); } }; @@ -83,8 +87,8 @@ i2p::transport::DHKeysPair * GetNextDHKeysPair (); void ReuseDHKeysPair (DHKeysPair * pair); - void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); - void SendMessages (const i2p::data::IdentHash& ident, const std::vector& msgs); + void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); + void SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs); void CloseSession (std::shared_ptr router); void PeerConnected (std::shared_ptr session); @@ -98,14 +102,15 @@ uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second bool IsBandwidthExceeded () const; + size_t GetNumPeers () const { return m_Peers.size (); }; + std::shared_ptr GetRandomPeer () const; private: void Run (); void RequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident); void HandleRequestComplete (std::shared_ptr r, const i2p::data::IdentHash& ident); - void PostMessage (i2p::data::IdentHash ident, i2p::I2NPMessage * msg); - void PostMessages (i2p::data::IdentHash ident, std::vector msgs); + void PostMessages (i2p::data::IdentHash ident, std::vector > msgs); void PostCloseSession (std::shared_ptr router); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); void HandlePeerCleanupTimer (const boost::system::error_code& ecode); @@ -136,6 +141,10 @@ uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastBandwidthUpdateTime; +#ifdef USE_UPNP + UPnP m_UPnP; +#endif + public: // for HTTP only diff -Nru i2pd-0.9.0/TunnelBase.h i2pd-0.10.0/TunnelBase.h --- i2pd-0.9.0/TunnelBase.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelBase.h 2015-07-06 16:11:17.000000000 +0000 @@ -26,7 +26,7 @@ TunnelDeliveryType deliveryType; i2p::data::IdentHash hash; uint32_t tunnelID; - I2NPMessage * data; + std::shared_ptr data; }; class TunnelBase @@ -37,10 +37,10 @@ TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; virtual ~TunnelBase () {}; - virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) = 0; - virtual void SendTunnelDataMsg (i2p::I2NPMessage * msg) = 0; + virtual void HandleTunnelDataMsg (std::shared_ptr tunnelMsg) = 0; + virtual void SendTunnelDataMsg (std::shared_ptr msg) = 0; virtual void FlushTunnelDataMsgs () {}; - virtual void EncryptTunnelMsg (I2NPMessage * tunnelMsg) = 0; + virtual void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) = 0; virtual uint32_t GetNextTunnelID () const = 0; virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0; virtual uint32_t GetTunnelID () const = 0; // as known at our side diff -Nru i2pd-0.9.0/TunnelConfig.h i2pd-0.10.0/TunnelConfig.h --- i2pd-0.9.0/TunnelConfig.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelConfig.h 2015-07-06 16:11:17.000000000 +0000 @@ -84,7 +84,7 @@ } } - void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) + void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) const { uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); @@ -107,13 +107,13 @@ } }; - class TunnelConfig + class TunnelConfig: public std::enable_shared_from_this { public: TunnelConfig (std::vector > peers, - const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound + std::shared_ptr replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound { TunnelHopConfig * prev = nullptr; for (auto it: peers) @@ -170,10 +170,24 @@ return num; } + bool IsInbound () const { return m_FirstHop->isGateway; } + + std::vector > GetPeers () const + { + std::vector > peers; + TunnelHopConfig * hop = m_FirstHop; + while (hop) + { + peers.push_back (hop->router); + hop = hop->next; + } + return peers; + } + void Print (std::stringstream& s) const { TunnelHopConfig * hop = m_FirstHop; - if (!m_FirstHop->isGateway) + if (!IsInbound ()) // outbound s << "me"; s << "-->" << m_FirstHop->tunnelID; while (hop) @@ -189,44 +203,17 @@ s << ":me"; } - TunnelConfig * Invert () const + std::shared_ptr Invert () const { - TunnelConfig * newConfig = new TunnelConfig (); - TunnelHopConfig * hop = m_FirstHop, * nextNewHop = nullptr; - while (hop) - { - TunnelHopConfig * newHop = new TunnelHopConfig (hop->router); - if (nextNewHop) - newHop->SetNext (nextNewHop); - nextNewHop = newHop; - newHop->isEndpoint = hop->isGateway; - newHop->isGateway = hop->isEndpoint; - - if (!hop->prev) // first hop - { - newConfig->m_LastHop = newHop; - if (hop->isGateway) // inbound tunnel - newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel - else - newHop->SetNextRouter (i2p::context.GetSharedRouterInfo ()); - } - if (!hop->next) newConfig->m_FirstHop = newHop; // last hop - - hop = hop->next; - } - return newConfig; + auto peers = GetPeers (); + std::reverse (peers.begin (), peers.end ()); + // we use ourself as reply tunnel for outbound tunnel + return IsInbound () ? std::make_shared(peers, shared_from_this ()) : std::make_shared(peers); } - TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const + std::shared_ptr Clone (std::shared_ptr replyTunnelConfig = nullptr) const { - std::vector > peers; - TunnelHopConfig * hop = m_FirstHop; - while (hop) - { - peers.push_back (hop->router); - hop = hop->next; - } - return new TunnelConfig (peers, replyTunnelConfig); + return std::make_shared (GetPeers (), replyTunnelConfig); } private: diff -Nru i2pd-0.9.0/Tunnel.cpp i2pd-0.10.0/Tunnel.cpp --- i2pd-0.9.0/Tunnel.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Tunnel.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -17,14 +17,13 @@ namespace tunnel { - Tunnel::Tunnel (TunnelConfig * config): - m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending) + Tunnel::Tunnel (std::shared_ptr config): + m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false) { } Tunnel::~Tunnel () { - delete m_Config; } void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel) @@ -32,7 +31,7 @@ CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); auto numHops = m_Config->GetNumHops (); int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; - I2NPMessage * msg = NewI2NPShortMessage (); + auto msg = NewI2NPShortMessage (); *msg->GetPayload () = numRecords; msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1; @@ -78,13 +77,13 @@ } hop = hop->prev; } - FillI2NPMessageHeader (msg, eI2NPVariableTunnelBuild); + msg->FillI2NPMessageHeader (eI2NPVariableTunnelBuild); // send message if (outboundTunnel) - outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); + outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, ToSharedI2NPMessage (msg)); else - i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); + i2p::transport::transports.SendMessage (GetNextIdentHash (), ToSharedI2NPMessage (msg)); } bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) @@ -141,32 +140,34 @@ return established; } - void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) + void Tunnel::EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) { - uint8_t * payload = tunnelMsg->GetPayload () + 4; + const uint8_t * inPayload = in->GetPayload () + 4; + uint8_t * outPayload = out->GetPayload () + 4; TunnelHopConfig * hop = m_Config->GetLastHop (); while (hop) { - hop->decryption.Decrypt (payload); + hop->decryption.Decrypt (inPayload, outPayload); hop = hop->prev; + inPayload = outPayload; } } - void Tunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) + void Tunnel::SendTunnelDataMsg (std::shared_ptr msg) { LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions"); - DeleteI2NPMessage (msg); } - void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) + void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr msg) { - if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive - msg->from = shared_from_this (); - EncryptTunnelMsg (msg); - m_Endpoint.HandleDecryptedTunnelDataMsg (msg); + if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive + auto newMsg = CreateEmptyTunnelDataMsg (); + EncryptTunnelMsg (msg, newMsg); + newMsg->from = shared_from_this (); + m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } - void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg) { TunnelMessageBlock block; if (gwHash) @@ -196,10 +197,9 @@ m_Gateway.SendBuffer (); } - void OutboundTunnel::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) + void OutboundTunnel::HandleTunnelDataMsg (std::shared_ptr tunnelMsg) { LogPrint (eLogError, "Incoming message for outbound tunnel ", GetTunnelID ()); - DeleteI2NPMessage (tunnelMsg); } Tunnels tunnels; @@ -287,9 +287,9 @@ return tunnel; } - std::shared_ptr Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops) + std::shared_ptr Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels) { - auto pool = std::make_shared (localDestination, numInboundHops, numOutboundHops); + auto pool = std::make_shared (localDestination, numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels); std::unique_lock l(m_PoolsMutex); m_Pools.push_back (pool); return pool; @@ -353,7 +353,7 @@ { try { - I2NPMessage * msg = m_Queue.GetNextWithTimeout (1000); // 1 sec + auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec if (msg) { uint32_t prevTunnelID = 0, tunnelID = 0; @@ -384,27 +384,18 @@ else // tunnel gateway assumed HandleTunnelGatewayMsg (tunnel, msg); } - else - { + else LogPrint (eLogWarning, "Tunnel ", tunnelID, " not found"); - DeleteI2NPMessage (msg); - } break; } case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuildReply: case eI2NPTunnelBuild: case eI2NPTunnelBuildReply: - { HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); - DeleteI2NPMessage (msg); - break; - } + break; default: - { LogPrint (eLogError, "Unexpected messsage type ", (int)typeID); - DeleteI2NPMessage (msg); - } } msg = m_Queue.Get (); @@ -433,12 +424,11 @@ } } - void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, I2NPMessage * msg) + void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr msg) { if (!tunnel) { LogPrint (eLogError, "Missing tunnel for TunnelGateway"); - i2p::DeleteI2NPMessage (msg); return; } const uint8_t * payload = msg->GetPayload (); @@ -450,13 +440,9 @@ LogPrint (eLogDebug, "TunnelGateway of ", (int)len, " bytes for tunnel ", tunnel->GetTunnelID (), ". Msg type ", (int)typeID); if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply) - { // transit DatabaseStore my contain new/updated RI // or DatabaseSearchReply with new routers - auto ds = NewI2NPMessage (); - *ds = *msg; - i2p::data::netdb.PostI2NPMsg (ds); - } + i2p::data::netdb.PostI2NPMsg (msg); tunnel->SendTunnelDataMsg (msg); } @@ -535,17 +521,25 @@ if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired"); - { - auto pool = tunnel->GetTunnelPool (); - if (pool) - pool->TunnelExpired (tunnel); - } + auto pool = tunnel->GetTunnelPool (); + if (pool) + pool->TunnelExpired (tunnel); it = m_OutboundTunnels.erase (it); } else { - if (tunnel->IsEstablished () && ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) - tunnel->SetState (eTunnelStateExpiring); + if (tunnel->IsEstablished ()) + { + if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + { + tunnel->SetIsRecreated (); + auto pool = tunnel->GetTunnelPool (); + if (pool) + pool->RecreateOutboundTunnel (tunnel); + } + if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + tunnel->SetState (eTunnelStateExpiring); + } it++; } } @@ -555,14 +549,13 @@ { // trying to create one more oubound tunnel auto inboundTunnel = GetNextInboundTunnel (); - if (!inboundTunnel) return; + auto router = i2p::data::netdb.GetRandomRouter (); + if (!inboundTunnel || !router) return; LogPrint ("Creating one hop outbound tunnel..."); CreateTunnel ( - new TunnelConfig (std::vector > - { - i2p::data::netdb.GetRandomRouter () - }, - inboundTunnel->GetTunnelConfig ())); + std::make_shared (std::vector > { router }, + inboundTunnel->GetTunnelConfig ()) + ); } } @@ -576,17 +569,26 @@ if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired"); - { - auto pool = tunnel->GetTunnelPool (); - if (pool) - pool->TunnelExpired (tunnel); - } + auto pool = tunnel->GetTunnelPool (); + if (pool) + pool->TunnelExpired (tunnel); it = m_InboundTunnels.erase (it); } else { - if (tunnel->IsEstablished () && ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) - tunnel->SetState (eTunnelStateExpiring); + if (tunnel->IsEstablished ()) + { + if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + { + tunnel->SetIsRecreated (); + auto pool = tunnel->GetTunnelPool (); + if (pool) + pool->RecreateInboundTunnel (tunnel); + } + + if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + tunnel->SetState (eTunnelStateExpiring); + } it++; } } @@ -597,19 +599,18 @@ LogPrint ("Creating zero hops inbound tunnel..."); CreateZeroHopsInboundTunnel (); if (!m_ExploratoryPool) - m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2); // 2-hop exploratory + m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2, 5, 5); // 2-hop exploratory, 5 tunnels return; } if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5) { - // trying to create one more inbound tunnel + // trying to create one more inbound tunnel + auto router = i2p::data::netdb.GetRandomRouter (); LogPrint ("Creating one hop inbound tunnel..."); CreateTunnel ( - new TunnelConfig (std::vector > - { - i2p::data::netdb.GetRandomRouter () - })); + std::make_shared (std::vector > { router }) + ); } } @@ -647,18 +648,18 @@ } } - void Tunnels::PostTunnelData (I2NPMessage * msg) + void Tunnels::PostTunnelData (std::shared_ptr msg) { if (msg) m_Queue.Put (msg); } - void Tunnels::PostTunnelData (const std::vector& msgs) + void Tunnels::PostTunnelData (const std::vector >& msgs) { m_Queue.Put (msgs); } template - std::shared_ptr Tunnels::CreateTunnel (TunnelConfig * config, std::shared_ptr outboundTunnel) + std::shared_ptr Tunnels::CreateTunnel (std::shared_ptr config, std::shared_ptr outboundTunnel) { auto newTunnel = std::make_shared (config); uint32_t replyMsgID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); @@ -709,7 +710,7 @@ void Tunnels::CreateZeroHopsInboundTunnel () { CreateTunnel ( - new TunnelConfig (std::vector > + std::make_shared (std::vector > { i2p::context.GetSharedRouterInfo () })); diff -Nru i2pd-0.9.0/TunnelEndpoint.cpp i2pd-0.10.0/TunnelEndpoint.cpp --- i2pd-0.9.0/TunnelEndpoint.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelEndpoint.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -13,13 +13,9 @@ { TunnelEndpoint::~TunnelEndpoint () { - for (auto it: m_IncompleteMessages) - i2p::DeleteI2NPMessage (it.second.data); - for (auto it: m_OutOfSequenceFragments) - i2p::DeleteI2NPMessage (it.second.data); } - void TunnelEndpoint::HandleDecryptedTunnelDataMsg (I2NPMessage * msg) + void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr msg) { m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; @@ -35,7 +31,6 @@ if (memcmp (hash, decrypted, 4)) { LogPrint (eLogError, "TunnelMessage: checksum verification failed"); - i2p::DeleteI2NPMessage (msg); return; } // process fragments @@ -97,7 +92,7 @@ if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) { // this is not last message. we have to copy it - m.data = NewI2NPShortMessage (); + m.data = ToSharedI2NPMessage (NewI2NPShortMessage ()); m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header m.data->len += TUNNEL_GATEWAY_HEADER_SIZE; *(m.data) = *msg; @@ -118,10 +113,7 @@ if (ret.second) HandleOutOfSequenceFragment (msgID, ret.first->second); else - { LogPrint (eLogError, "Incomplete message ", msgID, "already exists"); - DeleteI2NPMessage (m.data); - } } else { @@ -130,20 +122,14 @@ } } else - { LogPrint (eLogError, "Message is fragmented, but msgID is not presented"); - DeleteI2NPMessage (m.data); - } } fragment += size; } } else - { LogPrint (eLogError, "TunnelMessage: zero not found"); - i2p::DeleteI2NPMessage (msg); - } } void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m) @@ -161,9 +147,8 @@ if (msg.data->len + size > msg.data->maxLen) { LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); - I2NPMessage * newMsg = NewI2NPMessage (); + auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ()); *newMsg = *(msg.data); - DeleteI2NPMessage (msg.data); msg.data = newMsg; } memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment @@ -183,10 +168,8 @@ else { LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped"); - i2p::DeleteI2NPMessage (msg.data); m_IncompleteMessages.erase (it); } - i2p::DeleteI2NPMessage (m.data); } else { @@ -201,13 +184,11 @@ } } - void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, I2NPMessage * data) + void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr data) { auto it = m_OutOfSequenceFragments.find (msgID); if (it == m_OutOfSequenceFragments.end ()) m_OutOfSequenceFragments.insert (std::pair (msgID, {fragmentNum, isLastFragment, data})); - else - i2p::DeleteI2NPMessage (data); } void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg) @@ -222,9 +203,8 @@ if (msg.data->len + size > msg.data->maxLen) { LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); - I2NPMessage * newMsg = NewI2NPMessage (); + auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ()); *newMsg = *(msg.data); - DeleteI2NPMessage (msg.data); msg.data = newMsg; } memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment @@ -237,7 +217,6 @@ } else msg.nextFragmentNum++; - i2p::DeleteI2NPMessage (it->second.data); m_OutOfSequenceFragments.erase (it); } } @@ -262,28 +241,18 @@ // to somebody else if (!m_IsInbound) // outbound transit tunnel { - auto typeID = msg.data->GetTypeID (); + /* auto typeID = msg.data->GetTypeID (); if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply ) - { // catch RI or reply with new list of routers - auto ds = NewI2NPShortMessage (); - *ds = *(msg.data); - i2p::data::netdb.PostI2NPMsg (ds); - } + i2p::data::netdb.PostI2NPMsg (msg.data);*/ i2p::transport::transports.SendMessage (msg.hash, msg.data); } else // we shouldn't send this message. possible leakage - { LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped"); - i2p::DeleteI2NPMessage (msg.data); - } } break; default: - { LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); - i2p::DeleteI2NPMessage (msg.data); - } }; } } diff -Nru i2pd-0.9.0/TunnelEndpoint.h i2pd-0.10.0/TunnelEndpoint.h --- i2pd-0.9.0/TunnelEndpoint.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelEndpoint.h 2015-07-06 16:11:17.000000000 +0000 @@ -22,7 +22,7 @@ { uint8_t fragmentNum; bool isLastFragment; - I2NPMessage * data; + std::shared_ptr data; }; public: @@ -31,14 +31,14 @@ ~TunnelEndpoint (); size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; - void HandleDecryptedTunnelDataMsg (I2NPMessage * msg); + void HandleDecryptedTunnelDataMsg (std::shared_ptr msg); private: void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m); void HandleNextMessage (const TunnelMessageBlock& msg); - void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, I2NPMessage * data); + void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr data); void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); private: diff -Nru i2pd-0.9.0/TunnelGateway.cpp i2pd-0.10.0/TunnelGateway.cpp --- i2pd-0.9.0/TunnelGateway.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelGateway.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -10,10 +10,16 @@ { namespace tunnel { + TunnelGatewayBuffer::TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), + m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) + { + context.GetRandomNumberGenerator ().GenerateBlock (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); + for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++) + if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1; + } + TunnelGatewayBuffer::~TunnelGatewayBuffer () { - for (auto it: m_TunnelDataMsgs) - DeleteI2NPMessage (it); } void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) @@ -42,7 +48,7 @@ di[0] = block.deliveryType << 5; // set delivery type // create fragments - I2NPMessage * msg = block.data; + std::shared_ptr msg = block.data; auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length if (fullMsgLen <= m_RemainingSize) { @@ -55,7 +61,6 @@ m_RemainingSize -= diLen + msg->GetLength (); if (!m_RemainingSize) CompleteCurrentTunnelDataMessage (); - DeleteI2NPMessage (msg); } else { @@ -119,7 +124,6 @@ size += s; fragmentNumber++; } - DeleteI2NPMessage (msg); } else { @@ -138,7 +142,7 @@ void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () { - m_CurrentTunnelDataMsg = NewI2NPShortMessage (); + m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ()); m_CurrentTunnelDataMsg->Align (12); // we reserve space for padding m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE; @@ -164,13 +168,17 @@ payload[-1] = 0; // zero ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 if (paddingSize > 0) - memset (buf + 24, 1, paddingSize); // padding TODO: fill with random data + { + // non-zero padding + auto randomOffset = rnd.GenerateWord32 (0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize); + memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize); + } // we can't fill message header yet because encryption is required m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); m_CurrentTunnelDataMsg = nullptr; } - + void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) { if (block.data) @@ -192,8 +200,8 @@ auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs (); for (auto tunnelMsg : tunnelMsgs) { - m_Tunnel->EncryptTunnelMsg (tunnelMsg); - FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); + m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg); + tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData); m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), tunnelMsgs); diff -Nru i2pd-0.9.0/TunnelGateway.h i2pd-0.10.0/TunnelGateway.h --- i2pd-0.9.0/TunnelGateway.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelGateway.h 2015-07-06 16:11:17.000000000 +0000 @@ -3,6 +3,7 @@ #include #include +#include #include "I2NPProtocol.h" #include "TunnelBase.h" @@ -13,11 +14,10 @@ class TunnelGatewayBuffer { public: - TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), - m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; + TunnelGatewayBuffer (uint32_t tunnelID); ~TunnelGatewayBuffer (); void PutI2NPMsg (const TunnelMessageBlock& block); - const std::vector& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; + const std::vector >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; void ClearTunnelDataMsgs (); void CompleteCurrentTunnelDataMessage (); @@ -28,16 +28,17 @@ private: uint32_t m_TunnelID; - std::vector m_TunnelDataMsgs; - I2NPMessage * m_CurrentTunnelDataMsg; + std::vector > m_TunnelDataMsgs; + std::shared_ptr m_CurrentTunnelDataMsg; size_t m_RemainingSize; + uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE]; }; class TunnelGateway { public: - TunnelGateway (TunnelBase * tunnel): + TunnelGateway (TunnelBase * tunnel): m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; void SendTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block); diff -Nru i2pd-0.9.0/Tunnel.h i2pd-0.10.0/Tunnel.h --- i2pd-0.9.0/Tunnel.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Tunnel.h 2015-07-06 16:11:17.000000000 +0000 @@ -24,6 +24,7 @@ { const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute + const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message @@ -44,16 +45,18 @@ { public: - Tunnel (TunnelConfig * config); + Tunnel (std::shared_ptr config); ~Tunnel (); void Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel = nullptr); - TunnelConfig * GetTunnelConfig () const { return m_Config; } + std::shared_ptr GetTunnelConfig () const { return m_Config; } TunnelState GetState () const { return m_State; }; void SetState (TunnelState state) { m_State = state; }; bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsFailed () const { return m_State == eTunnelStateFailed; }; + bool IsRecreated () const { return m_IsRecreated; }; + void SetIsRecreated () { m_IsRecreated = true; }; std::shared_ptr GetTunnelPool () const { return m_Pool; }; void SetTunnelPool (std::shared_ptr pool) { m_Pool = pool; }; @@ -61,32 +64,33 @@ bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); // implements TunnelBase - void SendTunnelDataMsg (i2p::I2NPMessage * msg); - void EncryptTunnelMsg (I2NPMessage * tunnelMsg); + void SendTunnelDataMsg (std::shared_ptr msg); + void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; }; const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); }; private: - TunnelConfig * m_Config; + std::shared_ptr m_Config; std::shared_ptr m_Pool; // pool, tunnel belongs to, or null TunnelState m_State; + bool m_IsRecreated; }; class OutboundTunnel: public Tunnel { public: - OutboundTunnel (TunnelConfig * config): Tunnel (config), m_Gateway (this) {}; + OutboundTunnel (std::shared_ptr config): Tunnel (config), m_Gateway (this) {}; - void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg); void SendTunnelDataMsg (const std::vector& msgs); // multiple messages std::shared_ptr GetEndpointRouter () const { return GetTunnelConfig ()->GetLastHop ()->router; }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; // implements TunnelBase - void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); + void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); uint32_t GetTunnelID () const { return GetNextTunnelID (); }; private: @@ -99,8 +103,8 @@ { public: - InboundTunnel (TunnelConfig * config): Tunnel (config), m_Endpoint (true) {}; - void HandleTunnelDataMsg (I2NPMessage * msg); + InboundTunnel (std::shared_ptr config): Tunnel (config), m_Endpoint (true) {}; + void HandleTunnelDataMsg (std::shared_ptr msg); size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; // implements TunnelBase @@ -131,13 +135,13 @@ void AddTransitTunnel (TransitTunnel * tunnel); void AddOutboundTunnel (std::shared_ptr newTunnel); void AddInboundTunnel (std::shared_ptr newTunnel); - void PostTunnelData (I2NPMessage * msg); - void PostTunnelData (const std::vector& msgs); + void PostTunnelData (std::shared_ptr msg); + void PostTunnelData (const std::vector >& msgs); template - std::shared_ptr CreateTunnel (TunnelConfig * config, std::shared_ptr outboundTunnel = nullptr); + std::shared_ptr CreateTunnel (std::shared_ptr config, std::shared_ptr outboundTunnel = nullptr); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr tunnel); - std::shared_ptr CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops); + std::shared_ptr CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels); void DeleteTunnelPool (std::shared_ptr pool); void StopTunnelPool (std::shared_ptr pool); @@ -146,7 +150,7 @@ template std::shared_ptr GetPendingTunnel (uint32_t replyMsgID, const std::map >& pendingTunnels); - void HandleTunnelGatewayMsg (TunnelBase * tunnel, I2NPMessage * msg); + void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr msg); void Run (); void ManageTunnels (); @@ -173,7 +177,7 @@ std::mutex m_PoolsMutex; std::list> m_Pools; std::shared_ptr m_ExploratoryPool; - i2p::util::Queue m_Queue; + i2p::util::Queue > m_Queue; // some stats int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; diff -Nru i2pd-0.9.0/TunnelPool.cpp i2pd-0.10.0/TunnelPool.cpp --- i2pd-0.9.0/TunnelPool.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelPool.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -1,18 +1,20 @@ +#include #include "I2PEndian.h" #include "CryptoConst.h" #include "Tunnel.h" #include "NetDb.h" #include "Timestamp.h" #include "Garlic.h" +#include "Transports.h" #include "TunnelPool.h" namespace i2p { namespace tunnel { - TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels): + TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), - m_NumTunnels (numTunnels), m_IsActive (true) + m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true) { } @@ -21,6 +23,27 @@ DetachTunnels (); } + void TunnelPool::SetExplicitPeers (std::shared_ptr > explicitPeers) + { + m_ExplicitPeers = explicitPeers; + if (m_ExplicitPeers) + { + int size = m_ExplicitPeers->size (); + if (m_NumInboundHops > size) + { + m_NumInboundHops = size; + LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers"); + } + if (m_NumOutboundHops > size) + { + m_NumOutboundHops = size; + LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers"); + } + m_NumInboundTunnels = 1; + m_NumOutboundTunnels = 1; + } + } + void TunnelPool::DetachTunnels () { { @@ -56,7 +79,6 @@ expiredTunnel->SetTunnelPool (nullptr); for (auto it: m_Tests) if (it.second.second == expiredTunnel) it.second.second = nullptr; - RecreateInboundTunnel (expiredTunnel); std::unique_lock l(m_InboundTunnelsMutex); m_InboundTunnels.erase (expiredTunnel); @@ -66,8 +88,11 @@ void TunnelPool::TunnelCreated (std::shared_ptr createdTunnel) { if (!m_IsActive) return; - std::unique_lock l(m_OutboundTunnelsMutex); - m_OutboundTunnels.insert (createdTunnel); + { + std::unique_lock l(m_OutboundTunnelsMutex); + m_OutboundTunnels.insert (createdTunnel); + } + //CreatePairedInboundTunnel (createdTunnel); } void TunnelPool::TunnelExpired (std::shared_ptr expiredTunnel) @@ -77,7 +102,6 @@ expiredTunnel->SetTunnelPool (nullptr); for (auto it: m_Tests) if (it.second.first == expiredTunnel) it.second.first = nullptr; - RecreateOutboundTunnel (expiredTunnel); std::unique_lock l(m_OutboundTunnelsMutex); m_OutboundTunnels.erase (expiredTunnel); @@ -133,6 +157,26 @@ return tunnel; } + std::shared_ptr TunnelPool::GetNewOutboundTunnel (std::shared_ptr old) const + { + if (old && old->IsEstablished ()) return old; + std::shared_ptr tunnel; + if (old) + { + std::unique_lock l(m_OutboundTunnelsMutex); + for (auto it: m_OutboundTunnels) + if (it->IsEstablished () && old->GetEndpointRouter ()->GetIdentHash () == it->GetEndpointRouter ()->GetIdentHash ()) + { + tunnel = it; + break; + } + } + + if (!tunnel) + tunnel = GetNextOutboundTunnel (); + return tunnel; + } + void TunnelPool::CreateTunnels () { int num = 0; @@ -141,7 +185,7 @@ for (auto it : m_InboundTunnels) if (it->IsEstablished ()) num++; } - for (int i = num; i < m_NumTunnels; i++) + for (int i = num; i < m_NumInboundTunnels; i++) CreateInboundTunnel (); num = 0; @@ -150,7 +194,7 @@ for (auto it : m_OutboundTunnels) if (it->IsEstablished ()) num++; } - for (int i = num; i < m_NumTunnels; i++) + for (int i = num; i < m_NumOutboundTunnels; i++) CreateOutboundTunnel (); } @@ -216,18 +260,15 @@ } } - void TunnelPool::ProcessGarlicMessage (I2NPMessage * msg) + void TunnelPool::ProcessGarlicMessage (std::shared_ptr msg) { if (m_LocalDestination) m_LocalDestination->ProcessGarlicMessage (msg); else - { LogPrint (eLogWarning, "Local destination doesn't exist. Dropped"); - DeleteI2NPMessage (msg); - } } - void TunnelPool::ProcessDeliveryStatus (I2NPMessage * msg) + void TunnelPool::ProcessDeliveryStatus (std::shared_ptr msg) { const uint8_t * buf = msg->GetPayload (); uint32_t msgID = bufbe32toh (buf); @@ -244,17 +285,13 @@ it->second.second->SetState (eTunnelStateEstablished); LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds"); m_Tests.erase (it); - DeleteI2NPMessage (msg); } else { if (m_LocalDestination) m_LocalDestination->ProcessDeliveryStatusMessage (msg); else - { LogPrint (eLogWarning, "Local destination doesn't exist. Dropped"); - DeleteI2NPMessage (msg); - } } } @@ -263,46 +300,81 @@ bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop): i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop); - if (!isExploratory && hop && hop->GetProfile ()->IsBad ()) - { - LogPrint (eLogInfo, "Selected peer for tunnel has bad profile. Selecting another"); - hop = i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop); - } - - if (!hop) + + if (!hop || hop->GetProfile ()->IsBad ()) hop = i2p::data::netdb.GetRandomRouter (); return hop; } - - void TunnelPool::CreateInboundTunnel () + + bool TunnelPool::SelectPeers (std::vector >& hops, bool isInbound) { - auto outboundTunnel = GetNextOutboundTunnel (); - if (!outboundTunnel) - outboundTunnel = tunnels.GetNextOutboundTunnel (); - LogPrint ("Creating destination inbound tunnel..."); + if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound); auto prevHop = i2p::context.GetSharedRouterInfo (); - std::vector > hops; - int numHops = m_NumInboundHops; - if (outboundTunnel) - { - // last hop - auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; - if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel - { - prevHop = hop; - hops.push_back (prevHop); + int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; + if (i2p::transport::transports.GetNumPeers () > 25) + { + auto r = i2p::transport::transports.GetRandomPeer (); + if (r && !r->GetProfile ()->IsBad ()) + { + prevHop = r; + hops.push_back (r); numHops--; } } + for (int i = 0; i < numHops; i++) { auto hop = SelectNextHop (prevHop); + if (!hop) + { + LogPrint (eLogError, "Can't select next hop"); + return false; + } prevHop = hop; hops.push_back (hop); } - std::reverse (hops.begin (), hops.end ()); - auto tunnel = tunnels.CreateTunnel (new TunnelConfig (hops), outboundTunnel); - tunnel->SetTunnelPool (shared_from_this ()); + return true; + } + + bool TunnelPool::SelectExplicitPeers (std::vector >& hops, bool isInbound) + { + int size = m_ExplicitPeers->size (); + std::vector peerIndicies; + for (int i = 0; i < size; i++) peerIndicies.push_back(i); + std::random_shuffle (peerIndicies.begin(), peerIndicies.end()); + + int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; + for (int i = 0; i < numHops; i++) + { + auto& ident = (*m_ExplicitPeers)[peerIndicies[i]]; + auto r = i2p::data::netdb.FindRouter (ident); + if (r) + hops.push_back (r); + else + { + LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ()); + i2p::data::netdb.RequestDestination (ident); + return false; + } + } + return true; + } + + void TunnelPool::CreateInboundTunnel () + { + auto outboundTunnel = GetNextOutboundTunnel (); + if (!outboundTunnel) + outboundTunnel = tunnels.GetNextOutboundTunnel (); + LogPrint ("Creating destination inbound tunnel..."); + std::vector > hops; + if (SelectPeers (hops, true)) + { + std::reverse (hops.begin (), hops.end ()); + auto tunnel = tunnels.CreateTunnel (std::make_shared (hops), outboundTunnel); + tunnel->SetTunnelPool (shared_from_this ()); + } + else + LogPrint (eLogError, "Can't create inbound tunnel. No peers available"); } void TunnelPool::RecreateInboundTunnel (std::shared_ptr tunnel) @@ -323,22 +395,18 @@ if (inboundTunnel) { LogPrint ("Creating destination outbound tunnel..."); - - auto prevHop = i2p::context.GetSharedRouterInfo (); std::vector > hops; - for (int i = 0; i < m_NumOutboundHops; i++) - { - auto hop = SelectNextHop (prevHop); - prevHop = hop; - hops.push_back (hop); + if (SelectPeers (hops, false)) + { + auto tunnel = tunnels.CreateTunnel ( + std::make_shared (hops, inboundTunnel->GetTunnelConfig ())); + tunnel->SetTunnelPool (shared_from_this ()); } - - auto tunnel = tunnels.CreateTunnel ( - new TunnelConfig (hops, inboundTunnel->GetTunnelConfig ())); - tunnel->SetTunnelPool (shared_from_this ()); + else + LogPrint (eLogError, "Can't create outbound tunnel. No peers available"); } else - LogPrint ("Can't create outbound tunnel. No inbound tunnels found"); + LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found"); } void TunnelPool::RecreateOutboundTunnel (std::shared_ptr tunnel) @@ -355,6 +423,13 @@ } else LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found"); - } + } + + void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr outboundTunnel) + { + LogPrint (eLogInfo, "Creating paired inbound tunnel..."); + auto tunnel = tunnels.CreateTunnel (outboundTunnel->GetTunnelConfig ()->Invert (), outboundTunnel); + tunnel->SetTunnelPool (shared_from_this ()); + } } } diff -Nru i2pd-0.9.0/TunnelPool.h i2pd-0.10.0/TunnelPool.h --- i2pd-0.9.0/TunnelPool.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/TunnelPool.h 2015-07-06 16:11:17.000000000 +0000 @@ -27,24 +27,28 @@ { public: - TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels = 5); + TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels); ~TunnelPool (); i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; }; void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; }; + void SetExplicitPeers (std::shared_ptr > explicitPeers); void CreateTunnels (); void TunnelCreated (std::shared_ptr createdTunnel); void TunnelExpired (std::shared_ptr expiredTunnel); void TunnelCreated (std::shared_ptr createdTunnel); void TunnelExpired (std::shared_ptr expiredTunnel); + void RecreateInboundTunnel (std::shared_ptr tunnel); + void RecreateOutboundTunnel (std::shared_ptr tunnel); std::vector > GetInboundTunnels (int num) const; std::shared_ptr GetNextOutboundTunnel (std::shared_ptr excluded = nullptr) const; std::shared_ptr GetNextInboundTunnel (std::shared_ptr excluded = nullptr) const; + std::shared_ptr GetNewOutboundTunnel (std::shared_ptr old) const; void TestTunnels (); - void ProcessGarlicMessage (I2NPMessage * msg); - void ProcessDeliveryStatus (I2NPMessage * msg); + void ProcessGarlicMessage (std::shared_ptr msg); + void ProcessDeliveryStatus (std::shared_ptr msg); bool IsActive () const { return m_IsActive; }; void SetActive (bool isActive) { m_IsActive = isActive; }; @@ -54,16 +58,18 @@ void CreateInboundTunnel (); void CreateOutboundTunnel (); - void RecreateInboundTunnel (std::shared_ptr tunnel); - void RecreateOutboundTunnel (std::shared_ptr tunnel); + void CreatePairedInboundTunnel (std::shared_ptr outboundTunnel); template typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; std::shared_ptr SelectNextHop (std::shared_ptr prevHop) const; - + bool SelectPeers (std::vector >& hops, bool isInbound); + bool SelectExplicitPeers (std::vector >& hops, bool isInbound); + private: i2p::garlic::GarlicDestination * m_LocalDestination; - int m_NumInboundHops, m_NumOutboundHops, m_NumTunnels; + int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels; + std::shared_ptr > m_ExplicitPeers; mutable std::mutex m_InboundTunnelsMutex; std::set, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first mutable std::mutex m_OutboundTunnelsMutex; diff -Nru i2pd-0.9.0/UPnP.cpp i2pd-0.10.0/UPnP.cpp --- i2pd-0.9.0/UPnP.cpp 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/UPnP.cpp 2015-07-06 16:11:17.000000000 +0000 @@ -2,15 +2,19 @@ #include #include -#ifdef _WIN32 -#include -#endif - #include #include #include +#ifdef _WIN32 +#include +#define dlsym GetProcAddress +#else +#include +#endif + #include "Log.h" + #include "RouterContext.h" #include "UPnP.h" #include "NetDb.h" @@ -18,31 +22,41 @@ #include #include -#include +// These are per-process and are safe to reuse for all threads #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ -typedef UPNPDev* (*upnp_upnpDiscoverFunc) (int, const char *, const char *, int); -typedef int (*upnp_UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, +UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int); +int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); #else /* miniupnpc 1.6 */ -typedef UPNPDev* (*upnp_upnpDiscoverFunc) (int, const char *, const char *, int, int, int *); -typedef int (*upnp_UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, +UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int, int, int *); +int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *); #endif -typedef int (*upnp_UPNP_GetValidIGDFunc) (struct UPNPDev *, struct UPNPUrls *, struct IGDdatas *, char *, int); -typedef int (*upnp_UPNP_GetExternalIPAddressFunc) (const char *, const char *, char *); -typedef int (*upnp_UPNP_DeletePortMappingFunc) (const char *, const char *, const char *, const char *, const char *); -typedef void (*upnp_freeUPNPDevlistFunc) (struct UPNPDev *); -typedef void (*upnp_FreeUPNPUrlsFunc) (struct UPNPUrls *); +int (*UPNP_GetValidIGDFunc) (struct UPNPDev *, struct UPNPUrls *, struct IGDdatas *, char *, int); +int (*UPNP_GetExternalIPAddressFunc) (const char *, const char *, char *); +int (*UPNP_DeletePortMappingFunc) (const char *, const char *, const char *, const char *, const char *); +void (*freeUPNPDevlistFunc) (struct UPNPDev *); +void (*FreeUPNPUrlsFunc) (struct UPNPUrls *); + +// Nice approach http://stackoverflow.com/a/21517513/673826 +template +F GetKnownProcAddressImpl(M hmod, const char *name, F) { + auto proc = reinterpret_cast(dlsym(hmod, name)); + if (!proc) { + LogPrint("Error resolving ", name, " from UPNP library. This often happens if there is version mismatch!"); + } + return proc; +} +#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func); + namespace i2p { -namespace UPnP +namespace transport { - UPnP upnpc; - UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false) { } @@ -59,6 +73,33 @@ void UPnP::Start() { + if (!m_IsModuleLoaded) { +#ifdef MAC_OSX + m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY); +#elif _WIN32 + m_Module = LoadLibrary ("miniupnpc.dll"); // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip +#else + m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY); +#endif + if (m_Module == NULL) + { + LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!"); + return; + } + else + { + upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover); + UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD); + UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress); + UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping); + UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping); + freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist); + FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls); + if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc && + UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc) + m_IsModuleLoaded = true; + } + } m_Thread = new std::thread (std::bind (&UPnP::Run, this)); } @@ -68,46 +109,18 @@ void UPnP::Run () { -#ifdef MAC_OSX - m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY); -#elif _WIN32 - m_Module = LoadLibrary ("libminiupnpc.dll"); - if (m_Module == NULL) - { - LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!"); - return; - } - else - { - m_IsModuleLoaded = true; - } -#else - m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY); -#endif -#ifndef _WIN32 - if (!m_Module) - { - LogPrint ("no UPnP module available (", dlerror (), ")"); - return; - } - else - { - m_IsModuleLoaded = true; - } -#endif for (auto& address : context.GetRouterInfo ().GetAddresses ()) { if (!address.host.is_v6 ()) { - m_Port = std::to_string (util::config::GetArg ("-port", address.port)); Discover (); if (address.transportStyle == data::RouterInfo::eTransportSSU ) { - TryPortMapping (I2P_UPNP_UDP); + TryPortMapping (I2P_UPNP_UDP, address.port); } else if (address.transportStyle == data::RouterInfo::eTransportNTCP ) { - TryPortMapping (I2P_UPNP_TCP); + TryPortMapping (I2P_UPNP_TCP, address.port); } } } @@ -115,18 +128,6 @@ void UPnP::Discover () { - const char *error; -#ifdef _WIN32 - upnp_upnpDiscoverFunc upnpDiscoverFunc = (upnp_upnpDiscoverFunc) GetProcAddress (m_Module, "upnpDiscover"); -#else - upnp_upnpDiscoverFunc upnpDiscoverFunc = (upnp_upnpDiscoverFunc) dlsym (m_Module, "upnpDiscover"); - // reinterpret_cast (dlsym(...)); - if ( (error = dlerror ())) - { - LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!"); - return; - } -#endif // _WIN32 #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0); @@ -137,15 +138,9 @@ #endif int r; -#ifdef _WIN32 - upnp_UPNP_GetValidIGDFunc UPNP_GetValidIGDFunc = (upnp_UPNP_GetValidIGDFunc) GetProcAddress (m_Module, "UPNP_GetValidIGD"); -#else - upnp_UPNP_GetValidIGDFunc UPNP_GetValidIGDFunc = (upnp_UPNP_GetValidIGDFunc) dlsym (m_Module, "UPNP_GetValidIGD"); -#endif - r = (*UPNP_GetValidIGDFunc) (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); + r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); if (r == 1) { - upnp_UPNP_GetExternalIPAddressFunc UPNP_GetExternalIPAddressFunc = (upnp_UPNP_GetExternalIPAddressFunc) dlsym (m_Module, "UPNP_GetExternalIPAddress"); r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { @@ -169,9 +164,9 @@ } } - void UPnP::TryPortMapping (int type) + void UPnP::TryPortMapping (int type, int port) { - std::string strType; + std::string strType, strPort (std::to_string (port)); switch (type) { case I2P_UPNP_TCP: @@ -185,42 +180,39 @@ std::string strDesc = "I2Pd"; try { for (;;) { -#ifdef _WIN32 - upnp_UPNP_AddPortMappingFunc UPNP_AddPortMappingFunc = (upnp_UPNP_AddPortMappingFunc) GetProcAddress (m_Module, "UPNP_AddPortMapping"); -#else - upnp_UPNP_AddPortMappingFunc UPNP_AddPortMappingFunc = (upnp_UPNP_AddPortMappingFunc) dlsym (m_Module, "UPNP_AddPortMapping"); -#endif #ifndef UPNPDISCOVER_SUCCESS /* miniupnpc 1.5 */ - r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), m_Port.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0); + r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0); #else /* miniupnpc 1.6 */ - r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), m_Port.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); + r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); #endif if (r!=UPNPCOMMAND_SUCCESS) { - LogPrint ("AddPortMapping (", m_Port.c_str () ,", ", m_Port.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); + LogPrint ("AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); return; } else { - LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", m_Port.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", m_Port.c_str() ,")"); + LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")"); return; } - sleep(20*60); + std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11 + //boost::this_thread::sleep_for(); // pre c++11 + //sleep(20*60); // non-portable } } catch (boost::thread_interrupted) { - CloseMapping(type); + CloseMapping(type, port); Close(); throw; } } - void UPnP::CloseMapping (int type) + void UPnP::CloseMapping (int type, int port) { - std::string strType; + std::string strType, strPort (std::to_string (port)); switch (type) { case I2P_UPNP_TCP: @@ -231,29 +223,14 @@ strType = "UDP"; } int r = 0; -#ifdef _WIN32 - upnp_UPNP_DeletePortMappingFunc UPNP_DeletePortMappingFunc = (upnp_UPNP_DeletePortMappingFunc) GetProcAddress (m_Module, "UPNP_DeletePortMapping"); -#else - upnp_UPNP_DeletePortMappingFunc UPNP_DeletePortMappingFunc = (upnp_UPNP_DeletePortMappingFunc) dlsym (m_Module, "UPNP_DeletePortMapping"); -#endif - r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), strType.c_str (), 0); + r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0); LogPrint ("UPNP_DeletePortMapping() returned : ", r, "\n"); } void UPnP::Close () { -#ifdef _WIN32 - upnp_freeUPNPDevlistFunc freeUPNPDevlistFunc = (upnp_freeUPNPDevlistFunc) GetProcAddress (m_Module, "freeUPNPDevlist"); -#else - upnp_freeUPNPDevlistFunc freeUPNPDevlistFunc = (upnp_freeUPNPDevlistFunc) dlsym (m_Module, "freeUPNPDevlist"); -#endif freeUPNPDevlistFunc (m_Devlist); m_Devlist = 0; -#ifdef _WIN32 - upnp_FreeUPNPUrlsFunc FreeUPNPUrlsFunc = (upnp_FreeUPNPUrlsFunc) GetProcAddress (m_Module, "FreeUPNPUrlsFunc"); -#else - upnp_FreeUPNPUrlsFunc FreeUPNPUrlsFunc = (upnp_FreeUPNPUrlsFunc) dlsym (m_Module, "FreeUPNPUrlsFunc"); -#endif FreeUPNPUrlsFunc (&m_upnpUrls); #ifndef _WIN32 dlclose (m_Module); diff -Nru i2pd-0.9.0/UPnP.h i2pd-0.10.0/UPnP.h --- i2pd-0.9.0/UPnP.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/UPnP.h 2015-07-06 16:11:17.000000000 +0000 @@ -19,7 +19,7 @@ namespace i2p { -namespace UPnP +namespace transport { class UPnP { @@ -33,8 +33,8 @@ void Stop (); void Discover (); - void TryPortMapping (int type); - void CloseMapping (int type); + void TryPortMapping (int type, int port); + void CloseMapping (int type, int port); private: void Run (); @@ -49,14 +49,12 @@ char m_NetworkAddr[64]; char m_externalIPAddress[40]; bool m_IsModuleLoaded; - std::string m_Port = std::to_string (util::config::GetArg ("-port", 17070)); #ifndef _WIN32 void *m_Module; #else - HINSTANCE *m_Module; + HINSTANCE m_Module; #endif }; - extern UPnP upnpc; } } diff -Nru i2pd-0.9.0/version.h i2pd-0.10.0/version.h --- i2pd-0.9.0/version.h 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/version.h 2015-07-06 16:11:17.000000000 +0000 @@ -2,7 +2,7 @@ #define _VERSION_H_ #define CODENAME "Purple" -#define VERSION "0.9.0" -#define I2P_VERSION "0.9.18" +#define VERSION "0.10.0" +#define I2P_VERSION "0.9.20" #endif diff -Nru i2pd-0.9.0/Win32/i2pd.vcxproj i2pd-0.10.0/Win32/i2pd.vcxproj --- i2pd-0.9.0/Win32/i2pd.vcxproj 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Win32/i2pd.vcxproj 2015-07-06 16:11:17.000000000 +0000 @@ -37,11 +37,13 @@ + + @@ -80,6 +82,7 @@ + diff -Nru i2pd-0.9.0/Win32/README-Build.txt i2pd-0.10.0/Win32/README-Build.txt --- i2pd-0.9.0/Win32/README-Build.txt 2015-03-31 12:34:55.000000000 +0000 +++ i2pd-0.10.0/Win32/README-Build.txt 2015-07-06 16:11:17.000000000 +0000 @@ -3,8 +3,8 @@ Requirements for building: -* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4 RC) -* Boost (tested with 1.56 and 1.57) +* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4) +* Boost (tested with 1.56, 1.57, and 1.58) * Crypto++ (tested with 5.6.2) @@ -31,7 +31,7 @@ Boost was installed to. If you followed the instructions outlined here, you should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the version of Boost that you're using, but instead of a '.' use a '_'. For -example, I have `BOOSTVER` set to `1_57`. +example, I have `BOOSTVER` set to `1_58`. Building Crypto++ -----------------