Windows service work, remove old installer... not sure exactly what we're going to use.

This commit is contained in:
Adam Ierymenko 2014-02-06 22:06:27 -08:00
parent 6d17993eb6
commit 8a7486577a
7 changed files with 255 additions and 6109 deletions

368
main.cpp
View File

@ -44,6 +44,7 @@
#include <lmcons.h> #include <lmcons.h>
#include "windows/ZeroTierOne/ServiceInstaller.h" #include "windows/ZeroTierOne/ServiceInstaller.h"
#include "windows/ZeroTierOne/ServiceBase.h" #include "windows/ZeroTierOne/ServiceBase.h"
#include "windows/ZeroTierOne/ZeroTierOneService.h"
#else #else
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
@ -96,8 +97,9 @@ static void printHelp(const char *cn,FILE *out)
fprintf(out," -q - Send a query to a running service (zerotier-cli)"ZT_EOL_S); fprintf(out," -q - Send a query to a running service (zerotier-cli)"ZT_EOL_S);
fprintf(out," -i - Run idtool command (zerotier-idtool)"ZT_EOL_S); fprintf(out," -i - Run idtool command (zerotier-idtool)"ZT_EOL_S);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
fprintf(out," -I - Install Windows service"ZT_EOL_S); fprintf(out," -C - Run from command line instead of as service (Windows)"ZT_EOL_S);
fprintf(out," -R - Uninstall Windows service"ZT_EOL_S); fprintf(out," -I - Install Windows service (Windows)"ZT_EOL_S);
fprintf(out," -R - Uninstall Windows service (Windows)"ZT_EOL_S);
#endif #endif
} }
@ -379,6 +381,7 @@ static void sighandlerQuit(int sig)
#endif #endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
// Console signal handler routine to allow CTRL+C to work, mostly for testing
static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType) static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
{ {
switch(dwCtrlType) { switch(dwCtrlType) {
@ -394,183 +397,94 @@ static BOOL WINAPI _handlerRoutine(DWORD dwCtrlType)
return FALSE; return FALSE;
} }
// Returns true if this is running as the local administrator
static BOOL IsCurrentUserLocalAdministrator(void) static BOOL IsCurrentUserLocalAdministrator(void)
{ {
BOOL fReturn = FALSE; BOOL fReturn = FALSE;
DWORD dwStatus; DWORD dwStatus;
DWORD dwAccessMask; DWORD dwAccessMask;
DWORD dwAccessDesired; DWORD dwAccessDesired;
DWORD dwACLSize; DWORD dwACLSize;
DWORD dwStructureSize = sizeof(PRIVILEGE_SET); DWORD dwStructureSize = sizeof(PRIVILEGE_SET);
PACL pACL = NULL; PACL pACL = NULL;
PSID psidAdmin = NULL; PSID psidAdmin = NULL;
HANDLE hToken = NULL; HANDLE hToken = NULL;
HANDLE hImpersonationToken = NULL; HANDLE hImpersonationToken = NULL;
PRIVILEGE_SET ps; PRIVILEGE_SET ps;
GENERIC_MAPPING GenericMapping; GENERIC_MAPPING GenericMapping;
PSECURITY_DESCRIPTOR psdAdmin = NULL; PSECURITY_DESCRIPTOR psdAdmin = NULL;
SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
const DWORD ACCESS_READ = 1;
const DWORD ACCESS_WRITE = 2;
/* __try
Determine if the current thread is running as a user that is a member {
if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,TRUE,&hToken))
{
if (GetLastError() != ERROR_NO_TOKEN)
__leave;
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
__leave;
}
if (!DuplicateToken (hToken, SecurityImpersonation,&hImpersonationToken))
__leave;
if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &psidAdmin))
__leave;
psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psdAdmin == NULL)
__leave;
if (!InitializeSecurityDescriptor(psdAdmin,SECURITY_DESCRIPTOR_REVISION))
__leave;
dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD);
pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
if (pACL == NULL)
__leave;
if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
__leave;
dwAccessMask= ACCESS_READ | ACCESS_WRITE;
if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin))
__leave;
if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
__leave;
of SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
the local admins group. To do this, create a security descriptor SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
that if (!IsValidSecurityDescriptor(psdAdmin))
has a DACL which has an ACE that allows only local aministrators __leave;
dwAccessDesired = ACCESS_READ;
access. GenericMapping.GenericRead = ACCESS_READ;
Then, call AccessCheck with the current thread's token and the GenericMapping.GenericWrite = ACCESS_WRITE;
GenericMapping.GenericExecute = 0;
GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
security if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
descriptor. It will say whether the user could access an object if &GenericMapping, &ps, &dwStructureSize, &dwStatus,
&fReturn))
{
fReturn = FALSE;
__leave;
}
}
__finally
{
// Clean up.
if (pACL) LocalFree(pACL);
if (psdAdmin) LocalFree(psdAdmin);
if (psidAdmin) FreeSid(psidAdmin);
if (hImpersonationToken) CloseHandle (hImpersonationToken);
if (hToken) CloseHandle (hToken);
}
it return fReturn;
had that security descriptor. Note: you do not need to actually
create
the object. Just checking access against the security descriptor
alone
will be sufficient.
*/
const DWORD ACCESS_READ = 1;
const DWORD ACCESS_WRITE = 2;
__try
{
/*
AccessCheck() requires an impersonation token. We first get a
primary
token and then create a duplicate impersonation token. The
impersonation token is not actually assigned to the thread, but is
used in the call to AccessCheck. Thus, this function itself never
impersonates, but does use the identity of the thread. If the
thread
was impersonating already, this function uses that impersonation
context.
*/
if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,
TRUE, &hToken))
{
if (GetLastError() != ERROR_NO_TOKEN)
__leave;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
__leave;
}
if (!DuplicateToken (hToken, SecurityImpersonation,
&hImpersonationToken))
__leave;
/*
Create the binary representation of the well-known SID that
represents the local administrators group. Then create the
security
descriptor and DACL with an ACE that allows only local admins
access.
After that, perform the access check. This will determine whether
the current user is a local admin.
*/
if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &psidAdmin))
__leave;
psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (psdAdmin == NULL)
__leave;
if (!InitializeSecurityDescriptor(psdAdmin,
SECURITY_DESCRIPTOR_REVISION))
__leave;
// Compute size needed for the ACL.
dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) +
GetLengthSid(psidAdmin) - sizeof(DWORD);
pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
if (pACL == NULL)
__leave;
if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
__leave;
dwAccessMask= ACCESS_READ | ACCESS_WRITE;
if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask,
psidAdmin))
__leave;
if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
__leave;
/*
AccessCheck validates a security descriptor somewhat; set the
group
and owner so that enough of the security descriptor is filled out
to
make AccessCheck happy.
*/
SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
if (!IsValidSecurityDescriptor(psdAdmin))
__leave;
dwAccessDesired = ACCESS_READ;
/*
Initialize GenericMapping structure even though you
do not use generic rights.
*/
GenericMapping.GenericRead = ACCESS_READ;
GenericMapping.GenericWrite = ACCESS_WRITE;
GenericMapping.GenericExecute = 0;
GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
&GenericMapping, &ps, &dwStructureSize, &dwStatus,
&fReturn))
{
fReturn = FALSE;
__leave;
}
}
__finally
{
// Clean up.
if (pACL) LocalFree(pACL);
if (psdAdmin) LocalFree(psdAdmin);
if (psidAdmin) FreeSid(psidAdmin);
if (hImpersonationToken) CloseHandle (hImpersonationToken);
if (hToken) CloseHandle (hToken);
}
return fReturn;
} }
#endif // __WINDOWS__ #endif // __WINDOWS__
@ -605,6 +519,9 @@ int main(int argc,char **argv)
const char *homeDir = (const char *)0; const char *homeDir = (const char *)0;
unsigned int port = 0; unsigned int port = 0;
unsigned int controlPort = 0; unsigned int controlPort = 0;
#ifdef __WINDOWS__
bool winRunFromCommandLine = false;
#endif
for(int i=1;i<argc;++i) { for(int i=1;i<argc;++i) {
if (argv[i][0] == '-') { if (argv[i][0] == '-') {
switch(argv[i][1]) { switch(argv[i][1]) {
@ -635,6 +552,35 @@ int main(int argc,char **argv)
printHelp(argv[0],stderr); printHelp(argv[0],stderr);
return 0; return 0;
} else return ZeroTierIdTool::main(argc,argv); } else return ZeroTierIdTool::main(argc,argv);
#ifdef __WINDOWS__
case 'C':
winRunFromCommandLine = true;
break;
case 'I': { // install self as service
if (IsCurrentUserLocalAdministrator() != TRUE) {
fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
return 1;
}
std::string ret(InstallService(ZT_SERVICE_NAME,ZT_SERVICE_DISPLAY_NAME,ZT_SERVICE_START_TYPE,ZT_SERVICE_DEPENDENCIES,ZT_SERVICE_ACCOUNT,ZT_SERVICE_PASSWORD));
if (ret.length()) {
fprintf(stderr,"%s: unable to install service: %s"ZT_EOL_S,argv[0],ret.c_str());
return 3;
}
return 0;
} break;
case 'R': { // uninstall self as service
if (IsCurrentUserLocalAdministrator() != TRUE) {
fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
return 1;
}
std::string ret(UninstallService(ZT_SERVICE_NAME));
if (ret.length()) {
fprintf(stderr,"%s: unable to uninstall service: %s"ZT_EOL_S,argv[0],ret.c_str());
return 3;
}
return 0;
} break;
#endif
case 'h': case 'h':
case '?': case '?':
default: default:
@ -678,52 +624,56 @@ int main(int argc,char **argv)
#endif #endif
#endif #endif
int exitCode = 0;
try {
node = new Node(homeDir,port,controlPort);
switch(node->run()) {
case Node::NODE_RESTART_FOR_UPGRADE: {
const char *upgPath = node->reasonForTermination();
#ifdef __UNIX_LIKE__
// 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 = 2;
fprintf(stderr,"%s: abnormal termination: unable to execute update at %s\n",argv[0],(upgPath) ? upgPath : "(unknown path)");
#else // not __UNIX_LIKE
#ifdef __WINDOWS__ #ifdef __WINDOWS__
// On Windows the service checks updates.d and invokes updates if they are if (!winRunFromCommandLine) {
// found there. This only happens after exit code 4. The Windows service ZeroTierOneService zt1Service;
// will listen to stdout as well to catch the filename. if (CServiceBase::Run(zt1Service) == TRUE) {
if (upgPath) { return 0;
printf("[[[ UPDATE AVAILABLE: \"%s\" ]]]\r\n",upgPath); } else {
exitCode = 4; fprintf(stderr,"%s: unable to start service (try -h for help)"ZT_EOL_S,argv[0]);
} else { return 1;
exitCode = 2; }
} } else
#endif // __WINDOWS__ #endif
#endif // not __UNIX_LIKE__ {
} break; int exitCode = 0;
case Node::NODE_UNRECOVERABLE_ERROR: {
exitCode = 3; try {
const char *termReason = node->reasonForTermination(); node = new Node(homeDir,port,controlPort);
fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)"); switch(node->run()) {
} break; #ifndef __WINDOWS__
default: case Node::NODE_RESTART_FOR_UPGRADE: {
break; 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;
} }
delete node;
node = (Node *)0;
} catch ( ... ) {}
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str()); Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
#endif #endif
return exitCode; return exitCode;
}
} }

