adding a new string class to easily format packets. added features in the lobby protocol

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/networking@13089 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hilnius
2013-07-05 16:16:02 +00:00
parent ed6e4ebfb4
commit 78b9a7d6a7
19 changed files with 318 additions and 47 deletions

View File

@@ -141,6 +141,7 @@ src/network/game_setup.cpp
src/network/http_functions.cpp
src/network/network_interface.cpp
src/network/network_manager.cpp
src/network/network_string.cpp
src/network/protocol.cpp
src/network/protocol_manager.cpp
src/network/protocols/connect_to_server.cpp
@@ -404,6 +405,7 @@ src/network/game_setup.hpp
src/network/http_functions.hpp
src/network/network_interface.hpp
src/network/network_manager.hpp
src/network/network_string.hpp
src/network/protocol.hpp
src/network/protocol_manager.hpp
src/network/protocols/connect_to_server.hpp

View File

@@ -110,7 +110,7 @@ bool ClientNetworkManager::connectToHost(std::string serverNickname)
return success;
}
void ClientNetworkManager::sendPacket(const char* data)
void ClientNetworkManager::sendPacket(const NetworkString& data)
{
if (m_peers.size() > 1)
Log::warn("ClientNetworkManager", "Ambiguous send of data.\n");

View File

@@ -34,7 +34,7 @@ class ClientNetworkManager : public NetworkManager
bool connectToHost(std::string serverNickname);
virtual void sendPacket(const char* data);
virtual void sendPacket(const NetworkString& data);
STKPeer* getPeer();
virtual bool isServer() { return false; }

View File

@@ -38,7 +38,8 @@ Event::Event(ENetEvent* event)
if (type == EVENT_TYPE_MESSAGE)
data = std::string((char*)(event->packet->data));
else if (event->data)
data = std::string((char*)(event->data));
{
}
if (event->packet)
m_packet = event->packet;

View File

@@ -55,12 +55,13 @@ class GameSetup
void removePlayer(uint32_t id); //!< Remove a player by id.
void removePlayer(uint8_t id); //!< Remove a player by local id.
int getPlayerCount() { return m_players.size(); }
const NetworkPlayerProfile* getProfile(uint32_t id); //!< Get a profile by database id
const NetworkPlayerProfile* getProfile(uint8_t id); //!< Get the profile by the lobby id
protected:
std::vector<NetworkPlayerProfile> m_players; //!< Information about players
NetworkPlayerProfile m_self_profile; //!< Information about self
NetworkPlayerProfile m_self_profile; //!< Information about self (client only)
};
#endif // GAME_SETUP_HPP

View File

