"Fossies" - the Fresh Open Source Software Archive

Member "tvnserver-2.0.4/tvnserver-app/TvnServer.cpp" (3 Aug 2011, 10302 Bytes) of archive /windows/misc/tvnserver-2.0.4-src.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "TvnServer.cpp" see the Fossies "Dox" file reference documentation.

    1 // Copyright (C) 2008, 2009, 2010 GlavSoft LLC.
    2 // All rights reserved.
    3 //
    4 //-------------------------------------------------------------------------
    5 // This file is part of the TightVNC software.  Please visit our Web site:
    6 //
    7 //                       http://www.tightvnc.com/
    8 //
    9 // This program is free software; you can redistribute it and/or modify
   10 // it under the terms of the GNU General Public License as published by
   11 // the Free Software Foundation; either version 2 of the License, or
   12 // (at your option) any later version.
   13 //
   14 // This program is distributed in the hope that it will be useful,
   15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17 // GNU General Public License for more details.
   18 //
   19 // You should have received a copy of the GNU General Public License along
   20 // with this program; if not, write to the Free Software Foundation, Inc.,
   21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   22 //-------------------------------------------------------------------------
   23 //
   24 
   25 #include "TvnServer.h"
   26 #include "WsConfigRunner.h"
   27 #include "AdditionalActionApplication.h"
   28 #include "win-system/CurrentConsoleProcess.h"
   29 
   30 #include "server-config-lib/Configurator.h"
   31 
   32 #include "thread/GlobalMutex.h"
   33 
   34 #include "tvnserver/resource.h"
   35 
   36 #include "wsconfig-lib/TvnLogFilename.h"
   37 
   38 #include "network/socket/WindowsSocket.h"
   39 
   40 #include "util/FileLog.h"
   41 #include "util/StringTable.h"
   42 
   43 #include "file-lib/File.h"
   44 
   45 #include "tvncontrol-app/TransportFactory.h"
   46 #include "tvncontrol-app/ControlPipeName.h"
   47 
   48 #include "tvnserver/BuildTime.h"
   49 
   50 #include <crtdbg.h>
   51 #include <time.h>
   52 
   53 TvnServer::TvnServer(bool runsInServiceContext)
   54 : Singleton<TvnServer>(),
   55   ListenerContainer<TvnServerListener *>(),
   56   m_runAsService(runsInServiceContext),
   57   m_rfbClientManager(0),
   58   m_httpServer(0), m_controlServer(0), m_rfbServer(0)
   59 {
   60   Configurator *configurator = Configurator::getInstance();
   61 
   62   configurator->setServiceFlag(m_runAsService);
   63 
   64   configurator->load();
   65 
   66   m_config = Configurator::getInstance()->getServerConfig();
   67 
   68   resetLogFilePath();
   69 
   70   m_log.changeLevel(m_config->getLogLevel());
   71 
   72   Log::message(_T("TightVNC Server Build on %s"), BuildTime::DATE);
   73 
   74   Log::info(_T("Initialize WinSock"));
   75 
   76   try {
   77     WindowsSocket::startup(2, 1);
   78   } catch (Exception &ex) {
   79     Log::interror(_T("%s"), ex.getMessage());
   80   }
   81 
   82   ZombieKiller *zombieKiller = new ZombieKiller();
   83 
   84   m_rfbClientManager = new RfbClientManager(NULL);
   85 
   86   m_rfbClientManager->addListener(this);
   87 
   88   Configurator::getInstance()->addListener(this);
   89 
   90   {
   91     AutoLock l(&m_mutex);
   92 
   93     restartMainRfbServer();
   94     (void)m_extraRfbServers.reload(m_runAsService, m_rfbClientManager);
   95     restartHttpServer();
   96     restartControlServer();
   97   }
   98 }
   99 
  100 TvnServer::~TvnServer()
  101 {
  102   Configurator::getInstance()->removeListener(this);
  103 
  104   stopControlServer();
  105   stopHttpServer();
  106   m_extraRfbServers.shutDown();
  107   stopMainRfbServer();
  108 
  109   ZombieKiller *zombieKiller = ZombieKiller::getInstance();
  110 
  111   zombieKiller->killAllZombies();
  112 
  113   m_rfbClientManager->removeListener(this);
  114 
  115   delete m_rfbClientManager;
  116 
  117   delete zombieKiller;
  118 
  119   Log::info(_T("Shutdown WinSock"));
  120 
  121   try {
  122     WindowsSocket::cleanup();
  123   } catch (Exception &ex) {
  124     Log::error(_T("%s"), ex.getMessage());
  125   }
  126 
  127   delete Configurator::getInstance();
  128 }
  129 
  130 void TvnServer::onConfigReload(ServerConfig *serverConfig)
  131 {
  132   resetLogFilePath();
  133 
  134   m_log.changeLevel(serverConfig->getLogLevel());
  135 
  136   {
  137     AutoLock l(&m_mutex);
  138 
  139     bool toggleMainRfbServer =
  140       m_config->isAcceptingRfbConnections() != (m_rfbServer != 0);
  141     bool changeMainRfbPort = m_rfbServer != 0 &&
  142       (m_config->getRfbPort() != (int)m_rfbServer->getBindPort());
  143 
  144     const TCHAR *bindHost =
  145       m_config->isOnlyLoopbackConnectionsAllowed() ? _T("localhost") : _T("0.0.0.0");
  146     bool changeBindHost =  m_rfbServer != 0 &&
  147       _tcscmp(m_rfbServer->getBindHost(), bindHost) != 0;
  148 
  149     if (toggleMainRfbServer ||
  150         changeMainRfbPort ||
  151         changeBindHost) {
  152       restartMainRfbServer();
  153     }
  154 
  155     (void)m_extraRfbServers.reload(m_runAsService, m_rfbClientManager);
  156   }
  157 
  158   {
  159     AutoLock l(&m_mutex);
  160 
  161     bool toggleHttp =
  162       m_config->isAcceptingHttpConnections() != (m_httpServer != 0);
  163     bool changePort = m_httpServer != 0 &&
  164       (m_config->getHttpPort() != (int)m_httpServer->getBindPort());
  165 
  166     if (toggleHttp || changePort) {
  167       restartHttpServer();
  168     }
  169   }
  170 }
  171 
  172 void TvnServer::getServerInfo(TvnServerInfo *info)
  173 {
  174   bool rfbServerListening = true;
  175   {
  176     AutoLock l(&m_mutex);
  177     rfbServerListening = m_rfbServer != 0;
  178   }
  179 
  180   StringStorage statusString;
  181 
  182   bool vncAuthEnabled = m_config->isUsingAuthentication();
  183   bool noVncPasswords = !m_config->hasPrimaryPassword() && !m_config->hasReadOnlyPassword();
  184   bool vncPasswordsError = vncAuthEnabled && noVncPasswords;
  185 
  186   if (rfbServerListening) {
  187     if (vncPasswordsError) {
  188       statusString = StringTable::getString(IDS_NO_PASSWORDS_SET);
  189     } else {
  190       char localAddressString[1024];
  191       getLocalIPAddrString(localAddressString, 1024);
  192 
  193       statusString.fromAnsiString(localAddressString);
  194 
  195       if (!vncAuthEnabled) {
  196         statusString.appendString(StringTable::getString(IDS_NO_AUTH_STATUS));
  197       } 
  198     } 
  199   } else {
  200     statusString = StringTable::getString(IDS_SERVER_NOT_LISTENING);
  201   } 
  202 
  203   UINT stringId = m_runAsService ? IDS_TVNSERVER_SERVICE : IDS_TVNSERVER_APP;
  204 
  205   info->m_statusText.format(_T("%s - %s"),
  206                             StringTable::getString(stringId),
  207                             statusString.getString());
  208   info->m_acceptFlag = rfbServerListening && !vncPasswordsError;
  209   info->m_serviceFlag = m_runAsService;
  210 }
  211 
  212 void TvnServer::generateExternalShutdownSignal()
  213 {
  214   AutoLock l(&m_listeners);
  215 
  216   vector<TvnServerListener *>::iterator it;
  217   for (it = m_listeners.begin(); it != m_listeners.end(); it++) {
  218     TvnServerListener *each = *it;
  219 
  220     each->onTvnServerShutdown();
  221   } 
  222 }
  223 
  224 bool TvnServer::isRunningAsService() const
  225 {
  226   return m_runAsService;
  227 }
  228 
  229 void TvnServer::afterFirstClientConnect()
  230 {
  231 }
  232 
  233 void TvnServer::afterLastClientDisconnect()
  234 {
  235   ServerConfig::DisconnectAction action = m_config->getDisconnectAction();
  236 
  237   StringStorage keys;
  238 
  239   switch (action) {
  240   case ServerConfig::DA_LOCK_WORKSTATION:
  241     keys.format(_T("%s"), AdditionalActionApplication::LOCK_WORKSTATION_KEY);
  242     break;
  243   case ServerConfig::DA_LOGOUT_WORKSTATION:
  244     keys.format(_T("%s"), AdditionalActionApplication::LOGOUT_KEY);
  245     break;
  246   default:
  247     return;
  248   }
  249 
  250   Process *process;
  251 
  252   if (isRunningAsService()) {
  253     process = new CurrentConsoleProcess(_T("tvnserver.exe"), keys.getString());
  254   } else {
  255     process = new Process(_T("tvnserver.exe"), keys.getString());
  256   }
  257 
  258   Log::message(_T("Execute disconnect action in separate process"));
  259 
  260   try {
  261     process->start();
  262   } catch (SystemException &ex) {
  263     Log::error(_T("Failed to start application: \"%s\""), ex.getMessage());
  264   }
  265 
  266   delete process;
  267 }
  268 
  269 void TvnServer::restartHttpServer()
  270 {
  271 
  272   stopHttpServer();
  273 
  274   if (m_config->isAcceptingHttpConnections()) {
  275     Log::message(_T("Starting HTTP server"));
  276     try {
  277       m_httpServer = new HttpServer(_T("0.0.0.0"), m_config->getHttpPort(), m_runAsService);
  278     } catch (Exception &ex) {
  279       Log::error(_T("Failed to start HTTP server: \"%s\""), ex.getMessage());
  280     }
  281   }
  282 }
  283 
  284 void TvnServer::restartControlServer()
  285 {
  286 
  287   stopControlServer();
  288 
  289   Log::message(_T("Starting control server"));
  290 
  291   try {
  292     StringStorage pipeName;
  293     ControlPipeName::createPipeName(isRunningAsService(), &pipeName);
  294 
  295     SecurityAttributes *pipeSecurity = new SecurityAttributes();
  296     pipeSecurity->setInheritable();
  297     pipeSecurity->shareToAllUsers();
  298 
  299     PipeServer *pipeServer = new PipeServer(pipeName.getString(), pipeSecurity);
  300     m_controlServer = new ControlServer(pipeServer , m_rfbClientManager);
  301   } catch (Exception &ex) {
  302     Log::error(_T("Failed to start control server: \"%s\""), ex.getMessage());
  303   }
  304 }
  305 
  306 void TvnServer::restartMainRfbServer()
  307 {
  308 
  309   stopMainRfbServer();
  310 
  311   if (!m_config->isAcceptingRfbConnections()) {
  312     return;
  313   }
  314 
  315   const TCHAR *bindHost = m_config->isOnlyLoopbackConnectionsAllowed() ? _T("localhost") : _T("0.0.0.0");
  316   unsigned short bindPort = m_config->getRfbPort();
  317 
  318   Log::message(_T("Starting main RFB server"));
  319 
  320   try {
  321     m_rfbServer = new RfbServer(bindHost, bindPort, m_rfbClientManager, m_runAsService);
  322   } catch (Exception &ex) {
  323     Log::error(_T("Failed to start main RFB server: \"%s\""), ex.getMessage());
  324   }
  325 }
  326 
  327 void TvnServer::stopHttpServer()
  328 {
  329   Log::message(_T("Stopping HTTP server"));
  330 
  331   HttpServer *httpServer = 0;
  332   {
  333     AutoLock l(&m_mutex);
  334     httpServer = m_httpServer;
  335     m_httpServer = 0;
  336   }
  337   if (httpServer != 0) {
  338     delete httpServer;
  339   }
  340 }
  341 
  342 void TvnServer::stopControlServer()
  343 {
  344   Log::message(_T("Stopping control server"));
  345 
  346   ControlServer *controlServer = 0;
  347   {
  348     AutoLock l(&m_mutex);
  349     controlServer = m_controlServer;
  350     m_controlServer = 0;
  351   }
  352   if (controlServer != 0) {
  353     delete controlServer;
  354   }
  355 }
  356 
  357 void TvnServer::stopMainRfbServer()
  358 {
  359   Log::message(_T("Stopping main RFB server"));
  360 
  361   RfbServer *rfbServer = 0;
  362   {
  363     AutoLock l(&m_mutex);
  364     rfbServer = m_rfbServer;
  365     m_rfbServer = 0;
  366   }
  367   if (rfbServer != 0) {
  368     delete rfbServer;
  369   }
  370 }
  371 
  372 void TvnServer::resetLogFilePath()
  373 {
  374   StringStorage pathToLogDirectory;
  375 
  376   TvnLogFilename::queryLogFileDirectory(m_runAsService,
  377     m_config->isSaveLogToAllUsersPathFlagEnabled(),
  378     &pathToLogDirectory);
  379 
  380   {
  381     File logDirectory(pathToLogDirectory.getString());
  382 
  383     logDirectory.mkdir();
  384   }
  385 
  386   StringStorage pathToLogFile;
  387 
  388   TvnLogFilename::queryLogFilePath(m_runAsService,
  389     m_config->isSaveLogToAllUsersPathFlagEnabled(),
  390     &pathToLogFile);
  391 
  392   m_config->setLogFilePath(pathToLogFile.getString());
  393 
  394   m_log.changeFilename(pathToLogFile.getString());
  395 }