View File

@ -42,20 +42,21 @@
// NOTE: If the function fails to install the service, it prints the error // NOTE: If the function fails to install the service, it prints the error
// in the standard output stream for users to diagnose the problem. // in the standard output stream for users to diagnose the problem.
// //
void InstallService(PSTR pszServiceName, std::string InstallService(PSTR pszServiceName,
PSTR pszDisplayName, PSTR pszDisplayName,
DWORD dwStartType, DWORD dwStartType,
PSTR pszDependencies, PSTR pszDependencies,
PSTR pszAccount, PSTR pszAccount,
PSTR pszPassword) PSTR pszPassword)
{ {
std::string ret;
char szPath[MAX_PATH]; char szPath[MAX_PATH];
SC_HANDLE schSCManager = NULL; SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL; SC_HANDLE schService = NULL;
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0) if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
{ {
wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError()); ret = "GetModuleFileName failed, unable to get path to self";
goto Cleanup; goto Cleanup;
} }
@ -64,7 +65,7 @@ void InstallService(PSTR pszServiceName,
SC_MANAGER_CREATE_SERVICE); SC_MANAGER_CREATE_SERVICE);
if (schSCManager == NULL) if (schSCManager == NULL)
{ {
wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError()); ret = "OpenSCManager failed";
goto Cleanup; goto Cleanup;
} }
@ -86,12 +87,10 @@ void InstallService(PSTR pszServiceName,
); );
if (schService == NULL) if (schService == NULL)
{ {
wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError()); ret = "CreateService failed";
goto Cleanup; goto Cleanup;
} }
wprintf(L"%s is installed.\n", pszServiceName);
Cleanup: Cleanup:
// Centralized cleanup for all allocated resources. // Centralized cleanup for all allocated resources.
if (schSCManager) if (schSCManager)
@ -104,6 +103,8 @@ Cleanup:
CloseServiceHandle(schService); CloseServiceHandle(schService);
schService = NULL; schService = NULL;
} }
return ret;
} }
@ -119,8 +120,9 @@ Cleanup:
// NOTE: If the function fails to uninstall the service, it prints the // NOTE: If the function fails to uninstall the service, it prints the
// error in the standard output stream for users to diagnose the problem. // error in the standard output stream for users to diagnose the problem.
// //
void UninstallService(PSTR pszServiceName) std::string UninstallService(PSTR pszServiceName)
{ {
std::string ret;
SC_HANDLE schSCManager = NULL; SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL; SC_HANDLE schService = NULL;
SERVICE_STATUS ssSvcStatus = {}; SERVICE_STATUS ssSvcStatus = {};
@ -129,7 +131,7 @@ void UninstallService(PSTR pszServiceName)
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (schSCManager == NULL) if (schSCManager == NULL)
{ {
wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError()); ret = "OpenSCManager failed";
goto Cleanup; goto Cleanup;
} }
@ -138,45 +140,32 @@ void UninstallService(PSTR pszServiceName)
SERVICE_QUERY_STATUS | DELETE); SERVICE_QUERY_STATUS | DELETE);
if (schService == NULL) if (schService == NULL)
{ {
wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError()); ret = "OpenService failed (is service installed?)";
goto Cleanup; goto Cleanup;
} }
// Try to stop the service // Try to stop the service
if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus)) if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
{ {
wprintf(L"Stopping %s.", pszServiceName); Sleep(500);
Sleep(1000);
while (QueryServiceStatus(schService, &ssSvcStatus)) while (QueryServiceStatus(schService, &ssSvcStatus))
{ {
if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING) if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
{ {
wprintf(L"."); Sleep(500);
Sleep(1000);
} }
else break; else break;
} }
if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED)
{
wprintf(L"\n%s is stopped.\n", pszServiceName);
}
else
{
wprintf(L"\n%s failed to stop.\n", pszServiceName);
}
} }
// Now remove the service by calling DeleteService. // Now remove the service by calling DeleteService.
if (!DeleteService(schService)) if (!DeleteService(schService))
{ {
wprintf(L"DeleteService failed w/err 0x%08lx\n", GetLastError()); ret = "DeleteService failed (is service running?)";
goto Cleanup; goto Cleanup;
} }
wprintf(L"%s is removed.\n", pszServiceName);
Cleanup: Cleanup:
// Centralized cleanup for all allocated resources. // Centralized cleanup for all allocated resources.
if (schSCManager) if (schSCManager)
@ -189,4 +178,6 @@ Cleanup:
CloseServiceHandle(schService); CloseServiceHandle(schService);
schService = NULL; schService = NULL;
} }
return ret;
} }

