Add kicking players and properly recieve disconnect events

This commit is contained in:
Benau 2018-03-10 12:34:33 +08:00
parent 22ca1cb751
commit 98e3d82921
9 changed files with 111 additions and 63 deletions

View File

@ -30,6 +30,7 @@
Event::Event(ENetEvent* event, std::shared_ptr<STKPeer> peer)
{
m_arrival_time = (double)StkTime::getTimeSinceEpoch();
m_pdi = PDI_TIMEOUT;
switch (event->type)
{
@ -38,6 +39,7 @@ Event::Event(ENetEvent* event, std::shared_ptr<STKPeer> peer)
break;
case ENET_EVENT_TYPE_DISCONNECT:
m_type = EVENT_TYPE_DISCONNECTED;
m_pdi = (PeerDisconnectInfo)event->data;
break;
case ENET_EVENT_TYPE_RECEIVE:
m_type = EVENT_TYPE_MESSAGE;

View File

@ -44,6 +44,7 @@ enum EVENT_TYPE
EVENT_TYPE_DISCONNECTED,//!< A peer is disconnected
EVENT_TYPE_MESSAGE //!< A message between server and client protocols
};
enum PeerDisconnectInfo : unsigned int;
/*!
* \class Event
@ -72,6 +73,9 @@ private:
/** Arrivial time of the event, for timeouts. */
double m_arrival_time;
/** For disconnection event, a bit more info is provided. */
PeerDisconnectInfo m_pdi;
public:
Event(ENetEvent* event, std::shared_ptr<STKPeer> peer);
~Event();
@ -103,7 +107,8 @@ public:
// ------------------------------------------------------------------------
/** Returns the arrival time of this event. */
double getArrivalTime() const { return m_arrival_time; }
// ------------------------------------------------------------------------
PeerDisconnectInfo getPeerDisconnectInfo() const { return m_pdi; }
// ------------------------------------------------------------------------
}; // class Event

View File

@ -37,7 +37,7 @@ void kickAllPlayers(STKHost* host)
auto peers = host->getPeers();
for (unsigned int i = 0; i < peers.size(); i++)
{
peers[i]->disconnect();
peers[i]->kick();
}
} // kickAllPlayers

View File

@ -61,7 +61,6 @@ ClientLobby::ClientLobby() : LobbyProtocol(NULL)
{
m_server_address.clear();
m_server = NULL;
setHandleDisconnections(true);
} // ClientLobby
@ -207,8 +206,6 @@ void ClientLobby::voteLaps(uint8_t player_id, uint8_t laps,
*/
void ClientLobby::leave()
{
m_server->disconnect();
m_server_address.clear();
} // leave
//-----------------------------------------------------------------------------
@ -288,6 +285,22 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
// the ProtocolManager, which might already have been deleted.
// So only signal that STKHost should exit, which will be tested
// from the main thread.
STKHost::get()->disconnectAllPeers(false/*timeout_waiting*/);
switch(event->getPeerDisconnectInfo())
{
case PDI_TIMEOUT:
STKHost::get()->setErrorMessage(
_("Server connection timed out."));
break;
case PDI_NORMAL:
STKHost::get()->setErrorMessage(
_("Server has been shut down."));
break;
case PDI_KICK:
STKHost::get()->setErrorMessage(
_("You were kicked from the server."));
break;
} // switch
STKHost::get()->requestShutdown();
return true;
} // disconnection
@ -507,8 +520,8 @@ void ClientLobby::connectionAccepted(Event* event)
uint8_t player_id = data.getUInt8();
uint8_t host_id = data.getUInt8();
irr::core::stringw name;
int bytes_read = data.decodeStringW(&name);
data.decodeStringW(&name);
NetworkPlayerProfile* profile2 =
new NetworkPlayerProfile(name, player_id, host_id);
m_game_setup->addPlayer(profile2);
@ -521,7 +534,6 @@ void ClientLobby::connectionAccepted(Event* event)
// on server and all clients.
m_game_setup->addPlayer(profile);
NetworkingLobby::getInstance()->addPlayer(profile);
m_server = event->getPeer();
m_state = CONNECTED;
if (NetworkConfig::get()->isAutoConnect())
{
@ -841,7 +853,7 @@ void ClientLobby::playerTrackVote(Event* event)
std::string track_name;
uint8_t player_id = data.getUInt8();
uint8_t number = data.getUInt8();
int N = data.decodeString(&track_name);
data.decodeString(&track_name);
m_game_setup->getRaceConfig()->setPlayerTrackVote(player_id, track_name,
number);
} // playerTrackVote

View File

