P2pns.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2007 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include <IPAddressResolver.h>
00025 #include <XmlRpcInterface.h>
00026 #include <P2pnsMessage_m.h>
00027 
00028 #include "P2pns.h"
00029 
00030 Define_Module(P2pns);
00031 
00032 using namespace std;
00033 
00034 P2pns::P2pns()
00035 {
00036     p2pnsCache = NULL;
00037 }
00038 
00039 P2pns::~P2pns()
00040 {
00041 }
00042 
00043 void P2pns::initializeApp(int stage)
00044 {
00045     if (stage != MIN_STAGE_APP)
00046         return;
00047 
00048     twoStageResolution = par("twoStageResolution");
00049     keepaliveInterval = par("keepaliveInterval");
00050     idCacheLifetime = par("idCacheLifetime");
00051 
00052     p2pnsCache = check_and_cast<P2pnsCache*> (getParentModule()->
00053             getSubmodule("p2pnsCache"));
00054 
00055     xmlRpcInterface = dynamic_cast<XmlRpcInterface*>(overlay->
00056             getCompModule(TIER3_COMP));
00057 }
00058 
00059 void P2pns::handleReadyMessage(CompReadyMessage* msg)
00060 {
00061     if ((msg->getReady() == false) || (msg->getComp() != OVERLAY_COMP)) {
00062         delete msg;
00063         return;
00064     }
00065 
00066     thisId = (overlay->getThisNode().getKey() >> (OverlayKey::getLength() - 100))
00067              << (OverlayKey::getLength() - 100);
00068     delete msg;
00069 }
00070 
00071 void P2pns::tunnel(const OverlayKey& destKey, const BinaryValue& payload)
00072 {
00073     Enter_Method_Silent();
00074 
00075     P2pnsIdCacheEntry* entry = p2pnsCache->getIdCacheEntry(destKey);
00076 
00077     if (entry == NULL) {
00078         // lookup destKey and create new entry
00079 
00080         EV << "[P2pns::tunnel()]\n"
00081            << "    Establishing new cache entry for key: " << destKey
00082            << endl;
00083 
00084         LookupCall* lookupCall = new LookupCall();
00085         lookupCall->setKey(destKey);
00086         lookupCall->setNumSiblings(1);
00087         sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0,
00088                             TUNNEL_LOOKUP);
00089         p2pnsCache->addIdCacheEntry(destKey, &payload);
00090     } else if (entry->state == CONNECTION_PENDING) {
00091         // lookup not finished yet => append packet to queue
00092         EV << "[P2pns::tunnel()]\n"
00093            << "    Queuing packet since lookup is still pending for key: "
00094            << destKey << endl;
00095 
00096         entry->lastUsage = simTime();
00097         entry->payloadQueue.push_back(payload);
00098     } else {
00099         entry->lastUsage = simTime();
00100         sendTunnelMessage(entry->addr, payload);
00101     }
00102 }
00103 
00104 void P2pns::handleTunnelLookupResponse(LookupResponse* lookupResponse)
00105 {
00106     P2pnsIdCacheEntry* entry =
00107         p2pnsCache->getIdCacheEntry(lookupResponse->getKey());
00108 
00109     if ((entry == NULL) || (entry->state == CONNECTION_ACTIVE)) {
00110         // no matching entry in idCache or connection is already active
00111         // => lookup result not needed anymore
00112         return;
00113     }
00114 
00115     if (lookupResponse->getIsValid()) {
00116         // verify if nodeId of lookup's closest node matches requested id
00117         if (lookupResponse->getKey().sharedPrefixLength(lookupResponse->
00118                       getSiblings(0).getKey()) < (OverlayKey::getLength() - 100)) {
00119             EV << "[P2pns::handleTunnelLookupResponse()]\n"
00120                    << "    Lookup response " << lookupResponse->getSiblings(0)
00121                    << " doesn't match requested id " << lookupResponse->getKey()
00122                    << endl;
00123             // lookup failed => drop cache entry and all queued packets
00124             p2pnsCache->removeIdCacheEntry(lookupResponse->getKey());
00125 
00126             return;
00127         }
00128 
00129         // add transport address to cache entry
00130         entry->addr = lookupResponse->getSiblings(0);
00131         entry->state = CONNECTION_ACTIVE;
00132 
00133         // start periodic ping timer
00134         P2pnsKeepaliveTimer* msg =
00135             new P2pnsKeepaliveTimer("P2pnsKeepaliveTimer");
00136         msg->setKey(lookupResponse->getKey());
00137         scheduleAt(simTime() + keepaliveInterval, msg);
00138 
00139         // send all pending tunnel messages
00140         while (!entry->payloadQueue.empty()) {
00141             sendTunnelMessage(entry->addr, entry->payloadQueue.front());
00142             entry->payloadQueue.pop_front();
00143         }
00144     } else {
00145         // lookup failed => drop cache entry and all queued packets
00146         p2pnsCache->removeIdCacheEntry(lookupResponse->getKey());
00147     }
00148 }
00149 
00150 void P2pns::sendTunnelMessage(const TransportAddress& addr,
00151                               const BinaryValue& payload)
00152 {
00153     EV << "[P2pns::sendTunnelMessage()]\n"
00154            << "    Sending TUNNEL message to " << addr << endl;
00155 
00156     P2pnsTunnelMessage* msg = new P2pnsTunnelMessage("P2pnsTunnelMsg");
00157     msg->setPayload(payload);
00158     msg->setSrcId(thisId);
00159     msg->setBitLength(P2PNSTUNNELMESSAGE_L(msg));
00160 
00161     callRoute(OverlayKey::UNSPECIFIED_KEY, msg, addr);
00162 }
00163 
00164 void P2pns::registerId(const std::string& addr)
00165 {
00166     Enter_Method_Silent();
00167 
00168     std::string name = par("registerName").stdstringValue();
00169     DHTputCAPICall* dhtPutMsg = new DHTputCAPICall();
00170 
00171     EV << "[P2pns::p2pnsRegisterRpc()]\n"
00172        << "    registerId(): name: " << name << " addr: " << addr
00173        << endl;
00174 
00175     dhtPutMsg->setKey(OverlayKey::sha1(BinaryValue(name)));
00176 
00177     dhtPutMsg->setValue(BinaryValue(addr));
00178     dhtPutMsg->setKind(28);
00179     dhtPutMsg->setId(1);
00180     dhtPutMsg->setTtl(60*60*24*7);
00181     dhtPutMsg->setIsModifiable(true);
00182 
00183     sendInternalRpcCall(TIER1_COMP, dhtPutMsg);
00184 }
00185 
00186 void P2pns::deliver(OverlayKey& key, cMessage* msg)
00187 {
00188     P2pnsTunnelMessage* tunnelMsg = check_and_cast<P2pnsTunnelMessage*>(msg);
00189 
00190     if (xmlRpcInterface) {
00191         xmlRpcInterface->deliverTunneledMessage(tunnelMsg->getPayload());
00192     }
00193 
00194     updateIdCacheWithNewTransport(msg);
00195 
00196     delete msg;
00197 }
00198 
00199 void P2pns::pingRpcResponse(PingResponse* response, cPolymorphic* context,
00200                             int rpcId, simtime_t rtt)
00201 {
00202     delete context;
00203 }
00204 
00205 void P2pns::pingTimeout(PingCall* call, const TransportAddress& dest,
00206                         cPolymorphic* context, int rpcId)
00207 {
00208     OverlayKeyObject* key = dynamic_cast<OverlayKeyObject*>(context);
00209     P2pnsIdCacheEntry* entry = NULL;
00210 
00211     // lookup entry in id cache
00212     if ((key != NULL) &&
00213             (entry = p2pnsCache->getIdCacheEntry(*key))) {
00214 
00215         // remove entry if TransportAddress hasn't been updated in the meantime
00216         if (!entry->addr.isUnspecified() && (entry->addr != dest)) {
00217             EV << "[P2pns::pingTimeout()]\n"
00218                << "    Removing id " << key << " from idCache (ping timeout)"
00219                << endl;
00220             p2pnsCache->removeIdCacheEntry(*key);
00221         }
00222     }
00223 
00224     delete context;
00225 }
00226 
00227 void P2pns::handleTimerEvent(cMessage* msg)
00228 {
00229     P2pnsKeepaliveTimer* timer = dynamic_cast<P2pnsKeepaliveTimer*>(msg);
00230 
00231     if (timer) {
00232         P2pnsIdCacheEntry* entry = p2pnsCache->getIdCacheEntry(timer->getKey());
00233 
00234         if (entry == NULL) {
00235             // no valid cache entry found
00236             delete msg;
00237             return;
00238         }
00239 
00240         if ((entry->lastUsage + idCacheLifetime) < simTime()) {
00241             // remove idle connections
00242             EV << "[P2pns::handleTimerEvent()]\n"
00243                << "    Removing id " << timer->getKey()
00244                << " from idCache (connection idle)"
00245                << endl;
00246             p2pnsCache->removeIdCacheEntry(timer->getKey());
00247             delete msg;
00248             return;
00249         }
00250 
00251         if (!entry->addr.isUnspecified()) {
00252             // ping 3 times with default timeout
00253             pingNode(entry->addr, -1, 2, new OverlayKeyObject(timer->getKey()));
00254         }
00255 
00256         // reschedule periodic keepalive timer
00257         scheduleAt(simTime() + keepaliveInterval, msg);
00258 
00259         // exhaustive-iterative lookup to refresh siblings, if our ip has changed
00260         LookupCall* lookupCall = new LookupCall();
00261         lookupCall->setKey(overlay->getThisNode().getKey());
00262         lookupCall->setNumSiblings(1);
00263         lookupCall->setRoutingType(EXHAUSTIVE_ITERATIVE_ROUTING);
00264         sendInternalRpcCall(OVERLAY_COMP, lookupCall, NULL, -1, 0,
00265                             TUNNEL_LOOKUP);
00266     }
00267 }
00268 
00269 void P2pns::updateIdCacheWithNewTransport(cMessage* msg)
00270 {
00271     // update idCache with new TransportAddress of the ping originator
00272     OverlayCtrlInfo* ctrlInfo =
00273         dynamic_cast<OverlayCtrlInfo*>(msg->getControlInfo());
00274 
00275     OverlayKey srcId;
00276 
00277     if (!ctrlInfo) {
00278         // can't update cache without knowing the originator id
00279         EV << "[P2pns::updateCacheWithNewTransport()]\n"
00280            << "    Can't update cache without knowing the originator id"
00281            << endl;
00282         return;
00283     }
00284 
00285     if (ctrlInfo->getSrcRoute().isUnspecified()) {
00286         P2pnsTunnelMessage* tunnelMsg = dynamic_cast<P2pnsTunnelMessage*>(msg);
00287         if (tunnelMsg) {
00288             srcId = tunnelMsg->getSrcId();
00289         } else {
00290             // can't update cache without knowing the originator id
00291             EV << "[P2pns::updateCacheWithNewTransport()]\n"
00292                << "    Can't update cache without knowing the originator id"
00293                << endl;
00294             return;
00295         }
00296     } else {
00297         srcId = (ctrlInfo->getSrcRoute().getKey() >> (OverlayKey::getLength() - 100))
00298                 << (OverlayKey::getLength() - 100);
00299     }
00300 
00301     P2pnsIdCacheEntry* entry = p2pnsCache->getIdCacheEntry(srcId);
00302 
00303     if (entry == NULL) {
00304         EV << "[P2pns::updateCacheWithNewTransport()]\n"
00305            << "    Adding new cache entry for id " << srcId
00306            << " with addr " << (const TransportAddress&)ctrlInfo->getSrcRoute()
00307            << endl;
00308         entry = p2pnsCache->addIdCacheEntry(srcId);
00309         entry->addr = ctrlInfo->getSrcRoute();
00310 
00311         // start periodic ping timer
00312         P2pnsKeepaliveTimer* msg =
00313             new P2pnsKeepaliveTimer("P2pnsKeepaliveTimer");
00314         msg->setKey(srcId);
00315         scheduleAt(simTime() + keepaliveInterval, msg);
00316     }
00317 
00318     // update transport address in idCache (node may have a new
00319     // TransportAddress due to mobility)
00320     if (entry->addr.isUnspecified() ||
00321             (entry->addr != ctrlInfo->getSrcRoute())) {
00322         EV << "[P2pns::handleRpcCall()]\n"
00323            << "    Ping with new transport address received: "
00324            << "    Changing from " << entry->addr << " to "
00325            << static_cast<TransportAddress>(ctrlInfo->getSrcRoute())
00326            << " for id " << srcId << endl;
00327         entry->addr = ctrlInfo->getSrcRoute();
00328     }
00329 
00330     entry->state = CONNECTION_ACTIVE;
00331 }
00332 
00333 bool P2pns::handleRpcCall(BaseCallMessage* msg)
00334 {
00335     // delegate messages
00336     RPC_SWITCH_START(msg)
00337     RPC_ON_CALL(Ping) {
00338         updateIdCacheWithNewTransport(msg);
00339         return false;
00340     }
00341     RPC_DELEGATE( P2pnsRegister, p2pnsRegisterRpc );
00342     RPC_DELEGATE( P2pnsResolve, p2pnsResolveRpc );
00343     RPC_SWITCH_END()
00344 
00345     return RPC_HANDLED;
00346 }
00347 
00348 
00349 void P2pns::handleRpcResponse(BaseResponseMessage* msg,
00350                               cPolymorphic* context, int rpcId, simtime_t rtt)
00351 {
00352     RPC_SWITCH_START(msg)
00353     RPC_ON_RESPONSE( DHTputCAPI ) {
00354         EV << "[P2pns::handleRpcResponse()]\n"
00355            << "    DHTputCAPI RPC Response received: id=" << rpcId
00356            << " msg=" << *_DHTputCAPIResponse << " rtt=" << rtt
00357            << endl;
00358         if (dynamic_cast<P2pnsRegisterCall*>(context)) {
00359             handleDHTputCAPIResponse(_DHTputCAPIResponse,
00360                                  check_and_cast<P2pnsRegisterCall*>(context));
00361         }
00362         break;
00363     }
00364     RPC_ON_RESPONSE( DHTgetCAPI ) {
00365         EV << "[P2pns::handleRpcResponse()]\n"
00366            << "    DHTgetCAPI RPC Response received: id=" << rpcId
00367            << " msg=" << *_DHTgetCAPIResponse << " rtt=" << rtt
00368            << endl;
00369         handleDHTgetCAPIResponse(_DHTgetCAPIResponse,
00370                                  check_and_cast<P2pnsResolveCall*>(context));
00371         break;
00372     }
00373     RPC_ON_RESPONSE( Lookup ) {
00374         EV << "[P2pns::handleRpcResponse()]\n"
00375            << "    Lookup RPC Response received: id=" << rpcId
00376            << " msg=" << *_LookupResponse << " rtt=" << rtt
00377            << endl;
00378         handleLookupResponse(_LookupResponse, context, rpcId);
00379         break;
00380     }
00381     RPC_SWITCH_END()
00382 }
00383 
00384 void P2pns::p2pnsRegisterRpc(P2pnsRegisterCall* registerCall)
00385 {
00386     p2pnsCache->addData(registerCall->getP2pName(),
00387                         registerCall->getAddress());
00388 
00389     DHTputCAPICall* dhtPutMsg = new DHTputCAPICall();
00390 
00391     EV << "[P2pns::p2pnsRegisterRpc()]\n"
00392        << "    RegisterRpc: name: " << registerCall->getP2pName()
00393        << " addr: " << registerCall->getAddress()
00394        << endl;
00395 
00396     dhtPutMsg->setKey(OverlayKey::sha1(registerCall->getP2pName()));
00397     if (twoStageResolution) {
00398         dhtPutMsg->setValue(overlay->getThisNode().getKey().toString());
00399     } else {
00400         dhtPutMsg->setValue(registerCall->getAddress());
00401     }
00402 
00403     dhtPutMsg->setKind(registerCall->getKind());
00404     dhtPutMsg->setId(registerCall->getId());
00405     dhtPutMsg->setTtl(registerCall->getTtl());
00406     dhtPutMsg->setIsModifiable(true);
00407 
00408     sendInternalRpcCall(TIER1_COMP, dhtPutMsg, registerCall);
00409 }
00410 
00411 void P2pns::p2pnsResolveRpc(P2pnsResolveCall* resolveCall)
00412 {
00413     DHTgetCAPICall* dhtGetMsg = new DHTgetCAPICall();
00414 
00415     EV << "[P2pns::p2pnsResolveRpc()]\n"
00416        << "   ResolveRpc: name: " << resolveCall->getP2pName()
00417        << endl;
00418 
00419     dhtGetMsg->setKey(OverlayKey::sha1(resolveCall->getP2pName()));
00420     dhtGetMsg->setKind(resolveCall->getKind());
00421     dhtGetMsg->setId(resolveCall->getId());
00422 
00423     sendInternalRpcCall(TIER1_COMP, dhtGetMsg, resolveCall);
00424 }
00425 
00426 void P2pns::handleDHTputCAPIResponse(DHTputCAPIResponse* putResponse,
00427                                      P2pnsRegisterCall* registerCall)
00428 {
00429     P2pnsRegisterResponse* registerResponse = new P2pnsRegisterResponse();
00430     registerResponse->setP2pName(registerCall->getP2pName());
00431     registerResponse->setAddress(registerCall->getAddress());
00432     registerResponse->setIsSuccess(putResponse->getIsSuccess());
00433     sendRpcResponse(registerCall, registerResponse);
00434 }
00435 
00436 void P2pns::handleDHTgetCAPIResponse(DHTgetCAPIResponse* getResponse,
00437                                      P2pnsResolveCall* resolveCall)
00438 {
00439     if ((!getResponse->getIsSuccess())
00440             || (getResponse->getResultArraySize() == 0)) { // || (valueStream.str().size() == 0)) {
00441         P2pnsResolveResponse* resolveResponse = new P2pnsResolveResponse();
00442         resolveResponse->setAddressArraySize(1);
00443         resolveResponse->setKindArraySize(1);
00444         resolveResponse->setIdArraySize(1);
00445         resolveResponse->setP2pName(resolveCall->getP2pName());
00446         resolveResponse->setAddress(0, BinaryValue(""));
00447         resolveResponse->setKind(0, 0);
00448         resolveResponse->setId(0, 0);
00449         resolveResponse->setIsSuccess(false);
00450         sendRpcResponse(resolveCall, resolveResponse);
00451         return;
00452     }
00453 
00454 //    TODO: fix cache to support kind and id of data records
00455 //    p2pnsCache->addData(resolveCall->getP2pName(),
00456 //                        getResponse->getValue());
00457 
00458     if (twoStageResolution) {
00459         if (getResponse->getResultArraySize() != 1) {
00460             throw cRuntimeError("P2pns::handleDHTgetCAPIResponse: "
00461                                 "Two-stage name resolution currently only "
00462                                 "works with unique keys!");
00463         }
00464         std::stringstream valueStream;
00465         valueStream << getResponse->getResult(0).getValue();
00466         OverlayKey key(valueStream.str(), 16);
00467 
00468         LookupCall* lookupCall = new LookupCall();
00469 
00470         lookupCall->setKey(key);
00471         lookupCall->setNumSiblings(1);
00472 
00473         sendInternalRpcCall(OVERLAY_COMP, lookupCall, resolveCall, -1, 0,
00474                             RESOLVE_LOOKUP);
00475 
00476         return;
00477     }
00478 
00479     EV << "[P2pns::handleDHTgetCAPIResponse()]\n"
00480        << "   ResolveRpcResponse: name: " << resolveCall->getP2pName();
00481 
00482     P2pnsResolveResponse* resolveResponse = new P2pnsResolveResponse();
00483     resolveResponse->setP2pName(resolveCall->getP2pName());
00484     resolveResponse->setIsSuccess(getResponse->getIsSuccess());
00485     resolveResponse->setAddressArraySize(getResponse->getResultArraySize());
00486     resolveResponse->setKindArraySize(getResponse->getResultArraySize());
00487     resolveResponse->setIdArraySize(getResponse->getResultArraySize());
00488 
00489     for (uint i = 0; i < getResponse->getResultArraySize(); i++) {
00490         EV << " addr: " << getResponse->getResult(i).getValue();
00491         resolveResponse->setAddress(i, getResponse->getResult(i).getValue());
00492         resolveResponse->setKind(i, getResponse->getResult(i).getKind());
00493         resolveResponse->setId(i, getResponse->getResult(i).getId());
00494     }
00495 
00496     EV << endl;
00497     sendRpcResponse(resolveCall, resolveResponse);
00498 }
00499 
00500 void P2pns::handleLookupResponse(LookupResponse* lookupResponse,
00501                                  cObject* context,
00502                                  int rpcId)
00503 {
00504     switch (rpcId) {
00505     case RESOLVE_LOOKUP: {
00506         P2pnsResolveCall* resolveCall =
00507             check_and_cast<P2pnsResolveCall*>(context);
00508 
00509         stringstream sstream;
00510         sstream << lookupResponse->getSiblings(0);
00511 
00512         P2pnsResolveResponse* resolveResponse = new P2pnsResolveResponse();
00513         resolveResponse->setP2pName(resolveCall->getP2pName());
00514         resolveResponse->setAddressArraySize(1);
00515         resolveResponse->setKindArraySize(1);
00516         resolveResponse->setIdArraySize(1);
00517 
00518         resolveResponse->setAddress(0, sstream.str());
00519         resolveResponse->setKind(0, 0);
00520         resolveResponse->setId(0, 0);
00521         resolveResponse->setIsSuccess(lookupResponse->getIsValid());
00522         sendRpcResponse(resolveCall, resolveResponse);
00523         break;
00524     }
00525     case TUNNEL_LOOKUP:
00526         handleTunnelLookupResponse(lookupResponse);
00527         break;
00528     case REFRESH_LOOKUP:
00529         break;
00530     default:
00531         throw cRuntimeError("P2pns::handleLookupResponse(): invalid rpcId!");
00532     }
00533 }
00534 
00535 
00536 void P2pns::finishApp()
00537 {
00538 }
00539 
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3