Made access to the public address thread safe, and simplified setting

of the public address.
This commit is contained in:
hiker 2015-10-19 08:02:44 +11:00
parent 4fad614d55
commit faf697ef5d
9 changed files with 65 additions and 33 deletions

View File

@ -35,10 +35,12 @@
NetworkManager::NetworkManager() NetworkManager::NetworkManager()
{ {
m_public_address.clear(); m_public_address.lock();
m_public_address.getData().clear();
m_public_address.unlock();
m_localhost = NULL; m_localhost = NULL;
m_game_setup = NULL; m_game_setup = NULL;
} } // NetworkManager
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -195,8 +197,11 @@ void NetworkManager::setLogin(std::string username, std::string password)
void NetworkManager::setPublicAddress(const TransportAddress& addr) void NetworkManager::setPublicAddress(const TransportAddress& addr)
{ {
m_public_address.copy(addr); m_public_address.lock();
} m_public_address.getData().copy(addr);
m_public_address.unlock();
} // setPublicAddress
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void NetworkManager::removePeer(STKPeer* peer) void NetworkManager::removePeer(STKPeer* peer)

View File

@ -31,6 +31,7 @@
#include "network/event.hpp" #include "network/event.hpp"
#include "network/game_setup.hpp" #include "network/game_setup.hpp"
#include "utils/singleton.hpp" #include "utils/singleton.hpp"
#include "utils/synchronised.hpp"
#include <vector> #include <vector>
@ -98,12 +99,30 @@ class NetworkManager : public AbstractSingleton<NetworkManager>
virtual bool isConnectedTo(const TransportAddress& peer); virtual bool isConnectedTo(const TransportAddress& peer);
virtual bool isServer() = 0; virtual bool isServer() = 0;
// --------------------------------------------------------------------
inline bool isClient() { return !isServer(); } inline bool isClient() { return !isServer(); }
// --------------------------------------------------------------------
bool isPlayingOnline() { return m_playing_online; } bool isPlayingOnline() { return m_playing_online; }
// --------------------------------------------------------------------
STKHost* getHost() { return m_localhost; } STKHost* getHost() { return m_localhost; }
// --------------------------------------------------------------------
std::vector<STKPeer*> getPeers() { return m_peers; } std::vector<STKPeer*> getPeers() { return m_peers; }
// --------------------------------------------------------------------
unsigned int getPeerCount() { return (int)m_peers.size(); } unsigned int getPeerCount() { return (int)m_peers.size(); }
const TransportAddress& getPublicAddress() { return m_public_address; } // --------------------------------------------------------------------
/** Returns the public IP address (thread safe). The network manager
* is a friend of TransportAddress and so has access to the copy
* constructor, which is otherwise declared private. */
const TransportAddress getPublicAddress()
{
m_public_address.lock();
TransportAddress a;
a.copy(m_public_address.getData());
m_public_address.unlock();
return a;
} // getPublicAddress
// --------------------------------------------------------------------
GameSetup* getGameSetup() { return m_game_setup; } GameSetup* getGameSetup() { return m_game_setup; }
protected: protected:
@ -115,8 +134,9 @@ class NetworkManager : public AbstractSingleton<NetworkManager>
STKHost* m_localhost; STKHost* m_localhost;
bool m_playing_online; bool m_playing_online;
GameSetup* m_game_setup; GameSetup* m_game_setup;
/** This computer's public IP address. With lock since it can
TransportAddress m_public_address; * be updated from a separate thread. */
Synchronised<TransportAddress> m_public_address;
PlayerLogin m_player_login; PlayerLogin m_player_login;
}; };

View File