View File

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <string>
// //
// FUNCTION: InstallService // FUNCTION: InstallService
@ -38,7 +39,8 @@
// NOTE: If the function fails to install the service, it prints the error // NOTE: If the function fails to install the service, it prints the error
// in the standard output stream for users to diagnose the problem. // in the standard output stream for users to diagnose the problem.
// //
void InstallService(PSTR pszServiceName, // modified for ZT1 to return an error or empty string on success
std::string InstallService(PSTR pszServiceName,
PSTR pszDisplayName, PSTR pszDisplayName,
DWORD dwStartType, DWORD dwStartType,
PSTR pszDependencies, PSTR pszDependencies,
@ -58,4 +60,5 @@ void InstallService(PSTR pszServiceName,
// NOTE: If the function fails to uninstall the service, it prints the // NOTE: If the function fails to uninstall the service, it prints the
// error in the standard output stream for users to diagnose the problem. // error in the standard output stream for users to diagnose the problem.
// //
void UninstallService(PSTR pszServiceName); // Also modified to return rather than print errors
std::string UninstallService(PSTR pszServiceName);

View File

@ -27,29 +27,81 @@
#pragma region Includes #pragma region Includes
#include "ZeroTierOneService.h" #include "ZeroTierOneService.h"
#include "../../node/Node.hpp"
#include "../../node/Defaults.hpp"
#include "../../node/Thread.hpp"
#pragma endregion #pragma endregion
using namespace ZeroTier;
ZeroTierOneService::ZeroTierOneService() : ZeroTierOneService::ZeroTierOneService() :
CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,TRUE) CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,FALSE),
_thread(new Thread()),
_node((Node *)0)
{ {
} }
ZeroTierOneService::~ZeroTierOneService(void) ZeroTierOneService::~ZeroTierOneService(void)
{ {
delete _thread;
delete _node;
}
void ZeroTierOneService::threadMain()
throw()
{
try {
// Since Windows doesn't auto-restart services, we'll restart the node
// on normal termination.
for(;;) {
switch(_node->run()) {
case Node::NODE_NORMAL_TERMINATION:
delete _node;
_node = new Node(ZT_DEFAULTS.defaultHomePath.c_str(),0,0);
break; // restart
case Node::NODE_RESTART_FOR_UPGRADE: {
} return; // terminate thread
case Node::NODE_UNRECOVERABLE_ERROR: {
std::string err("unrecoverable error: ");
const char *r = _node->reasonForTermination;
if (r)
err.append(r);
else err.append("(unknown error)");
WriteEventLogEntry(const_cast <PSTR>(err.c_str()),EVENTLOG_ERROR_TYPE);
} return; // terminate thread
default:
break;
}
}
} catch ( ... ) {
WriteEventLogEntry("unexpected exception in Node::run() or during restart",EVENTLOG_ERROR_TYPE);
}
} }
void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv) void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv)
{ {
try {
_node = new Node(ZT_DEFAULTS.defaultHomePath.c_str(),0,0);
*_thread = Thread::start(this);
} catch ( ... ) {
// shouldn't happen unless something weird occurs like out of memory...
throw (DWORD)ERROR_EXCEPTION_IN_SERVICE;
}
} }
void ZeroTierOneService::OnStop() void ZeroTierOneService::OnStop()
{ {
Node *n = _node;
_node = (Node *)0;
if (n) {
n->terminate(Node::NODE_NORMAL_TERMINATION,"Service Shutdown");
Thread::join(*_thread);
delete n;
}
} }
void ZeroTierOneService::OnPause() void ZeroTierOneService::OnShutdown()
{
}
void ZeroTierOneService::OnContinue()
{ {
// make sure it's stopped
OnStop();
} }

