Started to refactor network code.

This commit is contained in:
hiker 2015-10-24 12:39:17 +11:00
parent b8cd9cfb81
commit 350f434c37
41 changed files with 1136 additions and 844 deletions

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -179,7 +179,7 @@
#include "network/protocol_manager.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "network/client_network_manager.hpp"
#include "network/server_network_manager.hpp"
#include "network/server_console.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "online/profile_manager.hpp"
@ -782,9 +782,16 @@ int handleCmdLine()
// Networking command lines
if(CommandLine::has("--server") )
{
NetworkManager::getInstance<ServerNetworkManager>();
Log::info("main", "Creating a server network manager.");
} // -server
STKHost::create(/*is_Server*/true);
Log::info("main", "Creating a server.");
}
else
{
STKHost::create(/*is_server*/false);
Log::info("main", "Creating a client.");
}
NetworkManager::getInstance<ClientNetworkManager>();
NetworkManager::getInstance()->run();
if(CommandLine::has("--max-players", &n))
UserConfigParams::m_server_max_players=n;
@ -801,8 +808,8 @@ int handleCmdLine()
// Race parameters
if(CommandLine::has("--kartsize-debug"))
{
for(unsigned int i=0;
i<kart_properties_manager->getNumberOfKarts(); i++)
for(unsigned int i=0; i<kart_properties_manager->getNumberOfKarts();
i++)
{
const KartProperties *km =
kart_properties_manager->getKartById(i);
@ -1343,17 +1350,13 @@ int main(int argc, char *argv[] )
if(!handleCmdLine()) exit(0);
// load the network manager
// If the server has been created (--server option), this will do nothing (just a warning):
NetworkManager::getInstance<ClientNetworkManager>();
if (NetworkManager::getInstance()->isServer())
{
ServerNetworkManager::getInstance()->setMaxPlayers(
UserConfigParams::m_server_max_players);
STKHost::setMaxPlayers(UserConfigParams::m_server_max_players);
(new ServerLobbyRoomProtocol())->requestStart();
}
NetworkManager::getInstance()->run();
if (NetworkManager::getInstance()->isServer())
else // is client
{
ProtocolManager::getInstance()->requestStart(new ServerLobbyRoomProtocol());
}
addons_manager->checkInstalledAddons();

View File

@ -134,9 +134,8 @@ void ClientNetworkManager::run()
Log::error("ClientNetworkManager", "Could not initialize enet.\n");
return;
}
m_localhost = new STKHost();
m_localhost->setupClient(1, 2, 0, 0);
m_localhost->startListening();
STKHost::get()->setupClient(1, 2, 0, 0);
STKHost::get()->startListening();
Log::info("ClientNetworkManager", "Host initialized.");
@ -170,9 +169,9 @@ void ClientNetworkManager::reset()
NetworkManager::reset();
m_connected = false;
m_localhost = new STKHost();
m_localhost->setupClient(1, 2, 0, 0);
m_localhost->startListening();
STKHost::create(/*is_server*/false);
STKHost::get()->setupClient(1, 2, 0, 0);
STKHost::get()->startListening();
}

273
src/network/network.cpp Executable file
View File

@ -0,0 +1,273 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 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.
#include "network/network.hpp"
#include "config/user_config.hpp"
#include "io/file_manager.hpp"
#include "network/network_string.hpp"
#include "utils/time.hpp"
#include <string.h>
#if defined(WIN32)
# include "ws2tcpip.h"
# define inet_ntop InetNtop
#else
# include <arpa/inet.h>
# include <errno.h>
# include <sys/socket.h>
#endif
#include <pthread.h>
#include <signal.h>
Synchronised<FILE*>Network::m_log_file = NULL;
// ============================================================================
/** Constructor that just initialises this object (esp. opening the packet
* log file), but it does not start a listener thread.
* \param peer_count : The maximum number of peers.
* \param channel_limit : The maximum number of channels per peer.
* \param max_incoming_bandwidth : The maximum incoming bandwidth.
* \param max_outgoing_bandwidth : The maximum outgoing bandwidth.
*/
Network::Network(int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth,
ENetAddress* address)
{
m_host = enet_host_create(address, peer_count, channel_limit, 0, 0);
if (!m_host)
{
Log::fatal("Network", "An error occurred while trying to create an "
"ENet client host.");
}
} // Network
// ----------------------------------------------------------------------------
/** Destructor. Stops the listening thread, closes the packet log file and
* destroys the enet host.
*/
Network::~Network()
{
if (m_host)
{
enet_host_destroy(m_host);
}
} // ~Network
// ----------------------------------------------------------------------------
ENetPeer *Network::connectTo(const TransportAddress &address)
{
const ENetAddress enet_address = address.toEnetAddress();
return enet_host_connect(m_host, &enet_address, 2, 0);
} // connectTo
// ----------------------------------------------------------------------------
/** \brief Sends a packet whithout ENet adding its headers.
* This function is used in particular to achieve the STUN protocol.
* \param data : Data to send.
* \param length : Length of the sent data.
* \param dst : Destination of the packet.
*/
void Network::sendRawPacket(uint8_t* data, int length,
const TransportAddress& dst)
{
struct sockaddr_in to;
int to_len = sizeof(to);
memset(&to,0,to_len);
to.sin_family = AF_INET;
to.sin_port = htons(dst.getPort());
to.sin_addr.s_addr = htonl(dst.getIP());
sendto(m_host->socket, (char*)data, length, 0,(sockaddr*)&to, to_len);
Log::verbose("Network", "Raw packet sent to %s",
dst.toString().c_str());
Network::logPacket(NetworkString(std::string((char*)(data), length)),
false);
} // sendRawPacket
// ----------------------------------------------------------------------------
/** \brief Receives a packet directly from the network interface.
* Receive a packet whithout ENet processing it and returns the
* sender's ip address and port in the TransportAddress structure.
* \param sender : Stores the transport address of the sender of the
* received packet.
* \return A string containing the data of the received packet.
*/
uint8_t* Network::receiveRawPacket(TransportAddress* sender)
{
const int LEN = 2048;
// max size needed normally (only used for stun)
uint8_t* buffer = new uint8_t[LEN];
memset(buffer, 0, LEN);
socklen_t from_len;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
int i = 0;
// wait to receive the message because enet sockets are non-blocking
while(len == -1) // nothing received
{
StkTime::sleep(1); // wait 1 millisecond between two checks
i++;
len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
}
if (len == SOCKET_ERROR)
{
Log::error("STKHost",
"Problem with the socket. Please contact the dev team.");
}
// we received the data
sender->setIP( ntohl((uint32_t)(addr.sin_addr.s_addr)) );
sender->setPort( ntohs(addr.sin_port) );
if (addr.sin_family == AF_INET)
{
Log::info("STKHost", "IPv4 Address of the sender was %s",
sender->toString().c_str());
}
return buffer;
} // receiveRawPacket(TransportAddress* sender)
// ----------------------------------------------------------------------------
/** \brief Receives a packet directly from the network interface and
* filter its address.
* Receive a packet whithout ENet processing it. Checks that the
* sender of the packet is the one that corresponds to the sender
* parameter. Does not check the port right now.
* \param sender : Transport address of the original sender of the
* wanted packet.
* \param max_tries : Number of times we try to read data from the
* socket. This is aproximately the time we wait in
* milliseconds. -1 means eternal tries.
* \return A string containing the data of the received packet
* matching the sender's ip address.
*/
uint8_t* Network::receiveRawPacket(const TransportAddress& sender,
int max_tries)
{
const int LEN = 2048;
uint8_t* buffer = new uint8_t[LEN];
memset(buffer, 0, LEN);
socklen_t from_len;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
int count = 0;
// wait to receive the message because enet sockets are non-blocking
while(len < 0 || addr.sin_addr.s_addr == sender.getIP())
{
count++;
if (len>=0)
{
Log::info("STKHost", "Message received but the ip address didn't "
"match the expected one.");
}
len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len);
StkTime::sleep(1); // wait 1 millisecond between two checks
if (count >= max_tries && max_tries != -1)
{
TransportAddress a(m_host->address);
Log::verbose("STKHost", "No answer from the server on %s",
a.toString().c_str());
return NULL;
}
}
if (addr.sin_family == AF_INET)
{
TransportAddress a(ntohl(addr.sin_addr.s_addr));
Log::info("STKHost", "IPv4 Address of the sender was %s",
a.toString(false).c_str());
}
Network::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
} // receiveRawPacket(const TransportAddress& sender, int max_tries)
// ----------------------------------------------------------------------------
/** \brief Broadcasts a packet to all peers.
* \param data : Data to send.
*/
void Network::broadcastPacket(const NetworkString& data, bool reliable)
{
ENetPacket* packet = enet_packet_create(data.getBytes(), data.size() + 1,
reliable ? ENET_PACKET_FLAG_RELIABLE
: ENET_PACKET_FLAG_UNSEQUENCED);
enet_host_broadcast(m_host, 0, packet);
} // broadcastPacket
// ----------------------------------------------------------------------------
void Network::openLog()
{
m_log_file.setAtomic(NULL);
if (UserConfigParams::m_packets_log_filename.toString() != "")
{
std::string s = file_manager
->getUserConfigFile(UserConfigParams::m_packets_log_filename);
m_log_file.setAtomic(fopen(s.c_str(), "w+"));
}
if (!m_log_file.getData())
Log::warn("STKHost", "Network packets won't be logged: no file.");
} // openLog
// ----------------------------------------------------------------------------
/** \brief Log packets into a file
* \param ns : The data in the packet
* \param incoming : True if the packet comes from a peer.
* False if it's sent to a peer.
*/
void Network::logPacket(const NetworkString &ns, bool incoming)
{
if (m_log_file.getData() == NULL) // read only access, no need to lock
return;
const char *arrow = incoming ? "<--" : "-->";
m_log_file.lock();
fprintf(m_log_file.getData(), "[%d\t] %s ",
(int)(StkTime::getRealTime()), arrow);
for (int i = 0; i < ns.size(); i++)
{
fprintf(m_log_file.getData(), "%d.", ns[i]);
}
fprintf(m_log_file.getData(), "\n");
m_log_file.unlock();
} // logPacket
// ----------------------------------------------------------------------------
void Network::closeLog()
{
if (m_log_file.getData())
{
m_log_file.lock();
fclose(m_log_file.getData());
Log::warn("STKHost", "Packet logging file has been closed.");
m_log_file.getData() = NULL;
m_log_file.unlock();
}
} // closeLog

72
src/network/network.hpp Normal file
View File

@ -0,0 +1,72 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 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.
/*! \file network.hpp
* \brief Defines an interface to use network low-level functions easily.
*/
#ifndef HEADER_NETWORK_HPP
#define HEADER_NETWORK_HPP
#include "network/types.hpp"
#include "utils/synchronised.hpp"
// enet.h includes win32.h, which without lean_and_mean includes
// winspool.h, which defines MAX_PRIORITY as a macro, which then
// results in request_manager.hpp not being compilable.
#define WIN32_LEAN_AND_MEAN
#include <enet/enet.h>
class NetworkString;
/** \class EnetHost
* A small wrapper around enet to allow sending and receiving
* packages.
*/
class Network
{
private:
/** ENet host interfacing sockets. */
ENetHost* m_host;
/** Where to log packets. If NULL for FILE* logging is disabled. */
static Synchronised<FILE*> m_log_file;
public:
Network(int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth,
ENetAddress* address = NULL);
virtual ~Network();
static void openLog();
static void logPacket(const NetworkString &ns, bool incoming);
static void closeLog();
ENetPeer *connectTo(const TransportAddress &address);
void sendRawPacket(uint8_t* data, int length,
const TransportAddress& dst);
uint8_t* receiveRawPacket(TransportAddress* sender);
uint8_t* receiveRawPacket(const TransportAddress& sender,
int max_tries = -1);
void broadcastPacket(const NetworkString& data,
bool reliable = true);
// ------------------------------------------------------------------------
/** Returns a pointer to the ENet host object. */
ENetHost* getENetHost() { return m_host; }
}; // class Network
#endif // HEADER_ENET_SOCKET_HPP

View File

