• Main Page
  • Classes
  • Files
  • File List

CArchDaemonWindows.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2012 Bolton Software Ltd.
00004  * Copyright (C) 2002 Chris Schoeneman
00005  * 
00006  * This package is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * found in the file COPYING that should have accompanied this file.
00009  * 
00010  * This package is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "CArchDaemonWindows.h"
00020 #include "CArch.h"
00021 #include "CArchMiscWindows.h"
00022 #include "XArchWindows.h"
00023 #include "stdvector.h"
00024 
00025 //
00026 // CArchDaemonWindows
00027 //
00028 
00029 CArchDaemonWindows*     CArchDaemonWindows::s_daemon = NULL;
00030 
00031 CArchDaemonWindows::CArchDaemonWindows() :
00032 m_daemonThreadID(0)
00033 {
00034     m_quitMessage = RegisterWindowMessage("SynergyDaemonExit");
00035 }
00036 
00037 CArchDaemonWindows::~CArchDaemonWindows()
00038 {
00039     // do nothing
00040 }
00041 
00042 int
00043 CArchDaemonWindows::runDaemon(RunFunc runFunc)
00044 {
00045     assert(s_daemon != NULL);
00046 
00047     return s_daemon->doRunDaemon(runFunc);
00048 }
00049 
00050 void
00051 CArchDaemonWindows::daemonRunning(bool running)
00052 {
00053     // if s_daemon is NULL we assume we're running on the windows
00054     // 95 family and we just ignore this call so the caller doesn't
00055     // have to go through the trouble of not calling it on the
00056     // windows 95 family.
00057     if (s_daemon != NULL) {
00058         s_daemon->doDaemonRunning(running);
00059     }
00060 }
00061 
00062 UINT
00063 CArchDaemonWindows::getDaemonQuitMessage()
00064 {
00065     if (s_daemon != NULL) {
00066         return s_daemon->doGetDaemonQuitMessage();
00067     }
00068     else {
00069         return 0;
00070     }
00071 }
00072 
00073 void
00074 CArchDaemonWindows::daemonFailed(int result)
00075 {
00076     // if s_daemon is NULL we assume we're running on the windows
00077     // 95 family and we just ignore this call so the caller doesn't
00078     // have to go through the trouble of not calling it on the
00079     // windows 95 family.
00080     if (s_daemon != NULL) {
00081         throw XArchDaemonRunFailed(result);
00082     }
00083 }
00084 
00085 void
00086 CArchDaemonWindows::installDaemon(const char* name,
00087                 const char* description,
00088                 const char* pathname,
00089                 const char* commandLine,
00090                 const char* dependencies,
00091                 bool allUsers)
00092 {
00093     // if not for all users then use the user's autostart registry.
00094     // key.  if windows 95 family then use windows 95 services key.
00095     if (!allUsers || CArchMiscWindows::isWindows95Family()) {
00096         // open registry
00097         HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
00098                             open95ServicesKey() : openUserStartupKey();
00099         if (key == NULL) {
00100             // can't open key
00101             throw XArchDaemonInstallFailed(new XArchEvalWindows);
00102         }
00103 
00104         // construct entry
00105         std::string value;
00106         value += "\"";
00107         value += pathname;
00108         value += "\" ";
00109         value += commandLine;
00110 
00111         // install entry
00112         CArchMiscWindows::setValue(key, name, value);
00113 
00114         // clean up
00115         CArchMiscWindows::closeKey(key);
00116     }
00117 
00118     // windows NT family services
00119     else {
00120         // open service manager
00121         SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
00122         if (mgr == NULL) {
00123             // can't open service manager
00124             throw XArchDaemonInstallFailed(new XArchEvalWindows);
00125         }
00126 
00127         // create the service
00128         SC_HANDLE service = CreateService(mgr,
00129                                 name,
00130                                 name,
00131                                 0,
00132                                 SERVICE_WIN32_OWN_PROCESS |
00133                                     SERVICE_INTERACTIVE_PROCESS,
00134                                 SERVICE_AUTO_START,
00135                                 SERVICE_ERROR_NORMAL,
00136                                 pathname,
00137                                 NULL,
00138                                 NULL,
00139                                 dependencies,
00140                                 NULL,
00141                                 NULL);
00142         if (service == NULL) {
00143             // can't create service
00144             DWORD err = GetLastError();
00145             if (err != ERROR_SERVICE_EXISTS) {
00146                 CloseServiceHandle(mgr);
00147                 throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
00148             }
00149         }
00150         else {
00151             // done with service (but only try to close if not null)
00152             CloseServiceHandle(service);
00153         }
00154 
00155         // done with manager
00156         CloseServiceHandle(mgr);
00157 
00158         // open the registry key for this service
00159         HKEY key = openNTServicesKey();
00160         key      = CArchMiscWindows::addKey(key, name);
00161         if (key == NULL) {
00162             // can't open key
00163             DWORD err = GetLastError();
00164             try {
00165                 uninstallDaemon(name, allUsers);
00166             }
00167             catch (...) {
00168                 // ignore
00169             }
00170             throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
00171         }
00172 
00173         // set the description
00174         CArchMiscWindows::setValue(key, _T("Description"), description);
00175 
00176         // set command line
00177         key = CArchMiscWindows::addKey(key, _T("Parameters"));
00178         if (key == NULL) {
00179             // can't open key
00180             DWORD err = GetLastError();
00181             CArchMiscWindows::closeKey(key);
00182             try {
00183                 uninstallDaemon(name, allUsers);
00184             }
00185             catch (...) {
00186                 // ignore
00187             }
00188             throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
00189         }
00190         CArchMiscWindows::setValue(key, _T("CommandLine"), commandLine);
00191 
00192         // done with registry
00193         CArchMiscWindows::closeKey(key);
00194     }
00195 }
00196 
00197 void
00198 CArchDaemonWindows::uninstallDaemon(const char* name, bool allUsers)
00199 {
00200     // if not for all users then use the user's autostart registry.
00201     // key.  if windows 95 family then use windows 95 services key.
00202     if (!allUsers || CArchMiscWindows::isWindows95Family()) {
00203         // open registry
00204         HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
00205                             open95ServicesKey() : openUserStartupKey();
00206         if (key == NULL) {
00207             // can't open key.  daemon is probably not installed.
00208             throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows);
00209         }
00210 
00211         // remove entry
00212         CArchMiscWindows::deleteValue(key, name);
00213 
00214         // clean up
00215         CArchMiscWindows::closeKey(key);
00216     }
00217 
00218     // windows NT family services
00219     else {
00220         // remove parameters for this service.  ignore failures.
00221         HKEY key = openNTServicesKey();
00222         key      = CArchMiscWindows::openKey(key, name);
00223         if (key != NULL) {
00224             CArchMiscWindows::deleteKey(key, _T("Parameters"));
00225             CArchMiscWindows::closeKey(key);
00226         }
00227 
00228         // open service manager
00229         SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
00230         if (mgr == NULL) {
00231             // can't open service manager
00232             throw XArchDaemonUninstallFailed(new XArchEvalWindows);
00233         }
00234 
00235         // open the service.  oddly, you must open a service to delete it.
00236         SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP);
00237         if (service == NULL) {
00238             DWORD err = GetLastError();
00239             CloseServiceHandle(mgr);
00240             if (err != ERROR_SERVICE_DOES_NOT_EXIST) {
00241                 throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
00242             }
00243             throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
00244         }
00245 
00246         // stop the service.  we don't care if we fail.
00247         SERVICE_STATUS status;
00248         ControlService(service, SERVICE_CONTROL_STOP, &status);
00249 
00250         // delete the service
00251         const bool okay = (DeleteService(service) == 0);
00252         const DWORD err = GetLastError();
00253 
00254         // clean up
00255         CloseServiceHandle(service);
00256         CloseServiceHandle(mgr);
00257 
00258         // give windows a chance to remove the service before
00259         // we check if it still exists.
00260         ARCH->sleep(1);
00261 
00262         // handle failure.  ignore error if service isn't installed anymore.
00263         if (!okay && isDaemonInstalled(name, allUsers)) {
00264             if (err == ERROR_SUCCESS) {
00265                 // this seems to occur even though the uninstall was successful.
00266                 // it could be a timing issue, i.e., isDaemonInstalled is
00267                 // called too soon. i've added a sleep to try and stop this.
00268                 return;
00269             }
00270             if (err == ERROR_IO_PENDING) {
00271                 // this seems to be a spurious error
00272                 return;
00273             }
00274             if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
00275                 throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
00276             }
00277             throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
00278         }
00279     }
00280 }
00281 
00282 int
00283 CArchDaemonWindows::daemonize(const char* name, DaemonFunc func)
00284 {
00285     assert(name != NULL);
00286     assert(func != NULL);
00287 
00288     // windows 95 family services
00289     if (CArchMiscWindows::isWindows95Family()) {
00290         typedef DWORD (WINAPI *RegisterServiceProcessT)(DWORD, DWORD);
00291 
00292         // mark this process as a service so it's not killed when the
00293         // user logs off.
00294         HINSTANCE kernel = LoadLibrary("kernel32.dll");
00295         if (kernel == NULL) {
00296             throw XArchDaemonFailed(new XArchEvalWindows);
00297         }
00298         RegisterServiceProcessT RegisterServiceProcess =
00299                                 reinterpret_cast<RegisterServiceProcessT>(
00300                                     GetProcAddress(kernel,
00301                                         "RegisterServiceProcess"));
00302         if (RegisterServiceProcess == NULL) {
00303             // missing RegisterServiceProcess function
00304             DWORD err = GetLastError();
00305             FreeLibrary(kernel);
00306             throw XArchDaemonFailed(new XArchEvalWindows(err));
00307         }
00308         if (RegisterServiceProcess(0, 1) == 0) {
00309             // RegisterServiceProcess failed
00310             DWORD err = GetLastError();
00311             FreeLibrary(kernel);
00312             throw XArchDaemonFailed(new XArchEvalWindows(err));
00313         }
00314         FreeLibrary(kernel);
00315 
00316         // now simply call the daemon function
00317         return func(1, &name);
00318     }
00319 
00320     // windows NT family services
00321     else {
00322         // save daemon function
00323         m_daemonFunc = func;
00324 
00325         // construct the service entry
00326         SERVICE_TABLE_ENTRY entry[2];
00327         entry[0].lpServiceName = const_cast<char*>(name);
00328         entry[0].lpServiceProc = &CArchDaemonWindows::serviceMainEntry;
00329         entry[1].lpServiceName = NULL;
00330         entry[1].lpServiceProc = NULL;
00331 
00332         // hook us up to the service control manager.  this won't return
00333         // (if successful) until the processes have terminated.
00334         s_daemon = this;
00335         if (StartServiceCtrlDispatcher(entry) == 0) {
00336             // StartServiceCtrlDispatcher failed
00337             s_daemon = NULL;
00338             throw XArchDaemonFailed(new XArchEvalWindows);
00339         }
00340 
00341         s_daemon = NULL;
00342         return m_daemonResult;
00343     }
00344 }
00345 
00346 bool
00347 CArchDaemonWindows::canInstallDaemon(const char* /*name*/, bool allUsers)
00348 {
00349     // if not for all users then use the user's autostart registry.
00350     // key.  if windows 95 family then use windows 95 services key.
00351     if (!allUsers || CArchMiscWindows::isWindows95Family()) {
00352         // check if we can open the registry key
00353         HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
00354                             open95ServicesKey() : openUserStartupKey();
00355         CArchMiscWindows::closeKey(key);
00356         return (key != NULL);
00357     }
00358 
00359     // windows NT family services
00360     else {
00361         // check if we can open service manager for write
00362         SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
00363         if (mgr == NULL) {
00364             return false;
00365         }
00366         CloseServiceHandle(mgr);
00367 
00368         // check if we can open the registry key
00369         HKEY key = openNTServicesKey();
00370 //      key      = CArchMiscWindows::addKey(key, name);
00371 //      key      = CArchMiscWindows::addKey(key, _T("Parameters"));
00372         CArchMiscWindows::closeKey(key);
00373 
00374         return (key != NULL);
00375     }
00376 }
00377 
00378 bool
00379 CArchDaemonWindows::isDaemonInstalled(const char* name, bool allUsers)
00380 {
00381     // open service manager
00382     SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
00383     if (mgr == NULL) {
00384         return false;
00385     }
00386 
00387     // open the service
00388     SC_HANDLE service = OpenService(mgr, name, GENERIC_READ);
00389 
00390     // clean up
00391     if (service != NULL) {
00392         CloseServiceHandle(service);
00393     }
00394     CloseServiceHandle(mgr);
00395 
00396     return (service != NULL);
00397 }
00398 
00399 HKEY
00400 CArchDaemonWindows::openNTServicesKey()
00401 {
00402     static const char* s_keyNames[] = {
00403         _T("SYSTEM"),
00404         _T("CurrentControlSet"),
00405         _T("Services"),
00406         NULL
00407     };
00408 
00409     return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
00410 }
00411 
00412 HKEY
00413 CArchDaemonWindows::open95ServicesKey()
00414 {
00415     static const char* s_keyNames[] = {
00416         _T("Software"),
00417         _T("Microsoft"),
00418         _T("Windows"),
00419         _T("CurrentVersion"),
00420         _T("RunServices"),
00421         NULL
00422     };
00423 
00424     return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
00425 }
00426 
00427 HKEY
00428 CArchDaemonWindows::openUserStartupKey()
00429 {
00430     static const char* s_keyNames[] = {
00431         _T("Software"),
00432         _T("Microsoft"),
00433         _T("Windows"),
00434         _T("CurrentVersion"),
00435         _T("Run"),
00436         NULL
00437     };
00438 
00439     return CArchMiscWindows::addKey(HKEY_CURRENT_USER, s_keyNames);
00440 }
00441 
00442 bool
00443 CArchDaemonWindows::isRunState(DWORD state)
00444 {
00445     switch (state) {
00446     case SERVICE_START_PENDING:
00447     case SERVICE_CONTINUE_PENDING:
00448     case SERVICE_RUNNING:
00449         return true;
00450 
00451     default:
00452         return false;
00453     }
00454 }
00455 
00456 int
00457 CArchDaemonWindows::doRunDaemon(RunFunc run)
00458 {
00459     // should only be called from DaemonFunc
00460     assert(m_serviceMutex != NULL);
00461     assert(run            != NULL);
00462 
00463     // create message queue for this thread
00464     MSG dummy;
00465     PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE);
00466 
00467     int result = 0;
00468     ARCH->lockMutex(m_serviceMutex);
00469     m_daemonThreadID = GetCurrentThreadId();
00470     while (m_serviceState != SERVICE_STOPPED) {
00471         // wait until we're told to start
00472         while (!isRunState(m_serviceState) &&
00473                 m_serviceState != SERVICE_STOP_PENDING) {
00474             ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
00475         }
00476 
00477         // run unless told to stop
00478         if (m_serviceState != SERVICE_STOP_PENDING) {
00479             ARCH->unlockMutex(m_serviceMutex);
00480             try {
00481                 result = run();
00482             }
00483             catch (...) {
00484                 ARCH->lockMutex(m_serviceMutex);
00485                 setStatusError(0);
00486                 m_serviceState = SERVICE_STOPPED;
00487                 setStatus(m_serviceState);
00488                 ARCH->broadcastCondVar(m_serviceCondVar);
00489                 ARCH->unlockMutex(m_serviceMutex);
00490                 throw;
00491             }
00492             ARCH->lockMutex(m_serviceMutex);
00493         }
00494 
00495         // notify of new state
00496         if (m_serviceState == SERVICE_PAUSE_PENDING) {
00497             m_serviceState = SERVICE_PAUSED;
00498         }
00499         else {
00500             m_serviceState = SERVICE_STOPPED;
00501         }
00502         setStatus(m_serviceState);
00503         ARCH->broadcastCondVar(m_serviceCondVar);
00504     }
00505     ARCH->unlockMutex(m_serviceMutex);
00506     return result;
00507 }
00508 
00509 void
00510 CArchDaemonWindows::doDaemonRunning(bool running)
00511 {
00512     ARCH->lockMutex(m_serviceMutex);
00513     if (running) {
00514         m_serviceState = SERVICE_RUNNING;
00515         setStatus(m_serviceState);
00516         ARCH->broadcastCondVar(m_serviceCondVar);
00517     }
00518     ARCH->unlockMutex(m_serviceMutex);
00519 }
00520 
00521 UINT
00522 CArchDaemonWindows::doGetDaemonQuitMessage()
00523 {
00524     return m_quitMessage;
00525 }
00526 
00527 void
00528 CArchDaemonWindows::setStatus(DWORD state)
00529 {
00530     setStatus(state, 0, 0);
00531 }
00532 
00533 void
00534 CArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
00535 {
00536     assert(s_daemon != NULL);
00537 
00538     SERVICE_STATUS status;
00539     status.dwServiceType             = SERVICE_WIN32_OWN_PROCESS |
00540                                         SERVICE_INTERACTIVE_PROCESS;
00541     status.dwCurrentState            = state;
00542     status.dwControlsAccepted        = SERVICE_ACCEPT_STOP |
00543                                         SERVICE_ACCEPT_PAUSE_CONTINUE |
00544                                         SERVICE_ACCEPT_SHUTDOWN;
00545     status.dwWin32ExitCode           = NO_ERROR;
00546     status.dwServiceSpecificExitCode = 0;
00547     status.dwCheckPoint              = step;
00548     status.dwWaitHint                = waitHint;
00549     SetServiceStatus(s_daemon->m_statusHandle, &status);
00550 }
00551 
00552 void
00553 CArchDaemonWindows::setStatusError(DWORD error)
00554 {
00555     assert(s_daemon != NULL);
00556 
00557     SERVICE_STATUS status;
00558     status.dwServiceType             = SERVICE_WIN32_OWN_PROCESS |
00559                                         SERVICE_INTERACTIVE_PROCESS;
00560     status.dwCurrentState            = SERVICE_STOPPED;
00561     status.dwControlsAccepted        = SERVICE_ACCEPT_STOP |
00562                                         SERVICE_ACCEPT_PAUSE_CONTINUE |
00563                                         SERVICE_ACCEPT_SHUTDOWN;
00564     status.dwWin32ExitCode           = ERROR_SERVICE_SPECIFIC_ERROR;
00565     status.dwServiceSpecificExitCode = error;
00566     status.dwCheckPoint              = 0;
00567     status.dwWaitHint                = 0;
00568     SetServiceStatus(s_daemon->m_statusHandle, &status);
00569 }
00570 
00571 void
00572 CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
00573 {
00574     typedef std::vector<LPCTSTR> ArgList;
00575     typedef std::vector<std::string> Arguments;
00576     const char** argv = const_cast<const char**>(argvIn);
00577 
00578     // create synchronization objects
00579     m_serviceMutex        = ARCH->newMutex();
00580     m_serviceCondVar      = ARCH->newCondVar();
00581     
00582     // register our service handler function
00583     m_statusHandle = RegisterServiceCtrlHandler(argv[0],
00584                                 &CArchDaemonWindows::serviceHandlerEntry);
00585     if (m_statusHandle == 0) {
00586         // cannot start as service
00587         m_daemonResult = -1;
00588         ARCH->closeCondVar(m_serviceCondVar);
00589         ARCH->closeMutex(m_serviceMutex);
00590         return;
00591     }
00592 
00593     // tell service control manager that we're starting
00594     m_serviceState = SERVICE_START_PENDING;
00595     setStatus(m_serviceState, 0, 10000);
00596 
00597     std::string commandLine;
00598 
00599     // if no arguments supplied then try getting them from the registry.
00600     // the first argument doesn't count because it's the service name.
00601     Arguments args;
00602     ArgList myArgv;
00603     if (argc <= 1) {
00604         // read command line
00605         HKEY key = openNTServicesKey();
00606         key      = CArchMiscWindows::openKey(key, argvIn[0]);
00607         key      = CArchMiscWindows::openKey(key, _T("Parameters"));
00608         if (key != NULL) {
00609             commandLine = CArchMiscWindows::readValueString(key,
00610                                                 _T("CommandLine"));
00611         }
00612 
00613         // if the command line isn't empty then parse and use it
00614         if (!commandLine.empty()) {
00615             // parse, honoring double quoted substrings
00616             std::string::size_type i = commandLine.find_first_not_of(" \t");
00617             while (i != std::string::npos && i != commandLine.size()) {
00618                 // find end of string
00619                 std::string::size_type e;
00620                 if (commandLine[i] == '\"') {
00621                     // quoted.  find closing quote.
00622                     ++i;
00623                     e = commandLine.find("\"", i);
00624 
00625                     // whitespace must follow closing quote
00626                     if (e == std::string::npos ||
00627                         (e + 1 != commandLine.size() &&
00628                         commandLine[e + 1] != ' ' &&
00629                         commandLine[e + 1] != '\t')) {
00630                         args.clear();
00631                         break;
00632                     }
00633 
00634                     // extract
00635                     args.push_back(commandLine.substr(i, e - i));
00636                     i = e + 1;
00637                 }
00638                 else {
00639                     // unquoted.  find next whitespace.
00640                     e = commandLine.find_first_of(" \t", i);
00641                     if (e == std::string::npos) {
00642                         e = commandLine.size();
00643                     }
00644 
00645                     // extract
00646                     args.push_back(commandLine.substr(i, e - i));
00647                     i = e + 1;
00648                 }
00649 
00650                 // next argument
00651                 i = commandLine.find_first_not_of(" \t", i);
00652             }
00653 
00654             // service name goes first
00655             myArgv.push_back(argv[0]);
00656 
00657             // get pointers
00658             for (size_t j = 0; j < args.size(); ++j) {
00659                 myArgv.push_back(args[j].c_str());
00660             }
00661 
00662             // adjust argc/argv
00663             argc = (DWORD)myArgv.size();
00664             argv = &myArgv[0];
00665         }
00666     }
00667 
00668     m_commandLine = commandLine;
00669 
00670     try {
00671         // invoke daemon function
00672         m_daemonResult = m_daemonFunc(static_cast<int>(argc), argv);
00673     }
00674     catch (XArchDaemonRunFailed& e) {
00675         setStatusError(e.m_result);
00676         m_daemonResult = -1;
00677     }
00678     catch (...) {
00679         setStatusError(1);
00680         m_daemonResult = -1;
00681     }
00682 
00683     // clean up
00684     ARCH->closeCondVar(m_serviceCondVar);
00685     ARCH->closeMutex(m_serviceMutex);
00686 
00687     // we're going to exit now, so set status to stopped
00688     m_serviceState = SERVICE_STOPPED;
00689     setStatus(m_serviceState, 0, 10000);
00690 }
00691 
00692 void WINAPI
00693 CArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR* argv)
00694 {
00695     s_daemon->serviceMain(argc, argv);
00696 }
00697 
00698 void
00699 CArchDaemonWindows::serviceHandler(DWORD ctrl)
00700 {
00701     assert(m_serviceMutex   != NULL);
00702     assert(m_serviceCondVar != NULL);
00703 
00704     ARCH->lockMutex(m_serviceMutex);
00705 
00706     // ignore request if service is already stopped
00707     if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
00708         if (s_daemon != NULL) {
00709             setStatus(m_serviceState);
00710         }
00711         ARCH->unlockMutex(m_serviceMutex);
00712         return;
00713     }
00714 
00715     switch (ctrl) {
00716     case SERVICE_CONTROL_PAUSE:
00717         m_serviceState = SERVICE_PAUSE_PENDING;
00718         setStatus(m_serviceState, 0, 5000);
00719         PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
00720         while (isRunState(m_serviceState)) {
00721             ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
00722         }
00723         break;
00724 
00725     case SERVICE_CONTROL_CONTINUE:
00726         // FIXME -- maybe should flush quit messages from queue
00727         m_serviceState = SERVICE_CONTINUE_PENDING;
00728         setStatus(m_serviceState, 0, 5000);
00729         ARCH->broadcastCondVar(m_serviceCondVar);
00730         break;
00731 
00732     case SERVICE_CONTROL_STOP:
00733     case SERVICE_CONTROL_SHUTDOWN:
00734         m_serviceState = SERVICE_STOP_PENDING;
00735         setStatus(m_serviceState, 0, 5000);
00736         PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
00737         ARCH->broadcastCondVar(m_serviceCondVar);
00738         while (isRunState(m_serviceState)) {
00739             ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
00740         }
00741         break;
00742 
00743     default:
00744         // unknown service command
00745         // fall through
00746 
00747     case SERVICE_CONTROL_INTERROGATE:
00748         setStatus(m_serviceState);
00749         break;
00750     }
00751 
00752     ARCH->unlockMutex(m_serviceMutex);
00753 }
00754 
00755 void WINAPI
00756 CArchDaemonWindows::serviceHandlerEntry(DWORD ctrl)
00757 {
00758     s_daemon->serviceHandler(ctrl);
00759 }
00760 
00761 void
00762 CArchDaemonWindows::start(const char* name)
00763 {
00764     // open service manager
00765     SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
00766     if (mgr == NULL) {
00767         throw XArchDaemonFailed(new XArchEvalWindows());
00768     }
00769 
00770     // open the service
00771     SC_HANDLE service = OpenService(
00772         mgr, name, SERVICE_START);
00773 
00774     if (service == NULL) {
00775         CloseServiceHandle(mgr);
00776         throw XArchDaemonFailed(new XArchEvalWindows());
00777     }
00778 
00779     // start the service
00780     if (!StartService(service, 0, NULL)) {
00781         throw XArchDaemonFailed(new XArchEvalWindows());
00782     }
00783 }
00784 
00785 void
00786 CArchDaemonWindows::stop(const char* name)
00787 {
00788     // open service manager
00789     SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
00790     if (mgr == NULL) {
00791         throw XArchDaemonFailed(new XArchEvalWindows());
00792     }
00793 
00794     // open the service
00795     SC_HANDLE service = OpenService(
00796         mgr, name,
00797         SERVICE_STOP | SERVICE_QUERY_STATUS);
00798 
00799     if (service == NULL) {
00800         CloseServiceHandle(mgr);
00801         throw XArchDaemonFailed(new XArchEvalWindows());
00802     }
00803 
00804     // ask the service to stop, asynchronously
00805     SERVICE_STATUS ss;
00806     if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) {
00807         DWORD dwErrCode = GetLastError(); 
00808         if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) {
00809             throw XArchDaemonFailed(new XArchEvalWindows());
00810         }
00811     }
00812 }
00813 
00814 void
00815 CArchDaemonWindows::installDaemon()
00816 {
00817     // install default daemon if not already installed.
00818     if (!isDaemonInstalled(DEFAULT_DAEMON_NAME, true)) {
00819         char path[MAX_PATH];
00820         GetModuleFileName(CArchMiscWindows::instanceWin32(), path, MAX_PATH);
00821         installDaemon(DEFAULT_DAEMON_NAME, DEFAULT_DAEMON_INFO, path, "", "", true);
00822     }
00823 
00824     start(DEFAULT_DAEMON_NAME);
00825 }
00826 
00827 void
00828 CArchDaemonWindows::uninstallDaemon()
00829 {
00830     // remove legacy services if installed.
00831     if (isDaemonInstalled(LEGACY_SERVER_DAEMON_NAME, true)) {
00832         uninstallDaemon(LEGACY_SERVER_DAEMON_NAME, true);
00833     }
00834     if (isDaemonInstalled(LEGACY_CLIENT_DAEMON_NAME, true)) {
00835         uninstallDaemon(LEGACY_CLIENT_DAEMON_NAME, true);
00836     }
00837 
00838     // remove new service if installed.
00839     if (isDaemonInstalled(DEFAULT_DAEMON_NAME, true)) {
00840         uninstallDaemon(DEFAULT_DAEMON_NAME, true);
00841     }
00842 }

Generated on Mon May 20 2013 00:00:04 for Synergy by  doxygen 1.7.1