improving again the protocol system, fixing some pointer issues that might appear

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/hilnius@13164 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius 2013-07-10 22:46:23 +00:00
parent 212b77fef3
commit 3c3868210f
21 changed files with 443 additions and 263 deletions

Binary file not shown.

View File

@ -23,6 +23,7 @@
#include "network/protocols/show_public_address.hpp"
#include "network/protocols/get_peer_address.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/client_lobby_room_protocol.hpp"
#include "utils/log.hpp"
@ -35,7 +36,7 @@ void* waitInput(void* data)
std::string str = "";
bool stop = false;
int n = 0;
while(!stop)
{
getline(std::cin, str);
@ -55,7 +56,15 @@ void* waitInput(void* data)
{
ProtocolManager::getInstance()->requestStart(new ConnectToServer(n));
}
else
else if (str == "select")
{
std::string str2;
getline(std::cin, str2);
Protocol* protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_LOBBY_ROOM);
ClientLobbyRoomProtocol* clrp = static_cast<ClientLobbyRoomProtocol*>(protocol);
clrp->requestKartSelection(str2);
}
else
{
NetworkString msg;
msg.ai8(0);
@ -65,7 +74,7 @@ void* waitInput(void* data)
}
exit(0);
return NULL;
}
@ -79,9 +88,9 @@ ClientNetworkManager::~ClientNetworkManager()
{
}
void ClientNetworkManager::run()
void ClientNetworkManager::run()
{
if (enet_initialize() != 0)
if (enet_initialize() != 0)
{
Log::error("ClientNetworkManager", "Could not initialize enet.\n");
return;
@ -89,11 +98,11 @@ void ClientNetworkManager::run()
m_localhost = new STKHost();
m_localhost->setupClient(1, 2, 0, 0);
m_localhost->startListening();
// listen keyboard console input
m_thread_keyboard = (pthread_t*)(malloc(sizeof(pthread_t)));
pthread_create(m_thread_keyboard, NULL, waitInput, NULL);
NetworkManager::run();
}

View File

@ -47,11 +47,11 @@ Event::Event(ENetEvent* event)
else if (event->data)
{
}
m_packet = NULL;
if (event->packet)
m_packet = event->packet;
if (m_packet)
enet_packet_destroy(m_packet); // we got all we need, just remove the data.
@ -73,7 +73,16 @@ Event::Event(ENetEvent* event)
Log::verbose("Event", "Creating a new peer, address are STKPeer:%ld, Peer:%ld", (long int)(new_peer), (long int)(event->peer));
}
}
Event::Event(const Event& event)
{
m_packet = NULL;
data = event.data;
// copy the peer
peer = new STKPeer(*event.peer);
type = event.type;
}
Event::~Event()
{
}

View File

@ -37,7 +37,7 @@ enum EVENT_TYPE
/*!
* \class Event
* \brief Class representing an event that need to pass trough the system.
* This is used to remove ENet dependency in the network.
* This is used to remove ENet dependency in the network.
* It interfaces the ENetEvent structure.
* The user has to be extremely careful about the peer.
* Indeed, when packets are logged, the state of the peer cannot be stored at
@ -51,20 +51,24 @@ class Event
* \param event : The event that needs to be translated.
*/
Event(ENetEvent* event);
/*! \brief Constructor
* \param event : The event to copy.
*/
Event(const Event& event);
/*! \brief Destructor
* frees the memory of the ENetPacket.
*/
~Event();
/*! \brief Remove bytes at the beginning of data.
* \param size : The number of bytes to remove.
*/
void removeFront(int size);
EVENT_TYPE type; //!< Type of the event.
NetworkString data; //!< Copy of the data passed by the event.
STKPeer* peer; //!< Pointer to the peer that triggered that event.
private:
ENetPacket* m_packet; //!< A pointer on the ENetPacket to be deleted.
};

View File

