CArchDaemonWindows.cpp

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

Generated on Fri Nov 6 00:18:44 2009 for synergy-plus by  doxygen 1.4.7