@ -33,7 +33,6 @@ NetworkManager::NetworkManager()
m_public_address.lock();
m_public_address.getData().clear();
m_public_address.unlock();
m_localhost = NULL;
m_game_setup = NULL;
} // NetworkManager
@ -43,8 +42,7 @@ NetworkManager::~NetworkManager()
{
ProtocolManager::kill();
if (m_localhost)
delete m_localhost;
STKHost::destroy();
while(!m_peers.empty())
{
delete m_peers.back();
@ -57,8 +55,6 @@ NetworkManager::~NetworkManager()
*/
void NetworkManager::run()
{
// create the protocol manager
ProtocolManager::getInstance<ProtocolManager>();
} // run
//-----------------------------------------------------------------------------
@ -67,9 +63,7 @@ void NetworkManager::run()
*/
void NetworkManager::reset()
{
if (m_localhost)
delete m_localhost;
m_localhost = NULL;
STKHost::destroy();
while(!m_peers.empty())
{
delete m_peers.back();
@ -84,7 +78,7 @@ void NetworkManager::reset()
*/
void NetworkManager::abort()
{
m_localhost->stopListening();
STKHost::get()->stopListening();
// FIXME: Why a reset here? This creates a new stk_host, which will open
// a new packet_log file (and therefore delete the previous file)???
// reset();
@ -101,7 +95,7 @@ bool NetworkManager::connect(const TransportAddress& address)
if (peerExists(address))
return isConnectedTo(address);
return STKPeer::connectToHost(m_localhost, address, 2, 0);
return STKPeer::connectToHost(STKHost::get(), address, 2, 0);
} // connect
//-----------------------------------------------------------------------------

View File

@ -51,10 +51,6 @@ protected:
NetworkManager();
virtual ~NetworkManager();
/** Pointer to the one stk host instance, which is used to do all
* network communication. */
STKHost* m_localhost;
/** The list of peers connected to this instance. */
std::vector<STKPeer*> m_peers;
@ -99,19 +95,17 @@ public:
* already exists. */
virtual bool peerExists(const TransportAddress& peer)
{
return m_localhost->peerExists(peer);
return STKHost::get()->peerExists(peer);
} // peerExists
// --------------------------------------------------------------------
virtual bool isConnectedTo(const TransportAddress& peer)
{
return m_localhost->isConnectedTo(peer);
return STKHost::get()->isConnectedTo(peer);
} // isConnectedTo
// --------------------------------------------------------------------
inline bool isClient() { return !isServer(); }
// --------------------------------------------------------------------
STKHost* getHost() { return m_localhost; }
// --------------------------------------------------------------------
std::vector<STKPeer*> getPeers() { return m_peers; }
// --------------------------------------------------------------------
unsigned int getPeerCount() { return (int)m_peers.size(); }

View File

@ -22,39 +22,30 @@
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
/** \brief Constructor
* Sets the basic protocol parameters, as the callback object and the
* protocol type.
* \param callback_object The callback object that will be used by the
* protocol. Protocols that do not use callback objects must set
* it to NULL.
* \param type The type of the protocol.
*/
Protocol::Protocol(CallbackObject* callback_object, ProtocolType type)
{
m_callback_object = callback_object;
m_type = type;
}
m_type = type;
m_state = PROTOCOL_STATE_INITIALISING;
m_id = 0;
} // Protocol
// ----------------------------------------------------------------------------
/** \brief Destructor.
*/
Protocol::~Protocol()
{
}
void Protocol::pause()
{
m_listener->requestPause(this);
}
void Protocol::unpause()
{
m_listener->requestUnpause(this);
}
void Protocol::kill()
{
}
void Protocol::setListener(ProtocolManager* listener)
{
m_listener = listener;
}
ProtocolType Protocol::getProtocolType()
{
return m_type;
}
} // ~Protocol
// ----------------------------------------------------------------------------
bool Protocol::checkDataSizeAndToken(Event* event, int minimum_size)
{
const NetworkString &data = event->data();
@ -74,8 +65,9 @@ bool Protocol::checkDataSizeAndToken(Event* event, int minimum_size)
return false;
}
return true;
}
} // checkDataSizeAndToken
// ----------------------------------------------------------------------------
bool Protocol::isByteCorrect(Event* event, int byte_nb, int value)
{
const NetworkString &data = event->data();
@ -86,15 +78,46 @@ bool Protocol::isByteCorrect(Event* event, int byte_nb, int value)
return false;
}
return true;
}
} // isByteCorrect
void Protocol::sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message)
// ----------------------------------------------------------------------------
/** Starts a request in the protocol manager to start this protocol.
*/
void Protocol::requestStart()
{
ProtocolManager::getInstance()->requestStart(this);
} // requestStart
// ----------------------------------------------------------------------------
/** Submits a request to the ProtocolManager to terminate this protocol.
*/
void Protocol::requestTerminate()
{
ProtocolManager::getInstance()->requestTerminate(this);
} // requestTerminate
// ----------------------------------------------------------------------------
void Protocol::sendMessageToPeersChangingToken(NetworkString prefix,
NetworkString message)
{
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
prefix.ai8(4).ai32(peers[i]->getClientServerToken());
prefix += message;
m_listener->sendMessage(this, peers[i], prefix);
ProtocolManager::getInstance()->sendMessage(this, peers[i], prefix);
}
}
} // sendMessageToPeersChangingToken
// ----------------------------------------------------------------------------
void Protocol::sendMessage(const NetworkString& message, bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, message, reliable);
} // sendMessage
// ----------------------------------------------------------------------------
void Protocol::sendMessage(STKPeer* peer, const NetworkString& message,
bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable);
} // sendMessage

View File

@ -25,105 +25,134 @@
#include "network/network_string.hpp"
#include "network/types.hpp"
#include "utils/no_copy.hpp"
#include "utils/types.hpp"
class Event;
class ProtocolManager;
class STKPeer;
/** \enum ProtocolType
* \brief The types that protocols can have. This is used to select which protocol receives which event.
* \ingroup network
*/
* \brief The types that protocols can have. This is used to select which
* protocol receives which event.
* \ingroup network
*/
enum ProtocolType
{
PROTOCOL_NONE = 0, //!< No protocol type assigned.
PROTOCOL_CONNECTION = 1, //!< Protocol that deals with client-server connection.
PROTOCOL_LOBBY_ROOM = 2, //!< Protocol that is used during the lobby room phase.
PROTOCOL_START_GAME = 3, //!< Protocol used when starting the game.
PROTOCOL_SYNCHRONIZATION = 4,//!<Protocol used to synchronize clocks.
PROTOCOL_KART_UPDATE = 5, //!< Protocol to update karts position, rotation etc...
PROTOCOL_GAME_EVENTS = 6, //!< Protocol to communicate the game events.
PROTOCOL_CONTROLLER_EVENTS = 7,//!< Protocol to transfer controller modifications
PROTOCOL_SILENT = 0xffff //!< Used for protocols that do not subscribe to any network event.
};
PROTOCOL_NONE = 0, //!< No protocol type assigned.
PROTOCOL_CONNECTION = 1, //!< Protocol that deals with client-server connection.
PROTOCOL_LOBBY_ROOM = 2, //!< Protocol that is used during the lobby room phase.
PROTOCOL_START_GAME = 3, //!< Protocol used when starting the game.
PROTOCOL_SYNCHRONIZATION = 4, //!<Protocol used to synchronize clocks.
PROTOCOL_KART_UPDATE = 5, //!< Protocol to update karts position, rotation etc...
PROTOCOL_GAME_EVENTS = 6, //!< Protocol to communicate the game events.
PROTOCOL_CONTROLLER_EVENTS = 7, //!< Protocol to transfer controller modifications
PROTOCOL_SILENT = 0xffff //!< Used for protocols that do not subscribe to any network event.
}; // ProtocolType
/** \class Protocol
* \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.
* \ingroup network
*/
class Protocol
// ----------------------------------------------------------------------------
/** \enum ProtocolState
* \brief Defines the three states that a protocol can have.
*/
enum ProtocolState
{
public:
/*!
* \brief Constructor
*
* Sets the basic protocol parameters, as the callback object and the protocol type.
*
* \param callback_object The callback object that will be used by the protocol. Protocols that do not use callback objects must set it to NULL.
* \param type The type of the protocol.
*/
Protocol(CallbackObject* callback_object, ProtocolType type);
/*! \brief Destructor
*/
virtual ~Protocol();
PROTOCOL_STATE_INITIALISING, //!< The protocol is waiting to be started
PROTOCOL_STATE_RUNNING, //!< The protocol is being updated everytime.
PROTOCOL_STATE_PAUSED, //!< The protocol is paused.
PROTOCOL_STATE_TERMINATED //!< The protocol is terminated/does not exist.
}; // ProtocolState
/*! \brief Notify a protocol matching the Event type of that event.
* \param event : Pointer to the event.
* \return True if the event has been treated, false elseway
*/
virtual bool notifyEvent(Event* event) { return false; }
// ----------------------------------------------------------------------------
/** \class Protocol
* \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.
* \ingroup network
*/
class Protocol : public NoCopy
{
protected:
/** The type of the protocol. */
ProtocolType m_type;
/*! \brief Notify a protocol matching the Event type of that event.
* This update is done asynchronously :
* \param event : Pointer to the event.
* \return True if the event has been treated, false elseway
*/
virtual bool notifyEventAsynchronous(Event* event) { return false; }
/** The callback object, if needed. */
CallbackObject* m_callback_object;
/*! \brief Set the protocol listener.
* \param listener : Pointer to the listener.
*/
void setListener(ProtocolManager* listener);
/** The state this protocol is in (e.g. running, paused, ...). */
ProtocolState m_state;
/*! \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).
* This function must be called by the subclasse's pause function if re-defined.
*/
virtual void pause();
/*! \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, synchronously with the main loop. Must be re-defined.
*/
virtual void update() = 0;
/*! \brief Called by the protocol listener as often as possible. Must be re-defined.
*/
virtual void asynchronousUpdate() = 0;
/*! \brief Called when the protocol is to be killed.
*/
virtual void kill();
/** The unique id of the protocol. */
uint32_t m_id;
/*! \brief Method to get a protocol's type.
* \return The protocol type.
*/
ProtocolType getProtocolType();
public:
/// functions to check incoming data easily
bool checkDataSizeAndToken(Event* event, int minimum_size);
bool isByteCorrect(Event* event, int byte_nb, int value);
void sendMessageToPeersChangingToken(NetworkString prefix, NetworkString message);
Protocol(CallbackObject* callback_object, ProtocolType type);
virtual ~Protocol();
/** \brief Called when the protocol is going to start. Must be re-defined
* by subclasses. */
virtual void setup() = 0;
/** \brief Called by the protocol listener, synchronously with the main
* loop. Must be re-defined.*/
virtual void update() = 0;
/** \brief Called by the protocol listener as often as possible.
* Must be re-defined. */
virtual void asynchronousUpdate() = 0;
/// functions to check incoming data easily
bool checkDataSizeAndToken(Event* event, int minimum_size);
bool isByteCorrect(Event* event, int byte_nb, int value);
void sendMessageToPeersChangingToken(NetworkString prefix,
NetworkString message);
void sendMessage(const NetworkString& message,
bool reliable = true);
void sendMessage(STKPeer* peer, const NetworkString& message,
bool reliable = true);
void requestStart();
void requestTerminate();
// ------------------------------------------------------------------------
/** Returns the current protocol state. */
ProtocolState getState() const { return m_state; }
// ------------------------------------------------------------------------
/** Sets the current protocol state. */
void setState(ProtocolState s) { m_state = s; }
// ------------------------------------------------------------------------
/** Returns the unique protocol ID. */
uint32_t getId() const { return m_id; }
// ------------------------------------------------------------------------
/** Sets the unique protocol id. */
void setId(uint32_t id) { m_id = id; }
// ------------------------------------------------------------------------
/** \brief Notify a protocol matching the Event type of that event.
* \param event : Pointer to the event.
* \return True if the event has been treated, false otherwise. */
virtual bool notifyEvent(Event* event) { return false; }
// ------------------------------------------------------------------------
/** \brief Notify a protocol matching the Event type of that event.
* This update is done asynchronously :
* \param event : Pointer to the event.
* \return True if the event has been treated, false otherwise */
virtual bool notifyEventAsynchronous(Event* event) { return false; }
// ------------------------------------------------------------------------
/** \brief Called when the protocol is paused (by an other entity or by
* itself). */
virtual void pause() { }
// ------------------------------------------------------------------------
/** \brief Called when the protocol is used.
*/
virtual void unpause() { }
// ------------------------------------------------------------------------
/** \brief Called when the protocol is to be killed. */
virtual void kill() {}
// ------------------------------------------------------------------------
/** \brief Method to get a protocol's type.
* \return The protocol type. */
ProtocolType getProtocolType() const { return m_type; }
protected:
ProtocolManager* m_listener; //!< The protocol listener
ProtocolType m_type; //!< The type of the protocol
CallbackObject* m_callback_object; //!< The callback object, if needed
};
}; // class Protocol
#endif // PROTOCOL_HPP

View File

