PubSubMMOG.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include <NotifierConsts.h>
00025 
00026 #include "PubSubMMOG.h"
00027 
00028 #include "GlobalNodeListAccess.h"
00029 #include <GlobalStatistics.h>
00030 #include <BootstrapList.h>
00031 
00032 Define_Module(PubSubMMOG);
00033 
00034 using namespace std;
00035 
00036 void PubSubMMOG::initializeOverlay(int stage)
00037 {
00038     // because of IPAddressResolver, we need to wait until interfaces are registered,
00039     // address auto-assignment takes place etc.
00040     if(stage != MIN_STAGE_OVERLAY) return;
00041 
00042     state = INIT;
00043     setBootstrapedIcon();
00044     // TODO: use BootstrapList instead (but this currently preferes
00045     //       nodes from the same partition)
00046     lobbyServer = globalNodeList->getBootstrapNode();
00047 
00048     joinTimer = new cMessage("join timer");
00049     simtime_t joinTime = ceil(simTime() + (simtime_t) par("joinDelay"));
00050     scheduleAt( joinTime, joinTimer );
00051 
00052     movementRate = par("movementRate");
00053     eventDeliveryTimer = new PubSubTimer("event delivery timer");
00054     eventDeliveryTimer->setType( PUBSUB_EVENTDELIVERY );
00055     scheduleAt( joinTime + 1.0/(2*movementRate), eventDeliveryTimer );
00056 
00057     numSubspaces = par("numSubspaces");
00058     subspaceSize = (int) ( (unsigned int) par("areaDimension") / numSubspaces);
00059     thisNode.setKey( OverlayKey::random() );
00060 
00061     maxChildren = par("maxChildren");
00062     PubSubSubspaceResponsible::maxChildren = maxChildren;
00063 
00064     AOIWidth = par("AOIWidth");
00065     maxMoveDelay = par("maxMoveDelay");
00066 
00067     parentTimeout = par("parentTimeout");
00068     heartbeatTimer = new PubSubTimer("HeartbeatTimer");
00069     heartbeatTimer->setType( PUBSUB_HEARTBEAT );
00070     startTimer( heartbeatTimer );
00071     childPingTimer = new PubSubTimer("ChildPingTimer");
00072     childPingTimer->setType( PUBSUB_CHILDPING );
00073     startTimer( childPingTimer );
00074 
00075     allowOldMoveMessages  = par("allowOldMoveMessages");
00076 
00077     numEventsWrongTimeslot = numEventsCorrectTimeslot = 0;
00078     numPubSubSignalingMessages = 0;
00079     pubSubSignalingMessagesSize = 0;
00080     numMoveMessages = 0;
00081     moveMessagesSize = 0;
00082     numMoveListMessages = 0;
00083     moveListMessagesSize = 0;
00084     respMoveListMessagesSize = 0;
00085     lostMovementLists = 0;
00086     receivedMovementLists = 0;
00087     WATCH( numPubSubSignalingMessages );
00088     WATCH( pubSubSignalingMessagesSize );
00089     WATCH( numMoveMessages );
00090     WATCH( moveMessagesSize );
00091     WATCH( numMoveListMessages );
00092     WATCH( moveListMessagesSize );
00093     WATCH( numEventsWrongTimeslot );
00094     WATCH( numEventsCorrectTimeslot );
00095     WATCH( lostMovementLists );
00096     WATCH( receivedMovementLists );
00097     WATCH_LIST( subscribedSubspaces );
00098     WATCH_MAP( responsibleSubspaces );
00099     WATCH_MAP( backupSubspaces );
00100     WATCH_MAP( intermediateSubspaces );
00101 }
00102 
00103 bool PubSubMMOG::handleRpcCall(BaseCallMessage* msg)
00104 {
00105     // delegate messages
00106     RPC_SWITCH_START( msg )
00107     RPC_DELEGATE( PubSubSubscription, handleSubscriptionCall );
00108     RPC_DELEGATE( PubSubTakeOverSubspace, handleTakeOver );
00109     RPC_DELEGATE( PubSubBackup, handleBackupCall );
00110     RPC_DELEGATE( PubSubIntermediate, handleIntermediateCall );
00111     RPC_DELEGATE( PubSubAdoptChild, handleAdoptChildCall );
00112     RPC_DELEGATE( PubSubPing, handlePingCall );
00113     RPC_SWITCH_END( )
00114 
00115     return RPC_HANDLED;
00116 
00117 }
00118 
00119 void PubSubMMOG::handleRpcResponse(BaseResponseMessage *msg,
00120                                    cPolymorphic* context, int rpcId,
00121                                    simtime_t rtt)
00122 {
00123     RPC_SWITCH_START(msg);
00124     RPC_ON_RESPONSE( PubSubJoin ) {
00125         handleJoinResponse( _PubSubJoinResponse );
00126         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00127             << " (" << thisNode.getKey().toString(16) << ")]\n"
00128             << "    Received a PubSubJoin RPC Response: id=" << rpcId << "\n"
00129             << "    msg=" << *_PubSubJoinResponse << " rtt=" << rtt
00130             << endl;
00131         break;
00132     }
00133     RPC_ON_RESPONSE( PubSubSubscription ) {
00134         handleSubscriptionResponse( _PubSubSubscriptionResponse );
00135         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00136             << " (" << thisNode.getKey().toString(16) << ")]\n"
00137             << "    Received a PubSubSubscription RPC Response: id=" << rpcId << "\n"
00138             << "    msg=" << *_PubSubSubscriptionResponse << " rtt=" << rtt
00139             << endl;
00140         break;
00141     }
00142     RPC_ON_RESPONSE( PubSubResponsibleNode ) {
00143         handleResponsibleNodeResponse( _PubSubResponsibleNodeResponse );
00144         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00145             << " (" << thisNode.getKey().toString(16) << ")]\n"
00146             << "    Received a PubSubResponsibleNode RPC Response: id=" << rpcId << "\n"
00147             << "    msg=" << *_PubSubResponsibleNodeResponse << " rtt=" << rtt
00148             << endl;
00149         break;
00150     }
00151     RPC_ON_RESPONSE( PubSubHelp ) {
00152         handleHelpResponse( _PubSubHelpResponse );
00153         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00154             << " (" << thisNode.getKey().toString(16) << ")]\n"
00155             << "    Received a PubSubHelp RPC Response: id=" << rpcId << "\n"
00156             << "    msg=" << *_PubSubHelpResponse << " rtt=" << rtt
00157             << endl;
00158         break;
00159     }
00160     RPC_ON_RESPONSE( PubSubBackup ) {
00161         handleBackupResponse( _PubSubBackupResponse );
00162         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00163             << " (" << thisNode.getKey().toString(16) << ")]\n"
00164             << "    Received a PubSubBackup RPC Response: id=" << rpcId << "\n"
00165             << "    msg=" << *_PubSubBackupResponse << " rtt=" << rtt
00166             << endl;
00167         break;
00168     }
00169     RPC_ON_RESPONSE( PubSubIntermediate ) {
00170         handleIntermediateResponse( _PubSubIntermediateResponse );
00171         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00172             << " (" << thisNode.getKey().toString(16) << ")]\n"
00173             << "    Received a PubSubIntermediate RPC Response: id=" << rpcId << "\n"
00174             << "    msg=" << *_PubSubIntermediateResponse << " rtt=" << rtt
00175             << endl;
00176         break;
00177     }
00178     RPC_ON_RESPONSE( PubSubAdoptChild ) {
00179         handleAdoptChildResponse( _PubSubAdoptChildResponse );
00180         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00181             << " (" << thisNode.getKey().toString(16) << ")]\n"
00182             << "    Received a PubSubAdoptChild RPC Response: id=" << rpcId << "\n"
00183             << "    msg=" << *_PubSubAdoptChildResponse << " rtt=" << rtt
00184             << endl;
00185         break;
00186     }
00187     RPC_ON_RESPONSE( PubSubPing ) {
00188         handlePingResponse( _PubSubPingResponse );
00189         EV << "[PubSubMMOG::handleRpcResponse() @ " << thisNode.getAddress()
00190             << " (" << thisNode.getKey().toString(16) << ")]\n"
00191             << "    Received a PubSubPing RPC Response: id=" << rpcId << "\n"
00192             << "    msg=" << *_PubSubPingResponse << " rtt=" << rtt
00193             << endl;
00194         break;
00195     }
00196     RPC_SWITCH_END( );
00197 }
00198 
00199 void PubSubMMOG::handleRpcTimeout (BaseCallMessage *msg,
00200                                    const TransportAddress &dest,
00201                                    cPolymorphic* context, int rpcId,
00202                                    const OverlayKey &destKey)
00203 {
00204     RPC_SWITCH_START(msg)
00205     RPC_ON_CALL( PubSubBackup ) {
00206         handleBackupCallTimeout( _PubSubBackupCall, dest );
00207         EV << "[PubSubMMOG::handleRpcTimeout() @ " << thisNode.getAddress()
00208            << " (" << thisNode.getKey().toString(16) << ")]\n"
00209            << "    Backup RPC Call timed out: id=" << rpcId << "\n"
00210            << "    msg=" << *_PubSubBackupCall
00211            << "    oldNode=" << dest
00212            << endl;
00213         break;
00214     }
00215     RPC_ON_CALL( PubSubPing ) {
00216         handlePingCallTimeout( _PubSubPingCall, dest );
00217         EV << "[PubSubMMOG::handleRpcTimeout() @ " << thisNode.getAddress()
00218            << " (" << thisNode.getKey().toString(16) << ")]\n"
00219            << "    Ping RPC Call timed out: id=" << rpcId << "\n"
00220            << "    msg=" << *_PubSubPingCall
00221            << "    oldNode=" << dest
00222            << endl;
00223         break;
00224     }
00225     RPC_ON_CALL( PubSubSubscription ) {
00226         handleSubscriptionCallTimeout( _PubSubSubscriptionCall, dest );
00227         EV << "[PubSubMMOG::handleRpcTimeout() @ " << thisNode.getAddress()
00228            << " (" << thisNode.getKey().toString(16) << ")]\n"
00229            << "    Subscription RPC Call timed out: id=" << rpcId << "\n"
00230            << "    msg=" << *_PubSubSubscriptionCall
00231            << "    oldNode=" << dest
00232            << endl;
00233         break;
00234     }
00235     RPC_SWITCH_END( )
00236 
00237     // FIXME:
00238     //   AdoptCall missing!
00239     //   IntermediateCall missing!
00240     //   (ResponsibleNodeCall missing)
00241     //   (HelpCall missing)
00242 }
00243 
00244 void PubSubMMOG::handleUDPMessage(BaseOverlayMessage* msg)
00245 {
00246     if( PubSubMoveListMessage* moveMsg = dynamic_cast<PubSubMoveListMessage*>(msg) ){
00247         handleMoveListMessage( moveMsg );
00248         delete moveMsg;
00249     } else if( PubSubMoveMessage* moveMsg = dynamic_cast<PubSubMoveMessage*>(msg) ){
00250         handleMoveMessage( moveMsg );
00251     } else if( PubSubUnsubscriptionMessage* unsMsg = dynamic_cast<PubSubUnsubscriptionMessage*>(msg) ){
00252         handleUnsubscriptionMessage( unsMsg );
00253         delete unsMsg;
00254     } else if( PubSubNodeLeftMessage* leftMsg = dynamic_cast<PubSubNodeLeftMessage*>(msg) ){
00255         handleNodeLeftMessage( leftMsg );
00256         delete leftMsg;
00257     } else if( PubSubReplacementMessage* replaceMsg = dynamic_cast<PubSubReplacementMessage*>(msg) ){
00258         handleReplacementMessage( replaceMsg );
00259         delete replaceMsg;
00260     } else if( PubSubBackupSubscriptionMessage* backupMsg = dynamic_cast<PubSubBackupSubscriptionMessage*>(msg) ){
00261         handleSubscriptionBackup( backupMsg );
00262         delete backupMsg;
00263     } else if( PubSubBackupUnsubscribeMessage* backupMsg = dynamic_cast<PubSubBackupUnsubscribeMessage*>(msg) ){
00264         handleUnsubscribeBackup( backupMsg );
00265         delete backupMsg;
00266     } else if( PubSubBackupIntermediateMessage* backupMsg = dynamic_cast<PubSubBackupIntermediateMessage*>(msg) ){
00267         handleIntermediateBackup( backupMsg );
00268         delete backupMsg;
00269     } else if( PubSubReleaseIntermediateMessage* releaseMsg = dynamic_cast<PubSubReleaseIntermediateMessage*>(msg) ){
00270         handleReleaseIntermediate( releaseMsg );
00271         delete releaseMsg;
00272     }
00273 }
00274 
00275 void PubSubMMOG::handleTimerEvent(cMessage* msg)
00276 {
00277     if( PubSubTimer* timer = dynamic_cast<PubSubTimer*>(msg) ) {
00278         switch( timer->getType() ) {
00279             case PUBSUB_HEARTBEAT:
00280                 sendHearbeatToChildren();
00281                 startTimer( timer );
00282                 break;
00283             case PUBSUB_CHILDPING:
00284                 sendPingToChildren();
00285                 startTimer( timer );
00286                 break;
00287             case PUBSUB_PARENT_TIMEOUT:
00288                 handleParentTimeout( timer );
00289                 break;
00290             case PUBSUB_EVENTDELIVERY:
00291                 publishEvents();
00292                 startTimer( timer );
00293                 break;
00294         }
00295     } else if( msg == joinTimer ) {
00296         // send a fake ready message to app to get initial position
00297         // Note: This is not consistent to the paper, where the lobby server
00298         // positions player. But it is needed for consistency with other MMOG protocols
00299         CompReadyMessage* msg = new CompReadyMessage("fake READY");
00300         msg->setReady(true);
00301         msg->setComp(getThisCompType());
00302         send( msg, "appOut");
00303         delete joinTimer;
00304         joinTimer = NULL;
00305         // send initial AOI size to the application
00306         // Note: This is not consistent to the paper.
00307         // But it is needed for this nodes movement generation within the application layer.
00308         GameAPIResizeAOIMessage* gameMsg = new GameAPIResizeAOIMessage("RESIZE_AOI");
00309         gameMsg->setCommand(RESIZE_AOI);
00310         gameMsg->setAOIsize(AOIWidth);
00311         send( gameMsg, "appOut");
00312     }
00313 }
00314 
00315 void PubSubMMOG::handleAppMessage(cMessage* msg)
00316 {
00317     if( GameAPIPositionMessage *posMsg = dynamic_cast<GameAPIPositionMessage*>(msg) ) {
00318         if( state == READY ) {
00319             handleMove( posMsg );
00320         } else if ( state == JOINING ) {
00321             // We are not connected to our responsible node, inform app
00322             CompReadyMessage* msg = new CompReadyMessage("Overlay not READY!");
00323             msg->setReady(false);
00324             msg->setComp(getThisCompType());
00325             send( msg, "appOut");
00326         } else if ( state == INIT ) {
00327             // This is only called for the first MOVE message
00328             // Trigger login
00329             PubSubJoinCall* joinMsg = new PubSubJoinCall("Login");
00330             joinMsg->setPosition( posMsg->getPosition() );
00331             // FIXME: Ressource handling not yet supported!
00332             joinMsg->setRessources( 4 );
00333             sendUdpRpcCall( lobbyServer, joinMsg );
00334 
00335             state = JOINING;
00336             setBootstrapedIcon();
00337 
00338             // tell app to wait until login is confirmed...
00339             CompReadyMessage* readyMsg = new CompReadyMessage("Overlay not READY!");
00340             readyMsg->setReady(false);
00341             readyMsg->setComp(getThisCompType());
00342             send( readyMsg, "appOut");
00343 
00344             currentRegionX = (unsigned int) (posMsg->getPosition().x/subspaceSize);
00345             currentRegionY = (unsigned int) (posMsg->getPosition().y/subspaceSize);
00346         }
00347         delete msg;
00348     }
00349 }
00350 
00351 void PubSubMMOG::handleSubscriptionResponse( PubSubSubscriptionResponse* subResp )
00352 {
00353     if( subResp->getFailed() ) {
00354         // TODO: get new resp node...
00355     } else {
00356         if( state != READY ){
00357             state = READY;
00358             setBootstrapedIcon();
00359             CompReadyMessage* readyMsg = new CompReadyMessage("Overlay READY!");
00360             readyMsg->setReady(true);
00361             readyMsg->setComp(getThisCompType());
00362             sendDelayed( readyMsg, ceil(simTime()) - simTime(), "appOut" );
00363         }
00364     }
00365 }
00366 
00367 void PubSubMMOG::handleJoinResponse( PubSubJoinResponse* joinResp )
00368 {
00369     state = JOINING;
00370     setBootstrapedIcon();
00371     PubSubSubspaceId region( currentRegionX, currentRegionY, numSubspaces);
00372 
00373     NodeHandle respNode = joinResp->getResponsibleNode();
00374     PubSubSubspace sub(region);
00375     sub.setResponsibleNode( respNode );
00376     subscribedSubspaces.push_back( sub );
00377     if( respNode.isUnspecified() ) {
00378         PubSubResponsibleNodeCall* respCall = new PubSubResponsibleNodeCall("Request Responsible NodeHandle");
00379         respCall->setSubspacePos( Vector2D(currentRegionX, currentRegionY) );
00380         respCall->setBitLength( PUBSUB_RESPONSIBLENODECALL_L( respCall ) );
00381         RECORD_STATS(
00382                 ++numPubSubSignalingMessages;
00383                 pubSubSignalingMessagesSize+= respCall->getByteLength()
00384                 );
00385         sendUdpRpcCall( lobbyServer, respCall, NULL, 5, 5 ); // FIXME: Make it a parameter...
00386     } else {
00387         PubSubSubscriptionCall* subCall = new PubSubSubscriptionCall("JoinSubspace");
00388         subCall->setSubspaceId( region.getId() );
00389         subCall->setBitLength( PUBSUB_SUBSCRIPTIONCALL_L( subCall ));
00390         RECORD_STATS(
00391                 ++numPubSubSignalingMessages;
00392                 pubSubSignalingMessagesSize+= subCall->getByteLength()
00393                 );
00394         sendUdpRpcCall( respNode, subCall );
00395     }
00396 }
00397 
00398 void PubSubMMOG::handleResponsibleNodeResponse( PubSubResponsibleNodeResponse* subResp )
00399 {
00400     int subspaceId = subResp->getSubspaceId();
00401     NodeHandle respNode = subResp->getResponsibleNode();
00402 
00403     std::list<PubSubSubspace>::iterator it = subscribedSubspaces.begin();
00404     while( it != subscribedSubspaces.end() ) {
00405         if( it->getId().getId() == subspaceId) break;
00406         ++it;
00407     }
00408     if( it != subscribedSubspaces.end() ) {
00409         it->setResponsibleNode( respNode );
00410 
00411         PubSubSubscriptionCall* subCall = new PubSubSubscriptionCall("JoinSubspace");
00412         subCall->setSubspaceId( subspaceId );
00413         subCall->setBitLength( PUBSUB_SUBSCRIPTIONCALL_L( subCall ));
00414         RECORD_STATS(
00415                 ++numPubSubSignalingMessages;
00416                 pubSubSignalingMessagesSize+= subCall->getByteLength()
00417                 );
00418         sendUdpRpcCall( respNode, subCall );
00419     }
00420 }
00421 
00422 void PubSubMMOG::handleUnsubscriptionMessage( PubSubUnsubscriptionMessage* unsMsg )
00423 {
00424     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
00425     it = responsibleSubspaces.find( PubSubSubspaceId(unsMsg->getSubspaceId(), numSubspaces) );
00426 
00427     if( it != responsibleSubspaces.end() ) {
00428         unsubscribeChild( unsMsg->getSrc(), it->second );
00429     }
00430 }
00431 
00432 void PubSubMMOG::handleNodeLeftMessage( PubSubNodeLeftMessage* leftMsg )
00433 {
00434     std::map<PubSubSubspaceId, PubSubSubspaceIntermediate>::iterator it;
00435     it = intermediateSubspaces.find( PubSubSubspaceId(leftMsg->getSubspaceId(), numSubspaces) );
00436 
00437     if( it == intermediateSubspaces.end() ) return;
00438 
00439     it->second.removeChild( leftMsg->getNode() );
00440 }
00441 
00442 void PubSubMMOG::handleSubscriptionCall( PubSubSubscriptionCall* subCall )
00443 {
00444     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
00445     it = responsibleSubspaces.find( PubSubSubspaceId(subCall->getSubspaceId(), numSubspaces) );
00446 
00447     PubSubBackupSubscriptionMessage* backupMsg = 0;
00448     PubSubSubscriptionResponse* resp;
00449     if( it == responsibleSubspaces.end() ) {
00450         resp = new PubSubSubscriptionResponse("Subscription failed");
00451         resp->setFailed( true );
00452     } else {
00453         resp = new PubSubSubscriptionResponse("Subscription successful");
00454         backupMsg = new PubSubBackupSubscriptionMessage("Backup: new subscription");
00455         backupMsg->setSubspaceId( subCall->getSubspaceId() );
00456         backupMsg->setChild( subCall->getSrcNode() );
00457 
00458         if( it->second.addChild( subCall->getSrcNode() )) {
00459             // We have still room for the child
00460             backupMsg->setParent( thisNode );
00461         } else {
00462             // Child has to go to an intermediate node...
00463             if( PubSubSubspaceResponsible::IntermediateNode* iNode = it->second.getNextFreeIntermediate() ){
00464                 // find intermediate node with free slots
00465                 PubSubAdoptChildCall* adoptCall = new PubSubAdoptChildCall("Adopt child");
00466                 adoptCall->setChild( subCall->getSrcNode() );
00467                 adoptCall->setSubspaceId( subCall->getSubspaceId() );
00468                 adoptCall->setBitLength( PUBSUB_ADOPTCHILDCALL_L( adoptCall ));
00469                 sendUdpRpcCall( iNode->node, adoptCall );
00470                 RECORD_STATS(
00471                         ++numPubSubSignalingMessages;
00472                         pubSubSignalingMessagesSize+= adoptCall->getByteLength()
00473                         );
00474                 iNode->waitingChildren++;
00475             } else {
00476                 // no free slots available, create new intermediate node
00477                 // FIXME: when getting two subscriptions at once, we're requesting too many intermediates
00478                 PubSubHelpCall* helpCall = new PubSubHelpCall("I need an intermediate node");
00479                 helpCall->setHelpType( PUBSUB_INTERMEDIATE );
00480                 helpCall->setSubspaceId( subCall->getSubspaceId() );
00481                 helpCall->setBitLength( PUBSUB_HELPCALL_L( helpCall ));
00482                 sendUdpRpcCall( lobbyServer, helpCall );
00483                 RECORD_STATS(
00484                         ++numPubSubSignalingMessages;
00485                         pubSubSignalingMessagesSize+= helpCall->getByteLength()
00486                         );
00487             }
00488         }
00489     }
00490     resp->setBitLength( PUBSUB_SUBSCRIPTIONRESPONSE_L( resp ));
00491     sendRpcResponse( subCall, resp );
00492     RECORD_STATS(
00493             ++numPubSubSignalingMessages;
00494             pubSubSignalingMessagesSize+= resp->getByteLength()
00495             );
00496 
00497     if( it == responsibleSubspaces.end() ) return;
00498 
00499 // FIXME: just for testing
00500 PubSubSubspaceResponsible& subspace = it->second;
00501 int iii = subspace.getTotalChildrenCount();
00502 subspace.fixTotalChildrenCount();
00503 if( iii != subspace.getTotalChildrenCount() ){
00504     opp_error("Huh?");
00505 }
00506 
00507     if( !it->second.getBackupNode().isUnspecified() ){
00508         backupMsg->setBitLength( PUBSUB_BACKUPSUBSCRIPTION_L( backupMsg ));
00509         RECORD_STATS(
00510                 ++numPubSubSignalingMessages;
00511                 pubSubSignalingMessagesSize+= backupMsg->getByteLength()
00512                 );
00513         sendMessageToUDP( it->second.getBackupNode(), backupMsg );
00514     } else {
00515         delete backupMsg;
00516     }
00517 }
00518 
00519 void PubSubMMOG::handleTakeOver( PubSubTakeOverSubspaceCall* toCall )
00520 {
00521     PubSubSubspaceId region((int) toCall->getSubspacePos().x, (int) toCall->getSubspacePos().y, numSubspaces);
00522 
00523     takeOverNewSubspace( region );
00524 
00525     PubSubTakeOverSubspaceResponse* toResp = new PubSubTakeOverSubspaceResponse("Accept subspace responsibility");
00526     toResp->setSubspacePos( toCall->getSubspacePos() );
00527     toResp->setBitLength( PUBSUB_TAKEOVERSUBSPACERESPONSE_L( toResp ));
00528     RECORD_STATS(
00529             ++numPubSubSignalingMessages;
00530             pubSubSignalingMessagesSize+= toResp->getByteLength()
00531             );
00532     sendRpcResponse( toCall, toResp );
00533 }
00534 
00535 void PubSubMMOG::receiveChangeNotification(int category, const cPolymorphic *details)
00536 {
00537     if(category == NF_OVERLAY_NODE_GRACEFUL_LEAVE && state == READY) {
00538     }
00539 }
00540 
00541 void PubSubMMOG::handleMove( GameAPIPositionMessage* posMsg )
00542 {
00543     currentRegionX = (unsigned int) (posMsg->getPosition().x/subspaceSize);
00544     currentRegionY = (unsigned int) (posMsg->getPosition().y/subspaceSize);
00545 
00546     PubSubSubspaceId region( currentRegionX, currentRegionY, numSubspaces);
00547 
00548     set<PubSubSubspaceId> expectedRegions;
00549     int minX = (int) ((posMsg->getPosition().x - AOIWidth)/subspaceSize);
00550     if( minX < 0 ) minX = 0;
00551     int maxX = (int) ((posMsg->getPosition().x + AOIWidth)/subspaceSize);
00552     if( maxX >= numSubspaces ) maxX = numSubspaces -1;
00553     int minY = (int) ((posMsg->getPosition().y - AOIWidth)/subspaceSize);
00554     if( minY < 0 ) minY = 0;
00555     int maxY = (int) ((posMsg->getPosition().y + AOIWidth)/subspaceSize);
00556     if( maxY >= numSubspaces ) maxY = numSubspaces -1;
00557 
00558     // FIXME: make parameter: unsubscription size
00559     int minUnsubX = (int) ((posMsg->getPosition().x - 1.5*AOIWidth)/subspaceSize);
00560     if( minUnsubX < 0 ) minUnsubX = 0;
00561     int maxUnsubX = (int) ((posMsg->getPosition().x + 1.5*AOIWidth)/subspaceSize);
00562     if( maxUnsubX >= numSubspaces ) maxUnsubX = numSubspaces -1;
00563     int minUnsubY = (int) ((posMsg->getPosition().y - 1.5*AOIWidth)/subspaceSize);
00564     if( minUnsubY < 0 ) minUnsubY = 0;
00565     int maxUnsubY = (int) ((posMsg->getPosition().y + 1.5+AOIWidth)/subspaceSize);
00566     if( maxUnsubY >= numSubspaces ) maxUnsubY = numSubspaces -1;
00567 
00568     for( int x = minX; x <= maxX; ++x ){
00569         for( int y = minY; y <= maxY; ++y ){
00570             expectedRegions.insert( PubSubSubspaceId( x, y, numSubspaces ));
00571         }
00572     }
00573 
00574     list<PubSubSubspace>::iterator subIt = subscribedSubspaces.begin();
00575     PubSubSubspace* subspace = NULL;
00576     while( subIt != subscribedSubspaces.end() ){
00577         if( subIt->getId() == region ){
00578             subspace = &*subIt;
00579         }
00580         expectedRegions.erase( subIt->getId() );
00581 
00582         // unsubscribe region if to far away
00583         if( subIt->getId().getX() < minX || subIt->getId().getX() > maxX ||
00584                 subIt->getId().getY() < minY || subIt->getId().getY() > maxY ){
00585             if( !subIt->getResponsibleNode().isUnspecified() ){
00586                 PubSubUnsubscriptionMessage* unsubMsg = new PubSubUnsubscriptionMessage("Unsubscribe from subspace");
00587                 unsubMsg->setSubspaceId( subIt->getId().getId() );
00588                 unsubMsg->setSrc( thisNode );
00589                 unsubMsg->setBitLength( PUBSUB_UNSUBSCRIPTION_L( unsubMsg ));
00590                 RECORD_STATS(
00591                         ++numPubSubSignalingMessages;
00592                         pubSubSignalingMessagesSize+= unsubMsg->getByteLength()
00593                         );
00594                 sendMessageToUDP( subIt->getResponsibleNode(), unsubMsg );
00595             }
00596             // Erase subspace from subscribedList and increase iterator
00597             subscribedSubspaces.erase( subIt++ );
00598         } else {
00599             ++subIt;
00600         }
00601     }
00602 
00603     // if any "near" region is not yet subscribed, subscribe
00604     for( set<PubSubSubspaceId>::iterator regionIt = expectedRegions.begin(); regionIt != expectedRegions.end(); ++regionIt ){
00605         PubSubSubspace sub( *regionIt );
00606         subscribedSubspaces.push_back( sub );
00607         PubSubResponsibleNodeCall* respCall = new PubSubResponsibleNodeCall("Request Responsible NodeHandle");
00608         respCall->setSubspacePos( Vector2D(regionIt->getX(), regionIt->getY()) );
00609         respCall->setBitLength( PUBSUB_RESPONSIBLENODECALL_L( respCall ));
00610         RECORD_STATS(
00611                 ++numPubSubSignalingMessages;
00612                 pubSubSignalingMessagesSize+= respCall->getByteLength()
00613                 );
00614         sendUdpRpcCall( lobbyServer, respCall, NULL, 5, 5 ); // FIXME: Make it a parameter...
00615     }
00616 
00617     if( subspace && !subspace->getResponsibleNode().isUnspecified() ){
00618         PubSubMoveMessage* moveMsg = new PubSubMoveMessage("Player move");
00619         moveMsg->setSubspaceId( region.getId() );
00620         moveMsg->setPlayer( thisNode );
00621         moveMsg->setPosition( posMsg->getPosition() );
00622         moveMsg->setTimestamp( simTime() );
00623         moveMsg->setBitLength( PUBSUB_MOVE_L( moveMsg ));
00624         RECORD_STATS(
00625                 ++numMoveMessages;
00626                 moveMessagesSize+= moveMsg->getByteLength()
00627                 );
00628         sendMessageToUDP( subspace->getResponsibleNode(), moveMsg );
00629     } else {
00630         // trying to move to not-yet subscribed region
00631         // FIXME: change state to JOINING?
00632     }
00633 }
00634 
00635 void PubSubMMOG::handleMoveMessage( PubSubMoveMessage* moveMsg )
00636 {
00637     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
00638     it = responsibleSubspaces.find( PubSubSubspaceId(moveMsg->getSubspaceId(), numSubspaces) );
00639     if( it == responsibleSubspaces.end() ){
00640          EV << "[PubSubMMOG::handleMoveMessage() @ " << thisNode.getAddress()
00641             << " (" << thisNode.getKey().toString(16) << ")]\n"
00642             << "  received moveMessage for unknown subspace" << moveMsg->getSubspaceId() << "\n"
00643             << endl;
00644         return;
00645     }
00646 
00647     // If message arrived in the correct timeslot, store move message until deadline
00648     // Note: This assumes, we get no messages with future timestamps. At least in
00649     // the simulation, this assumption will hold.
00650     // The allowOldMoveMessages parameter allows overriding the timeslot barriers and forward all
00651     // messages.
00652     if( allowOldMoveMessages || moveMsg->getTimestamp() >= eventDeliveryTimer->getArrivalTime() - 1.0/(2*movementRate) ){
00653         it->second.waitingMoveMessages.push_back( moveMsg );
00654         ++numEventsCorrectTimeslot;
00655     } else {
00656          EV << "[PubSubMMOG::handleMoveMessage() @ " << thisNode.getAddress()
00657             << " (" << thisNode.getKey().toString(16) << ")]\n"
00658             << "  received moveMesage with Timestamp: " << moveMsg->getTimestamp() << "\n"
00659             << "  deadline was: " << eventDeliveryTimer->getArrivalTime() - 1.0/(2*movementRate) << "\n"
00660             << endl;
00661         ++numEventsWrongTimeslot;
00662         cancelAndDelete( moveMsg );
00663     }
00664 }
00665 
00666 void PubSubMMOG::handleMoveListMessage( PubSubMoveListMessage* moveMsg )
00667 {
00668     simtime_t timestamp = moveMsg->getTimestamp();
00669 
00670     // If I'm intermediate node for this subspace, forward message to children
00671     std::map<PubSubSubspaceId, PubSubSubspaceIntermediate>::iterator it;
00672     it = intermediateSubspaces.find( PubSubSubspaceId(moveMsg->getSubspaceId(), numSubspaces) );
00673     if( it != intermediateSubspaces.end() ){
00674         // Forward only if the message has not already been forwarded
00675         if( it->second.getLastTimestamp() < moveMsg->getTimestamp() ){
00676             set<NodeHandle>::iterator childIt;
00677             for( childIt = it->second.children.begin(); childIt != it->second.children.end(); ++childIt ){
00678                 sendMessageToUDP( *childIt, (BaseOverlayMessage*) moveMsg->dup() );
00679                 RECORD_STATS(
00680                         ++numMoveListMessages;
00681                         moveListMessagesSize+= moveMsg->getByteLength()
00682                         );
00683             }
00684             it->second.setTimestamp( timestamp );
00685         }
00686     }
00687 
00688     // If I'm subscribed to the subspace, transfer a GameAPIMoveList to app
00689     std::list<PubSubSubspace>::iterator subIt;
00690     for( subIt = subscribedSubspaces.begin(); subIt != subscribedSubspaces.end(); ++subIt ){
00691         if( subIt->getId().getId() == moveMsg->getSubspaceId() ){
00692             if( subIt->getLastTimestamp() < moveMsg->getTimestamp() ){
00693                 GameAPIListMessage* moveList = new GameAPIListMessage("player position update");
00694                 moveList->setCommand( NEIGHBOR_UPDATE );
00695                 moveList->setAddNeighborArraySize( moveMsg->getPlayerArraySize() );
00696                 moveList->setNeighborPositionArraySize( moveMsg->getPositionArraySize() );
00697                 for( unsigned int i = 0; i < moveMsg->getPlayerArraySize(); ++i ){
00698                     moveList->setAddNeighbor( i, moveMsg->getPlayer(i) );
00699                     moveList->setNeighborPosition( i, moveMsg->getPosition(i) );
00700                     RECORD_STATS(
00701                         globalStatistics->addStdDev("PubSubMMOG: MoveDelay",
00702                                 SIMTIME_DBL(simTime() - timestamp + moveMsg->getPositionAge(i)) );
00703                         );
00704                 }
00705                 send( moveList, "appOut" );
00706                 RECORD_STATS(
00707                         if( timestamp < simTime() - maxMoveDelay ){
00708                             ++lostMovementLists;
00709                         } else {
00710                             ++receivedMovementLists;
00711                         }
00712                         if( subIt->getLastTimestamp() != 0) lostMovementLists += (int)(SIMTIME_DBL(timestamp - subIt->getLastTimestamp())*movementRate -1);
00713 
00714                         );
00715                 subIt->setTimestamp( timestamp );
00716             }
00717             return;
00718         }
00719     }
00720 }
00721 
00722 void PubSubMMOG::handleHelpResponse( PubSubHelpResponse* helpResp )
00723 {
00724    // lobby server answered our call for help
00725    // (i.e. he sends us a candidate for backup/intermediate nodes
00726     if( helpResp->getHelpType() == PUBSUB_BACKUP ){
00727         PubSubBackupCall* backupCall = new PubSubBackupCall("Become my backup node!");
00728         backupCall->setSubspaceId( helpResp->getSubspaceId() );
00729 
00730         // Find the subspace in the subspace map
00731         std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
00732         it = responsibleSubspaces.find( PubSubSubspaceId(helpResp->getSubspaceId(), numSubspaces) );
00733         if( it == responsibleSubspaces.end() ){
00734             EV << "[PubSubMMOG::handleHelpResponse() @ " << thisNode.getAddress()
00735                << " (" << thisNode.getKey().toString(16) << ")]\n"
00736                << "  received helpResponse for unknown subspace" << helpResp->getSubspaceId() << "\n"
00737                << endl;
00738             return;
00739         }
00740         PubSubSubspaceResponsible& subspace = it->second;
00741 
00742         // Assume the new backup will not refuse his task
00743         subspace.setBackupNode( helpResp->getNode() );
00744 
00745 // FIXME: just for testing
00746 int iii = subspace.getTotalChildrenCount();
00747 subspace.fixTotalChildrenCount();
00748 if( iii != subspace.getTotalChildrenCount() ){
00749     opp_error("Huh?");
00750 }
00751 
00752         // backup the load balancing tree
00753         backupCall->setChildrenArraySize( subspace.getTotalChildrenCount() );
00754         backupCall->setChildrenPosArraySize( subspace.getTotalChildrenCount() );
00755         backupCall->setIntermediatesArraySize( subspace.intermediateNodes.size() );
00756 
00757         set<NodeHandle>::iterator childIt;
00758         map<NodeHandle, bool>::iterator childMapIt;
00759         unsigned int i = 0;
00760         for( childMapIt = subspace.cachedChildren.begin(); childMapIt != subspace.cachedChildren.end(); ++childMapIt ){
00761             backupCall->setChildren(i, childMapIt->first);
00762             backupCall->setChildrenPos(i, -2);
00763             ++i;
00764         }
00765         for( childIt = subspace.children.begin(); childIt != subspace.children.end(); ++childIt ){
00766             backupCall->setChildren(i, *childIt);
00767             backupCall->setChildrenPos(i, -1);
00768             ++i;
00769         }
00770         for( unsigned int ii = 0; ii < subspace.intermediateNodes.size(); ++ii ){
00771             PubSubSubspaceResponsible::IntermediateNode& iNode =  subspace.intermediateNodes[ii];
00772             backupCall->setIntermediates(ii, iNode.node);
00773             for( childIt = iNode.children.begin(); childIt != iNode.children.end(); ++childIt ){
00774                 backupCall->setChildren(i, *childIt);
00775                 backupCall->setChildrenPos(i, ii);
00776                 ++i;
00777             }
00778         }
00779 
00780         backupCall->setBitLength( PUBSUB_BACKUPCALL_L( backupCall ));
00781         RECORD_STATS(
00782                 ++numPubSubSignalingMessages;
00783                 pubSubSignalingMessagesSize+= backupCall->getByteLength()
00784                 );
00785         sendUdpRpcCall( helpResp->getNode(), backupCall );
00786 
00787     } else if( helpResp->getHelpType() == PUBSUB_INTERMEDIATE ){
00788         PubSubIntermediateCall* intermediateCall = new PubSubIntermediateCall("Become my intermediate node!");
00789         intermediateCall->setSubspaceId( helpResp->getSubspaceId() );
00790         intermediateCall->setBitLength( PUBSUB_INTERMEDIATECALL_L( intermediateCall ));
00791         RECORD_STATS(
00792                 ++numPubSubSignalingMessages;
00793                 pubSubSignalingMessagesSize+= intermediateCall->getByteLength()
00794                 );
00795         sendUdpRpcCall( helpResp->getNode(), intermediateCall );
00796     }
00797 }
00798 
00799 void PubSubMMOG::handleBackupCall( PubSubBackupCall* backupCall )
00800 {
00801     int intId = backupCall->getSubspaceId();
00802     PubSubSubspaceId subspaceId(intId, numSubspaces);
00803 
00804     // Start Heartbeat Timer
00805     PubSubTimer* parentTimeout = new PubSubTimer("ParentTimeout");
00806     parentTimeout->setType( PUBSUB_PARENT_TIMEOUT );
00807     parentTimeout->setSubspaceId( intId );
00808     startTimer( parentTimeout );
00809 
00810     // insert subspace into responsible list
00811     PubSubSubspaceResponsible subspace( subspaceId );
00812     subspace.setResponsibleNode( backupCall->getSrcNode() );
00813     subspace.setHeartbeatTimer( parentTimeout );
00814 
00815     // recounstruct load balancing tree
00816     for( unsigned int i = 0; i < backupCall->getIntermediatesArraySize(); ++i ){
00817         PubSubSubspaceResponsible::IntermediateNode iNode;
00818         iNode.node = backupCall->getIntermediates(i);
00819         subspace.intermediateNodes.push_back( iNode );
00820     }
00821     for( unsigned int i = 0; i < backupCall->getChildrenArraySize(); ++i ){
00822         int pos = backupCall->getChildrenPos( i );
00823         if( pos == -2 ){
00824             subspace.cachedChildren.insert( make_pair( backupCall->getChildren(i), false ));
00825         } else if( pos == -1 ){
00826             subspace.children.insert( backupCall->getChildren(i) );
00827         } else {
00828             subspace.intermediateNodes[pos].children.insert( backupCall->getChildren(i) );
00829         }
00830     }
00831 
00832     backupSubspaces.insert( make_pair(subspaceId, subspace) );
00833 
00834     PubSubBackupResponse* backupResp = new PubSubBackupResponse("I'll be your backup");
00835     backupResp->setSubspaceId( intId );
00836     backupResp->setBitLength( PUBSUB_BACKUPRESPONSE_L( backupResp ));
00837     RECORD_STATS(
00838             ++numPubSubSignalingMessages;
00839             pubSubSignalingMessagesSize+= backupResp->getByteLength()
00840             );
00841     sendRpcResponse( backupCall, backupResp );
00842 }
00843 
00844 void PubSubMMOG::handleBackupResponse( PubSubBackupResponse* backupResp )
00845 {
00846     // Nothing to be done
00847     // HandleHelpResponse() already did everything important
00848 }
00849 
00850 void PubSubMMOG::handleIntermediateCall( PubSubIntermediateCall* intermediateCall )
00851 {
00852     // insert subspace into intermediate list
00853     PubSubSubspaceId subspaceId(intermediateCall->getSubspaceId(), numSubspaces);
00854     PubSubSubspaceIntermediate subspace( subspaceId );
00855     subspace.setResponsibleNode( intermediateCall->getSrcNode() );
00856     subspace.setTimestamp(0);
00857     intermediateSubspaces.insert( make_pair(subspaceId, subspace) );
00858 
00859     PubSubIntermediateResponse* iResp = new PubSubIntermediateResponse("I'll be your intermediate node");
00860     iResp->setSubspaceId( intermediateCall->getSubspaceId() );
00861     iResp->setBitLength( PUBSUB_INTERMEDIATERESPONSE_L( iResp ));
00862     RECORD_STATS(
00863             ++numPubSubSignalingMessages;
00864             pubSubSignalingMessagesSize+= iResp->getByteLength()
00865             );
00866     sendRpcResponse( intermediateCall, iResp );
00867 }
00868 
00869 void PubSubMMOG::handleIntermediateResponse( PubSubIntermediateResponse* intermediateResp )
00870 {
00871     // we found a new intermediate node for a subspace
00872     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
00873     it = responsibleSubspaces.find( PubSubSubspaceId(intermediateResp->getSubspaceId(), numSubspaces) );
00874     if( it == responsibleSubspaces.end() ) {
00875         EV << "[PubSubMMOG::handleIntermediateResponse() @ " << thisNode.getAddress()
00876            << " (" << thisNode.getKey().toString(16) << ")]\n"
00877            << "  Received Intermediate Response for unknown Subspace!\n"
00878            << endl;
00879         return;
00880     }
00881     PubSubSubspaceResponsible& subspace = it->second;
00882     PubSubSubspaceResponsible::IntermediateNode iNode;
00883     iNode.node = intermediateResp->getSrcNode();
00884 
00885     // if there is any broken intermediate node in list, replace it
00886     bool newIntermediate = true;
00887     deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
00888     for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
00889         if( iit->node.isUnspecified() ){
00890             iit->node = iNode.node;
00891             newIntermediate = false;
00892             break;
00893         }
00894     }
00895     if( iit == subspace.intermediateNodes.end() ){
00896         subspace.intermediateNodes.push_back( iNode );
00897         iit = subspace.intermediateNodes.end() - 1;
00898     }
00899 
00900     // inform Backup
00901     if( !subspace.getBackupNode().isUnspecified() ){
00902         PubSubBackupIntermediateMessage* backupMsg = new PubSubBackupIntermediateMessage("Backup: new Intermediate");
00903         backupMsg->setSubspaceId( intermediateResp->getSubspaceId() );
00904         backupMsg->setNode( iNode.node );
00905         backupMsg->setPos( iit - subspace.intermediateNodes.begin() );
00906         backupMsg->setBitLength( PUBSUB_BACKUPINTERMEDIATE_L( backupMsg ));
00907         RECORD_STATS(
00908                 ++numPubSubSignalingMessages;
00909                 pubSubSignalingMessagesSize+= backupMsg->getByteLength()
00910                 );
00911         sendMessageToUDP( subspace.getBackupNode(), backupMsg );
00912     }
00913 
00914     // if needed, send adopt to parent
00915     int intermediatePos = iit - subspace.intermediateNodes.begin();
00916     int parentPos = intermediatePos/maxChildren -1;
00917     if( parentPos >= 0 && !subspace.intermediateNodes[parentPos].node.isUnspecified() ){
00918         PubSubAdoptChildCall* adoptCall = new PubSubAdoptChildCall("Adopt (intermediate) Node");
00919         adoptCall->setSubspaceId( intermediateResp->getSubspaceId() );
00920         adoptCall->setChild( iit->node );
00921         adoptCall->setBitLength( PUBSUB_ADOPTCHILDCALL_L( adoptCall ));
00922         RECORD_STATS(
00923                 ++numPubSubSignalingMessages;
00924                 pubSubSignalingMessagesSize+= adoptCall->getByteLength()
00925                 );
00926         sendUdpRpcCall( subspace.intermediateNodes[parentPos].node, adoptCall );
00927     }
00928 
00929     if( newIntermediate ){
00930         // move one child from iNodes's parent to cache
00931         if( parentPos >= 0 ) {
00932             // parent is an intermediate node
00933             PubSubSubspaceResponsible::IntermediateNode& parent = subspace.intermediateNodes[parentPos];
00934             if( parent.children.begin() != parent.children.end() ){
00935                 bool fixNeeded = false;
00936                 if( !subspace.cachedChildren.insert( make_pair( *(parent.children.begin()), false )).second ){
00937                     fixNeeded = true;
00938                 }
00939                 if( !subspace.getBackupNode().isUnspecified() ){
00940                     PubSubBackupSubscriptionMessage* backupMsg = new PubSubBackupSubscriptionMessage("Backup: nodes moved to cache");
00941                     backupMsg->setSubspaceId( intermediateResp->getSubspaceId() );
00942                     backupMsg->setChild( *(parent.children.begin()) );
00943                     backupMsg->setOldParent( parent.node );
00944                     backupMsg->setBitLength( PUBSUB_BACKUPSUBSCRIPTION_L( backupMsg ));
00945                     RECORD_STATS(
00946                             ++numPubSubSignalingMessages;
00947                             pubSubSignalingMessagesSize+= backupMsg->getByteLength()
00948                             );
00949                     sendMessageToUDP( subspace.getBackupNode(), backupMsg );
00950                 }
00951                 PubSubNodeLeftMessage* goneMsg = new PubSubNodeLeftMessage("Node left: moved");
00952                 goneMsg->setNode( *(parent.children.begin()) );
00953                 goneMsg->setSubspaceId( intermediateResp->getSubspaceId() );
00954                 goneMsg->setBitLength( PUBSUB_NODELEFT_L( goneMsg ));
00955                 RECORD_STATS(
00956                         ++numPubSubSignalingMessages;
00957                         pubSubSignalingMessagesSize+= goneMsg->getByteLength()
00958                         );
00959                 sendMessageToUDP( parent.node, goneMsg );
00960                 parent.children.erase( parent.children.begin() );
00961                 if( fixNeeded ){
00962                     subspace.fixTotalChildrenCount();
00963                 }
00964             }
00965 
00966         } else {
00967             // we are parent
00968             if( subspace.children.begin() != subspace.children.end() ){
00969                 bool fixNeeded = false;
00970                 if( !subspace.cachedChildren.insert( make_pair( *(subspace.children.begin()), false )).second ){
00971                     fixNeeded = true;
00972                 }
00973                 if( !subspace.getBackupNode().isUnspecified() ){
00974                     PubSubBackupSubscriptionMessage* backupMsg = new PubSubBackupSubscriptionMessage("Backup: nodes moved to cache");
00975                     backupMsg->setSubspaceId( intermediateResp->getSubspaceId() );
00976                     backupMsg->setChild( *(subspace.children.begin()) );
00977                     backupMsg->setOldParent( thisNode );
00978                     backupMsg->setBitLength( PUBSUB_BACKUPSUBSCRIPTION_L( backupMsg ));
00979                     RECORD_STATS(
00980                             ++numPubSubSignalingMessages;
00981                             pubSubSignalingMessagesSize+= backupMsg->getByteLength()
00982                             );
00983                     sendMessageToUDP( subspace.getBackupNode(), backupMsg );
00984                 }
00985                 subspace.children.erase( *(subspace.children.begin()) );
00986                 if( fixNeeded ){
00987                     subspace.fixTotalChildrenCount();
00988                 }
00989             }
00990         }
00991     } else {
00992         // send adopt for all children intermediates
00993         for( int pos = (intermediatePos+1) * maxChildren; pos < (int) subspace.intermediateNodes.size() &&
00994                 pos < (intermediatePos+2) * maxChildren; ++pos ){
00995             if( subspace.intermediateNodes[pos].node.isUnspecified() ) continue;
00996             PubSubAdoptChildCall* adoptCall = new PubSubAdoptChildCall("Adopt (intermediate) Node");
00997             adoptCall->setSubspaceId( intermediateResp->getSubspaceId() );
00998             adoptCall->setChild( subspace.intermediateNodes[pos].node );
00999             adoptCall->setBitLength( PUBSUB_ADOPTCHILDCALL_L( adoptCall ));
01000             RECORD_STATS(
01001                     ++numPubSubSignalingMessages;
01002                     pubSubSignalingMessagesSize+= adoptCall->getByteLength()
01003                     );
01004             sendUdpRpcCall( iit->node, adoptCall );
01005         }
01006     }
01007 
01008     // move as many cached children to the new node as possible
01009     std::map<NodeHandle,bool>::iterator childIt;
01010     for( childIt = subspace.cachedChildren.begin(); childIt != subspace.cachedChildren.end(); ++childIt ){
01011         if( childIt->second ) continue;
01012         PubSubAdoptChildCall* adoptCall = new PubSubAdoptChildCall("Adopt Node");
01013         adoptCall->setSubspaceId( intermediateResp->getSubspaceId() );
01014         adoptCall->setChild( childIt->first );
01015         adoptCall->setBitLength( PUBSUB_ADOPTCHILDCALL_L( adoptCall ));
01016         RECORD_STATS(
01017                 ++numPubSubSignalingMessages;
01018                 pubSubSignalingMessagesSize+= adoptCall->getByteLength()
01019                 );
01020         sendUdpRpcCall( intermediateResp->getSrcNode(), adoptCall );
01021         childIt->second = true;
01022         if( (unsigned int) maxChildren == ++(iit->waitingChildren) ) break;
01023     }
01024 }
01025 
01026 void PubSubMMOG::handleAdoptChildCall( PubSubAdoptChildCall* adoptCall )
01027 {
01028     std::map<PubSubSubspaceId, PubSubSubspaceIntermediate>::iterator it;
01029     it = intermediateSubspaces.find( PubSubSubspaceId(adoptCall->getSubspaceId(), numSubspaces) );
01030     if( it == intermediateSubspaces.end() ) {
01031         EV << "[PubSubMMOG::handleAdoptChildCall() @ " << thisNode.getAddress()
01032            << " (" << thisNode.getKey().toString(16) << ")]\n"
01033            << "  Received Adopt Child Call for unknown Subspace!\n"
01034            << endl;
01035         cancelAndDelete( adoptCall );
01036         return;
01037     }
01038 
01039     it->second.addChild( adoptCall->getChild() );
01040     PubSubAdoptChildResponse* adoptResp = new PubSubAdoptChildResponse("I adopted child");
01041     adoptResp->setSubspaceId( adoptCall->getSubspaceId() );
01042     adoptResp->setChild( adoptCall->getChild() );
01043     adoptResp->setBitLength( PUBSUB_ADOPTCHILDRESPONSE_L( adoptResp ));
01044     RECORD_STATS(
01045             ++numPubSubSignalingMessages;
01046             pubSubSignalingMessagesSize+= adoptResp->getByteLength()
01047             );
01048     sendRpcResponse( adoptCall, adoptResp );
01049 }
01050 
01051 void PubSubMMOG::handleAdoptChildResponse( PubSubAdoptChildResponse* adoptResp )
01052 {
01053     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01054     it = responsibleSubspaces.find( PubSubSubspaceId(adoptResp->getSubspaceId(), numSubspaces) );
01055     if( it == responsibleSubspaces.end() ) {
01056         EV << "[PubSubMMOG::handleAdoptChildResponse() @ " << thisNode.getAddress()
01057            << " (" << thisNode.getKey().toString(16) << ")]\n"
01058            << "  Received AdoptChild Response for unknown Subspace!\n"
01059            << endl;
01060         return;
01061     }
01062 
01063 // FIXME: just for testing
01064 PubSubSubspaceResponsible& subspace = it->second;
01065 int iii = subspace.getTotalChildrenCount();
01066 subspace.fixTotalChildrenCount();
01067 if( iii != subspace.getTotalChildrenCount() ){
01068     opp_error("Huh?");
01069 }
01070 
01071     // Find intermediate node in subspace
01072     deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01073     for( iit = it->second.intermediateNodes.begin(); iit !=  it->second.intermediateNodes.end(); ++iit ){
01074         if( !iit->node.isUnspecified() && iit->node == adoptResp->getSrcNode() ){
01075 
01076             // if adoption was for a child intermediate node, nothing is to be done
01077             int intermediatePos = iit - it->second.intermediateNodes.begin();
01078             for( int pos = (intermediatePos+1) * maxChildren; pos < (int) it->second.intermediateNodes.size() &&
01079                     pos < (intermediatePos+2) * maxChildren; ++pos )
01080             {
01081                 if( !it->second.intermediateNodes[pos].node.isUnspecified() &&
01082                         adoptResp->getChild() == it->second.intermediateNodes[pos].node ){
01083                     return;
01084                 }
01085             }
01086 
01087             // child is a "real" child->remove it from cache
01088             if( !it->second.cachedChildren.erase( adoptResp->getChild() ) ){
01089                 // if node got deleted in the meantime, inform parent...
01090                 PubSubNodeLeftMessage* goneMsg = new PubSubNodeLeftMessage("Node left Subspace");
01091                 goneMsg->setNode( adoptResp->getChild() );
01092                 goneMsg->setSubspaceId( it->second.getId().getId() );
01093                 goneMsg->setBitLength( PUBSUB_NODELEFT_L( goneMsg ));
01094                 RECORD_STATS(
01095                         ++numPubSubSignalingMessages;
01096                         pubSubSignalingMessagesSize+= goneMsg->getByteLength()
01097                         );
01098                 sendMessageToUDP( adoptResp->getSrcNode(), goneMsg );
01099                 return;
01100             }
01101 
01102             // move child to intermediate node's childrenlist
01103             if( !iit->children.insert( adoptResp->getChild() ).second ){
01104                 // Node was already in children list, fix children count
01105                 subspace.fixTotalChildrenCount();
01106             }
01107             iit->waitingChildren--;
01108 
01109 // FIXME: just for testing
01110 PubSubSubspaceResponsible& subspace = it->second;
01111 int iii = subspace.getTotalChildrenCount();
01112 subspace.fixTotalChildrenCount();
01113 if( iii != subspace.getTotalChildrenCount() ){
01114     opp_error("Huh?");
01115 }
01116 
01117             // Inform Backup
01118             if( !it->second.getBackupNode().isUnspecified() ){
01119                 PubSubBackupSubscriptionMessage* backupMsg = new PubSubBackupSubscriptionMessage("Backup: node got a new parent");
01120                 backupMsg->setSubspaceId( adoptResp->getSubspaceId() );
01121                 backupMsg->setChild( adoptResp->getChild() );
01122                 backupMsg->setParent( adoptResp->getSrcNode() );
01123                 backupMsg->setBitLength( PUBSUB_BACKUPSUBSCRIPTION_L( backupMsg ));
01124                 RECORD_STATS(
01125                         ++numPubSubSignalingMessages;
01126                        pubSubSignalingMessagesSize+= backupMsg->getByteLength()
01127                        );
01128                 sendMessageToUDP( it->second.getBackupNode(), backupMsg );
01129                 return;
01130             }
01131         }
01132     }
01133 
01134     EV << "[PubSubMMOG::handleAdoptChildResponse() @ " << thisNode.getAddress()
01135        << " (" << thisNode.getKey().toString(16) << ")]\n"
01136        << "  Received AdoptChild Response for unknown child!\n"
01137        << endl;
01138 }
01139 
01140 void PubSubMMOG::handlePingCall( PubSubPingCall* pingCall )
01141 {
01142     int subspaceId = pingCall->getSubspaceId();
01143 
01144     if( pingCall->getPingType() == PUBSUB_PING_BACKUP ){
01145         // reset heartbeat timer
01146         std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01147         it = backupSubspaces.find( PubSubSubspaceId(pingCall->getSubspaceId(), numSubspaces) );
01148         if( it == backupSubspaces.end() ) {
01149             EV << "[PubSubMMOG::handlePingCall() @ " << thisNode.getAddress()
01150                << " (" << thisNode.getKey().toString(16) << ")]\n"
01151                << "  Received PingCall for unknown Subspace!\n"
01152                << endl;
01153             // FIXME: Somebody thinks we are his backup. What shall we do?
01154         } else {
01155             it->second.resetHeartbeatFailCount();
01156             startTimer( it->second.getHeartbeatTimer() );
01157         }
01158     }
01159 
01160     PubSubPingResponse* pingResp = new PubSubPingResponse("PingResponse");
01161     pingResp->setSubspaceId( subspaceId );
01162     pingResp->setBitLength( PUBSUB_PINGRESPONSE_L( pingResp ));
01163     RECORD_STATS(
01164             ++numPubSubSignalingMessages;
01165             pubSubSignalingMessagesSize+= pingResp->getByteLength()
01166             );
01167     sendRpcResponse( pingCall, pingResp );
01168 }
01169 
01170 void PubSubMMOG::handlePingResponse( PubSubPingResponse* pingResp )
01171 {
01172 }
01173 
01174 void PubSubMMOG::takeOverNewSubspace( PubSubSubspaceId subspaceId )
01175 {
01176     // create a new subspace
01177     PubSubSubspaceResponsible subspace( subspaceId );
01178     takeOverSubspace( subspace, true );
01179 }
01180 
01181 void PubSubMMOG::takeOverSubspace( PubSubSubspaceResponsible& subspace, bool isNew = false )
01182 {
01183     const PubSubSubspaceId& subspaceId = subspace.getId();
01184     int intId = subspaceId.getId();
01185 
01186     subspace.fixTotalChildrenCount();
01187 
01188     NodeHandle oldNode = subspace.getResponsibleNode();
01189 
01190     // insert subspace into responsible list
01191     subspace.setResponsibleNode( thisNode );
01192     responsibleSubspaces.insert( make_pair(subspaceId, subspace) );
01193 
01194     // request backup
01195     PubSubHelpCall* helpCall = new PubSubHelpCall("I need a backup node");
01196     helpCall->setHelpType( PUBSUB_BACKUP );
01197     helpCall->setSubspaceId( intId );
01198     helpCall->setBitLength( PUBSUB_HELPCALL_L( helpCall ));
01199     RECORD_STATS(
01200             ++numPubSubSignalingMessages;
01201             pubSubSignalingMessagesSize+= helpCall->getByteLength()
01202             );
01203     sendUdpRpcCall( lobbyServer, helpCall );
01204 
01205     if( !isNew ) {
01206         PubSubReplacementMessage* repMsg = new PubSubReplacementMessage("I replaced the responsible node");
01207         repMsg->setSubspaceId( intId );
01208         repMsg->setNewResponsibleNode( thisNode );
01209         repMsg->setBitLength( PUBSUB_REPLACEMENT_L( repMsg ));
01210 
01211         // Inform children and lobbyserver about takeover
01212         sendMessageToChildren( subspace, repMsg, NULL, repMsg );
01213         sendMessageToUDP( lobbyServer, repMsg );
01214 
01215         // inform lobby server over failed node
01216         PubSubFailedNodeMessage* failedNode = new PubSubFailedNodeMessage("Node failed");
01217         failedNode->setFailedNode( oldNode );
01218         failedNode->setBitLength( PUBSUB_FAILEDNODE_L( failedNode ));
01219         RECORD_STATS(
01220                 ++numPubSubSignalingMessages;
01221                 pubSubSignalingMessagesSize+= failedNode->getByteLength()
01222                 );
01223         sendMessageToUDP( lobbyServer, failedNode );
01224    }
01225 }
01226 
01227 void PubSubMMOG::sendHearbeatToChildren()
01228 {
01229     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01230     for( it = responsibleSubspaces.begin(); it != responsibleSubspaces.end(); ++it) {
01231         PubSubPingCall* bHeartbeat = new PubSubPingCall("Heartbeat Backup");
01232         bHeartbeat->setPingType( PUBSUB_PING_BACKUP );
01233         bHeartbeat->setSubspaceId( it->second.getId().getId() );
01234         bHeartbeat->setBitLength( PUBSUB_PINGCALL_L( bHeartbeat ));
01235 
01236         PubSubPingCall* iHeartbeat = new PubSubPingCall("Heartbeat Intermediate");
01237         iHeartbeat->setPingType( PUBSUB_PING_INTERMEDIATE );
01238         iHeartbeat->setSubspaceId( it->second.getId().getId() );
01239         iHeartbeat->setBitLength( PUBSUB_PINGCALL_L( iHeartbeat ));
01240 
01241         sendMessageToChildren( it->second, iHeartbeat, bHeartbeat, NULL);
01242         delete bHeartbeat;
01243         delete iHeartbeat;
01244     }
01245 }
01246 
01247 void PubSubMMOG::sendPingToChildren()
01248 {
01249     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01250     for( it = responsibleSubspaces.begin(); it != responsibleSubspaces.end(); ++it) {
01251         PubSubPingCall* heartbeat = new PubSubPingCall("Ping");
01252         heartbeat->setPingType( PUBSUB_PING_CHILD );
01253         heartbeat->setSubspaceId( it->second.getId().getId() );
01254         heartbeat->setBitLength( PUBSUB_PINGCALL_L( heartbeat ));
01255         sendMessageToChildren( it->second, NULL, NULL, heartbeat );
01256         delete heartbeat;
01257     }
01258 }
01259 
01260 void PubSubMMOG::handleParentTimeout( PubSubTimer* timer )
01261 {
01262     // our parent timed out. we have to take over the subspace...
01263     PubSubSubspaceId subspaceId(timer->getSubspaceId(), numSubspaces);
01264     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01265     it = backupSubspaces.find( subspaceId );
01266     if( it == backupSubspaces.end() ) {
01267         delete timer;
01268         return;
01269     }
01270 
01271     // increase fail count; if to high, take over subspace
01272     it->second.incHeartbeatFailCount();
01273     if( it->second.getHeartbeatFailCount() > 1 ) { // FIXME: make it a parameter
01274 
01275         // Delete Timer
01276         cancelAndDelete( timer );
01277         it->second.setHeartbeatTimer( NULL );
01278 
01279         // Take over Subspace
01280         takeOverSubspace( it->second );
01281         backupSubspaces.erase( it );
01282 
01283     } else {
01284         startTimer( timer );
01285     }
01286 }
01287 
01288 void PubSubMMOG::handleBackupCallTimeout( PubSubBackupCall* backupCall, const TransportAddress& oldNode )
01289 {
01290     // FIXME: cast oldNode to NodeHandle
01291     // Inform Lobbyserver over failed node
01292     PubSubFailedNodeMessage* failedNode = new PubSubFailedNodeMessage("Node failed");
01293     failedNode->setFailedNode( oldNode );
01294     failedNode->setBitLength( PUBSUB_FAILEDNODE_L( failedNode ));
01295     RECORD_STATS(
01296             ++numPubSubSignalingMessages;
01297             pubSubSignalingMessagesSize+= failedNode->getByteLength()
01298             );
01299     sendMessageToUDP( lobbyServer, failedNode );
01300 
01301     // Request new Backup
01302     PubSubHelpCall* helpCall = new PubSubHelpCall("I need a backup node");
01303     helpCall->setHelpType( PUBSUB_BACKUP );
01304     helpCall->setSubspaceId( backupCall->getSubspaceId() );
01305     helpCall->setBitLength( PUBSUB_HELPCALL_L( helpCall ));
01306     RECORD_STATS(
01307             ++numPubSubSignalingMessages;
01308             pubSubSignalingMessagesSize+= helpCall->getByteLength()
01309             );
01310     sendUdpRpcCall( lobbyServer, helpCall );
01311 
01312     // find appropriate subspace and mark backup as failed
01313     PubSubSubspaceId subspaceId(backupCall->getSubspaceId(), numSubspaces);
01314     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01315     it = responsibleSubspaces.find( subspaceId );
01316     if( it == responsibleSubspaces.end() ) {
01317         return;
01318     }
01319     it->second.setBackupNode( NodeHandle::UNSPECIFIED_NODE );
01320 }
01321 
01322 void PubSubMMOG::handlePingCallTimeout( PubSubPingCall* pingCall, const TransportAddress& oldNode )
01323 {
01324     // Inform Lobbyserver over failed node
01325     const NodeHandle& oldNodeHandle = dynamic_cast<const NodeHandle&>(oldNode);
01326     // FIXME: use oldNodeHandle instead of oldNode
01327     PubSubFailedNodeMessage* failedNode = new PubSubFailedNodeMessage("Node failed");
01328     failedNode->setBitLength( PUBSUB_FAILEDNODE_L( failedNode ));
01329     RECORD_STATS(
01330             ++numPubSubSignalingMessages;
01331             pubSubSignalingMessagesSize+= failedNode->getByteLength()
01332             );
01333     failedNode->setFailedNode( oldNode );
01334     sendMessageToUDP( lobbyServer, failedNode );
01335 
01336     // find appropriate subspace
01337     PubSubSubspaceId subspaceId(pingCall->getSubspaceId(), numSubspaces);
01338     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01339     it = responsibleSubspaces.find( subspaceId );
01340     if( it == responsibleSubspaces.end() ) {
01341         return;
01342     }
01343     PubSubSubspaceResponsible& subspace = it->second;
01344 
01345     if( pingCall->getPingType() == PUBSUB_PING_CHILD ){
01346         // remove child
01347         unsubscribeChild( oldNodeHandle, subspace );
01348 
01349     } else if( pingCall->getPingType() == PUBSUB_PING_BACKUP ){
01350 
01351         // if we didn't already have (or asked for) a new backup
01352         if( !subspace.getBackupNode().isUnspecified() &&
01353                 subspace.getBackupNode() == oldNodeHandle )
01354         {
01355             // our backup timed out. we have to request a new one...
01356             // delete old backup entry
01357             subspace.setBackupNode( NodeHandle::UNSPECIFIED_NODE );
01358 
01359             // Request new Backup
01360             PubSubHelpCall* helpCall = new PubSubHelpCall("I need a backup node");
01361             helpCall->setHelpType( PUBSUB_BACKUP );
01362             helpCall->setSubspaceId( pingCall->getSubspaceId() );
01363             helpCall->setBitLength( PUBSUB_HELPCALL_L( helpCall ));
01364             RECORD_STATS(
01365                     ++numPubSubSignalingMessages;
01366                     pubSubSignalingMessagesSize+= helpCall->getByteLength()
01367                     );
01368             sendUdpRpcCall( lobbyServer, helpCall );
01369         }
01370 
01371     } else if( pingCall->getPingType() == PUBSUB_PING_INTERMEDIATE ){
01372         // one intermediate node timed out. we have to request a new one...
01373         // delete old intermediate entry
01374         deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01375         for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01376             if( !iit->node.isUnspecified() && oldNode == iit->node ) break;
01377         }
01378         if( iit == subspace.intermediateNodes.end() ) return;
01379 
01380         NodeHandle oldNode = iit->node;
01381         iit->node = NodeHandle::UNSPECIFIED_NODE;
01382 
01383         // inform Backup
01384         if( !subspace.getBackupNode().isUnspecified() ){
01385             PubSubBackupIntermediateMessage* backupMsg = new PubSubBackupIntermediateMessage("Backup: Intermediate failed");
01386             backupMsg->setSubspaceId( pingCall->getSubspaceId() );
01387             backupMsg->setPos( iit - it->second.intermediateNodes.begin() );
01388             backupMsg->setBitLength( PUBSUB_BACKUPINTERMEDIATE_L( backupMsg ));
01389             RECORD_STATS(
01390                     ++numPubSubSignalingMessages;
01391                     pubSubSignalingMessagesSize+= backupMsg->getByteLength()
01392                     );
01393             sendMessageToUDP( subspace.getBackupNode(), backupMsg );
01394         }
01395 
01396         bool fixNeeded = false;
01397         // Take over all children until new intermediate is found.
01398         set<NodeHandle>::iterator childIt;
01399         for(  childIt = iit->children.begin(); childIt != iit->children.end(); ++childIt ){
01400             if( !subspace.cachedChildren.insert( make_pair(*childIt, false)).second ){
01401                 fixNeeded = true;
01402             }
01403 
01404             // Inform Backup
01405             if( !subspace.getBackupNode().isUnspecified() ){
01406                 PubSubBackupSubscriptionMessage* backupMsg = new PubSubBackupSubscriptionMessage("Backup: nodes moved to cache");
01407                 backupMsg->setSubspaceId( pingCall->getSubspaceId() );
01408                 backupMsg->setChild( *childIt );
01409                 backupMsg->setOldParent( oldNodeHandle );
01410                 backupMsg->setBitLength( PUBSUB_BACKUPSUBSCRIPTION_L( backupMsg ));
01411                 RECORD_STATS(
01412                         ++numPubSubSignalingMessages;
01413                         pubSubSignalingMessagesSize+= backupMsg->getByteLength()
01414                         );
01415                 sendMessageToUDP( subspace.getBackupNode(), backupMsg );
01416             }
01417         }
01418         iit->children.clear();
01419         if( fixNeeded ) subspace.fixTotalChildrenCount();
01420 
01421         // inform parent of intermediate node
01422         int parentPos = (iit - subspace.intermediateNodes.begin())/maxChildren -1;
01423         if( parentPos >= 0 ){
01424             PubSubSubspaceResponsible::IntermediateNode& parent = subspace.intermediateNodes[parentPos];
01425             if( !parent.node.isUnspecified() ){
01426                 PubSubNodeLeftMessage* goneMsg = new PubSubNodeLeftMessage("Intermediate left Subspace");
01427                 goneMsg->setNode( oldNodeHandle );
01428                 goneMsg->setSubspaceId( subspace.getId().getId() );
01429                 goneMsg->setBitLength( PUBSUB_NODELEFT_L( goneMsg ));
01430                 RECORD_STATS(
01431                         ++numPubSubSignalingMessages;
01432                         pubSubSignalingMessagesSize+= goneMsg->getByteLength()
01433                         );
01434                 sendMessageToUDP( parent.node, goneMsg );
01435             }
01436         }
01437 
01438         // Request new Intermediate
01439         PubSubHelpCall* helpCall = new PubSubHelpCall("I need an intermediate node");
01440         helpCall->setHelpType( PUBSUB_INTERMEDIATE );
01441         helpCall->setSubspaceId( pingCall->getSubspaceId() );
01442         helpCall->setBitLength( PUBSUB_HELPCALL_L( helpCall ));
01443         RECORD_STATS(
01444                 ++numPubSubSignalingMessages;
01445                 pubSubSignalingMessagesSize+= helpCall->getByteLength()
01446                 );
01447         sendUdpRpcCall( lobbyServer, helpCall );
01448     }
01449 // FIXME: just for testing
01450 int iii = subspace.getTotalChildrenCount();
01451 subspace.fixTotalChildrenCount();
01452 if( iii != subspace.getTotalChildrenCount() ){
01453     opp_error("Huh?");
01454 }
01455 
01456 }
01457 
01458 void PubSubMMOG::handleSubscriptionCallTimeout( PubSubSubscriptionCall* subscriptionCall, const TransportAddress& oldNode )
01459 {
01460     // FIXME: cast oldNode to NodeHandle
01461     // our subscription call timed out. This means the responsible node is dead...
01462     // Inform Lobbyserver over failed node
01463     PubSubFailedNodeMessage* failedNode = new PubSubFailedNodeMessage("Node failed");
01464     failedNode->setFailedNode( oldNode );
01465     failedNode->setBitLength( PUBSUB_FAILEDNODE_L( failedNode ));
01466     RECORD_STATS(
01467             ++numPubSubSignalingMessages;
01468             pubSubSignalingMessagesSize+= failedNode->getByteLength()
01469             );
01470     sendMessageToUDP( lobbyServer, failedNode );
01471 
01472     // Ask for new responsible node
01473     PubSubResponsibleNodeCall* respCall = new PubSubResponsibleNodeCall("Request Responsible NodeHandle");
01474     PubSubSubspaceId subspaceId( subscriptionCall->getSubspaceId(), numSubspaces);
01475     respCall->setSubspacePos( Vector2D(subspaceId.getX(), subspaceId.getY()) );
01476     respCall->setBitLength( PUBSUB_RESPONSIBLENODECALL_L( respCall ));
01477     RECORD_STATS(
01478             ++numPubSubSignalingMessages;
01479             pubSubSignalingMessagesSize+= respCall->getByteLength()
01480             );
01481     sendUdpRpcCall( lobbyServer, respCall, NULL, 5, 5 ); // FIXME: Make it a parameter...
01482 }
01483 
01484 void PubSubMMOG::handleReplacementMessage( PubSubReplacementMessage* replaceMsg )
01485 {
01486     PubSubSubspaceId subspaceId(replaceMsg->getSubspaceId(), numSubspaces);
01487 
01488     // There's a new responsible node for a subspace
01489     // Replace the old one in the intermediateSubspaces map...
01490     std::map<PubSubSubspaceId, PubSubSubspaceIntermediate>::iterator it;
01491     it = intermediateSubspaces.find( subspaceId );
01492     if( it != intermediateSubspaces.end() ) {
01493         it->second.setResponsibleNode( replaceMsg->getNewResponsibleNode() );
01494     }
01495 
01496     // ... and in the subsribed subspaces list
01497     std::list<PubSubSubspace>::iterator iit;
01498     for( iit = subscribedSubspaces.begin(); iit != subscribedSubspaces.end(); ++iit ){
01499         if( iit->getId() == subspaceId ) {
01500             iit->setResponsibleNode( replaceMsg->getNewResponsibleNode() );
01501             return;
01502         }
01503     }
01504 }
01505 
01506 void PubSubMMOG::handleReleaseIntermediate( PubSubReleaseIntermediateMessage* releaseMsg )
01507 {
01508     PubSubSubspaceId subspaceId(releaseMsg->getSubspaceId(), numSubspaces);
01509     intermediateSubspaces.erase( subspaceId );
01510 }
01511 
01512 void PubSubMMOG::handleIntermediateBackup( PubSubBackupIntermediateMessage* backupMsg )
01513 {
01514     // find appropriate subspace
01515     PubSubSubspaceId subspaceId(backupMsg->getSubspaceId(), numSubspaces);
01516     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01517     it = backupSubspaces.find( subspaceId );
01518     if( it == backupSubspaces.end() ) {
01519         return;
01520     }
01521 
01522     if( backupMsg->getPos() >= (int) it->second.intermediateNodes.size() ){
01523         it->second.intermediateNodes.resize( backupMsg->getPos() + 1 );
01524     }
01525     it->second.intermediateNodes[ backupMsg->getPos() ].node = backupMsg->getNode();
01526 }
01527 
01528 void PubSubMMOG::handleSubscriptionBackup( PubSubBackupSubscriptionMessage* backupMsg )
01529 {
01530     // Note: this funktion may break subspace's tatalChildrenCall
01531     // You have to use fixTotalChildrenCount before using the subspace
01532     // find appropriate subspace
01533     PubSubSubspaceId subspaceId(backupMsg->getSubspaceId(), numSubspaces);
01534     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01535     it = backupSubspaces.find( subspaceId );
01536     if( it == backupSubspaces.end() ) {
01537         return;
01538     }
01539     PubSubSubspaceResponsible& subspace = it->second;
01540 
01541     deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01542 
01543     if( !backupMsg->getOldParent().isUnspecified() ){
01544         // oldParent set -> move child
01545         if( backupMsg->getOldParent() == subspace.getResponsibleNode() ){
01546             // direct child -> cache
01547             subspace.removeChild( backupMsg->getChild() );
01548             subspace.cachedChildren.insert(make_pair( backupMsg->getChild(), false) );
01549 
01550         } else {
01551             // from I -> chache
01552             for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01553 //                if( !iit->node.isUnspecified() && iit->node == backupMsg->getOldParent() ){
01554                     iit->children.erase( backupMsg->getChild() );
01555 //                }
01556             }
01557             subspace.cachedChildren.insert(make_pair( backupMsg->getChild(), false) );
01558         }
01559     } else if( backupMsg->getParent().isUnspecified() ){
01560         // parent not set -> new child to chache
01561         subspace.cachedChildren.insert(make_pair( backupMsg->getChild(), false) );
01562 
01563     } else if( backupMsg->getParent() == subspace.getResponsibleNode() ){
01564         // new direct child
01565         subspace.addChild( backupMsg->getChild() );
01566     } else {
01567         // move child from cache to intermediate
01568         subspace.cachedChildren.erase( backupMsg->getChild() );
01569 
01570         for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01571             if( !iit->node.isUnspecified() && iit->node == backupMsg->getParent() ){
01572                 iit->children.insert( backupMsg->getChild() );
01573             }
01574         }
01575         // FIXME: check for errors
01576     }
01577 }
01578 
01579 void PubSubMMOG::handleUnsubscribeBackup( PubSubBackupUnsubscribeMessage* backupMsg )
01580 {
01581     // Note: this funktion may break subspace's tatalChildrenCall
01582     // You have to use fixTotalChildrenCount before using the subspace
01583     // find appropriate subspace
01584     PubSubSubspaceId subspaceId(backupMsg->getSubspaceId(), numSubspaces);
01585     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01586     it = backupSubspaces.find( subspaceId );
01587     if( it == backupSubspaces.end() ) {
01588         return;
01589     }
01590     PubSubSubspaceResponsible& subspace = it->second;
01591 
01592     deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01593     set<NodeHandle>::iterator childIt;
01594 
01595     if( !subspace.removeChild(backupMsg->getChild()) && !subspace.cachedChildren.erase( backupMsg->getChild()) ){
01596         for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01597             iit->children.erase( backupMsg->getChild() );
01598         }
01599     }
01600     if( !backupMsg->getIntermediate().isUnspecified() ){
01601         // remove intermediate
01602         for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01603             if( !iit->node.isUnspecified() && iit->node == backupMsg->getIntermediate() ){
01604                 for( childIt = iit->children.begin(); childIt != iit->children.end(); ++childIt ){
01605                     // FIXME: note really stable. let the resp node inform us about child moves
01606                     // remove children of last intermediate
01607                     if( subspace.getNumChildren() + subspace.getNumIntermediates() < maxChildren ){
01608                         // we have room for the child
01609                         subspace.children.insert( *childIt );
01610                     } else {
01611                         // Node has to go to some intermediate
01612                         // cache it
01613                         subspace.cachedChildren.insert( make_pair(*childIt, true) );
01614                     }
01615                 }
01616                 subspace.intermediateNodes.erase( iit );
01617                 break;
01618             }
01619         }
01620     }
01621 }
01622 
01623 void PubSubMMOG::unsubscribeChild( const NodeHandle& node, PubSubSubspaceResponsible& subspace )
01624 {
01625     PubSubBackupUnsubscribeMessage* backupMsg = new PubSubBackupUnsubscribeMessage("Backup: node left subspace");
01626     backupMsg->setChild( node );
01627     backupMsg->setSubspaceId( subspace.getId().getId() );
01628     PubSubSubspaceResponsible::IntermediateNode* iNode = subspace.removeAnyChild( node );
01629     if( iNode && !iNode->node.isUnspecified() ) {
01630         // Node is handled by an intermediate node, inform him
01631         PubSubNodeLeftMessage* goneMsg = new PubSubNodeLeftMessage("Node left Subspace");
01632         goneMsg->setNode( node );
01633         goneMsg->setSubspaceId( subspace.getId().getId() );
01634         goneMsg->setBitLength( PUBSUB_NODELEFT_L( goneMsg ));
01635         RECORD_STATS(
01636                 ++numPubSubSignalingMessages;
01637                 pubSubSignalingMessagesSize+= goneMsg->getByteLength()
01638                 );
01639         sendMessageToUDP( iNode->node, goneMsg );
01640     }
01641     if ( subspace.getTotalChildrenCount() < ( maxChildren - 1) * subspace.getNumIntermediates()){// FIXME: parameter when to start cleanup?
01642         // Too many "free" slots, remove one intermediate node
01643         PubSubSubspaceResponsible::IntermediateNode& liNode = subspace.intermediateNodes.back();
01644         if( !liNode.node.isUnspecified() ){
01645             // Inform node + lobby about release from intermediate node status
01646             PubSubReleaseIntermediateMessage* releaseMsg = new PubSubReleaseIntermediateMessage("I don't need you anymore as intermediate");
01647             releaseMsg->setSubspaceId( subspace.getId().getId() );
01648             releaseMsg->setBitLength( PUBSUB_RELEASEINTERMEDIATE_L( releaseMsg ));
01649             RECORD_STATS(
01650                     ++numPubSubSignalingMessages;
01651                     pubSubSignalingMessagesSize+= releaseMsg->getByteLength()
01652                     );
01653             sendMessageToUDP( liNode.node, releaseMsg );
01654 
01655             PubSubHelpReleaseMessage* helpRMsg = new PubSubHelpReleaseMessage("node is not my intermediate anymore");
01656             helpRMsg->setSubspaceId( subspace.getId().getId() );
01657             helpRMsg->setNode( liNode.node );
01658             helpRMsg->setBitLength( PUBSUB_HELPRELEASE_L( helpRMsg ));
01659             RECORD_STATS(
01660                     ++numPubSubSignalingMessages;
01661                     pubSubSignalingMessagesSize+= helpRMsg->getByteLength()
01662                     );
01663             sendMessageToUDP( lobbyServer, helpRMsg );
01664 
01665             // inform parent of intermediate node
01666             int parentPos = (subspace.intermediateNodes.size()-1)/maxChildren -1;
01667             if( parentPos >= 0 ){
01668                 PubSubSubspaceResponsible::IntermediateNode& parent = subspace.intermediateNodes[parentPos];
01669                 if( !parent.node.isUnspecified() ){
01670                     PubSubNodeLeftMessage* goneMsg = new PubSubNodeLeftMessage("Intermediate left Subspace");
01671                     goneMsg->setNode( liNode.node );
01672                     goneMsg->setSubspaceId( subspace.getId().getId() );
01673                     goneMsg->setBitLength( PUBSUB_NODELEFT_L( goneMsg ));
01674                     RECORD_STATS(
01675                             ++numPubSubSignalingMessages;
01676                             pubSubSignalingMessagesSize+= goneMsg->getByteLength()
01677                             );
01678                     sendMessageToUDP( parent.node, goneMsg );
01679                 }
01680             }
01681         }
01682 
01683         bool fixNeeded = false;
01684         set<NodeHandle>::iterator childIt;
01685         for( childIt = liNode.children.begin(); childIt != liNode.children.end(); ++childIt ){
01686             // remove children of last intermediate
01687             if( subspace.getNumChildren() + subspace.getNumIntermediates() < maxChildren ){
01688                 // we have room for the child
01689                 if( !subspace.children.insert( *childIt ).second ) fixNeeded = true;
01690 
01691                 //FIXME: send backup new->toMe
01692             } else {
01693                 // Node has to go to some intermediate
01694                 // find intermediate with free capacities
01695                 PubSubSubspaceResponsible::IntermediateNode* newINode;
01696                 newINode = subspace.getNextFreeIntermediate();
01697 
01698                 if( newINode  && newINode->node != liNode.node ){
01699                     // cache it
01700                     if( !subspace.cachedChildren.insert( make_pair(*childIt, true) ).second ) fixNeeded = true;
01701                     //FIXME: send backup new->toCache
01702 
01703                     ++(newINode->waitingChildren);
01704 
01705                     // let him adopt the child
01706                     PubSubAdoptChildCall* adoptCall = new PubSubAdoptChildCall("Adopt Node");
01707                     adoptCall->setSubspaceId( subspace.getId().getId() );
01708                     adoptCall->setChild( *childIt );
01709                     adoptCall->setBitLength( PUBSUB_ADOPTCHILDCALL_L( adoptCall ));
01710                     RECORD_STATS(
01711                             ++numPubSubSignalingMessages;
01712                             pubSubSignalingMessagesSize+= adoptCall->getByteLength()
01713                             );
01714                     sendUdpRpcCall( newINode->node, adoptCall );
01715                 } else {
01716                     // no intermediate found
01717                     // just move child to cache and wait for a new one
01718                     if( !subspace.cachedChildren.insert( make_pair(*childIt, false) ).second ) fixNeeded = true;
01719                 }
01720             }
01721         }
01722         // delete node from subspace's intermediate node list
01723         subspace.intermediateNodes.pop_back();
01724         // inform backup about deleted intermediate
01725         backupMsg->setIntermediate( liNode.node );
01726 
01727         if( fixNeeded ) subspace.fixTotalChildrenCount();
01728     }
01729 
01730 // FIXME: just for testing
01731 int iii = subspace.getTotalChildrenCount();
01732 subspace.fixTotalChildrenCount();
01733 if( iii != subspace.getTotalChildrenCount() ){
01734     opp_error("Huh?");
01735 }
01736 
01737     if( !subspace.getBackupNode().isUnspecified() ){
01738         backupMsg->setBitLength( PUBSUB_BACKUPUNSUBSCRIBE_L( backupMsg ));
01739         RECORD_STATS(
01740                 ++numPubSubSignalingMessages;
01741                 pubSubSignalingMessagesSize+= backupMsg->getByteLength()
01742                 );
01743         sendMessageToUDP( subspace.getBackupNode(), backupMsg );
01744     } else {
01745         delete backupMsg;
01746     }
01747 }
01748 
01749 void PubSubMMOG::sendMessageToChildren( PubSubSubspaceResponsible& subspace,
01750                                         BaseOverlayMessage* toIntermediates,
01751                                         BaseOverlayMessage* toBackup,
01752                                         BaseOverlayMessage* toPlayers )
01753 {
01754     BaseCallMessage* intermediateCall = dynamic_cast<BaseCallMessage*>(toIntermediates);
01755     BaseCallMessage* backupCall = dynamic_cast<BaseCallMessage*>(toBackup);
01756     BaseCallMessage* playerCall = dynamic_cast<BaseCallMessage*>(toPlayers);
01757 
01758     std::set<NodeHandle>::iterator childIt;
01759 
01760     if( toPlayers ) {
01761         // Inform all children ...
01762         for( childIt = subspace.children.begin(); childIt != subspace.children.end(); ++childIt ) {
01763             if( playerCall ){
01764                 RECORD_STATS(
01765                         ++numPubSubSignalingMessages;
01766                         pubSubSignalingMessagesSize+= playerCall->getByteLength()
01767                         );
01768                 sendUdpRpcCall( *childIt, static_cast<BaseCallMessage*>(playerCall->dup()) );
01769             } else {
01770                 RECORD_STATS(
01771                         ++numPubSubSignalingMessages;
01772                         pubSubSignalingMessagesSize+= toPlayers->getByteLength()
01773                         );
01774                 sendMessageToUDP( *childIt, static_cast<BaseOverlayMessage*>(toPlayers->dup()) );
01775             }
01776         }
01777         // ... and all cached children ...
01778         std::map<NodeHandle, bool>::iterator cacheChildIt;
01779         for( cacheChildIt = subspace.cachedChildren.begin(); cacheChildIt != subspace.cachedChildren.end(); ++cacheChildIt ) {
01780             if( playerCall ){
01781                 RECORD_STATS(
01782                         ++numPubSubSignalingMessages;
01783                         pubSubSignalingMessagesSize+= playerCall->getByteLength()
01784                         );
01785                 sendUdpRpcCall( cacheChildIt->first, static_cast<BaseCallMessage*>(playerCall->dup()) );
01786             } else {
01787                 RECORD_STATS(
01788                         ++numPubSubSignalingMessages;
01789                         pubSubSignalingMessagesSize+= toPlayers->getByteLength()
01790                         );
01791                 sendMessageToUDP( cacheChildIt->first, static_cast<BaseOverlayMessage*>(toPlayers->dup()) );
01792             }
01793         }
01794     }
01795     deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01796     // ... all intermediate nodes ...
01797     for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit ){
01798         if( toIntermediates && !iit->node.isUnspecified() ){
01799             if( intermediateCall ){
01800                 RECORD_STATS(
01801                         ++numPubSubSignalingMessages;
01802                         pubSubSignalingMessagesSize+= intermediateCall->getByteLength()
01803                         );
01804                 sendUdpRpcCall( iit->node, static_cast<BaseCallMessage*>(intermediateCall->dup()) );
01805             } else {
01806                 RECORD_STATS(
01807                         ++numPubSubSignalingMessages;
01808                         pubSubSignalingMessagesSize+= toIntermediates->getByteLength()
01809                         );
01810                 sendMessageToUDP( iit->node, static_cast<BaseOverlayMessage*>(toIntermediates->dup()) );
01811             }
01812         }
01813         if( toPlayers ) {
01814             // .. and all intermediate node's children ...
01815             for( childIt = iit->children.begin(); childIt != iit->children.end(); ++childIt ){
01816                 if( playerCall ){
01817                     RECORD_STATS(
01818                             ++numPubSubSignalingMessages;
01819                             pubSubSignalingMessagesSize+= playerCall->getByteLength()
01820                             );
01821                     sendUdpRpcCall( *childIt, static_cast<BaseCallMessage*>(playerCall->dup()) );
01822                 } else {
01823                     RECORD_STATS(
01824                             ++numPubSubSignalingMessages;
01825                             pubSubSignalingMessagesSize+= toPlayers->getByteLength()
01826                             );
01827                     sendMessageToUDP( *childIt, static_cast<BaseOverlayMessage*>(toPlayers->dup()) );
01828                 }
01829             }
01830         }
01831     }
01832     // ... and the backup node
01833     if( toBackup && !subspace.getBackupNode().isUnspecified() ) {
01834         if( backupCall ){
01835             RECORD_STATS(
01836                     ++numPubSubSignalingMessages;
01837                     pubSubSignalingMessagesSize+= backupCall->getByteLength()
01838                     );
01839             sendUdpRpcCall( subspace.getBackupNode(), static_cast<BaseCallMessage*>(backupCall->dup()) );
01840         } else {
01841             RECORD_STATS(
01842                     ++numPubSubSignalingMessages;
01843                     pubSubSignalingMessagesSize+= toBackup->getByteLength()
01844                     );
01845             sendMessageToUDP( subspace.getBackupNode(), static_cast<BaseOverlayMessage*>(toBackup->dup()) );
01846         }
01847     }
01848 }
01849 
01850 
01851 void PubSubMMOG::publishEvents()
01852 {
01853     // FOr all (responsible) subspaces
01854     int numRespSubspaces = responsibleSubspaces.size();
01855     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
01856     for( it = responsibleSubspaces.begin(); it != responsibleSubspaces.end(); ++it ){
01857         PubSubSubspaceResponsible& subspace = it->second;
01858 
01859         // Prepare a movement list message aggregating all stored move messages
01860         PubSubMoveListMessage* moveList = new PubSubMoveListMessage("Movement list");
01861         moveList->setTimestamp( simTime() );
01862         moveList->setSubspaceId( subspace.getId().getId() );
01863         moveList->setPlayerArraySize( subspace.waitingMoveMessages.size() );
01864         moveList->setPositionArraySize( subspace.waitingMoveMessages.size() );
01865         moveList->setPositionAgeArraySize( subspace.waitingMoveMessages.size() );
01866 
01867         std::deque<PubSubMoveMessage*>::iterator msgIt;
01868         int pos = 0;
01869         for( msgIt = subspace.waitingMoveMessages.begin(); msgIt != subspace.waitingMoveMessages.end(); ++msgIt ){
01870             moveList->setPlayer( pos, (*msgIt)->getPlayer() );
01871             moveList->setPosition( pos, (*msgIt)->getPosition() );
01872             moveList->setPositionAge( pos, simTime() - (*msgIt)->getCreationTime() );
01873             pos++;
01874             cancelAndDelete( *msgIt );
01875         }
01876         subspace.waitingMoveMessages.clear();
01877 
01878         moveList->setBitLength( PUBSUB_MOVELIST_L( moveList ));
01879         // Send message to all direct children...
01880         for( set<NodeHandle>::iterator childIt = subspace.children.begin();
01881                 childIt != subspace.children.end(); ++childIt )
01882         {
01883             RECORD_STATS(
01884                     ++numMoveListMessages;
01885                     moveListMessagesSize+= moveList->getByteLength();
01886                     respMoveListMessagesSize+= (int)((double) moveList->getByteLength() / numRespSubspaces)
01887                     );
01888             sendMessageToUDP( *childIt, (BaseOverlayMessage*) moveList->dup() );
01889         }
01890 
01891         //... all cached children (if messages are not too big) ...
01892         if( moveList->getByteLength() < 1024 ){ // FIXME: magic number. make it a parameter, or dependant on the available bandwidth
01893             for( map<NodeHandle, bool>::iterator childIt = subspace.cachedChildren.begin();
01894                     childIt != subspace.cachedChildren.end(); ++childIt )
01895             {
01896                 RECORD_STATS(
01897                         ++numMoveListMessages;
01898                         moveListMessagesSize+= moveList->getByteLength();
01899                         respMoveListMessagesSize+= (int)((double) moveList->getByteLength() / numRespSubspaces)
01900                         );
01901                 sendMessageToUDP( childIt->first, (BaseOverlayMessage*) moveList->dup() );
01902                 // ... but don't send msgs to too many cached children, as this would exhaust our bandwidth
01903             }
01904         }
01905 
01906         // ... all direct intermediates and intermediates with broken parent
01907         deque<PubSubSubspaceResponsible::IntermediateNode>::iterator iit;
01908         for( iit = subspace.intermediateNodes.begin(); iit != subspace.intermediateNodes.end(); ++iit )
01909         {
01910             int intermediatePos = iit - subspace.intermediateNodes.begin();
01911             if( intermediatePos >= maxChildren &&
01912                   !subspace.intermediateNodes[intermediatePos/maxChildren -1].node.isUnspecified() ) continue;
01913             if( !iit->node.isUnspecified() ) {
01914                 RECORD_STATS(
01915                         ++numMoveListMessages;
01916                         moveListMessagesSize+= moveList->getByteLength();
01917                         respMoveListMessagesSize+= (int)((double) moveList->getByteLength() / numRespSubspaces)
01918                 );
01919                 sendMessageToUDP( iit->node, (BaseOverlayMessage*) moveList->dup() );
01920             }
01921         }
01922 
01923         delete moveList;
01924     }
01925 }
01926 
01927 void PubSubMMOG::setBootstrapedIcon()
01928 {
01929     if(ev.isGUI()) {
01930         if(state == READY) {
01931             getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "green");
01932             getDisplayString().setTagArg("i", 1, "green");
01933         }
01934         else if(state == JOINING) {
01935             getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "yellow");
01936             getDisplayString().setTagArg("i", 1, "yellow");
01937         }
01938         else {
01939             getParentModule()->getParentModule()->getDisplayString().setTagArg("i2", 1, "red");
01940             getDisplayString().setTagArg("i", 1, "red");
01941         }
01942     }
01943 }
01944 
01945 void PubSubMMOG::startTimer( PubSubTimer* timer )
01946 {
01947     if( !timer ) {
01948         EV << "[PubSubMMOG::startTimer() @ " << thisNode.getAddress()
01949            << " (" << thisNode.getKey().toString(16) << ")]\n"
01950            << "    WARNING! Trying to start NULL timer @ " << thisNode << "\n"
01951            << endl;
01952         return;
01953     }
01954 
01955     if( timer->isScheduled() ) {
01956         cancelEvent( timer );
01957     }
01958 
01959     simtime_t duration = 0;
01960     switch( timer->getType() ) {
01961         case PUBSUB_HEARTBEAT:
01962             duration = parentTimeout/2;
01963             break;
01964         case PUBSUB_CHILDPING:
01965             duration = parentTimeout*10; // FIXME: make it a parameter
01966             break;
01967         case PUBSUB_PARENT_TIMEOUT:
01968             duration = parentTimeout;
01969             break;
01970         case PUBSUB_EVENTDELIVERY:
01971             duration = 1.0/movementRate;
01972             break;
01973     }
01974     scheduleAt(simTime() + duration, timer );
01975 }
01976 
01977 void PubSubMMOG::finishOverlay()
01978 {
01979     simtime_t time = globalStatistics->calcMeasuredLifetime(creationTime);
01980     if (time < GlobalStatistics::MIN_MEASURED) return;
01981 
01982     globalStatistics->addStdDev("PubSubMMOG: Sent Signaling Messages/s",
01983                                 numPubSubSignalingMessages / time);
01984     globalStatistics->addStdDev("PubSubMMOG: Sent Signaling bytes/s",
01985                                 pubSubSignalingMessagesSize / time);
01986     globalStatistics->addStdDev("PubSubMMOG: Sent Move Messages/s",
01987                                 numMoveMessages / time);
01988     globalStatistics->addStdDev("PubSubMMOG: Sent Move bytes/s",
01989                                 moveMessagesSize / time);
01990     globalStatistics->addStdDev("PubSubMMOG: Sent MoveList Messages/s",
01991                                 numMoveListMessages / time);
01992     globalStatistics->addStdDev("PubSubMMOG: Sent MoveList bytes/s",
01993                                 moveListMessagesSize / time);
01994     globalStatistics->addStdDev("PubSubMMOG: Received Move Events (correct timeslot)/s",
01995                                 numEventsCorrectTimeslot / time);
01996     globalStatistics->addStdDev("PubSubMMOG: Received Move Events (wrong timeslot)/s",
01997                                 numEventsWrongTimeslot / time);
01998     globalStatistics->addStdDev("PubSubMMOG: Responsible Nodes: Send MoveList Bytes/s",
01999                                 respMoveListMessagesSize / time);
02000     globalStatistics->addStdDev("PubSubMMOG: Lost or too long delayed MoveLists/s",
02001                                 lostMovementLists / time);
02002     globalStatistics->addStdDev("PubSubMMOG: Received valid MoveLists/s",
02003                                 receivedMovementLists / time);
02004 }
02005 
02006 PubSubMMOG::~PubSubMMOG()
02007 {
02008     // Delete all waiting move messages
02009     std::map<PubSubSubspaceId, PubSubSubspaceResponsible>::iterator it;
02010     for( it = responsibleSubspaces.begin(); it != responsibleSubspaces.end(); ++it) {
02011         deque<PubSubMoveMessage*>::iterator msgIt;
02012         for( msgIt = it->second.waitingMoveMessages.begin(); msgIt != it->second.waitingMoveMessages.end(); ++msgIt ){
02013             cancelAndDelete( *msgIt );
02014         }
02015         it->second.waitingMoveMessages.clear();
02016     }
02017 
02018     cancelAndDelete(heartbeatTimer);
02019 }
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3