Windows service works now!

This commit is contained in:
Adam Ierymenko 2014-02-27 16:28:55 -08:00
parent cbeb9c5236
commit 9d05897f7a
7 changed files with 246 additions and 78 deletions

@ -38,6 +38,8 @@
#include "../node/Address.hpp"
// Right now InstallDialog is only used on Mac
namespace Ui {
class InstallDialog;
}

@ -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();

@ -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"/>

131
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()) {
#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 {
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);
}
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;
}
#ifdef __UNIX_LIKE__
Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
#endif
return exitCode;
}
#endif
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 {
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);
}
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;
}
#ifdef __UNIX_LIKE__
Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
#endif
return exitCode;
}

@ -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);

@ -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();
}

@ -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