@ -79,7 +79,7 @@ void ProtocolManager::abort()
pthread_mutex_lock(&m_requests_mutex);
pthread_mutex_lock(&m_id_mutex);
for (unsigned int i = 0; i < m_protocols.getData().size() ; i++)
delete m_protocols.getData()[i].m_protocol;
delete m_protocols.getData()[i];
for (unsigned int i = 0; i < m_events_to_process.getData().size() ; i++)
delete m_events_to_process.getData()[i].m_event;
m_protocols.getData().clear();
@ -131,12 +131,12 @@ void ProtocolManager::propagateEvent(Event* event)
m_protocols.lock();
for (unsigned int i = 0; i < m_protocols.getData().size() ; i++)
{
const ProtocolInfo &pi = m_protocols.getData()[i];
const Protocol *p = m_protocols.getData()[i];
// Pass data to protocols even when paused
if (pi.m_protocol->getProtocolType() == searched_protocol ||
if (p->getProtocolType() == searched_protocol ||
event->getType() == EVENT_TYPE_DISCONNECTED)
{
protocols_ids.push_back(pi.m_id);
protocols_ids.push_back(p->getId());
}
} // for i in m_protocols
m_protocols.unlock();
@ -209,18 +209,16 @@ void ProtocolManager::sendMessageExcept(Protocol* sender, STKPeer* peer,
*/
uint32_t ProtocolManager::requestStart(Protocol* protocol)
{
// assign a unique id to the protocol.
protocol->setId(getNextProtocolId());
// create the request
ProtocolRequest req;
req.m_protocol_info.m_protocol = protocol;
req.m_protocol_info.m_state = PROTOCOL_STATE_INITIALISING;
assignProtocolId(&req.m_protocol_info); // assign a unique id to the protocol.
req.m_type = PROTOCOL_REQUEST_START;
ProtocolRequest req(PROTOCOL_REQUEST_START, protocol);
// add it to the request stack
pthread_mutex_lock(&m_requests_mutex);
m_requests.push_back(req);
pthread_mutex_unlock(&m_requests_mutex);
return req.m_protocol_info.m_id;
return req.getProtocol()->getId();
} // requestStart
// ----------------------------------------------------------------------------
@ -234,9 +232,7 @@ void ProtocolManager::requestStop(Protocol* protocol)
if (!protocol)
return;
// create the request
ProtocolRequest req;
req.m_protocol_info.m_protocol = protocol;
req.m_type = PROTOCOL_REQUEST_STOP;
ProtocolRequest req(PROTOCOL_REQUEST_STOP, protocol);
// add it to the request stack
pthread_mutex_lock(&m_requests_mutex);
m_requests.push_back(req);
@ -254,9 +250,7 @@ void ProtocolManager::requestPause(Protocol* protocol)
if (!protocol)
return;
// create the request
ProtocolRequest req;
req.m_protocol_info.m_protocol = protocol;
req.m_type = PROTOCOL_REQUEST_PAUSE;
ProtocolRequest req(PROTOCOL_REQUEST_PAUSE, protocol);
// add it to the request stack
pthread_mutex_lock(&m_requests_mutex);
m_requests.push_back(req);
@ -274,9 +268,7 @@ void ProtocolManager::requestUnpause(Protocol* protocol)
if (!protocol)
return;
// create the request
ProtocolRequest req;
req.m_protocol_info.m_protocol = protocol;
req.m_type = PROTOCOL_REQUEST_UNPAUSE;
ProtocolRequest req(PROTOCOL_REQUEST_UNPAUSE, protocol);;
// add it to the request stack
pthread_mutex_lock(&m_requests_mutex);
m_requests.push_back(req);
@ -294,15 +286,13 @@ void ProtocolManager::requestTerminate(Protocol* protocol)
if (!protocol)
return;
// create the request
ProtocolRequest req;
req.m_protocol_info.m_protocol = protocol;
req.m_type = PROTOCOL_REQUEST_TERMINATE;
ProtocolRequest req(PROTOCOL_REQUEST_TERMINATE, protocol);
// add it to the request stack
pthread_mutex_lock(&m_requests_mutex);
// check that the request does not already exist :
for (unsigned int i = 0; i < m_requests.size(); i++)
{
if (m_requests[i].m_protocol_info.m_protocol == protocol)
if (m_requests[i].m_protocol == protocol)
{
pthread_mutex_unlock(&m_requests_mutex);
return;
@ -317,75 +307,88 @@ void ProtocolManager::requestTerminate(Protocol* protocol)
* Add the protocol info to the m_protocols vector.
* \param protocol : ProtocolInfo to start.
*/
void ProtocolManager::startProtocol(ProtocolInfo &protocol)
void ProtocolManager::startProtocol(Protocol *protocol)
{
assert(protocol.m_state == PROTOCOL_STATE_INITIALISING);
// assert(protocol_info.m_state == PROTOCOL_STATE_INITIALISING);
// add the protocol to the protocol vector so that it's updated
m_protocols.lock();
pthread_mutex_lock(&m_asynchronous_protocols_mutex);
Log::info("ProtocolManager",
"A %s protocol with id=%u has been started. There are %ld protocols running.",
typeid(*protocol.m_protocol).name(), protocol.m_id,
typeid(protocol).name(), protocol->getId(),
m_protocols.getData().size()+1);
m_protocols.getData().push_back(protocol);
// setup the protocol and notify it that it's started
protocol.m_protocol->setListener(this);
protocol.m_protocol->setup();
protocol.m_state = PROTOCOL_STATE_RUNNING;
protocol->setup();
protocol->setState(PROTOCOL_STATE_RUNNING);
m_protocols.unlock();
pthread_mutex_unlock(&m_asynchronous_protocols_mutex);
} // startProtocol
// ----------------------------------------------------------------------------
void ProtocolManager::stopProtocol(ProtocolInfo protocol)
void ProtocolManager::stopProtocol(Protocol *protocol)
{
} // stopProtocol
// ----------------------------------------------------------------------------
void ProtocolManager::pauseProtocol(ProtocolInfo protocol)
void ProtocolManager::pauseProtocol(Protocol *protocol)
{
assert(protocol->getState() == PROTOCOL_STATE_RUNNING);
protocol->setState(PROTOCOL_STATE_PAUSED);
return;
// FIXME ... why so complicated???
#ifdef XX
// FIXME Does this need to be locked?
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
ProtocolInfo &pi = m_protocols.getData()[i];
if (pi.m_protocol == protocol.m_protocol &&
pi.m_state == PROTOCOL_STATE_RUNNING)
//ProtocolInfo *pi = m_protocols.getData()[i];
if (pi->m_protocol == protocol.m_protocol &&
pi->m_state == PROTOCOL_STATE_RUNNING)
{
pi.m_state = PROTOCOL_STATE_PAUSED;
pi.m_protocol->pause();
pi->m_state = PROTOCOL_STATE_PAUSED;
pi->m_protocol->pause();
}
}
#endif
} // pauseProtocol
// ----------------------------------------------------------------------------
void ProtocolManager::unpauseProtocol(ProtocolInfo protocol)
void ProtocolManager::unpauseProtocol(Protocol *protocol)
{
protocol->setState(PROTOCOL_STATE_RUNNING);
protocol->unpause();
//FIXME: why call protocol->unpause() (which would queue a new request and
// then calls this function again) ... and why so complicated??
#ifdef XX
// FIXME Does this need to be locked??
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
ProtocolInfo &p = m_protocols.getData()[i];
if (p.m_protocol == protocol.m_protocol &&
p.m_state == PROTOCOL_STATE_PAUSED)
ProtocolInfo *p = m_protocols.getData()[i];
if (p->m_protocol == protocol.m_protocol &&
p->m_state == PROTOCOL_STATE_PAUSED)
{
p.m_state = PROTOCOL_STATE_RUNNING;
p.m_protocol->unpause();
p->m_state = PROTOCOL_STATE_RUNNING;
p->m_protocol->unpause();
}
}
#endif
} // unpauseProtocol
// ----------------------------------------------------------------------------
void ProtocolManager::protocolTerminated(ProtocolInfo protocol)
void ProtocolManager::protocolTerminated(Protocol *protocol)
{
// Be sure that noone accesses the protocols vector while we erase a protocol
m_protocols.lock();
pthread_mutex_lock(&m_asynchronous_protocols_mutex);
int offset = 0;
std::string protocol_type = typeid(*protocol.m_protocol).name();
std::string protocol_type = typeid(protocol).name();
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i-offset].m_protocol == protocol.m_protocol)
if (m_protocols.getData()[i-offset] == protocol)
{
delete m_protocols.getData()[i].m_protocol;
delete protocol;
m_protocols.getData().erase(m_protocols.getData().begin()+(i-offset),
m_protocols.getData().begin()+(i-offset)+1);
offset++;
@ -407,14 +410,14 @@ bool ProtocolManager::sendEvent(EventProcessingInfo* event, bool synchronous)
int index = 0;
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (event->m_protocols_ids[index] == m_protocols.getData()[i].m_id)
if (event->m_protocols_ids[index] == m_protocols.getData()[i]->getId())
{
bool result = false;
if (synchronous)
result = m_protocols.getData()[i].m_protocol
result = m_protocols.getData()[i]
->notifyEvent(event->m_event);
else
result = m_protocols.getData()[i].m_protocol
result = m_protocols.getData()[i]
->notifyEventAsynchronous(event->m_event);
if (result)
event->m_protocols_ids.pop_back();
@ -465,8 +468,8 @@ void ProtocolManager::update()
m_protocols.lock();
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_state == PROTOCOL_STATE_RUNNING)
m_protocols.getData()[i].m_protocol->update();
if (m_protocols.getData()[i]->getState() == PROTOCOL_STATE_RUNNING)
m_protocols.getData()[i]->update();
}
m_protocols.unlock();
} // update
@ -504,8 +507,8 @@ void ProtocolManager::asynchronousUpdate()
// FIXME: does m_protocols need to be locked???
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_state == PROTOCOL_STATE_RUNNING)
m_protocols.getData()[i].m_protocol->asynchronousUpdate();
if (m_protocols.getData()[i]->getState() == PROTOCOL_STATE_RUNNING)
m_protocols.getData()[i]->asynchronousUpdate();
}
pthread_mutex_unlock(&m_asynchronous_protocols_mutex);
@ -514,22 +517,22 @@ void ProtocolManager::asynchronousUpdate()
pthread_mutex_lock(&m_requests_mutex);
for (unsigned int i = 0; i < m_requests.size(); i++)
{
switch (m_requests[i].m_type)
switch (m_requests[i].getType())
{
case PROTOCOL_REQUEST_START:
startProtocol(m_requests[i].m_protocol_info);
startProtocol(m_requests[i].getProtocol());
break;
case PROTOCOL_REQUEST_STOP:
stopProtocol(m_requests[i].m_protocol_info);
stopProtocol(m_requests[i].getProtocol());
break;
case PROTOCOL_REQUEST_PAUSE:
pauseProtocol(m_requests[i].m_protocol_info);
pauseProtocol(m_requests[i].getProtocol());
break;
case PROTOCOL_REQUEST_UNPAUSE:
unpauseProtocol(m_requests[i].m_protocol_info);
unpauseProtocol(m_requests[i].getProtocol());
break;
case PROTOCOL_REQUEST_TERMINATE:
protocolTerminated(m_requests[i].m_protocol_info);
protocolTerminated(m_requests[i].getProtocol());
break;
}
}
@ -548,14 +551,14 @@ ProtocolState ProtocolManager::getProtocolState(uint32_t id)
// a locked section anyway
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_id == id) // we know a protocol with that id
return m_protocols.getData()[i].m_state;
if (m_protocols.getData()[i]->getId() == id) // we know a protocol with that id
return m_protocols.getData()[i]->getState();
}
// the protocol isn't running right now
for (unsigned int i = 0; i < m_requests.size(); i++)
{
// the protocol is going to be started
if (m_requests[i].m_protocol_info.m_id == id)
if (m_requests[i].m_protocol->getId() == id)
return PROTOCOL_STATE_RUNNING; // we can say it's running
}
return PROTOCOL_STATE_TERMINATED; // else, it's already finished
@ -571,13 +574,13 @@ ProtocolState ProtocolManager::getProtocolState(Protocol* protocol)
// FIXME Does this need to be locked?
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_protocol == protocol) // the protocol is known
return m_protocols.getData()[i].m_state;
if (m_protocols.getData()[i] == protocol) // the protocol is known
return m_protocols.getData()[i]->getState();
}
for (unsigned int i = 0; i < m_requests.size(); i++)
{
// the protocol is going to be started
if (m_requests[i].m_protocol_info.m_protocol == protocol)
if (m_requests[i].m_protocol == protocol)
return PROTOCOL_STATE_RUNNING; // we can say it's running
}
// we don't know this protocol at all, it's finished
@ -594,8 +597,8 @@ uint32_t ProtocolManager::getProtocolID(Protocol* protocol)
// FIXME: Does this need to be locked?
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_protocol == protocol)
return m_protocols.getData()[i].m_id;
if (m_protocols.getData()[i] == protocol)
return m_protocols.getData()[i]->getId();
}
return 0;
} // getProtocolID
@ -610,8 +613,8 @@ Protocol* ProtocolManager::getProtocol(uint32_t id)
// FIXME: does m_protocols need to be locked??
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_id == id)
return m_protocols.getData()[i].m_protocol;
if (m_protocols.getData()[i]->getId() == id)
return m_protocols.getData()[i];
}
return NULL;
} // getProtocol
@ -626,8 +629,8 @@ Protocol* ProtocolManager::getProtocol(ProtocolType type)
// FIXME: Does m_protocols need to be locked?
for (unsigned int i = 0; i < m_protocols.getData().size(); i++)
{
if (m_protocols.getData()[i].m_protocol->getProtocolType() == type)
return m_protocols.getData()[i].m_protocol;
if (m_protocols.getData()[i]->getProtocolType() == type)
return m_protocols.getData()[i];
}
return NULL;
} // getProtocol
@ -657,12 +660,19 @@ int ProtocolManager::exit()
} // exit
// ----------------------------------------------------------------------------
void ProtocolManager::assignProtocolId(ProtocolInfo* protocol_info)
/** \brief Assign an id to a protocol.
* This function will assign m_next_protocol_id as the protocol id.
* This id starts at 0 at the beginning and is increased by 1 each time
* a protocol starts.
* \param protocol_info : The protocol info that needs an id.
*/
uint32_t ProtocolManager::getNextProtocolId()
{
pthread_mutex_lock(&m_id_mutex);
protocol_info->m_id = m_next_protocol_id;
uint32_t id = m_next_protocol_id;
m_next_protocol_id++;
pthread_mutex_unlock(&m_id_mutex);
} // assignProtocolId
return id;
} // getNextProtocolId

View File

