• Main Page
  • Classes
  • Files
  • File List

CServerApp.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 "CServerApp.h"
00020 #include "CLog.h"
00021 #include "CArch.h"
00022 #include "XSocket.h"
00023 #include "Version.h"
00024 #include "IEventQueue.h"
00025 #include "CServer.h"
00026 #include "CClientListener.h"
00027 #include "CClientProxy.h"
00028 #include "TMethodEventJob.h"
00029 #include "CServerTaskBarReceiver.h"
00030 #include "CPrimaryClient.h"
00031 #include "CScreen.h"
00032 #include "CSocketMultiplexer.h"
00033 #include "CEventQueue.h"
00034 #include "LogOutputters.h"
00035 #include "CFunctionEventJob.h"
00036 #include "TMethodJob.h"
00037 #include "CVncClient.h"
00038 
00039 #if SYSAPI_WIN32
00040 #include "CArchMiscWindows.h"
00041 #endif
00042 
00043 #if WINAPI_MSWINDOWS
00044 #include "CMSWindowsScreen.h"
00045 #elif WINAPI_XWINDOWS
00046 #include "CXWindowsScreen.h"
00047 #elif WINAPI_CARBON
00048 #include "COSXScreen.h"
00049 #endif
00050 
00051 #include <iostream>
00052 #include <stdio.h>
00053 #include <fstream>
00054 #include "XScreen.h"
00055 #include "CTCPSocketFactory.h"
00056 
00057 CEvent::Type CServerApp::s_reloadConfigEvent = CEvent::kUnknown;
00058 
00059 CServerApp::CServerApp(CreateTaskBarReceiverFunc createTaskBarReceiver) :
00060 CApp(createTaskBarReceiver, new CArgs()),
00061 s_server(NULL),
00062 s_forceReconnectEvent(CEvent::kUnknown),
00063 s_resetServerEvent(CEvent::kUnknown),
00064 s_serverState(kUninitialized),
00065 s_serverScreen(NULL),
00066 s_primaryClient(NULL),
00067 s_listener(NULL),
00068 s_timer(NULL),
00069 m_vncClient(NULL)
00070 {
00071 }
00072 
00073 CServerApp::~CServerApp()
00074 {
00075 }
00076 
00077 CServerApp::CArgs::CArgs() :
00078 m_synergyAddress(NULL),
00079 m_config(NULL)
00080 {
00081 }
00082 
00083 CServerApp::CArgs::~CArgs()
00084 {
00085 }
00086 
00087 bool
00088 CServerApp::parseArg(const int& argc, const char* const* argv, int& i)
00089 {
00090     if (CApp::parseArg(argc, argv, i)) {
00091         // found common arg
00092         return true;
00093     }
00094 
00095     else if (isArg(i, argc, argv, "-a", "--address", 1)) {
00096         // save listen address
00097         try {
00098             *args().m_synergyAddress = CNetworkAddress(argv[i + 1],
00099                 kDefaultPort);
00100             args().m_synergyAddress->resolve();
00101         }
00102         catch (XSocketAddress& e) {
00103             LOG((CLOG_PRINT "%s: %s" BYE,
00104                 args().m_pname, e.what(), args().m_pname));
00105             m_bye(kExitArgs);
00106         }
00107         ++i;
00108     }
00109 
00110     else if (isArg(i, argc, argv, "-c", "--config", 1)) {
00111         // save configuration file path
00112         args().m_configFile = argv[++i];
00113     }
00114 
00115     else {
00116         // option not supported here
00117         return false;
00118     }
00119 
00120     // argument was valid
00121     return true;
00122 }
00123 
00124 void
00125 CServerApp::parseArgs(int argc, const char* const* argv)
00126 {
00127     // asserts values, sets defaults, and parses args
00128     int i;
00129     CApp::parseArgs(argc, argv, i);
00130 
00131     // no non-option arguments are allowed
00132     if (i != argc) {
00133         LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
00134             args().m_pname, argv[i], args().m_pname));
00135         m_bye(kExitArgs);
00136     }
00137 
00138     // set log filter
00139     if (!CLOG->setFilter(args().m_logFilter)) {
00140         LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
00141             args().m_pname, args().m_logFilter, args().m_pname));
00142         m_bye(kExitArgs);
00143     }
00144 
00145     // identify system
00146     LOG((CLOG_INFO "%s Server on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
00147 
00148     loggingFilterWarning();
00149 }
00150 
00151 void
00152 CServerApp::help()
00153 {
00154     // window api args (windows/x-windows/carbon)
00155 #if WINAPI_XWINDOWS
00156 #  define WINAPI_ARGS \
00157     " [--display <display>] [--no-xinitthreads]"
00158 #  define WINAPI_INFO \
00159     "      --display <display>  connect to the X server at <display>\n" \
00160     "      --no-xinitthreads    do not call XInitThreads()\n"
00161 #else
00162 #  define WINAPI_ARGS
00163 #  define WINAPI_INFO
00164 #endif
00165 
00166     char buffer[2000];
00167     sprintf(
00168         buffer,
00169         "Usage: %s"
00170         " [--address <address>]"
00171         " [--config <pathname>]"
00172         WINAPI_ARGS
00173         HELP_SYS_ARGS
00174         HELP_COMMON_ARGS
00175         "\n\n"
00176         "Start the synergy mouse/keyboard sharing server.\n"
00177         "\n"
00178         "  -a, --address <address>  listen for clients on the given address.\n"
00179         "  -c, --config <pathname>  use the named configuration file instead.\n"
00180         HELP_COMMON_INFO_1
00181         WINAPI_INFO
00182         HELP_SYS_INFO
00183         HELP_COMMON_INFO_2
00184         "\n"
00185         "* marks defaults.\n"
00186         "\n"
00187         "The argument for --address is of the form: [<hostname>][:<port>].  The\n"
00188         "hostname must be the address or hostname of an interface on the system.\n"
00189         "The default is to listen on all interfaces.  The port overrides the\n"
00190         "default port, %d.\n"
00191         "\n"
00192         "If no configuration file pathname is provided then the first of the\n"
00193         "following to load successfully sets the configuration:\n"
00194         "  %s\n"
00195         "  %s\n",
00196         args().m_pname, kDefaultPort,
00197         ARCH->concatPath(ARCH->getUserDirectory(), USR_CONFIG_NAME).c_str(),
00198         ARCH->concatPath(ARCH->getSystemDirectory(), SYS_CONFIG_NAME).c_str()
00199     );
00200 
00201     LOG((CLOG_PRINT "%s", buffer));
00202 }
00203 
00204 void
00205 CServerApp::reloadSignalHandler(CArch::ESignal, void*)
00206 {
00207     EVENTQUEUE->addEvent(CEvent(getReloadConfigEvent(),
00208         IEventQueue::getSystemTarget()));
00209 }
00210 
00211 void
00212 CServerApp::reloadConfig(const CEvent&, void*)
00213 {
00214     LOG((CLOG_DEBUG "reload configuration"));
00215     if (loadConfig(args().m_configFile)) {
00216         if (s_server != NULL) {
00217             s_server->setConfig(*args().m_config);
00218         }
00219         LOG((CLOG_NOTE "reloaded configuration"));
00220     }
00221 }
00222 
00223 void
00224 CServerApp::loadConfig()
00225 {
00226     bool loaded = false;
00227 
00228     // load the config file, if specified
00229     if (!args().m_configFile.empty()) {
00230         loaded = loadConfig(args().m_configFile);
00231     }
00232 
00233     // load the default configuration if no explicit file given
00234     else {
00235         // get the user's home directory
00236         CString path = ARCH->getUserDirectory();
00237         if (!path.empty()) {
00238             // complete path
00239             path = ARCH->concatPath(path, USR_CONFIG_NAME);
00240 
00241             // now try loading the user's configuration
00242             if (loadConfig(path)) {
00243                 loaded            = true;
00244                 args().m_configFile = path;
00245             }
00246         }
00247         if (!loaded) {
00248             // try the system-wide config file
00249             path = ARCH->getSystemDirectory();
00250             if (!path.empty()) {
00251                 path = ARCH->concatPath(path, SYS_CONFIG_NAME);
00252                 if (loadConfig(path)) {
00253                     loaded            = true;
00254                     args().m_configFile = path;
00255                 }
00256             }
00257         }
00258     }
00259 
00260     if (!loaded) {
00261         LOG((CLOG_PRINT "%s: no configuration available", args().m_pname));
00262         m_bye(kExitConfig);
00263     }
00264 }
00265 
00266 bool
00267 CServerApp::loadConfig(const CString& pathname)
00268 {
00269     try {
00270         // load configuration
00271         LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str()));
00272         std::ifstream configStream(pathname.c_str());
00273         if (!configStream.is_open()) {
00274             // report failure to open configuration as a debug message
00275             // since we try several paths and we expect some to be
00276             // missing.
00277             LOG((CLOG_DEBUG "cannot open configuration \"%s\"",
00278                 pathname.c_str()));
00279             return false;
00280         }
00281         configStream >> *args().m_config;
00282         LOG((CLOG_DEBUG "configuration read successfully"));
00283         return true;
00284     }
00285     catch (XConfigRead& e) {
00286         // report error in configuration file
00287         LOG((CLOG_ERR "cannot read configuration \"%s\": %s",
00288             pathname.c_str(), e.what()));
00289     }
00290     return false;
00291 }
00292 
00293 CEvent::Type 
00294 CServerApp::getReloadConfigEvent()
00295 {
00296     return EVENTQUEUE->registerTypeOnce(s_reloadConfigEvent, "reloadConfig");
00297 }
00298 
00299 void 
00300 CServerApp::forceReconnect(const CEvent&, void*)
00301 {
00302     if (s_server != NULL) {
00303         s_server->disconnect();
00304     }
00305 }
00306 
00307 CEvent::Type 
00308 CServerApp::getForceReconnectEvent()
00309 {
00310     return EVENTQUEUE->registerTypeOnce(s_forceReconnectEvent, "forceReconnect");
00311 }
00312 
00313 CEvent::Type
00314 CServerApp::getResetServerEvent()
00315 {
00316     return EVENTQUEUE->registerTypeOnce(s_resetServerEvent, "resetServer");
00317 }
00318 
00319 void 
00320 CServerApp::handleClientConnected(const CEvent&, void* vlistener)
00321 {
00322     CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
00323     CClientProxy* client = listener->getNextClient();
00324     if (client != NULL) {
00325         s_server->adoptClient(client);
00326         updateStatus();
00327 
00328         if (args().m_enableVnc) {
00329             // TODO: figure out client IP address from name.
00330             CVncClient* vncClient = new CVncClient("192.168.0.13", client->getName());
00331             vncClient->start();
00332             m_vncClients.insert(std::pair<CString, CVncClient*>(client->getName(), vncClient));
00333         }
00334     }
00335 }
00336 
00337 void
00338 CServerApp::handleClientsDisconnected(const CEvent&, void*)
00339 {
00340     EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00341 }
00342 
00343 void
00344 CServerApp::closeServer(CServer* server)
00345 {
00346     if (server == NULL) {
00347         return;
00348     }
00349 
00350     // tell all clients to disconnect
00351     server->disconnect();
00352 
00353     // wait for clients to disconnect for up to timeout seconds
00354     double timeout = 3.0;
00355     CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
00356     EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
00357         new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected));
00358     EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
00359         new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected));
00360     
00361     EVENTQUEUE->loop();
00362 
00363     EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
00364     EVENTQUEUE->deleteTimer(timer);
00365     EVENTQUEUE->removeHandler(CServer::getDisconnectedEvent(), server);
00366 
00367     // done with server
00368     delete server;
00369 }
00370 
00371 void 
00372 CServerApp::stopRetryTimer()
00373 {
00374     if (s_timer != NULL) {
00375         EVENTQUEUE->deleteTimer(s_timer);
00376         EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
00377         s_timer = NULL;
00378     }
00379 }
00380 
00381 void
00382 CServerApp::updateStatus()
00383 {
00384     updateStatus("");
00385 }
00386 
00387 void CServerApp::updateStatus( const CString& msg )
00388 {
00389     if (m_taskBarReceiver)
00390     {
00391         m_taskBarReceiver->updateStatus(s_server, msg);
00392     }
00393 }
00394 
00395 void 
00396 CServerApp::closeClientListener(CClientListener* listen)
00397 {
00398     if (listen != NULL) {
00399         EVENTQUEUE->removeHandler(CClientListener::getConnectedEvent(), listen);
00400         delete listen;
00401     }
00402 }
00403 
00404 void 
00405 CServerApp::stopServer()
00406 {
00407     if (s_serverState == kStarted) {
00408         closeClientListener(s_listener);
00409         closeServer(s_server);
00410         s_server      = NULL;
00411         s_listener    = NULL;
00412         s_serverState = kInitialized;
00413     }
00414     else if (s_serverState == kStarting) {
00415         stopRetryTimer();
00416         s_serverState = kInitialized;
00417     }
00418     assert(s_server == NULL);
00419     assert(s_listener == NULL);
00420 }
00421 
00422 void
00423 CServerApp::closePrimaryClient(CPrimaryClient* primaryClient)
00424 {
00425     delete primaryClient;
00426 }
00427 
00428 void 
00429 CServerApp::closeServerScreen(CScreen* screen)
00430 {
00431     if (screen != NULL) {
00432         EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
00433             screen->getEventTarget());
00434         EVENTQUEUE->removeHandler(IScreen::getSuspendEvent(),
00435             screen->getEventTarget());
00436         EVENTQUEUE->removeHandler(IScreen::getResumeEvent(),
00437             screen->getEventTarget());
00438         delete screen;
00439     }
00440 }
00441 
00442 void CServerApp::cleanupServer()
00443 {
00444     stopServer();
00445     if (s_serverState == kInitialized) {
00446         closePrimaryClient(s_primaryClient);
00447         closeServerScreen(s_serverScreen);
00448         s_primaryClient = NULL;
00449         s_serverScreen  = NULL;
00450         s_serverState   = kUninitialized;
00451     }
00452     else if (s_serverState == kInitializing ||
00453         s_serverState == kInitializingToStart) {
00454             stopRetryTimer();
00455             s_serverState = kUninitialized;
00456     }
00457     assert(s_primaryClient == NULL);
00458     assert(s_serverScreen == NULL);
00459     assert(s_serverState == kUninitialized);
00460 }
00461 
00462 void
00463 CServerApp::retryHandler(const CEvent&, void*)
00464 {
00465     // discard old timer
00466     assert(s_timer != NULL);
00467     stopRetryTimer();
00468 
00469     // try initializing/starting the server again
00470     switch (s_serverState) {
00471     case kUninitialized:
00472     case kInitialized:
00473     case kStarted:
00474         assert(0 && "bad internal server state");
00475         break;
00476 
00477     case kInitializing:
00478         LOG((CLOG_DEBUG1 "retry server initialization"));
00479         s_serverState = kUninitialized;
00480         if (!initServer()) {
00481             EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00482         }
00483         break;
00484 
00485     case kInitializingToStart:
00486         LOG((CLOG_DEBUG1 "retry server initialization"));
00487         s_serverState = kUninitialized;
00488         if (!initServer()) {
00489             EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00490         }
00491         else if (s_serverState == kInitialized) {
00492             LOG((CLOG_DEBUG1 "starting server"));
00493             if (!startServer()) {
00494                 EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00495             }
00496         }
00497         break;
00498 
00499     case kStarting:
00500         LOG((CLOG_DEBUG1 "retry starting server"));
00501         s_serverState = kInitialized;
00502         if (!startServer()) {
00503             EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00504         }
00505         break;
00506     }
00507 }
00508 
00509 bool CServerApp::initServer()
00510 {
00511     // skip if already initialized or initializing
00512     if (s_serverState != kUninitialized) {
00513         return true;
00514     }
00515 
00516     double retryTime;
00517     CScreen* serverScreen         = NULL;
00518     CPrimaryClient* primaryClient = NULL;
00519     try {
00520         CString name    = args().m_config->getCanonicalName(args().m_name);
00521         serverScreen    = openServerScreen();
00522         primaryClient   = openPrimaryClient(name, serverScreen);
00523         s_serverScreen  = serverScreen;
00524         s_primaryClient = primaryClient;
00525         s_serverState   = kInitialized;
00526         updateStatus();
00527         return true;
00528     }
00529     catch (XScreenUnavailable& e) {
00530         LOG((CLOG_WARN "primary screen unavailable: %s", e.what()));
00531         closePrimaryClient(primaryClient);
00532         closeServerScreen(serverScreen);
00533         updateStatus(CString("primary screen unavailable: ") + e.what());
00534         retryTime = e.getRetryTime();
00535     }
00536     catch (XScreenOpenFailure& e) {
00537         LOG((CLOG_CRIT "failed to start server: %s", e.what()));
00538         closePrimaryClient(primaryClient);
00539         closeServerScreen(serverScreen);
00540         return false;
00541     }
00542     catch (XBase& e) {
00543         LOG((CLOG_CRIT "failed to start server: %s", e.what()));
00544         closePrimaryClient(primaryClient);
00545         closeServerScreen(serverScreen);
00546         return false;
00547     }
00548 
00549     if (args().m_restartable) {
00550         // install a timer and handler to retry later
00551         assert(s_timer == NULL);
00552         LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
00553         s_timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
00554         EVENTQUEUE->adoptHandler(CEvent::kTimer, s_timer,
00555             new TMethodEventJob<CServerApp>(this, &CServerApp::retryHandler));
00556         s_serverState = kInitializing;
00557         return true;
00558     }
00559     else {
00560         // don't try again
00561         return false;
00562     }
00563 }
00564 
00565 CScreen* CServerApp::openServerScreen()
00566 {
00567     CScreen* screen = createScreen();
00568     EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
00569         screen->getEventTarget(),
00570         new TMethodEventJob<CServerApp>(
00571         this, &CServerApp::handleScreenError));
00572     EVENTQUEUE->adoptHandler(IScreen::getSuspendEvent(),
00573         screen->getEventTarget(),
00574         new TMethodEventJob<CServerApp>(
00575         this, &CServerApp::handleSuspend));
00576     EVENTQUEUE->adoptHandler(IScreen::getResumeEvent(),
00577         screen->getEventTarget(),
00578         new TMethodEventJob<CServerApp>(
00579         this, &CServerApp::handleResume));
00580     return screen;
00581 }
00582 
00583 bool 
00584 CServerApp::startServer()
00585 {
00586     // skip if already started or starting
00587     if (s_serverState == kStarting || s_serverState == kStarted) {
00588         return true;
00589     }
00590 
00591     // initialize if necessary
00592     if (s_serverState != kInitialized) {
00593         if (!initServer()) {
00594             // hard initialization failure
00595             return false;
00596         }
00597         if (s_serverState == kInitializing) {
00598             // not ready to start
00599             s_serverState = kInitializingToStart;
00600             return true;
00601         }
00602         assert(s_serverState == kInitialized);
00603     }
00604 
00605     double retryTime;
00606     CClientListener* listener = NULL;
00607     try {
00608         listener   = openClientListener(args().m_config->getSynergyAddress());
00609         s_server   = openServer(*args().m_config, s_primaryClient);
00610         listener->setServer(s_server);
00611         s_listener = listener;
00612         updateStatus();
00613         LOG((CLOG_NOTE "started server, waiting for clients"));
00614         s_serverState = kStarted;
00615         return true;
00616     }
00617     catch (XSocketAddressInUse& e) {
00618         LOG((CLOG_WARN "cannot listen for clients: %s", e.what()));
00619         closeClientListener(listener);
00620         updateStatus(CString("cannot listen for clients: ") + e.what());
00621         retryTime = 10.0;
00622     }
00623     catch (XBase& e) {
00624         LOG((CLOG_CRIT "failed to start server: %s", e.what()));
00625         closeClientListener(listener);
00626         return false;
00627     }
00628 
00629     if (args().m_restartable) {
00630         // install a timer and handler to retry later
00631         assert(s_timer == NULL);
00632         LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
00633         s_timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
00634         EVENTQUEUE->adoptHandler(CEvent::kTimer, s_timer,
00635             new TMethodEventJob<CServerApp>(this, &CServerApp::retryHandler));
00636         s_serverState = kStarting;
00637         return true;
00638     }
00639     else {
00640         // don't try again
00641         return false;
00642     }
00643 }
00644 
00645 CScreen* 
00646 CServerApp::createScreen()
00647 {
00648 #if WINAPI_MSWINDOWS
00649     return new CScreen(new CMSWindowsScreen(
00650         true, args().m_noHooks, args().m_gameDevice, args().m_stopOnDeskSwitch));
00651 #elif WINAPI_XWINDOWS
00652     return new CScreen(new CXWindowsScreen(
00653         args().m_display, true, args().m_disableXInitThreads, 0, *EVENTQUEUE));
00654 #elif WINAPI_CARBON
00655     return new CScreen(new COSXScreen(true));
00656 #endif
00657 }
00658 
00659 CPrimaryClient* 
00660 CServerApp::openPrimaryClient(const CString& name, CScreen* screen)
00661 {
00662     LOG((CLOG_DEBUG1 "creating primary screen"));
00663     return new CPrimaryClient(name, screen);
00664 
00665 }
00666 
00667 void
00668 CServerApp::handleScreenError(const CEvent&, void*)
00669 {
00670     LOG((CLOG_CRIT "error on screen"));
00671     EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
00672 }
00673 
00674 void 
00675 CServerApp::handleSuspend(const CEvent&, void*)
00676 {
00677     if (!m_suspended) {
00678         LOG((CLOG_INFO "suspend"));
00679         stopServer();
00680         m_suspended = true;
00681     }
00682 }
00683 
00684 void 
00685 CServerApp::handleResume(const CEvent&, void*)
00686 {
00687     if (m_suspended) {
00688         LOG((CLOG_INFO "resume"));
00689         startServer();
00690         m_suspended = false;
00691     }
00692 }
00693 
00694 CClientListener*
00695 CServerApp::openClientListener(const CNetworkAddress& address)
00696 {
00697     CClientListener* listen =
00698         new CClientListener(address, new CTCPSocketFactory, NULL, args().m_crypto);
00699     EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
00700         new TMethodEventJob<CServerApp>(
00701         this, &CServerApp::handleClientConnected, listen));
00702     return listen;
00703 }
00704 
00705 CServer* 
00706 CServerApp::openServer(const CConfig& config, CPrimaryClient* primaryClient)
00707 {
00708     CServer* server = new CServer(config, primaryClient, s_serverScreen);
00709 
00710     try {
00711         EVENTQUEUE->adoptHandler(
00712             CServer::getDisconnectedEvent(), server,
00713             new TMethodEventJob<CServerApp>(this, &CServerApp::handleNoClients));
00714 
00715         EVENTQUEUE->adoptHandler(
00716             CServer::getScreenSwitchedEvent(), server,
00717             new TMethodEventJob<CServerApp>(this, &CServerApp::handleScreenSwitched));
00718 
00719     } catch (std::bad_alloc &ba) {
00720         delete server;
00721         throw ba;
00722     }
00723 
00724     return server;
00725 }
00726 
00727 void
00728 CServerApp::handleNoClients(const CEvent&, void*)
00729 {
00730     updateStatus();
00731 }
00732 
00733 void
00734 CServerApp::handleScreenSwitched(const CEvent& e, void*)
00735 {
00736     if (!args().m_enableVnc)
00737         return;
00738 
00739     if (m_vncClient != NULL) {
00740         LOG((CLOG_DEBUG "hiding vnc viewer for: %s", m_vncClient->m_screen.c_str()));
00741         m_vncClient->hideViewer();
00742     }
00743 
00744     CServer::CSwitchToScreenInfo* info = reinterpret_cast<CServer::CSwitchToScreenInfo*>(e.getData());
00745     std::map<CString, CVncClient*>::iterator it = m_vncClients.find(info->m_screen);
00746     if (it == m_vncClients.end()) {
00747         LOG((CLOG_DEBUG "could not find vnc client for: %s", info->m_screen));
00748         return;
00749     }
00750 
00751     LOG((CLOG_DEBUG "showing vnc viewer for: %s", info->m_screen));
00752     m_vncClient = it->second;
00753     m_vncClient->showViewer();
00754 }
00755 
00756 int
00757 CServerApp::mainLoop()
00758 {
00759     // create socket multiplexer.  this must happen after daemonization
00760     // on unix because threads evaporate across a fork().
00761     CSocketMultiplexer multiplexer;
00762 
00763     // if configuration has no screens then add this system
00764     // as the default
00765     if (args().m_config->begin() == args().m_config->end()) {
00766         args().m_config->addScreen(args().m_name);
00767     }
00768 
00769     // set the contact address, if provided, in the config.
00770     // otherwise, if the config doesn't have an address, use
00771     // the default.
00772     if (args().m_synergyAddress->isValid()) {
00773         args().m_config->setSynergyAddress(*args().m_synergyAddress);
00774     }
00775     else if (!args().m_config->getSynergyAddress().isValid()) {
00776         args().m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
00777     }
00778 
00779     // canonicalize the primary screen name
00780     CString primaryName = args().m_config->getCanonicalName(args().m_name);
00781     if (primaryName.empty()) {
00782         LOG((CLOG_CRIT "unknown screen name `%s'", args().m_name.c_str()));
00783         return kExitFailed;
00784     }
00785 
00786     // start server, etc
00787     appUtil().startNode();
00788     
00789     // init ipc client after node start, since create a new screen wipes out
00790     // the event queue (the screen ctors call adoptBuffer).
00791     if (argsBase().m_enableIpc) {
00792         initIpcClient();
00793     }
00794 
00795     // load all available plugins.
00796     ARCH->plugin().init(s_serverScreen->getEventTarget());
00797 
00798     // handle hangup signal by reloading the server's configuration
00799     ARCH->setSignalHandler(CArch::kHANGUP, &reloadSignalHandler, NULL);
00800     EVENTQUEUE->adoptHandler(getReloadConfigEvent(),
00801         IEventQueue::getSystemTarget(),
00802         new TMethodEventJob<CServerApp>(this, &CServerApp::reloadConfig));
00803 
00804     // handle force reconnect event by disconnecting clients.  they'll
00805     // reconnect automatically.
00806     EVENTQUEUE->adoptHandler(getForceReconnectEvent(),
00807         IEventQueue::getSystemTarget(),
00808         new TMethodEventJob<CServerApp>(this, &CServerApp::forceReconnect));
00809 
00810     // to work around the sticky meta keys problem, we'll give users
00811     // the option to reset the state of synergys
00812     EVENTQUEUE->adoptHandler(getResetServerEvent(),
00813         IEventQueue::getSystemTarget(),
00814         new TMethodEventJob<CServerApp>(this, &CServerApp::resetServer));
00815 
00816     // run event loop.  if startServer() failed we're supposed to retry
00817     // later.  the timer installed by startServer() will take care of
00818     // that.
00819     DAEMON_RUNNING(true);
00820     EVENTQUEUE->loop();
00821     DAEMON_RUNNING(false);
00822 
00823     // close down
00824     LOG((CLOG_DEBUG1 "stopping server"));
00825     EVENTQUEUE->removeHandler(getForceReconnectEvent(),
00826         IEventQueue::getSystemTarget());
00827     EVENTQUEUE->removeHandler(getReloadConfigEvent(),
00828         IEventQueue::getSystemTarget());
00829     cleanupServer();
00830     updateStatus();
00831     LOG((CLOG_NOTE "stopped server"));
00832 
00833     if (argsBase().m_enableIpc) {
00834         cleanupIpcClient();
00835     }
00836 
00837     return kExitSuccess;
00838 }
00839 
00840 void CServerApp::resetServer(const CEvent&, void*)
00841 {
00842     LOG((CLOG_DEBUG1 "resetting server"));
00843     stopServer();
00844     cleanupServer();
00845     startServer();
00846 }
00847 
00848 int 
00849 CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
00850 {
00851     // general initialization
00852     args().m_synergyAddress = new CNetworkAddress;
00853     args().m_config         = new CConfig;
00854     args().m_pname          = ARCH->getBasename(argv[0]);
00855 
00856     // install caller's output filter
00857     if (outputter != NULL) {
00858         CLOG->insert(outputter);
00859     }
00860 
00861     // run
00862     int result = startup(argc, argv);
00863 
00864     if (m_taskBarReceiver)
00865     {
00866         // done with task bar receiver
00867         delete m_taskBarReceiver;
00868     }
00869 
00870     delete args().m_config;
00871     delete args().m_synergyAddress;
00872     return result;
00873 }
00874 
00875 int daemonMainLoopStatic(int argc, const char** argv) {
00876     return CServerApp::instance().daemonMainLoop(argc, argv);
00877 }
00878 
00879 int 
00880 CServerApp::standardStartup(int argc, char** argv)
00881 {
00882     initApp(argc, argv);
00883 
00884     // daemonize if requested
00885     if (args().m_daemon) {
00886         return ARCH->daemonize(daemonName(), daemonMainLoopStatic);
00887     }
00888     else {
00889         return mainLoop();
00890     }
00891 }
00892 
00893 int 
00894 CServerApp::foregroundStartup(int argc, char** argv)
00895 {
00896     initApp(argc, argv);
00897 
00898     // never daemonize
00899     return mainLoop();
00900 }
00901 
00902 static
00903 int 
00904 mainLoopStatic() 
00905 {
00906     return CServerApp::instance().mainLoop();
00907 }
00908 
00909 const char* 
00910 CServerApp::daemonName() const
00911 {
00912 #if SYSAPI_WIN32
00913     return "Synergy Server";
00914 #elif SYSAPI_UNIX
00915     return "synergys";
00916 #endif
00917 }
00918 
00919 const char* 
00920 CServerApp::daemonInfo() const
00921 {
00922 #if SYSAPI_WIN32
00923     return "Shares this computers mouse and keyboard with other computers.";
00924 #elif SYSAPI_UNIX
00925     return "";
00926 #endif
00927 }
00928 
00929 void
00930 CServerApp::startNode()
00931 {
00932     // start the server.  if this return false then we've failed and
00933     // we shouldn't retry.
00934     LOG((CLOG_DEBUG1 "starting server"));
00935     if (!startServer()) {
00936         m_bye(kExitFailed);
00937     }
00938 }

Generated on Thu May 23 2013 00:00:04 for Synergy by  doxygen 1.7.1