diff --git a/.travis.yml b/.travis.yml index d83cdbc0..e52c53a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink boost openssl && brew link boost openssl -f ; fi env: matrix: - - BUILD_TYPE=Release UPNP=ON +# - BUILD_TYPE=Release UPNP=ON - BUILD_TYPE=Release UPNP=OFF script: - cd build && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_UPNP=${UPNP} && make diff --git a/Base.cpp b/Base.cpp index e0b6af07..766eaab9 100644 --- a/Base.cpp +++ b/Base.cpp @@ -1,5 +1,4 @@ #include -#include "Log.h" #include "Base.h" namespace i2p @@ -305,13 +304,10 @@ namespace data m_Inflator.next_out = out; m_Inflator.avail_out = outLen; int err; - if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) + if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) { return outLen - m_Inflator.avail_out; - else - { - LogPrint (eLogError, "Decompression error ", err); - return 0; - } + } + return 0; } bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s) @@ -328,13 +324,11 @@ namespace data ret = inflate (&m_Inflator, Z_NO_FLUSH); if (ret < 0) { - LogPrint (eLogError, "Decompression error ", ret); inflateEnd (&m_Inflator); s.setstate(std::ios_base::failbit); break; } - else - s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); + s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); } while (!m_Inflator.avail_out); // more data to read delete[] out; @@ -377,13 +371,10 @@ namespace data m_Deflator.next_out = out; m_Deflator.avail_out = outLen; int err; - if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) + if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) { return outLen - m_Deflator.avail_out; - else - { - LogPrint (eLogError, "Compression error ", err); - return 0; - } + } /* else */ + return 0; } } } diff --git a/ChangeLog b/ChangeLog index 9a32e42f..520978df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,23 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog -## [2.8.0] - UNRELEASED +## [2.9.0] - UNRELEASED ### Changed - Proxy refactoring & speedup + +## [2.8.0] - 2016-06-20 +### Added +- Basic Android support +- I2CP implementation +- 'doxygen' target + +### Changed - I2PControl refactoring & fixes (proper jsonrpc responses on errors) - boost::regex no more needed ### Fixed - initscripts: added openrc one, in sysv-ish make I2PD_PORT optional +- properly close NTCP sessions (memleak) ## [2.7.0] - 2016-05-18 ### Added diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 48fa0ae6..e11d430d 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -3,6 +3,13 @@ #include #include #include +#include +#include +#include +#include + +#include "I2PService.h" +#include "Destination.h" #include "HTTPProxy.h" #include "util.h" #include "Identity.h" @@ -13,13 +20,12 @@ #include "I2PTunnel.h" #include "Config.h" #include "HTTP.h" +#include "HTTPServer.h" -namespace i2p -{ -namespace proxy -{ +namespace i2p { +namespace proxy { static const size_t http_buffer_size = 8192; - class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this + class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this { private: enum state @@ -36,7 +42,7 @@ namespace proxy void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void Terminate(); void AsyncSockRead(); - void HTTPRequestFailed(/*std::string message*/); + void HTTPRequestFailed(const char *message); void RedirectToJumpService(); void ExtractRequest(); bool IsI2PAddress(); @@ -59,26 +65,26 @@ namespace proxy public: - HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr sock) : + HTTPReqHandler(HTTPProxy * parent, std::shared_ptr sock) : I2PServiceHandler(parent), m_sock(sock) { EnterState(GET_METHOD); } - ~HTTPProxyHandler() { Terminate(); } + ~HTTPReqHandler() { Terminate(); } void Handle () { AsyncSockRead(); } }; - void HTTPProxyHandler::AsyncSockRead() + void HTTPReqHandler::AsyncSockRead() { LogPrint(eLogDebug, "HTTPProxy: async sock read"); if(m_sock) { m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), - std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(), + std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } else { LogPrint(eLogError, "HTTPProxy: no socket for read"); } } - void HTTPProxyHandler::Terminate() { + void HTTPReqHandler::Terminate() { if (Kill()) return; if (m_sock) { @@ -91,30 +97,34 @@ namespace proxy /* All hope is lost beyond this point */ //TODO: handle this apropriately - void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/) + void HTTPReqHandler::HTTPRequestFailed(const char *message) { - static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n\r\n"; - boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), - std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); + std::size_t size = std::strlen(message); + std::stringstream ss; + ss << "HTTP/1.0 500 Internal Server Error\r\n" + << "Content-Type: text/plain\r\n"; + ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" + << "\r\n"; /* end of headers */ + ss << message << "\r\n"; + std::string response = ss.str(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response), + std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPProxyHandler::RedirectToJumpService(/*HTTPProxyHandler::errTypes error*/) + void HTTPReqHandler::RedirectToJumpService(/*HTTPReqHandler::errTypes error*/) { - std::stringstream response; - std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); - uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); - - response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; - boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), - std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); + std::stringstream ss; + i2p::http::ShowJumpServices (ss, m_address); + boost::asio::async_write(*m_sock, boost::asio::buffer(ss.str ()), + std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } - void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate) + void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate) { m_state = nstate; } - void HTTPProxyHandler::ExtractRequest() + void HTTPReqHandler::ExtractRequest() { LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); i2p::http::URL url; @@ -127,18 +137,18 @@ namespace proxy LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path); } - bool HTTPProxyHandler::ValidateHTTPRequest() + bool HTTPReqHandler::ValidateHTTPRequest() { if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) { LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); - HTTPRequestFailed(); //TODO: send right stuff + HTTPRequestFailed("unsupported HTTP version"); return false; } return true; } - void HTTPProxyHandler::HandleJumpServices() + void HTTPReqHandler::HandleJumpServices() { static const char * helpermark1 = "?i2paddresshelper="; static const char * helpermark2 = "&i2paddresshelper="; @@ -170,7 +180,7 @@ namespace proxy m_path.erase(addressHelperPos); } - bool HTTPProxyHandler::IsI2PAddress() + bool HTTPReqHandler::IsI2PAddress() { auto pos = m_address.rfind (".i2p"); if (pos != std::string::npos && (pos+4) == m_address.length ()) @@ -180,7 +190,7 @@ namespace proxy return false; } - bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) + bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) { ExtractRequest(); //TODO: parse earlier if (!ValidateHTTPRequest()) return false; @@ -235,7 +245,7 @@ namespace proxy return true; } - bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len) + bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len) { while (len > 0) { @@ -269,13 +279,13 @@ namespace proxy case '\n': EnterState(DONE); break; default: LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); - HTTPRequestFailed(); //TODO: add correct code + HTTPRequestFailed("rejected invalid request"); return false; } break; default: LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); - HTTPRequestFailed(); //TODO: add correct code 500 + HTTPRequestFailed("invalid parser state"); return false; } http_buff++; @@ -286,7 +296,7 @@ namespace proxy return true; } - void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) + void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) { LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes"); if(ecode) @@ -301,7 +311,7 @@ namespace proxy if (m_state == DONE) { LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url); - GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete, + GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_address, m_port); } else @@ -310,14 +320,14 @@ namespace proxy } - void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode) + void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode) { if (ecode) LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ()); Terminate(); } - void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr stream) + void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr stream) { if (stream) { @@ -331,19 +341,18 @@ namespace proxy else { LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); - HTTPRequestFailed(); // TODO: Send correct error message host unreachable + HTTPRequestFailed("error when creating the stream, check logs"); } } - HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr localDestination): + HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination): TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()) { } - std::shared_ptr HTTPProxyServer::CreateHandler(std::shared_ptr socket) + std::shared_ptr HTTPProxy::CreateHandler(std::shared_ptr socket) { - return std::make_shared (this, socket); + return std::make_shared (this, socket); } - -} -} +} // http +} // i2p diff --git a/HTTPProxy.h b/HTTPProxy.h index b5ed77b9..29b997eb 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -1,32 +1,21 @@ #ifndef HTTP_PROXY_H__ #define HTTP_PROXY_H__ -#include -#include -#include -#include -#include "I2PService.h" -#include "Destination.h" - -namespace i2p -{ -namespace proxy -{ - class HTTPProxyServer: public i2p::client::TCPIPAcceptor +namespace i2p { +namespace proxy { + class HTTPProxy: public i2p::client::TCPIPAcceptor { public: - HTTPProxyServer(const std::string& address, int port, std::shared_ptr localDestination = nullptr); - ~HTTPProxyServer() {}; + HTTPProxy(const std::string& address, int port, std::shared_ptr localDestination = nullptr); + ~HTTPProxy() {}; protected: // Implements TCPIPAcceptor std::shared_ptr CreateHandler(std::shared_ptr socket); const char* GetName() { return "HTTP Proxy"; } }; - - typedef HTTPProxyServer HTTPProxy; -} -} +} // http +} // i2p #endif diff --git a/HTTPServer.cpp b/HTTPServer.cpp index b40cef27..f35e02d3 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -612,7 +612,7 @@ namespace http { HandleCommand (req, res, s); } else { ShowStatus (s); - //res.add_header("Refresh", "5"); + res.add_header("Refresh", "10"); } ShowPageTail (s); diff --git a/HTTPServer.h b/HTTPServer.h index bf7f5c65..6aa0d792 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -61,6 +61,8 @@ namespace http { boost::asio::io_service::work m_Work; boost::asio::ip::tcp::acceptor m_Acceptor; }; + + void ShowJumpServices (std::stringstream& s, const std::string& address); } // http } // i2p diff --git a/I2CP.cpp b/I2CP.cpp index 2434b486..061f220c 100644 --- a/I2CP.cpp +++ b/I2CP.cpp @@ -114,7 +114,7 @@ namespace client } } - I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr socket): + I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr socket): m_Owner (owner), m_Socket (socket), m_Payload (nullptr), m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true) { @@ -594,7 +594,12 @@ namespace client I2CPServer::I2CPServer (const std::string& interface, int port): m_IsRunning (false), m_Thread (nullptr), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port)) + m_Acceptor (m_Service, +#ifdef ANDROID + I2CPSession::proto::endpoint(std::string (1, '\0') + interface)) // leading 0 for abstract address +#else + I2CPSession::proto::endpoint(boost::asio::ip::address::from_string(interface), port)) +#endif { memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers)); m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; @@ -655,12 +660,13 @@ namespace client void I2CPServer::Accept () { - auto newSocket = std::make_shared (m_Service); + auto newSocket = std::make_shared (m_Service); m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this, std::placeholders::_1, newSocket)); } - void I2CPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) + void I2CPServer::HandleAccept(const boost::system::error_code& ecode, + std::shared_ptr socket) { if (!ecode && socket) { diff --git a/I2CP.h b/I2CP.h index 6fc0e846..4964c575 100644 --- a/I2CP.h +++ b/I2CP.h @@ -99,7 +99,14 @@ namespace client { public: - I2CPSession (I2CPServer& owner, std::shared_ptr socket); +#ifdef ANDROID + typedef boost::asio::local::stream_protocol proto; +#else + typedef boost::asio::ip::tcp proto; +#endif + + I2CPSession (I2CPServer& owner, std::shared_ptr socket); + ~I2CPSession (); void Start (); @@ -144,7 +151,7 @@ namespace client private: I2CPServer& m_Owner; - std::shared_ptr m_Socket; + std::shared_ptr m_Socket; uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload; size_t m_PayloadLen; @@ -173,7 +180,8 @@ namespace client void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); private: @@ -183,7 +191,7 @@ namespace client bool m_IsRunning; std::thread * m_Thread; boost::asio::io_service m_Service; - boost::asio::ip::tcp::acceptor m_Acceptor; + I2CPSession::proto::acceptor m_Acceptor; public: diff --git a/Makefile.linux b/Makefile.linux index 70e9e7dd..59a7d414 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -44,7 +44,7 @@ endif # UPNP Support (miniupnpc 1.5 or 1.6) ifeq ($(USE_UPNP),1) - LDFLAGS += -ldl + LDFLAGS += -lminiupnpc CXXFLAGS += -DUSE_UPNP endif diff --git a/Makefile.mingw b/Makefile.mingw index 0390d66a..682221d1 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,42 +1,47 @@ -USE_WIN32_APP=yes -CXX = g++ -WINDRES = windres -CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -NEEDED_CXXFLAGS = -std=c++11 -BOOST_SUFFIX = -mt -INCFLAGS = -I/usr/include/ -I/usr/local/include/ -LDFLAGS = -Wl,-rpath,/usr/local/lib \ - -L/usr/local/lib \ - -L/c/dev/openssl \ - -L/c/dev/boost/lib -LDLIBS = \ - -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ - -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ - -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ - -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \ - -Wl,-Bstatic -lssl \ - -Wl,-Bstatic -lcrypto \ - -Wl,-Bstatic -lz \ - -Wl,-Bstatic -lwsock32 \ - -Wl,-Bstatic -lws2_32 \ - -Wl,-Bstatic -lgdi32 \ - -Wl,-Bstatic -liphlpapi \ - -static-libgcc -static-libstdc++ \ - -Wl,-Bstatic -lstdc++ \ - -Wl,-Bstatic -lpthread - -ifeq ($(USE_WIN32_APP), yes) - CXXFLAGS += -DWIN32_APP - LDFLAGS += -mwindows -s - DAEMON_RC += Win32/Resource.rc - DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) -endif - -ifeq ($(USE_AESNI),1) - CPU_FLAGS = -maes -DAESNI -else - CPU_FLAGS = -msse -endif - -obj/%.o : %.rc - $(WINDRES) -i $< -o $@ +USE_WIN32_APP=yes +CXX = g++ +WINDRES = windres +CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +NEEDED_CXXFLAGS = -std=c++11 +BOOST_SUFFIX = -mt +INCFLAGS = -I/usr/include/ -I/usr/local/include/ +LDFLAGS = -Wl,-rpath,/usr/local/lib \ + -L/usr/local/lib + +# UPNP Support +ifeq ($(USE_UPNP),1) + CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB + LDLIBS = -Wl,-Bstatic -lminiupnpc +endif + +LDLIBS += \ + -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ + -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ + -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ + -Wl,-Bstatic -lboost_program_options$(BOOST_SUFFIX) \ + -Wl,-Bstatic -lssl \ + -Wl,-Bstatic -lcrypto \ + -Wl,-Bstatic -lz \ + -Wl,-Bstatic -lwsock32 \ + -Wl,-Bstatic -lws2_32 \ + -Wl,-Bstatic -lgdi32 \ + -Wl,-Bstatic -liphlpapi \ + -static-libgcc -static-libstdc++ \ + -Wl,-Bstatic -lstdc++ \ + -Wl,-Bstatic -lpthread + +ifeq ($(USE_WIN32_APP), yes) + CXXFLAGS += -DWIN32_APP + LDFLAGS += -mwindows -s + DAEMON_RC += Win32/Resource.rc + DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) +endif + +ifeq ($(USE_AESNI),1) + CPU_FLAGS = -maes -DAESNI +else + CPU_FLAGS = -msse +endif + +obj/%.o : %.rc + $(WINDRES) -i $< -o $@ diff --git a/Streaming.cpp b/Streaming.cpp index 1a6fdbca..e5260556 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -395,8 +395,11 @@ namespace stream } if (packets.size () > 0) { - m_IsAckSendScheduled = false; - m_AckSendTimer.cancel (); + if (m_SavedPackets.empty ()) // no NACKS + { + m_IsAckSendScheduled = false; + m_AckSendTimer.cancel (); + } bool isEmpty = m_SentPackets.empty (); auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: packets) diff --git a/UPnP.cpp b/UPnP.cpp index fea2ff9e..477342b3 100644 --- a/UPnP.cpp +++ b/UPnP.cpp @@ -6,13 +6,6 @@ #include #include -#ifdef _WIN32 -#include -#define dlsym GetProcAddress -#else -#include -#endif - #include "Log.h" #include "RouterContext.h" @@ -24,32 +17,11 @@ #include #include -// These are per-process and are safe to reuse for all threads -decltype(upnpDiscover) *upnpDiscoverFunc; -decltype(UPNP_AddPortMapping) *UPNP_AddPortMappingFunc; -decltype(UPNP_GetValidIGD) *UPNP_GetValidIGDFunc; -decltype(UPNP_GetExternalIPAddress) *UPNP_GetExternalIPAddressFunc; -decltype(UPNP_DeletePortMapping) *UPNP_DeletePortMappingFunc; -decltype(freeUPNPDevlist) *freeUPNPDevlistFunc; -decltype(FreeUPNPUrls) *FreeUPNPUrlsFunc; - -// 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(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?"); - } - return proc; -} -#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func); - - namespace i2p { namespace transport { - UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false) + UPnP::UPnP () : m_Thread (nullptr) { } @@ -65,33 +37,6 @@ namespace transport 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 (eLogError, "UPnP: Error loading UPNP library, 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)); } @@ -123,16 +68,16 @@ namespace transport { int nerror = 0; #if MINIUPNPC_API_VERSION >= 14 - m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror); + m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror); #else - m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); + m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); #endif int r; - r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); + r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); if (r == 1) { - r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); + r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); if(r != UPNPCOMMAND_SUCCESS) { LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r); @@ -171,7 +116,7 @@ namespace transport std::string strDesc = "I2Pd"; try { for (;;) { - 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"); + r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); if (r!=UPNPCOMMAND_SUCCESS) { LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); @@ -208,20 +153,15 @@ namespace transport strType = "UDP"; } int r = 0; - r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0); + r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n"); } void UPnP::Close () { - freeUPNPDevlistFunc (m_Devlist); + freeUPNPDevlist (m_Devlist); m_Devlist = 0; - FreeUPNPUrlsFunc (&m_upnpUrls); -#ifndef _WIN32 - dlclose (m_Module); -#else - FreeLibrary (m_Module); -#endif + FreeUPNPUrls (&m_upnpUrls); } } diff --git a/UPnP.h b/UPnP.h index 32c42118..0a000177 100644 --- a/UPnP.h +++ b/UPnP.h @@ -48,12 +48,6 @@ namespace transport struct UPNPDev * m_Devlist = 0; char m_NetworkAddr[64]; char m_externalIPAddress[40]; - bool m_IsModuleLoaded; -#ifndef _WIN32 - void *m_Module; -#else - HINSTANCE m_Module; -#endif }; } } diff --git a/debian/tunnels.conf b/debian/tunnels.conf index f710b70c..fa92a56b 100644 --- a/debian/tunnels.conf +++ b/debian/tunnels.conf @@ -1,7 +1,33 @@ [IRC] type = client +address = 127.0.0.1 port = 6668 destination = irc.postman.i2p +destinationport = 6667 keys = irc-keys.dat +#[SMTP] +#type = client +#address = 127.0.0.1 +#port = 7659 +#destination = smtp.postman.i2p +#destinationport = 25 +#keys = smtp-keys.dat + +#[POP3] +#type = client +#address = 127.0.0.1 +#port = 7660 +#destination = pop.postman.i2p +#destinationport = 110 +#keys = pop3-keys.dat + +#[MTN] +#type = client +#address = 127.0.0.1 +#port = 8998 +#destination = mtn.i2p-projekt.i2p +#destinationport = 4691 +#keys = mtn-keys.dat + # see more examples in /usr/share/doc/i2pd/configuration.md.gz diff --git a/docs/build_notes_windows.md b/docs/build_notes_windows.md index 921a6110..8ba36131 100644 --- a/docs/build_notes_windows.md +++ b/docs/build_notes_windows.md @@ -164,6 +164,13 @@ folder name included in downloaded archive. Note that you might need to build DLL yourself for 64-bit systems using msys2 as 64-bit DLLs are not provided by the project. +You can also install it through the MSYS2 +and build with USE_UPNP key. + +```bash +pacman -S mingw-w64-i686-miniupnpc +make USE_UPNP=1 +``` ### Creating Visual Studio project diff --git a/docs/configuration.md b/docs/configuration.md index 9ab85b46..1b3e899b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -41,7 +41,7 @@ All options below still possible in cmdline, but better write it in config file: * --http.pass= - Password for basic auth (default: random, see logs) * --httpproxy.address= - The address to listen on (HTTP Proxy) -* --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default +* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default * --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) * --httpproxy.enabled= - If HTTP proxy is enabled. true by default @@ -60,9 +60,9 @@ All options below still possible in cmdline, but better write it in config file: * --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified * --bob.enabled= - If BOB is enabled. false by default -* --i2cp.address= - The address to listen on -* --i2cp.port= - Port of I2CP server. Usually 7654. IPCP is off if not specified -* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't requeire I2CP +* --i2cp.address= - The address to listen on or an abstract address for Android LocalSocket +* --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid +* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP * --i2pcontrol.address= - The address to listen on (I2P control service) * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified diff --git a/docs/i2pd.conf b/docs/i2pd.conf index d4ea226a..16314274 100644 --- a/docs/i2pd.conf +++ b/docs/i2pd.conf @@ -42,14 +42,18 @@ ## Port to listen for connections ## By default i2pd picks random port. You MUST pick a random number too, ## don't just uncomment this -# port = 4321 +# port = 4567 + +## Enable communication through ipv4 +ipv4 = true ## Enable communication through ipv6 -ipv6 = true +ipv6 = false ## Bandwidth configuration -## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited -## Default is P for floodfill, L for regular node +## L limit bandwidth to 32Kbs/sec, O - to 256Kbs/sec, P - to 2048Kbs/sec, +## X - unlimited +## Default is X for floodfill, L for regular node # bandwidth = L ## Router will not accept transit tunnels at startup @@ -58,6 +62,15 @@ ipv6 = true ## Router will be floodfill # floodfill = true +[limits] +## Maximum active transit sessions (default:2500) +# transittunnels = 2500 + +[precomputation] +## Enable or disable elgamal precomputation table +## By default, enabled on i386 hosts +# elgamal = true + [http] ## Uncomment and set to 'false' to disable Web Console # enabled = true @@ -78,10 +91,11 @@ port = 4444 ## Uncomment and set to 'false' to disable SOCKS Proxy # enabled = true ## Address and port service will listen on -# address = 127.0.0.1 -# port = 4447 +address = 127.0.0.1 +port = 4447 ## Optional keys file for proxy local destination # keys = socks-proxy-keys.dat + ## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Address and port of outproxy # outproxy = 127.0.0.1 @@ -101,6 +115,13 @@ port = 4444 # address = 127.0.0.1 # port = 2827 +[i2cp] +## Uncomment and set to 'true' to enable I2CP protocol +# enabled = false +## Address and port service will listen on +# address = 127.0.0.1 +# port = 7654 + [i2pcontrol] ## Uncomment and set to 'true' to enable I2PControl protocol # enabled = false diff --git a/qt/i2pd_qt/android/AndroidManifest.xml b/qt/i2pd_qt/android/AndroidManifest.xml index 6ab763ff..37a736fd 100644 --- a/qt/i2pd_qt/android/AndroidManifest.xml +++ b/qt/i2pd_qt/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index c3b38a8c..b3829fcc 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -11,14 +11,17 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app QMAKE_CXXFLAGS *= -std=c++11 +DEFINES += USE_UPNP # git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -BOOST_PATH = /mnt/media/android/Boost-for-Android-Prebuilt -OPENSSL_PATH = /mnt/media/android/OpenSSL-for-Android-Prebuilt -IFADDRS_PATH = /mnt/media/android/android-ifaddrs +BOOST_PATH = /home/rebby/andp/Boost-for-Android-Prebuilt +OPENSSL_PATH = /home/rebby/andp/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = /home/rebby/andp/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = /home/rebby/andp/android-ifaddrs # Steps in Android SDK manager: # 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html @@ -27,7 +30,7 @@ IFADDRS_PATH = /mnt/media/android/android-ifaddrs SOURCES += DaemonQT.cpp\ mainwindow.cpp \ - ../../HTTPServer.cpp ../../I2PControl.cpp ../../UPnP.cpp ../../Daemon.cpp ../../Config.cpp \ + ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \ ../../AddressBook.cpp \ ../../api.cpp \ ../../Base.cpp \ @@ -69,9 +72,9 @@ SOURCES += DaemonQT.cpp\ ../../TunnelEndpoint.cpp \ ../../TunnelGateway.cpp \ ../../TunnelPool.cpp \ + ../../UPnP.cpp \ ../../util.cpp \ - ../../i2pd.cpp \ - $$IFADDRS_PATH/ifaddrs.c + ../../i2pd.cpp HEADERS += DaemonQT.h mainwindow.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ @@ -122,9 +125,9 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../TunnelEndpoint.h \ ../../TunnelGateway.h \ ../../TunnelPool.h \ + ../../UPnP.h \ ../../util.h \ - ../../version.h \ - $$IFADDRS_PATH/ifaddrs.h + ../../version.h FORMS += mainwindow.ui @@ -138,14 +141,19 @@ android { message("Using Android settings") DEFINES += ANDROID=1 DEFINES += __ANDROID__ + INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ $$OPENSSL_PATH/openssl-1.0.2/include \ + $$MINIUPNP_PATH/miniupnp-2.0/include \ $$IFADDRS_PATH DISTFILES += \ android/AndroidManifest.xml ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android +SOURCES += $$IFADDRS_PATH/ifaddrs.c ../../UPnP.cpp +HEADERS += $$IFADDRS_PATH/ifaddrs.h + equals(ANDROID_TARGET_ARCH, armeabi-v7a){ DEFINES += ANDROID_ARM7A @@ -156,7 +164,8 @@ LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ -lboost_date_time-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 \ -lboost_program_options-gcc-mt-1_53 \ --L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl +-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \ +-L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a @@ -164,7 +173,8 @@ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so + $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so } equals(ANDROID_TARGET_ARCH, x86){ # http://stackoverflow.com/a/30235934/529442 @@ -173,7 +183,8 @@ LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ -lboost_date_time-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 \ -lboost_program_options-gcc-mt-1_53 \ --L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl +-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \ +-L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a @@ -181,12 +192,13 @@ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so + $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so } } linux:!android { message("Using Linux settings") -LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread +LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc } diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index c1654295..ab872ff4 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -1,6 +1,8 @@ #include "mainwindow.h" //#include "ui_mainwindow.h" #include +#include +#include "../../RouterContext.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)/*, @@ -22,20 +24,29 @@ MainWindow::MainWindow(QWidget *parent) : verticalLayout1->setContentsMargins(0, 0, 0, 0); quitButton = new QPushButton(verticalLayoutWidget); quitButton->setObjectName(QStringLiteral("quitButton")); - QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + sizePolicy.setHorizontalStretch(1); + //sizePolicy.setVerticalStretch(1); sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth()); quitButton->setSizePolicy(sizePolicy); - verticalLayout1->addWidget(quitButton); + gracefulQuitButton = new QPushButton(verticalLayoutWidget); + gracefulQuitButton->setObjectName(QStringLiteral("gracefulQuitButton")); + QSizePolicy sizePolicy2(QSizePolicy::Maximum, QSizePolicy::Maximum); + sizePolicy2.setHorizontalStretch(1); + //sizePolicy2.setVerticalStretch(1); + sizePolicy2.setHeightForWidth(gracefulQuitButton->sizePolicy().hasHeightForWidth()); + gracefulQuitButton->setSizePolicy(sizePolicy2); + verticalLayout1->addWidget(gracefulQuitButton); setCentralWidget(centralWidget); setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0)); quitButton->setText(QApplication::translate("MainWindow", "Quit", 0)); + gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful Quit", 0)); QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton())); + QObject::connect(gracefulQuitButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton())); //QMetaObject::connectSlotsByName(this); } @@ -46,6 +57,23 @@ void MainWindow::handleQuitButton() { QApplication::instance()->quit(); } +void MainWindow::handleGracefulQuitButton() { + qDebug("Graceful Quit pressed."); + gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0)); + gracefulQuitButton->setEnabled(false); + gracefulQuitButton->adjustSize(); + verticalLayoutWidget->adjustSize(); + i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels + QTimer::singleShot(10*60*1000/*millis*/, this, SLOT(handleGracefulQuitTimerEvent())); +} + +void MainWindow::handleGracefulQuitTimerEvent() { + qDebug("Hiding the main window"); + close(); + qDebug("Performing quit"); + QApplication::instance()->quit(); +} + MainWindow::~MainWindow() { qDebug("Destroying main window"); diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index 3a172c25..94e3a7b3 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -27,12 +27,15 @@ public: private slots: void handleQuitButton(); + void handleGracefulQuitButton(); + void handleGracefulQuitTimerEvent(); private: QWidget *centralWidget; QWidget *verticalLayoutWidget; QVBoxLayout *verticalLayout1; QPushButton *quitButton; + QPushButton *gracefulQuitButton; }; #endif // MAINWINDOW_H diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index bdb57867..d73e7743 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -37,6 +37,13 @@ + + + + Graceful Quit + + + @@ -60,8 +67,25 @@ + + gracefulShutdownButton + released() + MainWindow + handleGracefulQuitButton() + + + 395 + 319 + + + 399 + 239 + + + handleQuitButton() + handleGracefulQuitButton()