@@ -135,6 +135,25 @@ void NetworkManager::notifyEvent(Event* event)
//-----------------------------------------------------------------------------
void NetworkManager::sendPacket(STKPeer* peer, const NetworkString& data)
{
if (peer)
peer->sendPacket(data);
}
//-----------------------------------------------------------------------------
void NetworkManager::sendPacketExcept(STKPeer* peer, const NetworkString& data)
{
for (unsigned int i = 0; i < m_peers.size(); i++)
{
if (m_peers[i] != peer)
m_peers[i]->sendPacket(data);
}
}
//-----------------------------------------------------------------------------
GameSetup* NetworkManager::setupNewGame()
{
if (m_game_setup)

View File

@@ -42,7 +42,9 @@ class NetworkManager : public Singleton<NetworkManager>
// message/packets related functions
virtual void notifyEvent(Event* event);
virtual void sendPacket(const char* data) = 0;
virtual void sendPacket(const NetworkString& data) = 0;
virtual void sendPacket(STKPeer* peer, const NetworkString& data);
virtual void sendPacketExcept(STKPeer* peer, const NetworkString& data);
// Game related functions
virtual GameSetup* setupNewGame(); //!< Creates a new game setup and returns it

View File

@@ -0,0 +1,8 @@
#include "network/network_string.hpp"
NetworkString operator+(NetworkString const& a, NetworkString const& b)
{
NetworkString ns(a);
ns += b;
return ns;
}

View File

@@ -0,0 +1,136 @@
#ifndef NETWORK_STRING_HPP
#define NETWORK_STRING_HPP
#include <string>
#include <stdarg.h>
#include <assert.h>
#include <stdint.h>
class NetworkString
{
union {
float f;
uint8_t i[4];
} f_as_i; // float as integer
union {
double d;
uint8_t i[8];
} d_as_i; // double as integer
public:
NetworkString() { }
NetworkString(const uint8_t& value) { m_string = (char)(value); }
NetworkString(NetworkString const& copy) { m_string = copy.m_string; }
NetworkString(std::string str) { m_string = str; }
NetworkString& addUInt8(const uint8_t& value)
{
m_string += (char)(value);
return *this;
}
inline NetworkString& ai8(const uint8_t& value) { return addUInt8(value); }
NetworkString& addUInt16(const uint16_t& value)
{
m_string += (char)((value<<8)&0xff);
m_string += (char)(value&0xff);
return *this;
}
inline NetworkString& ai16(const uint16_t& value) { return addUInt16(value); }
NetworkString& addUInt32(const uint32_t& value)
{
m_string += (char)((value<<24)&0xff);
m_string += (char)((value<<16)&0xff);
m_string += (char)((value<<8)&0xff);
m_string += (char)(value&0xff);
return *this;
}
inline NetworkString& ai32(const uint32_t& value) { return addUInt32(value); }
NetworkString& addInt(const int& value)
{
m_string += (char)((value<<24)&0xff);
m_string += (char)((value<<16)&0xff);
m_string += (char)((value<<8)&0xff);
m_string += (char)(value&0xff);
return *this;
}
inline NetworkString& ai(const int& value) { return addInt(value); }
NetworkString& addFloat(const float& value) //!< BEWARE OF PRECISION
{
assert(sizeof(float)==4);
f_as_i.f = value;
m_string += (char)(f_as_i.i[0]);
m_string += (char)(f_as_i.i[1]);
m_string += (char)(f_as_i.i[2]);
m_string += (char)(f_as_i.i[3]);
return *this;
}
inline NetworkString& af(const float& value) { return addFloat(value); }
NetworkString& addDouble(const double& value) //!< BEWARE OF PRECISION
{
assert(sizeof(double)==8);
d_as_i.d = value;
m_string += (char)(d_as_i.i[0]);
m_string += (char)(d_as_i.i[1]);
m_string += (char)(d_as_i.i[2]);
m_string += (char)(d_as_i.i[3]);
m_string += (char)(d_as_i.i[4]);
m_string += (char)(d_as_i.i[5]);
m_string += (char)(d_as_i.i[6]);
m_string += (char)(d_as_i.i[7]);
return *this;
}
inline NetworkString& ad(const double& value) { return addDouble(value); }
NetworkString& operator+=(NetworkString const& value)
{
m_string += value.m_string;
return *this;
}
const char* c_str() const
{
return m_string.c_str();
}
int size() const
{
return m_string.size();
}
template<typename T, size_t n>
T get(int pos)
{
int a = n;
T result = 0;
while(a--)
{
result <<= 8; // offset one byte
result += ((uint8_t)(m_string[pos+n-1-a]) & 0xff); // add the data
}
return result;
}
inline int getInt(int pos = 0) { return get<int,4>(pos); }
inline uint32_t getUInt(int pos = 0) { return get<uint32_t,4>(pos); }
inline uint32_t getUInt32(int pos = 0) { return get<uint32_t,4>(pos); }
inline uint16_t getUInt16(int pos = 0) { return get<uint16_t,2>(pos); }
inline uint8_t getUInt8(int pos = 0) { return get<uint8_t,1>(pos); }
inline char getChar(int pos = 0) { return get<char,1>(pos); }
inline unsigned char getUChar(int pos = 0) { return get<unsigned char,1>(pos); }
double getDouble(int pos = 0) //!< BEWARE OF PRECISION
{
for (int i = 0; i < 8; i++)
d_as_i.i[i] = m_string[pos+i];
return d_as_i.d;
}
float getFloat(int pos = 0) //!< BEWARE OF PRECISION
{
for (int i = 0; i < 4; i++)
f_as_i.i[i] = m_string[pos+i];
return f_as_i.f;
}
protected:
std::string m_string;
};
NetworkString operator+(NetworkString const& a, NetworkString const& b);
#endif // NETWORK_STRING_HPP

View File

@@ -65,11 +65,27 @@ void ProtocolManager::notifyEvent(Event* event)
pthread_mutex_unlock(&m_events_mutex);
}
void ProtocolManager::sendMessage(Protocol* sender, std::string message)
void ProtocolManager::sendMessage(Protocol* sender, const NetworkString& message)
{
std::string newMessage = " " + message; // add one byte to add protocol type
newMessage[0] = (char)(sender->getProtocolType());
NetworkManager::getInstance()->sendPacket(newMessage.c_str());
NetworkString newMessage;
newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type
newMessage += message;
NetworkManager::getInstance()->sendPacket(newMessage);
}
void ProtocolManager::sendMessage(Protocol* sender, STKPeer* peer, const NetworkString& message)
{
NetworkString newMessage;
newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type
newMessage += message;
NetworkManager::getInstance()->sendPacket(peer, newMessage);
}
void ProtocolManager::sendMessageExcept(Protocol* sender, STKPeer* peer, const NetworkString& message)
{
NetworkString newMessage;
newMessage.ai8(sender->getProtocolType()); // add one byte to add protocol type
newMessage += message;
NetworkManager::getInstance()->sendPacketExcept(peer, newMessage);
}
int ProtocolManager::requestStart(Protocol* protocol)

