/// <summary> /// Looks for a route to the given peer address. /// </summary> /// <param name="peerAddresses">Nodes that should be asked first for a route.</param> /// <param name="routingBuilder"></param> /// <param name="type"></param> /// <param name="cc"></param> /// <returns>A task object that is set to complete if the route has been found.</returns> private TcsRouting Routing(ICollection <PeerAddress> peerAddresses, RoutingBuilder routingBuilder, Message.Message.MessageType type, ChannelCreator cc) { try { if (peerAddresses == null) { throw new ArgumentException("Some nodes/addresses need to be specified."); } bool randomSearch = routingBuilder.LocationKey == null; IComparer <PeerAddress> comparer; if (randomSearch) { comparer = _peerBean.PeerMap.CreateComparer(); } else { comparer = PeerMap.CreateComparer(routingBuilder.LocationKey); } var queueToAsk = new SortedSet <PeerAddress>(comparer); var alreadyAsked = new SortedSet <PeerAddress>(comparer); // As presented by Kazuyuki Shudo at AIMS 2009, it is better to ask random // peers with the data than ask peers that are ordered by distance. // -> this balances load var directHits = new SortedDictionary <PeerAddress, DigestInfo>(comparer); var potentialHits = new SortedSet <PeerAddress>(comparer); // fill initially queueToAsk.AddAll(peerAddresses); alreadyAsked.Add(_peerBean.ServerPeerAddress); potentialHits.Add(_peerBean.ServerPeerAddress); // domain key can be null if we bootstrap if (type == Message.Message.MessageType.Request2 && routingBuilder.DomainKey != null && !randomSearch && _peerBean.DigestStorage != null) { Number640 from; Number640 to; if (routingBuilder.From != null && routingBuilder.To != null) { from = routingBuilder.From; to = routingBuilder.To; } else if (routingBuilder.ContentKey == null) { from = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, Number160.Zero, Number160.Zero); to = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, Number160.MaxValue, Number160.MaxValue); } else { from = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey, Number160.Zero); to = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey, Number160.MaxValue); } var digestBean = _peerBean.DigestStorage.Digest(from, to, -1, true); if (digestBean.Size > 0) { directHits.Add(_peerBean.ServerPeerAddress, digestBean); } } else if (type == Message.Message.MessageType.Request3 && !randomSearch && _peerBean.DigestTracker != null) { var digestInfo = _peerBean.DigestTracker.Digest(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey); // we always put ourselfs to the tracker list, so we need to check // if we know also other peers on our trackers if (digestInfo.Size > 0) { directHits.Add(_peerBean.ServerPeerAddress, digestInfo); } } var tcsRouting = new TcsRouting(); if (peerAddresses.Count == 0) { tcsRouting.SetNeighbors(directHits, potentialHits, alreadyAsked, routingBuilder.IsBootstrap, false); } else { // If a peer bootstraps to itself, then the size of peer addresses is 1 // and it contains itself. Check for that because we need to know if we // are routing, bootstrapping and bootstrapping to ourselfs, to return // the correct status for the task. var isRoutingOnlyToSelf = peerAddresses.Count == 1 && peerAddresses.First().Equals(_peerBean.ServerPeerAddress); var routingMechanism = routingBuilder.CreateRoutingMechanism(tcsRouting); routingMechanism.SetQueueToAsk(queueToAsk); routingMechanism.SetPotentialHits(potentialHits); routingMechanism.SetDirectHits(directHits); routingMechanism.SetAlreadyAsked(alreadyAsked); routingBuilder.SetIsRoutingOnlyToSelf(isRoutingOnlyToSelf); RoutingRec(routingBuilder, routingMechanism, type, cc); } return(tcsRouting); } catch (Exception ex) { Logger.Error("An exception occurred during routing.", ex); throw; } }