2013-06-29 18:57:18 -04:00
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2013-07-04 09:19:32 -04:00
# include "network/protocol_manager.hpp"
2013-06-29 18:57:18 -04:00
2013-07-04 09:19:32 -04:00
# include "network/protocol.hpp"
# include "network/network_manager.hpp"
2013-07-04 12:59:30 -04:00
# include "utils/log.hpp"
2013-06-29 18:57:18 -04:00
# include <assert.h>
# include <cstdlib>
2013-07-09 10:07:28 -04:00
# include <errno.h>
2013-07-09 18:05:06 -04:00
# include <typeinfo>
2013-07-09 10:07:28 -04:00
void * protocolManagerUpdate ( void * data )
{
ProtocolManager * manager = static_cast < ProtocolManager * > ( data ) ;
while ( ! manager - > exit ( ) )
{
manager - > update ( ) ;
}
return NULL ;
}
2013-06-29 18:57:18 -04:00
2013-07-10 18:46:23 -04:00
ProtocolManager : : ProtocolManager ( )
2013-06-29 18:57:18 -04:00
{
pthread_mutex_init ( & m_events_mutex , NULL ) ;
pthread_mutex_init ( & m_protocols_mutex , NULL ) ;
pthread_mutex_init ( & m_requests_mutex , NULL ) ;
pthread_mutex_init ( & m_id_mutex , NULL ) ;
2013-07-09 10:07:28 -04:00
pthread_mutex_init ( & m_exit_mutex , NULL ) ;
2013-06-29 18:57:18 -04:00
m_next_protocol_id = 0 ;
2013-07-10 18:46:23 -04:00
2013-07-09 10:07:28 -04:00
pthread_mutex_lock ( & m_exit_mutex ) ; // will let the update function run
m_update_thread = ( pthread_t * ) ( malloc ( sizeof ( pthread_t ) ) ) ;
pthread_create ( m_update_thread , NULL , protocolManagerUpdate , this ) ;
2013-06-29 18:57:18 -04:00
}
ProtocolManager : : ~ ProtocolManager ( )
{
2013-07-09 10:07:28 -04:00
pthread_mutex_unlock ( & m_exit_mutex ) ; // will stop the update function
2013-07-04 12:59:30 -04:00
pthread_mutex_lock ( & m_events_mutex ) ;
pthread_mutex_lock ( & m_protocols_mutex ) ;
pthread_mutex_lock ( & m_requests_mutex ) ;
pthread_mutex_lock ( & m_id_mutex ) ;
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
delete m_protocols [ i ] . protocol ;
for ( unsigned int i = 0 ; i < m_events_to_process . size ( ) ; i + + )
delete m_events_to_process [ i ] ;
m_protocols . clear ( ) ;
m_requests . clear ( ) ;
m_events_to_process . clear ( ) ;
pthread_mutex_unlock ( & m_events_mutex ) ;
pthread_mutex_unlock ( & m_protocols_mutex ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
pthread_mutex_unlock ( & m_id_mutex ) ;
2013-07-10 18:46:23 -04:00
2013-07-04 12:59:30 -04:00
pthread_mutex_destroy ( & m_events_mutex ) ;
pthread_mutex_destroy ( & m_protocols_mutex ) ;
pthread_mutex_destroy ( & m_requests_mutex ) ;
pthread_mutex_destroy ( & m_id_mutex ) ;
2013-07-09 10:07:28 -04:00
pthread_mutex_destroy ( & m_exit_mutex ) ;
2013-06-29 18:57:18 -04:00
}
void ProtocolManager : : notifyEvent ( Event * event )
{
2013-07-10 20:38:33 -04:00
Event * event2 = event ;
2013-07-10 20:03:47 -04:00
if ( event - > type = = EVENT_TYPE_DISCONNECTED )
{
// make a copy if needed (the peer will be lost elseway)
2013-07-10 20:38:33 -04:00
event2 = new Event ( * event ) ;
2013-07-10 20:03:47 -04:00
Log : : warn ( " ProtocolManager " , " Trying to copy the event " ) ;
}
2013-06-29 18:57:18 -04:00
pthread_mutex_lock ( & m_events_mutex ) ;
2013-07-10 20:38:33 -04:00
m_events_to_process . push_back ( event2 ) ; // add the event to the queue
2013-06-29 18:57:18 -04:00
pthread_mutex_unlock ( & m_events_mutex ) ;
}
2013-07-05 12:16:02 -04:00
void ProtocolManager : : sendMessage ( Protocol * sender , const NetworkString & message )
2013-06-29 18:57:18 -04:00
{
2013-07-05 12:16:02 -04:00
NetworkString newMessage ;
newMessage . ai8 ( sender - > getProtocolType ( ) ) ; // add one byte to add protocol type
2013-07-10 18:46:23 -04:00
newMessage + = message ;
2013-07-05 12:16:02 -04:00
NetworkManager : : getInstance ( ) - > sendPacket ( newMessage ) ;
}
void ProtocolManager : : sendMessage ( Protocol * sender , STKPeer * peer , const NetworkString & message )
{
NetworkString newMessage ;
newMessage . ai8 ( sender - > getProtocolType ( ) ) ; // add one byte to add protocol type
2013-07-10 18:46:23 -04:00
newMessage + = message ;
2013-07-05 12:16:02 -04:00
NetworkManager : : getInstance ( ) - > sendPacket ( peer , newMessage ) ;
}
void ProtocolManager : : sendMessageExcept ( Protocol * sender , STKPeer * peer , const NetworkString & message )
{
NetworkString newMessage ;
newMessage . ai8 ( sender - > getProtocolType ( ) ) ; // add one byte to add protocol type
2013-07-10 18:46:23 -04:00
newMessage + = message ;
2013-07-05 12:16:02 -04:00
NetworkManager : : getInstance ( ) - > sendPacketExcept ( peer , newMessage ) ;
2013-06-29 18:57:18 -04:00
}
2013-07-07 15:49:51 -04:00
uint32_t ProtocolManager : : requestStart ( Protocol * protocol )
2013-06-29 18:57:18 -04:00
{
// create the request
ProtocolRequest req ;
ProtocolInfo info ;
info . protocol = protocol ;
info . state = PROTOCOL_STATE_RUNNING ;
assignProtocolId ( & info ) ; // assign a unique id to the protocol.
req . protocol_info = info ;
req . type = PROTOCOL_REQUEST_START ;
// add it to the request stack
pthread_mutex_lock ( & m_requests_mutex ) ;
m_requests . push_back ( req ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
2013-07-10 18:46:23 -04:00
2013-06-29 18:57:18 -04:00
return info . id ;
}
void ProtocolManager : : requestStop ( Protocol * protocol )
{
// create the request
ProtocolRequest req ;
req . protocol_info . protocol = protocol ;
req . type = PROTOCOL_REQUEST_STOP ;
// add it to the request stack
pthread_mutex_lock ( & m_requests_mutex ) ;
m_requests . push_back ( req ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
}
void ProtocolManager : : requestPause ( Protocol * protocol )
{
// create the request
ProtocolRequest req ;
req . protocol_info . protocol = protocol ;
req . type = PROTOCOL_REQUEST_PAUSE ;
// add it to the request stack
pthread_mutex_lock ( & m_requests_mutex ) ;
m_requests . push_back ( req ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
}
void ProtocolManager : : requestUnpause ( Protocol * protocol )
{
// create the request
ProtocolRequest req ;
req . protocol_info . protocol = protocol ;
req . type = PROTOCOL_REQUEST_UNPAUSE ;
// add it to the request stack
pthread_mutex_lock ( & m_requests_mutex ) ;
m_requests . push_back ( req ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
}
void ProtocolManager : : requestTerminate ( Protocol * protocol )
{
// create the request
ProtocolRequest req ;
req . protocol_info . protocol = protocol ;
req . type = PROTOCOL_REQUEST_TERMINATE ;
// add it to the request stack
pthread_mutex_lock ( & m_requests_mutex ) ;
m_requests . push_back ( req ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
}
void ProtocolManager : : startProtocol ( ProtocolInfo protocol )
{
2013-07-09 18:05:06 -04:00
Log : : info ( " ProtocolManager " , " A %s protocol with id=%u has been started. There are %ld protocols running. " , typeid ( * protocol . protocol ) . name ( ) , protocol . id , m_protocols . size ( ) + 1 ) ;
2013-06-29 18:57:18 -04:00
// add the protocol to the protocol vector so that it's updated
pthread_mutex_lock ( & m_protocols_mutex ) ;
m_protocols . push_back ( protocol ) ;
pthread_mutex_unlock ( & m_protocols_mutex ) ;
// setup the protocol and notify it that it's started
protocol . protocol - > setListener ( this ) ;
protocol . protocol - > setup ( ) ;
}
void ProtocolManager : : stopProtocol ( ProtocolInfo protocol )
{
2013-07-10 18:46:23 -04:00
2013-06-29 18:57:18 -04:00
}
void ProtocolManager : : pauseProtocol ( ProtocolInfo protocol )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . protocol = = protocol . protocol & & m_protocols [ i ] . state = = PROTOCOL_STATE_RUNNING )
{
m_protocols [ i ] . state = PROTOCOL_STATE_PAUSED ;
m_protocols [ i ] . protocol - > pause ( ) ;
}
}
}
void ProtocolManager : : unpauseProtocol ( ProtocolInfo protocol )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . protocol = = protocol . protocol & & m_protocols [ i ] . state = = PROTOCOL_STATE_PAUSED )
{
m_protocols [ i ] . state = PROTOCOL_STATE_RUNNING ;
m_protocols [ i ] . protocol - > unpause ( ) ;
}
}
}
void ProtocolManager : : protocolTerminated ( ProtocolInfo protocol )
{
pthread_mutex_lock ( & m_protocols_mutex ) ; // be sure that noone accesses the protocols vector while we erase a protocol
int offset = 0 ;
2013-07-09 18:05:06 -04:00
std : : string protocol_type = typeid ( * protocol . protocol ) . name ( ) ;
2013-06-29 18:57:18 -04:00
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i - offset ] . protocol = = protocol . protocol )
{
delete m_protocols [ i ] . protocol ;
m_protocols . erase ( m_protocols . begin ( ) + ( i - offset ) , m_protocols . begin ( ) + ( i - offset ) + 1 ) ;
offset + + ;
}
}
2013-07-09 18:05:06 -04:00
Log : : info ( " ProtocolManager " , " A %s protocol has been terminated. There are %ld protocols running. " , protocol_type . c_str ( ) , m_protocols . size ( ) ) ;
2013-06-29 18:57:18 -04:00
pthread_mutex_unlock ( & m_protocols_mutex ) ;
}
void ProtocolManager : : update ( )
{
// before updating, notice protocols that they have received information
int size = m_events_to_process . size ( ) ;
for ( int i = 0 ; i < size ; i + + )
{
2013-07-09 19:46:09 -04:00
pthread_mutex_lock ( & m_events_mutex ) ; // secure threads
2013-06-29 18:57:18 -04:00
Event * event = m_events_to_process . back ( ) ;
2013-07-09 19:46:09 -04:00
m_events_to_process . pop_back ( ) ;
pthread_mutex_unlock ( & m_events_mutex ) ; // release the mutex
2013-07-10 18:46:23 -04:00
2013-06-29 18:57:18 -04:00
PROTOCOL_TYPE searchedProtocol = PROTOCOL_NONE ;
2013-07-04 16:36:50 -04:00
if ( event - > type = = EVENT_TYPE_MESSAGE )
{
if ( event - > data . size ( ) > 0 )
2013-07-10 09:44:30 -04:00
searchedProtocol = ( PROTOCOL_TYPE ) ( event - > data . getAndRemoveUInt8 ( ) ) ;
2013-07-04 16:36:50 -04:00
}
2013-07-07 18:23:13 -04:00
if ( event - > type = = EVENT_TYPE_CONNECTED )
{
searchedProtocol = PROTOCOL_CONNECTION ;
}
2013-06-29 18:57:18 -04:00
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
2013-07-07 18:23:13 -04:00
if ( m_protocols [ i ] . protocol - > getProtocolType ( ) = = searchedProtocol | | event - > type = = EVENT_TYPE_DISCONNECTED ) // pass data to protocols even when paused
2013-06-29 18:57:18 -04:00
m_protocols [ i ] . protocol - > notifyEvent ( event ) ;
}
2013-07-10 09:44:30 -04:00
if ( searchedProtocol = = PROTOCOL_NONE ) // no protocol was aimed, show the msg to debug
{
Log : : debug ( " ProtocolManager " , " Message is \" %s \" " , event - > data . c_str ( ) ) ;
}
2013-07-10 20:25:39 -04:00
2013-07-10 20:38:33 -04:00
if ( event - > type = = EVENT_TYPE_DISCONNECTED )
2013-07-10 20:25:39 -04:00
{ // because we made a copy of the event and the peer
2013-07-10 20:38:33 -04:00
delete event - > peer ;
2013-07-10 20:25:39 -04:00
delete event ;
}
2013-06-29 18:57:18 -04:00
}
2013-07-10 18:46:23 -04:00
2013-06-29 18:57:18 -04:00
// now update all protocols
pthread_mutex_lock ( & m_protocols_mutex ) ;
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . state = = PROTOCOL_STATE_RUNNING )
m_protocols [ i ] . protocol - > update ( ) ;
}
2013-07-10 18:46:23 -04:00
pthread_mutex_unlock ( & m_protocols_mutex ) ;
2013-06-29 18:57:18 -04:00
// process queued events for protocols
pthread_mutex_lock ( & m_requests_mutex ) ;
for ( unsigned int i = 0 ; i < m_requests . size ( ) ; i + + )
{
switch ( m_requests [ i ] . type )
{
case PROTOCOL_REQUEST_START :
startProtocol ( m_requests [ i ] . protocol_info ) ;
break ;
case PROTOCOL_REQUEST_STOP :
stopProtocol ( m_requests [ i ] . protocol_info ) ;
break ;
case PROTOCOL_REQUEST_PAUSE :
pauseProtocol ( m_requests [ i ] . protocol_info ) ;
break ;
case PROTOCOL_REQUEST_UNPAUSE :
unpauseProtocol ( m_requests [ i ] . protocol_info ) ;
break ;
case PROTOCOL_REQUEST_TERMINATE :
protocolTerminated ( m_requests [ i ] . protocol_info ) ;
break ;
}
}
m_requests . clear ( ) ;
pthread_mutex_unlock ( & m_requests_mutex ) ;
}
int ProtocolManager : : runningProtocolsCount ( )
{
return m_protocols . size ( ) ;
}
PROTOCOL_STATE ProtocolManager : : getProtocolState ( uint32_t id )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . id = = id ) // we know a protocol with that id
return m_protocols [ i ] . state ; // return its state
}
// the protocol isn't running right now
for ( unsigned int i = 0 ; i < m_requests . size ( ) ; i + + )
{
if ( m_requests [ i ] . protocol_info . id = = id ) // the protocol is going to be started
return PROTOCOL_STATE_RUNNING ; // we can say it's running
}
2013-07-10 18:46:23 -04:00
return PROTOCOL_STATE_TERMINATED ; // else, it's already finished
2013-06-29 18:57:18 -04:00
}
PROTOCOL_STATE ProtocolManager : : getProtocolState ( Protocol * protocol )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . protocol = = protocol ) // the protocol is known
return m_protocols [ i ] . state ; // return its state
}
for ( unsigned int i = 0 ; i < m_requests . size ( ) ; i + + )
{
if ( m_requests [ i ] . protocol_info . protocol = = protocol ) // the protocol is going to be started
return PROTOCOL_STATE_RUNNING ; // we can say it's running
}
return PROTOCOL_STATE_TERMINATED ; // we don't know this protocol at all, it's finished
}
2013-07-07 15:49:51 -04:00
uint32_t ProtocolManager : : getProtocolID ( Protocol * protocol )
2013-06-29 18:57:18 -04:00
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . protocol = = protocol )
return m_protocols [ i ] . id ;
}
return 0 ;
}
2013-07-07 15:49:51 -04:00
Protocol * ProtocolManager : : getProtocol ( uint32_t id )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . id = = id )
return m_protocols [ i ] . protocol ;
}
return NULL ;
}
2013-07-10 18:46:23 -04:00
Protocol * ProtocolManager : : getProtocol ( PROTOCOL_TYPE type )
{
for ( unsigned int i = 0 ; i < m_protocols . size ( ) ; i + + )
{
if ( m_protocols [ i ] . protocol - > getProtocolType ( ) = = type )
return m_protocols [ i ] . protocol ;
}
return NULL ;
}
2013-07-04 18:49:45 -04:00
bool ProtocolManager : : isServer ( )
{
return NetworkManager : : getInstance ( ) - > isServer ( ) ;
}
2013-07-09 10:07:28 -04:00
int ProtocolManager : : exit ( )
{
switch ( pthread_mutex_trylock ( & m_exit_mutex ) ) {
case 0 : /* if we got the lock, unlock and return 1 (true) */
pthread_mutex_unlock ( & m_exit_mutex ) ;
return 1 ;
case EBUSY : /* return 0 (false) if the mutex was locked */
return 0 ;
}
return 1 ;
}
2013-06-29 18:57:18 -04:00
void ProtocolManager : : assignProtocolId ( ProtocolInfo * protocol_info )
{
pthread_mutex_lock ( & m_id_mutex ) ;
protocol_info - > id = m_next_protocol_id ;
m_next_protocol_id + + ;
pthread_mutex_unlock ( & m_id_mutex ) ;
}