From d5b50ee46621d4cdef5504419235383699873048 Mon Sep 17 00:00:00 2001
From: Adam Ierymenko <adam.ierymenko@zerotier.com>
Date: Wed, 5 Feb 2014 16:37:50 -0800
Subject: [PATCH] C++ service base stuff taken from MS public domain example
 project and modified slightly.

---
 main.cpp                                      |   6 +
 windows/ZeroTierOne/ServiceBase.cpp           | 563 ++++++++++++++++++
 windows/ZeroTierOne/ServiceBase.h             | 122 ++++
 windows/ZeroTierOne/ServiceInstaller.cpp      | 192 ++++++
 windows/ZeroTierOne/ServiceInstaller.h        |  61 ++
 windows/ZeroTierOne/ZeroTierOne.vcxproj       |   6 +
 .../ZeroTierOne/ZeroTierOne.vcxproj.filters   |  18 +
 windows/ZeroTierOne/ZeroTierOneService.cpp    |  47 ++
 windows/ZeroTierOne/ZeroTierOneService.h      |  42 ++
 9 files changed, 1057 insertions(+)
 create mode 100644 windows/ZeroTierOne/ServiceBase.cpp
 create mode 100644 windows/ZeroTierOne/ServiceBase.h
 create mode 100644 windows/ZeroTierOne/ServiceInstaller.cpp
 create mode 100644 windows/ZeroTierOne/ServiceInstaller.h
 create mode 100644 windows/ZeroTierOne/ZeroTierOneService.cpp
 create mode 100644 windows/ZeroTierOne/ZeroTierOneService.h

diff --git a/main.cpp b/main.cpp
index 97b01c600..2d94efd7c 100644
--- a/main.cpp
+++ b/main.cpp
@@ -42,6 +42,8 @@
 #include <tchar.h>
 #include <wchar.h>
 #include <lmcons.h>
+#include "windows/ZeroTierOne/ServiceInstaller.h"
+#include "windows/ZeroTierOne/ServiceBase.h"
 #else
 #include <unistd.h>
 #include <pwd.h>
@@ -93,6 +95,10 @@ static void printHelp(const char *cn,FILE *out)
 	fprintf(out,"  -c<port>          - Bind to this port for local control packets"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);
