00001
00002
00003
00004
00005 #include "client.h"
00006
00007 #include "commands.h"
00008 #include "global.h"
00009 #include "init.h"
00010 #include "nodeFactory.h"
00011 #include "packets.h"
00012 #include "server.h"
00013
00014 #include <eq/net/command.h>
00015 #include <eq/net/connection.h>
00016
00017 #ifdef WIN32
00018 # define EQ_DL_ERROR getErrorString( GetLastError( ))
00019 #else
00020 # include <dlfcn.h>
00021 # define EQ_DL_ERROR dlerror()
00022 #endif
00023
00024 using namespace eq::base;
00025 using namespace std;
00026
00027 namespace eq
00028 {
00029 typedef net::CommandFunc<Client> ClientFunc;
00030
00031 static net::ConnectionPtr _startLocalServer();
00032 static void _joinLocalServer();
00033
00034 Client::Client()
00035 : _nodeThreadQueue( 0 )
00036 , _running( false )
00037 {
00038 EQINFO << "New client at " << (void*)this << endl;
00039 }
00040
00041 Client::~Client()
00042 {
00043 EQINFO << "Delete client at " << (void*)this << endl;
00044 stopListening();
00045 }
00046
00047 bool Client::listen()
00048 {
00049 EQASSERT( !_nodeThreadQueue );
00050 _nodeThreadQueue = new CommandQueue;
00051 registerCommand( CMD_CLIENT_EXIT, ClientFunc( this, &Client::_cmdExit ),
00052 _nodeThreadQueue );
00053
00054 return net::Node::listen();
00055 }
00056
00057 void Client::setWindowSystem( const WindowSystem windowSystem )
00058 {
00059
00060 if( _nodeThreadQueue->getWindowSystem() == WINDOW_SYSTEM_NONE )
00061 {
00062 _nodeThreadQueue->setWindowSystem( windowSystem );
00063 EQINFO << "Client message pump set up for " << windowSystem << endl;
00064 }
00065 else if( _nodeThreadQueue->getWindowSystem() != windowSystem )
00066 EQWARN << "Can't switch to window system " << windowSystem
00067 << ", already using " << _nodeThreadQueue->getWindowSystem()
00068 << endl;
00069 }
00070
00071 bool Client::stopListening()
00072 {
00073 if( !net::Node::stopListening( ))
00074 return false;
00075
00076 delete _nodeThreadQueue;
00077 _nodeThreadQueue = 0;
00078 return true;
00079 }
00080
00081 bool Client::connectServer( ServerPtr server )
00082 {
00083 if( server->isConnected( ))
00084 return true;
00085 bool explicitAddress = true;
00086
00087 if( server->getConnectionDescriptions().empty( ))
00088 {
00089 net::ConnectionDescriptionPtr connDesc =
00090 new net::ConnectionDescription;
00091 connDesc->TCPIP.port = EQ_DEFAULT_PORT;
00092
00093 const string globalServer = Global::getServer();
00094 const char* envServer = getenv( "EQ_SERVER" );
00095 string address = !globalServer.empty() ? globalServer :
00096 envServer ? envServer :
00097 "localhost";
00098
00099 if( !connDesc->fromString( address ))
00100 EQWARN << "Can't parse server address " << address << endl;
00101 EQASSERT( address.empty( ));
00102 EQINFO << "Connecting to " << connDesc->toString() << endl;
00103
00104 server->addConnectionDescription( connDesc );
00105
00106 if( globalServer.empty() && !envServer )
00107 explicitAddress = false;
00108 }
00109
00110 if( connect( server.get( )))
00111 {
00112 server->setClient( this );
00113 return true;
00114 }
00115
00116 if( explicitAddress )
00117 return false;
00118
00119
00120 net::ConnectionPtr connection = _startLocalServer();
00121 if( !connection )
00122 return false;
00123
00124 if( connect( server.get(), connection ))
00125 {
00126 server->setClient( this );
00127 server->_localServer = true;
00128 return true;
00129 }
00130
00131
00132 return false;
00133 }
00134
00135 namespace
00136 {
00137 #ifdef WIN32_VC
00138 static HMODULE _libeqserver = 0;
00139 #elif defined (WIN32)
00140 static HMODULE _libeqserver = 0;
00141 #elif defined (Darwin)
00142 static void* _libeqserver = 0;
00143 #else
00144 static void* _libeqserver = 0;
00145 #endif
00146 }
00147
00148 typedef net::ConnectionPtr (*eqsStartLocalServer_t)();
00149
00150 net::ConnectionPtr _startLocalServer()
00151 {
00152 if( !_libeqserver )
00153 {
00154 #ifdef WIN32_VC
00155 _libeqserver = LoadLibrary( "EqualizerServer.dll" );
00156 #elif defined (WIN32)
00157 _libeqserver = LoadLibrary( "libeqserver.dll" );
00158 #elif defined (Darwin)
00159 _libeqserver = dlopen( "libeqserver.dylib", RTLD_LAZY );
00160 #else
00161 _libeqserver = dlopen( "libeqserver.so", RTLD_LAZY );
00162 #endif
00163 }
00164
00165 if( !_libeqserver )
00166 {
00167 EQWARN << "Can't open Equalizer server library: " << EQ_DL_ERROR <<endl;
00168 return 0;
00169 }
00170
00171 #ifdef WIN32
00172 eqsStartLocalServer_t eqsStartLocalServer = (eqsStartLocalServer_t)
00173 GetProcAddress( _libeqserver, "eqsStartLocalServer" );
00174 #else
00175 eqsStartLocalServer_t eqsStartLocalServer = (eqsStartLocalServer_t)
00176 dlsym( _libeqserver, "eqsStartLocalServer" );
00177 #endif
00178
00179 if( !eqsStartLocalServer )
00180 {
00181 EQWARN << "Can't find server entry function eqsStartLocalServer: "
00182 << EQ_DL_ERROR << endl;
00183 return 0;
00184 }
00185
00186 return eqsStartLocalServer();
00187 }
00188
00189 typedef void (*eqsJoinLocalServer_t)();
00190
00191 static void _joinLocalServer()
00192 {
00193 if( !_libeqserver )
00194 {
00195 EQWARN << "Equalizer server library not opened" << endl;
00196 return;
00197 }
00198
00199 #ifdef WIN32
00200 eqsJoinLocalServer_t eqsJoinLocalServer = (eqsJoinLocalServer_t)
00201 GetProcAddress( _libeqserver, "eqsJoinLocalServer" );
00202 #else
00203 eqsJoinLocalServer_t eqsJoinLocalServer = (eqsJoinLocalServer_t)
00204 dlsym( _libeqserver, "eqsJoinLocalServer" );
00205 #endif
00206
00207 if( !eqsJoinLocalServer )
00208 {
00209 EQWARN << "Can't find server entry function eqsJoinLocalServer: "
00210 << EQ_DL_ERROR << endl;
00211 return;
00212 }
00213
00214 eqsJoinLocalServer();
00215 }
00216
00217 bool Client::disconnectServer( ServerPtr server )
00218 {
00219 if( !server->isConnected( ))
00220 {
00221 EQWARN << "Trying to disconnect unconnected server" << endl;
00222 return false;
00223 }
00224
00225
00226 if( server->_localServer )
00227 {
00228 server->shutdown();
00229 _joinLocalServer();
00230 }
00231
00232 server->setClient( 0 );
00233 server->_localServer = false;
00234
00235 const int success = disconnect( server.get( ));
00236 if( !success )
00237 EQWARN << "Server disconnect failed" << endl;
00238
00239
00240 _nodeThreadQueue->flush();
00241 return success;
00242 }
00243
00244
00245 net::NodePtr Client::createNode( const uint32_t type )
00246 {
00247 switch( type )
00248 {
00249 case TYPE_EQ_SERVER:
00250 {
00251 Server* server = new Server;
00252 server->setClient( this );
00253 return server;
00254 }
00255
00256 default:
00257 return net::Node::createNode( type );
00258 }
00259 }
00260
00261 bool Client::clientLoop()
00262 {
00263 EQINFO << "Entered client loop" << endl;
00264
00265 _running = true;
00266 while( _running )
00267 processCommand();
00268
00269
00270 _nodeThreadQueue->flush();
00271 EQASSERT( !hasSessions( ));
00272
00273 return true;
00274 }
00275
00276 bool Client::exitClient()
00277 {
00278 return (net::Node::exitClient() & eq::exit( ));
00279 }
00280
00281 void Client::processCommand()
00282 {
00283 net::Command* command = _nodeThreadQueue->pop();
00284 if( !command )
00285 return;
00286
00287 switch( invokeCommand( *command ))
00288 {
00289 case net::COMMAND_HANDLED:
00290 case net::COMMAND_DISCARD:
00291 break;
00292
00293 case net::COMMAND_ERROR:
00294 EQERROR << "Error handling command packet" << endl;
00295 abort();
00296 }
00297 _nodeThreadQueue->release( command );
00298 }
00299
00300 bool Client::dispatchCommand( net::Command& command )
00301 {
00302 EQVERB << "dispatchCommand " << command << endl;
00303
00304 switch( command->datatype )
00305 {
00306 case DATATYPE_EQ_CLIENT:
00307 return net::Base::dispatchCommand( command );
00308
00309 case DATATYPE_EQ_SERVER:
00310 {
00311 net::NodePtr node = command.getNode();
00312
00313 EQASSERT( dynamic_cast< Server* >( node.get( )) );
00314 ServerPtr server = static_cast< Server* >( node.get( ));
00315
00316 return server->net::Base::dispatchCommand( command );
00317 }
00318
00319 default:
00320 return net::Node::dispatchCommand( command );
00321 }
00322 }
00323
00324 net::CommandResult Client::invokeCommand( net::Command& command )
00325 {
00326 EQVERB << "invokeCommand " << command << endl;
00327
00328 switch( command->datatype )
00329 {
00330 case DATATYPE_EQ_CLIENT:
00331 return net::Base::invokeCommand( command );
00332
00333 case DATATYPE_EQ_SERVER:
00334 {
00335 net::NodePtr node = command.getNode();
00336
00337 EQASSERT( dynamic_cast<Server*>( node.get( )) );
00338 ServerPtr server = static_cast<Server*>( node.get( ));
00339
00340 return server->net::Base::invokeCommand( command );
00341 }
00342 default:
00343 return net::Node::invokeCommand( command );
00344 }
00345 }
00346
00347 net::CommandResult Client::_cmdExit( net::Command& command )
00348 {
00349 _running = false;
00350
00351 command.getLocalNode()->disconnect( command.getNode( ));
00352 return net::COMMAND_HANDLED;
00353 }
00354 }