Protocols are now either synchronous or asynchronous. This avoids a problem

that in (rare) circumstances e.g. a message that is only handled synchronously
is deleted from the asynchronous thread (if the main thread is too slow and
a time out is reached).
This commit is contained in:
hiker
2016-01-27 10:05:25 +11:00
parent e31ce6844e
commit 892e1b58d1
6 changed files with 75 additions and 27 deletions

View File

@@ -137,12 +137,30 @@ void Protocol::sendMessageToPeersChangingToken(uint8_t type,
// ----------------------------------------------------------------------------
void Protocol::sendMessage(const NetworkString& message, bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, message, reliable);
ProtocolManager::getInstance()->sendMessage(this, message, reliable,
/*synchronous*/false);
} // sendMessage
// ----------------------------------------------------------------------------
void Protocol::sendSynchronousMessage(const NetworkString& message,
bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, message, reliable,
/*synchron*/true);
} // sendMessage
// ----------------------------------------------------------------------------
void Protocol::sendMessage(STKPeer* peer, const NetworkString& message,
bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable);
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable,
/*synchronous*/false);
} // sendMessage
// ----------------------------------------------------------------------------
void Protocol::sendSynchronousMessage(STKPeer* peer,
const NetworkString& message,
bool reliable)
{
ProtocolManager::getInstance()->sendMessage(this, peer, message, reliable,
/*synchronous*/true);
} // sendSynchronousMessage

View File

@@ -39,15 +39,16 @@ class STKPeer;
*/
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 = 0x00, //!< No protocol type assigned.
PROTOCOL_CONNECTION = 0x01, //!< Protocol that deals with client-server connection.
PROTOCOL_LOBBY_ROOM = 0x02, //!< Protocol that is used during the lobby room phase.
PROTOCOL_START_GAME = 0x03, //!< Protocol used when starting the game.
PROTOCOL_SYNCHRONIZATION = 0x04, //!<Protocol used to synchronize clocks.
PROTOCOL_KART_UPDATE = 0x05, //!< Protocol to update karts position, rotation etc...
PROTOCOL_GAME_EVENTS = 0x06, //!< Protocol to communicate the game events.
PROTOCOL_CONTROLLER_EVENTS = 0x07, //!< Protocol to transfer controller modifications
PROTOCOL_SYNCHRONOUS = 0x80, //!< Flag, indicates synchronous delivery
PROTOCOL_SILENT = 0xff //!< Used for protocols that do not subscribe to any network event.
}; // ProtocolType
// ----------------------------------------------------------------------------
@@ -128,6 +129,10 @@ public:
bool reliable = true);
void sendMessage(STKPeer* peer, const NetworkString& message,
bool reliable = true);
void sendSynchronousMessage(const NetworkString& message,
bool reliable=true);
void sendSynchronousMessage(STKPeer* peer, const NetworkString& message,
bool reliable = true);
void requestStart();
void requestPause();
void requestUnpause();

View File