View File

@ -36,15 +36,29 @@
#define ZT_SERVICE_ACCOUNT "NT AUTHORITY\\LocalService" #define ZT_SERVICE_ACCOUNT "NT AUTHORITY\\LocalService"
#define ZT_SERVICE_PASSWORD NULL #define ZT_SERVICE_PASSWORD NULL
namespace ZeroTier {
class Node;
class Thread;
} // namespace ZeroTier
class ZeroTierOneService : public CServiceBase class ZeroTierOneService : public CServiceBase
{ {
public: public:
ZeroTierOneService(); ZeroTierOneService();
virtual ~ZeroTierOneService(void); virtual ~ZeroTierOneService(void);
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
protected: protected:
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
virtual void OnStop(); virtual void OnStop();
virtual void OnPause(); virtual void OnShutdown();
virtual void OnContinue();
private:
ZeroTier::Node *volatile _node;
ZeroTier::Thread *volatile _thread;
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Select a Product Configuration -->
<InstallShieldProductConfiguration>Express</InstallShieldProductConfiguration>
<!-- Select a Visual Studio Configuration / InstallShield Release -->
<Configuration>Debug</Configuration>
<InstallShieldRelease>$(Configuration)</InstallShieldRelease>
</PropertyGroup>
<ItemGroup>
<!-- The InstallShieldProject item selects the project to build -->
<InstallShieldProject Include="$(MSBuildProjectDirectory)\$(MSBuildProjectName).isl"/>
<!-- The InstallShieldReleaseFlags sets Release Flags -->
<!--<InstallShieldReleaseFlags Include=""/>-->
<!-- The InstallShieldMergeModulePath specifies what directories are
searched for Merge Modules -->
<!--<InstallShieldMergeModulePath Include=""/>-->
</ItemGroup>
<ItemGroup>
<!-- The ProjectReference items refer to any Visual Studio solutions you want to automatically probe for Project Output Groups. -->
</ItemGroup>
<ItemGroup>
<!-- The TaggedOutputs items allow you to explicitly add extra files to output groups. Each item must include both Name and OutputGroup, as well as TargetPath metadata values. -->
<!--<TaggedOutputs Include="C:\My Test Exe.exe">
<Name>My Test Project</Name>
<OutputGroup>Primary output</OutputGroup>
<TargetPath>My Test Exe.exe</TargetPath>
</TaggedOutputs> -->
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\InstallShield\2013Limited\InstallShield.targets"/>
<ItemGroup>
<ProjectReference Include="..\ZeroTierOneService\ZeroTierOneService.csproj">
<Name>ZeroTierOneService</Name>
<Project>{63D28112-9A56-42FA-9C3E-EF6C58AF09B3}</Project>
</ProjectReference>
</ItemGroup>
</Project>