[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[vidalia-svn] r1495: Load NT service functions dynamically so we can run on old W (in trunk/src: control util)



Author: edmanm
Date: 2006-12-04 00:33:21 -0500 (Mon, 04 Dec 2006)
New Revision: 1495

Modified:
   trunk/src/control/torservice.cpp
   trunk/src/control/torservice.h
   trunk/src/util/win32.cpp
Log:
Load NT service functions dynamically so we can run on old Windowses again.
All three users in the world who care, rejoice!


Modified: trunk/src/control/torservice.cpp
===================================================================
--- trunk/src/control/torservice.cpp	2006-12-04 04:07:13 UTC (rev 1494)
+++ trunk/src/control/torservice.cpp	2006-12-04 05:33:21 UTC (rev 1495)
@@ -25,13 +25,21 @@
  * \brief Starts, stops, installs, and uninstalls a Tor service (Win32).
  */
 
+#include <QLibrary>
+
 #include "torservice.h"
 
 /** Returned by TorService::exitCode() when we are unable to determine the
  * actual exit code of the service (unless, of course, Tor returns -999999). */
 #define UNKNOWN_EXIT_CODE     -999999
 
+/** List of dynamically loaded NT service functions. */
+ServiceFunctions TorService::_service_fns = 
+  { false,
+    NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL };
 
+
 /** Returns true if services are supported. */
 bool
 TorService::isSupported()
@@ -39,6 +47,37 @@
   return (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based);
 }
 
