00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00056 if (!stReceived.empty()) {
00057 for (std::vector<PastryStateMsgHandle>::iterator it =
00058 stReceived.begin(); it != stReceived.end(); it++) {
00059
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
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
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
00105
00106 useDiscovery = false;
00107 sendStateAtLeafsetRepair = true;
00108 routingTableMaintenanceInterval = 0;
00109 }
00110
00111 if (overrideNewPastry) {
00112
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
00140 changeState(READY);
00141 } else {
00142
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
00163 nearNodeRtt = MAXTIME;
00164 pingNode(bootstrapNode, discoveryTimeoutAmount, 0,
00165 NULL, "PING bootstrapNode in discovery mode",
00166 NULL, PING_DISCOVERY, UDP_TRANSPORT);
00167 sendRequest(bootstrapNode, PASTRY_REQ_LEAFSET);
00168 depth = -1;
00169
00170
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
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, sourceRoute);
00188 }
00189 break;
00190
00191 case READY:
00192
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
00201 cancelEvent(joinUpdateWait);
00202 scheduleAt(simTime() + 0.0001, joinUpdateWait);
00203
00204
00205 if (secondStageInterval > 0) {
00206 cancelEvent(secondStageWait);
00207 scheduleAt(simTime() + secondStageInterval, secondStageWait);
00208 }
00209
00210
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
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++;
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
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
00430 if ( !(node->isUnspecified()) ) {
00431 pingNode(*node, discoveryTimeoutAmount, 0,
00432 NULL, "PING received leafs for nearest node",
00433 NULL, -1, UDP_TRANSPORT);
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
00498 if ( !(node->isUnspecified()) ) {
00499
00500 pingNode(*node, discoveryTimeoutAmount, 0, NULL,
00501 "PING received routing table for nearest node",
00502 NULL, -1, UDP_TRANSPORT);
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
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
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
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
00620
00621
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 ×tamp);
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
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
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
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
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
00733
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
00756
00757
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
00772 assert(stateCache.msg || !stateCache.prox);
00773 if (!stateCache.msg) return;
00774
00775
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
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
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
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
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 simtime_t now = simTime();
00840
00841 if (state == JOINING_2) {
00842
00843 stReceivedPos->prox = stateCache.prox;
00844
00845
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
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
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
00904 if (stateCache.msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
00905
00906 const TransportAddress& askRt =
00907 routingTable->repair(stateCache.msg, stateCache.prox);
00908 if (! askRt.isUnspecified()) {
00909 sendRequest(askRt, PASTRY_REQ_REPAIR);
00910 }
00911
00912
00913
00914 lastStateChange = now;
00915 } else {
00916 if (stateCache.outdatedUpdate) {
00917
00918 updateCounter++;
00919 sendStateDelayed(stateCache.msg->getSender());
00920 } else {
00921
00922
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
00947 if (stateCache.msg &&
00948 stateCache.msg->getPastryStateMsgType() != PASTRY_STATE_UPDATE &&
00949 (alwaysSendUpdate || lastStateChange == simTime()) &&
00950 thisNode != stateCache.msg->getSender()) {
00951 simtime_t timestamp = stateCache.msg->getTimestamp();
00952 sendStateTables(stateCache.msg->getSender(), PASTRY_STATE_UPDATE,
00953 ×tamp);
00954 }
00955
00956 delete stateCache.msg;
00957 stateCache.msg = NULL;
00958 delete stateCache.prox;
00959 stateCache.prox = NULL;
00960
00961
00962 if (! stateCacheQueue.empty()) {
00963 stateCache = stateCacheQueue.front();
00964 stateCacheQueue.pop();
00965 processState();
00966 }
00967
00968
00969
00970
00971
00972
00973 }
00974
00975 bool Pastry::mergeState(void)
00976 {
00977 bool ret = true;
00978
00979 if (state == JOINING_2) {
00980
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
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
01025
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
01047
01048
01049 ret = false;
01050 }
01051 } else if (state == READY) {
01052
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
01103 if (state == JOINING_2) {
01104
01105
01106
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
01129
01130
01131 cancelEvent(joinTimeout);
01132 }
01133
01134
01135
01136
01137
01138
01139
01140
01141
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
01150
01151 joinOverlay();
01152 return;
01153 }
01154
01155 joinHopCount = msg->getJoinHopCount();
01156
01157 if (stReceived.size() < joinHopCount) {
01158
01159 cancelEvent(readyWait);
01160 scheduleAt(simTime() + readyWaitAmount, readyWait);
01161
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
01173 joinOverlay();
01174 return;
01175 }
01176 if (stReceived.size() == joinHopCount) {
01177
01178 sort(stReceived.begin(), stReceived.end(),
01179 stateMsgIsSmaller);
01180
01181
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();
01192
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
01202 if (readyWait->isScheduled()) cancelEvent(readyWait);
01203 } else {
01204
01205
01206
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
01237
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
01246
01247 determineAliveTable(msg);
01248
01249 if (msg->getPastryStateMsgType() == PASTRY_STATE_REPAIR) {
01250
01251 const TransportAddress& askLs = leafSet->repair(msg, &aliveTable);
01252 if (! askLs.isUnspecified()) {
01253 sendRequest(askLs, PASTRY_REQ_REPAIR);
01254 }
01255
01256
01257
01258 lastStateChange = simTime();
01259 newLeafs();
01260 } else if (leafSet->mergeState(msg, &aliveTable)) {
01261
01262 lastStateChange = simTime();
01263 newLeafs();
01264 updateTooltip();
01265 }
01266
01267 if (!stateCache.msg) {
01268
01269 stateCache = handle;
01270 processState();
01271 } else {
01272 if (proximityNeighborSelection && (pingBeforeSecondStage ||
01273 msg->getPastryStateMsgType() == PASTRY_STATE_STD)) {
01274
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 }