@ -37,17 +37,6 @@ class STKPeer;
#define TIME_TO_KEEP_EVENTS 1.0
/** \enum PROTOCOL_STATE
* \brief Defines the three states that a protocol can have.
*/
enum ProtocolState
{
PROTOCOL_STATE_INITIALISING, //!< The protocol is waiting to be started
PROTOCOL_STATE_RUNNING, //!< The protocol is being updated everytime.
PROTOCOL_STATE_PAUSED, //!< The protocol is paused.
PROTOCOL_STATE_TERMINATED //!< The protocol is terminated/does not exist.
}; // ProtocolState
// ----------------------------------------------------------------------------
/** \enum ProtocolRequestType
* \brief Defines actions that can be done about protocols.
@ -63,29 +52,32 @@ enum ProtocolRequestType
PROTOCOL_REQUEST_TERMINATE //!< Terminate a protocol
}; // ProtocolRequestType
// ----------------------------------------------------------------------------
/** \struct ProtocolInfo
* \brief Stores the information needed to manage protocols
*/
typedef struct ProtocolInfo
{
ProtocolState m_state; //!< The state of the protocol
Protocol* m_protocol; //!< A pointer to the protocol
uint32_t m_id; //!< The unique id of the protocol
} ProtocolInfo;
// ----------------------------------------------------------------------------
/** \struct ProtocolRequest
* \brief Represents a request to do an action about a protocol.
*/
typedef struct ProtocolRequest
class ProtocolRequest
{
public:
/** The type of request. */
ProtocolRequestType m_type;
/** The concerned protocol information. */
ProtocolInfo m_protocol_info;
} ProtocolRequest;
Protocol *m_protocol;
public:
ProtocolRequest(ProtocolRequestType type, Protocol *protocol)
{
m_type = type;
m_protocol = protocol;
} // ProtocolRequest
// ------------------------------------------------------------------------
/** Returns the request type. */
ProtocolRequestType getType() const { return m_type; }
// ------------------------------------------------------------------------
/** Returns the protocol for this request. */
Protocol *getProtocol() { return m_protocol; }
}; // class ProtocolRequest;
// ----------------------------------------------------------------------------
/** \struct ProtocolRequest
@ -153,40 +145,33 @@ class ProtocolManager : public AbstractSingleton<ProtocolManager>,
* \brief Destructor
*/
virtual ~ProtocolManager();
/*!
* \brief Assign an id to a protocol.
* This function will assign m_next_protocol_id as the protocol id.
* This id starts at 0 at the beginning and is increased by 1 each time
* a protocol starts.
* \param protocol_info : The protocol info that needs an id.
*/
void assignProtocolId(ProtocolInfo* protocol_info);
uint32_t getNextProtocolId();
virtual void startProtocol(ProtocolInfo &protocol);
virtual void startProtocol(Protocol *protocol);
/*!
* \brief Stops a protocol.
* Coes nothing. Noone can stop running protocols for now.
* \param protocol : ProtocolInfo to stop.
* \param protocol : Protocol to stop.
*/
virtual void stopProtocol(ProtocolInfo protocol);
virtual void stopProtocol(Protocol *protocol);
/*!
* \brief Pauses a protocol.
* Pauses a protocol and tells it that it's being paused.
* \param protocol : ProtocolInfo to pause.
* \param protocol : Protocol to pause.
*/
virtual void pauseProtocol(ProtocolInfo protocol);
virtual void pauseProtocol(Protocol *protocol);
/*!
* \brief Unpauses a protocol.
* Unpauses a protocol and notifies it.
* \param protocol : ProtocolInfo to unpause.
* \param protocol : Protocol to unpause.
*/
virtual void unpauseProtocol(ProtocolInfo protocol);
virtual void unpauseProtocol(Protocol *protocol);
/*!
* \brief Notes that a protocol is terminated.
* Remove a protocol from the protocols vector.
* \param protocol : ProtocolInfo concerned.
* \param protocol : Protocol concerned.
*/
virtual void protocolTerminated(ProtocolInfo protocol);
virtual void protocolTerminated(Protocol *protocol);
bool sendEvent(EventProcessingInfo* event, bool synchronous);
@ -194,7 +179,7 @@ class ProtocolManager : public AbstractSingleton<ProtocolManager>,
/** Contains the running protocols.
* This stores the protocols that are either running or paused, their
* state and their unique id. */
Synchronised<std::vector<ProtocolInfo> >m_protocols;
Synchronised<std::vector<Protocol*> >m_protocols;
/** Contains the network events to pass to protocols. */
Synchronised<std::vector<EventProcessingInfo> > m_events_to_process;

View File

@ -58,7 +58,7 @@ void ClientLobbyRoomProtocol::requestKartSelection(std::string kart_name)
NetworkString request(6+1+kart_name.size());
// 0x02 : kart selection request, size_token (4), token, size kart name, kart name
request.ai8(0x02).ai8(4).ai32(m_server->getClientServerToken()).add(kart_name);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // requestKartSelection
//-----------------------------------------------------------------------------
@ -68,7 +68,7 @@ void ClientLobbyRoomProtocol::voteMajor(uint8_t major)
NetworkString request(8);
// 0xc0 : major vote, size_token (4), token, size major(1),major
request.ai8(0xc0).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(major);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteMajor
//-----------------------------------------------------------------------------
@ -78,7 +78,7 @@ void ClientLobbyRoomProtocol::voteRaceCount(uint8_t count)
NetworkString request(8);
// 0xc0 : race count vote, size_token (4), token, size race count(1), count
request.ai8(0xc1).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(count);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteRaceCount
//-----------------------------------------------------------------------------
@ -88,7 +88,7 @@ void ClientLobbyRoomProtocol::voteMinor(uint8_t minor)
NetworkString request(8);
// 0xc0 : minor vote, size_token (4), token, size minor(1),minor
request.ai8(0xc2).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(minor);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteMinor
//-----------------------------------------------------------------------------
@ -98,7 +98,7 @@ void ClientLobbyRoomProtocol::voteTrack(std::string track, uint8_t track_nb)
NetworkString request(8+1+track.size());
// 0xc0 : major vote, size_token (4), token, size track, track, size #track, #track
request.ai8(0xc3).ai8(4).ai32(m_server->getClientServerToken()).add(track).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteTrack
//-----------------------------------------------------------------------------
@ -108,7 +108,7 @@ void ClientLobbyRoomProtocol::voteReversed(bool reversed, uint8_t track_nb)
NetworkString request(9);
// 0xc0 : major vote, size_token (4), token, size reversed(1),reversed, size #track, #track
request.ai8(0xc4).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(reversed).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteReversed
//-----------------------------------------------------------------------------
@ -118,7 +118,7 @@ void ClientLobbyRoomProtocol::voteLaps(uint8_t laps, uint8_t track_nb)
NetworkString request(10);
// 0xc0 : major vote, size_token (4), token, size laps(1),laps, size #track, #track
request.ai8(0xc5).ai8(4).ai32(m_server->getClientServerToken()).ai8(1).ai8(laps).ai8(1).ai8(track_nb);
m_listener->sendMessage(this, request, true);
sendMessage(request, true);
} // voteLaps
//-----------------------------------------------------------------------------
@ -209,7 +209,7 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
NetworkManager::getInstance()->removePeer(m_server);
m_server = NULL;
NetworkManager::getInstance()->disconnected();
m_listener->requestTerminate(this);
ProtocolManager::getInstance()->requestTerminate(this);
NetworkManager::getInstance()->reset();
// probably the same as m_server
NetworkManager::getInstance()->removePeer(event->getPeer());
@ -235,7 +235,7 @@ void ClientLobbyRoomProtocol::update()
NetworkString ns(6);
// 1 (connection request), 4 (size of id), global id
ns.ai8(1).ai8(4).ai32(PlayerManager::getCurrentOnlineId());
m_listener->sendMessage(this, ns);
sendMessage(ns);
m_state = REQUESTING_CONNECTION;
}
break;
@ -265,7 +265,7 @@ void ClientLobbyRoomProtocol::update()
break;
case DONE:
m_state = EXITING;
m_listener->requestTerminate(this);
ProtocolManager::getInstance()->requestTerminate(this);
break;
case EXITING:
break;
@ -546,7 +546,7 @@ void ClientLobbyRoomProtocol::startGame(Event* event)
if (token == NetworkManager::getInstance()->getPeers()[0]->getClientServerToken())
{
m_state = PLAYING;
m_listener->requestStart(new StartGameProtocol(m_setup));
ProtocolManager::getInstance()->requestStart(new StartGameProtocol(m_setup));
Log::error("ClientLobbyRoomProtocol", "Starting new game");
}
else
@ -616,21 +616,21 @@ void ClientLobbyRoomProtocol::raceFinished(Event* event)
// stop race protocols
Protocol* protocol = NULL;
protocol = m_listener->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
ProtocolManager::getInstance()->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No controller events protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_KART_UPDATE);
protocol = ProtocolManager::getInstance() ->getProtocol(PROTOCOL_KART_UPDATE);
if (protocol)
m_listener->requestTerminate(protocol);
ProtocolManager::getInstance()->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No kart update protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_GAME_EVENTS);
protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
ProtocolManager::getInstance()->requestTerminate(protocol);
else
Log::error("ClientLobbyRoomProtocol", "No game events protocol registered.");

View File

@ -19,7 +19,6 @@ class ClientLobbyRoomProtocol : public LobbyRoomProtocol
void voteTrack(std::string track, uint8_t track_nb = 0);
void voteReversed(bool reversed, uint8_t track_nb = 0);
void voteLaps(uint8_t laps, uint8_t track_nb = 0);
void sendMessage(std::string message);
void leave();
virtual bool notifyEvent(Event* event);

View File

@ -31,18 +31,18 @@
// ----------------------------------------------------------------------------
ConnectToPeer::ConnectToPeer(uint32_t peer_id) :
Protocol(NULL, PROTOCOL_CONNECTION)
ConnectToPeer::ConnectToPeer(uint32_t peer_id)
: Protocol(NULL, PROTOCOL_CONNECTION)
{
m_peer_id = peer_id;
m_state = NONE;
}
} // ConnectToPeer
// ----------------------------------------------------------------------------
ConnectToPeer::~ConnectToPeer()
{
}
} // ~ConnectToPeer
// ----------------------------------------------------------------------------
@ -54,17 +54,17 @@ bool ConnectToPeer::notifyEventAsynchronous(Event* event)
m_state = CONNECTED; // we received a message, we are connected
}
return true;
}
} // notifyEventAsynchronous
// ----------------------------------------------------------------------------
void ConnectToPeer::setup()
{
m_state = NONE;
m_public_address.clear();
m_peer_address.clear();
m_current_protocol_id = 0;
}
m_current_protocol = NULL;
m_state = NONE;
} // setup
// ----------------------------------------------------------------------------
@ -74,13 +74,14 @@ void ConnectToPeer::asynchronousUpdate()
{
case NONE:
{
m_current_protocol_id = m_listener->requestStart(new GetPeerAddress(m_peer_id, &m_peer_address));
m_current_protocol = new GetPeerAddress(m_peer_id, &m_peer_address);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
m_state = WAITING_PEER_ADDRESS;
break;
}
case WAITING_PEER_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we know the peer address
// Wait till we know the peer address
if (m_current_protocol->getState()== PROTOCOL_STATE_TERMINATED)
{
if (m_peer_address.getIP() != 0 && m_peer_address.getPort() != 0)
{
@ -88,22 +89,22 @@ void ConnectToPeer::asynchronousUpdate()
if (m_peer_address.getIP() == NetworkManager::getInstance()->getPublicAddress().getIP())
{
// just send a broadcast packet with the string aloha_stk inside, the client will know our ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost();
TransportAddress broadcast_address;
broadcast_address.setIP(-1); // 255.255.255.255
broadcast_address.setPort(m_peer_address.getPort()); // 0b10101100000101101101111111111111; // for test
char data[] = "aloha_stk\0";
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
STKHost::get()->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha sent.");
StkTime::sleep(1);
broadcast_address.setIP(0x7f000001); // 127.0.0.1 (localhost)
broadcast_address.setPort(m_peer_address.getPort());
host->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
STKHost::get()->sendRawPacket((uint8_t*)(data), 10, broadcast_address);
Log::info("ConnectToPeer", "Broadcast aloha to self.");
}
else
{
m_current_protocol_id = m_listener->requestStart(new PingProtocol(m_peer_address, 2.0));
m_current_protocol = new PingProtocol(m_peer_address, 2.0);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
}
m_state = CONNECTING;
}
@ -120,18 +121,22 @@ void ConnectToPeer::asynchronousUpdate()
{
// the ping protocol is there for NAT traversal (disabled when connecting to LAN peer)
if (m_peer_address != NetworkManager::getInstance()->getPublicAddress())
m_listener->requestTerminate( m_listener->getProtocol(m_current_protocol_id)); // kill the ping protocol because we're connected
{
// Kill the ping protocol because we're connected
ProtocolManager::getInstance()
->requestTerminate(m_current_protocol);
}
m_state = DONE;
break;
}
case DONE:
m_state = EXITING;
m_listener->requestTerminate(this);
ProtocolManager::getInstance()->requestTerminate(this);
break;
case EXITING:
break;
}
}
} // asynchronousUpdate
// ----------------------------------------------------------------------------

View File

