summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ZeroTierUI/installdialog.h2
-rw-r--r--ZeroTierUI/main.cpp104
-rw-r--r--ext/installfiles/windows/ZeroTier One.aip31
-rw-r--r--main.cpp115
-rw-r--r--windows/ZeroTierOne/ServiceInstaller.cpp7
-rw-r--r--windows/ZeroTierOne/ZeroTierOneService.cpp33
-rw-r--r--windows/ZeroTierOne/ZeroTierOneService.h16
7 files changed, 238 insertions, 70 deletions
diff --git a/ZeroTierUI/installdialog.h b/ZeroTierUI/installdialog.h
index 498bc16b..2b38a775 100644
--- a/ZeroTierUI/installdialog.h
+++ b/ZeroTierUI/installdialog.h
@@ -38,6 +38,8 @@
#include "../node/Address.hpp"
+// Right now InstallDialog is only used on Mac
+
namespace Ui {
class InstallDialog;
}
diff --git a/ZeroTierUI/main.cpp b/ZeroTierUI/main.cpp
index c2849edc..84e1e121 100644
--- a/ZeroTierUI/main.cpp
+++ b/ZeroTierUI/main.cpp
@@ -25,6 +25,10 @@
* LLC. Start here: http://www.zerotier.com/
*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "mainwindow.h"
#include "installdialog.h"
#include "licensedialog.h"
@@ -33,12 +37,62 @@
#include <QDir>
#include <QString>
#include <QFont>
+#include <QMessageBox>
+
+#include "../node/Constants.hpp"
+#include "../node/Defaults.hpp"
#ifdef __WINDOWS__
#include <WinSock2.h>
#include <windows.h>
-#endif
+#include "../windows/ZeroTierOne/ZeroTierOneService.h"
+
+// Returns true if started or already running, false if failed or not installed
+static bool startWindowsService()
+{
+ SERVICE_STATUS ssSvcStatus;
+ SC_HANDLE schSCManager = NULL;
+ SC_HANDLE schService = NULL;
+
+ schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+ if (schSCManager == NULL)
+ return false;
+
+ schService = OpenService(schSCManager, ZT_SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
+ if (schService == NULL) {
+ CloseServiceHandle(schSCManager);
+ return false;
+ }
+
+ int tries = 0;
+ bool running = true;
+
+ for(;;) {
+ memset(&ssSvcStatus,0,sizeof(ssSvcStatus));
+ if ((++tries > 20)||(!QueryServiceStatus(schService,&ssSvcStatus))) {
+ running = false;
+ break;
+ }
+
+ if (ssSvcStatus.dwCurrentState == SERVICE_RUNNING) {
+ break;
+ } else if (ssSvcStatus.dwCurrentState == SERVICE_START_PENDING) {
+ Sleep(500);
+ continue;
+ }
+
+ memset(&ssSvcStatus,0,sizeof(ssSvcStatus));
+ ControlService(schService, SERVICE_CONTROL_START, &ssSvcStatus);
+ Sleep(500);
+ }
+
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+ return running;
+}
+#endif // __WINDOWS__
+// Globally visible settings for the app
QSettings *settings = (QSettings *)0;
int main(int argc, char *argv[])
@@ -46,6 +100,7 @@ int main(int argc, char *argv[])
QApplication a(argc, argv);
#ifdef __WINDOWS__
+ // Start up Winsock2
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);
@@ -65,12 +120,11 @@ int main(int argc, char *argv[])
// InstallDialog is an alternative main window. It will re-launch the app
// when done.
InstallDialog id;
+ id.setStyleSheet(a.styleSheet());
id.show();
return a.exec();
}
-#endif
-#ifdef __APPLE__
{
// Put QSettings here because this is one of the writable directories allowed
// in Apple's app store sandbox specs. We might end up in app store someday.
@@ -78,7 +132,7 @@ int main(int argc, char *argv[])
QDir::root().mkpath(zt1AppSupport);
settings = new QSettings(zt1AppSupport + "/ui.ini",QSettings::IniFormat);
}
-#else
+#else // on non-Apple boxen put it in the standard place using the default format
settings = new QSettings("ZeroTier Networks","ZeroTier One");
#endif
@@ -88,6 +142,48 @@ int main(int argc, char *argv[])
ld.exec();
}
+#ifdef __WINDOWS__
+ {
+ bool winSvcInstalled = false;
+ while (!startWindowsService()) {
+ if (winSvcInstalled) {
+ // Service was installed and subsequently failed to start again, so
+ // something is wrong!
+ QMessageBox::critical((QWidget *)0,"Service Not Available","Unable to locate or start ZeroTier One service. There may be a problem with the installation. Try installing from the .msi file again or e-mail contact@zerotier.com if you cannot install. (Error: service failed to start)",QMessageBox::Ok);
+ return 1;
+ }
+
+#ifdef _WIN64
+ BOOL is64Bit = TRUE;
+#else
+ BOOL is64Bit = FALSE;
+ IsWow64Process(GetCurrentProcess(),&is64Bit);
+#endif
+ std::string exe(ZeroTier::ZT_DEFAULTS.defaultHomePath + "\\zerotier-one_");
+ exe.append((is64Bit == TRUE) ? "x64.exe" : "x86.exe");
+
+ if (QFile::exists(exe.c_str())) {
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+ memset(&si,0,sizeof(si));
+ memset(&pi,0,sizeof(pi));
+ if (CreateProcessA(NULL,const_cast <LPSTR>((exe + " -I").c_str()),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi)) {
+ WaitForSingleObject(pi.hProcess,INFINITE);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ winSvcInstalled = true;
+ }
+ }
+
+ if (!winSvcInstalled) {
+ // Service failed to install -- installation problem like missing .exe
+ QMessageBox::critical((QWidget *)0,"Service Not Available","Unable to locate or start ZeroTier One service. There may be a problem with the installation. Try installing from the .msi file again or e-mail contact@zerotier.com if you cannot install. (Error: service not installed)",QMessageBox::Ok);
+ return 1;
+ }
+ }
+ }
+#endif
+
MainWindow w;
w.show();
return a.exec();
diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip
index d03c0aaf..e8208817 100644
--- a/ext/installfiles/windows/ZeroTier One.aip
+++ b/ext/installfiles/windows/ZeroTier One.aip
@@ -38,32 +38,56 @@
<ROW Directory="ZeroTier_1_Dir" Directory_Parent="ProgramFilesFolder" DefaultDir="ZeroTier"/>
<ROW Directory="ZeroTier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="ZeroTier"/>
<ROW Directory="networks.d_Dir" Directory_Parent="One_Dir" DefaultDir="networks.d"/>
+ <ROW Directory="platforms_Dir" Directory_Parent="One_1_Dir" DefaultDir="PLATFO~1|platforms"/>
<ROW Directory="tapwindows_Dir" Directory_Parent="One_Dir" DefaultDir="TAP-WI~1|tap-windows"/>
<ROW Directory="updates.d_Dir" Directory_Parent="One_Dir" DefaultDir="updates.d"/>
<ROW Directory="x64_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x64"/>
<ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
- <ROW Component="One" ComponentId="{5CAAC183-3291-4660-9065-438314DC5181}" Directory_="One_1_Dir" Attributes="0"/>
<ROW Component="ProductInformation" ComponentId="{DB078D04-EA8E-4A7C-9001-89BAD932F9D9}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
+ <ROW Component="Qt5Core.dll" ComponentId="{F6BFD713-0DD7-411C-BE9A-7A5A902814F2}" Directory_="One_1_Dir" Attributes="0" KeyPath="Qt5Core.dll"/>
+ <ROW Component="Qt5Gui.dll" ComponentId="{9005A0ED-9E05-4E7B-8083-AC57131BCF98}" Directory_="One_1_Dir" Attributes="0" KeyPath="Qt5Gui.dll"/>
+ <ROW Component="Qt5Network.dll" ComponentId="{0ECD4DCF-8E1D-4FF7-BB0D-3A9E1629AFC7}" Directory_="One_1_Dir" Attributes="0" KeyPath="Qt5Network.dll"/>
+ <ROW Component="Qt5Widgets.dll" ComponentId="{7B35E61D-D2F2-4605-AE92-9F0E0765831D}" Directory_="One_1_Dir" Attributes="0" KeyPath="Qt5Widgets.dll"/>
<ROW Component="WdfCoinstaller01011.dll" ComponentId="{A417293D-AA26-447A-9A16-E0BCB2084CBA}" Directory_="x64_Dir" Attributes="256" KeyPath="WdfCoinstaller01011.dll"/>
<ROW Component="WdfCoinstaller01011.dll_1" ComponentId="{C629091A-4845-4BD8-9E49-3A051FDDBEF9}" Directory_="x86_Dir" Attributes="0" KeyPath="WdfCoinstaller01011.dll_1"/>
<ROW Component="devcon_x64.exe" ComponentId="{0711ACF9-EEF5-48B0-95D7-8421B74AE314}" Directory_="One_Dir" Attributes="256" KeyPath="devcon_x64.exe"/>
<ROW Component="devcon_x86.exe" ComponentId="{335F6945-AC5D-40DD-B671-C9BA9C304623}" Directory_="One_Dir" Attributes="0" KeyPath="devcon_x86.exe"/>
+ <ROW Component="icudt51.dll" ComponentId="{413E1355-FEFE-4767-95A0-8A4B61B77821}" Directory_="One_1_Dir" Attributes="0" KeyPath="icudt51.dll"/>
+ <ROW Component="icuin51.dll" ComponentId="{2BD5EEFC-E613-49B6-9CC7-01E377F2C73C}" Directory_="One_1_Dir" Attributes="0" KeyPath="icuin51.dll"/>
+ <ROW Component="icuuc51.dll" ComponentId="{CCFECFF4-2B24-4A4B-8D77-2C6E6BBEEB2C}" Directory_="One_1_Dir" Attributes="0" KeyPath="icuuc51.dll"/>
+ <ROW Component="libEGL.dll" ComponentId="{D0C896BF-4145-4C0F-8CE1-577283DA7B4A}" Directory_="One_1_Dir" Attributes="0" KeyPath="libEGL.dll"/>
+ <ROW Component="libGLESv2.dll" ComponentId="{C4DD4C75-1EA8-4679-8706-0E4CD2358D3F}" Directory_="One_1_Dir" Attributes="0" KeyPath="libGLESv2.dll"/>
<ROW Component="networks.d" ComponentId="{EF54D0DF-889F-41DC-AF5C-4E7F96AB1C8B}" Directory_="networks.d_Dir" Attributes="0"/>
+ <ROW Component="qwindows.dll" ComponentId="{5B31F279-3A03-4BED-B777-05554F7B00EF}" Directory_="platforms_Dir" Attributes="0" KeyPath="qwindows.dll"/>
<ROW Component="updates.d" ComponentId="{E07A5480-3942-4529-A976-E7764542274C}" Directory_="updates.d_Dir" Attributes="0"/>
+ <ROW Component="zerotierone_x64.exe" ComponentId="{DFCFB72D-B055-4E60-B6D8-81FF585C2183}" Directory_="One_Dir" Attributes="256" KeyPath="zerotierone_x64.exe"/>
+ <ROW Component="zerotierone_x86.exe" ComponentId="{5D2F3366-4FE1-40A4-A81A-66C49FA11F1C}" Directory_="One_Dir" Attributes="0" KeyPath="zerotierone_x86.exe"/>
<ROW Component="zttap200.cat" ComponentId="{CCBE3FBA-1D6E-4486-914D-7444954DE12B}" Directory_="x64_Dir" Attributes="0" KeyPath="zttap200.cat" Type="0"/>
<ROW Component="zttap200.cat_1" ComponentId="{BA0FB826-479C-46E8-AB2C-9017D40A99D8}" Directory_="x86_Dir" Attributes="0" KeyPath="zttap200.cat_1" Type="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
- <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="One ProductInformation WdfCoinstaller01011.dll WdfCoinstaller01011.dll_1 devcon_x64.exe devcon_x86.exe networks.d updates.d zttap200.cat zttap200.cat_1"/>
+ <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="ProductInformation Qt5Core.dll Qt5Gui.dll Qt5Network.dll Qt5Widgets.dll WdfCoinstaller01011.dll WdfCoinstaller01011.dll_1 devcon_x64.exe devcon_x86.exe icudt51.dll icuin51.dll icuuc51.dll libEGL.dll libGLESv2.dll networks.d qwindows.dll updates.d zerotierone_x64.exe zerotierone_x86.exe zttap200.cat zttap200.cat_1"/>
<ATTRIBUTE name="CurrentFeature" value="MainFeature"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
+ <ROW File="Qt5Core.dll" Component_="Qt5Core.dll" FileName="Qt5Core.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\Qt5Core.dll" SelfReg="false" NextFile="Qt5Gui.dll"/>
+ <ROW File="Qt5Gui.dll" Component_="Qt5Gui.dll" FileName="Qt5Gui.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\Qt5Gui.dll" SelfReg="false" NextFile="Qt5Network.dll"/>
+ <ROW File="Qt5Network.dll" Component_="Qt5Network.dll" FileName="QT5NET~1.DLL|Qt5Network.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\Qt5Network.dll" SelfReg="false" NextFile="Qt5Widgets.dll"/>
+ <ROW File="Qt5Widgets.dll" Component_="Qt5Widgets.dll" FileName="QT5WID~1.DLL|Qt5Widgets.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\Qt5Widgets.dll" SelfReg="false" NextFile="qwindows.dll"/>
<ROW File="WdfCoinstaller01011.dll" Component_="WdfCoinstaller01011.dll" FileName="WDFCOI~1.DLL|WdfCoinstaller01011.dll" Attributes="0" SourcePath="..\..\bin\tap-windows\x64\WdfCoinstaller01011.dll" SelfReg="false" NextFile="zttap200.cat"/>
<ROW File="WdfCoinstaller01011.dll_1" Component_="WdfCoinstaller01011.dll_1" FileName="WDFCOI~1.DLL|WdfCoinstaller01011.dll" Attributes="0" SourcePath="..\..\bin\tap-windows\x86\WdfCoinstaller01011.dll" SelfReg="false" NextFile="zttap200.cat_1"/>
<ROW File="devcon_x64.exe" Component_="devcon_x64.exe" FileName="DEVCON~1.EXE|devcon_x64.exe" Attributes="0" SourcePath="..\..\bin\devcon\devcon_x64.exe" SelfReg="false" NextFile="devcon_x86.exe" DigSign="true"/>
- <ROW File="devcon_x86.exe" Component_="devcon_x86.exe" FileName="DEVCON~2.EXE|devcon_x86.exe" Attributes="0" SourcePath="..\..\bin\devcon\devcon_x86.exe" SelfReg="false" DigSign="true"/>
+ <ROW File="devcon_x86.exe" Component_="devcon_x86.exe" FileName="DEVCON~2.EXE|devcon_x86.exe" Attributes="0" SourcePath="..\..\bin\devcon\devcon_x86.exe" SelfReg="false" NextFile="icudt51.dll" DigSign="true"/>
+ <ROW File="icudt51.dll" Component_="icudt51.dll" FileName="icudt51.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\icudt51.dll" SelfReg="false" NextFile="icuin51.dll"/>
+ <ROW File="icuin51.dll" Component_="icuin51.dll" FileName="icuin51.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\icuin51.dll" SelfReg="false" NextFile="icuuc51.dll"/>
+ <ROW File="icuuc51.dll" Component_="icuuc51.dll" FileName="icuuc51.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\icuuc51.dll" SelfReg="false" NextFile="libEGL.dll"/>
+ <ROW File="libEGL.dll" Component_="libEGL.dll" FileName="libEGL.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\libEGL.dll" SelfReg="false" NextFile="libGLESv2.dll"/>
+ <ROW File="libGLESv2.dll" Component_="libGLESv2.dll" FileName="LIBGLE~1.DLL|libGLESv2.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\libGLESv2.dll" SelfReg="false" NextFile="Qt5Core.dll"/>
+ <ROW File="qwindows.dll" Component_="qwindows.dll" FileName="qwindows.dll" Attributes="0" SourcePath="..\..\..\..\..\..\QtWin32Dlls\platforms\qwindows.dll" SelfReg="false" NextFile="zerotierone_x86.exe"/>
+ <ROW File="zerotierone_x64.exe" Component_="zerotierone_x64.exe" FileName="ZEROTI~2.EXE|zerotier-one_x64.exe" Attributes="0" SourcePath="..\..\..\windows\Build\x64\Release\zerotier-one_x64.exe" SelfReg="false" DigSign="true"/>
+ <ROW File="zerotierone_x86.exe" Component_="zerotierone_x86.exe" FileName="ZEROTI~1.EXE|zerotier-one_x86.exe" Attributes="0" SourcePath="..\..\..\windows\Build\Win32\Release\zerotier-one_x86.exe" SelfReg="false" NextFile="zerotierone_x64.exe" DigSign="true"/>
<ROW File="zttap200.cat" Component_="zttap200.cat" FileName="zttap200.cat" Attributes="0" SourcePath="..\..\bin\tap-windows\x64\zttap200.cat" SelfReg="false" NextFile="zttap200.inf"/>
<ROW File="zttap200.cat_1" Component_="zttap200.cat_1" FileName="zttap200.cat" Attributes="0" SourcePath="..\..\bin\tap-windows\x86\zttap200.cat" SelfReg="false" NextFile="zttap200.inf_1"/>
<ROW File="zttap200.inf" Component_="zttap200.cat" FileName="zttap200.inf" Attributes="0" SourcePath="..\..\bin\tap-windows\x64\zttap200.inf" SelfReg="false" NextFile="zttap200.sys"/>
@@ -133,7 +157,6 @@
<COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">
<ROW Directory_="networks.d_Dir" Component_="networks.d"/>
<ROW Directory_="updates.d_Dir" Component_="updates.d"/>
- <ROW Directory_="One_1_Dir" Component_="One"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">
<ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>
diff --git a/main.cpp b/main.cpp
index 28d8e2e8..a9c13fe4 100644
--- a/main.cpp
+++ b/main.cpp
@@ -382,7 +382,7 @@ static void sighandlerQuit(int sig)
#ifdef __WINDOWS__
// Console signal handler routine to allow CTRL+C to work, mostly for testing
-static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
+static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType)
{
switch(dwCtrlType) {
case CTRL_C_EVENT:
@@ -508,7 +508,6 @@ int main(int argc,char **argv)
#ifdef __WINDOWS__
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);
- SetConsoleCtrlHandler(&_handlerRoutine,TRUE);
#endif
if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI")))
@@ -580,7 +579,7 @@ int main(int argc,char **argv)
}
return 0;
} break;
-#endif
+#endif // __WINDOWS__
case 'h':
case '?':
default:
@@ -596,7 +595,6 @@ int main(int argc,char **argv)
break;
}
}
-
if ((!homeDir)||(strlen(homeDir) == 0))
homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
@@ -607,6 +605,7 @@ int main(int argc,char **argv)
}
mkdir(homeDir,0755); // will fail if it already exists
{
+ // Write .pid file to home folder
char pidpath[4096];
Utils::snprintf(pidpath,sizeof(pidpath),"%s/zerotier-one.pid",homeDir);
FILE *pf = fopen(pidpath,"w");
@@ -615,76 +614,78 @@ int main(int argc,char **argv)
fclose(pf);
}
}
-#else
-#ifdef __WINDOWS__
- if (IsCurrentUserLocalAdministrator() != TRUE) {
- fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
- return 1;
- }
-#endif
#endif
#ifdef __WINDOWS__
- if (!winRunFromCommandLine) {
+ if (winRunFromCommandLine) {
+ // Running in "interactive" mode (mostly for debugging)
+ if (IsCurrentUserLocalAdministrator() != TRUE) {
+ fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
+ return 1;
+ }
+ SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE);
+ // continues on to ordinary command line execution code below...
+ } else {
+ // Running from service manager
ZeroTierOneService zt1Service;
if (CServiceBase::Run(zt1Service) == TRUE) {
- // Normal termination of service process
return 0;
} else {
fprintf(stderr,"%s: unable to start service (try -h for help)"ZT_EOL_S,argv[0]);
return 1;
}
- } else
+ }
#endif
- {
- int exitCode = 0;
- try {
- node = new Node(homeDir,port,controlPort);
- switch(node->run()) {
+
+ int exitCode = 0;
+ try {
+ node = new Node(homeDir,port,controlPort);
+ switch(node->run()) {
#ifdef __WINDOWS__
- case Node::NODE_RESTART_FOR_UPGRADE: {
- const char *upgPath = node->reasonForTermination();
- if (upgPath) {
- if (!ZeroTierOneService::doStartUpgrade(std::string(upgPath))) {
- exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (doStartUpgrade failed)\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
- }
- } else {
+ case Node::NODE_RESTART_FOR_UPGRADE: {
+ const char *upgPath = node->reasonForTermination();
+ if (upgPath) {
+ if (!ZeroTierOneService::doStartUpgrade(std::string(upgPath))) {
exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (no upgrade path provided)\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
- }
- } break;
-#else // __UNIX_LIKE__
- case Node::NODE_RESTART_FOR_UPGRADE: {
- const char *upgPath = node->reasonForTermination();
- // On Unix-type OSes we exec() right into the upgrade. This in turn will
- // end with us being re-launched either via the upgrade itself or something
- // like OSX's launchd.
- if (upgPath) {
- Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
- ::execl(upgPath,upgPath,(char *)0);
+ fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (doStartUpgrade failed)\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
}
+ } else {
exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
- } break;
+ fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (no upgrade path provided)\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
+ }
+ } break;
+#else // __UNIX_LIKE__
+ case Node::NODE_RESTART_FOR_UPGRADE: {
+ const char *upgPath = node->reasonForTermination();
+ // On Unix-type OSes we exec() right into the upgrade. This in turn will
+ // end with us being re-launched either via the upgrade itself or something
+ // like OSX's launchd.
+ if (upgPath) {
+ Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
+ ::execl(upgPath,upgPath,(char *)0);
+ }
+ exitCode = 3;
+ fprintf(stderr,"%s: abnormal termination: unable to execute update at %s\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
+ } break;
#endif
- case Node::NODE_UNRECOVERABLE_ERROR: {
- exitCode = 3;
- const char *termReason = node->reasonForTermination();
- fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)");
- } break;
- default:
- break;
- }
- delete node;
- node = (Node *)0;
- } catch ( ... ) {
- fprintf(stderr,"%s: unexpected exception!"ZT_EOL_S,argv[0]);
- exitCode = 3;
+ case Node::NODE_UNRECOVERABLE_ERROR: {
+ exitCode = 3;
+ const char *termReason = node->reasonForTermination();
+ fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)");
+ } break;
+ default:
+ break;
}
+ delete node;
+ node = (Node *)0;
+ } catch ( ... ) {
+ fprintf(stderr,"%s: unexpected exception!"ZT_EOL_S,argv[0]);
+ exitCode = 3;
+ }
+
#ifdef __UNIX_LIKE__
- Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
+ Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
#endif
- return exitCode;
- }
+
+ return exitCode;
}
diff --git a/windows/ZeroTierOne/ServiceInstaller.cpp b/windows/ZeroTierOne/ServiceInstaller.cpp
index 5945ecdf..d302d9f6 100644
--- a/windows/ZeroTierOne/ServiceInstaller.cpp
+++ b/windows/ZeroTierOne/ServiceInstaller.cpp
@@ -50,16 +50,19 @@ std::string InstallService(PSTR pszServiceName,
PSTR pszPassword)
{
std::string ret;
- char szPath[MAX_PATH];
+ char szPathTmp[MAX_PATH],szPath[MAX_PATH];
SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL;
- if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
+ if (GetModuleFileName(NULL, szPathTmp, ARRAYSIZE(szPath)) == 0)
{
ret = "GetModuleFileName failed, unable to get path to self";
goto Cleanup;
}
+ // Quote path in case it contains spaces
+ _snprintf_s(szPath,sizeof(szPath),"\"%s\"",szPathTmp);
+
// Open the local default service control manager database
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE);
diff --git a/windows/ZeroTierOne/ZeroTierOneService.cpp b/windows/ZeroTierOne/ZeroTierOneService.cpp
index daff0bb0..364e93cb 100644
--- a/windows/ZeroTierOne/ZeroTierOneService.cpp
+++ b/windows/ZeroTierOne/ZeroTierOneService.cpp
@@ -36,19 +36,44 @@
#include "../../node/Utils.hpp"
#pragma endregion
+#ifdef ZT_DEBUG_SERVICE
+FILE *SVCDBGfile = (FILE *)0;
+ZeroTier::Mutex SVCDBGfile_m;
+#endif
+
ZeroTierOneService::ZeroTierOneService() :
CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,FALSE),
_node((ZeroTier::Node *)0)
{
+#ifdef ZT_DEBUG_SERVICE
+ SVCDBGfile_m.lock();
+ if (!SVCDBGfile)
+ SVCDBGfile = fopen(ZT_DEBUG_SERVICE,"a");
+ SVCDBGfile_m.unlock();
+#endif
+
+ ZT_SVCDBG("ZeroTierOneService::ZeroTierOneService()\r\n");
}
ZeroTierOneService::~ZeroTierOneService(void)
{
+ ZT_SVCDBG("ZeroTierOneService::~ZeroTierOneService()\r\n");
+
+#ifdef ZT_DEBUG_SERVICE
+ SVCDBGfile_m.lock();
+ if (SVCDBGfile) {
+ fclose(SVCDBGfile);
+ SVCDBGfile = (FILE *)0;
+ }
+ SVCDBGfile_m.unlock();
+#endif
}
void ZeroTierOneService::threadMain()
throw()
{
+ ZT_SVCDBG("ZeroTierOneService::threadMain()\r\n");
+
restart_node:
try {
{
@@ -144,8 +169,8 @@ bool ZeroTierOneService::doStartUpgrade(const std::string &msiPath)
void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv)
{
- if (_node)
- return; // sanity check
+ ZT_SVCDBG("ZeroTierOneService::OnStart()\r\n");
+
try {
_thread = ZeroTier::Thread::start(this);
} catch ( ... ) {
@@ -155,6 +180,8 @@ void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv)
void ZeroTierOneService::OnStop()
{
+ ZT_SVCDBG("ZeroTierOneService::OnStop()\r\n");
+
_lock.lock();
ZeroTier::Node *n = _node;
_lock.unlock();
@@ -166,6 +193,8 @@ void ZeroTierOneService::OnStop()
void ZeroTierOneService::OnShutdown()
{
+ ZT_SVCDBG("ZeroTierOneService::OnShutdown()\r\n");
+
// stop thread on system shutdown (if it hasn't happened already)
OnStop();
}
diff --git a/windows/ZeroTierOne/ZeroTierOneService.h b/windows/ZeroTierOne/ZeroTierOneService.h
index 042a398a..2f6f733d 100644
--- a/windows/ZeroTierOne/ZeroTierOneService.h
+++ b/windows/ZeroTierOne/ZeroTierOneService.h
@@ -27,6 +27,8 @@
#pragma once
+#include <stdio.h>
+
#include "ServiceBase.h"
#include <string>
@@ -37,11 +39,23 @@
#include "../../node/Mutex.hpp"
#include "../../node/Utils.hpp"
+// Uncomment to make debugging Windows services suck slightly less hard.
+//#define ZT_DEBUG_SERVICE "C:\\ZeroTierOneServiceDebugLog.txt"
+
+#ifdef ZT_DEBUG_SERVICE
+extern FILE *SVCDBGfile;
+extern ZeroTier::Mutex SVCDBGfile_m;
+#define ZT_SVCDBG(f,...) { SVCDBGfile_m.lock(); fprintf(SVCDBGfile,f,##__VA_ARGS__); fflush(SVCDBGfile); SVCDBGfile_m.unlock(); }
+#else
+#define ZT_SVCDBG(f,...) {}
+#endif
+
#define ZT_SERVICE_NAME "ZeroTierOneService"
#define ZT_SERVICE_DISPLAY_NAME "ZeroTier One"
#define ZT_SERVICE_START_TYPE SERVICE_AUTO_START
#define ZT_SERVICE_DEPENDENCIES ""
-#define ZT_SERVICE_ACCOUNT "NT AUTHORITY\\LocalService"
+//#define ZT_SERVICE_ACCOUNT "NT AUTHORITY\\LocalService"
+#define ZT_SERVICE_ACCOUNT NULL
#define ZT_SERVICE_PASSWORD NULL
class ZeroTierOneService : public CServiceBase