예제 #1
0
        public void Failed(Message.Message.MessageType type)
        {
            var responseMessage = DispatchHandler.CreateResponseMessage(_requestMessage, type,
                                                                        _peerBeanMaster.ServerPeerAddress);

            _dispatcher.Respond(_ctx, responseMessage);
        }
예제 #2
0
        /// <summary>
        /// Looks for a route to the location key given in the routing builder.
        /// </summary>
        /// <param name="routingBuilder">All relevant information for the routing process.</param>
        /// <param name="type">The type of the routing. (4 types)</param>
        /// <param name="cc">The channel creator.</param>
        /// <returns>A task object that is set to complete if the route has been found.</returns>
        public TcsRouting Route(RoutingBuilder routingBuilder, Message.Message.MessageType type, ChannelCreator cc)
        {
            // for bad distribution, use large #noNewInformation
            ICollection <PeerAddress> startPeers = _peerBean.PeerMap.ClosePeers(routingBuilder.LocationKey,
                                                                                routingBuilder.Parallel * 2);

            return(Routing(startPeers, routingBuilder, type, cc));
        }
예제 #3
0
        /// <summary>
        /// Creates a RequestHandler.
        /// </summary>
        /// <param name="remotePeer">The destination peer.</param>
        /// <param name="type">The type of the request.</param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        private RequestHandler CreateHandler(PeerAddress remotePeer, Message.Message.MessageType type,
                                             IConnectionConfiguration configuration)
        {
            // .NET-specific:
            // 1. use TCS<Message> instead of FutureResponse
            // 2. store message as the TCS's AsyncState
            var message = CreateRequestMessage(remotePeer, Rpc.Commands.Ping.GetNr(), type);

            var tcsResponse = new TaskCompletionSource <Message.Message>(message);

            return(new RequestHandler(tcsResponse, PeerBean, ConnectionBean, configuration));
        }
예제 #4
0
 public static Message.Message CreateResponseMessage(Message.Message requestMessage,
                                                     Message.Message.MessageType replyType, PeerAddress peerAddress)
 {
     // this will have the ports >40'000 that we need to know for sending the reply
     return(new Message.Message()
            .SetSenderSocket(requestMessage.SenderSocket)
            .SetRecipientSocket(requestMessage.RecipientSocket)
            .SetRecipient(requestMessage.Sender)
            .SetSender(peerAddress)
            .SetCommand(requestMessage.Command)
            .SetType(replyType)
            .SetVersion(requestMessage.Version)
            .SetMessageId(requestMessage.MessageId)
            .SetIsUdp(requestMessage.IsUdp));
 }
예제 #5
0
        private void RoutingRec(RoutingBuilder routingBuilder, RoutingMechanism routingMechanism,
                                Message.Message.MessageType type, ChannelCreator channelCreator)
        {
            var randomSearch = routingBuilder.LocationKey == null;
            var active       = 0;

            for (var i = 0; i < routingMechanism.Parallel; i++)
            {
                if (routingMechanism.GetTcsResponse(i) == null &&
                    !routingMechanism.IsStopCreatingNewFutures)
                {
                    PeerAddress next;
                    if (randomSearch)
                    {
                        next = routingMechanism.PollRandomInQueueToAsk(_rnd);
                    }
                    else
                    {
                        next = routingMechanism.PollFirstInQueueToAsk();
                    }
                    if (next != null)
                    {
                        routingMechanism.AddToAlreadyAsked(next);
                        active++;
                        // If we search for a random peer, then the peer should
                        // return the address farest away.
                        var locationKey2 = randomSearch
                            ? next.PeerId.Xor(Number160.MaxValue)
                            : routingBuilder.LocationKey;
                        routingBuilder.LocationKey = locationKey2;

                        // routing is per default UDP, don't show warning if the other TCP/UDP is used
                        // TODO find .NET-specific way to show sanity check warning

                        routingMechanism.SetTcsResponse(i,
                                                        _neighbors.CloseNeighborsTcs(next, routingBuilder.SearchValues(), type, channelCreator,
                                                                                     routingBuilder));
                        Logger.Debug("Get close neighbours: {0} on {1}.", next, i);
                    }
                }
                else if (routingMechanism.GetTcsResponse(i) != null)
                {
                    Logger.Debug("Activity on {0}.", i);
                    active++;
                }
            }

            if (active == 0)
            {
                Logger.Debug("No activity, closing.");
                routingMechanism.SetNeighbors(routingBuilder);
                routingMechanism.Cancel();
                return;
            }

            // .NET-specific: // TODO move to TcsForkJoin as separate c'tor?
            var extractedTasks = new Task <Message.Message> [routingMechanism.TcsResponses.Length];

            for (int i = 0; i < routingMechanism.TcsResponses.Length; i++)
            {
                extractedTasks[i] = routingMechanism.GetTcsResponse(i) != null?routingMechanism.GetTcsResponse(i).Task : null;
            }
            var volatileArray = new VolatileReferenceArray <Task <Message.Message> >(extractedTasks);

            bool last        = active == 1;
            var  tcsForkJoin = new TcsForkJoin <Task <Message.Message> >(1, false, volatileArray);

            tcsForkJoin.Task.ContinueWith(tfj =>
            {
                bool finished;
                if (!tfj.IsFaulted)
                {
                    var lastResponse = tcsForkJoin.Last.Result;
                    var remotePeer   = lastResponse.Sender;
                    routingMechanism.AddPotentialHits(remotePeer);
                    var newNeighbors = lastResponse.NeighborsSet(0).Neighbors;

                    var resultSize    = lastResponse.IntAt(0);
                    var keyDigest     = lastResponse.Key(0);
                    var contentDigest = lastResponse.Key(1);
                    var digestBean    = new DigestInfo(keyDigest, contentDigest, resultSize);
                    Logger.Debug("Peer ({0}) {1} reported {2} in message {3}.", (digestBean.Size > 0 ? "direct" : "none"), remotePeer, newNeighbors.Count, lastResponse);
                    finished = routingMechanism.EvaluateSuccess(remotePeer, digestBean, newNeighbors, last,
                                                                routingBuilder.LocationKey);
                    Logger.Debug("Routing finished {0} / {1}.", finished, routingMechanism.IsStopCreatingNewFutures);
                }
                else
                {
                    // if it failed but the failed is the closest one, it is good to try again,
                    // since the peer might just be busy
                    Logger.Debug("Routing error {0}.", tfj.Exception);
                    finished = routingMechanism.EvaluateFailed();
                    routingMechanism.IsStopCreatingNewFutures = finished;
                }

                if (finished)
                {
                    Logger.Debug("Routing finished. Direct hits: {0}. Potential hits: {1}.", routingMechanism.DirectHits.Count, routingMechanism.PotentialHits.Count);
                    routingMechanism.SetNeighbors(routingBuilder);
                    routingMechanism.Cancel();
                    // stop all operations, as we are finished, no need to go further
                }
                else
                {
                    RoutingRec(routingBuilder, routingMechanism, type, channelCreator);
                }
            });
        }
