/** * {@inheritDoc} * * <p>This is called by the Generic ResolverServiceImpl when processing a response to a query. */ public void processResponse(ResolverResponseMsg response) { if (!useRouteResolver) { // Route resolver disabled return; } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse got a response"); } // convert the response into a RouteResponse Reader ip = null; RouteResponse doc = null; try { ip = new StringReader(response.getResponse()); StructuredTextDocument asDoc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, ip); doc = new RouteResponse(asDoc); } catch (Throwable e) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed response - discard", e); } return; } finally { try { if (null != ip) { ip.close(); ip = null; } } catch (Throwable ignored) { } } RouteAdvertisement dstRoute = doc.getDestRoute(); RouteAdvertisement srcRoute = doc.getSrcRoute(); int queryId = response.getQueryId(); if ((dstRoute == null) || (srcRoute == null)) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed response - discard."); } // Malformed response. Just discard. return; } EndpointAddress routingPeer = router.pid2addr(srcRoute.getDestPeerID()); EndpointAddress destPeer = router.pid2addr(dstRoute.getDestPeerID()); if ((routingPeer == null) || (destPeer == null)) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed PeerID in response - discard."); } // Malformed response. Just discard. return; } // check if we have a negative route response if (queryId == NACKROUTE_QUERYID) { AccessPointAdvertisement badHop = dstRoute.nextHop(router.addr2pid(routingPeer)); PeerID badPeer = null; if (badHop != null) { badPeer = badHop.getPeerID(); } else { // the bad hop is the final destination badPeer = dstRoute.getDestPeerID(); } processBadRoute(badPeer, dstRoute); return; } // This is not our own peer adv, so we must not keep it // for more than its expiration time. // we only need to publish this route if // we don't know about it yet // XXX: here is where we could be more conservative and use isNormallyReachable() instead, thus // excluding // incoming messengers. if ((!router.isLocalRoute(router.pid2addr(srcRoute.getDestPeerID()))) && (!router.isRoutedRoute(router.pid2addr(srcRoute.getDestPeerID())))) { router.updateRouteAdv(srcRoute); } if (destPeer.equals(routingPeer)) { // The dest peer itself managed to respond to us. That means we // learned the route from the reverseRoute in the message // itself. So, there's nothing we need to do. if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("learn route directly from the destination"); } } else { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("learn route:" + routingPeer); } try { // build the candidate route using the // route response from the respondant peer RouteAdvertisement candidateRoute = RouteAdvertisement.newRoute( router.addr2pid(destPeer), router.addr2pid(routingPeer), (Vector) dstRoute.getVectorHops().clone()); // cleanup the candidate route from any loop and remove the local peer extra // cycle RouteAdvertisement.cleanupLoop(candidateRoute, (PeerID) localPeerId); // Is there anything left in that route (or did the respondant // believe that we are the last hop on the route - which // obviously we are not. if (candidateRoute.size() == 0) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response outdated: NACK responder"); } generateNACKRoute( router.addr2pid(routingPeer), router.addr2pid(destPeer), dstRoute.getVectorHops()); return; } // get the address of the first hop in the route to verify that // we have a route (direct or long) to the first hop, so the route // is valid EndpointAddress candidateRouter = router.pid2addr(candidateRoute.getFirstHop().getPeerID()); // check that we have a direct connection to the first hop if (router.ensureLocalRoute(candidateRouter, null) == null) { // If we do not have a direct route to the candidate router check // for a long route in that case stich the route RouteAdvertisement routeToRouter = router.getRoute(candidateRouter, false); if (routeToRouter == null) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response useless: no route to next router hop"); } return; } // stich the route removing any loops and localPeer cycle if (RouteAdvertisement.stichRoute(candidateRoute, routeToRouter, (PeerID) localPeerId)) { router.setRoute(candidateRoute, false); } else { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response error stiching route response"); } return; } } else { // we have a direct connection with the first hop of the candidate route // set the new route, which starts with the peer that replied to us. router.setRoute(candidateRoute, false); } } catch (Exception ex) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response exception when building response route" + ex); LOG.debug(" bad dstRoute: " + dstRoute.display()); } } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("finish process route response successfully"); } } }
/** * {@inheritDoc} * * @param encodeAs Description of the Parameter * @return The document value */ public Document getDocument(MimeMediaType encodeAs) { StructuredDocument adv = (StructuredDocument) super.getDocument(encodeAs); if (hasALoop()) { throw new IllegalStateException("I won't write a doc for a route with a loop"); } PeerID pid = getDestPeerID(); AccessPointAdvertisement dest = getDest(); if ((null != pid) && (null != dest) && (null != dest.getPeerID())) { if (!pid.equals(dest.getPeerID())) { throw new IllegalStateException( "Destination peer id and destination access point adv don't refer to the same peer"); } } // HACK Backwards Compatibility if ((null == pid) && (null != dest)) { pid = dest.getPeerID(); } if (pid != null) { Element e0 = adv.createElement(DEST_PID_TAG, pid.toString()); adv.appendChild(e0); } if (dest != null) { // create the copy without the PID AccessPointAdvertisement ap = (AccessPointAdvertisement) AdvertisementFactory.newAdvertisement( AccessPointAdvertisement.getAdvertisementType()); ap.setEndpointAddresses(dest.getVectorEndpointAddresses()); StructuredTextDocument xptDoc = (StructuredTextDocument) ap.getDocument(encodeAs); Element e1 = adv.createElement("Dst"); adv.appendChild(e1); StructuredDocumentUtils.copyElements(adv, e1, xptDoc); } // only include hops if we have some if (getHops().hasMoreElements()) { Element e2 = adv.createElement("Hops"); adv.appendChild(e2); for (Enumeration e = getHops(); e.hasMoreElements(); ) { AccessPointAdvertisement hop = (AccessPointAdvertisement) e.nextElement(); if (hop != null) { StructuredTextDocument xptDoc = (StructuredTextDocument) hop.getDocument(encodeAs); StructuredDocumentUtils.copyElements(adv, e2, xptDoc); } } } return adv; }