#include <PubSubLobby.h>
Classes | |
class | ChildEntry |
Public Member Functions | |
virtual | ~PubSubLobby () |
virtual void | initializeOverlay (int stage) |
Initializes derived-class-attributes. | |
virtual void | finishOverlay () |
collects statistical data in derived class | |
virtual void | handleUDPMessage (BaseOverlayMessage *msg) |
Processes messages from underlay. | |
virtual void | handleTimerEvent (cMessage *msg) |
virtual bool | handleRpcCall (BaseCallMessage *msg) |
virtual void | handleRpcResponse (BaseResponseMessage *msg, cPolymorphic *context, int rpcId, simtime_t rtt) |
virtual void | handleRpcTimeout (BaseCallMessage *msg, const TransportAddress &dest, cPolymorphic *context, int rpcId, const OverlayKey &destKey) |
Protected Types | |
typedef std::map < TransportAddress, ChildEntry > | PlayerMap |
typedef std::multimap< int, ChildEntry *, std::greater < int > > | PlayerRessourceMap |
Protected Member Functions | |
virtual void | handleJoin (PubSubJoinCall *joinMsg) |
virtual void | handleHelpCall (PubSubHelpCall *helpMsg) |
virtual void | handleRespCall (PubSubResponsibleNodeCall *respCall) |
virtual void | handleTakeOverResponse (PubSubTakeOverSubspaceResponse *takeOverResp) |
virtual void | handleTakeOverTimeout (PubSubTakeOverSubspaceCall *takeOverCall, const TransportAddress &oldNode) |
void | handleHelpReleaseMessage (PubSubHelpReleaseMessage *helpRMsg) |
void | replaceResponsibleNode (int subspaceId, NodeHandle respNode) |
void | replaceResponsibleNode (PubSubSubspaceId subspaceId, NodeHandle respNode) |
void | failedNode (const TransportAddress &node) |
Protected Attributes | |
int | subspaceSize |
int | numSubspaces |
std::vector< std::vector < PubSubSubspaceLobby > > | subspaces |
std::list< PubSubHelpCall * > | waitingForHelp |
PlayerMap | playerMap |
PlayerRessourceMap | playerRessourceMap |
int | numPubSubSignalingMessages |
int | pubSubSignalingMessagesSize |
Friends | |
std::ostream & | operator<< (std::ostream &o, const ChildEntry &entry) |
Definition at line 36 of file PubSubLobby.h.
typedef std::map<TransportAddress, ChildEntry> PubSubLobby::PlayerMap [protected] |
Definition at line 73 of file PubSubLobby.h.
typedef std::multimap<int, ChildEntry*, std::greater<int> > PubSubLobby::PlayerRessourceMap [protected] |
Definition at line 75 of file PubSubLobby.h.
PubSubLobby::~PubSubLobby | ( | ) | [virtual] |
Definition at line 474 of file PubSubLobby.cc.
{ }
void PubSubLobby::failedNode | ( | const TransportAddress & | node | ) | [protected] |
Definition at line 414 of file PubSubLobby.cc.
Referenced by handleTakeOverTimeout(), and handleUDPMessage().
{ if( node.isUnspecified() ) return; // Find node in playerMap PlayerMap::iterator playerIt = playerMap.find( node ); if( playerIt == playerMap.end() ){ // Player was already deleted return; } ChildEntry* respNodeEntry = &(playerIt->second); // FIXME: only for debugging if( GlobalNodeListAccess().get()->getPeerInfo( node ) ){ opp_error("Trying to delete node that's still there..."); } // check if node was responsible for a subspace set<int>::iterator dutyIt; for( dutyIt = respNodeEntry->dutySet.begin(); dutyIt != respNodeEntry->dutySet.end(); ++dutyIt ){ PubSubSubspaceId subspaceId( *dutyIt, numSubspaces ); PubSubSubspaceLobby& subspace = subspaces[subspaceId.getX()][subspaceId.getY()]; if( !subspace.getResponsibleNode().isUnspecified() && node == subspace.getResponsibleNode() ){ // remove old responsible node subspace.setResponsibleNode(NodeHandle()); // wait for the backup node to claim subspace; if timer expires, waiting-flag will be reset subspace.waitingForRespNode = true; PubSubTimer* graceTimer = new PubSubTimer("Grace timer for claiming subspace"); graceTimer->setType( PUBSUB_TAKEOVER_GRACE_TIME ); graceTimer->setSubspaceId( subspace.getId().getId() ); scheduleAt( simTime() + 5, graceTimer ); //FIXME: make it a parameter } } // delete node from backupList pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange; PlayerRessourceMap::iterator resIt; resRange = playerRessourceMap.equal_range( respNodeEntry->ressources ); for( resIt = resRange.first; resIt != resRange.second; ++resIt ){ if( resIt->second == respNodeEntry ){ playerRessourceMap.erase( resIt ); break; } } playerMap.erase( playerIt ); }
void PubSubLobby::finishOverlay | ( | ) | [virtual] |
collects statistical data in derived class
Reimplemented from BaseOverlay.
Definition at line 463 of file PubSubLobby.cc.
{ simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime); if (time < GlobalStatistics::MIN_MEASURED) return; globalStatistics->addStdDev("PubSubLobby: Sent Signaling Messages/s", numPubSubSignalingMessages / time); globalStatistics->addStdDev("PubSubLobby: Sent Signaling bytes/s", pubSubSignalingMessagesSize / time); }
void PubSubLobby::handleHelpCall | ( | PubSubHelpCall * | helpMsg | ) | [protected, virtual] |
Definition at line 226 of file PubSubLobby.cc.
Referenced by handleRpcCall().
{ // A node needs help! Give him the handle of the node with the most ressources... const NodeHandle& src = helpMsg->getSrcNode(); int subspaceId = helpMsg->getSubspaceId(); PlayerRessourceMap::iterator it; for( it = playerRessourceMap.begin(); it != playerRessourceMap.end(); ++it ){ if( it->second->handle != src && it->second->dutySet.find( subspaceId ) == it->second->dutySet.end() && it->second->ressources > 1 ){ break; } } // No suitable node found! if( it == playerRessourceMap.end() ){ waitingForHelp.push_back( helpMsg ); return; } // decrease ressources ChildEntry* child = it->second; child->ressources -= ( helpMsg->getHelpType() == PUBSUB_BACKUP ) ? 2 : 1; // FIXME: make it a parameter child->dutySet.insert( subspaceId ); playerRessourceMap.erase( it ); playerRessourceMap.insert( make_pair(child->ressources, child) ); // Send handle to requesting node PubSubHelpResponse* helpResp = new PubSubHelpResponse("Ask him to help you"); helpResp->setSubspaceId( subspaceId ); helpResp->setHelpType( helpMsg->getHelpType() ); helpResp->setNode( child->handle ); helpResp->setBitLength( PUBSUB_HELPRESPONSE_L( helpResp )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += helpResp->getByteLength() ); sendRpcResponse( helpMsg, helpResp ); }
void PubSubLobby::handleHelpReleaseMessage | ( | PubSubHelpReleaseMessage * | helpRMsg | ) | [protected] |
Definition at line 331 of file PubSubLobby.cc.
Referenced by handleUDPMessage().
{ PlayerMap::iterator playerIt = playerMap.find( helpRMsg->getNode() ); if( playerIt == playerMap.end() ){ // Player was already deleted return; } ChildEntry* nodeEntry = &(playerIt->second); // remove subspace from node's duty set nodeEntry->dutySet.erase( helpRMsg->getSubspaceId() ); // Increase node's ressources pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange; PlayerRessourceMap::iterator resIt; resRange = playerRessourceMap.equal_range( nodeEntry->ressources ); for( resIt = resRange.first; resIt != resRange.second; ++resIt ){ if( resIt->second == nodeEntry ){ playerRessourceMap.erase( resIt ); break; } } nodeEntry->ressources += 1; // FIXME: make it a parameter playerRessourceMap.insert( make_pair(nodeEntry->ressources, nodeEntry) ); }
void PubSubLobby::handleJoin | ( | PubSubJoinCall * | joinMsg | ) | [protected, virtual] |
Definition at line 138 of file PubSubLobby.cc.
Referenced by handleRpcCall().
{ // Insert node in the queue of possible backup nodes ChildEntry e; e.handle = joinMsg->getSrcNode(); e.ressources = joinMsg->getRessources(); pair<PlayerMap::iterator, bool> inserter; inserter = playerMap.insert( make_pair( e.handle, e )); ChildEntry* childEntry = &(inserter.first->second); //pair<PlayerRessourceMap::iterator, bool> rInserter; //rInserter = playerRessourceMap.insert( make_pair( e.ressources, childEntry )); PlayerRessourceMap::iterator rInserter; rInserter = playerRessourceMap.insert( make_pair( e.ressources, childEntry )); bool insertedAtBegin = rInserter == playerRessourceMap.begin(); // send answer with responsible node PubSubJoinResponse* joinResp = new PubSubJoinResponse( "Join Response"); unsigned int x = (unsigned int) (joinMsg->getPosition().x / subspaceSize); unsigned int y = (unsigned int) (joinMsg->getPosition().y / subspaceSize); PubSubSubspaceLobby& subspace = subspaces[x][y]; NodeHandle respNode = subspace.getResponsibleNode(); joinResp->setResponsibleNode( respNode ); joinResp->setBitLength( PUBSUB_JOINRESPONSE_L( joinResp )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += joinResp->getByteLength() ); sendRpcResponse( joinMsg, joinResp ); if( respNode.isUnspecified() && !subspace.waitingForRespNode) { // respNode is unknown, create new... // TODO: refactor: make a funktion out of this... PubSubTakeOverSubspaceCall* toCall = new PubSubTakeOverSubspaceCall( "Take over subspace"); toCall->setSubspacePos( Vector2D(x, y) ); ChildEntry* child = playerRessourceMap.begin()->second; toCall->setBitLength( PUBSUB_TAKEOVERSUBSPACECALL_L( toCall )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += toCall->getByteLength() ); sendUdpRpcCall( child->handle, toCall ); playerRessourceMap.erase( playerRessourceMap.begin() ); child->dutySet.insert( subspace.getId().getId() ); child->ressources-=2; // XXX FIXME: make it a parameter... if( insertedAtBegin ){ rInserter = playerRessourceMap.insert( make_pair(child->ressources, child) ); } else { playerRessourceMap.insert( make_pair(child->ressources, child) ); } subspace.waitingForRespNode = true; } // New node is out of luck: he gets to help all waiting nodes as long as he has ressources left if( waitingForHelp.size() > 0 ) { std::list<PubSubHelpCall*>::iterator it = waitingForHelp.begin(); while( it != waitingForHelp.end() ) { // Insert subspace into node's dutySet if( childEntry->dutySet.insert( (*it)->getSubspaceId() ).second ){ // If it was not already there (due to duplicate HelpCalls because of retransmissions), // decrease ressources childEntry->ressources -= ( (*it)->getHelpType() == PUBSUB_BACKUP ) ? 2 : 1; // FIXME: make it a parameter } PubSubHelpResponse* helpResp = new PubSubHelpResponse("Ask him to help you"); helpResp->setSubspaceId( (*it)->getSubspaceId() ); helpResp->setType( (*it)->getType() ); helpResp->setNode( e.handle ); helpResp->setBitLength( PUBSUB_HELPRESPONSE_L( helpResp )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += helpResp->getByteLength() ); sendRpcResponse( *it, helpResp ); waitingForHelp.erase( it++ ); if( childEntry->ressources <= 0 ) break; // FIXME: clean up duplicate calls! } // Fix ressource map entry playerRessourceMap.erase( rInserter ); playerRessourceMap.insert( make_pair(childEntry->ressources, childEntry) ); } }
void PubSubLobby::handleRespCall | ( | PubSubResponsibleNodeCall * | respCall | ) | [protected, virtual] |
Definition at line 266 of file PubSubLobby.cc.
Referenced by handleRpcCall().
{ unsigned int x = (unsigned int) respCall->getSubspacePos().x; unsigned int y = (unsigned int) respCall->getSubspacePos().y; NodeHandle respNode = subspaces[x][y].getResponsibleNode(); if( !respNode.isUnspecified() ) { PubSubSubspaceId region( x, y, numSubspaces); PubSubResponsibleNodeResponse* msg = new PubSubResponsibleNodeResponse( "ResponsibleNode Response"); msg->setResponsibleNode( respNode ); msg->setSubspaceId( region.getId() ); msg->setBitLength( PUBSUB_RESPONSIBLENODERESPONSE_L( msg )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += msg->getByteLength() ); sendRpcResponse( respCall, msg ); } else { // no responsible node for subspace known. // push call to list of waiting nodes ... PubSubSubspaceLobby& subspace = subspaces[x][y]; subspace.waitingNodes.push_back( respCall ); if (!subspace.waitingForRespNode) { // ... and ask a node to take over the subspace PubSubTakeOverSubspaceCall* msg = new PubSubTakeOverSubspaceCall( "Take over subspace"); msg->setSubspacePos( Vector2D( x, y) ); ChildEntry* child = playerRessourceMap.begin()->second; msg->setBitLength( PUBSUB_TAKEOVERSUBSPACECALL_L( msg )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += msg->getByteLength() ); sendUdpRpcCall( child->handle, msg ); playerRessourceMap.erase( playerRessourceMap.begin() ); child->dutySet.insert( subspace.getId().getId() ); // Decrease ressources. Note: the ressources are decreased by the cost of an "backup" node // The rest will be decreased when the new responsible answeres the takeover call child->ressources-=1; // FIXME: make it a parameter... playerRessourceMap.insert( make_pair(child->ressources, child) ); subspace.waitingForRespNode = true; } } }
bool PubSubLobby::handleRpcCall | ( | BaseCallMessage * | msg | ) | [virtual] |
Definition at line 96 of file PubSubLobby.cc.
{ // delegate messages RPC_SWITCH_START( msg ) RPC_DELEGATE( PubSubJoin, handleJoin ); RPC_DELEGATE( PubSubHelp, handleHelpCall ); RPC_DELEGATE( PubSubResponsibleNode, handleRespCall ); RPC_SWITCH_END( ) return RPC_HANDLED; }
void PubSubLobby::handleRpcResponse | ( | BaseResponseMessage * | msg, | |
cPolymorphic * | context, | |||
int | rpcId, | |||
simtime_t | rtt | |||
) | [virtual] |
Definition at line 108 of file PubSubLobby.cc.
{ RPC_SWITCH_START(msg); RPC_ON_RESPONSE( PubSubTakeOverSubspace ) { handleTakeOverResponse( _PubSubTakeOverSubspaceResponse ); break; } RPC_SWITCH_END( ); }
void PubSubLobby::handleRpcTimeout | ( | BaseCallMessage * | msg, | |
const TransportAddress & | dest, | |||
cPolymorphic * | context, | |||
int | rpcId, | |||
const OverlayKey & | destKey | |||
) | [virtual] |
Definition at line 120 of file PubSubLobby.cc.
{ RPC_SWITCH_START(msg) RPC_ON_CALL( PubSubTakeOverSubspace ) { handleTakeOverTimeout( _PubSubTakeOverSubspaceCall, dest ); EV << "[PubSubMMOG::handleRpcTimeout() @ " << thisNode.getIp() << " (" << thisNode.getKey().toString(16) << ")]\n" << " TakeOverSubspace RPC Call timed out: id=" << rpcId << "\n" << " msg=" << *_PubSubTakeOverSubspaceCall << endl; break; } RPC_SWITCH_END( ) }
void PubSubLobby::handleTakeOverResponse | ( | PubSubTakeOverSubspaceResponse * | takeOverResp | ) | [protected, virtual] |
Definition at line 314 of file PubSubLobby.cc.
Referenced by handleRpcResponse().
{ NodeHandle respNode = takeOverResp->getSrcNode(); unsigned int x = (unsigned int) takeOverResp->getSubspacePos().x; unsigned int y = (unsigned int) takeOverResp->getSubspacePos().y; PubSubSubspaceId region( x, y, numSubspaces); replaceResponsibleNode( region, takeOverResp->getSrcNode() ); }
void PubSubLobby::handleTakeOverTimeout | ( | PubSubTakeOverSubspaceCall * | takeOverCall, | |
const TransportAddress & | oldNode | |||
) | [protected, virtual] |
Definition at line 324 of file PubSubLobby.cc.
Referenced by handleRpcTimeout().
{ Vector2D pos = takeOverCall->getSubspacePos(); subspaces[(int) pos.x][(int) pos.y].waitingForRespNode = false; failedNode( oldNode ); }
void PubSubLobby::handleTimerEvent | ( | cMessage * | msg | ) | [virtual] |
Definition at line 67 of file PubSubLobby.cc.
{ if( PubSubTimer* timer = dynamic_cast<PubSubTimer*>(msg) ) { if( timer->getType() == PUBSUB_TAKEOVER_GRACE_TIME ){ // Grace period for subspace takeover timed out. // If noone claimed the subspace yet, the next respNode query will // trigger the selection of a new responsible node PubSubSubspaceId subspaceId(timer->getSubspaceId(), numSubspaces ); subspaces[subspaceId.getX()][subspaceId.getY()].waitingForRespNode = false; delete timer; } } }
void PubSubLobby::handleUDPMessage | ( | BaseOverlayMessage * | msg | ) | [virtual] |
Processes messages from underlay.
msg | Message from UDP |
Reimplemented from BaseOverlay.
Definition at line 81 of file PubSubLobby.cc.
{ if( PubSubFailedNodeMessage* failMsg = dynamic_cast<PubSubFailedNodeMessage*>(msg) ){ failedNode( failMsg->getFailedNode() ); delete msg; } else if( PubSubReplacementMessage* repMsg = dynamic_cast<PubSubReplacementMessage*>(msg) ){ replaceResponsibleNode( repMsg->getSubspaceId(), repMsg->getNewResponsibleNode() ); delete msg; } else if( PubSubHelpReleaseMessage* helpRMsg = dynamic_cast<PubSubHelpReleaseMessage*>(msg) ){ handleHelpReleaseMessage( helpRMsg ); delete msg; } }
void PubSubLobby::initializeOverlay | ( | int | stage | ) | [virtual] |
Initializes derived-class-attributes.
Initializes derived-class-attributes, called by BaseOverlay::initialize(). By default this method is called once. If more stages are needed one can overload numInitStages() and add more stages.
stage | the init stage |
Reimplemented from BaseOverlay.
Definition at line 39 of file PubSubLobby.cc.
{ // because of IPAddressResolver, we need to wait until interfaces are registered, // address auto-assignment takes place etc. if(stage != MIN_STAGE_OVERLAY) return; numSubspaces = par("numSubspaces"); subspaceSize = (int) ( (unsigned int) par("areaDimension") / numSubspaces); // FIXME: Inefficient, make subspace a single dimensioned array subspaces.resize( numSubspaces ); for ( int i = 0; i < numSubspaces; ++i ) { for( int ii = 0; ii < numSubspaces; ++ii ) { PubSubSubspaceId region( i, ii, numSubspaces ); subspaces[i].push_back( PubSubSubspaceLobby( region ) ); } WATCH_VECTOR( subspaces[i] ); } thisNode.setKey( OverlayKey::random() ); GlobalNodeListAccess().get()->registerPeer( thisNode ); numPubSubSignalingMessages = 0; pubSubSignalingMessagesSize = 0; WATCH( numPubSubSignalingMessages ); WATCH( pubSubSignalingMessagesSize ); WATCH_MAP( playerMap ); }
void PubSubLobby::replaceResponsibleNode | ( | int | subspaceId, | |
NodeHandle | respNode | |||
) | [protected] |
Definition at line 357 of file PubSubLobby.cc.
Referenced by handleTakeOverResponse(), and handleUDPMessage().
{ replaceResponsibleNode( PubSubSubspaceId( subspaceId, numSubspaces), respNode ); }
void PubSubLobby::replaceResponsibleNode | ( | PubSubSubspaceId | subspaceId, | |
NodeHandle | respNode | |||
) | [protected] |
Definition at line 362 of file PubSubLobby.cc.
{ // a new responsible node was found for a subspace PubSubSubspaceLobby& subspace = subspaces[subspaceId.getX()][subspaceId.getY()]; // NodeHandle oldNode = subspace.getResponsibleNode(); // set new responsible node subspace.setResponsibleNode( respNode ); subspace.waitingForRespNode = false; // decrease responsible node's ressources pair<PlayerRessourceMap::iterator, PlayerRessourceMap::iterator> resRange; PlayerRessourceMap::iterator resIt; PlayerMap::iterator plIt = playerMap.find( respNode ); if( plIt == playerMap.end() ){ // FIXME: How to react? // Best would be: reinsert node. But most probable we have two nodes that want to be // responsible, so how to avoid the resulting inconsostency? opp_error("PlayerMap inconsistent: Allegedly failed node wants to become Responsible node"); } // ChildEntry* respNodeEntry = &(plIt->second); // resRange = playerRessourceMap.equal_range( respNodeEntry->ressources ); // for( resIt = resRange.first; resIt != resRange.second; ++resIt ){ // if( resIt->second == respNodeEntry ){ // playerRessourceMap.erase( resIt ); // break; // } // } // respNodeEntry->ressources -= 2; // FIXME: make it a parameter // playerRessourceMap.insert( make_pair(respNodeEntry->ressources, respNodeEntry) ); // remove old node from backupList->he failed... // failedNode( oldNode ); // inform all waiting nodes... std::list<PubSubResponsibleNodeCall*>::iterator it; for( it = subspace.waitingNodes.begin(); it != subspace.waitingNodes.end(); ++it ) { PubSubResponsibleNodeResponse* msg = new PubSubResponsibleNodeResponse( "ResponsibleNode Response"); msg->setResponsibleNode( respNode ); msg->setSubspaceId( subspaceId.getId() ); msg->setBitLength( PUBSUB_RESPONSIBLENODERESPONSE_L( msg )); RECORD_STATS( ++numPubSubSignalingMessages; pubSubSignalingMessagesSize += msg->getByteLength() ); sendRpcResponse( *it, msg ); } subspace.waitingNodes.clear(); }
std::ostream& operator<< | ( | std::ostream & | o, | |
const ChildEntry & | entry | |||
) | [friend] |
Definition at line 31 of file PubSubLobby.cc.
{ o << "Node: " << entry.handle << " ressources: " << entry.ressources; return o; }
int PubSubLobby::numPubSubSignalingMessages [protected] |
Definition at line 90 of file PubSubLobby.h.
Referenced by finishOverlay(), handleHelpCall(), handleJoin(), handleRespCall(), initializeOverlay(), and replaceResponsibleNode().
int PubSubLobby::numSubspaces [protected] |
Definition at line 68 of file PubSubLobby.h.
Referenced by failedNode(), handleRespCall(), handleTakeOverResponse(), handleTimerEvent(), initializeOverlay(), and replaceResponsibleNode().
PlayerMap PubSubLobby::playerMap [protected] |
Definition at line 74 of file PubSubLobby.h.
Referenced by failedNode(), handleHelpReleaseMessage(), handleJoin(), initializeOverlay(), and replaceResponsibleNode().
PlayerRessourceMap PubSubLobby::playerRessourceMap [protected] |
Definition at line 76 of file PubSubLobby.h.
Referenced by failedNode(), handleHelpCall(), handleHelpReleaseMessage(), handleJoin(), and handleRespCall().
int PubSubLobby::pubSubSignalingMessagesSize [protected] |
Definition at line 91 of file PubSubLobby.h.
Referenced by finishOverlay(), handleHelpCall(), handleJoin(), handleRespCall(), initializeOverlay(), and replaceResponsibleNode().
std::vector<std::vector<PubSubSubspaceLobby> > PubSubLobby::subspaces [protected] |
Definition at line 69 of file PubSubLobby.h.
Referenced by failedNode(), handleJoin(), handleRespCall(), handleTakeOverTimeout(), handleTimerEvent(), initializeOverlay(), and replaceResponsibleNode().
int PubSubLobby::subspaceSize [protected] |
Definition at line 67 of file PubSubLobby.h.
Referenced by handleJoin(), and initializeOverlay().
std::list<PubSubHelpCall*> PubSubLobby::waitingForHelp [protected] |
Definition at line 70 of file PubSubLobby.h.
Referenced by handleHelpCall(), and handleJoin().