diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 566ad53e..a811ad45 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -22,6 +22,9 @@ #include "HTTPServer.h" #include "Daemon.h" #include "util.h" +#ifdef WIN32_APP +#include "Win32/Win32App.h" +#endif // For image and info #include "version.h" @@ -409,15 +412,21 @@ namespace http { else s << " Accept transit tunnels
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - if (Daemon.gracefullShutdownInterval) { + if (Daemon.gracefullShutdownInterval) + { s << " Cancel gracefull shutdown ("; s << Daemon.gracefullShutdownInterval; s << " seconds remains)
\r\n"; - } else { + } + else + { s << " Start gracefull shutdown
\r\n"; } - s << " Force shutdown
\r\n"; #endif +#ifdef WIN32_APP + s << " Gracefull shutdown
\r\n"; +#endif + s << " Force shutdown
\r\n"; } void ShowTransitTunnels (std::stringstream& s) @@ -723,6 +732,9 @@ namespace http { i2p::context.SetAcceptsTunnels (false); #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) Daemon.gracefullShutdownInterval = 10*60; +#endif +#ifdef WIN32_APP + i2p::win32::GracefulShutdown (); #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { i2p::context.SetAcceptsTunnels (true); @@ -770,12 +782,14 @@ namespace http { std::string pass; i2p::config::GetOption("http.pass", pass); /* generate pass if needed */ if (needAuth && pass == "") { + uint8_t random[16]; char alnum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; - pass.resize(16); - for (size_t i = 0; i < pass.size(); i++) { - pass[i] = alnum[rand() % (sizeof(alnum) - 1)]; + pass.resize(sizeof(random)); + RAND_bytes(random, sizeof(random)); + for (size_t i = 0; i < sizeof(random); i++) { + pass[i] = alnum[random[i] % (sizeof(alnum) - 1)]; } i2p::config::SetOption("http.pass", pass); LogPrint(eLogInfo, "HTTPServer: password set to ", pass); diff --git a/Makefile.mingw b/Makefile.mingw index 5cf16bf5..85b6b455 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -9,7 +9,7 @@ LDFLAGS = -Wl,-rpath,/usr/local/lib \ -L/usr/local/lib # UPNP Support -ifeq ($(USE_UPNP),yes) +ifeq ($(USE_UPNP),yes) CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB LDLIBS = -Wl,-Bstatic -lminiupnpc endif @@ -37,7 +37,7 @@ ifeq ($(USE_WIN32_APP), yes) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif -ifeq ($(USE_AESNI),yes) +ifeq ($(USE_AESNI),1) CPU_FLAGS = -maes -DAESNI else CPU_FLAGS = -msse diff --git a/NetDb.cpp b/NetDb.cpp index f5b51064..1752f1a9 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,7 +14,6 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" -#include "util.h" using namespace i2p::transport; diff --git a/UPnP.h b/UPnP.h index 4013b3df..f62ce402 100644 --- a/UPnP.h +++ b/UPnP.h @@ -13,8 +13,6 @@ #include -#include "util.h" - namespace i2p { namespace transport diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 01432381..7da8f882 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -2,6 +2,7 @@ #include #include #include "../Config.h" +#include "../RouterContext.h" #include "../version.h" #include "resource.h" #include "Win32App.h" @@ -15,10 +16,13 @@ #define ID_EXIT 2001 #define ID_CONSOLE 2002 #define ID_APP 2003 +#define ID_GRACEFUL_SHUTDOWN 2004 #define ID_TRAY_ICON 2050 #define WM_TRAYICON (WM_USER + 1) +#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100 + namespace i2p { namespace win32 @@ -30,6 +34,7 @@ namespace win32 InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, NULL, NULL); + InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); @@ -82,6 +87,7 @@ namespace win32 case WM_CLOSE: { RemoveTrayIcon (hWnd); + KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); PostQuitMessage (0); break; } @@ -101,6 +107,12 @@ namespace win32 PostMessage (hWnd, WM_CLOSE, 0, 0); return 0; } + case ID_GRACEFUL_SHUTDOWN: + { + i2p::context.SetAcceptsTunnels (false); + SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes + return 0; + } case ID_CONSOLE: { char buf[30]; @@ -167,6 +179,15 @@ namespace win32 } break; } + case WM_TIMER: + { + if (wParam == IDT_GRACEFUL_SHUTDOWN_TIMER) + { + PostMessage (hWnd, WM_CLOSE, 0, 0); // exit + return 0; + } + break; + } } return DefWindowProc( hWnd, uMsg, wParam, lParam); } @@ -218,5 +239,13 @@ namespace win32 { UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); } + + bool GracefulShutdown () + { + HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); + if (hWnd) + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); + return hWnd; + } } } diff --git a/Win32/Win32App.h b/Win32/Win32App.h index 7d35ec1e..3babffa9 100644 --- a/Win32/Win32App.h +++ b/Win32/Win32App.h @@ -10,6 +10,7 @@ namespace win32 bool StartWin32App (); void StopWin32App (); int RunWin32App (); + bool GracefulShutdown (); } } #endif // WIN32APP_H__ diff --git a/docs/configuration.md b/docs/configuration.md index e6ac74d2..8bd072b9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -109,7 +109,7 @@ tunnels.conf: # * 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 # * address -- local interface to bind - # * signaturetype -- signature type for new destination. 0,1 or 7 + # * signaturetype -- signature type for new destination. 0 (DSA/SHA1), 1 (EcDSA/SHA256) or 7 (EdDSA/SHA512) [IRC] type = client address = 127.0.0.1 diff --git a/util.cpp b/util.cpp index 08ee6672..ca2b61c2 100644 --- a/util.cpp +++ b/util.cpp @@ -1,12 +1,7 @@ #include #include -#include -#include -#include -#include -#include #include -#include + #include "util.h" #include "Log.h" @@ -60,158 +55,6 @@ namespace i2p { namespace util { -namespace http -{ - std::string GetHttpContent (std::istream& response) - { - std::string version, statusMessage; - response >> version; // HTTP version - int status; - response >> status; // status - std::getline (response, statusMessage); - if (status == 200) // OK - { - bool isChunked = false; - std::string header; - while (!response.eof () && header != "\r") - { - std::getline(response, header); - auto colon = header.find (':'); - if (colon != std::string::npos) - { - std::string field = header.substr (0, colon); - std::transform(field.begin(), field.end(), field.begin(), ::tolower); - if (field == i2p::util::http::TRANSFER_ENCODING) - isChunked = (header.find ("chunked", colon + 1) != std::string::npos); - } - } - - std::stringstream ss; - if (isChunked) - MergeChunkedResponse (response, ss); - else - ss << response.rdbuf(); - return ss.str(); - } - else - { - LogPrint (eLogError, "HTTPClient: error, server responds ", status); - return ""; - } - } - - void MergeChunkedResponse (std::istream& response, std::ostream& merged) - { - while (!response.eof ()) - { - std::string hexLen; - size_t len; - std::getline (response, hexLen); - std::istringstream iss (hexLen); - iss >> std::hex >> len; - if (!len || len > 10000000L) // 10M - { - LogPrint (eLogError, "Unexpected chunk length ", len); - break; - } - char * buf = new char[len]; - response.read (buf, len); - merged.write (buf, len); - delete[] buf; - std::getline (response, hexLen); // read \r\n after chunk - } - } - - url::url(const std::string& url_s) - { - portstr_ = "80"; - port_ = 80; - user_ = ""; - pass_ = ""; - - parse(url_s); - } - - - // code for parser tests - //{ - // i2p::util::http::url u_0("http://127.0.0.1:7070/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_1("http://user:password@site.com:8080/asdasd?qqqqqqqqqqqqq"); - // i2p::util::http::url u_2("http://user:password@site.com/asdasd?qqqqqqqqqqqqqq"); - // i2p::util::http::url u_3("http://user:@site.com/asdasd?qqqqqqqqqqqqq"); - // i2p::util::http::url u_4("http://user@site.com/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_5("http://@site.com:800/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_6("http://@site.com:err_port/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_7("http://user:password@site.com:err_port/asdasd?qqqqqqqqqqqq"); - //} - void url::parse(const std::string& url_s) - { - const std::string prot_end("://"); - std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - std::ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - std::ptr_fun(tolower)); // host is icase - - // parse user/password - auto user_pass_i = find(host_.begin(), host_.end(), '@'); - if (user_pass_i != host_.end()) - { - std::string user_pass = std::string(host_.begin(), user_pass_i); - auto pass_i = find(user_pass.begin(), user_pass.end(), ':'); - if (pass_i != user_pass.end()) - { - user_ = std::string(user_pass.begin(), pass_i); - pass_ = std::string(pass_i + 1, user_pass.end()); - } - else - user_ = user_pass; - - host_.assign(user_pass_i + 1, host_.end()); - } - - // parse port - auto port_i = find(host_.begin(), host_.end(), ':'); - if (port_i != host_.end()) - { - portstr_ = std::string(port_i + 1, host_.end()); - host_.assign(host_.begin(), port_i); - try{ - port_ = boost::lexical_cast(portstr_); - } - catch (std::exception e) { - port_ = 80; - } - } - - std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); - } - - std::string urlDecode(const std::string& data) - { - std::string res(data); - for (size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%',pos+1)) - { - char c = strtol(res.substr(pos+1,2).c_str(), NULL, 16); - res.replace(pos,3,1,c); - } - return res; - } -} - namespace net { #ifdef WIN32 diff --git a/util.h b/util.h index 642ecc9b..77b94995 100644 --- a/util.h +++ b/util.h @@ -22,7 +22,6 @@ namespace i2p { namespace util { - /** wrapper arround boost::lexical_cast that "never" fails */ @@ -34,34 +33,6 @@ namespace util return fallback; } } - - namespace http - { - // in (lower case) - const char ETAG[] = "etag"; // ETag - const char LAST_MODIFIED[] = "last-modified"; // Last-Modified - const char TRANSFER_ENCODING[] = "transfer-encoding"; // Transfer-Encoding - const char CONTENT_ENCODING[] = "content-encoding"; // Content-Encoding - // out - const char IF_NONE_MATCH[] = "If-None-Match"; - const char IF_MODIFIED_SINCE[] = "If-Modified-Since"; - - std::string GetHttpContent (std::istream& response); - void MergeChunkedResponse (std::istream& response, std::ostream& merged); - std::string urlDecode(const std::string& data); - - struct url { - url(const std::string& url_s); // omitted copy, ==, accessors, ... - private: - void parse(const std::string& url_s); - public: - std::string protocol_, host_, path_, query_; - std::string portstr_; - unsigned int port_; - std::string user_; - std::string pass_; - }; - } namespace net {