예제 #6
0
        /// <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;
            }
        }
예제 #7
0
 /// <summary>
 /// Creates a response requestMessage and fills it with peer bean and connection bean parameters.
 /// </summary>
 /// <param name="requestMessage">The request requestMessage.</param>
 /// <param name="replyType">The type of the reply.</param>
 /// <returns>The response requestMessage.</returns>
 public Message.Message CreateResponseMessage(Message.Message requestMessage,
                                              Message.Message.MessageType replyType)
 {
     return(CreateResponseMessage(requestMessage, replyType, PeerBean.ServerPeerAddress));
 }
예제 #8
0
 /// <summary>
 /// Creates a request requestMessage and fills it with peer bean and connection bean parameters.
 /// </summary>
 /// <param name="recipient">The recipient of this requestMessage.</param>
 /// <param name="name">The command type.</param>
 /// <param name="type">The request type.</param>
 /// <returns>The created request requestMessage.</returns>
 public Message.Message CreateRequestMessage(PeerAddress recipient, sbyte name, Message.Message.MessageType type)
 {
     return(new Message.Message()
            .SetRecipient(recipient)
            .SetSender(PeerBean.ServerPeerAddress)
            .SetCommand(name)
            .SetType(type)
            .SetVersion(ConnectionBean.P2PId));
 }
예제 #9
0
        /// <summary>
        /// .NET-specific: Used for DistributedRouting only.
        /// </summary>
        internal TaskCompletionSource <Message.Message> CloseNeighborsTcs(PeerAddress remotePeer, SearchValues searchValues, Message.Message.MessageType type,
                                                                          ChannelCreator channelCreator, IConnectionConfiguration configuration)
        {
            var message = CreateRequestMessage(remotePeer, Rpc.Commands.Neighbor.GetNr(), type);

            if (!message.IsRequest())
            {
                throw new ArgumentException("The type must be a request.");
            }
            message.SetKey(searchValues.LocationKey);
            message.SetKey(searchValues.DomainKey ?? Number160.Zero);

            if (searchValues.From != null && searchValues.To != null)
            {
                ICollection <Number640> collection = new List <Number640>();
                collection.Add(searchValues.From);
                collection.Add(searchValues.To);
                var keyCollection = new KeyCollection(collection);
                message.SetKeyCollection(keyCollection);
            }
            else
            {
                if (searchValues.ContentKey != null)
                {
                    message.SetKey(searchValues.ContentKey);
                }
                if (searchValues.KeyBloomFilter != null)
                {
                    message.SetBloomFilter(searchValues.KeyBloomFilter);
                }
                if (searchValues.ContentBloomFilter != null)
                {
                    message.SetBloomFilter(searchValues.ContentBloomFilter);
                }
            }
            return(Send(message, configuration, channelCreator));
        }
예제 #10
0
        /// <summary>
        /// Requests close neighbors from the remote peer. The remote peer may indicate if the
        /// data is present on that peer. This is an RPC.
        /// </summary>
        /// <param name="remotePeer">The remote peer to send this request to.</param>
        /// <param name="searchValues">The values to search for in the storage.</param>
        /// <param name="type">The type of the neighbor request:
        /// - Request1 for Neighbors means check for Put (no digest) for tracker and storage.
        /// - Request2 for Neighbors means check for Get (with digest) for storage.
        /// - Request3 for Neighbors means check for Get (with digest) for tracker.
        /// - Request4 for Neighbors means check for Put (with digest) for task.</param>
        /// <param name="channelCreator">The channel creator that creates connections.</param>
        /// <param name="configuration">The client-side connection configuration.</param>
        /// <returns>The future response message.</returns>
        public Task <Message.Message> CloseNeighborsAsync(PeerAddress remotePeer, SearchValues searchValues, Message.Message.MessageType type,
                                                          ChannelCreator channelCreator, IConnectionConfiguration configuration)
        {
            var tcsResponse = CloseNeighborsTcs(remotePeer, searchValues, type, channelCreator, configuration);

            return(tcsResponse.Task);
        }