diff options
| author | Odd Stranne <odd@mullvad.net> | 2021-03-17 18:06:16 +0100 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2021-07-02 16:31:31 +0200 |
| commit | 15be4405fcbe845f806d0e2a50c4e948e049d0d5 (patch) | |
| tree | 869d26d02bad41af6c6bff61d0831ce3705edabc /windows/driverlogic/src/service.cpp | |
| parent | 79f52b5adc0d965e1688bb1253a6c782bf74f03f (diff) | |
| download | mullvadvpn-15be4405fcbe845f806d0e2a50c4e948e049d0d5.tar.xz mullvadvpn-15be4405fcbe845f806d0e2a50c4e948e049d0d5.zip | |
Restructure and extend driverlogic
Diffstat (limited to 'windows/driverlogic/src/service.cpp')
| -rw-r--r-- | windows/driverlogic/src/service.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/windows/driverlogic/src/service.cpp b/windows/driverlogic/src/service.cpp new file mode 100644 index 0000000000..14ed7880fa --- /dev/null +++ b/windows/driverlogic/src/service.cpp @@ -0,0 +1,134 @@ +#include "stdafx.h" +#include "service.h" +#include "log.h" +#include <libcommon/error.h> +#include <libcommon/memory.h> + +#undef min +#undef max +#include <chrono> + +template<typename TTime = std::chrono::milliseconds> +class TimeBox +{ + // `steady_clock` wraps around every ~292 years. + using Clock = std::chrono::steady_clock; + using ClockTimePoint = std::chrono::time_point<Clock>; + +public: + + TimeBox(typename TTime::rep maxWaitTime) + : m_startTime(Clock::now()) + , m_maxWaitTime(TTime(maxWaitTime)) + { + } + + bool expired() const + { + const auto now = Clock::now(); + + const auto elapsed = + ( + (now < m_startTime) + ? (ClockTimePoint::max() - m_startTime) + (now - ClockTimePoint::min()) + : now - m_startTime + ); + + return std::chrono::duration_cast<TTime>(elapsed) > m_maxWaitTime; + } + +private: + + ClockTimePoint m_startTime; + TTime m_maxWaitTime; +}; + +void WaitUntilServiceStopped(SC_HANDLE service, DWORD maxWaitMs) +{ + TimeBox timer(maxWaitMs); + + for (;;) + { + SERVICE_STATUS_PROCESS ssp; + + DWORD bytesNeeded; + + auto status = QueryServiceStatusEx + ( + service, + SC_STATUS_PROCESS_INFO, + reinterpret_cast<BYTE*>(&ssp), + sizeof(ssp), + &bytesNeeded + ); + + if (status != 0 + && ssp.dwCurrentState == SERVICE_STOPPED) + { + return; + } + + if (timer.expired()) + { + THROW_ERROR("Failed when waiting for service to stop"); + } + + Sleep(100); + } +} + +void PokeService(const std::wstring &serviceName, bool stopService, bool deleteService) +{ + auto serviceManager = OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); + + if (serviceManager == NULL) + { + THROW_WINDOWS_ERROR(GetLastError(), "OpenSCManagerW"); + } + + common::memory::ScopeDestructor dtor; + + dtor += [serviceManager]() + { + CloseServiceHandle(serviceManager); + }; + + auto service = OpenServiceW(serviceManager, serviceName.c_str(), SERVICE_ALL_ACCESS); + + if (service == NULL) + { + THROW_WINDOWS_ERROR(GetLastError(), "OpenServiceW"); + } + + dtor += [service]() + { + CloseServiceHandle(service); + }; + + if (stopService) + { + Log(L"Stopping service"); + + SERVICE_STATUS ss; + + ControlService(service, SERVICE_CONTROL_STOP, &ss); + + WaitUntilServiceStopped(service, 1000 * 5); + + Log(L"Successfully stopped service"); + } + + if (deleteService) + { + Log(L"Deleting service"); + + auto status = DeleteService(service); + + if (status == 0) + { + THROW_WINDOWS_ERROR(GetLastError(), "DeleteService"); + } + + Log(L"Successfully deleted service"); + } +} |