View File

@@ -25,6 +25,7 @@
#include "network/singleton.hpp"
#include "network/event.hpp"
#include "network/network_string.hpp"
#include <vector>
#include <stdint.h>
@@ -104,7 +105,15 @@ class ProtocolManager : public Singleton<ProtocolManager>
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessage(Protocol* sender, std::string message);
virtual void sendMessage(Protocol* sender, const NetworkString& message);
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessage(Protocol* sender, STKPeer* peer, const NetworkString& message);
/*!
* \brief WILL BE COMMENTED LATER
*/
virtual void sendMessageExcept(Protocol* sender, STKPeer* peer, const NetworkString& message);
/*!
* \brief Asks the manager to start a protocol.

View File

@@ -44,7 +44,7 @@ void LobbyRoomProtocol::notifyEvent(Event* event)
Log::verbose("LobbyRoomProtocol", "Message from %u : \"%s\"", event->peer->getAddress(), event->data.c_str());
if (!m_listener->isServer()) // if we're a client
{
if (event->data[0] == (char)(1)) // new player connected
if ((uint8_t)(event->data[0]) == 1) // new player connected
{
assert(event->data[1] == (char)(4)); // id is on 4 bytes
assert(event->data[6] == (char)(1)); // local id on 1 byte
@@ -60,52 +60,125 @@ void LobbyRoomProtocol::notifyEvent(Event* event)
global_id += (uint8_t)(event->data[5]);
if (global_id == CurrentOnlineUser::get()->getUserID())
{
Log::verbose("LobbyRoomProtocol", "The server confirmed that we are logged.");
profile.user_profile = CurrentOnlineUser::get();
Log::fatal("LobbyRoomProtocol", "The server sent a message that he shouldn't.");
}
else
{
Log::verbose("LobbyRoomProtocol", "New player connected.");
profile.user_profile = new OnlineUser(""); ///! INSERT THE ID OF THE PLAYER HERE (global_id)
m_setup->addPlayer(profile);
}
m_setup->addPlayer(profile);
} // if (event->data[0] == (char)(1))
else
else if ((uint8_t)(event->data[0]) == 0b10000001) // connection accepted
{
assert(event->data[1] == (char)(4)); // id is on 4 bytes
assert(event->data[6] == (char)(1)); // local id on 1 byte
assert(event->data.size() == 8); // the message was 8 bytes
NetworkPlayerProfile profile;
profile.kart_name = "";
profile.race_id = (uint8_t)(event->data[7]);
uint32_t global_id = 0;
global_id += (uint8_t)(event->data[2])<<24;
global_id += (uint8_t)(event->data[3])<<16;
global_id += (uint8_t)(event->data[4])<<8;
global_id += (uint8_t)(event->data[5]);
if (global_id == CurrentOnlineUser::get()->getUserID())
{
Log::info("LobbyRoomProtocol", "The server accepted the connection.");
profile.user_profile = CurrentOnlineUser::get();
m_setup->addPlayer(profile);
}
else
{
Log::fatal("LobbyRoomProtocol", "The server told you that you have a different id than yours.");
}
} // connection accepted
else if ((uint8_t)(event->data[0]) == 0b10000000) // connection refused
{
if ((uint8_t)(event->data[1]) != 1 || event->data.size() != 2)
{
Log::warn("LobbyRoomProtocol", "Inappropriate answer from the server.");
}
else // the message is correctly made
{
Log::info("LobbyRoomProtocol", "The connection has been refused.");
switch ((uint8_t)(event->data[2]))
{
case 0:
Log::info("LobbyRoomProtocol", "Too many clients in the race.");
break;
case 1:
Log::info("LobbyRoomProtocol", "The host has banned you.");
break;
default:
break;
}
}
} // connection refused
} // if we're a client
else // we're the server
{
if ((uint8_t)(event->data[0]) == 1) // player requesting connection
{
if (event->data.size() != 5 || event->data[1] != (char)(4))
{
Log::warn("LobbyRoomProtocol", "A player is sending a badly formated message.");
}
else // well-formated message
{
Log::verbose("LobbyRoomProtocol", "New player.");
int player_id = 0;
// can we add the player ?
if (m_setup->getPlayerCount() < 16)
{
// add the player to the game setup
while(m_setup->getProfile(m_next_id)!=NULL)
m_next_id++;
NetworkPlayerProfile profile;
profile.race_id = m_next_id;
profile.kart_name = "";
profile.user_profile = new OnlineUser("Unnamed Player");
m_setup->addPlayer(profile);
// notify everybody that there is a new player
NetworkString message;
// type -- 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->sendMessage(this, message);
}
else // refuse the connection with code 0 (too much players)
{
NetworkString message;
message.ai8(0b10000000); // 128 means connection refused
message.ai8(1); // 1 bytes for the error code
message.ai8(0); // 0 = too much players
m_listener->sendMessage(this, message);
}
}
}
} // if (!m_listener->isServer())
} // we're the server
} // if (event->type == EVENT_TYPE_MESSAGE)
if (event->type == EVENT_TYPE_CONNECTED)
else if (event->type == EVENT_TYPE_CONNECTED)
{
if (m_listener->isServer()) // if we're the server
{
Log::verbose("LobbyRoomProtocol", "New player.");
int player_id = 0;
// add the player to the game setup
while(m_setup->getProfile(m_next_id)!=NULL)
m_next_id++;
NetworkPlayerProfile profile;
profile.race_id = m_next_id;
profile.kart_name = "";
profile.user_profile = new OnlineUser("Unnamed Player");
m_setup->addPlayer(profile);
// notify everybody that there is a new player
std::string message;
message += (char)(1); // 1 means new player
message += (char)(4); // 4 bytes for the id
message += (char)((player_id<<24)&0xff); // 1rst id byte
message += (char)((player_id<<16)&0xff); // 2nd id byte
message += (char)((player_id<<8)&0xff); // 3rd id byte
message += (char)(player_id&0xff); // 4th id byte
message += (char)(1); // 1 byte for local id
message += (char)(m_next_id); // 1 byte of local id
m_listener->sendMessage(this, message);
}
else
{
Log::verbose("LobbyRoomProtocol", "Connected.");
}
} // if (event->type == EVENT_TYPE_CONNECTED)
else if (event->type == EVENT_TYPE_DISCONNECTED)
{
if (m_listener->isServer()) // if we're the server
{
Log::fatal("LobbyRoomProtocol", "A client is now disconnected.");
}
else
{
Log::verbose("LobbyRoomProtocol", "Player Connected.");
}
} // if (event->type == EVENT_TYPE_DISCONNECTED)
Log::setLogLevel(3);
}

View File

@@ -22,6 +22,7 @@
#include "network/protocol.hpp"
#include "network/game_setup.hpp"
#include "network/network_string.hpp"
/*!
* \class LobbyRoomProtocol

View File

@@ -111,7 +111,7 @@ bool ServerNetworkManager::connectToPeer(std::string peer_username)
return success;
}
void ServerNetworkManager::sendPacket(const char* data)
void ServerNetworkManager::sendPacket(const NetworkString& data)
{
m_localhost->broadcastPacket(data);
}

View File

@@ -36,7 +36,7 @@ class ServerNetworkManager : public NetworkManager
void start();
bool connectToPeer(std::string peer_username);
virtual void sendPacket(const char* data);
virtual void sendPacket(const NetworkString& data);
virtual bool isServer() { return false; }

View File

@@ -193,9 +193,9 @@ uint8_t* STKHost::receiveRawPacket(TransportAddress sender)
// ----------------------------------------------------------------------------
void STKHost::broadcastPacket(const char* data)
void STKHost::broadcastPacket(const NetworkString& data)
{
ENetPacket* packet = enet_packet_create(data, strlen(data)+1,
ENetPacket* packet = enet_packet_create(data.c_str(), data.size()+1,
ENET_PACKET_FLAG_RELIABLE);
enet_host_broadcast(m_host, 0, packet);
}

View File

@@ -22,8 +22,10 @@
#ifndef STK_HOST_HPP
#define STK_HOST_HPP
#include <enet/enet.h>
#include "network/types.hpp"
#include "network/network_string.hpp"
#include <enet/enet.h>
/*! \class STKHost
* \brief Represents the local host.
@@ -122,7 +124,7 @@ class STKHost
/*! \brief Broadcasts a packet to all peers.
* \param data : Data to send.
*/
void broadcastPacket(const char* data);
void broadcastPacket(const NetworkString& data);
/*! \brief Tells if a peer is known.
* \return True if the peer is known, false elseway.

View File

@@ -52,11 +52,11 @@ bool STKPeer::connectToHost(STKHost* localhost, TransportAddress host, uint32_t
return true;
}
void STKPeer::sendPacket(const char* data)
void STKPeer::sendPacket(NetworkString const& data)
{
//Log::info("STKPeer", "sending packet to %i.%i.%i.%i:%i", (m_peer->address.host>>24)&0xff,(m_peer->address.host>>16)&0xff,(m_peer->address.host>>8)&0xff,(m_peer->address.host>>0)&0xff,m_peer->address.port);
ENetPacket* packet = enet_packet_create(data.c_str(), data.size()+1,ENET_PACKET_FLAG_RELIABLE);
ENetPacket* packet = enet_packet_create(data, strlen(data)+1,ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(m_peer, 0, packet);
}

View File

@@ -20,6 +20,7 @@
#define STK_PEER_HPP
#include "network/stk_host.hpp"
#include "network/network_string.hpp"
#include <enet/enet.h>
class STKPeer
@@ -29,7 +30,7 @@ class STKPeer
STKPeer();
virtual ~STKPeer();
virtual void sendPacket(const char* data);
virtual void sendPacket(const NetworkString& data);
static bool connectToHost(STKHost* localhost, TransportAddress host, uint32_t channel_count, uint32_t data);