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