@ -82,7 +82,6 @@ void ConnectToServer::setup()
{ {
Log::info("ConnectToServer", "SETUPP"); Log::info("ConnectToServer", "SETUPP");
m_state = NONE; m_state = NONE;
m_public_address.clear();
m_server_address.clear(); m_server_address.clear();
m_current_protocol_id = 0; m_current_protocol_id = 0;
} }
@ -96,7 +95,7 @@ void ConnectToServer::asynchronousUpdate()
case NONE: case NONE:
{ {
Log::info("ConnectToServer", "Protocol starting"); Log::info("ConnectToServer", "Protocol starting");
m_current_protocol_id = m_listener->requestStart(new GetPublicAddress(&m_public_address)); m_current_protocol_id = m_listener->requestStart(new GetPublicAddress());
m_state = GETTING_SELF_ADDRESS; m_state = GETTING_SELF_ADDRESS;
break; break;
} }
@ -105,7 +104,6 @@ void ConnectToServer::asynchronousUpdate()
== PROTOCOL_STATE_TERMINATED) // now we know the public addr == PROTOCOL_STATE_TERMINATED) // now we know the public addr
{ {
m_state = SHOWING_SELF_ADDRESS; m_state = SHOWING_SELF_ADDRESS;
NetworkManager::getInstance()->setPublicAddress(m_public_address); // set our public address
m_current_protocol_id = m_listener->requestStart(new ShowPublicAddress()); m_current_protocol_id = m_listener->requestStart(new ShowPublicAddress());
Log::info("ConnectToServer", "Public address known"); Log::info("ConnectToServer", "Public address known");
/* /*
@ -138,10 +136,13 @@ void ConnectToServer::asynchronousUpdate()
{ {
Log::info("ConnectToServer", "Server's address known"); Log::info("ConnectToServer", "Server's address known");
// we're in the same lan (same public ip address) !! // we're in the same lan (same public ip address) !!
if (m_server_address.getIP() == m_public_address.getIP()) if (m_server_address.getIP() ==
Log::info("ConnectToServer", "Server appears to be in the same LAN."); NetworkManager::getInstance()->getPublicAddress().getIP())
Log::info("ConnectToServer",
"Server appears to be in the same LAN.");
m_state = REQUESTING_CONNECTION; m_state = REQUESTING_CONNECTION;
m_current_protocol_id = m_listener->requestStart(new RequestConnection(m_server_id)); m_current_protocol_id =
m_listener->requestStart(new RequestConnection(m_server_id));
} }
break; break;
case REQUESTING_CONNECTION: case REQUESTING_CONNECTION:
@ -159,7 +160,8 @@ void ConnectToServer::asynchronousUpdate()
return; return;
} }
// we're in the same lan (same public ip address) !! // we're in the same lan (same public ip address) !!
if (m_server_address.getIP() == m_public_address.getIP()) if (m_server_address.getIP() ==
NetworkManager::getInstance()->getPublicAddress().getIP())
{ {
// just send a broadcast packet, the client will know our ip address and will connect // just send a broadcast packet, the client will know our ip address and will connect
STKHost* host = NetworkManager::getInstance()->getHost(); STKHost* host = NetworkManager::getInstance()->getHost();

View File

@ -37,7 +37,6 @@ class ConnectToServer : public Protocol, public CallbackObject
protected: protected:
TransportAddress m_server_address; TransportAddress m_server_address;
TransportAddress m_public_address;
uint32_t m_server_id; uint32_t m_server_id;
uint32_t m_host_id; uint32_t m_host_id;
uint32_t m_current_protocol_id; uint32_t m_current_protocol_id;

View File

@ -45,8 +45,8 @@
// make the linker happy // make the linker happy
const uint32_t GetPublicAddress::m_stun_magic_cookie = 0x2112A442; const uint32_t GetPublicAddress::m_stun_magic_cookie = 0x2112A442;
GetPublicAddress::GetPublicAddress(CallbackObject* callback_object) GetPublicAddress::GetPublicAddress()
: Protocol(callback_object, PROTOCOL_SILENT) : Protocol(NULL, PROTOCOL_SILENT)
{ {
m_state = NOTHING_DONE; m_state = NOTHING_DONE;
} // GetPublicAddress } // GetPublicAddress
@ -154,9 +154,8 @@ std::string GetPublicAddress::parseStunResponse()
if (message_size < 4) // cannot even read the size if (message_size < 4) // cannot even read the size
return "STUN response is too short."; return "STUN response is too short.";
// Those are the port and the address to be detected // Those are the port and the address to be detected
TransportAddress address;
int pos = 20; int pos = 20;
while (true) while (true)
{ {
@ -166,8 +165,13 @@ std::string GetPublicAddress::parseStunResponse()
{ {
assert(size == 8); assert(size == 8);
assert(datas.getUInt8(pos+5) == 0x01); // Family IPv4 only assert(datas.getUInt8(pos+5) == 0x01); // Family IPv4 only
address.setPort(datas.getUInt16(pos + 6)); TransportAddress address(datas.getUInt32(pos + 8),
address.setIP(datas.getUInt32(pos + 8)); datas.getUInt16(pos + 6));
// finished parsing, we know our public transport address
Log::debug("GetPublicAddress",
"The public address has been found: %s",
address.toString().c_str());
NetworkManager::getInstance()->setPublicAddress(address);
break; break;
} // type = 0 or 1 } // type = 0 or 1
pos += 4 + size; pos += 4 + size;
@ -178,12 +182,6 @@ std::string GetPublicAddress::parseStunResponse()
return "STUN response is invalid."; return "STUN response is invalid.";
} // while true } // while true
// finished parsing, we know our public transport address
Log::debug("GetPublicAddress", "The public address has been found: %s",
address.toString().c_str());
TransportAddress* addr = static_cast<TransportAddress*>(m_callback_object);
addr->copy(address);
// The address and the port are known, so the connection can be closed // The address and the port are known, so the connection can be closed
m_state = EXITING; m_state = EXITING;
m_listener->requestTerminate(this); m_listener->requestTerminate(this);

View File

@ -26,7 +26,7 @@
class GetPublicAddress : public Protocol class GetPublicAddress : public Protocol
{ {
public: public:
GetPublicAddress(CallbackObject* callback_object); GetPublicAddress();
virtual ~GetPublicAddress() {} virtual ~GetPublicAddress() {}
virtual bool notifyEvent(Event* event) { return true; } virtual bool notifyEvent(Event* event) { return true; }

View File

@ -53,7 +53,6 @@ void ServerLobbyRoomProtocol::setup()
m_setup->getRaceConfig()->setPlayerCount(16); //FIXME : this has to be moved to when logging into the server m_setup->getRaceConfig()->setPlayerCount(16); //FIXME : this has to be moved to when logging into the server
m_next_id = 0; m_next_id = 0;
m_state = NONE; m_state = NONE;
m_public_address.clear();
m_selection_enabled = false; m_selection_enabled = false;
m_in_race = false; m_in_race = false;
Log::info("ServerLobbyRoomProtocol", "Starting the protocol."); Log::info("ServerLobbyRoomProtocol", "Starting the protocol.");
@ -106,13 +105,12 @@ void ServerLobbyRoomProtocol::update()
switch (m_state) switch (m_state)
{ {
case NONE: case NONE:
m_current_protocol_id = m_listener->requestStart(new GetPublicAddress(&m_public_address)); m_current_protocol_id = m_listener->requestStart(new GetPublicAddress());
m_state = GETTING_PUBLIC_ADDRESS; m_state = GETTING_PUBLIC_ADDRESS;
break; break;
case GETTING_PUBLIC_ADDRESS: case GETTING_PUBLIC_ADDRESS:
if (m_listener->getProtocolState(m_current_protocol_id) == PROTOCOL_STATE_TERMINATED) if (m_listener->getProtocolState(m_current_protocol_id) == PROTOCOL_STATE_TERMINATED)
{ {
NetworkManager::getInstance()->setPublicAddress(m_public_address);
m_current_protocol_id = m_listener->requestStart(new StartServer()); m_current_protocol_id = m_listener->requestStart(new StartServer());
m_state = LAUNCHING_SERVER; m_state = LAUNCHING_SERVER;
Log::debug("ServerLobbyRoomProtocol", "Public address known."); Log::debug("ServerLobbyRoomProtocol", "Public address known.");

View File

@ -37,7 +37,6 @@ class ServerLobbyRoomProtocol : public LobbyRoomProtocol
std::vector<TransportAddress> m_peers; std::vector<TransportAddress> m_peers;
std::vector<uint32_t> m_incoming_peers_ids; std::vector<uint32_t> m_incoming_peers_ids;
uint32_t m_current_protocol_id; uint32_t m_current_protocol_id;
TransportAddress m_public_address;
bool m_selection_enabled; bool m_selection_enabled;
bool m_in_race; bool m_in_race;

View File

@ -72,8 +72,19 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
~TransportAddress() {} ~TransportAddress() {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
private:
friend class NetworkManager;
/** The copy constructor is private, so that the friend class
* NetworkManager can access it to create a copy, but no other
* class can. */
TransportAddress(const TransportAddress &other)
{
copy(other);
} // TransportAddress(const TransportAddress&)
public:
// ------------------------------------------------------------------------
/** A copy function (to replace the copy constructor which is disabled /** A copy function (to replace the copy constructor which is disabled
* using NoCopy). */ * using NoCopy): it copies the data from the argument into this object.*/
void copy(const TransportAddress &other) void copy(const TransportAddress &other)
{ {
m_ip = other.m_ip; m_ip = other.m_ip;