[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;