+#ifdef __WINDOWS__
+	fprintf(out,"  -I                - Install Windows service"ZT_EOL_S);
+	fprintf(out,"  -R                - Uninstall Windows service"ZT_EOL_S);
+#endif
 }
 
 namespace ZeroTierCLI { // ---------------------------------------------------
diff --git a/windows/ZeroTierOne/ServiceBase.cpp b/windows/ZeroTierOne/ServiceBase.cpp
new file mode 100644
index 000000000..59d384c5d
--- /dev/null
+++ b/windows/ZeroTierOne/ServiceBase.cpp
@@ -0,0 +1,563 @@
+/****************************** Module Header ******************************\
+* Module Name:  ServiceBase.cpp
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* Provides a base class for a service that will exist as part of a service 
+* application. CServiceBase must be derived from when creating a new service 
+* class.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma region Includes
+#include "ServiceBase.h"
+#include <assert.h>
+#include <strsafe.h>
+#include <string>
+#pragma endregion
+
+
+#pragma region Static Members
+
+// Initialize the singleton service instance.
+CServiceBase *CServiceBase::s_service = NULL;
+
+
+//
+//   FUNCTION: CServiceBase::Run(CServiceBase &)
+//
+//   PURPOSE: Register the executable for a service with the Service Control 
+//   Manager (SCM). After you call Run(ServiceBase), the SCM issues a Start 
+//   command, which results in a call to the OnStart method in the service. 
+//   This method blocks until the service has stopped.
+//
+//   PARAMETERS:
+//   * service - the reference to a CServiceBase object. It will become the 
+//     singleton service instance of this service application.
+//
+//   RETURN VALUE: If the function succeeds, the return value is TRUE. If the 
+//   function fails, the return value is FALSE. To get extended error 
+//   information, call GetLastError.
+//
+BOOL CServiceBase::Run(CServiceBase &service)
+{
+    s_service = &service;
+
+    SERVICE_TABLE_ENTRYA serviceTable[] = 
+    {
+        { service.m_name, ServiceMain },
+        { NULL, NULL }
+    };
+
+    // Connects the main thread of a service process to the service control 
+    // manager, which causes the thread to be the service control dispatcher 
+    // thread for the calling process. This call returns when the service has 
+    // stopped. The process should simply terminate when the call returns.
+    return StartServiceCtrlDispatcher(serviceTable);
+}
+
+
+//
+//   FUNCTION: CServiceBase::ServiceMain(DWORD, PWSTR *)
+//
+//   PURPOSE: Entry point for the service. It registers the handler function 
+//   for the service and starts the service.
+//
+//   PARAMETERS:
+//   * dwArgc   - number of command line arguments
+//   * lpszArgv - array of command line arguments
+//
+void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
+{
+    assert(s_service != NULL);
+
+    // Register the handler function for the service
+    s_service->m_statusHandle = RegisterServiceCtrlHandler(
+        s_service->m_name, ServiceCtrlHandler);
+    if (s_service->m_statusHandle == NULL)
+    {
+        throw GetLastError();
+    }
+
+    // Start the service.
+    s_service->Start(dwArgc, pszArgv);
+}
+
+
+//
+//   FUNCTION: CServiceBase::ServiceCtrlHandler(DWORD)
+//
+//   PURPOSE: The function is called by the SCM whenever a control code is 
+//   sent to the service. 
+//
+//   PARAMETERS:
+//   * dwCtrlCode - the control code. This parameter can be one of the 
+//   following values: 
+//
+//     SERVICE_CONTROL_CONTINUE
+//     SERVICE_CONTROL_INTERROGATE
+//     SERVICE_CONTROL_NETBINDADD
+//     SERVICE_CONTROL_NETBINDDISABLE
+//     SERVICE_CONTROL_NETBINDREMOVE
+//     SERVICE_CONTROL_PARAMCHANGE
+//     SERVICE_CONTROL_PAUSE
+//     SERVICE_CONTROL_SHUTDOWN
+//     SERVICE_CONTROL_STOP
+//
+//   This parameter can also be a user-defined control code ranges from 128 
+//   to 255.
+//
+void WINAPI CServiceBase::ServiceCtrlHandler(DWORD dwCtrl)
+{
+    switch (dwCtrl)
+    {
+    case SERVICE_CONTROL_STOP: s_service->Stop(); break;
+    case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
+    case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
+    case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
+    case SERVICE_CONTROL_INTERROGATE: break;
+    default: break;
+    }
+}
+
+#pragma endregion
+
+
+#pragma region Service Constructor and Destructor
+
+//
+//   FUNCTION: CServiceBase::CServiceBase(PWSTR, BOOL, BOOL, BOOL)
+//
+//   PURPOSE: The constructor of CServiceBase. It initializes a new instance 
+//   of the CServiceBase class. The optional parameters (fCanStop, 
+///  fCanShutdown and fCanPauseContinue) allow you to specify whether the 
+//   service can be stopped, paused and continued, or be notified when system 
+//   shutdown occurs.
+//
+//   PARAMETERS:
+//   * pszServiceName - the name of the service
+//   * fCanStop - the service can be stopped
+//   * fCanShutdown - the service is notified when system shutdown occurs
+//   * fCanPauseContinue - the service can be paused and continued
+//
+CServiceBase::CServiceBase(PSTR pszServiceName, 
+                           BOOL fCanStop, 
+                           BOOL fCanShutdown, 
+                           BOOL fCanPauseContinue)
+{
+    // Service name must be a valid string and cannot be NULL.
+    m_name = (pszServiceName == NULL) ? "" : pszServiceName;
+
+    m_statusHandle = NULL;
+
+    // The service runs in its own process.
+    m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+
+    // The service is starting.
+    m_status.dwCurrentState = SERVICE_START_PENDING;
+
+    // The accepted commands of the service.
+    DWORD dwControlsAccepted = 0;
+    if (fCanStop) 
+        dwControlsAccepted |= SERVICE_ACCEPT_STOP;
+    if (fCanShutdown) 
+        dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
+    if (fCanPauseContinue) 
+        dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
+    m_status.dwControlsAccepted = dwControlsAccepted;
+
+    m_status.dwWin32ExitCode = NO_ERROR;
+    m_status.dwServiceSpecificExitCode = 0;
+    m_status.dwCheckPoint = 0;
+    m_status.dwWaitHint = 0;
+}
+
+
+//
+//   FUNCTION: CServiceBase::~CServiceBase()
+//
+//   PURPOSE: The virtual destructor of CServiceBase. 
+//
+CServiceBase::~CServiceBase(void)
+{
+}
+
+#pragma endregion
+
+
+#pragma region Service Start, Stop, Pause, Continue, and Shutdown
+
+//
+//   FUNCTION: CServiceBase::Start(DWORD, PWSTR *)
+//
+//   PURPOSE: The function starts the service. It calls the OnStart virtual 
+//   function in which you can specify the actions to take when the service 
+//   starts. If an error occurs during the startup, the error will be logged 
+//   in the Application event log, and the service will be stopped.
+//
+//   PARAMETERS:
+//   * dwArgc   - number of command line arguments
+//   * lpszArgv - array of command line arguments
+//
+void CServiceBase::Start(DWORD dwArgc, PSTR *pszArgv)
+{
+    try
+    {
+        // Tell SCM that the service is starting.
+        SetServiceStatus(SERVICE_START_PENDING);
+
+        // Perform service-specific initialization.
+        OnStart(dwArgc, pszArgv);
+
+        // Tell SCM that the service is started.
+        SetServiceStatus(SERVICE_RUNNING);
+    }
+    catch (DWORD dwError)
+    {
+        // Log the error.
+        WriteErrorLogEntry("Service Start", dwError);
+
+        // Set the service status to be stopped.
+        SetServiceStatus(SERVICE_STOPPED, dwError);
+    }
+    catch (...)
+    {
+        // Log the error.
+        WriteEventLogEntry("Service failed to start.", EVENTLOG_ERROR_TYPE);
+
+        // Set the service status to be stopped.
+        SetServiceStatus(SERVICE_STOPPED);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::OnStart(DWORD, PWSTR *)
+//
+//   PURPOSE: When implemented in a derived class, executes when a Start 
+//   command is sent to the service by the SCM or when the operating system 
+//   starts (for a service that starts automatically). Specifies actions to 
+//   take when the service starts. Be sure to periodically call 
+//   CServiceBase::SetServiceStatus() with SERVICE_START_PENDING if the 
+//   procedure is going to take long time. You may also consider spawning a 
+//   new thread in OnStart to perform time-consuming initialization tasks.
+//
+//   PARAMETERS:
+//   * dwArgc   - number of command line arguments
+//   * lpszArgv - array of command line arguments
+//
+void CServiceBase::OnStart(DWORD dwArgc, PSTR *pszArgv)
+{
+}
+
+
+//
+//   FUNCTION: CServiceBase::Stop()
+//
+//   PURPOSE: The function stops the service. It calls the OnStop virtual 
+//   function in which you can specify the actions to take when the service 
+//   stops. If an error occurs, the error will be logged in the Application 
+//   event log, and the service will be restored to the original state.
+//
+void CServiceBase::Stop()
+{
+    DWORD dwOriginalState = m_status.dwCurrentState;
+    try
+    {
+        // Tell SCM that the service is stopping.
+        SetServiceStatus(SERVICE_STOP_PENDING);
+
+        // Perform service-specific stop operations.
+        OnStop();
+
+        // Tell SCM that the service is stopped.
+        SetServiceStatus(SERVICE_STOPPED);
+    }
+    catch (DWORD dwError)
+    {
+        // Log the error.
+        WriteErrorLogEntry("Service Stop", dwError);
+
+        // Set the orginal service status.
+        SetServiceStatus(dwOriginalState);
+    }
+    catch (...)
+    {
+        // Log the error.
+        WriteEventLogEntry("Service failed to stop.", EVENTLOG_ERROR_TYPE);
+
+        // Set the orginal service status.
+        SetServiceStatus(dwOriginalState);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::OnStop()
+//
+//   PURPOSE: When implemented in a derived class, executes when a Stop 
+//   command is sent to the service by the SCM. Specifies actions to take 
+//   when a service stops running. Be sure to periodically call 
+//   CServiceBase::SetServiceStatus() with SERVICE_STOP_PENDING if the 
+//   procedure is going to take long time. 
+//
+void CServiceBase::OnStop()
+{
+}
+
+
+//
+//   FUNCTION: CServiceBase::Pause()
+//
+//   PURPOSE: The function pauses the service if the service supports pause 
+//   and continue. It calls the OnPause virtual function in which you can 
+//   specify the actions to take when the service pauses. If an error occurs, 
+//   the error will be logged in the Application event log, and the service 
+//   will become running.
+//
+void CServiceBase::Pause()
+{
+    try
+    {
+        // Tell SCM that the service is pausing.
+        SetServiceStatus(SERVICE_PAUSE_PENDING);
+
+        // Perform service-specific pause operations.
+        OnPause();
+
+        // Tell SCM that the service is paused.
+        SetServiceStatus(SERVICE_PAUSED);
+    }
+    catch (DWORD dwError)
+    {
+        // Log the error.
+        WriteErrorLogEntry("Service Pause", dwError);
+
+        // Tell SCM that the service is still running.
+        SetServiceStatus(SERVICE_RUNNING);
+    }
+    catch (...)
+    {
+        // Log the error.
+        WriteEventLogEntry("Service failed to pause.", EVENTLOG_ERROR_TYPE);
+
+        // Tell SCM that the service is still running.
+        SetServiceStatus(SERVICE_RUNNING);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::OnPause()
+//
+//   PURPOSE: When implemented in a derived class, executes when a Pause 
+//   command is sent to the service by the SCM. Specifies actions to take 
+//   when a service pauses.
+//
+void CServiceBase::OnPause()
+{
+}
+
+
+//
+//   FUNCTION: CServiceBase::Continue()
+//
+//   PURPOSE: The function resumes normal functioning after being paused if
+//   the service supports pause and continue. It calls the OnContinue virtual 
+//   function in which you can specify the actions to take when the service 
+//   continues. If an error occurs, the error will be logged in the 
+//   Application event log, and the service will still be paused.
+//
+void CServiceBase::Continue()
+{
+    try
+    {
+        // Tell SCM that the service is resuming.
+        SetServiceStatus(SERVICE_CONTINUE_PENDING);
+
+        // Perform service-specific continue operations.
+        OnContinue();
+
+        // Tell SCM that the service is running.
+        SetServiceStatus(SERVICE_RUNNING);
+    }
+    catch (DWORD dwError)
+    {
+        // Log the error.
+        WriteErrorLogEntry("Service Continue", dwError);
+
+        // Tell SCM that the service is still paused.
+        SetServiceStatus(SERVICE_PAUSED);
+    }
+    catch (...)
+    {
+        // Log the error.
+        WriteEventLogEntry("Service failed to resume.", EVENTLOG_ERROR_TYPE);
+
+        // Tell SCM that the service is still paused.
+        SetServiceStatus(SERVICE_PAUSED);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::OnContinue()
+//
+//   PURPOSE: When implemented in a derived class, OnContinue runs when a 
+//   Continue command is sent to the service by the SCM. Specifies actions to 
+//   take when a service resumes normal functioning after being paused.
+//
+void CServiceBase::OnContinue()
+{
+}
+
+
+//
+//   FUNCTION: CServiceBase::Shutdown()
+//
+//   PURPOSE: The function executes when the system is shutting down. It 
+//   calls the OnShutdown virtual function in which you can specify what 
+//   should occur immediately prior to the system shutting down. If an error 
+//   occurs, the error will be logged in the Application event log.
+//
+void CServiceBase::Shutdown()
+{
+    try
+    {
+        // Perform service-specific shutdown operations.
+        OnShutdown();
+
+        // Tell SCM that the service is stopped.
+        SetServiceStatus(SERVICE_STOPPED);
+    }
+    catch (DWORD dwError)
+    {
+        // Log the error.
+        WriteErrorLogEntry("Service Shutdown", dwError);
+    }
+    catch (...)
+    {
+        // Log the error.
+        WriteEventLogEntry("Service failed to shut down.", EVENTLOG_ERROR_TYPE);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::OnShutdown()
+//
+//   PURPOSE: When implemented in a derived class, executes when the system 
+//   is shutting down. Specifies what should occur immediately prior to the 
+//   system shutting down.
+//
+void CServiceBase::OnShutdown()
+{
+}
+
+#pragma endregion
+
+
+#pragma region Helper Functions
+
+//
+//   FUNCTION: CServiceBase::SetServiceStatus(DWORD, DWORD, DWORD)
+//
+//   PURPOSE: The function sets the service status and reports the status to 
+//   the SCM.
+//
+//   PARAMETERS:
+//   * dwCurrentState - the state of the service
+//   * dwWin32ExitCode - error code to report
+//   * dwWaitHint - estimated time for pending operation, in milliseconds
+//
+void CServiceBase::SetServiceStatus(DWORD dwCurrentState, 
+                                    DWORD dwWin32ExitCode, 
+                                    DWORD dwWaitHint)
+{
+    static DWORD dwCheckPoint = 1;
+
+    // Fill in the SERVICE_STATUS structure of the service.
+
+    m_status.dwCurrentState = dwCurrentState;
+    m_status.dwWin32ExitCode = dwWin32ExitCode;
+    m_status.dwWaitHint = dwWaitHint;
+
+    m_status.dwCheckPoint = 
+        ((dwCurrentState == SERVICE_RUNNING) ||
+        (dwCurrentState == SERVICE_STOPPED)) ? 
+        0 : dwCheckPoint++;
+
+    // Report the status of the service to the SCM.
+    ::SetServiceStatus(m_statusHandle, &m_status);
+}
+
+
+//
+//   FUNCTION: CServiceBase::WriteEventLogEntry(PWSTR, WORD)
+//
+//   PURPOSE: Log a message to the Application event log.
+//
+//   PARAMETERS:
+//   * pszMessage - string message to be logged.
+//   * wType - the type of event to be logged. The parameter can be one of 
+//     the following values.
+//
+//     EVENTLOG_SUCCESS
+//     EVENTLOG_AUDIT_FAILURE
+//     EVENTLOG_AUDIT_SUCCESS
+//     EVENTLOG_ERROR_TYPE
+//     EVENTLOG_INFORMATION_TYPE
+//     EVENTLOG_WARNING_TYPE
+//
+void CServiceBase::WriteEventLogEntry(PSTR pszMessage, WORD wType)
+{
+    HANDLE hEventSource = NULL;
+    LPCSTR lpszStrings[2] = { NULL, NULL };
+
+    hEventSource = RegisterEventSource(NULL, m_name);
+    if (hEventSource)
+    {
+        lpszStrings[0] = m_name;
+        lpszStrings[1] = pszMessage;
+
+        ReportEvent(hEventSource,  // Event log handle
+            wType,                 // Event type
+            0,                     // Event category
+            0,                     // Event identifier
+            NULL,                  // No security identifier
+            2,                     // Size of lpszStrings array
+            0,                     // No binary data
+            lpszStrings,           // Array of strings
+            NULL                   // No binary data
+            );
+
+        DeregisterEventSource(hEventSource);
+    }
+}
+
+
+//
+//   FUNCTION: CServiceBase::WriteErrorLogEntry(PWSTR, DWORD)
+//
+//   PURPOSE: Log an error message to the Application event log.
+//
+//   PARAMETERS:
+//   * pszFunction - the function that gives the error
+//   * dwError - the error code
+//
+void CServiceBase::WriteErrorLogEntry(PSTR pszFunction, DWORD dwError)
+{
+    char szMessage[260];
+    StringCchPrintf(szMessage, ARRAYSIZE(szMessage), 
+        "%s failed w/err 0x%08lx", pszFunction, dwError);
+    WriteEventLogEntry(szMessage, EVENTLOG_ERROR_TYPE);
+}
+
+#pragma endregion
\ No newline at end of file
diff --git a/windows/ZeroTierOne/ServiceBase.h b/windows/ZeroTierOne/ServiceBase.h
new file mode 100644
index 000000000..5288194f1
--- /dev/null
+++ b/windows/ZeroTierOne/ServiceBase.h
@@ -0,0 +1,122 @@
+/****************************** Module Header ******************************\
+* Module Name:  ServiceBase.h
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* Provides a base class for a service that will exist as part of a service 
+* application. CServiceBase must be derived from when creating a new service 
+* class.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma once
+
+#include <windows.h>
+
+
+class CServiceBase
+{
+public:
+
+    // Register the executable for a service with the Service Control Manager 
+    // (SCM). After you call Run(ServiceBase), the SCM issues a Start command, 
+    // which results in a call to the OnStart method in the service. This 
+    // method blocks until the service has stopped.
+    static BOOL Run(CServiceBase &service);
+
+    // Service object constructor. The optional parameters (fCanStop, 
+    // fCanShutdown and fCanPauseContinue) allow you to specify whether the 
+    // service can be stopped, paused and continued, or be notified when 
+    // system shutdown occurs.
+    CServiceBase(LPSTR pszServiceName, 
+        BOOL fCanStop = TRUE, 
+        BOOL fCanShutdown = TRUE, 
+        BOOL fCanPauseContinue = FALSE);
+
+    // Service object destructor. 
+    virtual ~CServiceBase(void);
+
+    // Stop the service.
+    void Stop();
+
+protected:
+
+    // When implemented in a derived class, executes when a Start command is 
+    // sent to the service by the SCM or when the operating system starts 
+    // (for a service that starts automatically). Specifies actions to take 
+    // when the service starts.
+    virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
+
+    // When implemented in a derived class, executes when a Stop command is 
+    // sent to the service by the SCM. Specifies actions to take when a 
+    // service stops running.
+    virtual void OnStop();
+
+    // When implemented in a derived class, executes when a Pause command is 
+    // sent to the service by the SCM. Specifies actions to take when a 
+    // service pauses.
+    virtual void OnPause();
+
+    // When implemented in a derived class, OnContinue runs when a Continue 
+    // command is sent to the service by the SCM. Specifies actions to take 
+    // when a service resumes normal functioning after being paused.
+    virtual void OnContinue();
+
+    // When implemented in a derived class, executes when the system is 
+    // shutting down. Specifies what should occur immediately prior to the 
+    // system shutting down.
+    virtual void OnShutdown();
+
+    // Set the service status and report the status to the SCM.
+    void SetServiceStatus(DWORD dwCurrentState, 
+        DWORD dwWin32ExitCode = NO_ERROR, 
+        DWORD dwWaitHint = 0);
+
+    // Log a message to the Application event log.
+    void WriteEventLogEntry(PSTR pszMessage, WORD wType);
+
+    // Log an error message to the Application event log.
+    void WriteErrorLogEntry(PSTR pszFunction, 
+        DWORD dwError = GetLastError());
+
+private:
+
+    // Entry point for the service. It registers the handler function for the 
+    // service and starts the service.
+    static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
+
+    // The function is called by the SCM whenever a control code is sent to 
+    // the service.
+    static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
+
+    // Start the service.
+    void Start(DWORD dwArgc, PSTR *pszArgv);
+    
+    // Pause the service.
+    void Pause();
+
+    // Resume the service after being paused.
+    void Continue();
+
+    // Execute when the system is shutting down.
+    void Shutdown();
+
+    // The singleton service instance.
+    static CServiceBase *s_service;
+
+    // The name of the service
+    LPSTR m_name;
+
+    // The status of the service
+    SERVICE_STATUS m_status;
+
+    // The service status handle
+    SERVICE_STATUS_HANDLE m_statusHandle;
+};
\ No newline at end of file
diff --git a/windows/ZeroTierOne/ServiceInstaller.cpp b/windows/ZeroTierOne/ServiceInstaller.cpp
new file mode 100644
index 000000000..9d7b22c71
--- /dev/null
+++ b/windows/ZeroTierOne/ServiceInstaller.cpp
@@ -0,0 +1,192 @@
+/****************************** Module Header ******************************\
+* Module Name:  ServiceInstaller.cpp
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* The file implements functions that install and uninstall the service.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma region "Includes"
+#include <stdio.h>
+#include <windows.h>
+#include "ServiceInstaller.h"
+#pragma endregion
+
+
+//
+//   FUNCTION: InstallService
+//
+//   PURPOSE: Install the current application as a service to the local 
+//   service control manager database.
+//
+//   PARAMETERS:
+//   * pszServiceName - the name of the service to be installed
+//   * pszDisplayName - the display name of the service
+//   * dwStartType - the service start option. This parameter can be one of 
+//     the following values: SERVICE_AUTO_START, SERVICE_BOOT_START, 
+//     SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
+//   * pszDependencies - a pointer to a double null-terminated array of null-
+//     separated names of services or load ordering groups that the system 
+//     must start before this service.
+//   * pszAccount - the name of the account under which the service runs.
+//   * pszPassword - the password to the account name.
+//
+//   NOTE: If the function fails to install the service, it prints the error 
+//   in the standard output stream for users to diagnose the problem.
+//
+void InstallService(PSTR pszServiceName, 
+                    PSTR pszDisplayName, 
+                    DWORD dwStartType,
+                    PSTR pszDependencies, 
+                    PSTR pszAccount, 
+                    PSTR pszPassword)
+{
+    char szPath[MAX_PATH];
+    SC_HANDLE schSCManager = NULL;
+    SC_HANDLE schService = NULL;
+
+    if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
+    {
+        wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Open the local default service control manager database
+    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | 
+        SC_MANAGER_CREATE_SERVICE);
+    if (schSCManager == NULL)
+    {
+        wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Install the service into SCM by calling CreateService
+    schService = CreateService(
+        schSCManager,                   // SCManager database
+        pszServiceName,                 // Name of service
+        pszDisplayName,                 // Name to display
+        SERVICE_QUERY_STATUS,           // Desired access
+        SERVICE_WIN32_OWN_PROCESS,      // Service type
+        dwStartType,                    // Service start type
+        SERVICE_ERROR_NORMAL,           // Error control type
+        szPath,                         // Service's binary
+        NULL,                           // No load ordering group
+        NULL,                           // No tag identifier
+        pszDependencies,                // Dependencies
+        pszAccount,                     // Service running account
+        pszPassword                     // Password of the account
+        );
+    if (schService == NULL)
+    {
+        wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    wprintf(L"%s is installed.\n", pszServiceName);
+
+Cleanup:
+    // Centralized cleanup for all allocated resources.
+    if (schSCManager)
+    {
+        CloseServiceHandle(schSCManager);
+        schSCManager = NULL;
+    }
+    if (schService)
+    {
+        CloseServiceHandle(schService);
+        schService = NULL;
+    }
+}
+
+
+//
+//   FUNCTION: UninstallService
+//
+//   PURPOSE: Stop and remove the service from the local service control 
+//   manager database.
+//
+//   PARAMETERS: 
+//   * pszServiceName - the name of the service to be removed.
+//
+//   NOTE: If the function fails to uninstall the service, it prints the 
+//   error in the standard output stream for users to diagnose the problem.
+//
+void UninstallService(PSTR pszServiceName)
+{
+    SC_HANDLE schSCManager = NULL;
+    SC_HANDLE schService = NULL;
+    SERVICE_STATUS ssSvcStatus = {};
+
+    // Open the local default service control manager database
+    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+    if (schSCManager == NULL)
+    {
+        wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Open the service with delete, stop, and query status permissions
+    schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | 
+        SERVICE_QUERY_STATUS | DELETE);
+    if (schService == NULL)
+    {
+        wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    // Try to stop the service
+    if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
+    {
+        wprintf(L"Stopping %s.", pszServiceName);
+        Sleep(1000);
+
+        while (QueryServiceStatus(schService, &ssSvcStatus))
+        {
+            if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
+            {
+                wprintf(L".");
+                Sleep(1000);
+            }
+            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.
+    if (!DeleteService(schService))
+    {
+        wprintf(L"DeleteService failed w/err 0x%08lx\n", GetLastError());
+        goto Cleanup;
+    }
+
+    wprintf(L"%s is removed.\n", pszServiceName);
+
+Cleanup:
+    // Centralized cleanup for all allocated resources.
+    if (schSCManager)
+    {
+        CloseServiceHandle(schSCManager);
+        schSCManager = NULL;
+    }
+    if (schService)
+    {
+        CloseServiceHandle(schService);
+        schService = NULL;
+    }
+}
\ No newline at end of file
diff --git a/windows/ZeroTierOne/ServiceInstaller.h b/windows/ZeroTierOne/ServiceInstaller.h
new file mode 100644
index 000000000..1f007c056
--- /dev/null
+++ b/windows/ZeroTierOne/ServiceInstaller.h
@@ -0,0 +1,61 @@
+/****************************** Module Header ******************************\
+* Module Name:  ServiceInstaller.h
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* The file declares functions that install and uninstall the service.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma once
+
+
+//
+//   FUNCTION: InstallService
+//
+//   PURPOSE: Install the current application as a service to the local 
+//   service control manager database.
+//
+//   PARAMETERS:
+//   * pszServiceName - the name of the service to be installed
+//   * pszDisplayName - the display name of the service
+//   * dwStartType - the service start option. This parameter can be one of 
+//     the following values: SERVICE_AUTO_START, SERVICE_BOOT_START, 
+//     SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
+//   * pszDependencies - a pointer to a double null-terminated array of null-
+//     separated names of services or load ordering groups that the system 
+//     must start before this service.
+//   * pszAccount - the name of the account under which the service runs.
+//   * pszPassword - the password to the account name.
+//
+//   NOTE: If the function fails to install the service, it prints the error 
+//   in the standard output stream for users to diagnose the problem.
+//
+void InstallService(PSTR pszServiceName, 
+                    PSTR pszDisplayName, 
+                    DWORD dwStartType,
+                    PSTR pszDependencies, 
+                    PSTR pszAccount, 
+                    PSTR pszPassword);
+
+
+//
+//   FUNCTION: UninstallService
+//
+//   PURPOSE: Stop and remove the service from the local service control 
+//   manager database.
+//
+//   PARAMETERS: 
+//   * pszServiceName - the name of the service to be removed.
+//
+//   NOTE: If the function fails to uninstall the service, it prints the 
+//   error in the standard output stream for users to diagnose the problem.
+//
+void UninstallService(PSTR pszServiceName);
\ No newline at end of file
diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj
index f739ea1a8..14dd0ea12 100644
--- a/windows/ZeroTierOne/ZeroTierOne.vcxproj
+++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj
@@ -49,6 +49,9 @@
     <ClCompile Include="..\..\node\Topology.cpp" />
     <ClCompile Include="..\..\node\UdpSocket.cpp" />
     <ClCompile Include="..\..\node\Utils.cpp" />
+    <ClCompile Include="ServiceBase.cpp" />
+    <ClCompile Include="ServiceInstaller.cpp" />
+    <ClCompile Include="ZeroTierOneService.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\ext\lz4\lz4.h" />
@@ -97,6 +100,9 @@
     <ClInclude Include="..\..\node\UdpSocket.hpp" />
     <ClInclude Include="..\..\node\Utils.hpp" />
     <ClInclude Include="resource.h" />
+    <ClInclude Include="ServiceBase.h" />
+    <ClInclude Include="ServiceInstaller.h" />
+    <ClInclude Include="ZeroTierOneService.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ZeroTierOne.rc" />
diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
index df6d9d7ab..71da70335 100644
--- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
+++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters
@@ -105,6 +105,15 @@
     <ClCompile Include="..\..\main.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="ServiceBase.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="ServiceInstaller.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="ZeroTierOneService.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\ext\lz4\lz4.h">
@@ -245,6 +254,15 @@
     <ClInclude Include="resource.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="ServiceBase.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="ServiceInstaller.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="ZeroTierOneService.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ZeroTierOne.rc">
diff --git a/windows/ZeroTierOne/ZeroTierOneService.cpp b/windows/ZeroTierOne/ZeroTierOneService.cpp
new file mode 100644
index 000000000..f146ce287
--- /dev/null
+++ b/windows/ZeroTierOne/ZeroTierOneService.cpp
@@ -0,0 +1,47 @@
+/****************************** Module Header ******************************\
+* Module Name:  SampleService.cpp
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* Provides a sample service class that derives from the service base class - 
+* CServiceBase. The sample service logs the service start and stop 
+* information to the Application event log, and shows how to run the main 
+* function of the service in a thread pool worker thread.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma region Includes
+#include "ZeroTierOneService.h"
+#pragma endregion
+
+ZeroTierOneService::ZeroTierOneService() :
+	CServiceBase(ZT_SERVICE_NAME,TRUE,TRUE,TRUE)
+{
+}
+
+ZeroTierOneService::~ZeroTierOneService(void)
+{
+}
+
+void ZeroTierOneService::OnStart(DWORD dwArgc, LPSTR *lpszArgv)
+{
+}
+
+void ZeroTierOneService::OnStop()
+{
+}
+
+void ZeroTierOneService::OnPause()
+{
+}
+
+void ZeroTierOneService::OnContinue()
+{
+}
diff --git a/windows/ZeroTierOne/ZeroTierOneService.h b/windows/ZeroTierOne/ZeroTierOneService.h
new file mode 100644
index 000000000..42f170aec
--- /dev/null
+++ b/windows/ZeroTierOne/ZeroTierOneService.h
@@ -0,0 +1,42 @@
+/****************************** Module Header ******************************\
+* Module Name:  SampleService.h
+* Project:      CppWindowsService
+* Copyright (c) Microsoft Corporation.
+* 
+* Provides a sample service class that derives from the service base class - 
+* CServiceBase. The sample service logs the service start and stop 
+* information to the Application event log, and shows how to run the main 
+* function of the service in a thread pool worker thread.
+* 
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+* 
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+#pragma once
+
+#include "ServiceBase.h"
+
+#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_PASSWORD NULL
+
+class ZeroTierOneService : public CServiceBase
+{
+public:
+    ZeroTierOneService();
+    virtual ~ZeroTierOneService(void);
+
+protected:
+    virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
+    virtual void OnStop();
+    virtual void OnPause();
+    virtual void OnContinue();
+};