@ -38,7 +38,9 @@ class ConnectToPeer : public Protocol, public CallbackObject
TransportAddress m_peer_address;
TransportAddress m_public_address;
uint32_t m_peer_id;
uint32_t m_current_protocol_id;
/** Pointer to the protocol which is monitored for state changes. */
Protocol *m_current_protocol;
enum STATE
{

View File

@ -86,9 +86,9 @@ bool ConnectToServer::notifyEventAsynchronous(Event* event)
void ConnectToServer::setup()
{
Log::info("ConnectToServer", "SETUP");
m_state = NONE;
m_server_address.clear();
m_current_protocol_id = 0;
m_state = NONE;
m_current_protocol = NULL;
} // setup
// ----------------------------------------------------------------------------
@ -99,46 +99,45 @@ void ConnectToServer::asynchronousUpdate()
case NONE:
{
Log::info("ConnectToServer", "Protocol starting");
m_current_protocol_id =
m_listener->requestStart(new GetPublicAddress());
m_current_protocol = new GetPublicAddress();
ProtocolManager::getInstance()->requestStart(m_current_protocol);
m_state = GETTING_SELF_ADDRESS;
break;
}
case GETTING_SELF_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id) ==
PROTOCOL_STATE_TERMINATED) // now we know the public addr
// Wait till we know the public address
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
m_state = SHOWING_SELF_ADDRESS;
m_current_protocol_id =
m_listener->requestStart(new ShowPublicAddress());
m_current_protocol = new ShowPublicAddress();
ProtocolManager::getInstance()->requestStart(m_current_protocol);
Log::info("ConnectToServer", "Public address known");
}
break;
case SHOWING_SELF_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id) ==
PROTOCOL_STATE_TERMINATED)
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
// now our public address is in the database
Log::info("ConnectToServer", "Public address shown");
if (m_quick_join)
{
m_current_protocol_id = m_listener->requestStart(
new QuickJoinProtocol(&m_server_address,
&m_server_id) );
m_current_protocol = new QuickJoinProtocol(&m_server_address,
&m_server_id);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
m_state = REQUESTING_CONNECTION;
}
else
{
m_current_protocol_id = m_listener->requestStart(
new GetPeerAddress(m_host_id,
&m_server_address) );
m_current_protocol = new GetPeerAddress(m_host_id,
&m_server_address);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
m_state = GETTING_SERVER_ADDRESS;
}
}
break;
case GETTING_SERVER_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id) ==
PROTOCOL_STATE_TERMINATED) // we know the server address
// Wait till we know the server address
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
Log::info("ConnectToServer", "Server's address known");
// we're in the same lan (same public ip address) !!
@ -149,14 +148,12 @@ void ConnectToServer::asynchronousUpdate()
"Server appears to be in the same LAN.");
}
m_state = REQUESTING_CONNECTION;
m_current_protocol_id =
m_listener->requestStart(
new RequestConnection(m_server_id));
m_current_protocol = new RequestConnection(m_server_id);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
}
break;
case REQUESTING_CONNECTION:
if (m_listener->getProtocolState(m_current_protocol_id) ==
PROTOCOL_STATE_TERMINATED)
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
// Server knows we want to connect
Log::info("ConnectToServer", "Connection request made");
@ -167,8 +164,8 @@ void ConnectToServer::asynchronousUpdate()
m_state = HIDING_ADDRESS;
Log::error("ConnectToServer", "Server address is %s",
m_server_address.toString().c_str());
m_current_protocol_id =
m_listener->requestStart(new HidePublicAddress());
m_current_protocol = new HidePublicAddress();
ProtocolManager::getInstance()->requestStart(m_current_protocol);
return;
}
if (m_server_address.getIP() == NetworkManager::getInstance()
@ -180,8 +177,8 @@ void ConnectToServer::asynchronousUpdate()
else
{
m_state = CONNECTING;
m_current_protocol_id = m_listener->requestStart(
new PingProtocol(m_server_address, 2.0));
m_current_protocol = new PingProtocol(m_server_address, 2.0);
ProtocolManager::getInstance()->requestStart(m_current_protocol);
}
}
break;
@ -201,30 +198,29 @@ void ConnectToServer::asynchronousUpdate()
{
Log::info("ConnectToServer", "Connected");
// Kill the ping protocol because we're connected
m_listener->requestTerminate(
m_listener->getProtocol(m_current_protocol_id));
m_current_protocol_id =
m_listener->requestStart(new HidePublicAddress());
ProtocolManager::getInstance()->requestTerminate(m_current_protocol);
m_current_protocol = new HidePublicAddress();
ProtocolManager::getInstance()->requestStart(m_current_protocol);
ClientNetworkManager::getInstance()->setConnected(true);
m_state = HIDING_ADDRESS;
break;
}
case HIDING_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id)
== PROTOCOL_STATE_TERMINATED) // we have hidden our address
// Wait till we have hidden our address
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
Log::info("ConnectToServer", "Address hidden");
m_state = DONE;
// lobby room protocol if we're connected only
if (ClientNetworkManager::getInstance()->isConnected())
{
m_listener->requestStart(
ProtocolManager::getInstance()->requestStart(
new ClientLobbyRoomProtocol(m_server_address));
}
}
break;
case DONE:
m_listener->requestTerminate(this);
ProtocolManager::getInstance()->requestTerminate(this);
m_state = EXITING;
break;
case EXITING:
@ -240,7 +236,7 @@ void ConnectToServer::handleSameLAN()
{
// just send a broadcast packet, the client will know our
// ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost();
STKHost* host = STKHost::get();
host->stopListening(); // stop the listening
TransportAddress broadcast_address;

View File

@ -30,7 +30,9 @@ private:
TransportAddress m_server_address;
uint32_t m_server_id;
uint32_t m_host_id;
uint32_t m_current_protocol_id;
/** Protocol currently being monitored. */
Protocol *m_current_protocol;
bool m_quick_join;
enum State

View File

@ -37,7 +37,7 @@ void ControllerEventsProtocol::setup()
m_self_controller_index = i;
}
STKPeer* peer = NULL;
if (m_listener->isServer())
if (ProtocolManager::getInstance()->isServer())
{
for (unsigned int j = 0; j < peers.size(); j++)
{
@ -114,7 +114,7 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
Log::warn("ControllerEventProtocol", "Couldn't have a client id.");
return true;
}
if (m_listener->isServer())
if (ProtocolManager::getInstance()->isServer())
{
// notify everybody of the event :
for (unsigned int i = 0; i < m_controllers.size(); i++)
@ -124,12 +124,13 @@ bool ControllerEventsProtocol::notifyEventAsynchronous(Event* event)
NetworkString ns2(4+pure_message.size());
ns2.ai32(m_controllers[i].second->getClientServerToken());
ns2 += pure_message;
m_listener->sendMessage(this, m_controllers[i].second, ns2, false);
ProtocolManager::getInstance()
->sendMessage(this, m_controllers[i].second, ns2, false);
//Log::info("ControllerEventsProtocol", "Sizes are %d and %d", ns2.size(), pure_message.size());
}
}
return true;
}
} // notifyEventAsynchronous
//-----------------------------------------------------------------------------
@ -140,9 +141,9 @@ void ControllerEventsProtocol::update()
//-----------------------------------------------------------------------------
void ControllerEventsProtocol::controllerAction(Controller* controller,
PlayerAction action, int value)
PlayerAction action, int value)
{
assert(!m_listener->isServer());
assert(!ProtocolManager::getInstance()->isServer());
KartControl* controls = controller->getControls();
uint8_t serialized_1 = 0;
@ -168,7 +169,7 @@ void ControllerEventsProtocol::controllerAction(Controller* controller,
ns.ai8((uint8_t)(action)).ai32(value);
Log::info("ControllerEventsProtocol", "Action %d value %d", action, value);
m_listener->sendMessage(this, ns, false); // send message to server
sendMessage(ns, false); // send message to server
}

View File

@ -92,7 +92,7 @@ void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
powerup = (((int)(kart->getPowerup()->getType()) << 4)&0xf0) + (kart->getPowerup()->getNum()&0x0f);
ns.ai8(0x01).ai32(item->getItemId()).ai8(powerup).ai8(player_profile->race_id); // send item,
m_listener->sendMessage(this, peers[i], ns, true); // reliable
ProtocolManager::getInstance()->sendMessage(this, peers[i], ns, true); // reliable
Log::info("GameEventsProtocol", "Notified a peer that a kart collected item %d.", (int)(kart->getPowerup()->getType()));
}
}

View File

@ -91,7 +91,7 @@ void GetPeerAddress::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
}

View File

@ -85,8 +85,7 @@ void GetPublicAddress::createStunRequest()
assert(res != NULL);
struct sockaddr_in* current_interface = (struct sockaddr_in*)(res->ai_addr);
m_stun_server_ip = ntohl(current_interface->sin_addr.s_addr);
m_transaction_host = new STKHost();
m_transaction_host->setupClient(1, 1, 0, 0);
m_transaction_host = new Network(1, 1, 0, 0);
// Assemble the message for the stun server
NetworkString s(21);
@ -194,7 +193,7 @@ std::string GetPublicAddress::parseStunResponse()
// The address and the port are known, so the connection can be closed
m_state = EXITING;
m_listener->requestTerminate(this);
requestTerminate();
return "";
} // parseStunResponse

View File

@ -23,7 +23,7 @@
#include <string>
class STKHost;
class Network;
class GetPublicAddress : public Protocol
{
@ -54,7 +54,7 @@ class GetPublicAddress : public Protocol
STATE m_state;
uint8_t m_stun_tansaction_id[12];
uint32_t m_stun_server_ip;
STKHost* m_transaction_host;
Network* m_transaction_host;
};
#endif // GET_PUBLIC_ADDRESS_HPP

View File

@ -74,6 +74,6 @@ void HidePublicAddress::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
}

View File

@ -77,7 +77,7 @@ void KartUpdateProtocol::update()
if (current_time > time + 0.1) // 10 updates per second
{
time = current_time;
if (m_listener->isServer())
if (ProtocolManager::getInstance()->isServer())
{
NetworkString ns(4+m_karts.size()*32);
ns.af( World::getWorld()->getTime());
@ -89,9 +89,11 @@ void KartUpdateProtocol::update()
ns.ai32( kart->getWorldKartId());
ns.af(v[0]).af(v[1]).af(v[2]); // add position
ns.af(quat.x()).af(quat.y()).af(quat.z()).af(quat.w()); // add rotation
Log::verbose("KartUpdateProtocol", "Sending %d's positions %f %f %f", kart->getWorldKartId(), v[0], v[1], v[2]);
Log::verbose("KartUpdateProtocol",
"Sending %d's positions %f %f %f",
kart->getWorldKartId(), v[0], v[1], v[2]);
}
m_listener->sendMessage(this, ns, false);
sendMessage(ns, false);
}
else
{
@ -103,8 +105,10 @@ void KartUpdateProtocol::update()
ns.ai32( kart->getWorldKartId());
ns.af(v[0]).af(v[1]).af(v[2]); // add position
ns.af(quat.x()).af(quat.y()).af(quat.z()).af(quat.w()); // add rotation
Log::verbose("KartUpdateProtocol", "Sending %d's positions %f %f %f", kart->getWorldKartId(), v[0], v[1], v[2]);
m_listener->sendMessage(this, ns, false);
Log::verbose("KartUpdateProtocol",
"Sending %d's positions %f %f %f",
kart->getWorldKartId(), v[0], v[1], v[2]);
sendMessage(ns, false);
}
}
switch(pthread_mutex_trylock(&m_positions_updates_mutex))
@ -113,7 +117,8 @@ void KartUpdateProtocol::update()
while (!m_next_positions.empty())
{
uint32_t id = m_karts_ids.back();
if (id != m_self_kart_index || m_listener->isServer()) // server takes all updates
if (id != m_self_kart_index ||
ProtocolManager::getInstance()->isServer()) // server takes all updates
{
Vec3 pos = m_next_positions.back();
btTransform transform = m_karts[id]->getBody()->getInterpolationWorldTransform();

View File

@ -43,7 +43,7 @@ void PingProtocol::asynchronousUpdate()
{
m_last_ping_time = StkTime::getRealTime();
uint8_t data = 0;
NetworkManager::getInstance()->getHost()->sendRawPacket(&data, 1, m_ping_dst);
STKHost::get()->sendRawPacket(&data, 1, m_ping_dst);
Log::info("PingProtocol", "Ping message sent");
}
}

View File

@ -85,6 +85,6 @@ void QuickJoinProtocol::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
}

View File

@ -113,7 +113,7 @@ void RequestConnection::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
break;
case EXITING:
break;

View File