@ -6,8 +6,6 @@
#include "utils/cpp2011.hpp"
#include <set>
class STKPeer;
class ClientLobby : public LobbyProtocol
{
private:
@ -31,8 +29,6 @@ private:
TransportAddress m_server_address;
STKPeer* m_server;
enum STATE
{
NONE,

View File

@ -59,6 +59,7 @@
#include <algorithm>
#include <functional>
#include <limits>
#include <random>
#include <string>
@ -320,9 +321,7 @@ void STKHost::init()
m_shutdown = false;
m_network = NULL;
m_game_setup = NULL;
m_exit_flag.clear();
m_exit_flag.test_and_set();
m_exit_timeout.store(std::numeric_limits<double>::max());
// Start with initialising ENet
// ============================
@ -358,8 +357,7 @@ STKHost::~STKHost()
delete m_game_setup;
m_game_setup = NULL;
m_peers.clear();
disconnectAllPeers(true/*timeout_waiting*/);
Network::closeLog();
stopListening();
@ -385,7 +383,6 @@ STKHost::~STKHost()
void STKHost::shutdown()
{
ProtocolManager::lock()->abort();
deleteAllPeers();
destroy();
} // shutdown
@ -624,14 +621,21 @@ GameSetup* STKHost::setupNewGame()
} // setupNewGame
//-----------------------------------------------------------------------------
/** Called when you leave a server.
/** Disconnect all connected peers.
*/
void STKHost::deleteAllPeers()
void STKHost::disconnectAllPeers(bool timeout_waiting)
{
m_peers.clear();
} // deleteAllPeers
std::lock_guard<std::mutex> lock(m_peers_mutex);
if (!m_peers.empty())
{
// Wait for at most 2 seconds for disconnect event to be generated
if (timeout_waiting)
m_exit_timeout.store(StkTime::getRealTime() + 2.0);
m_peers.clear();
}
} // disconnectAllPeers
// --------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** Sets an error message for the gui.
*/
void STKHost::setErrorMessage(const irr::core::stringw &message)
@ -644,7 +648,7 @@ void STKHost::setErrorMessage(const irr::core::stringw &message)
m_error_message = message;
} // setErrorMessage
// --------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** \brief Try to establish a connection to a given transport address.
* \param peer : The transport address which you want to connect to.
* \return True if we're successfully connected. False elseway.
@ -672,8 +676,7 @@ bool STKHost::connect(const TransportAddress& address)
*/
void STKHost::startListening()
{
m_exit_flag.clear();
m_exit_flag.test_and_set();
m_exit_timeout.store(std::numeric_limits<double>::max());
m_listening_thread = std::thread(std::bind(&STKHost::mainLoop, this));
} // startListening
@ -683,7 +686,8 @@ void STKHost::startListening()
*/
void STKHost::stopListening()
{
m_exit_flag.clear();
if (m_exit_timeout.load() == std::numeric_limits<double>::max())
m_exit_timeout.store(0.0);
if (m_listening_thread.joinable())
m_listening_thread.join();
} // stopListening
@ -736,7 +740,7 @@ void STKHost::mainLoop()
}
}
while (m_exit_flag.test_and_set())
while (m_exit_timeout.load() > StkTime::getRealTime())
{
auto sl = LobbyProtocol::get<ServerLobby>();
if (direct_socket && sl && sl->waitingForPlayers())
@ -749,21 +753,14 @@ void STKHost::mainLoop()
if (event.type == ENET_EVENT_TYPE_NONE)
continue;
auto pm = ProtocolManager::lock();
if (!pm || pm->isExiting())
{
// Don't create more event if no protocol manager or it will
// be exiting
enet_packet_destroy(event.packet);
continue;
}
Event* stk_event = NULL;
if (event.type == ENET_EVENT_TYPE_CONNECT)
{
auto stk_peer =
std::make_shared<STKPeer>(event.peer, m_network);
std::unique_lock<std::mutex> lock(m_peers_mutex);
m_peers[event.peer] = stk_peer;
lock.unlock();
stk_event = new Event(&event, stk_peer);
TransportAddress addr(event.peer->address);
Log::info("STKHost", "%s has just connected. There are "
@ -772,21 +769,36 @@ void STKHost::mainLoop()
else if (event.type == ENET_EVENT_TYPE_DISCONNECT)
{
Log::flushBuffers();
// If used a timeout waiting disconnect, exit now
if (m_exit_timeout.load() !=
std::numeric_limits<double>::max())
{
m_exit_timeout.store(0.0);
break;
}
// Use the previous stk peer so protocol can see the network
// profile and handle it for disconnection
assert(m_peers.find(event.peer) != m_peers.end());
stk_event = new Event(&event, m_peers.at(event.peer));
m_peers.erase(event.peer);
if (m_peers.find(event.peer) != m_peers.end())
{
stk_event = new Event(&event, m_peers.at(event.peer));
std::lock_guard<std::mutex> lock(m_peers_mutex);
m_peers.erase(event.peer);
}
TransportAddress addr(event.peer->address);
Log::info("STKHost", "%s has just disconnected. There are "
"now %u peers.", addr.toString().c_str(), getPeerCount());
} // ENET_EVENT_TYPE_DISCONNECT
if (!stk_event)
if (!stk_event && m_peers.find(event.peer) != m_peers.end())
{
assert(m_peers.find(event.peer) != m_peers.end());
stk_event = new Event(&event, m_peers.at(event.peer));
}
else if (!stk_event)
{
enet_packet_destroy(event.packet);
continue;
}
if (stk_event->getType() == EVENT_TYPE_MESSAGE)
{
Network::logPacket(stk_event->data(), true);
@ -802,8 +814,11 @@ void STKHost::mainLoop()
} // if message event
// notify for the event now.
pm->propagateEvent(stk_event);
auto pm = ProtocolManager::lock();
if (pm && !pm->isExiting())
pm->propagateEvent(stk_event);
else
delete stk_event;
} // while enet_host_service
} // while m_exit_flag.test_and_set()
delete direct_socket;

View File

@ -97,8 +97,8 @@ private:
* triggers a shutdown of the STKHost (and the Protocolmanager). */
std::atomic_bool m_shutdown;
/** Atomic flag used to stop this thread. */
std::atomic_flag m_exit_flag = ATOMIC_FLAG_INIT;
/** Use as a timeout to waiting a disconnect event when exiting. */
std::atomic<double> m_exit_timeout;
/** An error message, which is set by a protocol to be displayed
* in the GUI. */
@ -162,10 +162,11 @@ public:
// ------------------------------------------------------------------------
void setPublicAddress();
// ------------------------------------------------------------------------
virtual GameSetup* setupNewGame();
void deleteAllPeers();
GameSetup* setupNewGame();
// ------------------------------------------------------------------------
void disconnectAllPeers(bool timeout_waiting = false);
// ------------------------------------------------------------------------
bool connect(const TransportAddress& peer);
//-------------------------------------------------------------------------
/** Requests that the network infrastructure is to be shut down. This
* function is called from a thread, but the actual shutdown needs to be

View File

@ -44,17 +44,26 @@ STKPeer::STKPeer(ENetPeer *enet_peer, Network* network)
*/
STKPeer::~STKPeer()
{
enet_peer_disconnect(m_enet_peer, 0);
m_client_server_token = 0;
TransportAddress a(m_enet_peer->address);
if (m_enet_peer->state != ENET_PEER_STATE_CONNECTED ||
a != m_peer_address)
return;
auto lock = m_network->acquireEnetLock();
enet_peer_disconnect(m_enet_peer, PDI_NORMAL);
} // ~STKPeer
//-----------------------------------------------------------------------------
/** Disconnect from the server.
/** Kick this peer (used by server).
*/
void STKPeer::disconnect()
void STKPeer::kick()
{
enet_peer_disconnect(m_enet_peer, 0);
} // disconnect
TransportAddress a(m_enet_peer->address);
if (m_enet_peer->state != ENET_PEER_STATE_CONNECTED ||
a != m_peer_address)
return;
auto lock = m_network->acquireEnetLock();
enet_peer_disconnect(m_enet_peer, PDI_KICK);
} // kick
//-----------------------------------------------------------------------------
/** Sends a packet to this host.
@ -86,7 +95,7 @@ void STKPeer::sendPacket(NetworkString *data, bool reliable)
*/
bool STKPeer::isConnected() const
{
Log::info("STKPeer", "The peer state is %i", m_enet_peer->state);
Log::debug("STKPeer", "The peer state is %i", m_enet_peer->state);
return (m_enet_peer->state == ENET_PEER_STATE_CONNECTED);
} // isConnected

