MercuryNetServer.cpp

Go to the documentation of this file.
00001 #include "MercuryNetServer.h"
00002 #include "MercuryLog.h"
00003 #include "MercuryObject.h"
00004 #include "MercuryODE.h"
00005 
00006 MercuryNetServerConnection::~MercuryNetServerConnection()
00007 {
00008     delete m_pConnection;
00009     m_thdMain.Halt();
00010     m_thdMain.Close();
00011 }
00012 
00013 MercuryNetServerConnection::MercuryNetServerConnection( ezSockets * pAccepted )
00014 {
00015     m_pNetClass = NULL;
00016     m_bIsActive = false;
00017     m_pConnection = pAccepted;
00018 
00019     //Do any IP-based black listing here.
00020     if( pAccepted->GetAddress() == "88.55.123.44" )
00021         return;
00022 
00023     m_bIsActive = true;
00024     m_thdMain.Create( CoreThreadCaller, this );
00025 }
00026 
00027 void MercuryNetServerConnection::SendCommand( const MString & sCommandName, const PStack & kParameters )
00028 {
00029     ezSocketsPacket p;
00030     p.ClearPacket();
00031     p.Write1( 3 );
00032     p.WriteNT( sCommandName );
00033     NetEncodePStack( p, kParameters );
00034     m_pConnection->SendPack( p );
00035 }
00036 
00037 void MercuryNetServerConnection::BroadcastToClient( const MString & sMessage, const PStack & pParameters )
00038 {
00039     ezSocketsPacket pack;
00040     pack.ClearPacket();
00041     pack.Write4( 2 );
00042     pack.WriteNT( sMessage );
00043     NetEncodePStack( pack, pParameters );
00044     m_pConnection->SendPack( pack );
00045 }
00046 
00047 void * MercuryNetServerConnection::CoreThreadCaller( void * NetClient)
00048 {
00049     ((MercuryNetServerConnection *)NetClient)->CoreThread();
00050     return 0;
00051 }
00052 
00053 void MercuryNetServerConnection::CoreThread( void)
00054 {
00055     ezSocketsPacket tmp;
00056     m_pConnection->bBlocking = true;
00057     m_pConnection->mode = ezSockets::skPackets;
00058     while( !m_pConnection->IsError() )
00059     {
00060         if( !m_pConnection->ReadPack( tmp ) )
00061             break;
00062         unsigned char cCode = tmp.Read4();
00063         switch( cCode )
00064         {
00065         case 0:
00066             break;
00067         case 1:
00068             break;
00069         case 2: //Message
00070             break;
00071         case 3: //Command
00072             {
00073             MString sName = tmp.ReadNT();
00074             PStack t;
00075             NetDecodePStack( tmp, t );
00076             if( m_pNetClass )
00077             {
00078                 PStack ret;
00079                 m_pNetClass->Command( ret, sName.c_str(), t );
00080             }
00081             }
00082             break;
00083         case 4:
00084             {
00085             double dCurTime = m_pParent->m_tmrSync.Age();
00086             double dClientTime;
00087             long delTimeID;
00088             delTimeID = tmp.Read4();
00089 
00090             tmp.ReadData( 8, (char*)&dClientTime );
00091 
00092             //Reply packet back to client + our current time.
00093             ezSocketsPacket p;
00094             p.ClearPacket();
00095             p.Write4( 4 );
00096             p.Write4( delTimeID );  //Must be post-increment
00097             p.WriteData( (char*)&dClientTime, 8 );
00098             p.WriteData( (char*)&dCurTime, 8 );
00099 
00100             m_pConnection->SendPack( p );
00101             break;
00102             }
00103         }
00104     }
00105     m_pConnection->Close();
00106     m_bIsActive = false;
00107 }
00108 
00109 
00110 //SERVER SOCKET
00111 
00112 MercuryNetServer::MercuryNetServer()
00113 {
00114     m_pListener = new ezSockets;
00115     m_fTimeSinceLastODE = 0;
00116 }
00117 
00118 MercuryNetServer::~MercuryNetServer()
00119 {
00120     m_thdMain.Halt( true );
00121     m_thdMain.Close();
00122     m_thdUDPMain.Halt( true );
00123     m_thdUDPMain.Close();
00124     for( MDequeIterator< MercuryNetServerConnection * > i = m_vClients.begin(); i != m_vClients.end(); ++i )
00125     {
00126         i.Data()->m_thdMain.Close();
00127         SAFE_DELETE( i.Data()->m_pConnection );
00128         SAFE_DELETE( i.Data() );
00129     }
00130     SAFE_DELETE( m_pListener );
00131     SAFE_DELETE( m_pUDPListener );
00132 }
00133 
00134 void MercuryNetServer::BroadcastToAllClients( const MString & sMessage, const PStack & pParameters )
00135 {
00136     for( MDequeIterator< MercuryNetServerConnection * > i = m_vClients.begin(); i != m_vClients.end(); ++i )
00137         i.Data()->BroadcastToClient( sMessage, pParameters );
00138 }
00139 
00140 bool MercuryNetServer::BindAndListen( int iPort, GenClientFunction cbFunction )
00141 {
00142     m_tmrSync.Touch();
00143     m_cbGenFunction = cbFunction;
00144     if( !m_pListener->Create() )
00145         return false;
00146     m_pListener->bBlocking = true;
00147     if( !m_pListener->Bind( iPort ) )
00148         return false;
00149     if( !m_pListener->Listen() )
00150         return false;
00151 
00152     m_pUDPListener = new ezSockets;
00153     m_pUDPListener->mode = ezSockets::skUDP;
00154     m_pUDPListener->bBlocking = true;
00155     m_pUDPListener->Create( IPPROTO_UDP, SOCK_DGRAM );
00156     if( !m_pUDPListener->Bind( iPort ) )
00157         return false;
00158 
00159     m_thdUDPMain.Close();
00160     m_thdUDPMain.Create( CoreUDPThreadCaller, this );
00161 
00162     m_thdMain.Close();
00163     m_thdMain.Create( CoreThreadCaller, this );
00164     return true;
00165 }
00166 
00167 void MercuryNetServer::Update( const float dTime )
00168 {
00169     m_fTimeSinceLastODE += dTime;
00170 
00171     if( m_fTimeSinceLastODE > .5f )
00172     {
00173         UpdateODE();
00174         m_fTimeSinceLastODE=0;
00175     }
00176 }
00177 
00178 void MercuryNetServer::UpdateODE( const MString & sNameOfObject )
00179 {
00180     if( m_pWorld == NULL )
00181         return;
00182 
00183     unsigned i;
00184     double dCurTime = m_tmrSync.Age();
00185     ezSocketsPacket p;
00186     p.ClearPacket();
00187     
00188     //ODE Update command packet.
00189     p.Write4( 5 );
00190 
00191     //Server time
00192     p.WriteData( (char*)&dCurTime, 8 );
00193 
00194 
00195     MHash<MercuryODEObject *> & pAllObjects = m_pWorld->GetAllObjectMap();
00196 
00197     if( sNameOfObject != "" )
00198     {
00199         p.Write4( 1 );
00200         MercuryODEObject * g = pAllObjects[sNameOfObject];
00201         ODEUnitInfo inf;
00202         if( g->m_oBody )
00203         {
00204             p.WriteNT( sNameOfObject );
00205             inf.pos = dBodyGetPosition( g->m_oBody );
00206             const float * f = dBodyGetQuaternion( g->m_oBody );
00207             inf.rot.w = f[0]; inf.rot.x = f[1]; inf.rot.y = f[2]; inf.rot.z = f[3];
00208             inf.linvel = dBodyGetLinearVel( g->m_oBody );
00209             inf.angvel = dBodyGetAngularVel( g->m_oBody );
00210             p.WriteData( (const char*) &inf, sizeof( ODEUnitInfo ) );
00211         }
00212     }
00213     else
00214     {
00215         MVector< MString > pAllIndicies;
00216         pAllObjects.VectorIndicies( pAllIndicies );
00217 
00218         //# of ODE Objects in this update
00219         p.Write4( pAllIndicies.size() );
00220 
00221         for( i = 0; i < pAllIndicies.size(); i++ )
00222         {
00223             MercuryODEObject * g = pAllObjects[pAllIndicies[i]];
00224             ODEUnitInfo inf;
00225             if( g->m_oBody )
00226             {
00227                 p.WriteNT( pAllIndicies[i] );
00228 
00229                 inf.pos = dBodyGetPosition( g->m_oBody );
00230                 const float * f = dBodyGetQuaternion( g->m_oBody );
00231                 inf.rot.w = f[0]; inf.rot.x = f[1]; inf.rot.y = f[2]; inf.rot.z = f[3];
00232                 inf.linvel = dBodyGetLinearVel( g->m_oBody );
00233                 inf.angvel = dBodyGetAngularVel( g->m_oBody );
00234                 p.WriteData( (const char*) &inf, sizeof( ODEUnitInfo ) );
00235             }
00236         }
00237     }
00238 
00239     for( MDequeIterator< MercuryNetServerConnection * > j = m_vClients.begin(); j != m_vClients.end(); ++j )
00240         (*j)->m_pConnection->SendPack( p );
00241 }
00242 
00243 void * MercuryNetServer::CoreThreadCaller( void * NetClient)
00244 {
00245     ((MercuryNetServer *)NetClient)->CoreThread();
00246     return 0;
00247 }
00248 
00249 void MercuryNetServer::CoreThread()
00250 {
00251     while( !m_pListener->IsError() )
00252     {
00253         ezSockets * s = m_pListener->Accept();
00254         if( s )
00255         {
00256             m_vClients.push_back( m_cbGenFunction( s ) );
00257             m_vClients.back()->AttachParent( this );
00258         }
00259     }
00260 }
00261 
00262 void * MercuryNetServer::CoreUDPThreadCaller( void * NetClient )
00263 {
00264     ((MercuryNetServer *)NetClient)->CoreUDPThread();
00265     return NULL;
00266 }
00267 
00268 void MercuryNetServer::CoreUDPThread()
00269 {
00270     ezSocketsPacket g;
00271     while( !m_pUDPListener->IsError() )
00272     {
00273         g.ClearPacket();
00274         m_pUDPListener->ReadPack( g );
00275 
00276         Sleep( 1000.0f );
00277         ezSocketsPacket j;
00278         j.ClearPacket();
00279         j.Write4( 5 );
00280         j.Port = g.Port;
00281         j.PositionTAG = g.PositionTAG;
00282         j.Write4( 5 );
00283         m_pUDPListener->SendPack( j );
00284     }
00285 }
00286 
00287 MercuryNetServerConnection * DefaultSocketConnection(ezSockets * pAccepted)
00288 {
00289     return new MercuryNetServerConnection( pAccepted );
00290 }
00291 
00292 
00293 //Utility functions
00294 void NetEncodePStack( ezSocketsPacket & pPacket, const PStack & pParameters )
00295 {
00296     pPacket.Write1( pParameters.GetSize() );
00297     for( unsigned i = 0; i < pParameters.GetSize(); i++ )
00298     {
00299         pPacket.Write1( pParameters.PeekItem( i ).GetType() );
00300         switch( pParameters.PeekItem( i ).GetType() )
00301         {
00302         case PSElement::BOOL:
00303             pPacket.Write1( pParameters.PeekItem( i ).GetValueB() );
00304             break;
00305         case PSElement::INTEGER:
00306             pPacket.Write4( pParameters.PeekItem( i ).GetValueI() );
00307             break;
00308         case PSElement::FLOAT:
00309             {
00310             float f = pParameters.PeekItem( i ).GetValueF();
00311             pPacket.Write4( *((unsigned long*)((float*)&f)) );
00312             break;
00313             }
00314         case PSElement::STRING:
00315             pPacket.WriteNT( pParameters.PeekItem( i ).GetValueS() );
00316             break;
00317         default:
00318             break;
00319         }
00320     }
00321 }
00322 
00323 void NetDecodePStack( ezSocketsPacket & pPacket, PStack & pParameters )
00324 {
00325     unsigned long iParameters = pPacket.Read1();
00326     for( unsigned i = 0; i < iParameters; i++ )
00327     {
00328         switch( pPacket.Read1() )
00329         {
00330         case PSElement::BOOL:
00331             pParameters.PushItemBack( PSElement( (bool)(pPacket.Read1() != 0) ) );
00332             break;
00333         case PSElement::INTEGER:
00334             pParameters.PushItemBack( PSElement( (int)pPacket.Read4() ) );
00335             break;
00336         case PSElement::FLOAT:
00337             {
00338             unsigned long l = pPacket.Read4();
00339             pParameters.PushItemBack( PSElement( *((float*)((unsigned long*)&l))));
00340             break;
00341             }
00342         case PSElement::STRING:
00343             pParameters.PushItemBack( PSElement( pPacket.ReadNT() ) );
00344             break;
00345         default:
00346             break;
00347         }
00348     }
00349 }

Hosted by SourceForge.net Logo