@ -22,13 +22,14 @@
#include "config/user_config.hpp"
#include "modes/world.hpp"
#include "network/event.hpp"
#include "network/network_manager.hpp"
#include "network/network_world.hpp"
#include "network/protocols/get_public_address.hpp"
#include "network/protocols/show_public_address.hpp"
#include "network/protocols/connect_to_peer.hpp"
#include "network/protocols/start_server.hpp"
#include "network/protocols/start_game_protocol.hpp"
#include "network/server_network_manager.hpp"
#include "network/server_console.hpp"
#include "online/online_profile.hpp"
#include "online/request_manager.hpp"
#include "utils/log.hpp"
@ -106,19 +107,21 @@ void ServerLobbyRoomProtocol::update()
switch (m_state)
{
case NONE:
m_current_protocol_id = m_listener->requestStart(new GetPublicAddress());
m_current_protocol = new GetPublicAddress();
m_current_protocol->requestStart();
m_state = GETTING_PUBLIC_ADDRESS;
break;
case GETTING_PUBLIC_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id) == PROTOCOL_STATE_TERMINATED)
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
m_current_protocol_id = m_listener->requestStart(new StartServer());
m_current_protocol = new StartServer();
m_current_protocol->requestStart();
m_state = LAUNCHING_SERVER;
Log::debug("ServerLobbyRoomProtocol", "Public address known.");
}
break;
case LAUNCHING_SERVER:
if (m_listener->getProtocolState(m_current_protocol_id) == PROTOCOL_STATE_TERMINATED)
if (m_current_protocol->getState() == PROTOCOL_STATE_TERMINATED)
{
m_state = WORKING;
Log::info("ServerLobbyRoomProtocol", "Server setup");
@ -127,14 +130,17 @@ void ServerLobbyRoomProtocol::update()
case WORKING:
{
checkIncomingConnectionRequests();
if (m_in_race && World::getWorld() && NetworkWorld::getInstance<NetworkWorld>()->isRunning())
if (m_in_race && World::getWorld() &&
NetworkWorld::getInstance<NetworkWorld>()->isRunning())
{
checkRaceFinished();
}
break;
}
case DONE:
m_state = EXITING;
m_listener->requestTerminate(this);
requestTerminate();
break;
case EXITING:
break;
@ -150,11 +156,12 @@ void ServerLobbyRoomProtocol::startGame()
{
NetworkString ns(6);
ns.ai8(0x04).ai8(4).ai32(peers[i]->getClientServerToken()); // start game
m_listener->sendMessage(this, peers[i], ns, true); // reliably
sendMessage(peers[i], ns, true); // reliably
}
m_listener->requestStart(new StartGameProtocol(m_setup));
Protocol *p = new StartGameProtocol(m_setup);
p->requestStart();
m_in_race = true;
}
} // startGame
//-----------------------------------------------------------------------------
@ -165,10 +172,10 @@ void ServerLobbyRoomProtocol::startSelection()
{
NetworkString ns(6);
ns.ai8(0x05).ai8(4).ai32(peers[i]->getClientServerToken()); // start selection
m_listener->sendMessage(this, peers[i], ns, true); // reliably
sendMessage(peers[i], ns, true); // reliably
}
m_selection_enabled = true;
}
} // startSelection
//-----------------------------------------------------------------------------
@ -220,10 +227,11 @@ void ServerLobbyRoomProtocol::checkIncomingConnectionRequests()
// now
for (unsigned int i = 0; i < m_incoming_peers_ids.size(); i++)
{
m_listener->requestStart(new ConnectToPeer(m_incoming_peers_ids[i]));
Protocol *p = new ConnectToPeer(m_incoming_peers_ids[i]);
p->requestStart();
}
m_incoming_peers_ids.clear();
}
} // checkIncomingConnectionRequests
//-----------------------------------------------------------------------------
@ -265,28 +273,28 @@ void ServerLobbyRoomProtocol::checkRaceFinished()
NetworkString ns(6);
ns.ai8(0x06).ai8(4).ai32(peers[i]->getClientServerToken());
NetworkString total = ns + queue;
m_listener->sendMessage(this, peers[i], total, true);
sendMessage(peers[i], total, true);
}
Log::info("ServerLobbyRoomProtocol", "End of game message sent");
m_in_race = false;
// stop race protocols
Protocol* protocol = NULL;
protocol = m_listener->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_CONTROLLER_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
protocol->requestTerminate();
else
Log::error("ClientLobbyRoomProtocol", "No controller events protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_KART_UPDATE);
protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_KART_UPDATE);
if (protocol)
m_listener->requestTerminate(protocol);
protocol->requestTerminate();
else
Log::error("ClientLobbyRoomProtocol", "No kart update protocol registered.");
protocol = m_listener->getProtocol(PROTOCOL_GAME_EVENTS);
protocol = ProtocolManager::getInstance()->getProtocol(PROTOCOL_GAME_EVENTS);
if (protocol)
m_listener->requestTerminate(protocol);
protocol->requestTerminate();
else
Log::error("ClientLobbyRoomProtocol", "No game events protocol registered.");
@ -300,7 +308,7 @@ void ServerLobbyRoomProtocol::checkRaceFinished()
{
//Log::info("ServerLobbyRoomProtocol", "Phase is %d", World::getWorld()->getPhase());
}
}
} // checkRaceFinished
//-----------------------------------------------------------------------------
@ -311,7 +319,7 @@ void ServerLobbyRoomProtocol::kartDisconnected(Event* event)
{
NetworkString msg(3);
msg.ai8(0x02).ai8(1).ai8(peer->getPlayerProfile()->race_id);
m_listener->sendMessage(this, msg);
sendMessage(msg);
Log::info("ServerLobbyRoomProtocol", "Player disconnected : id %d",
peer->getPlayerProfile()->race_id);
m_setup->removePlayer(peer->getPlayerProfile()->race_id);
@ -345,8 +353,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
uint32_t player_id = 0;
player_id = data.getUInt32(1);
// can we add the player ?
if (m_setup->getPlayerCount() <
ServerNetworkManager::getInstance()->getMaxPlayers()) //accept
if (m_setup->getPlayerCount() < STKHost::getMaxPlayers()) //accept
{
// add the player to the game setup
m_next_id = m_setup->getPlayerCount();
@ -354,7 +361,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
NetworkString message(8);
// 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, peer, message);
ProtocolManager::getInstance()->sendMessageExcept(this, peer, message);
/// now answer to the peer that just connected
RandomGenerator token_generator;
@ -377,7 +384,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
if (players[i]->race_id != m_next_id && players[i]->user_profile->getID() != player_id)
message_ack.ai8(1).ai8(players[i]->race_id).ai8(4).ai32(players[i]->user_profile->getID());
}
m_listener->sendMessage(this, peer, message_ack);
sendMessage(peer, message_ack);
peer->setClientServerToken(token);
@ -396,7 +403,7 @@ void ServerLobbyRoomProtocol::connectionRequested(Event* event)
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, peer, message);
sendMessage(peer, message);
Log::verbose("ServerLobbyRoomProtocol", "Player refused");
}
}
@ -433,7 +440,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
{
NetworkString answer(3);
answer.ai8(0x82).ai8(1).ai8(2); // selection still not started
m_listener->sendMessage(this, peer, answer);
sendMessage(peer, answer);
return;
}
// check if somebody picked that kart
@ -441,7 +448,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
{
NetworkString answer(3);
answer.ai8(0x82).ai8(1).ai8(0); // kart is already taken
m_listener->sendMessage(this, peer, answer);
sendMessage(peer, answer);
return;
}
// check if this kart is authorized
@ -449,7 +456,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
{
NetworkString answer(3);
answer.ai8(0x82).ai8(1).ai8(1); // kart is not authorized
m_listener->sendMessage(this, peer, answer);
sendMessage(peer, answer);
return;
}
// send a kart update to everyone
@ -458,7 +465,7 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
answer.ai8(0x03).ai8(1).ai8(peer->getPlayerProfile()->race_id);
// kart name size, kart name
answer.add(kart_name);
m_listener->sendMessage(this, answer);
sendMessage(answer);
m_setup->setPlayerKart(peer->getPlayerProfile()->race_id, kart_name);
}

View File

@ -5,7 +5,38 @@
class ServerLobbyRoomProtocol : public LobbyRoomProtocol
{
public:
private:
uint8_t m_next_id; //!< Next id to assign to a peer.
std::vector<uint32_t> m_incoming_peers_ids;
Protocol *m_current_protocol;
bool m_selection_enabled;
bool m_in_race;
// connection management
void kartDisconnected(Event* event);
void connectionRequested(Event* event);
// kart selection
void kartSelectionRequested(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
enum STATE
{
NONE,
GETTING_PUBLIC_ADDRESS,
LAUNCHING_SERVER,
WORKING,
DONE,
EXITING
};
STATE m_state; public:
ServerLobbyRoomProtocol();
virtual ~ServerLobbyRoomProtocol();
@ -19,35 +50,6 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
void checkIncomingConnectionRequests();
void checkRaceFinished();
protected:
// connection management
void kartDisconnected(Event* event);
void connectionRequested(Event* event);
// kart selection
void kartSelectionRequested(Event* event);
// race votes
void playerMajorVote(Event* event);
void playerRaceCountVote(Event* event);
void playerMinorVote(Event* event);
void playerTrackVote(Event* event);
void playerReversedVote(Event* event);
void playerLapsVote(Event* event);
uint8_t m_next_id; //!< Next id to assign to a peer.
std::vector<uint32_t> m_incoming_peers_ids;
uint32_t m_current_protocol_id;
bool m_selection_enabled;
bool m_in_race;
enum STATE
{
NONE,
GETTING_PUBLIC_ADDRESS,
LAUNCHING_SERVER,
WORKING,
DONE,
EXITING
};
STATE m_state;
};
#endif // SERVER_LOBBY_ROOM_PROTOCOL_HPP

View File

@ -47,7 +47,7 @@ void ShowPublicAddress::asynchronousUpdate()
m_request->addParameter("address", addr.getIP());
m_request->addParameter("port", addr.getPort());
m_request->addParameter("private_port", NetworkManager::getInstance()->getHost()->getPort());
m_request->addParameter("private_port", STKHost::get()->getPort());
Log::info("ShowPublicAddress", "Showing addr %s", addr.toString().c_str());
@ -81,6 +81,6 @@ void ShowPublicAddress::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
}
} // asynchronousUpdate

View File

@ -51,7 +51,7 @@ bool StartGameProtocol::notifyEventAsynchronous(Event* event)
Log::error("StartGameProtocol", "Bad token received.");
return true;
}
if (m_listener->isServer() && ready) // on server, player is ready
if (ProtocolManager::getInstance()->isServer() && ready) // on server, player is ready
{
Log::info("StartGameProtocol", "One of the players is ready.");
m_player_states[peer->getPlayerProfile()] = READY;
@ -59,7 +59,10 @@ bool StartGameProtocol::notifyEventAsynchronous(Event* event)
if (m_ready_count == m_game_setup->getPlayerCount())
{
// everybody ready, synchronize
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION));
Protocol *p = ProtocolManager::getInstance()
->getProtocol(PROTOCOL_SYNCHRONIZATION);
SynchronizationProtocol* protocol =
static_cast<SynchronizationProtocol*>(p);
if (protocol)
{
protocol->startCountdown(5000); // 5 seconds countdown
@ -94,7 +97,8 @@ void StartGameProtocol::update()
if (m_state == NONE)
{
// if no synchronization protocol exists, create one
m_listener->requestStart(new SynchronizationProtocol());
Protocol *p = new SynchronizationProtocol();
p->requestStart();
Log::info("StartGameProtocol", "SynchronizationProtocol started.");
// race startup sequence
NetworkWorld::getInstance<NetworkWorld>()->start(); // builds it and starts
@ -145,9 +149,13 @@ void StartGameProtocol::update()
rki.setDifficulty(profile->difficulty);
rki.setGlobalPlayerId(profile->race_id);
// on the server, the race id must be the local one.
rki.setLocalPlayerId(m_listener->isServer()?profile->race_id:(is_me?0:1));
rki.setLocalPlayerId(ProtocolManager::getInstance()->isServer()
? profile->race_id
: (is_me ? 0 : 1) );
rki.setHostId(profile->race_id);
Log::info("StartGameProtocol", "Creating kart %s for Player#%d with race_id %d", profile->kart_name.c_str(), i, profile->race_id);
Log::info("StartGameProtocol",
"Creating kart %s for Player#%d with race_id %d",
profile->kart_name.c_str(), i, profile->race_id);
if (!is_me)
{
@ -167,8 +175,9 @@ void StartGameProtocol::update()
}
else if (m_state == SYNCHRONIZATION_WAIT)
{
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>
(m_listener->getProtocol(PROTOCOL_SYNCHRONIZATION));
Protocol *p = ProtocolManager::getInstance()
->getProtocol(PROTOCOL_SYNCHRONIZATION);
SynchronizationProtocol* protocol = static_cast<SynchronizationProtocol*>(p);
if (protocol)
{
// now the synchronization protocol exists.
@ -190,19 +199,19 @@ void StartGameProtocol::update()
// set karts into the network game setup
NetworkManager::getInstance()->getGameSetup()->bindKartsToProfiles();
m_state = EXITING;
m_listener->requestTerminate(this);
requestTerminate();
}
}
void StartGameProtocol::ready() // on clients, means the loading is finished
{
if (!m_listener->isServer()) // if we're a client
if (!ProtocolManager::getInstance()->isServer()) // if we're a client
{
assert(NetworkManager::getInstance()->getPeerCount() == 1);
NetworkString ns(5);
ns.ai32(NetworkManager::getInstance()->getPeers()[0]->getClientServerToken()).ai8(1);
Log::info("StartGameProtocol", "Player ready, notifying server.");
m_listener->sendMessage(this, ns, true);
sendMessage(ns, true);
m_state = READY;
m_ready = true;
return;

View File

@ -49,7 +49,7 @@ void StartServer::asynchronousUpdate()
m_request->addParameter("address", addr.getIP());
m_request->addParameter("port", addr.getPort());
m_request->addParameter("private_port", NetworkManager::getInstance()->getHost()->getPort());
m_request->addParameter("private_port", STKHost::get()->getPort());
m_request->addParameter("max_players", UserConfigParams::m_server_max_players);
Log::info("ShowPublicAddress", "Showing addr %s", addr.toString().c_str());
@ -84,7 +84,7 @@ void StartServer::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
} // asynchronousUpdate

View File

@ -84,6 +84,6 @@ void StopServer::asynchronousUpdate()
m_state = EXITING;
delete m_request;
m_request = NULL;
m_listener->requestTerminate(this);
requestTerminate();
}
}
} // asynchronousUpdate

