diff --git a/Config.cpp b/Config.cpp index 0de4d0aa..15c8ad67 100644 --- a/Config.cpp +++ b/Config.cpp @@ -125,6 +125,7 @@ namespace config { ("bandwidth", value()->default_value('-'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") + ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") #endif ; diff --git a/DaemonWin32.cpp b/DaemonWin32.cpp index 02c602f0..222d2395 100644 --- a/DaemonWin32.cpp +++ b/DaemonWin32.cpp @@ -5,6 +5,7 @@ #ifdef _WIN32 +#include "Win32/Win32Service.h" #include "Win32/Win32App.h" namespace i2p @@ -16,8 +17,46 @@ namespace i2p setlocale(LC_CTYPE, ""); SetConsoleCP(1251); SetConsoleOutputCP(1251); - setlocale(LC_ALL, "Russian"); - return Daemon_Singleton::init(argc, argv); + + if (!Daemon_Singleton::init(argc, argv)) + return false; + + std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); + if (serviceControl == "install") + { + LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); + InstallService( + SERVICE_NAME, // Name of service + SERVICE_DISPLAY_NAME, // Name to display + SERVICE_START_TYPE, // Service start type + SERVICE_DEPENDENCIES, // Dependencies + SERVICE_ACCOUNT, // Service running account + SERVICE_PASSWORD // Password of the account + ); + return false; + } + else if (serviceControl == "remove") + { + LogPrint(eLogInfo, "WinSVC: uninstalling ", SERVICE_NAME, " service"); + UninstallService(SERVICE_NAME); + return false; + } + + if (isDaemon == 1) + { + LogPrint(eLogDebug, "Daemon: running as service"); + I2PService service(SERVICE_NAME); + if (!I2PService::Run(service)) + { + LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); + return false; + } + return false; + } + else + LogPrint(eLogDebug, "Daemon: running as user"); + + return true; } bool DaemonWin32::start() @@ -37,6 +76,9 @@ namespace i2p SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE); SetStdHandle(STD_ERROR_HANDLE, INVALID_HANDLE_VALUE); } + bool insomnia; i2p::config::GetOption("insomnia", insomnia); + if (insomnia) + SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); return ret; } diff --git a/FS.cpp b/FS.cpp index e84ff1d4..19963195 100644 --- a/FS.cpp +++ b/FS.cpp @@ -9,7 +9,7 @@ #include #include -#ifdef WIN32 +#ifdef _WIN32 #include #endif @@ -108,7 +108,7 @@ namespace fs { bool HashedStorage::Init(const char * chars, size_t count) { if (!boost::filesystem::exists(root)) { - boost::filesystem::create_directory(root); + boost::filesystem::create_directories(root); } for (size_t i = 0; i < count; i++) { diff --git a/Identity.cpp b/Identity.cpp index 9d4162bf..0ca9567a 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -244,21 +244,20 @@ namespace data size_t IdentityEx::FromBase64(const std::string& s) { const size_t slen = s.length(); - uint8_t buf[slen]; // binary data can't exceed base64 - const size_t len = Base64ToByteStream (s.c_str(), slen, buf, slen); - return FromBuffer (buf, len); + std::vector buf(slen); // binary data can't exceed base64 + const size_t len = Base64ToByteStream (s.c_str(), slen, buf.data(), slen); + return FromBuffer (buf.data(), len); } std::string IdentityEx::ToBase64 () const { const size_t bufLen = GetFullLen(); const size_t strLen = Base64EncodingBufferSize(bufLen); - uint8_t buf[bufLen]; - char str[strLen]; - size_t l = ToBuffer (buf, bufLen); - size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, strLen); - str[l1] = 0; - return std::string (str); + std::vector buf(bufLen); + std::vector str(strLen); + size_t l = ToBuffer (buf.data(), bufLen); + size_t l1 = i2p::data::ByteStreamToBase64 (buf.data(), l, str.data(), strLen); + return std::string (str.data(), l1); } size_t IdentityEx::GetSigningPublicKeyLen () const diff --git a/UPnP.cpp b/UPnP.cpp index f8c038ff..0466d9e7 100644 --- a/UPnP.cpp +++ b/UPnP.cpp @@ -19,27 +19,19 @@ #include "UPnP.h" #include "NetDb.h" #include "util.h" +#include "RouterInfo.h" #include #include // These are per-process and are safe to reuse for all threads -#ifndef UPNPDISCOVER_SUCCESS -/* miniupnpc 1.5 */ -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 */ -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 -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 *); +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 @@ -109,7 +101,8 @@ namespace transport void UPnP::Run () { - for (auto& address : context.GetRouterInfo ().GetAddresses ()) + std::vector a = context.GetRouterInfo().GetAddresses(); + for (auto& address : a) { if (!address.host.is_v6 ()) { @@ -134,7 +127,11 @@ namespace transport #else /* miniupnpc 1.6 */ int nerror = 0; - m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); +#if MINIUPNPC_API_VERSION >= 15 + m_Devlist = upnpDiscoverFunc(2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 0, &nerror); +#else + m_Devlist = upnpDiscoverFunc(2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); +#endif #endif int r; diff --git a/appveyor.yml b/appveyor.yml index e190b949..6600714d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -142,9 +142,9 @@ install: - if not defined msvc ( C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel" && if "%x64%" == "1" ( - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc" + C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc" ) else ( - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-boost mingw-w64-i686-miniupnpc" + C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-openssl mingw-w64-i686-boost mingw-w64-i686-miniupnpc" ) ) cache: @@ -167,7 +167,7 @@ build_script: echo "bitness=%bitness%; static=%static%; dll=%dll%; type=%type%; generator=%generator%; variant=%variant%; cmake=%cmake%; cmake_extra=%cmake_extra%" - if not defined msvc ( - C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin && cd /c/projects/build && cmake /c/projects/i2pd/build -G 'Unix Makefiles' -DWITH_AESNI=ON -DWITH_UPNP=ON %cmake% %cmake_extra% -DWITH_STATIC=%static% -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=/c/projects/instdir -DCMAKE_FIND_ROOT_PATH=/mingw%bitness% && make install" + C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin && cd /c/projects/build && CC=/mingw%bitness%/bin/gcc.exe CXX=/mingw%bitness%/bin/g++.exe /usr/bin/cmake /c/projects/i2pd/build -G 'Unix Makefiles' -DWITH_AESNI=ON -DWITH_UPNP=ON %cmake% %cmake_extra% -DWITH_STATIC=%static% -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=/c/projects/instdir -DCMAKE_FIND_ROOT_PATH=/mingw%bitness% && make install" && 7z a -tzip -mx9 -mmt C:\projects\i2pd\i2pd-mingw-win%bitness%-%type%.zip C:\projects\instdir\* C:\msys64\mingw%bitness%\bin\zlib1.dll C:\msys64\mingw%bitness%\bin\*eay32.dll ) - rem We are fine with multiple generated configurations in MS solution. Will use later diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 577dcc66..f863bd69 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -56,7 +56,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS) endif () add_library(libi2pd ${LIBI2PD_SRC}) -set_target_properties(libi2pd PROPERTIES OUTPUT_NAME "i2pd") +set_target_properties(libi2pd PROPERTIES PREFIX "") install(TARGETS libi2pd EXPORT libi2pd ARCHIVE DESTINATION lib @@ -95,7 +95,7 @@ endif () # compiler flags customization (by vendor) if (MSVC) - add_definitions( -D_WIN32_WINNT=_WIN32_WINNT_WINXP -DWIN32_LEAN_AND_MEAN -DNOMINMAX ) #-DOPENSSL_NO_SSL2 -DOPENSSL_USE_DEPRECATED + add_definitions( -DWIN32_LEAN_AND_MEAN -DNOMINMAX ) # TODO Check & report to Boost dev, there should be no need for these two add_definitions( -DBOOST_THREAD_NO_LIB -DBOOST_CHRONO_NO_LIB ) set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL" ) @@ -157,6 +157,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp") elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS) list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp") + list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32App.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Resource.rc") endif () @@ -309,11 +310,14 @@ include(GNUInstallDirs) if (WITH_BINARY) add_executable ( "${PROJECT_NAME}" ${DAEMON_SRC} ) - if(NOT MSVC) # FIXME: incremental linker file name (.ilk) collision for dll & exe - if (WITH_STATIC) - set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static" ) - endif () - endif() + if (WIN32) + set_target_properties("${PROJECT_NAME}" PROPERTIES WIN32_EXECUTABLE TRUE ) + endif() + if(NOT MSVC) + if (WITH_STATIC) + set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static" ) + endif () + endif() if (WITH_PCH) if (MSVC) diff --git a/i2pd.cpp b/i2pd.cpp index 6167f10e..f3ac6b3f 100644 --- a/i2pd.cpp +++ b/i2pd.cpp @@ -3,10 +3,25 @@ int main( int argc, char* argv[] ) { - Daemon.init(argc, argv); - if (Daemon.start()) - Daemon.run (); - Daemon.stop(); + if (Daemon.init(argc, argv)) + { + if (Daemon.start()) + Daemon.run (); + Daemon.stop(); + } return EXIT_SUCCESS; } +#ifdef _WIN32 +#include + +int CALLBACK WinMain( + _In_ HINSTANCE hInstance, + _In_ HINSTANCE hPrevInstance, + _In_ LPSTR lpCmdLine, + _In_ int nCmdShow + ) +{ + return main(__argc, __argv); +} +#endif