summaryrefslogtreecommitdiffhomepage
path: root/windows/driverlogic/src/service.cpp
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2021-03-17 18:06:16 +0100
committerOdd Stranne <odd@mullvad.net>2021-07-02 16:31:31 +0200
commit15be4405fcbe845f806d0e2a50c4e948e049d0d5 (patch)
tree869d26d02bad41af6c6bff61d0831ce3705edabc /windows/driverlogic/src/service.cpp
parent79f52b5adc0d965e1688bb1253a6c782bf74f03f (diff)
downloadmullvadvpn-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.cpp134
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");
+ }
+}