View File

@ -50,7 +50,7 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
assert(peers.size() > 0);
if (m_listener->isServer())
if (ProtocolManager::getInstance()->isServer())
{
if (talk_id > peers.size())
{
@ -77,9 +77,11 @@ bool SynchronizationProtocol::notifyEventAsynchronous(Event* event)
{
NetworkString response(10);
response.ai8(data.gui8(talk_id)).ai32(token).ai8(0).ai32(sequence);
m_listener->sendMessage(this, peers[peer_id], response, false);
sendMessage(peers[peer_id], response, false);
Log::verbose("SynchronizationProtocol", "Answering sequence %u", sequence);
if (data.size() == 14 && !m_listener->isServer()) // countdown time in the message
// countdown time in the message
if (data.size() == 14 && !ProtocolManager::getInstance()->isServer())
{
uint32_t time_to_start = data.gui32(10);
Log::debug("SynchronizationProtocol", "Request to start game in %d.", time_to_start);
@ -134,10 +136,10 @@ void SynchronizationProtocol::asynchronousUpdate()
{
m_has_quit = true;
Log::info("SynchronizationProtocol", "Countdown finished. Starting now.");
m_listener->requestStart(new KartUpdateProtocol());
m_listener->requestStart(new ControllerEventsProtocol());
m_listener->requestStart(new GameEventsProtocol());
m_listener->requestTerminate(this);
(new KartUpdateProtocol())->requestStart();
(new ControllerEventsProtocol())->requestStart();
(new GameEventsProtocol())->requestStart();
requestTerminate();
return;
}
static int seconds = -1;
@ -159,7 +161,8 @@ void SynchronizationProtocol::asynchronousUpdate()
NetworkString ns(10);
ns.ai8(i).addUInt32(peers[i]->getClientServerToken()).addUInt8(1).addUInt32(m_pings[i].size());
// now add the countdown if necessary
if (m_countdown_activated && m_listener->isServer())
if (m_countdown_activated &&
ProtocolManager::getInstance()->isServer())
{
ns.addUInt32((int)(m_countdown*1000.0));
Log::debug("SynchronizationProtocol", "CNTActivated: Countdown value : %f", m_countdown);
@ -167,7 +170,7 @@ void SynchronizationProtocol::asynchronousUpdate()
Log::verbose("SynchronizationProtocol", "Added sequence number %u for peer %d", m_pings[i].size(), i);
timer = current_time;
m_pings[i].insert(std::pair<int,double>(m_pings_count[i], timer));
m_listener->sendMessage(this, peers[i], ns, false);
sendMessage(peers[i], ns, false);
m_pings_count[i]++;
}
}

View File

@ -16,27 +16,67 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "network/server_network_manager.hpp"
#include "network/server_console.hpp"
#include "main_loop.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/get_peer_address.hpp"
#include "network/protocols/get_public_address.hpp"
#include "network/protocols/hide_public_address.hpp"
#include "network/network_manager.hpp"
#include "network/protocol_manager.hpp"
#include "network/stk_host.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "network/protocols/show_public_address.hpp"
#include "network/protocols/stop_server.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
#include <iostream>
#ifdef XX
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/get_peer_address.hpp"
#include "network/protocols/get_public_address.hpp"
#include "network/protocols/hide_public_address.hpp"
#include "network/protocols/show_public_address.hpp"
#include <enet/enet.h>
#include <pthread.h>
#include <iostream>
#include <string>
#include <stdlib.h>
#endif
void* waitInput2(void* data)
ServerConsole::ServerConsole()
{
m_localhost = NULL;
m_thread_keyboard = NULL;
}
// ----------------------------------------------------------------------------
ServerConsole::~ServerConsole()
{
if (m_thread_keyboard)
pthread_cancel(*m_thread_keyboard);//, SIGKILL);
}
// ----------------------------------------------------------------------------
void ServerConsole::run()
{
if (enet_initialize() != 0)
{
Log::error("ServerConsole", "Could not initialize enet.");
return;
}
Log::info("ServerConsole", "Host initialized.");
// listen keyboard console input
m_thread_keyboard = new pthread_t;
pthread_create(m_thread_keyboard, NULL, mainLoop, this);
Log::info("ServerConsole", "Ready.");
} // run
// ----------------------------------------------------------------------------
void* ServerConsole::mainLoop(void* data)
{
ServerConsole *me = static_cast<ServerConsole*>(data);
std::string str = "";
bool stop = false;
while(!stop)
@ -48,7 +88,7 @@ void* waitInput2(void* data)
}
else if (str == "kickall")
{
ServerNetworkManager::getInstance()->kickAllPlayers();
me->kickAllPlayers();
}
else if (str == "start")
{
@ -83,50 +123,20 @@ void* waitInput2(void* data)
main_loop->abort();
return NULL;
}
} // mainLoop
ServerNetworkManager::ServerNetworkManager()
// ----------------------------------------------------------------------------
void ServerConsole::kickAllPlayers()
{
m_localhost = NULL;
m_thread_keyboard = NULL;
}
ServerNetworkManager::~ServerNetworkManager()
{
if (m_thread_keyboard)
pthread_cancel(*m_thread_keyboard);//, SIGKILL);
}
void ServerNetworkManager::run()
{
if (enet_initialize() != 0)
std::vector<STKPeer*> peers = NetworkManager::getInstance()->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
Log::error("ServerNetworkManager", "Could not initialize enet.");
return;
peers[i]->disconnect();
}
m_localhost = new STKHost();
m_localhost->setupServer(STKHost::HOST_ANY, 7321, 16, 2, 0, 0);
m_localhost->startListening();
} // kickAllPlayers
Log::info("ServerNetworkManager", "Host initialized.");
// listen keyboard console input
m_thread_keyboard = new pthread_t;
pthread_create(m_thread_keyboard, NULL, waitInput2, NULL);
NetworkManager::run();
Log::info("ServerNetworkManager", "Ready.");
}
void ServerNetworkManager::kickAllPlayers()
{
for (unsigned int i = 0; i < m_peers.size(); i++)
{
m_peers[i]->disconnect();
}
}
void ServerNetworkManager::sendPacket(const NetworkString& data, bool reliable)
// ----------------------------------------------------------------------------
void ServerConsole::sendPacket(const NetworkString& data, bool reliable)
{
m_localhost->broadcastPacket(data, reliable);
}
} // sendPacket

View File

@ -0,0 +1,58 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 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.
#ifndef SERVER_CONSOLE_HPP
#define SERVER_CONSOLE_HPP
#include "utils/types.hpp"
#include "pthread.h"
class NetworkString;
class STKHost;
class ServerConsole
{
protected:
STKHost *m_localhost;
pthread_t* m_thread_keyboard;
uint8_t m_max_players;
static void* mainLoop(void* data);
public:
ServerConsole();
virtual ~ServerConsole();
virtual void run();
void setMaxPlayers(uint8_t count) { m_max_players = count; }
uint8_t getMaxPlayers() { return m_max_players; }
void kickAllPlayers();
virtual void sendPacket(const NetworkString& data, bool reliable = true);
virtual bool isServer() { return true; }
}; // class ServerConsole
#endif // SERVER_CONSOLE_HPP

View File

@ -1,57 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2013-2015 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.
/*! \file server_network_manager.hpp
*/
#ifndef SERVER_NETWORK_MANAGER_HPP
#define SERVER_NETWORK_MANAGER_HPP
#include "network/network_manager.hpp"
class ServerNetworkManager : public NetworkManager
{
friend class AbstractSingleton<NetworkManager>;
public:
static ServerNetworkManager* getInstance()
{
return AbstractSingleton<NetworkManager>::getInstance<ServerNetworkManager>();
}
virtual void run();
void setMaxPlayers(uint8_t count) { m_max_players = count; }
uint8_t getMaxPlayers() {return m_max_players;}
void kickAllPlayers();
virtual void sendPacket(const NetworkString& data, bool reliable = true);
virtual bool isServer() { return true; }
protected:
ServerNetworkManager();
virtual ~ServerNetworkManager();
pthread_t* m_thread_keyboard;
uint8_t m_max_players;
};
#endif // SERVER_NETWORK_MANAGER_HPP

View File