@@ -131,6 +131,14 @@ void ProtocolManager::propagateEvent(Event* event)
Log::verbose("ProtocolManager", "Received event for protocols of type %d",
searched_protocol);
bool is_synchronous = false;
if(searched_protocol & PROTOCOL_SYNCHRONOUS)
{
is_synchronous = true;
// Reset synchronous flag to restore original protocol id
searched_protocol = ProtocolType(searched_protocol &
~PROTOCOL_SYNCHRONOUS );
}
std::vector<unsigned int> protocols_ids;
m_protocols.lock();
for (unsigned int i = 0; i < m_protocols.getData().size() ; i++)
@@ -155,9 +163,10 @@ void ProtocolManager::propagateEvent(Event* event)
if (protocols_ids.size() != 0)
{
EventProcessingInfo epi;
epi.m_arrival_time = (double)StkTime::getTimeSinceEpoch();
epi.m_event = event;
epi.m_protocols_ids = protocols_ids;
epi.m_arrival_time = (double)StkTime::getTimeSinceEpoch();
epi.m_is_synchronous = is_synchronous;
epi.m_event = event;
epi.m_protocols_ids = protocols_ids;
// Add the event to the queue. After the event is handled
// its memory will be freed.
m_events_to_process.getData().push_back(epi);
@@ -175,20 +184,29 @@ void ProtocolManager::propagateEvent(Event* event)
// ----------------------------------------------------------------------------
void ProtocolManager::sendMessage(Protocol* sender, const NetworkString& message,
bool reliable)
bool reliable, bool send_synchronously)
{
NetworkString new_message(1+message.size());
new_message.ai8(sender->getProtocolType()); // add one byte to add protocol type
ProtocolType type = sender->getProtocolType();
// Set flag if the message must be handled synchronously on arrivat
if(send_synchronously)
type = ProtocolType(type | PROTOCOL_SYNCHRONOUS);
new_message.ai8(type); // add one byte to add protocol type
new_message += message;
STKHost::get()->sendMessage(new_message, reliable);
} // sendMessage
// ----------------------------------------------------------------------------
void ProtocolManager::sendMessage(Protocol* sender, STKPeer* peer,
const NetworkString& message, bool reliable)
const NetworkString& message, bool reliable,
bool send_synchronously)
{
NetworkString new_message(1+message.size());
new_message.ai8(sender->getProtocolType()); // add one byte to add protocol type
ProtocolType type = sender->getProtocolType();
// Set flag if the message must be handled synchronously on arrivat
if(send_synchronously)
type = ProtocolType(type | PROTOCOL_SYNCHRONOUS);
new_message.ai8(type); // add one byte to add protocol type
new_message += message;
peer->sendPacket(new_message, reliable);
} // sendMessage
@@ -418,6 +436,8 @@ void ProtocolManager::update()
int offset = 0;
for (int i = 0; i < size; i++)
{
// Don't handle asynchronous events here.
if(!m_events_to_process.getData()[i+offset].m_is_synchronous) continue;
bool result = sendEvent(&m_events_to_process.getData()[i+offset], true);
if (result)
{
@@ -455,6 +475,8 @@ void ProtocolManager::asynchronousUpdate()
int offset = 0;
for (int i = 0; i < size; i++)
{
// Don't handle synchronous events here.
if(m_events_to_process.getData()[i+offset].m_is_synchronous) continue;
bool result = sendEvent(&m_events_to_process.getData()[i+offset], false);
if (result)
{

View File

@@ -95,7 +95,10 @@ struct EventProcessingInfo
* sent to. */
std::vector<unsigned int> m_protocols_ids;
} EventProcessingInfo;
/** Indicates if this received message must be handled synchronously or
* asynchronously. */
bool m_is_synchronous;
}; // EventProcessingInfo
// ============================================================================
/** \class ProtocolManager
@@ -120,10 +123,12 @@ class ProtocolManager : public AbstractSingleton<ProtocolManager>,
virtual void propagateEvent(Event* event);
virtual void sendMessage(Protocol* sender,
const NetworkString& message,
bool reliable = true);
bool reliable = true,
bool send_synchronously = false);
virtual void sendMessage(Protocol* sender, STKPeer* peer,
const NetworkString& message,
bool reliable = true);
bool reliable = true,
bool send_synchronously = false);
virtual void sendMessageExcept(Protocol* sender, STKPeer* peer,
const NetworkString& message,
bool reliable = true);

View File

@@ -180,9 +180,6 @@ bool ClientLobbyRoomProtocol::notifyEventAsynchronous(Event* event)
const NetworkString &data = event->data();
assert(data.size()); // assert that data isn't empty
uint8_t message_type = data[0];
if (message_type == LE_KART_SELECTION_UPDATE ||
message_type == LE_RACE_FINISHED )
return false; // don't treat the event
event->removeFront(1);
Log::info("ClientLobbyRoomProtocol", "Asynchronous message of type %d",

View File

@@ -348,9 +348,9 @@ void ServerLobbyRoomProtocol::checkRaceFinished()
for (unsigned int i = 0; i < peers.size(); i++)
{
NetworkString ns(6);
ns.ai8(0x06).ai8(4).ai32(peers[i]->getClientServerToken());
ns.ai8(LE_RACE_FINISHED).ai8(4).ai32(peers[i]->getClientServerToken());
NetworkString total = ns + queue;
sendMessage(peers[i], total, true);
sendSynchronousMessage(peers[i], total, true);
}
Log::info("ServerLobbyRoomProtocol", "End of game message sent");
m_in_race = false;
@@ -563,7 +563,8 @@ void ServerLobbyRoomProtocol::kartSelectionRequested(Event* event)
uint8_t player_id = peer->getPlayerProfile()->getGlobalPlayerId();
answer.ai8(LE_KART_SELECTION_UPDATE).ai8(1).ai8(player_id)
.encodeString(kart_name);
sendMessage(answer);
// This message must be handled synchronously on the client.
sendSynchronousMessage(answer);
m_setup->setPlayerKart(player_id, kart_name);
} // kartSelectionRequested