lib/client/client.cpp

00001 
00002 /* Copyright (c) 2005-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include "client.h"
00019 
00020 #include "commandQueue.h"
00021 #include "commands.h"
00022 #include "global.h"
00023 #include "init.h"
00024 #include "nodeFactory.h"
00025 #include "packets.h"
00026 #include "server.h"
00027 
00028 #include <eq/net/command.h>
00029 #include <eq/net/connection.h>
00030 #include <eq/base/dso.h>
00031 
00032 namespace eq
00033 {
00035 typedef net::CommandFunc<Client> ClientFunc;
00036 
00037 static net::ConnectionPtr _startLocalServer();
00038 static void _joinLocalServer();
00039 
00040 typedef net::ConnectionPtr (*eqsStartLocalServer_t)( const std::string& file );
00041 typedef void (*eqsJoinLocalServer_t)();
00044 Client::Client()
00045         : _nodeThreadQueue( 0 )
00046         , _running( false )
00047 {
00048     EQINFO << "New client at " << (void*)this << std::endl;
00049 }
00050 
00051 Client::~Client()
00052 {
00053     EQINFO << "Delete client at " << (void*)this << std::endl;
00054     close();
00055 }
00056 
00057 bool Client::listen()
00058 {
00059     EQASSERT( !_nodeThreadQueue );
00060     _nodeThreadQueue = new CommandQueue;
00061 
00062     registerCommand( CMD_CLIENT_EXIT, ClientFunc( this, &Client::_cmdExit ),
00063                      _nodeThreadQueue );
00064 
00065     return net::Node::listen();
00066 }
00067 
00068 bool Client::close()
00069 {
00070     if( !net::Node::close( ))
00071         return false;
00072 
00073     delete _nodeThreadQueue;
00074     _nodeThreadQueue = 0;
00075     return true;
00076 }
00077 
00078 bool Client::connectServer( ServerPtr server )
00079 {
00080     if( server->isConnected( ))
00081         return true;
00082     bool explicitAddress = true;
00083 
00084     if( server->getConnectionDescriptions().empty( ))
00085     {
00086         net::ConnectionDescriptionPtr connDesc = 
00087             new net::ConnectionDescription;
00088         connDesc->port = EQ_DEFAULT_PORT;
00089     
00090         const std::string globalServer = Global::getServer();
00091         const char* envServer = getenv( "EQ_SERVER" );
00092         std::string address = !globalServer.empty() ? globalServer :
00093                                envServer            ? envServer : "localhost";
00094 
00095         if( !connDesc->fromString( address ))
00096             EQWARN << "Can't parse server address " << address << std::endl;
00097         EQASSERT( address.empty( ));
00098         EQINFO << "Connecting to " << connDesc->toString() << std::endl;
00099 
00100         server->addConnectionDescription( connDesc );
00101 
00102         if( globalServer.empty() && !envServer )
00103             explicitAddress = false;
00104     }
00105 
00106     if( connect( net::NodePtr( server.get( )) ))
00107     {
00108         server->setClient( this );
00109         return true;
00110     }
00111 
00112     if( explicitAddress )
00113         return false;
00114 
00115     // Use app-local server if no explicit server was set
00116     net::ConnectionPtr connection = _startLocalServer();
00117     if( !connection )
00118         return false;
00119 
00120     if( !_connect( server.get(), connection ))
00121         // giving up
00122         return false;
00123 
00124     server->setClient( this );
00125     server->_localServer = true;
00126     return true;
00127 }
00128 
00130 namespace
00131 {
00132 base::DSO _libeqserver;
00133 }
00134 
00135 net::ConnectionPtr _startLocalServer()
00136 {
00137     if( !_libeqserver.open(
00138 #ifdef WIN32_VC
00139          "EqualizerServer.dll"
00140 #elif defined (WIN32)
00141         "libeqserver.dll"
00142 #elif defined (Darwin)
00143         "libeqserver.dylib"
00144 #else
00145         "libeqserver.so"
00146 #endif
00147                            ))
00148     {
00149         EQWARN << "Can't open Equalizer server library" << std::endl;
00150         return 0;
00151     }
00152 
00153     eqsStartLocalServer_t eqsStartLocalServer = (eqsStartLocalServer_t)
00154         _libeqserver.getFunctionPointer( "eqsStartLocalServer" );
00155 
00156     if( !eqsStartLocalServer )
00157     {
00158         EQWARN << "Can't find server entry function eqsStartLocalServer"
00159                << std::endl;
00160         return 0;
00161     }
00162 
00163     return eqsStartLocalServer( Global::getConfigFile( ));
00164 }
00165 
00166 static void _joinLocalServer()
00167 {
00168     eqsJoinLocalServer_t eqsJoinLocalServer = (eqsJoinLocalServer_t)
00169         _libeqserver.getFunctionPointer( "eqsJoinLocalServer" );
00170 
00171     if( !eqsJoinLocalServer )
00172     {
00173         EQWARN << "Can't find server entry function eqsJoinLocalServer"
00174                << std::endl;
00175         return;
00176     }
00177 
00178     eqsJoinLocalServer();
00179     _libeqserver.close();
00180 }
00183 bool Client::disconnectServer( ServerPtr server )
00184 {
00185     if( !server->isConnected( ))
00186     {
00187         EQWARN << "Trying to disconnect unconnected server" << std::endl;
00188         return false;
00189     }
00190 
00191     // shut down process-local server (see _startLocalServer)
00192     if( server->_localServer )
00193     {
00194         server->shutdown();
00195         _joinLocalServer();
00196     }
00197 
00198     server->setClient( 0 );
00199     server->_localServer = false;
00200 
00201     const int success = net::Node::close( server.get( ));
00202     if( !success )
00203         EQWARN << "Server disconnect failed" << std::endl;
00204 
00205     // cleanup
00206     _nodeThreadQueue->flush();
00207     return success;
00208 }
00209 
00210 
00211 net::NodePtr Client::createNode( const uint32_t type )
00212 { 
00213     switch( type )
00214     {
00215         case TYPE_EQ_SERVER:
00216         {
00217             Server* server = new Server;
00218             server->setClient( this );
00219             return server;
00220         }
00221 
00222         default:
00223             return net::Node::createNode( type );
00224     }
00225 }
00226 
00227 bool Client::clientLoop()
00228 {
00229     EQINFO << "Entered client loop" << std::endl;
00230 
00231     _running = true;
00232     while( _running )
00233         processCommand();
00234 
00235     // cleanup
00236     _nodeThreadQueue->flush();
00237     EQASSERT( !hasSessions( ));
00238 
00239     return true;
00240 }
00241 
00242 bool Client::exitClient()
00243 {
00244     return (net::Node::exitClient() & eq::exit( ));
00245 }
00246 
00247 bool Client::hasCommands()
00248 {
00249     return !_nodeThreadQueue->isEmpty();
00250 }
00251 
00252 void Client::processCommand()
00253 {
00254     net::Command* command = _nodeThreadQueue->pop();
00255     if( !command ) // just a wakeup()
00256         return;
00257 
00258     switch( invokeCommand( *command ))
00259     {
00260         case net::COMMAND_HANDLED:
00261         case net::COMMAND_DISCARD:
00262             break;
00263             
00264         case net::COMMAND_ERROR:
00265             EQABORT( "Error handling command packet" );
00266             break;
00267     }
00268     command->release();
00269 }
00270 
00271 bool Client::dispatchCommand( net::Command& command )
00272 {
00273     EQVERB << "dispatchCommand " << command << std::endl;
00274 
00275     switch( command->datatype )
00276     {
00277         case DATATYPE_EQ_CLIENT:
00278             return net::Dispatcher::dispatchCommand( command );
00279 
00280         case DATATYPE_EQ_SERVER:
00281         {
00282             net::NodePtr node = command.getNode();
00283 
00284             EQASSERT( dynamic_cast< Server* >( node.get( )) );
00285             ServerPtr server = static_cast< Server* >( node.get( ));
00286 
00287             return server->net::Dispatcher::dispatchCommand( command );
00288         }
00289 
00290         default:
00291             return net::Node::dispatchCommand( command );
00292     }
00293 }
00294 
00295 net::CommandResult Client::invokeCommand( net::Command& command )
00296 {
00297     EQVERB << "invokeCommand " << command << std::endl;
00298 
00299     switch( command->datatype )
00300     {
00301         case DATATYPE_EQ_CLIENT:
00302             return net::Dispatcher::invokeCommand( command );
00303 
00304         case DATATYPE_EQ_SERVER:
00305         {
00306             net::NodePtr node = command.getNode();
00307 
00308             EQASSERT( dynamic_cast<Server*>( node.get( )) );
00309             ServerPtr server = static_cast<Server*>( node.get( ));
00310 
00311             return server->net::Dispatcher::invokeCommand( command );
00312         }
00313         default:
00314             return net::Node::invokeCommand( command );
00315     }
00316 }
00317 
00318 net::CommandResult Client::_cmdExit( net::Command& command )
00319 {
00320     _running = false;
00321     // Close connection here, this is the last packet we'll get on it
00322     command.getLocalNode()->close( command.getNode( ));
00323     return net::COMMAND_HANDLED;
00324 }
00325 }
Generated on Sat Feb 6 12:59:46 2010 for Equalizer 0.9.1 by  doxygen 1.6.1