@ -22,6 +22,8 @@
#include "io/file_manager.hpp"
#include "network/event.hpp"
#include "network/network_manager.hpp"
#include "network/protocols/server_lobby_room_protocol.hpp"
#include "network/server_console.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
@ -37,25 +39,9 @@
#include <pthread.h>
#include <signal.h>
#ifdef __MINGW32__
const char* inet_ntop(int af, const void* src, char* dst, int cnt)
{
struct sockaddr_in srcaddr;
memset(&srcaddr, 0, sizeof(struct sockaddr_in));
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
srcaddr.sin_family = af;
if (WSAAddressToString((struct sockaddr*) &srcaddr,
sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt) != 0)
{
return NULL;
}
return dst;
}
#endif
Synchronised<FILE*> STKHost::m_log_file = NULL;
STKHost *STKHost::m_stk_host = NULL;
int STKHost::m_max_players = 0;
bool STKHost::m_is_server = false;
// ============================================================================
/** Constructor that just initialises this object (esp. opening the packet
@ -63,18 +49,21 @@ Synchronised<FILE*> STKHost::m_log_file = NULL;
*/
STKHost::STKHost()
{
m_host = NULL;
m_network = NULL;
m_listening_thread = NULL;
m_log_file.setAtomic(NULL);
pthread_mutex_init(&m_exit_mutex, NULL);
if (UserConfigParams::m_packets_log_filename.toString() != "")
Network::openLog();
ProtocolManager::getInstance<ProtocolManager>();
if (m_is_server)
{
std::string s = file_manager
->getUserConfigFile(UserConfigParams::m_packets_log_filename);
m_log_file.setAtomic(fopen(s.c_str(), "w+"));
ServerConsole *sc = new ServerConsole();
sc->run();
setupServer(STKHost::HOST_ANY, 7321, 16, 2, 0, 0);
startListening();
ProtocolManager::getInstance()->requestStart(new ServerLobbyRoomProtocol());
}
if (!m_log_file.getData())
Log::warn("STKHost", "Network packets won't be logged: no file.");
} // STKHost
// ----------------------------------------------------------------------------
@ -83,46 +72,11 @@ STKHost::STKHost()
*/
STKHost::~STKHost()
{
Network::closeLog();
stopListening();
if (m_log_file.getData())
{
m_log_file.lock();
fclose(m_log_file.getData());
Log::warn("STKHost", "Packet logging file has been closed.");
m_log_file.getData() = NULL;
m_log_file.unlock();
}
if (m_host)
{
enet_host_destroy(m_host);
}
delete m_network;
} // ~STKHost
// ----------------------------------------------------------------------------
/** \brief Log packets into a file
* \param ns : The data in the packet
* \param incoming : True if the packet comes from a peer.
* False if it's sent to a peer.
*/
void STKHost::logPacket(const NetworkString &ns, bool incoming)
{
if (m_log_file.getData() == NULL) // read only access, no need to lock
return;
const char *arrow = incoming ? "<--" : "-->";
m_log_file.lock();
fprintf(m_log_file.getData(), "[%d\t] %s ",
(int)(StkTime::getRealTime()), arrow);
for (int i = 0; i < ns.size(); i++)
{
fprintf(m_log_file.getData(), "%d.", ns[i]);
}
fprintf(m_log_file.getData(), "\n");
m_log_file.unlock();
} // logPacket
// ----------------------------------------------------------------------------
/** \brief Starts the listening of events from ENet.
* Starts a thread for receiveData that updates it as often as possible.
@ -174,7 +128,7 @@ void* STKHost::mainLoop(void* self)
{
ENetEvent event;
STKHost* myself = (STKHost*)(self);
ENetHost* host = myself->m_host;
ENetHost* host = myself->m_network->getENetHost();
while (!myself->mustStopListening())
{
while (enet_host_service(host, &event, 20) != 0)
@ -185,7 +139,7 @@ void* STKHost::mainLoop(void* self)
// Create an STKEvent with the event data
Event* stk_event = new Event(&event);
if (stk_event->getType() == EVENT_TYPE_MESSAGE)
logPacket(stk_event->data(), true);
Network::logPacket(stk_event->data(), true);
// The event is forwarded to the NetworkManger and from there
// there to the ProtocolManager. The ProtocolManager is
@ -202,7 +156,7 @@ void* STKHost::mainLoop(void* self)
} // mainLoop
// ----------------------------------------------------------------------------
/** \brief Setups this host as a server.
/** \brief Setup this host as a server.
* \param address : The IPv4 address of incoming connections.
* \param port : The port on which the server listens.
* \param peer_count : The maximum number of peers.
@ -218,16 +172,10 @@ void STKHost::setupServer(uint32_t address, uint16_t port, int peer_count,
addr->host = address;
addr->port = port;
#ifdef WIN32/*
addr->host = 0;
addr->host += ((unsigned int)(192)<<0); // 192.168.0.11
addr->host += ((unsigned int)(168)<<8); // 192.168.0.11
addr->host += ((unsigned int)(11)<<24); // 192.168.0.11*/
#endif
m_host = enet_host_create(addr, peer_count, channel_limit,
max_incoming_bandwidth, max_outgoing_bandwidth);
if (!m_host)
m_network= new Network(peer_count, channel_limit,
max_incoming_bandwidth,
max_outgoing_bandwidth, addr);
if (!m_network)
{
Log::fatal("STKHost", "An error occurred while trying to create an ENet"
" server host.");
@ -247,159 +195,16 @@ void STKHost::setupClient(int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth)
{
m_host = enet_host_create(NULL, peer_count, channel_limit,
max_incoming_bandwidth, max_outgoing_bandwidth);
if (!m_host)
m_network = new Network(peer_count, channel_limit,
max_incoming_bandwidth,
max_outgoing_bandwidth, NULL);
if (!m_network)
{
Log::fatal ("STKHost", "An error occurred while trying to create an "
"ENet client host.");
Log::fatal ("STKHost", "An error occurred while trying to create "
"an ENet client host.");
}
} // setupClient
// ----------------------------------------------------------------------------
/** \brief Sends a packet whithout ENet adding its headers.
* This function is used in particular to achieve the STUN protocol.
* \param data : Data to send.
* \param length : Length of the sent data.
* \param dst : Destination of the packet.
*/
void STKHost::sendRawPacket(uint8_t* data, int length,
const TransportAddress& dst)
{
struct sockaddr_in to;
int to_len = sizeof(to);
memset(&to,0,to_len);
to.sin_family = AF_INET;
to.sin_port = htons(dst.getPort());
to.sin_addr.s_addr = htonl(dst.getIP());
sendto(m_host->socket, (char*)data, length, 0,(sockaddr*)&to, to_len);
Log::verbose("STKHost", "Raw packet sent to %s", dst.toString().c_str());
STKHost::logPacket(NetworkString(std::string((char*)(data), length)),
false);
} // sendRawPacket
// ----------------------------------------------------------------------------
/** \brief Receives a packet directly from the network interface.
* Receive a packet whithout ENet processing it and returns the
* sender's ip address and port in the TransportAddress structure.
* \param sender : Stores the transport address of the sender of the
* received packet.
* \return A string containing the data of the received packet.
*/
uint8_t* STKHost::receiveRawPacket(TransportAddress* sender)
{
const int LEN = 2048;
// max size needed normally (only used for stun)
uint8_t* buffer = new uint8_t[LEN];
memset(buffer, 0, LEN);
socklen_t from_len;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
int i = 0;
// wait to receive the message because enet sockets are non-blocking
while(len == -1) // nothing received
{
StkTime::sleep(1); // wait 1 millisecond between two checks
i++;
len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
}
if (len == SOCKET_ERROR)
{
Log::error("STKHost",
"Problem with the socket. Please contact the dev team.");
}
// we received the data
sender->setIP( ntohl((uint32_t)(addr.sin_addr.s_addr)) );
sender->setPort( ntohs(addr.sin_port) );
if (addr.sin_family == AF_INET)
{
Log::info("STKHost", "IPv4 Address of the sender was %s",
sender->toString().c_str());
}
STKHost::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
} // receiveRawPacket(TransportAddress* sender)
// ----------------------------------------------------------------------------
/** \brief Receives a packet directly from the network interface and
* filter its address.
* Receive a packet whithout ENet processing it. Checks that the
* sender of the packet is the one that corresponds to the sender
* parameter. Does not check the port right now.
* \param sender : Transport address of the original sender of the
* wanted packet.
* \param max_tries : Number of times we try to read data from the
* socket. This is aproximately the time we wait in
* milliseconds. -1 means eternal tries.
* \return A string containing the data of the received packet
* matching the sender's ip address.
*/
uint8_t* STKHost::receiveRawPacket(const TransportAddress& sender,
int max_tries)
{
const int LEN = 2048;
uint8_t* buffer = new uint8_t[LEN];
memset(buffer, 0, LEN);
socklen_t from_len;
struct sockaddr_in addr;
from_len = sizeof(addr);
int len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len );
int count = 0;
// wait to receive the message because enet sockets are non-blocking
while(len < 0 || addr.sin_addr.s_addr == sender.getIP())
{
count++;
if (len>=0)
{
Log::info("STKHost", "Message received but the ip address didn't "
"match the expected one.");
}
len = recvfrom(m_host->socket, (char*)buffer, LEN, 0,
(struct sockaddr*)(&addr), &from_len);
StkTime::sleep(1); // wait 1 millisecond between two checks
if (count >= max_tries && max_tries != -1)
{
TransportAddress a(m_host->address);
Log::verbose("STKHost", "No answer from the server on %s",
a.toString().c_str());
return NULL;
}
}
if (addr.sin_family == AF_INET)
{
TransportAddress a(ntohl(addr.sin_addr.s_addr));
Log::info("STKHost", "IPv4 Address of the sender was %s",
a.toString(false).c_str());
}
STKHost::logPacket(NetworkString(std::string((char*)(buffer), len)), true);
return buffer;
} // receiveRawPacket(const TransportAddress& sender, int max_tries)
// ----------------------------------------------------------------------------
/** \brief Broadcasts a packet to all peers.
* \param data : Data to send.
*/
void STKHost::broadcastPacket(const NetworkString& data, bool reliable)
{
ENetPacket* packet = enet_packet_create(data.getBytes(), data.size() + 1,
reliable ? ENET_PACKET_FLAG_RELIABLE
: ENET_PACKET_FLAG_UNSEQUENCED);
enet_host_broadcast(m_host, 0, packet);
STKHost::logPacket(data, false);
} // broadcastPacket
// ----------------------------------------------------------------------------
/** \brief Tells if a peer is known.
@ -407,10 +212,11 @@ void STKHost::broadcastPacket(const NetworkString& data, bool reliable)
*/
bool STKHost::peerExists(const TransportAddress& peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
ENetHost *host = m_network->getENetHost();
for (unsigned int i = 0; i < host->peerCount ; i++)
{
if (m_host->peers[i].address.host == ntohl(peer.getIP()) &&
m_host->peers[i].address.port == peer.getPort() )
if (host->peers[i].address.host == ntohl(peer.getIP()) &&
host->peers[i].address.port == peer.getPort() )
{
return true;
}
@ -424,10 +230,11 @@ bool STKHost::peerExists(const TransportAddress& peer)
*/
bool STKHost::isConnectedTo(const TransportAddress& peer)
{
for (unsigned int i = 0; i < m_host->peerCount; i++)
ENetHost *host = m_network->getENetHost();
for (unsigned int i = 0; i < host->peerCount; i++)
{
if (peer == m_host->peers[i].address &&
m_host->peers[i].state == ENET_PEER_STATE_CONNECTED)
if (peer == host->peers[i].address &&
host->peers[i].state == ENET_PEER_STATE_CONNECTED)
{
return true;
}
@ -440,7 +247,8 @@ uint16_t STKHost::getPort() const
{
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(m_host->socket, (struct sockaddr *)&sin, &len) == -1)
ENetHost *host = m_network->getENetHost();
if (getsockname(host->socket, (struct sockaddr *)&sin, &len) == -1)
Log::error("STKHost", "Error while using getsockname().");
else
return ntohs(sin.sin_port);

View File

@ -22,6 +22,7 @@
#ifndef STK_HOST_HPP
#define STK_HOST_HPP
#include "network/network.hpp"
#include "network/network_string.hpp"
#include "network/types.hpp"
#include "utils/synchronised.hpp"
@ -46,64 +47,125 @@
*/
class STKHost
{
public:
/** \brief Defines three host types for the server.
* These values tells the host where he will accept connections from.
*/
enum
{
HOST_ANY = 0, //!< Any host.
HOST_BROADCAST = 0xFFFFFFFF, //!< Defines the broadcast address.
PORT_ANY = 0 //!< Any port.
};
friend class STKPeer; // allow direct enet modifications in implementations
private:
/** Singleton pointer to the instance. */
static STKHost* m_stk_host;
/** True if this host is a server, false otherwise. */
static bool m_is_server;
/** ENet host interfacing sockets. */
ENetHost* m_host;
Network* m_network;
/** Id of thread listening to enet events. */
pthread_t* m_listening_thread;
pthread_t* m_listening_thread;
/** Mutex used to stop this thread. */
pthread_mutex_t m_exit_mutex;
//** Where to log packets. If NULL for FILE* logging is disabled. */
static Synchronised<FILE*> m_log_file;
/** Maximum number of players on the server. */
static int m_max_players;
public:
/*! \enum HOST_TYPE
* \brief Defines three host types for the server.
* These values tells the host where he will accept connections from.
*/
enum HOST_TYPE
{
HOST_ANY = 0, //!< Any host.
HOST_BROADCAST = 0xFFFFFFFF, //!< Defines the broadcast address.
PORT_ANY = 0 //!< Any port.
};
STKHost();
virtual ~STKHost();
/*! \brief Constructor */
STKHost();
/*! \brief Destructor */
virtual ~STKHost();
static void logPacket(const NetworkString &ns, bool incoming);
static void* mainLoop(void* self);
public:
void setupServer(uint32_t address, uint16_t port,
int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth);
void setupClient(int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth);
void startListening();
void stopListening();
void sendRawPacket(uint8_t* data, int length,
const TransportAddress& dst);
uint8_t* receiveRawPacket(TransportAddress* sender);
uint8_t* receiveRawPacket(const TransportAddress& sender,
int max_tries = -1);
void broadcastPacket(const NetworkString& data,
bool reliable = true);
bool peerExists(const TransportAddress& peer_address);
bool isConnectedTo(const TransportAddress& peer_address);
int mustStopListening();
uint16_t getPort() const;
// --------------------------------------------------------------------
uint32_t getAddress() const { return m_host->address.host; }
/** Creates the singleton. */
static void create(bool is_server)
{
m_is_server = is_server;
assert(m_stk_host == NULL);
m_stk_host = new STKHost();
} // create
// ------------------------------------------------------------------------
/** Returns the instance of STKHost. */
static STKHost *get()
{
assert(m_stk_host != NULL);
return m_stk_host;
} // get
// ------------------------------------------------------------------------
static void destroy()
{
assert(m_stk_host != NULL);
delete m_stk_host;
m_stk_host = NULL;
}
// ------------------------------------------------------------------------
};
static void* mainLoop(void* self);
void setupServer(uint32_t address, uint16_t port,
int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth);
void setupClient(int peer_count, int channel_limit,
uint32_t max_incoming_bandwidth,
uint32_t max_outgoing_bandwidth);
void startListening();
void stopListening();
uint8_t* receiveRawPacket(const TransportAddress& sender,
int max_tries = -1);
bool peerExists(const TransportAddress& peer_address);
bool isConnectedTo(const TransportAddress& peer_address);
int mustStopListening();
uint16_t getPort() const;
// --------------------------------------------------------------------
ENetPeer* connectTo(const TransportAddress &address)
{
return m_network->connectTo(address);
} // connectTo
// --------------------------------------------------------------------
uint8_t* receiveRawPacket(TransportAddress* sender)
{
return m_network->receiveRawPacket(sender);
} // receiveRawPacket
// --------------------------------------------------------------------
void broadcastPacket(const NetworkString& data,
bool reliable = true)
{
m_network->broadcastPacket(data, reliable);
} // broadcastPacket
// --------------------------------------------------------------------
void sendRawPacket(uint8_t* data, int length,
const TransportAddress& dst)
{
m_network->sendRawPacket(data, length, dst);
} // sendRawPacket
// --------------------------------------------------------------------
/** Returns the IP address of this host. */
uint32_t getAddress() const
{
return m_network->getENetHost()->address.host;
} // getAddress
// --------------------------------------------------------------------
/** Sets the maximum number of players for this server. */
static void setMaxPlayers(int n) { m_max_players = n; }
// --------------------------------------------------------------------
/** Returns the maximum number of players for this server. */
static int getMaxPlayers() { return m_max_players; }
}; // class STKHost
#endif // STK_HOST_HPP

View File

@ -50,12 +50,11 @@ STKPeer::~STKPeer()
//-----------------------------------------------------------------------------
/** Connect to the specified host.
*/
bool STKPeer::connectToHost(STKHost* localhost, const TransportAddress &host,
bool STKPeer::connectToHost(STKHost* localhost, const TransportAddress &address,
uint32_t channel_count, uint32_t data)
{
const ENetAddress address = host.toEnetAddress();
ENetPeer* peer = localhost->connectTo(address);
ENetPeer* peer = enet_host_connect(localhost->m_host, &address, 2, 0);
if (peer == NULL)
{
Log::error("STKPeer", "Could not try to connect to server.\n");

View File

@ -19,8 +19,8 @@
/*! \file types.hpp
* \brief Declares the general types that are used by the network.
*/
#ifndef TYPES_HPP
#define TYPES_HPP
#ifndef HEADER_NETWORK_TYPES_HPP
#define HEADER_NETWORK_TYPES_HPP
#include "utils/no_copy.hpp"
#include "utils/string_utils.hpp"