View File

@ -36,6 +36,13 @@ class NetworkPlayerProfile;
class NetworkString;
class TransportAddress;
enum PeerDisconnectInfo : unsigned int
{
PDI_TIMEOUT = 0, //!< Timeout disconnected (default in enet).
PDI_NORMAL = 1, //!< Normal disconnction with acknowledgement
PDI_KICK = 2, //!< Kick disconnection
}; // PeerDisconnectInfo
/*! \class STKPeer
* \brief Represents a peer.
* This class is used to interface the ENetPeer structure.
@ -64,11 +71,12 @@ protected:
public:
STKPeer(ENetPeer *enet_peer, Network* network);
virtual ~STKPeer();
virtual void sendPacket(NetworkString *data,
bool reliable = true);
void disconnect();
~STKPeer();
// ------------------------------------------------------------------------
void sendPacket(NetworkString *data, bool reliable = true);
// ------------------------------------------------------------------------
void kick();
// ------------------------------------------------------------------------
bool isConnected() const;
const TransportAddress& getAddress() const { return m_peer_address; }
bool isSamePeer(const STKPeer* peer) const;
@ -79,7 +87,7 @@ public:
void setClientServerToken(const uint32_t& token)
{
m_client_server_token = token;
m_token_set = true;
m_token_set = true;
} // setClientServerToken
// ------------------------------------------------------------------------
void unsetClientServerToken() { m_token_set = false; }