Pastry.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 
00026 #include <cassert>
00027 
00028 #include <IPAddressResolver.h>
00029 #include <IPvXAddress.h>
00030 #include <IInterfaceTable.h>
00031 #include <IPv4InterfaceData.h>
00032 #include <RpcMacros.h>
00033 #include <InitStages.h>
00034 #include <GlobalStatistics.h>
00035 
00036 #include "Pastry.h"
00037 
00038 
00039 Define_Module(Pastry);
00040 
00041 Pastry::~Pastry()
00042 {
00043     // destroy self timer messages
00044     cancelAndDelete(readyWait);
00045     cancelAndDelete(joinUpdateWait);
00046     cancelAndDelete(secondStageWait);
00047     if (useDiscovery) cancelAndDelete(discoveryTimeout);
00048     if (routingTableMaintenanceInterval > 0) cancelAndDelete(repairTaskTimeout);
00049 
00050     clearVectors();
00051 }
00052 
00053 void Pastry::clearVectors()
00054 {
00055     // purge pending state messages
00056     if (!stReceived.empty()) {
00057         for (std::vector<PastryStateMsgHandle>::iterator it =
00058             stReceived.begin(); it != stReceived.end(); it++) {
00059             // check whether one of the pointers is a duplicate of stateCache
00060             if (it->msg == stateCache.msg) stateCache.msg = NULL;
00061             if (it->prox == stateCache.prox) stateCache.prox = NULL;
00062             delete it->msg;
00063             delete it->prox;
00064         }
00065         stReceived.clear();
00066         stReceivedPos = stReceived.end();
00067     }
00068 
00069     // purge notify list:
00070     notifyList.clear();
00071 }
00072 
00073 void Pastry::purgeVectors(void)
00074 {
00075     clearVectors();
00076 
00077     BasePastry::purgeVectors();
00078 }
00079 
00080 void Pastry::initializeOverlay(int stage)
00081 {
00082     if ( stage != MIN_STAGE_OVERLAY )
00083         return;
00084 
00085     // Pastry provides KBR services
00086     kbr = true;
00087 
00088     baseInit();
00089 
00090     useDiscovery = par("useDiscovery");
00091     pingBeforeSecondStage = par("pingBeforeSecondStage");
00092     secondStageInterval = par("secondStageWait");
00093     discoveryTimeoutAmount = par("discoveryTimeoutAmount");
00094     routingTableMaintenanceInterval = par("routingTableMaintenanceInterval");
00095     sendStateAtLeafsetRepair = par("sendStateAtLeafsetRepair");
00096     partialJoinPath = par("partialJoinPath");
00097     readyWaitAmount = par("readyWait");
00098     minimalJoinState = par("minimalJoinState");
00099 
00100     overrideOldPastry = par("overrideOldPastry");
00101     overrideNewPastry = par("overrideNewPastry");
00102 
00103     if (overrideOldPastry) {
00104         //useSecondStage = true;
00105         //secondStageInterval = ???;
00106         useDiscovery = false;
00107         sendStateAtLeafsetRepair = true;
00108         routingTableMaintenanceInterval = 0;
00109     }
00110 
00111     if (overrideNewPastry) {
00112         //useSecondStage = false;
00113         secondStageInterval = 0;
00114         useDiscovery = true;
00115         discoveryTimeoutAmount = 0.4;
00116         routingTableMaintenanceInterval = 60;
00117         sendStateAtLeafsetRepair = false;
00118     }
00119 
00120     joinTimeout = new cMessage("joinTimeout");
00121     readyWait = new cMessage("readyWait");
00122     secondStageWait = new cMessage("secondStageWait");
00123     joinUpdateWait = new cMessage("joinUpdateWait");
00124 
00125     discoveryTimeout =
00126         (useDiscovery ? new cMessage("discoveryTimeout") : NULL);
00127     repairTaskTimeout =
00128         ((routingTableMaintenanceInterval > 0) ?
00129                 new cMessage("repairTaskTimeout") : NULL);
00130 
00131     updateCounter = 0;
00132 }
00133 
00134 void Pastry::joinOverlay()
00135 {
00136     changeState(INIT);
00137 
00138     if (bootstrapNode.isUnspecified()) {
00139         // no existing pastry network -> first node of a new one
00140         changeState(READY);
00141     } else {
00142         // join existing pastry network
00143         nearNode = bootstrapNode;
00144         if (useDiscovery) changeState(DISCOVERY);
00145         else changeState(JOINING_2);
00146     }
00147 }
00148 
00149 void Pastry::changeState(int toState)
00150 {
00151     if (readyWait->isScheduled()) cancelEvent(readyWait);
00152     baseChangeState(toState);
00153 
00154     switch (toState) {
00155     case INIT:
00156         cancelAllRpcs();
00157         purgeVectors();
00158         break;
00159 
00160     case DISCOVERY:
00161         state = DISCOVERY;
00162         //nearNode = bootstrapNode;
00163         nearNodeRtt = MAXTIME;
00164         pingNode(bootstrapNode, discoveryTimeoutAmount, 0,
00165                  NULL, "PING bootstrapNode in discovery mode",
00166                  NULL, PING_DISCOVERY, UDP_TRANSPORT); //TODO
00167         sendRequest(bootstrapNode, PASTRY_REQ_LEAFSET); //TODO should be an RPC
00168         depth = -1;
00169 
00170         // schedule join timer for discovery algorithm
00171         cancelEvent(joinTimeout);
00172         scheduleAt(simTime() + joinTimeoutAmount, joinTimeout);
00173 
00174         break;
00175 
00176     case JOINING_2: {
00177         joinHopCount = 0;
00178         PastryJoinMessage* msg = new PastryJoinMessage("JOIN-Request");
00179         //TODO add timestamp to join msg
00180         msg->setPastryMsgType(PASTRY_MSG_JOIN);
00181         msg->setStatType(MAINTENANCE_STAT);
00182         msg->setSendStateTo(thisNode);
00183         msg->setBitLength(PASTRYJOIN_L(msg));
00184         RECORD_STATS(joinSent++; joinBytesSent += msg->getByteLength());
00185         std::vector<TransportAddress> sourceRoute;
00186         sourceRoute.push_back(nearNode);
00187         sendToKey(thisNode.getKey(), msg, 0/*1*/, sourceRoute);
00188     }
00189     break;
00190 
00191     case READY:
00192         // determine list of all known nodes as notifyList
00193         notifyList.clear();
00194         leafSet->dumpToVector(notifyList);
00195         routingTable->dumpToVector(notifyList);
00196         sort(notifyList.begin(), notifyList.end());
00197         notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00198                          notifyList.end());
00199 
00200         // schedule update
00201         cancelEvent(joinUpdateWait);
00202         scheduleAt(simTime() + 0.0001, joinUpdateWait);
00203 
00204         // schedule second stage
00205         if (secondStageInterval > 0) {
00206             cancelEvent(secondStageWait);
00207             scheduleAt(simTime() + secondStageInterval, secondStageWait);
00208         }
00209 
00210         // schedule routing table maintenance task
00211         if (routingTableMaintenanceInterval > 0) {
00212             cancelEvent(repairTaskTimeout);
00213             scheduleAt(simTime() + routingTableMaintenanceInterval, repairTaskTimeout);
00214         }
00215 
00216         break;
00217     }
00218 }
00219 
00220 
00221 void Pastry::pingResponse(PingResponse* pingResponse,
00222                           cPolymorphic* context, int rpcId,
00223                           simtime_t rtt)
00224 {
00225     if (state == DISCOVERY) {
00226         EV << "[Pastry::pingResponse() @ " << thisNode.getAddress()
00227            << " (" << thisNode.getKey().toString(16) << ")]\n"
00228            << "    Pong (or Ping-context from NeighborCache) received (from "
00229            << pingResponse->getSrcNode().getAddress() << ") in DISCOVERY mode"
00230            << endl;
00231 
00232         if (nearNodeRtt > rtt) {
00233             nearNode = pingResponse->getSrcNode();
00234             nearNodeRtt = rtt;
00235             nearNodeImproved = true;
00236         }
00237     } else {
00238         BasePastry::pingResponse(pingResponse, context, rpcId, rtt);
00239     }
00240 }
00241 
00242 
00243 void Pastry::handleTimerEvent(cMessage* msg)
00244 {
00245 
00246     if (msg == joinTimeout) {
00247         EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00248            << " (" << thisNode.getKey().toString(16) << ")]\n"
00249            << "    timeout expired, restarting..."
00250            << endl;
00251         join();
00252     } else if (msg == readyWait) {
00253         if (partialJoinPath) {
00254             RECORD_STATS(joinPartial++);
00255             sort(stReceived.begin(), stReceived.end(), stateMsgIsSmaller);
00256 
00257             // start pinging the nodes found in the first state message:
00258             stReceivedPos = stReceived.begin();
00259             stateCache = *stReceivedPos;
00260             EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00261                << " (" << thisNode.getKey().toString(16) << ")]\n"
00262                << "    joining despite some missing STATE messages."
00263                << endl;
00264             processState();
00265         } else {
00266             EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00267                << " (" << thisNode.getKey().toString(16) << ")]\n"
00268                << "    timeout waiting for missing state messages"
00269                << " in JOIN state, restarting..."
00270                << endl;
00271             joinOverlay();
00272         }
00273     } else if (msg == joinUpdateWait) {
00274         EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00275            << " (" << thisNode.getKey().toString(16) << ")]\n"
00276            << "    sending state updates to all nodes."
00277            << endl;
00278         doJoinUpdate();
00279     } else if (msg == secondStageWait) {
00280         EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00281            << " (" << thisNode.getKey().toString(16) << ")]\n"
00282            << "    sending STATE requests to all nodes in"
00283            << " second stage of initialization."
00284            << endl;
00285         doSecondStage();
00286     } else if (msg->isName("sendStateWait")) {
00287         PastrySendState* sendStateMsg = check_and_cast<PastrySendState*>(msg);
00288 
00289         std::vector<PastrySendState*>::iterator pos =
00290             std::find(sendStateWait.begin(), sendStateWait.end(),
00291                       sendStateMsg);
00292         if (pos != sendStateWait.end()) sendStateWait.erase(pos);
00293 
00294         sendStateTables(sendStateMsg->getDest());
00295         delete sendStateMsg;
00296     } else if (msg == discoveryTimeout) {
00297         if ((depth == 0) && (nearNodeImproved)) {
00298             depth++; //repeat last step if closer node was found
00299         }
00300         if ((depth == 0) || (pingedNodes < 1)) {
00301             changeState(JOINING_2);
00302         } else {
00303             PastryRoutingRowRequestMessage* msg =
00304                 new PastryRoutingRowRequestMessage("ROWREQ");
00305             msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00306             msg->setStatType(MAINTENANCE_STAT);
00307             msg->setSendStateTo(thisNode);
00308             msg->setRow(depth);
00309             msg->setBitLength(PASTRYRTREQ_L(msg));
00310             RECORD_STATS(routingTableReqSent++;
00311                          routingTableReqBytesSent += msg->getByteLength());
00312             sendMessageToUDP(nearNode, msg);
00313         }
00314     } else if (msg == repairTaskTimeout) {
00315         EV << "[Pastry::handleTimerEvent() @ " << thisNode.getAddress()
00316            << " (" << thisNode.getKey().toString(16) << ")]\n"
00317            << "    starting routing table maintenance"
00318            << endl;
00319         doRoutingTableMaintenance();
00320         scheduleAt(simTime() + routingTableMaintenanceInterval,
00321                    repairTaskTimeout);
00322     }
00323 }
00324 
00325 void Pastry::handleUDPMessage(BaseOverlayMessage* msg)
00326 {
00327     PastryMessage* pastryMsg = check_and_cast<PastryMessage*>(msg);
00328     uint32_t type = pastryMsg->getPastryMsgType();
00329 
00330     if (debugOutput) {
00331         EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00332            << " (" << thisNode.getKey().toString(16) << ")]\n"
00333            << "    incoming message of type ";
00334         switch(type) {
00335         case PASTRY_MSG_STD:
00336             EV << "PASTRY_MSG_STD";
00337             break;
00338         case PASTRY_MSG_JOIN:
00339             EV << "PASTRY_MSG_JOIN";
00340             break;
00341         case PASTRY_MSG_STATE:
00342             EV << "PASTRY_MSG_STATE";
00343             break;
00344         case PASTRY_MSG_LEAFSET:
00345             EV << "PASTRY_MSG_LEAFSET";
00346             break;
00347         case PASTRY_MSG_ROWREQ:
00348             EV << "PASTRY_MSG_ROWREQ";
00349             break;
00350         case PASTRY_MSG_RROW:
00351             EV << "PASTRY_MSG_RROW";
00352             break;
00353         case PASTRY_MSG_REQ:
00354             EV << "PASTRY_MSG_REQ";
00355             break;
00356         default:
00357             EV << "UNKNOWN (" << type <<")";
00358             break;
00359         }
00360         EV << endl;
00361     }
00362 
00363     switch (type) {
00364     case PASTRY_MSG_STD:
00365         opp_error("Pastry received PastryMessage of unknown type!");
00366         break;
00367 
00368     case PASTRY_MSG_JOIN: {
00369         PastryJoinMessage* jmsg =
00370             check_and_cast<PastryJoinMessage*>(pastryMsg);
00371         RECORD_STATS(joinReceived++; joinBytesReceived +=
00372                      jmsg->getByteLength());
00373         if (state != READY) {
00374             if (jmsg->getSendStateTo() == thisNode) {
00375                 EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00376                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00377                    << "    PastryJoinMessage received by originator!"
00378                    << endl;
00379             } else {
00380                 EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00381                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00382                    << "    received join message before reaching "
00383                    << "READY state, dropping message!"
00384                    << endl;
00385             }
00386         }
00387         else if (jmsg->getSendStateTo() == thisNode) {
00388             EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00389                << " (" << thisNode.getKey().toString(16) << ")]\n"
00390                << "    PastryJoinMessage gets dropped because it is "
00391                << "outdated and has been received by originator!"
00392                << endl;
00393         } else {
00394             OverlayCtrlInfo* overlayCtrlInfo
00395                 = check_and_cast<OverlayCtrlInfo*>(jmsg->getControlInfo());
00396 
00397             uint32_t joinHopCount =  overlayCtrlInfo->getHopCount();
00398             if ((joinHopCount > 1) &&
00399                 ((defaultRoutingType == ITERATIVE_ROUTING) ||
00400                  (defaultRoutingType == EXHAUSTIVE_ITERATIVE_ROUTING)))
00401                  joinHopCount--;
00402 
00403             // remove node from state if it is rejoining
00404             handleFailedNode(jmsg->getSendStateTo());
00405 
00406             sendStateTables(jmsg->getSendStateTo(),
00407                             (minimalJoinState ?
00408                               PASTRY_STATE_MINJOIN : PASTRY_STATE_JOIN),
00409                              joinHopCount, true);
00410         }
00411 
00412         delete jmsg;
00413     }
00414     break;
00415 
00416     case PASTRY_MSG_LEAFSET: {
00417         PastryLeafsetMessage* lmsg =
00418             check_and_cast<PastryLeafsetMessage*>(pastryMsg);
00419         RECORD_STATS(leafsetReceived++; leafsetBytesReceived +=
00420             lmsg->getByteLength());
00421 
00422         if (state == DISCOVERY) {
00423             uint32_t lsSize = lmsg->getLeafSetArraySize();
00424             const NodeHandle* node;
00425             pingedNodes = 0;
00426 
00427             for (uint32_t i = 0; i < lsSize; i++) {
00428                 node = &(lmsg->getLeafSet(i));
00429                 // unspecified nodes not considered
00430                 if ( !(node->isUnspecified()) ) {
00431                     pingNode(*node, discoveryTimeoutAmount, 0,
00432                              NULL, "PING received leafs for nearest node",
00433                              NULL, -1, UDP_TRANSPORT);//TODO
00434                     pingedNodes++;
00435                }
00436             }
00437 
00438             EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00439                << " (" << thisNode.getKey().toString(16) << ")]\n"
00440                << "    received leafset, waiting for pings"
00441               << endl;
00442 
00443             if (discoveryTimeout->isScheduled()) cancelEvent(discoveryTimeout);
00444             scheduleAt(simTime() + discoveryTimeoutAmount, discoveryTimeout);
00445             delete lmsg;
00446         } else if (state == READY) {
00447             handleLeafsetMessage(lmsg, false);
00448         } else {
00449             delete lmsg;
00450         }
00451     }
00452     break;
00453 
00454     case PASTRY_MSG_ROWREQ: {
00455         PastryRoutingRowRequestMessage* rtrmsg =
00456             check_and_cast<PastryRoutingRowRequestMessage*>(pastryMsg);
00457         RECORD_STATS(routingTableReqReceived++; routingTableReqBytesReceived +=
00458             rtrmsg->getByteLength());
00459         if (state == READY)
00460             if (rtrmsg->getRow() == -1)
00461                 sendRoutingRow(rtrmsg->getSendStateTo(), routingTable->getLastRow());
00462                 else if (rtrmsg->getRow() > routingTable->getLastRow())
00463                     EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00464                        << " (" << thisNode.getKey().toString(16) << ")]\n"
00465                        << "    received request for nonexistent routing"
00466                        << "table row, dropping message!"
00467                        << endl;
00468                 else sendRoutingRow(rtrmsg->getSendStateTo(), rtrmsg->getRow());
00469         else
00470             EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00471                << " (" << thisNode.getKey().toString(16) << ")]\n"
00472                << "    received routing table request before reaching "
00473                << "READY state, dropping message!"
00474                << endl;
00475         delete rtrmsg;
00476     }
00477     break;
00478 
00479     case PASTRY_MSG_RROW: {
00480         PastryRoutingRowMessage* rtmsg =
00481             check_and_cast<PastryRoutingRowMessage*>(pastryMsg);
00482         RECORD_STATS(routingTableReceived++; routingTableBytesReceived +=
00483             rtmsg->getByteLength());
00484 
00485         if (state == DISCOVERY) {
00486             uint32_t nodesPerRow = rtmsg->getRoutingTableArraySize();
00487             const NodeHandle* node;
00488             if (depth == -1) {
00489                 depth = rtmsg->getRow();
00490             }
00491             pingedNodes = 0;
00492             nearNodeImproved = false;
00493 
00494             if (depth > 0) {
00495                 for (uint32_t i = 0; i < nodesPerRow; i++) {
00496                     node = &(rtmsg->getRoutingTable(i));
00497                     // unspecified nodes not considered
00498                     if ( !(node->isUnspecified()) ) {
00499                         // we look for best connection here, so Timeout is short and there are no retries
00500                         pingNode(*node, discoveryTimeoutAmount, 0, NULL,
00501                                  "PING received routing table for nearest node",
00502                                  NULL, -1, UDP_TRANSPORT); //TODO
00503                         pingedNodes++;
00504                     }
00505                 }
00506                 depth--;
00507             }
00508             EV << "[Pastry::handleUDPMessage() @ " << thisNode.getAddress()
00509                << " (" << thisNode.getKey().toString(16) << ")]\n"
00510                << "    received routing table, waiting for pings"
00511                << endl;
00512             if (discoveryTimeout->isScheduled()) {
00513                 cancelEvent(discoveryTimeout);
00514             }
00515             scheduleAt(simTime() + discoveryTimeoutAmount, discoveryTimeout);
00516         }
00517 
00518         else if (state == READY) {
00519 
00520             uint32_t nodesPerRow = rtmsg->getRoutingTableArraySize();
00521             PastryStateMessage* stateMsg;
00522 
00523             stateMsg = new PastryStateMessage("STATE");
00524             stateMsg->setTimestamp(rtmsg->getTimestamp());
00525             stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00526             stateMsg->setStatType(MAINTENANCE_STAT);
00527             stateMsg->setSender(rtmsg->getSender());
00528             stateMsg->setLeafSetArraySize(0);
00529             stateMsg->setNeighborhoodSetArraySize(0);
00530             stateMsg->setRoutingTableArraySize(nodesPerRow);
00531 
00532             for (uint32_t i = 0; i < nodesPerRow; i++) {
00533                 stateMsg->setRoutingTable(i, rtmsg->getRoutingTable(i));
00534             }
00535 
00536             handleStateMessage(stateMsg);
00537         }
00538 
00539         delete rtmsg;
00540     }
00541     break;
00542 
00543     case PASTRY_MSG_REQ: {
00544         PastryRequestMessage* lrmsg =
00545             check_and_cast<PastryRequestMessage*>(pastryMsg);
00546         handleRequestMessage(lrmsg);
00547     }
00548     break;
00549 
00550     case PASTRY_MSG_STATE: {
00551         PastryStateMessage* stateMsg =
00552             check_and_cast<PastryStateMessage*>(msg);
00553         RECORD_STATS(stateReceived++; stateBytesReceived +=
00554                      stateMsg->getByteLength());
00555         handleStateMessage(stateMsg);
00556     }
00557     break;
00558     }
00559 }
00560 
00561 
00562 bool Pastry::recursiveRoutingHook(const TransportAddress& dest,
00563                                   BaseRouteMessage* msg)
00564 {
00565     if (dest == thisNode) {
00566         return true;
00567     }
00568 
00569     PastryMessage* pmsg =
00570         dynamic_cast<PastryMessage*>(msg->getEncapsulatedPacket());
00571 
00572     if (pmsg && pmsg->getPastryMsgType() == PASTRY_MSG_JOIN) {
00573         PastryJoinMessage* jmsg = static_cast<PastryJoinMessage*>(pmsg);
00574         if (jmsg->getSendStateTo() != thisNode) {
00575             RECORD_STATS(joinSeen++; joinBytesSeen += jmsg->getByteLength());
00576             // remove node from state if it is rejoining
00577             handleFailedNode(jmsg->getSendStateTo());
00578 
00579             sendStateTables(jmsg->getSendStateTo(),
00580                             minimalJoinState ?
00581                             PASTRY_STATE_MINJOIN : PASTRY_STATE_JOIN,
00582                             check_and_cast<OverlayCtrlInfo*>(msg->getControlInfo())
00583                             ->getHopCount(), false);
00584         }
00585     }
00586 
00587     // forward now:
00588     return true;
00589 }
00590 
00591 void Pastry::iterativeJoinHook(BaseOverlayMessage* msg, bool incrHopCount)
00592 {
00593     PastryFindNodeExtData* findNodeExt = NULL;
00594     if (msg && msg->hasObject("findNodeExt")) {
00595         findNodeExt =
00596             check_and_cast<PastryFindNodeExtData*>(msg->
00597                     getObject("findNodeExt"));
00598     }
00599     // Send state tables on any JOIN message we see:
00600     if (findNodeExt) {
00601         const TransportAddress& stateRecipient =
00602             findNodeExt->getSendStateTo();
00603         if (!stateRecipient.isUnspecified()) {
00604             RECORD_STATS(joinSeen++);
00605             sendStateTables(stateRecipient,
00606                             minimalJoinState ?
00607                             PASTRY_STATE_MINJOIN : PASTRY_STATE_JOIN,
00608                             findNodeExt->getJoinHopCount(), false);
00609         }
00610         if (incrHopCount) {
00611             findNodeExt->setJoinHopCount(findNodeExt->getJoinHopCount() + 1);
00612         }
00613     }
00614 }
00615 
00616 
00617 void Pastry::doJoinUpdate(void)
00618 {
00619     // send "update" state message to all nodes who sent us their state
00620     // during INIT, remove these from notifyList so they don't get our
00621     // state twice
00622     std::vector<TransportAddress>::iterator nListPos;
00623     if (!stReceived.empty()) {
00624         for (std::vector<PastryStateMsgHandle>::iterator it =
00625                  stReceived.begin(); it != stReceived.end(); ++it) {
00626             simtime_t timestamp = it->msg->getTimestamp();
00627             sendStateTables(it->msg->getSender(), PASTRY_STATE_UPDATE,
00628                             &timestamp);
00629             nListPos = find(notifyList.begin(), notifyList.end(),
00630                             it->msg->getSender());
00631             if (nListPos != notifyList.end()) {
00632                 notifyList.erase(nListPos);
00633             }
00634             delete it->msg;
00635             delete it->prox;
00636         }
00637         stReceived.clear();
00638     }
00639 
00640     // send a normal STATE message to all remaining known nodes
00641     for (std::vector<TransportAddress>::iterator it =
00642              notifyList.begin(); it != notifyList.end(); it++) {
00643         if (*it != thisNode) sendStateTables(*it, PASTRY_STATE_JOINUPDATE);
00644     }
00645     notifyList.clear();
00646 
00647     updateTooltip();
00648 }
00649 
00650 void Pastry::doSecondStage(void)
00651 {
00652     getParentModule()->getParentModule()->bubble("entering SECOND STAGE");
00653 
00654     // probe nodes in local state
00655     if (leafSet->isValid()) {
00656         PastryStateMessage* stateMsg = new PastryStateMessage("STATE");
00657         stateMsg->setPastryMsgType(PASTRY_MSG_STATE);
00658         stateMsg->setStatType(MAINTENANCE_STAT);
00659         stateMsg->setPastryStateMsgType(PASTRY_STATE_STD);
00660         stateMsg->setSender(thisNode);
00661         routingTable->dumpToStateMessage(stateMsg);
00662         leafSet->dumpToStateMessage(stateMsg);
00663         neighborhoodSet->dumpToStateMessage(stateMsg);
00664         //stateMsg->setBitLength(PASTRYSTATE_L(stateMsg));
00665         PastryStateMsgHandle handle(stateMsg);
00666 
00667         if (!stateCache.msg) {
00668             stateCache = handle;
00669             processState();
00670         } else {
00671             stateCacheQueue.push(handle);
00672             prePing(stateMsg);
00673         }
00674     }
00675 
00676     // "second stage" for locality:
00677     notifyList.clear();
00678     routingTable->dumpToVector(notifyList);
00679     neighborhoodSet->dumpToVector(notifyList);
00680     sort(notifyList.begin(), notifyList.end());
00681     notifyList.erase(unique(notifyList.begin(), notifyList.end()),
00682                      notifyList.end());
00683     for (std::vector<TransportAddress>::iterator it = notifyList.begin();
00684          it != notifyList.end(); it++) {
00685         if (*it == thisNode) continue;
00686         EV << "[Pastry::doSecondStage() @ " << thisNode.getAddress()
00687            << " (" << thisNode.getKey().toString(16) << ")]\n"
00688            << "    second stage: requesting state from " << *it
00689            << endl;
00690         sendRequest(*it, PASTRY_REQ_STATE);
00691     }
00692     notifyList.clear();
00693 }
00694 
00695 
00696 void Pastry::doRoutingTableMaintenance()
00697 {
00698     for (int i = 0; i < routingTable->getLastRow(); i++) {
00699         const TransportAddress& ask4row = routingTable->getRandomNode(i);
00700 
00701         if ((!ask4row.isUnspecified()) && (ask4row != thisNode)) {
00702             PastryRoutingRowRequestMessage* msg =
00703                 new PastryRoutingRowRequestMessage("ROWREQ");
00704             msg->setPastryMsgType(PASTRY_MSG_ROWREQ);
00705             msg->setStatType(MAINTENANCE_STAT);
00706             msg->setSendStateTo(thisNode);
00707             msg->setRow(i + 1);
00708             msg->setBitLength(PASTRYRTREQ_L(msg));
00709 
00710             RECORD_STATS(routingTableReqSent++;
00711                          routingTableReqBytesSent += msg->getByteLength());
00712 
00713             sendMessageToUDP(ask4row, msg);
00714         } else {
00715             EV << "[Pastry::doRoutingTableMaintenance() @ "
00716                << thisNode.getAddress()
00717                << " (" << thisNode.getKey().toString(16) << ")]\n"
00718                << "    could not send Message to Node in Row" << i
00719                << endl;
00720         }
00721     }
00722 }
00723 
00724 
00725 bool Pastry::handleFailedNode(const TransportAddress& failed)
00726 {
00727     if (state != READY) {
00728         return false;
00729     }
00730     bool wasValid = leafSet->isValid();
00731 
00732     //std::cout << thisNode.getAddress() << " is handling failed node: "
00733     //          << failed.getAddress() << std::endl;
00734     if (failed.isUnspecified())
00735         opp_error("Pastry::handleFailedNode(): failed is unspecified!");
00736 
00737     const TransportAddress& lsAsk = leafSet->failedNode(failed);
00738     const TransportAddress& rtAsk = routingTable->failedNode(failed);
00739     neighborhoodSet->failedNode(failed);
00740 
00741     if (! lsAsk.isUnspecified()) {
00742         newLeafs();
00743         if (sendStateAtLeafsetRepair) sendRequest(lsAsk, PASTRY_REQ_REPAIR);
00744         else sendRequest(lsAsk, PASTRY_REQ_LEAFSET);
00745     }
00746     if (! rtAsk.isUnspecified() &&
00747         (lsAsk.isUnspecified() ||
00748          lsAsk != rtAsk)) sendRequest(rtAsk, PASTRY_REQ_REPAIR);
00749 
00750     if (wasValid && lsAsk.isUnspecified() && (! leafSet->isValid())) {
00751         EV << "[Pastry::handleFailedNode() @ " << thisNode.getAddress()
00752            << " (" << thisNode.getKey().toString(16) << ")]\n"
00753            << "    lost connection to the network, trying to re-join."
00754            << endl;
00755         //std::cout << thisNode.getAddress()
00756         //          << " Pastry: lost connection to the network, trying to re-join."
00757         //          << std::endl;
00758         join();
00759         return false;
00760     }
00761 
00762     return true;
00763 }
00764 
00765 void Pastry::checkProxCache(void)
00766 {
00767     EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00768        << " (" << thisNode.getKey().toString(16) << ")]"
00769        << endl;
00770 
00771     // no cached STATE message?
00772     assert(stateCache.msg || !stateCache.prox);
00773     if (!stateCache.msg) return;
00774 
00775     // no entries in stateCache.prox?
00776     if (stateCache.prox->pr_rt.empty() &&
00777         stateCache.prox->pr_ls.empty() &&
00778         stateCache.prox->pr_ns.empty())
00779         throw new cRuntimeError("ERROR in Pastry: stateCache.prox empty!");
00780 
00781     /*
00782     //debug
00783     for (uint i = 0; i < stateCache.prox->pr_rt.size(); ++i) {
00784         if (stateCache.prox->pr_rt[i] == -3)
00785             EV << stateCache.msg->getRoutingTable(i).getAddress() << " ";
00786     }
00787     for (uint i = 0; i < stateCache.prox->pr_ls.size(); ++i) {
00788         if (stateCache.prox->pr_ls[i] == -3)
00789             EV << stateCache.msg->getLeafSet(i).getAddress() << " ";
00790     }
00791     for (uint i = 0; i < stateCache.prox->pr_ns.size(); ++i) {
00792         if (stateCache.prox->pr_ns[i] == -3)
00793             EV << stateCache.msg->getNeighborhoodSet(i).getAddress() << " ";
00794     }
00795     EV << endl;
00796      */
00797 
00798     // some entries not yet determined?
00799     if ((find(stateCache.prox->pr_rt.begin(), stateCache.prox->pr_rt.end(),
00800         PASTRY_PROX_PENDING) != stateCache.prox->pr_rt.end()) ||
00801         (find(stateCache.prox->pr_ls.begin(), stateCache.prox->pr_ls.end(),
00802          PASTRY_PROX_PENDING) != stateCache.prox->pr_ls.end()) ||
00803         (find(stateCache.prox->pr_ns.begin(), stateCache.prox->pr_ns.end(),
00804          PASTRY_PROX_PENDING) != stateCache.prox->pr_ns.end())) {
00805         //std::cout << "pending" << std::endl;
00806         return;
00807     }
00808 
00809     EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00810        << " (" << thisNode.getKey().toString(16) << ")]\n"
00811        << "    all proximities for current STATE message from "
00812        << stateCache.msg->getSender().getAddress()
00813        << " collected!"
00814        << endl;
00815     /*
00816     //debug
00817     if (stateCache.prox != NULL) {
00818         std::vector<PastryStateMsgHandle>::iterator it;
00819         for (it = stReceived.begin(); it != stReceived.end(); ++it) {
00820             if (it->prox == NULL) {
00821                 EV << ". " << endl;
00822                 continue;
00823             }
00824             for (uint i = 0; i < it->prox->pr_rt.size(); ++i) {
00825                 EV << it->prox->pr_rt[i] << " ";
00826             }
00827             for (uint i = 0; i < it->prox->pr_ls.size(); ++i) {
00828                 EV << it->prox->pr_ls[i] << " ";
00829             }
00830             for (uint i = 0; i < it->prox->pr_ns.size(); ++i) {
00831                 EV << it->prox->pr_ns[i] << " ";
00832             }
00833             EV << endl;
00834         }
00835         EV << endl;
00836     } else EV << "NULL" << endl;
00837 */
00838 
00839     simtime_t now = simTime();
00840 
00841     if (state == JOINING_2) {
00842         // save pointer to proximity vectors (it is NULL until now):
00843         stReceivedPos->prox = stateCache.prox;
00844 
00845         // collected proximities for all STATE messages?
00846         if (++stReceivedPos == stReceived.end()) {
00847             EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00848                << " (" << thisNode.getKey().toString(16) << ")]\n"
00849                << "    proximities for all STATE messages collected!"
00850                << endl;
00851             stateCache.msg = NULL;
00852             stateCache.prox = NULL;
00853             if (debugOutput) {
00854                 EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00855                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00856                    << "    [JOIN] starting to build own state from "
00857                    << stReceived.size() << " received state messages..."
00858                    << endl;
00859             }
00860             if (mergeState()) {
00861                 changeState(READY);
00862                 EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00863                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00864                    << "    changeState(READY) called"
00865                    << endl;
00866             } else {
00867                 EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00868                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00869                    << "    Error initializing while joining! Restarting ..."
00870                    << endl;
00871                 joinOverlay();
00872             }
00873 
00874         } else {
00875             EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00876                << " (" << thisNode.getKey().toString(16) << ")]\n"
00877                << "    NOT all proximities for all STATE messages collected!"
00878                << endl;
00879             /*
00880             for (uint32_t i = 0; i < stReceived.size(); ++i) {
00881                 EV << ((i == 0) ? "    " : " | ");
00882                 std::cout << ((i == 0) ? "    " : " | ");
00883                 if (stReceived[i].msg == stReceivedPos->msg) {
00884                     EV << "*";
00885                     std::cout << "*";
00886                 }
00887                 EV << stReceived[i].msg << " " << stReceived[i].prox;
00888                 std::cout << stReceived[i].msg << " " << stReceived[i].prox;
00889             }
00890             EV << endl;
00891             std::cout << std::endl;
00892              */
00893 
00894             // process next state message in vector:
00895             if (stReceivedPos->msg == NULL)
00896                 throw cRuntimeError("stReceivedPos->msg = NULL");
00897             stateCache = *stReceivedPos;
00898             if (stateCache.msg == NULL)
00899                 throw cRuntimeError("msg = NULL");
00900             processState();
00901         }
00902     } else {
00903         // state == READY
00904         if (stateCache.msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
00905             // try to repair routingtable based on repair message:
00906             const TransportAddress& askRt =
00907                 routingTable->repair(stateCache.msg, stateCache.prox);
00908             if (! askRt.isUnspecified()) {
00909                 sendRequest(askRt, PASTRY_REQ_REPAIR);
00910             }
00911 
00912             // while not really known, it's safe to assume that a repair
00913             // message changed our state:
00914             lastStateChange = now;
00915         } else {
00916             if (stateCache.outdatedUpdate) {
00917                 // send another STATE message on outdated state update:
00918                 updateCounter++;
00919                 sendStateDelayed(stateCache.msg->getSender());
00920             } else {
00921                 // merge info in own state tables
00922                 // except leafset (was already handled in handleStateMessage)
00923                 if (neighborhoodSet->mergeState(stateCache.msg, stateCache.prox))
00924                     lastStateChange = now;
00925                 EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00926                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00927                    << "    Merging nodes into routing table"
00928                    << endl;
00929                 if (routingTable->mergeState(stateCache.msg, stateCache.prox)) {
00930                     lastStateChange = now;
00931                     EV << "[Pastry::checkProxCache() @ " << thisNode.getAddress()
00932                        << " (" << thisNode.getKey().toString(16) << ")]\n"
00933                        << "    Merged nodes into routing table"
00934                        << endl;
00935                 }
00936             }
00937         }
00938         updateTooltip();
00939 
00940         endProcessingState();
00941     }
00942 }
00943 
00944 void Pastry::endProcessingState(void)
00945 {
00946     // if state message was not an update, send one back:
00947     if (stateCache.msg &&
00948         stateCache.msg->getPastryStateMsgType() != PASTRY_STATE_UPDATE &&
00949         (alwaysSendUpdate || lastStateChange == simTime()) &&
00950         thisNode != stateCache.msg->getSender()) {//hack
00951         simtime_t timestamp = stateCache.msg->getTimestamp();
00952         sendStateTables(stateCache.msg->getSender(), PASTRY_STATE_UPDATE,
00953                         &timestamp);
00954     }
00955 
00956     delete stateCache.msg;
00957     stateCache.msg = NULL;
00958     delete stateCache.prox;
00959     stateCache.prox = NULL;
00960 
00961     // process next queued message:
00962     if (! stateCacheQueue.empty()) {
00963         stateCache = stateCacheQueue.front();
00964         stateCacheQueue.pop();
00965         processState();
00966     } //TODO get rid of the delayed update messages...
00967     /*else {
00968         std::cout << thisNode.getAddress() << "\t" << simTime()
00969                   << " all states processed ("
00970                   << updateCounter << ")" << std::endl;
00971         updateCounter = 0;
00972     }*/
00973 }
00974 
00975 bool Pastry::mergeState(void)
00976 {
00977     bool ret = true;
00978 
00979     if (state == JOINING_2) {
00980         // building initial state
00981         if (debugOutput) {
00982             EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
00983                << " (" << thisNode.getKey().toString(16) << ")]\n"
00984                << "    [JOIN] starting to build own state from "
00985                << stReceived.size() << " received state messages..."
00986                << endl;
00987         }
00988         if (stateCache.msg &&
00989             stateCache.msg->getNeighborhoodSetArraySize() > 0) {
00990             if (debugOutput) {
00991                 EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
00992                    << " (" << thisNode.getKey().toString(16) << ")]\n"
00993                    << "    [JOIN] initializing NeighborhoodSet from "
00994                    << stReceived.front().msg->getJoinHopCount() << ". hop"
00995                    << endl;
00996             }
00997             if (!neighborhoodSet->mergeState(stReceived.front().msg,
00998                                              stReceived.front().prox )) {
00999                 EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
01000                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01001                    << "    Error initializing own neighborhoodSet"
01002                    << " while joining! Restarting ..."
01003                    << endl;
01004                 ret = false;
01005             }
01006         }
01007         if (debugOutput) {
01008             EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
01009                << " (" << thisNode.getKey().toString(16) << ")]\n"
01010                << "    [JOIN] initializing LeafSet from "
01011                << stReceived.back().msg->getJoinHopCount() << ". hop"
01012                << endl;
01013         }
01014 
01015         //assert(!stateCache.msg || stateCache.msg->getLeafSetArraySize() > 0);
01016 
01017         if (!leafSet->mergeState(stReceived.back().msg,
01018                                  stReceived.back().prox )) {
01019             EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
01020                << " (" << thisNode.getKey().toString(16) << ")]\n"
01021                << "    Error initializing own leafSet while joining!"
01022                << " Restarting ..."
01023                << endl;
01024             //std::cout << "Pastry: Error initializing own leafSet while "
01025             //                    "joining! Restarting ..." << std::endl;
01026             ret = false;
01027         } else {
01028             newLeafs();
01029         }
01030         if (debugOutput) {
01031             EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
01032                << " (" << thisNode.getKey().toString(16) << ")]\n"
01033                << "    [JOIN] initializing RoutingTable from all hops"
01034                << endl;
01035         }
01036 
01037         assert(!stateCache.msg ||
01038                stateCache.msg->getRoutingTableArraySize() > 0);
01039 
01040         if (!routingTable->initStateFromHandleVector(stReceived)) {
01041             EV << "[Pastry::mergeState() @ " << thisNode.getAddress()
01042                << " (" << thisNode.getKey().toString(16) << ")]\n"
01043                << "    Error initializing own routingTable while joining!"
01044                << " Restarting ..."
01045                << endl;
01046             //std::cout << "Pastry: Error initializing own routingTable "
01047             //             "while joining! Restarting ..." << std::endl;
01048 
01049             ret = false;
01050         }
01051     } else if (state == READY) {
01052         // merging single state (stateCache.msg)
01053         if ((stateCache.msg->getNeighborhoodSetArraySize() > 0) &&
01054             (!neighborhoodSet->mergeState(stateCache.msg, NULL))) {
01055             ret = false;
01056         }
01057         if (!leafSet->mergeState(stateCache.msg, NULL)) {
01058             ret = false;
01059         } else {
01060             newLeafs();
01061         }
01062         if (!routingTable->mergeState(stateCache.msg, NULL)) {
01063             ret = false;
01064         }
01065     }
01066 
01067     if (ret) lastStateChange = simTime();
01068     return ret;
01069 }
01070 
01071 void Pastry::handleStateMessage(PastryStateMessage* msg)
01072 {
01073     if (debugOutput) {
01074         EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01075            << " (" << thisNode.getKey().toString(16) << ")]\n"
01076            << "    new STATE message to process "
01077            << static_cast<void*>(msg) << " in state " <<
01078             ((state == READY)?"READY":((state == JOINING_2)?"JOIN":"INIT"))
01079            << endl;
01080         if (state == JOINING_2) {
01081             EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01082                << " (" << thisNode.getKey().toString(16) << ")]\n"
01083                << "    ***   own joinHopCount:  " << joinHopCount << endl
01084                << "    ***   already received:  " << stReceived.size() << endl
01085                << "    ***   last-hop flag:     "
01086                << (msg->getLastHop() ? "true" : "false") << endl
01087                << "    ***   msg joinHopCount:  "
01088                << msg->getJoinHopCount() << endl;
01089         }
01090     }
01091     if (state == INIT || state == DISCOVERY) {
01092         EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01093            << " (" << thisNode.getKey().toString(16) << ")]\n"
01094            << "    can't handle state messages until at least reaching JOIN state."
01095            << endl;
01096         delete msg;
01097         return;
01098     }
01099 
01100     PastryStateMsgHandle handle(msg);
01101 
01102     // in JOIN state, store all received state Messages, need them later:
01103     if (state == JOINING_2) {
01104         //std::cout << simTime() << " " << thisNode.getAddress() << " "
01105         //          << msg->getJoinHopCount()
01106         //          << (msg->getLastHop() ? " *" : "") << std::endl;
01107 
01108         if (msg->getPastryStateMsgType() != PASTRY_STATE_JOIN) {
01109             delete msg;
01110             return;
01111         }
01112 
01113         if (joinHopCount && stReceived.size() == joinHopCount) {
01114             EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01115                << " (" << thisNode.getKey().toString(16) << ")]\n"
01116                << "    Warning: dropping state message received after "
01117                << "all needed state messages were collected in JOIN state."
01118                << endl;
01119             delete msg;
01120             return;
01121         }
01122 
01123         stReceived.push_back(handle);
01124         if (pingBeforeSecondStage && proximityNeighborSelection) prePing(msg);
01125 
01126         if (msg->getLastHop()) {
01127             if (joinTimeout->isScheduled()) {
01128                 //std::cout << simTime() << " " << thisNode.getAddress()
01129                 //<< " cancelEvent(joinTimeout), received:"
01130                 //<< stReceived.size() << ", hopcount:" << joinHopCount << std::endl;
01131                 cancelEvent(joinTimeout);
01132             }
01133             /*if (msg->getSender().getKey() == thisNode.getKey()) {
01134                 EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01135                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01136                    << "    Error: OverlayKey already in use, restarting!"
01137                    << endl;
01138                 //std::cout << "Pastry: Error: OverlayKey already in use, restarting!"
01139                 //                   << std::endl;
01140                 joinOverlay();
01141                 return;
01142             }*/
01143 
01144             if (joinHopCount) {
01145                 EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01146                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01147                    << "    Error: received a second `last' state message! Restarting ..."
01148                    << endl;
01149                 //std::cout << thisNode.getAddress() << "Pastry: Error: received a second `last' state message! "
01150                 //                    "Restarting ..." << std::endl;
01151                 joinOverlay();
01152                 return;
01153             }
01154 
01155             joinHopCount = msg->getJoinHopCount();
01156             //std::cout << stReceived.size() << " " << joinHopCount << std::endl;
01157             if (stReceived.size() < joinHopCount) {
01158                 // some states still missing:
01159                 cancelEvent(readyWait);
01160                 scheduleAt(simTime() + readyWaitAmount, readyWait);
01161                 //std::cout << simTime() << " " << thisNode.getAddress() << " readyWait scheduled!" << std::endl;
01162             }
01163         }
01164 
01165         if (joinHopCount) {
01166             if (stReceived.size() > joinHopCount) {
01167                 EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01168                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01169                    << "    Error: too many state messages received in JOIN state! ("
01170                    << stReceived.size() << " > " << joinHopCount << ") Restarting ..."
01171                    << endl;
01172                 //std::cout << " failed!" << std::endl;
01173                 joinOverlay();
01174                 return;
01175             }
01176             if (stReceived.size() == joinHopCount) {
01177                 // all state messages are here, sort by hopcount:
01178                 sort(stReceived.begin(), stReceived.end(),
01179                      stateMsgIsSmaller);
01180 
01181                 // start pinging the nodes found in the first state message:
01182                 stReceivedPos = stReceived.begin();
01183                 stateCache = *stReceivedPos;
01184                 EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01185                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01186                    << "    have all STATE messages, now pinging nodes."
01187                    << endl;
01188                 if (pingBeforeSecondStage && proximityNeighborSelection) {
01189                     pingNodes();
01190                 } else {
01191                     mergeState(); // JOINING / stateCache
01192                     //endProcessingState(); //no way
01193                     stateCache.msg = NULL;
01194                     changeState(READY);
01195                     EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01196                        << " (" << thisNode.getKey().toString(16) << ")]\n"
01197                        << "    changeState(READY) called"
01198                        << endl;
01199                 }
01200 
01201                 // cancel timeout:
01202                 if (readyWait->isScheduled()) cancelEvent(readyWait);
01203             } else {
01204                 //TODO occasionally, here we got a wrong hop count in
01205                 // iterative mode due to more than one it. lookup during join
01206                 // procedure
01207                 EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01208                    << " (" << thisNode.getKey().toString(16) << ")]\n"
01209                    << "    Still need some STATE messages."
01210                    << endl;
01211             }
01212 
01213         }
01214         return;
01215     }
01216 
01217     if (debugOutput) {
01218         EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01219            << " (" << thisNode.getKey().toString(16) << ")]\n"
01220            << "    handling STATE message"
01221            << endl;
01222         EV << "        type: " << ((msg->getPastryStateMsgType()
01223                                     == PASTRY_STATE_UPDATE) ? "update"
01224                                                             :"standard")
01225            << endl;
01226         if (msg->getPastryStateMsgType() == PASTRY_STATE_UPDATE) {
01227             EV << "        msg timestamp:      " <<
01228                 msg->getTimestamp() << endl;
01229             EV << "        last state change:  " <<
01230                 lastStateChange << endl;
01231         }
01232     }
01233 
01234     if (((msg->getPastryStateMsgType() == PASTRY_STATE_UPDATE))
01235             && (msg->getTimestamp() <= lastStateChange)) {
01236         // if we received an update based on our outdated state,
01237         // mark handle for retrying later:
01238         EV << "[Pastry::handleStateMessage() @ " << thisNode.getAddress()
01239            << " (" << thisNode.getKey().toString(16) << ")]\n"
01240            << "    outdated state from " << msg->getSender()
01241            << endl;
01242         handle.outdatedUpdate = true;
01243     }
01244 
01245     // determine aliveTable to prevent leafSet from merging nodes that are
01246     // known to be dead:
01247     determineAliveTable(msg);
01248 
01249     if (msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
01250         // try to repair leafset based on repair message right now
01251         const TransportAddress& askLs = leafSet->repair(msg, &aliveTable);
01252         if (! askLs.isUnspecified()) {
01253             sendRequest(askLs, PASTRY_REQ_REPAIR);
01254         }
01255 
01256         // while not really known, it's safe to assume that a repair
01257         // message changed our state:
01258         lastStateChange = simTime();
01259         newLeafs();
01260     } else if (leafSet->mergeState(msg, &aliveTable)) {
01261         // merged state into leafset right now
01262         lastStateChange = simTime();
01263         newLeafs();
01264         updateTooltip();
01265     }
01266     // in READY state, only ping nodes to get proximity metric:
01267     if (!stateCache.msg) {
01268         // no state message is processed right now, start immediately:
01269         stateCache = handle;
01270         processState();
01271     } else {
01272         if (proximityNeighborSelection && (pingBeforeSecondStage ||
01273             msg->getPastryStateMsgType() == PASTRY_STATE_STD)) {
01274             // enqueue message for later processing:
01275             stateCacheQueue.push(handle);
01276             prePing(msg);
01277         } else {
01278             bool temp = true;
01279             if (!neighborhoodSet->mergeState(msg, NULL)) {
01280                 temp = false;
01281             }
01282             if (!leafSet->mergeState(msg, NULL)) {
01283                 temp = false;
01284             } else {
01285                 newLeafs();
01286             }
01287             if (!routingTable->mergeState(msg, NULL)) {
01288                 temp = false;
01289             }
01290             if (temp) lastStateChange = simTime();
01291             delete msg;
01292         }
01293     }
01294 }
01295 
01296 void Pastry::processState(void)
01297 {
01298     if (proximityNeighborSelection && (pingBeforeSecondStage ||
01299         stateCache.msg->getPastryStateMsgType() == PASTRY_STATE_STD)) {
01300         pingNodes();
01301     } else {
01302         mergeState();
01303         endProcessingState();
01304     }
01305 }
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3