00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <QLibrary>
00018
00019 #include "tcglobal.h"
00020 #include "torservice.h"
00021
00022
00023
00024 #define UNKNOWN_EXIT_CODE -999999
00025
00026
00027 ServiceFunctions TorService::_service_fns =
00028 { false,
00029 NULL, NULL, NULL, NULL, NULL,
00030 NULL, NULL, NULL, NULL, NULL };
00031
00032
00033
00034 TorService::TorService(QObject *parent)
00035 : QObject(parent)
00036 {
00037 _scm = openSCM();
00038 }
00039
00040
00041 TorService::~TorService()
00042 {
00043 closeHandle(_scm);
00044 }
00045
00046
00047 bool
00048 TorService::isSupported()
00049 {
00050 return (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based);
00051 }
00052
00053
00054
00055
00056 bool
00057 TorService::loadServiceFunctions()
00058 {
00059 #define LOAD_SERVICE_FN(f) do { \
00060 void *fn; \
00061 if (!((fn = QLibrary::resolve("advapi32", #f)))) { \
00062 return false; \
00063 } else { \
00064 _service_fns.f = (f ## _fn) fn; \
00065 } \
00066 } while (0)
00067
00068 if (!isSupported()) {
00069 _service_fns.loaded = false;
00070 } else if (!_service_fns.loaded) {
00071 LOAD_SERVICE_FN(ChangeServiceConfig2A);
00072 LOAD_SERVICE_FN(CloseServiceHandle);
00073 LOAD_SERVICE_FN(ControlService);
00074 LOAD_SERVICE_FN(CreateServiceA);
00075 LOAD_SERVICE_FN(DeleteService);
00076 LOAD_SERVICE_FN(OpenSCManagerA);
00077 LOAD_SERVICE_FN(OpenServiceA);
00078 LOAD_SERVICE_FN(QueryServiceStatus);
00079 LOAD_SERVICE_FN(SetServiceStatus);
00080 LOAD_SERVICE_FN(StartServiceA);
00081 _service_fns.loaded = true;
00082 }
00083 return _service_fns.loaded;
00084 }
00085
00086
00087 SC_HANDLE
00088 TorService::openService()
00089 {
00090 if (!loadServiceFunctions())
00091 return NULL;
00092 if (!_scm)
00093 return NULL;
00094 return _service_fns.OpenServiceA(_scm,
00095 (LPCTSTR)TOR_SERVICE_NAME,
00096 TOR_SERVICE_ACCESS);
00097 }
00098
00099
00100 SC_HANDLE
00101 TorService::openSCM()
00102 {
00103 if (!loadServiceFunctions())
00104 return NULL;
00105 return _service_fns.OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
00106 }
00107
00108
00109 void
00110 TorService::closeHandle(SC_HANDLE handle)
00111 {
00112 if (!loadServiceFunctions())
00113 return;
00114 _service_fns.CloseServiceHandle(handle);
00115 }
00116
00117
00118 bool
00119 TorService::isInstalled()
00120 {
00121 bool installed;
00122 SC_HANDLE service = openService();
00123 installed = (service != NULL);
00124 closeHandle(service);
00125 return installed;
00126 }
00127
00128
00129 bool
00130 TorService::isRunning()
00131 {
00132 return (status() == SERVICE_RUNNING);
00133 }
00134
00135
00136 void
00137 TorService::start()
00138 {
00139 SC_HANDLE service = openService();
00140
00141 if (!service) {
00142 tc::error("Bug: We tried to start the Tor service, but it is not installed.");
00143 emit startFailed(tr("The Tor service is not installed."));
00144 return;
00145 }
00146
00147
00148 if (status() != SERVICE_RUNNING) {
00149 int tries = 0;
00150 tc::debug("Starting the Tor service.");
00151 _service_fns.StartServiceA(service, 0, NULL);
00152
00153 while ((status() != SERVICE_RUNNING) && ++tries <= 5)
00154 Sleep(1000);
00155 }
00156
00157 if (status() == SERVICE_RUNNING) {
00158 emit started();
00159 } else {
00160 tc::error("Unable to start the Tor service.");
00161 emit startFailed(tr("Unable to start the Tor service."));
00162 }
00163 closeHandle(service);
00164 }
00165
00166
00167 bool
00168 TorService::stop()
00169 {
00170 SC_HANDLE service = openService();
00171
00172 if (!service)
00173 return false;
00174
00175 if (status() != SERVICE_STOPPED) {
00176 SERVICE_STATUS stat;
00177 stat.dwCurrentState = SERVICE_RUNNING;
00178 tc::debug("Stopping the Tor service.");
00179 if (_service_fns.ControlService(service, SERVICE_CONTROL_STOP, &stat)) {
00180
00181
00182
00183
00184 int tries = 0;
00185 while ((status() != SERVICE_STOPPED) && (++tries <= 5))
00186 Sleep(1000);
00187 }
00188 }
00189 closeHandle(service);
00190
00191
00192 if (status() == SERVICE_STOPPED) {
00193 emit finished(exitCode(), exitStatus());
00194 return true;
00195 }
00196
00197 tc::error("Unable to stop the Tor service.");
00198 return false;
00199 }
00200
00201
00202 int
00203 TorService::exitCode()
00204 {
00205 SC_HANDLE service;
00206 int exitCode = UNKNOWN_EXIT_CODE;
00207
00208 service = openService();
00209 if (service) {
00210 SERVICE_STATUS s;
00211 if (_service_fns.QueryServiceStatus(service, &s)) {
00212
00213
00214 exitCode = (int)(s.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR
00215 ? s.dwServiceSpecificExitCode
00216 : s.dwWin32ExitCode);
00217 }
00218 closeHandle(service);
00219 }
00220 return exitCode;
00221 }
00222
00223
00224 QProcess::ExitStatus
00225 TorService::exitStatus()
00226 {
00227
00228
00229
00230
00231
00232
00233 return QProcess::NormalExit;
00234 }
00235
00236
00237
00238 bool
00239 TorService::install(const QString &torPath, const QString &torrc,
00240 quint16 controlPort)
00241 {
00242 SC_HANDLE service;
00243
00244 if (!_scm)
00245 return false;
00246
00247 service = openService();
00248 if (!service) {
00249 QString command = QString("\"%1\" --nt-service -f \"%2\" ControlPort %3")
00250 .arg(torPath)
00251 .arg(torrc)
00252 .arg(controlPort);
00253
00254 tc::debug("Installing the Tor service using the command line '%1'")
00255 .arg(command);
00256 service = _service_fns.CreateServiceA(_scm,
00257 (LPCTSTR)TOR_SERVICE_NAME, (LPCTSTR)TOR_SERVICE_DISP,
00258 TOR_SERVICE_ACCESS, SERVICE_WIN32_OWN_PROCESS,
00259 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
00260 (LPCTSTR)command.toAscii().data(), NULL, NULL, NULL,
00261 NULL, NULL);
00262 if (!service) {
00263
00264 tc::error("Failed to install the Tor service.");
00265 return false;
00266 }
00267
00268 SERVICE_DESCRIPTION desc;
00269 desc.lpDescription = TOR_SERVICE_DESC;
00270 _service_fns.ChangeServiceConfig2A(service,
00271 SERVICE_CONFIG_DESCRIPTION, &desc);
00272 closeHandle(service);
00273 }
00274 return true;
00275 }
00276
00277
00278
00279 bool
00280 TorService::remove()
00281 {
00282 bool removed = true;
00283 SC_HANDLE service = openService();
00284
00285 if (service) {
00286 stop();
00287 tc::debug("Removing the Tor service.");
00288 removed = _service_fns.DeleteService(service);
00289 closeHandle(service);
00290 }
00291 if (!removed) {
00292
00293 tc::error("Failed to remove the Tor service.");
00294 }
00295 return removed;
00296 }
00297
00298
00299 DWORD
00300 TorService::status()
00301 {
00302 SC_HANDLE service;
00303 SERVICE_STATUS s;
00304 DWORD stat = SERVICE_ERROR;
00305
00306 service = openService();
00307 if (service && _service_fns.QueryServiceStatus(service, &s))
00308 stat = s.dwCurrentState;
00309 closeHandle(service);
00310 return stat;
00311 }
00312