@ -34,19 +34,20 @@ GameSetup::~GameSetup()
//-----------------------------------------------------------------------------
void GameSetup::addPlayer(NetworkPlayerProfile profile)
void GameSetup::addPlayer(NetworkPlayerProfile* profile)
{
m_players.push_back(profile);
}
//-----------------------------------------------------------------------------
bool GameSetup::removePlayer(uint32_t id)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i].user_profile->getUserID() == id)
if (m_players[i]->user_profile->getUserID() == id)
{
delete m_players[i];
m_players.erase(m_players.begin()+i, m_players.begin()+i+1);
Log::verbose("GameSetup", "Removed a player from the game setup.");
return true;
@ -56,12 +57,12 @@ bool GameSetup::removePlayer(uint32_t id)
}
//-----------------------------------------------------------------------------
bool GameSetup::removePlayer(uint8_t id)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i].race_id == id) // check the given id
if (m_players[i]->race_id == id) // check the given id
{
m_players.erase(m_players.begin()+i, m_players.begin()+i+1);
Log::verbose("GameSetup", "Removed a player from the game setup.");
@ -72,28 +73,42 @@ bool GameSetup::removePlayer(uint8_t id)
}
//-----------------------------------------------------------------------------
void GameSetup::setPlayerKart(uint8_t id, std::string kart_name)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i]->race_id == id)
{
m_players[i]->kart_name = kart_name;
Log::info("GameSetup", "Player %d took kart %s", id, kart_name.c_str());
}
}
}
//-----------------------------------------------------------------------------
const NetworkPlayerProfile* GameSetup::getProfile(uint32_t id)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i].user_profile->getUserID() == id)
if (m_players[i]->user_profile->getUserID() == id)
{
return &m_players[i];
return m_players[i];
}
}
return NULL;
}
//-----------------------------------------------------------------------------
const NetworkPlayerProfile* GameSetup::getProfile(uint8_t id)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i].race_id == id)
if (m_players[i]->race_id == id)
{
return &m_players[i];
return m_players[i];
}
}
return NULL;
@ -105,7 +120,7 @@ bool GameSetup::isKartAvailable(std::string kart_name)
{
for (unsigned int i = 0; i < m_players.size(); i++)
{
if (m_players[i].kart_name == kart_name)
if (m_players[i]->kart_name == kart_name)
return false;
}
return true;

View File

@ -28,14 +28,14 @@
#include <string>
/*! \class PlayerProfile
* \brief Contains the profile of a player.
* \brief Contains the profile of a player.
*/
class NetworkPlayerProfile
class NetworkPlayerProfile
{
public:
NetworkPlayerProfile() { race_id = 0; user_profile = NULL; }
~NetworkPlayerProfile() {}
uint8_t race_id; //!< The id of the player for the race
std::string kart_name; //!< The selected kart.
OnlineUser* user_profile; //!< Pointer to the lobby profile
@ -50,19 +50,22 @@ class GameSetup
public:
GameSetup();
virtual ~GameSetup();
void addPlayer(NetworkPlayerProfile profile); //!< Add a player.
void addPlayer(NetworkPlayerProfile* profile); //!< Add a player.
bool removePlayer(uint32_t id); //!< Remove a player by id.
bool removePlayer(uint8_t id); //!< Remove a player by local id.
void setPlayerKart(uint8_t id, std::string kart_name); //!< Set the kart of a player
int getPlayerCount() { return m_players.size(); }
const NetworkPlayerProfile* getProfile(uint32_t id); //!< Get a profile by database id
const NetworkPlayerProfile* getProfile(uint8_t id); //!< Get the profile by the lobby id
bool isKartAvailable(std::string kart_name);
bool isKartAllowed(std::string kart_name) {return true; }
protected:
std::vector<NetworkPlayerProfile> m_players; //!< Information about players
std::vector<NetworkPlayerProfile*> m_players; //!< Information about players
NetworkPlayerProfile m_self_profile; //!< Information about self (client only)
};

View File

@ -43,12 +43,12 @@ NetworkManager::NetworkManager()
//-----------------------------------------------------------------------------
NetworkManager::~NetworkManager()
NetworkManager::~NetworkManager()
{
ProtocolManager::kill();
if (m_localhost)
delete m_localhost;
delete m_localhost;
while(!m_peers.empty())
{
delete m_peers.back();
@ -59,7 +59,7 @@ NetworkManager::~NetworkManager()
//-----------------------------------------------------------------------------
void NetworkManager::run()
{
{
// create the protocol manager
ProtocolManager::getInstance<ProtocolManager>();
}
@ -70,7 +70,7 @@ bool NetworkManager::connect(TransportAddress peer)
{
if (peerExists(peer))
return isConnectedTo(peer);
return STKPeer::connectToHost(m_localhost, peer, 2, 0);
}
@ -89,54 +89,55 @@ void NetworkManager::setManualSocketsMode(bool manual)
void NetworkManager::notifyEvent(Event* event)
{
Log::info("NetworkManager", "EVENT received of type %d", (int)(event->type));
switch (event->type)
if (event->type == EVENT_TYPE_CONNECTED)
{
case EVENT_TYPE_CONNECTED:
Log::debug("NetworkManager", "A client has just connected. There are now %lu peers.", m_peers.size() + 1);
Log::verbose("NetworkManager", "Address of event->peer after connection : %ld", (long int)(event->peer));
// create the new peer:
m_peers.push_back(event->peer);
break;
case EVENT_TYPE_DISCONNECTED:
{
Log::debug("NetworkManager", "Disconnected host: %i.%i.%i.%i:%i", event->peer->getAddress()>>24&0xff, event->peer->getAddress()>>16&0xff, event->peer->getAddress()>>8&0xff, event->peer->getAddress()&0xff,event->peer->getPort());
// remove the peer:
bool removed = false;
for (unsigned int i = 0; i < m_peers.size(); i++)
{
Log::error("NetworkManager", "Saved : %ld, Sender : %ld", (long int)(m_peers[i]), (long int)(event->peer));
if (m_peers[i] == event->peer && !removed) // remove only one
{
delete m_peers[i];
m_peers.erase(m_peers.begin()+i, m_peers.begin()+i+1);
Log::verbose("NetworkManager", "The peer has been removed from the Network Manager.");
removed = true;
}
else if (m_peers[i] == event->peer)
{
Log::fatal("NetworkManager", "Multiple peers match the disconnected one.");
}
}
if (!removed)
Log::warn("NetworkManager", "The peer that has been disconnected was not registered by the Network Manager.");
Log::debug("NetworkManager", "Somebody is now disconnected. There are now %lu peers.", m_peers.size());
} break;
case EVENT_TYPE_MESSAGE:
{
//exit(0);
uint32_t addr = event->peer->getAddress();
Log::info("NetworkManager", "Message, Sender : %i.%i.%i.%i, message = \"%s\"",
((addr>>24)&0xff),
((addr>>16)&0xff),
((addr>>8)&0xff),
(addr&0xff), event->data.c_str());
} break;
Log::debug("NetworkManager", "A client has just connected. There are now %lu peers.", m_peers.size() + 1);
Log::verbose("NetworkManager", "Address of event->peer after connection : %ld", (long int)(event->peer));
// create the new peer:
m_peers.push_back(event->peer);
}
if (event->type == EVENT_TYPE_MESSAGE)
{
uint32_t addr = event->peer->getAddress();
Log::info("NetworkManager", "Message, Sender : %i.%i.%i.%i, message = \"%s\"",
((addr>>24)&0xff),
((addr>>16)&0xff),
((addr>>8)&0xff),
(addr&0xff), event->data.c_str());
}
// notify for the event now.
ProtocolManager::getInstance()->notifyEvent(event);
if (event->type == EVENT_TYPE_DISCONNECTED)
{
Log::debug("NetworkManager", "Disconnected host: %i.%i.%i.%i:%i", event->peer->getAddress()>>24&0xff, event->peer->getAddress()>>16&0xff, event->peer->getAddress()>>8&0xff, event->peer->getAddress()&0xff,event->peer->getPort());
// remove the peer:
bool removed = false;
for (unsigned int i = 0; i < m_peers.size(); i++)
{
Log::error("NetworkManager", "Saved : %ld, Sender : %ld", (long int)(m_peers[i]), (long int)(event->peer));
if (m_peers[i] == event->peer && !removed) // remove only one
{
delete m_peers[i];
m_peers.erase(m_peers.begin()+i, m_peers.begin()+i+1);
Log::verbose("NetworkManager", "The peer has been removed from the Network Manager.");
removed = true;
}
else if (m_peers[i] == event->peer)
{
Log::fatal("NetworkManager", "Multiple peers match the disconnected one.");
}
}
if (!removed)
Log::warn("NetworkManager", "The peer that has been disconnected was not registered by the Network Manager.");
Log::debug("NetworkManager", "Somebody is now disconnected. There are now %lu peers.", m_peers.size());
}
delete event;
}
//-----------------------------------------------------------------------------

View File

@ -141,6 +141,7 @@ class NetworkString
inline uint8_t getUInt8(int pos = 0) { return get<uint8_t,1>(pos); }
inline char getChar(int pos = 0) { return get<char,1>(pos); }
inline unsigned char getUChar(int pos = 0) { return get<unsigned char,1>(pos); }
std::string getString(int pos = 0) { return std::string(m_string.c_str()+pos); }
inline int gi(int pos = 0) { return get<int,4>(pos); }
inline uint32_t gui(int pos = 0) { return get<uint32_t,4>(pos); }
@ -149,6 +150,7 @@ class NetworkString
inline uint8_t gui8(int pos = 0) { return get<uint8_t,1>(pos); }
inline char gc(int pos = 0) { return get<char,1>(pos); }
inline unsigned char guc(int pos = 0) { return get<unsigned char,1>(pos); }
std::string gs(int pos = 0) { return std::string(m_string.c_str()+pos); }
double getDouble(int pos = 0) //!< BEWARE OF PRECISION
{

View File

@ -18,6 +18,8 @@
#include "network/protocol.hpp"
#include "network/protocol_manager.hpp"
Protocol::Protocol(CallbackObject* callback_object, PROTOCOL_TYPE type)
{
m_callback_object = callback_object;
@ -43,7 +45,7 @@ void Protocol::kill()
void Protocol::setListener(ProtocolManager* listener)
{
m_listener = listener;
m_listener = listener;
}
PROTOCOL_TYPE Protocol::getProtocolType()

View File

@ -19,10 +19,12 @@
#ifndef PROTOCOL_HPP
#define PROTOCOL_HPP
#include "network/protocol_manager.hpp"
#include "network/event.hpp"
#include "network/types.hpp"
#include "utils/types.hpp"
class ProtocolManager;
/** \enum PROTOCOL_TYPE
* \brief The types that protocols can have. This is used to select which protocol receives which event.
* \ingroup network
@ -36,7 +38,7 @@ enum PROTOCOL_TYPE
};
/** \class Protocol
* \brief Abstract class used to define the global protocol functions.
* \brief Abstract class used to define the global protocol functions.
* A protocol is an entity that is started at a point, and that is updated by a thread.
* A protocol can be terminated by an other class, or it can terminate itself if has fulfilled its role.
* This class must be inherited to make any network job.
@ -57,44 +59,44 @@ class Protocol
/*!
* \brief Destructor
*/
virtual ~Protocol();
virtual ~Protocol();
/*!
* \brief Notify a protocol matching the Event type of that event.
* \param event : Pointer to the event.
*/
virtual void notifyEvent(Event* event) = 0;
/*!
/*!
* \brief Set the protocol listener.
* \param listener : Pointer to the listener.
*/
void setListener(ProtocolManager* listener);
/*!
/*!
* \brief Called when the protocol is going to start. Must be re-defined by subclasses.
*/
virtual void setup() = 0;
/*!
* \brief Called when the protocol is paused (by an other entity or by itself).
/*!
* \brief Called when the protocol is paused (by an other entity or by itself).
* This function must be called by the subclasse's pause function if re-defined.
*/
virtual void pause();
/*!
* \brief Called when the protocol is unpaused.
/*!
* \brief Called when the protocol is unpaused.
* This function must be called by the subclasse's unpause function if re-defined.
*/
virtual void unpause();
/*!
/*!
* \brief Called by the protocol listener as often as possible. Must be re-defined.
*/
virtual void update() = 0;
/*!
/*!
* \brief Called when the protocol is to be killed.
*/
virtual void kill();
/*!
/*!
* \brief Method to get a protocol's type.
* \return The protocol type.
*/

View File

@ -37,7 +37,7 @@ void* protocolManagerUpdate(void* data)
return NULL;
}
ProtocolManager::ProtocolManager()
ProtocolManager::ProtocolManager()
{
pthread_mutex_init(&m_events_mutex, NULL);
pthread_mutex_init(&m_protocols_mutex, NULL);
@ -45,8 +45,8 @@ ProtocolManager::ProtocolManager()
pthread_mutex_init(&m_id_mutex, NULL);
pthread_mutex_init(&m_exit_mutex, NULL);
m_next_protocol_id = 0;
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);
@ -70,7 +70,7 @@ ProtocolManager::~ProtocolManager()
pthread_mutex_unlock(&m_protocols_mutex);
pthread_mutex_unlock(&m_requests_mutex);
pthread_mutex_unlock(&m_id_mutex);
pthread_mutex_destroy(&m_events_mutex);
pthread_mutex_destroy(&m_protocols_mutex);
pthread_mutex_destroy(&m_requests_mutex);
@ -80,8 +80,9 @@ ProtocolManager::~ProtocolManager()
void ProtocolManager::notifyEvent(Event* event)
{
Event* event2 = new Event(*event);
pthread_mutex_lock(&m_events_mutex);
m_events_to_process.push_back(event); // add the event to the queue
m_events_to_process.push_back(event2); // add the event to the queue
pthread_mutex_unlock(&m_events_mutex);
}
@ -89,7 +90,7 @@ void ProtocolManager::sendMessage(Protocol* sender, const NetworkString& message
{
NetworkString newMessage;
newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type
newMessage += message;
newMessage += message;
NetworkManager::getInstance()->sendPacket(newMessage);
}
@ -97,14 +98,14 @@ void ProtocolManager::sendMessage(Protocol* sender, STKPeer* peer, const Network
{
NetworkString newMessage;
newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type
newMessage += message;
newMessage += message;
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
newMessage += message;
newMessage += message;
NetworkManager::getInstance()->sendPacketExcept(peer, newMessage);
}
@ -122,7 +123,7 @@ uint32_t ProtocolManager::requestStart(Protocol* protocol)
pthread_mutex_lock(&m_requests_mutex);
m_requests.push_back(req);
pthread_mutex_unlock(&m_requests_mutex);
return info.id;
}
@ -187,7 +188,7 @@ void ProtocolManager::startProtocol(ProtocolInfo protocol)
}
void ProtocolManager::stopProtocol(ProtocolInfo protocol)
{
}
void ProtocolManager::pauseProtocol(ProtocolInfo protocol)
{
@ -239,7 +240,7 @@ void ProtocolManager::update()
Event* event = m_events_to_process.back();
m_events_to_process.pop_back();
pthread_mutex_unlock(&m_events_mutex); // release the mutex
PROTOCOL_TYPE searchedProtocol = PROTOCOL_NONE;
if (event->type == EVENT_TYPE_MESSAGE)
{
@ -259,9 +260,10 @@ void ProtocolManager::update()
{
Log::debug("ProtocolManager", "Message is \"%s\"", event->data.c_str());
}
delete event->peer; // because we made a copy of the peer
delete event;
}
// now update all protocols
pthread_mutex_lock(&m_protocols_mutex);
for (unsigned int i = 0; i < m_protocols.size(); i++)
@ -269,8 +271,8 @@ void ProtocolManager::update()
if (m_protocols[i].state == PROTOCOL_STATE_RUNNING)
m_protocols[i].protocol->update();
}
pthread_mutex_unlock(&m_protocols_mutex);
pthread_mutex_unlock(&m_protocols_mutex);
// process queued events for protocols
pthread_mutex_lock(&m_requests_mutex);
for (unsigned int i = 0; i < m_requests.size(); i++)
@ -316,7 +318,7 @@ PROTOCOL_STATE ProtocolManager::getProtocolState(uint32_t id)
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
}
return PROTOCOL_STATE_TERMINATED; // else, it's already finished
return PROTOCOL_STATE_TERMINATED; // else, it's already finished
}
PROTOCOL_STATE ProtocolManager::getProtocolState(Protocol* protocol)
@ -354,6 +356,16 @@ Protocol* ProtocolManager::getProtocol(uint32_t id)
return NULL;
}
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;
}
bool ProtocolManager::isServer()
{
return NetworkManager::getInstance()->isServer();

View File

@ -26,39 +26,38 @@
#include "network/singleton.hpp"
#include "network/event.hpp"
#include "network/network_string.hpp"
#include "network/protocol.hpp"
#include "utils/types.hpp"
#include <vector>
class Protocol;
/*!
/*!
* \enum PROTOCOL_STATE
* \brief Defines the three states that a protocol can have.
*/
enum PROTOCOL_STATE
{
PROTOCOL_STATE_RUNNING, //!< The protocol is being updated everytime.
PROTOCOL_STATE_PAUSED, //!< The protocol is paused.
PROTOCOL_STATE_PAUSED, //!< The protocol is paused.
PROTOCOL_STATE_TERMINATED //!< The protocol is terminated/does not exist.
};
/*!
/*!
* \enum PROTOCOL_REQUEST_TYPE
* \brief Defines actions that can be done about protocols.
* This enum is used essentially to keep the manager thread-safe and
* This enum is used essentially to keep the manager thread-safe and
* to avoid protocols modifying directly their state.
*/
enum PROTOCOL_REQUEST_TYPE
{
PROTOCOL_REQUEST_START, //!< Start a protocol
PROTOCOL_REQUEST_STOP, //!< Stop a protocol
PROTOCOL_REQUEST_STOP, //!< Stop a protocol
PROTOCOL_REQUEST_PAUSE, //!< Pause a protocol
PROTOCOL_REQUEST_UNPAUSE, //!< Unpause a protocol
PROTOCOL_REQUEST_TERMINATE //!< Terminate a protocol
};
/*!
/*!
* \struct ProtocolInfo
* \brief Stores the information needed to manage protocols
*/
@ -68,7 +67,7 @@ typedef struct ProtocolInfo
Protocol* protocol; //!< A pointer to the protocol
uint32_t id; //!< The unique id of the protocol
} ProtocolInfo;
/*!
* \struct ProtocolRequest
* \brief Represents a request to do an action about a protocol.
@ -79,43 +78,43 @@ typedef struct ProtocolRequest
ProtocolInfo protocol_info; //!< The concerned protocol information
} ProtocolRequest;
/*!
/*!
* \class ProtocolManager
* \brief Manages the protocols at runtime.
*
* This class is in charge of storing and managing protocols.
* It is a singleton as there can be only one protocol manager per game
* instance. Any game object that wants to start a protocol must create a
* protocol and give it to this singleton. The protocols are updated in a
*
* This class is in charge of storing and managing protocols.
* It is a singleton as there can be only one protocol manager per game
* instance. Any game object that wants to start a protocol must create a
* protocol and give it to this singleton. The protocols are updated in a
* special thread, to ensure that they are processed independently from the
* frames per second. Then, the management of protocols is thread-safe: any
* frames per second. Then, the management of protocols is thread-safe: any
* object can start/pause/stop protocols whithout problems.
*/
class ProtocolManager : public Singleton<ProtocolManager>
{
friend class Singleton<ProtocolManager>;
public:
/*!
* \brief Function that processes incoming events.
* This function is called by the network manager each time there is an
* incoming packet.
* incoming packet.
*/
virtual void notifyEvent(Event* event);
/*!
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessage(Protocol* sender, const NetworkString& message);
/*!
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessage(Protocol* sender, STKPeer* peer, const NetworkString& message);
/*!
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessageExcept(Protocol* sender, STKPeer* peer, const NetworkString& message);
/*!
/*!
* \brief Asks the manager to start a protocol.
* This function will store the request, and process it at a time it is
* thread-safe.
@ -123,48 +122,48 @@ class ProtocolManager : public Singleton<ProtocolManager>
* \return The unique id of the protocol that is being started.
*/
virtual uint32_t requestStart(Protocol* protocol);
/*!
/*!
* \brief Asks the manager to stop a protocol.
* This function will store the request, and process it at a time it is
* thread-safe.
* \param protocol : A pointer to the protocol to stop
*/
virtual void requestStop(Protocol* protocol);
/*!
/*!
* \brief Asks the manager to pause a protocol.
* This function will store the request, and process it at a time it is
* thread-safe.
* \param protocol : A pointer to the protocol to pause
*/
virtual void requestPause(Protocol* protocol);
/*!
/*!
* \brief Asks the manager to unpause a protocol.
* This function will store the request, and process it at a time it is
* thread-safe.
* \param protocol : A pointer to the protocol to unpause
*/
virtual void requestUnpause(Protocol* protocol);
/*!
/*!
* \brief Notifies the manager that a protocol is terminated.
* This function will store the request, and process it at a time it is
* thread-safe.
* \param protocol : A pointer to the protocol that is finished
*/
virtual void requestTerminate(Protocol* protocol);
/*!
/*!
* \brief Updates the manager.
*
* This function processes the events queue, notifies the concerned
*
* This function processes the events queue, notifies the concerned
* protocols that they have events to process. Then ask all protocols
* to update themselves. Finally processes stored requests about
* to update themselves. Finally processes stored requests about
* starting, stoping, pausing etc... protocols.
* This function is called by a thread as often as possible.
* This function is not FPS-dependant.
*/
virtual void update();
/*!
/*!
* \brief Get the number of protocols running.
* \return The number of protocols that are actually running.
*/
@ -172,13 +171,13 @@ class ProtocolManager : public Singleton<ProtocolManager>
/*!
* \brief Get the state of a protocol using its id.
* \param id : The id of the protocol you seek the state.
* \return The state of the protocol.
* \return The state of the protocol.
*/
virtual PROTOCOL_STATE getProtocolState(uint32_t id);
/*!
* \brief Get the state of a protocol using a pointer on it.
* \param protocol : A pointer to the protocol you seek the state.
* \return The state of the protocol.
* \return The state of the protocol.
*/
virtual PROTOCOL_STATE getProtocolState(Protocol* protocol);
/*!
@ -187,29 +186,35 @@ class ProtocolManager : public Singleton<ProtocolManager>
* \return The id of the protocol pointed by the protocol parameter.
*/
virtual uint32_t getProtocolID(Protocol* protocol);
/*!
* \brief Get a protocol using his id.
* \brief Get a protocol using its id.
* \param id : Unique ID of the seek protocol.
* \return The protocol that has the ID id.
*/
virtual Protocol* getProtocol(uint32_t id);
/*!
* \brief Get a protocol using its type.
* \param type : The type of the protocol.
* \return The protocol that matches the given type.
*/
virtual Protocol* getProtocol(PROTOCOL_TYPE type);
/*! \brief Know whether the app is a server.
* \return True if this application is in server mode, false elseway.
*/
bool isServer();
/*! \brief Tells if we need to stop the update thread. */
int exit();
protected:
// protected functions
/*!
/*!
* \brief Constructor
*/
ProtocolManager();
/*!
/*!
* \brief Destructor
*/
virtual ~ProtocolManager();
@ -221,7 +226,7 @@ class ProtocolManager : public Singleton<ProtocolManager>
* \param protocol_info : The protocol info that needs an id.
*/
void assignProtocolId(ProtocolInfo* protocol_info);
/*!
* \brief Starts a protocol.
* Add the protocol info to the m_protocols vector.
@ -252,11 +257,11 @@ class ProtocolManager : public Singleton<ProtocolManager>
* \param protocol : ProtocolInfo concerned.
*/
virtual void protocolTerminated(ProtocolInfo protocol);
// protected members
/*!
/*!
* \brief Contains the running protocols.
* This stores the protocols that are either running or paused, their
* This stores the protocols that are either running or paused, their
* state and their unique id.
*/
std::vector<ProtocolInfo> m_protocols;
@ -268,13 +273,13 @@ class ProtocolManager : public Singleton<ProtocolManager>
* \brief Contains the requests to start/stop etc... protocols.
*/
std::vector<ProtocolRequest> m_requests;
/*! \brief The next id to assign to a protocol.
* This value is incremented by 1 each time a protocol is started.
/*! \brief The next id to assign to a protocol.
* This value is incremented by 1 each time a protocol is started.
* If a protocol has an id lower than this value, it means that it have
* been formerly started.
* been formerly started.
*/
uint32_t m_next_protocol_id;
// mutexes:
/*! Used to ensure that the event queue is used thread-safely. */
pthread_mutex_t m_events_mutex;
@ -286,10 +291,10 @@ class ProtocolManager : public Singleton<ProtocolManager>
pthread_mutex_t m_id_mutex;
/*! Used when need to quit.*/
pthread_mutex_t m_exit_mutex;
/*! Update thread.*/
pthread_t* m_update_thread;
};
#endif // PROTOCOL_MANAGER_HPP

View File

@ -4,10 +4,10 @@
#include "online/current_online_user.hpp"
#include "utils/log.hpp"
ClientLobbyRoomProtocol::ClientLobbyRoomProtocol(const TransportAddress& server_address)
: LobbyRoomProtocol(NULL)
{
m_server_address = server_address;
ClientLobbyRoomProtocol::ClientLobbyRoomProtocol(const TransportAddress& server_address)
: LobbyRoomProtocol(NULL)
{
m_server_address = server_address;
m_server = NULL;
}
@ -45,7 +45,7 @@ void ClientLobbyRoomProtocol::notifyEvent(Event* event)
assert(event->data.size()); // assert that data isn't empty
Log::verbose("ClientLobbyRoomProtocol", "Message from %u : \"%s\"", event->peer->getAddress(), event->data.c_str());
uint8_t message_type = event->data.getAndRemoveUInt8();
if (message_type == 0x01) // new player connected
newPlayer(event);
else if (message_type == 0x02) // player disconnected
@ -102,7 +102,7 @@ void ClientLobbyRoomProtocol::update()
/*! \brief Called when a new player is connected to the server
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 5 6 7
* ------------------------------------------------
@ -120,9 +120,9 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event)
uint32_t global_id = event->data.gui32(1);
NetworkPlayerProfile profile;
profile.kart_name = "";
profile.race_id = event->data.gui8(6);
NetworkPlayerProfile* profile = new NetworkPlayerProfile();
profile->kart_name = "";
profile->race_id = event->data.gui8(6);
if (global_id == CurrentOnlineUser::get()->getUserID())
{
@ -131,7 +131,7 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event)
else
{
Log::verbose("ClientLobbyRoomProtocol", "New player connected.");
profile.user_profile = new OnlineUser(global_id);
profile->user_profile = new OnlineUser(global_id);
m_setup->addPlayer(profile);
}
}
@ -140,7 +140,7 @@ void ClientLobbyRoomProtocol::newPlayer(Event* event)
/*! \brief Called when a new player is disconnected
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 2
* -------------------------
@ -170,7 +170,7 @@ void ClientLobbyRoomProtocol::disconnectedPlayer(Event* event)
/*! \brief Called when the server accepts the connection.
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 2 3 7 8 12
* ----------------------------------------------------------
@ -186,15 +186,15 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
return;
}
NetworkPlayerProfile profile;
profile.kart_name = "";
profile.race_id = event->data.gui8(1);
NetworkPlayerProfile* profile = new NetworkPlayerProfile();
profile->kart_name = "";
profile->race_id = event->data.gui8(1);
uint32_t token = event->data.gui32(3);
uint32_t global_id = event->data.gui32(8);
if (global_id == CurrentOnlineUser::get()->getUserID())
{
Log::info("ClientLobbyRoomProtocol", "The server accepted the connection.");
profile.user_profile = CurrentOnlineUser::get();
profile->user_profile = CurrentOnlineUser::get();
m_setup->addPlayer(profile);
event->peer->setClientServerToken(token);
m_server = event->peer;
@ -206,7 +206,7 @@ void ClientLobbyRoomProtocol::connectionAccepted(Event* event)
/*! \brief Called when the server refuses the connection.
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 2
* --------------------
@ -240,7 +240,7 @@ void ClientLobbyRoomProtocol::connectionRefused(Event* event)
/*! \brief Called when the server refuses the kart selection request.
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 2
* --------------------
@ -272,11 +272,11 @@ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event)
//-----------------------------------------------------------------------------
/*! \brief Called when the server refuses the kart selection request.
/*! \brief Called when the server tells to update a player's kart.
* \param event : Event providing the information.
*
*
* Format of the data :
* Byte 0 1 2 3 N+3
* Byte 0 1 2 3 N+3
* ------------------------------------------------
* Size | 1 | 1 | 1 | N |
* Data | 1 | race id | N (kart name size) | kart name |
@ -284,9 +284,24 @@ void ClientLobbyRoomProtocol::kartSelectionRefused(Event* event)
*/
void ClientLobbyRoomProtocol::kartSelectionUpdate(Event* event)
{
if (event->data[0] != 1)
if (event->data.size() < 3 || event->data[0] != 1)
{
Log::error("ClientLobbyRoomProtocol", "A message notifying a refused connection wasn't formated as expected.");
Log::error("ClientLobbyRoomProtocol", "A message notifying a kart selection update wasn't formated as expected.");
return;
}
uint8_t player_id = event->data[1];
uint8_t kart_name_length = event->data[2];
std::string data = event->data.getString(3);
if (data.size() != kart_name_length)
{
Log::error("ClientLobbyRoomProtocol", "Kart names sizes differ: told: %d, real: %d.", kart_name_length, data.size());
return;
}
if (!m_setup->isKartAvailable(data))
{
Log::error("ClientLobbyRoomProtocol", "The updated kart is taken already.");
}
m_setup->setPlayerKart(player_id, data);
}
//-----------------------------------------------------------------------------

View File

@ -8,15 +8,15 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
public:
ClientLobbyRoomProtocol(const TransportAddress& server_address);
virtual ~ClientLobbyRoomProtocol();
void requestKartSelection(std::string kart_name);
void sendMessage(std::string message);
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
protected:
void newPlayer(Event* event);
void disconnectedPlayer(Event* event);
@ -25,9 +25,9 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
void kartSelectionRefused(Event* event);
void kartSelectionUpdate(Event* event);
TransportAddress m_server_address;
TransportAddress m_server_address;
STKPeer* m_server;
enum STATE
{
NONE,

View File

@ -18,6 +18,7 @@
#include "network/protocols/get_peer_address.hpp"
#include "network/protocol_manager.hpp"
#include "network/http_functions.hpp"
#include "online/http_connector.hpp"
#include "online/current_online_user.hpp"
@ -47,7 +48,7 @@ void GetPeerAddress::update()
{
if (m_state == NONE)
{
HTTPConnector * connector = new HTTPConnector((std::string)UserConfigParams::m_server_multiplayer + "address-management.php");
connector->setParameter("id",CurrentOnlineUser::get()->getUserID());
connector->setParameter("token",CurrentOnlineUser::get()->getToken());

View File

@ -18,6 +18,7 @@
#include "network/protocols/hide_public_address.hpp"
#include "network/protocol_manager.hpp"
#include "online/http_connector.hpp"
#include "online/current_online_user.hpp"
#include "config/user_config.hpp"

View File

@ -1,5 +1,6 @@
#include "network/protocols/request_connection.hpp"
#include "network/protocol_manager.hpp"
#include "online/http_connector.hpp"
#include "online/current_online_user.hpp"
#include "config/user_config.hpp"
@ -53,7 +54,7 @@ void RequestConnection::update()
Log::error("RequestConnection", "Fail to make a request.");
}
m_state = DONE;
break;
}
case DONE:

View File

@ -46,62 +46,17 @@ void ServerLobbyRoomProtocol::notifyEvent(Event* event)
uint8_t message_type;
message_type = event->data.getAndRemoveUInt8();
Log::info("ServerLobbyRoomProtocol", "Message received with type %d.", message_type);
if (message_type == 1) // player requesting connection
{
if (event->data.size() != 5 || event->data[0] != 4)
{
Log::warn("LobbyRoomProtocol", "A player is sending a badly formated message. Size is %d and first byte %d", event->data.size(), event->data[0]);
return;
}
Log::verbose("LobbyRoomProtocol", "New player.");
int player_id = 0;
player_id = event->data.getUInt32(1);
// can we add the player ?
if (m_setup->getPlayerCount() < 16) // accept player
{
// add the player to the game setup
while(m_setup->getProfile(m_next_id)!=NULL)
m_next_id++;
NetworkPlayerProfile profile;
profile.race_id = m_next_id;
profile.kart_name = "";
profile.user_profile = new OnlineUser("Unnamed Player");
m_setup->addPlayer(profile);
// notify everybody that there is a new player
NetworkString message;
// new player (1) -- size of id -- id -- size of local id -- local id;
message.ai8(1).ai8(4).ai32(player_id).ai8(1).ai8(m_next_id);
m_listener->sendMessageExcept(this, event->peer, message);
// send a message to the one that asked to connect
NetworkString message_ack;
// 0b10000001 (connection success) ;
RandomGenerator token_generator;
// use 4 random numbers because rand_max is probably 2^15-1.
uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX)<<24) & 0xff) +
((token_generator.get(RAND_MAX)<<16) & 0xff) +
((token_generator.get(RAND_MAX)<<8) & 0xff) +
((token_generator.get(RAND_MAX) & 0xff)));
// connection success (129) -- size of token -- token
message_ack.ai8(0x81).ai8(1).ai8(m_next_id).ai8(4).ai32(token).ai8(4).ai32(player_id);
m_listener->sendMessage(this, event->peer, message_ack);
} // accept player
else // refuse the connection with code 0 (too much players)
{
NetworkString message;
message.ai8(0x80); // 128 means connection refused
message.ai8(1); // 1 bytes for the error code
message.ai8(0); // 0 = too much players
// send only to the peer that made the request
m_listener->sendMessage(this, event->peer, message);
}
}
if (message_type == 0x01) // player requesting connection
connectionRequested(event);
if (message_type == 0x02) // player requesting kart selection
kartSelectionRequested(event);
} // if (event->type == EVENT_TYPE_MESSAGE)
else if (event->type == EVENT_TYPE_CONNECTED)
{
} // if (event->type == EVENT_TYPE_CONNECTED)
else if (event->type == EVENT_TYPE_DISCONNECTED)
{
kartDisconnected(event);
} // if (event->type == EVENT_TYPE_DISCONNECTED)
}
@ -188,3 +143,137 @@ void ServerLobbyRoomProtocol::update()
}
//-----------------------------------------------------------------------------
void ServerLobbyRoomProtocol::kartDisconnected(Event* event)
{
if (event->peer->getPlayerProfile() != NULL) // others knew him
{
NetworkString msg;
msg.ai8(0x02).ai8(1).ai8(event->peer->getPlayerProfile()->race_id);
m_listener->sendMessage(this, msg);
}
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player asks for a connection.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5
* ------------------------
* Size | 1 | 4 |
* Data | 4 | global player id |
* ------------------------
*/
void ServerLobbyRoomProtocol::connectionRequested(Event* event)
{
if (event->data.size() != 5 || event->data[0] != 4)
{
Log::warn("ServerLobbyRoomProtocol", "The server is sending a badly formated message. Size is %d and first byte %d", event->data.size(), event->data[0]);
return;
}
Log::verbose("ServerLobbyRoomProtocol", "New player.");
int player_id = 0;
player_id = event->data.getUInt32(1);
// can we add the player ?
if (m_setup->getPlayerCount() < 16) // accept player
{
// add the player to the game setup
while(m_setup->getProfile(m_next_id)!=NULL)
m_next_id++;
NetworkPlayerProfile* profile = new NetworkPlayerProfile();
profile->race_id = m_next_id;
profile->kart_name = "";
profile->user_profile = new OnlineUser("Unnamed Player");
m_setup->addPlayer(profile);
event->peer->setPlayerProfile(profile);
// notify everybody that there is a new player
NetworkString message;
// new player (1) -- size of id -- id -- size of local id -- local id;
message.ai8(1).ai8(4).ai32(player_id).ai8(1).ai8(m_next_id);
m_listener->sendMessageExcept(this, event->peer, message);
// send a message to the one that asked to connect
NetworkString message_ack;
// 0b10000001 (connection success) ;
RandomGenerator token_generator;
// use 4 random numbers because rand_max is probably 2^15-1.
uint32_t token = (uint32_t)(((token_generator.get(RAND_MAX)<<24) & 0xff) +
((token_generator.get(RAND_MAX)<<16) & 0xff) +
((token_generator.get(RAND_MAX)<<8) & 0xff) +
((token_generator.get(RAND_MAX) & 0xff)));
// connection success (129) -- size of token -- token
message_ack.ai8(0x81).ai8(1).ai8(m_next_id).ai8(4).ai32(token).ai8(4).ai32(player_id);
m_listener->sendMessage(this, event->peer, message_ack);
} // accept player
else // refuse the connection with code 0 (too much players)
{
NetworkString message;
message.ai8(0x80); // 128 means connection refused
message.ai8(1); // 1 bytes for the error code
message.ai8(0); // 0 = too much players
// send only to the peer that made the request
m_listener->sendMessage(this, event->peer, message);
}
}
//-----------------------------------------------------------------------------
/*! \brief Called when a player asks to select a kart.
* \param event : Event providing the information.
*
* Format of the data :
* Byte 0 1 5 6 N+6
* ---------------------------------------------------
* Size | 1 | 4 | 1 | N |
* Data | 4 | priv token | N (kart name size) | kart name |
* ---------------------------------------------------
*/
void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
{
if (event->data.size() < 6 || event->data[0] != 4)
{
Log::warn("ServerLobbyRoomProtocol", "The server is sending a badly "
"formated message. Size is %d and first byte %d",
event->data.size(), event->data[0]);
return;
}
uint32_t token = event->data.gui32(1);
if (token != event->peer->getClientServerToken())
{
Log::warn("ServerLobbyRoomProtocol", "Peer sending bad token. Request "
"aborted.");
return;
}
uint8_t kart_name_size = event->data.gui8(5);
std::string kart_name = event->data.gs(6);
if (kart_name.size() != kart_name_size)
{
Log::error("ServerLobbyRoomProtocol", "Kart names sizes differ: told:"
"%d, real: %d.", kart_name_size, kart_name.size());
return;
}
if (!m_setup->isKartAvailable(kart_name))
{
NetworkString answer;
answer.ai8(0x82).ai8(1).ai8(0); // kart is already taken
m_listener->sendMessage(this, event->peer, answer);
return;
}
// check if this kart is authorized
if (!m_setup->isKartAllowed(kart_name))
{
NetworkString answer;
answer.ai8(0x82).ai8(1).ai8(1); // kart is not authorized
m_listener->sendMessage(this, event->peer, answer);
return;
}
// send a kart update to everyone
NetworkString answer;
// kart update (3), 1, race id
answer.ai8(0x03).ai8(1).ai8(event->peer->getPlayerProfile()->race_id);
// kart name size, kart name
answer.ai8(kart_name.size()).as(kart_name);
m_listener->sendMessage(this, answer);
}
//-----------------------------------------------------------------------------

View File

@ -8,18 +8,22 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
public:
ServerLobbyRoomProtocol();
virtual ~ServerLobbyRoomProtocol();
virtual void notifyEvent(Event* event);
virtual void setup();
virtual void update();
protected:
void kartDisconnected(Event* event);
void connectionRequested(Event* event);
void kartSelectionRequested(Event* event);
uint8_t m_next_id; //!< Next id to assign to a peer.
std::vector<TransportAddress> m_peers;
std::vector<uint32_t> m_incoming_peers_ids;
uint32_t m_current_protocol_id;
TransportAddress m_public_address;
enum STATE
{
NONE,

View File

@ -25,13 +25,14 @@
STKPeer::STKPeer()
{
m_peer = NULL;
m_player_profile = NULL;
}
STKPeer::~STKPeer()
{
if (m_peer)
{
//free(m_peer);
free(m_peer);
m_peer = NULL;
}
}
@ -39,15 +40,15 @@ STKPeer::~STKPeer()
bool STKPeer::connectToHost(STKHost* localhost, TransportAddress host, uint32_t channel_count, uint32_t data)
{
ENetAddress address;
address.host =
address.host =
((host.ip & 0xff000000) >> 24)
+ ((host.ip & 0x00ff0000) >> 8)
+ ((host.ip & 0x0000ff00) << 8)
+ ((host.ip & 0x000000ff) << 24); // because ENet wants little endian
address.port = host.port;
ENetPeer* peer = enet_host_connect(localhost->m_host, &address, 2, 0);
if (peer == NULL)
if (peer == NULL)
{
Log::error("STKPeer", "Could not try to connect to server.\n");
return false;
@ -65,7 +66,7 @@ void STKPeer::sendPacket(NetworkString const& data)
{
Log::verbose("STKPeer", "sending packet of size %d to %i.%i.%i.%i:%i", data.size(), (m_peer->address.host>>0)&0xff,(m_peer->address.host>>8)&0xff,(m_peer->address.host>>16)&0xff,(m_peer->address.host>>24)&0xff,m_peer->address.port);
ENetPacket* packet = enet_packet_create(data.c_str(), data.size()+1,ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(m_peer, 0, packet);
}

View File

@ -21,6 +21,7 @@
#include "network/stk_host.hpp"
#include "network/network_string.hpp"
#include "network/game_setup.hpp"
#include <enet/enet.h>
class STKPeer
@ -29,9 +30,9 @@ class STKPeer
public:
STKPeer();
virtual ~STKPeer();
virtual void sendPacket(const NetworkString& data);
static bool connectToHost(STKHost* localhost, TransportAddress host, uint32_t channel_count, uint32_t data);
void disconnect();
@ -39,16 +40,19 @@ class STKPeer
bool isConnected() const;
void setClientServerToken(const uint32_t& token) { m_client_server_token = token; m_token_set = true; }
void unsetClientServerToken() { m_token_set = false; }
void setPlayerProfile(NetworkPlayerProfile* profile) { m_player_profile = profile; }
uint32_t getAddress() const;
uint16_t getPort() const;
uint32_t getClientServerToken() const { return m_client_server_token; }
bool isClientServerTokenSet() const { return m_token_set; }
NetworkPlayerProfile* getPlayerProfile() { return m_player_profile; }
bool operator==(const ENetPeer* peer) const;
protected:
ENetPeer* m_peer;
NetworkPlayerProfile* m_player_profile;
uint32_t m_client_server_token;
bool m_token_set;
};