+/** Dyanmically loads NT service related functions from advapi32.dll. This
+ * function is adapted from Tor's nt_service_load_library() function. See
+ * LICENSE for details on Tor's license. */
+bool
+TorService::loadServiceFunctions()
+{
+#define LOAD_SERVICE_FN(f) do {                                         \
+  void *fn;                                                             \
+  if (!((fn = QLibrary::resolve("advapi32", #f)))) {                    \
+      return false;                                                     \
+    } else {                                                            \
+      _service_fns.f = (f ## _fn) fn;                                   \
+    }                                                                   \
+  } while (0)
+
+  if (!_service_fns.loaded) {
+    LOAD_SERVICE_FN(ChangeServiceConfig2A);
+    LOAD_SERVICE_FN(CloseServiceHandle);
+    LOAD_SERVICE_FN(ControlService);
+    LOAD_SERVICE_FN(CreateServiceA);
+    LOAD_SERVICE_FN(DeleteService);
+    LOAD_SERVICE_FN(OpenSCManagerA);
+    LOAD_SERVICE_FN(OpenServiceA);
+    LOAD_SERVICE_FN(QueryServiceStatus);
+    LOAD_SERVICE_FN(SetServiceStatus);
+    LOAD_SERVICE_FN(StartServiceA);
+    _service_fns.loaded = true;
+  }
+  return true;
+}
+
 /** Default ctor. */
 TorService::TorService(QObject* parent)
   : QObject(parent)
@@ -55,34 +94,45 @@
   close();
 }
 
+/** Closes the service and the service manager. */
 void
 TorService::close()
 {
-  if (_service) {
-    CloseServiceHandle(_service);
-    _service = NULL;
+  if (loadServiceFunctions()) {
+    if (_service) {
+      _service_fns.CloseServiceHandle(_service);
+      _service = NULL;
+    }
+    if (_manager) {
+      _service_fns.CloseServiceHandle(_manager);
+      _manager = NULL;
+    }
   }
-  if (_manager) {
-    CloseServiceHandle(_manager);
-    _manager = NULL;
-  }
 }
 
 /** Initializes the service and service manager. */
-void
+bool
 TorService::initialize()
 {
   /* If services are supported, initialize the manager and service */
   if (isSupported()) {
+    /* Load NT service related functions */
+    if (!loadServiceFunctions()) {
+      return false;
+    }
     /* Open service manager */
     if (_manager == NULL) {
-    _manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+      _manager = _service_fns.OpenSCManagerA(NULL, NULL, 
+                                             SC_MANAGER_ALL_ACCESS);
     }
     /* Open tor service */
     if (_service == NULL) {
-    _service = OpenServiceA(_manager, TOR_SERVICE_NAME, TOR_SERVICE_ACCESS);
+      _service = _service_fns.OpenServiceA(_manager, 
+                                           (LPCTSTR)TOR_SERVICE_NAME,
+                                           TOR_SERVICE_ACCESS);
     }
   }
+  return true;
 }
 
 /** Returns true if the Tor service is installed. */
@@ -113,12 +163,14 @@
     emit startFailed(tr("The Tor service is not installed."));
     return;
   }
+  if (!initialize()) {
+    return;
+  }
 
-  /* Make sure we're initialized */
-  initialize();
-
   /* Starting a service can take up to 30 seconds! */
-  if (!isRunning()) StartService(_service, 0, NULL); 
+  if (!isRunning()) {
+    _service_fns.StartServiceA(_service, 0, NULL);
+  }
   
   int tries = 0;
   while (true) {
@@ -139,10 +191,13 @@
 void
 TorService::stop()
 {
+  if (!loadServiceFunctions()) {
+    return;
+  }
   if (isRunning()) {
     SERVICE_STATUS stat;
     stat.dwCurrentState = SERVICE_RUNNING;
-    ControlService(_service, SERVICE_CONTROL_STOP, &stat);
+    _service_fns.ControlService(_service, SERVICE_CONTROL_STOP, &stat);
 
     int tries = 0;
     while (true) {
@@ -165,15 +220,16 @@
 {
   int exitCode = UNKNOWN_EXIT_CODE;
   
-  if (isSupported() && _manager && _service) {
-    SERVICE_STATUS s;
-
-    if (QueryServiceStatus(_service, &s)) {
-      /* Services return one exit code, but it could be in one of two
-       * variables. Fun. */
-      exitCode = (int)(s.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR
+  if (loadServiceFunctions()) {
+    if (isSupported() && _manager && _service) {
+      SERVICE_STATUS s;
+      if (_service_fns.QueryServiceStatus(_service, &s)) {
+        /* Services return one exit code, but it could be in one of two
+         * variables. Fun. */
+        exitCode = (int)(s.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR
                                               ? s.dwServiceSpecificExitCode
                                               : s.dwWin32ExitCode);
+      }
     }
   }
   return exitCode;
@@ -205,15 +261,18 @@
                                                  .arg(torrc)
                                                  .arg(controlPort);
 
-    _service = CreateServiceA(_manager, TOR_SERVICE_NAME, TOR_SERVICE_DISP,
+    _service = _service_fns.CreateServiceA(_manager, 
+                              (LPCTSTR)TOR_SERVICE_NAME, (LPCTSTR)TOR_SERVICE_DISP,
                               TOR_SERVICE_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                               SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
-                              command.toAscii().data(), NULL, NULL, NULL, NULL, "");
+                              (LPCTSTR)command.toAscii().data(), NULL, NULL, NULL, 
+                              NULL, NULL);
 
     if (_service != NULL) {
       SERVICE_DESCRIPTION desc;
       desc.lpDescription = TOR_SERVICE_DESC;
-      ChangeServiceConfig2(_service, SERVICE_CONFIG_DESCRIPTION, &desc);
+      _service_fns.ChangeServiceConfig2A(_service, 
+                                         SERVICE_CONFIG_DESCRIPTION, &desc);
     }
   }
   return isInstalled();
@@ -223,13 +282,17 @@
 bool
 TorService::remove()
 {
+  if (!loadServiceFunctions()) {
+    return false;
+  }
+
   if (!isSupported()) return false;
   if (isInstalled()) {
     /* Stop the service */
     stop();
 
     /* Delete the service */
-    if (!DeleteService(_service)) return false;
+    if (!_service_fns.DeleteService(_service)) return false;
     
     /* Release references to manager and service */
     close();
@@ -247,7 +310,7 @@
   SERVICE_STATUS s;
   DWORD stat = SERVICE_ERROR;
 
-  if (QueryServiceStatus(_service, &s)) {
+  if (_service_fns.QueryServiceStatus(_service, &s)) {
     stat = s.dwCurrentState;
   } 
   return stat;

Modified: trunk/src/control/torservice.h
===================================================================
--- trunk/src/control/torservice.h	2006-12-04 04:07:13 UTC (rev 1494)
+++ trunk/src/control/torservice.h	2006-12-04 05:33:21 UTC (rev 1495)
@@ -39,14 +39,78 @@
 #define TOR_SERVICE_ACCESS SERVICE_ALL_ACCESS
 #define SERVICE_ERROR 8
 
+/* NT service function prototypes. This code is adapted from Tor's
+ * nt_service_load_library() in main.c. See LICENSE for details on
+ * Tor's license. */
+typedef BOOL (WINAPI *ChangeServiceConfig2A_fn)(
+                             SC_HANDLE hService,
+                             DWORD dwInfoLevel,
+                             LPVOID lpInfo);
+typedef BOOL (WINAPI *CloseServiceHandle_fn)(
+                             SC_HANDLE hSCObject);
+typedef BOOL (WINAPI *ControlService_fn)(
+                             SC_HANDLE hService,
+                             DWORD dwControl,
+                             LPSERVICE_STATUS lpServiceStatus);
+typedef SC_HANDLE (WINAPI *CreateServiceA_fn)(
+                             SC_HANDLE hSCManager,
+                             LPCTSTR lpServiceName,
+                             LPCTSTR lpDisplayName,
+                             DWORD dwDesiredAccess,
+                             DWORD dwServiceType,
+                             DWORD dwStartType,
+                             DWORD dwErrorControl,
+                             LPCTSTR lpBinaryPathName,
+                             LPCTSTR lpLoadOrderGroup,
+                             LPDWORD lpdwTagId,
+                             LPCTSTR lpDependencies,
+                             LPCTSTR lpServiceStartName,
+                             LPCTSTR lpPassword);
+typedef BOOL (WINAPI *DeleteService_fn)(
+                             SC_HANDLE hService);
+typedef SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
+                             LPCTSTR lpMachineName,
+                             LPCTSTR lpDatabaseName,
+                             DWORD dwDesiredAccess);
+typedef SC_HANDLE (WINAPI *OpenServiceA_fn)(
+                             SC_HANDLE hSCManager,
+                             LPCTSTR lpServiceName,
+                             DWORD dwDesiredAccess);
+typedef BOOL (WINAPI *QueryServiceStatus_fn)(
+                             SC_HANDLE hService,
+                             LPSERVICE_STATUS lpServiceStatus);
+typedef BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
+                             LPSERVICE_STATUS);
+typedef BOOL (WINAPI *StartServiceA_fn)(
+                             SC_HANDLE hService,
+                             DWORD dwNumServiceArgs,
+                             LPCTSTR* lpServiceArgVectors);
 
+/** Table of NT service related functions. */
+typedef struct ServiceFunctions {
+  bool loaded;
+  ChangeServiceConfig2A_fn ChangeServiceConfig2A;
+  CloseServiceHandle_fn    CloseServiceHandle;
+  ControlService_fn        ControlService;
+  CreateServiceA_fn        CreateServiceA;
+  DeleteService_fn         DeleteService;
+  OpenSCManagerA_fn        OpenSCManagerA;
+  OpenServiceA_fn          OpenServiceA;
+  QueryServiceStatus_fn    QueryServiceStatus;
+  SetServiceStatus_fn      SetServiceStatus;
+  StartServiceA_fn         StartServiceA;
+};
+
+
 class TorService : public QObject
 {
   Q_OBJECT
 
 public:
-  /* Returns if services are supported. */
+  /** Returns if services are supported. */
   static bool isSupported();
+  /** Dynamically loads NT service related functions from advapi32.dll. */
+  static bool loadServiceFunctions();
 
   /** Default ctor. */
   TorService(QObject* parent = 0);
@@ -81,7 +145,7 @@
 
 private:
   /** Initializes the service and the service manager. */
-  void initialize();
+  bool initialize();
   /** Closes the service and the service manager. */
   void close();
   /** Gets the status of the Tor service. */
@@ -89,6 +153,9 @@
   
   SC_HANDLE _manager; /** Handle to a service manager object. */
   SC_HANDLE _service; /** Handle to the Tor service object. */
+
+  /** List of dynamically loaded NT service functions. */
+  static ServiceFunctions _service_fns;
 };
 
 #endif

Modified: trunk/src/util/win32.cpp
===================================================================
--- trunk/src/util/win32.cpp	2006-12-04 04:07:13 UTC (rev 1494)
+++ trunk/src/util/win32.cpp	2006-12-04 05:33:21 UTC (rev 1495)
@@ -149,6 +149,13 @@
 QHash<qint64, QString>
 win32_process_list()
 {
+#if defined(UNICODE)
+/* Force the ascii verisons of these functions, so we can run on Win98. We
+ * don't pass any Unicode strings to these functions anyway. */
+#undef PROCESSENTRY32
+#undef Process32First
+#undef Process32Next
+#endif
   QHash<qint64, QString> procList;
   HANDLE hSnapshot;
   PROCESSENTRY32 proc;