Ejemplo n.º 1
0
        private async Task <ImmutableList <BoundPeer> > QueryNeighborsAsync(
            Address target,
            TimeSpan?timeout,
            CancellationToken cancellationToken)
        {
            List <BoundPeer> neighbors = _routing.Neighbors(target, _bucketSize).ToList();
            var found = new List <BoundPeer>();
            int count = (neighbors.Count < Kademlia.FindConcurrency)
                ? neighbors.Count
                : Kademlia.FindConcurrency;
            bool timeoutOccurred = true;

            for (int i = 0; i < count; i++)
            {
                try
                {
                    found.AddRange(
                        await GetNeighbors(neighbors[i], target, timeout, cancellationToken));
                    timeoutOccurred = false;
                }
                catch (TimeoutException)
                {
                    continue;
                }
            }

            if (count != 0 && timeoutOccurred)
            {
                _logger.Debug($"Timeout occurred during {nameof(QueryNeighborsAsync)}.");
                throw new TimeoutException(
                          $"Timeout occurred during {nameof(QueryNeighborsAsync)}.");
            }

            return(found.ToImmutableList());
        }
Ejemplo n.º 2
0
        private async Task <IEnumerable <BoundPeer> > QueryNeighborsAsync(
            ConcurrentBag <BoundPeer> history,
            Address target,
            TimeSpan?timeout,
            CancellationToken cancellationToken)
        {
            List <BoundPeer> neighbors = _routing.Neighbors(target, _bucketSize).ToList();
            var found = new List <BoundPeer>();
            int count = neighbors.Count < Kademlia.FindConcurrency
                ? neighbors.Count
                : Kademlia.FindConcurrency;
            var timeoutOccurred = true;

            for (var i = 0; i < count; i++)
            {
                try
                {
                    var peers =
                        await GetNeighbors(neighbors[i], target, timeout, cancellationToken);

                    history.Add(neighbors[i]);
                    found.AddRange(peers.Where(peer => !found.Contains(peer)));
                    timeoutOccurred = false;
                }
                catch (TimeoutException)
                {
                }
            }

            if (count != 0 && timeoutOccurred)
            {
                _logger.Debug($"Timeout occurred during {nameof(QueryNeighborsAsync)}.");
                throw new TimeoutException(
                          $"Timeout occurred during {nameof(QueryNeighborsAsync)}.");
            }

            return(found);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Use <see cref="FindNeighbors"/> messages to to find a <see cref="BoundPeer"/> with
        /// <see cref="Address"/> of <paramref name="target"/>.
        /// </summary>
        /// <param name="target">The <see cref="Address"/> to find.</param>
        /// <param name="depth">Target depth of recursive operation.</param>
        /// <param name="timeout"><see cref="TimeSpan"/> for waiting reply of
        /// <see cref="FindNeighbors"/>.</param>
        /// <param name="cancellationToken">A cancellation token used to propagate notification
        /// that this operation should be canceled.</param>
        /// <returns>A <see cref="BoundPeer"/> with <see cref="Address"/> of
        /// <paramref name="target"/>.</returns>
        public async Task <BoundPeer> FindSpecificPeerAsync(
            Address target,
            int depth,
            TimeSpan?timeout,
            CancellationToken cancellationToken)
        {
            _logger.Verbose(
                $"{nameof(FindSpecificPeerAsync)}() with {{Target}}. " +
                "(depth: {Depth})",
                target,
                depth);

            if (_table.GetPeer(target) is BoundPeer boundPeer)
            {
                try
                {
                    await PingAsync(boundPeer, _requestTimeout, cancellationToken);
                }
                catch (PingTimeoutException)
                {
                    var msg =
                        "{BoundPeer}, a target peer, is in the routing table does not respond.";
                    _logger.Verbose(msg, boundPeer);
                    RemovePeer(boundPeer);
                    return(null);
                }

                _logger.Verbose(
                    "{BoundPeer}, a target peer, is in the routing table.",
                    boundPeer);
                return(boundPeer);
            }

            var history     = new ConcurrentBag <BoundPeer>();
            var peersToFind = new ConcurrentQueue <Tuple <BoundPeer, int> >();

            foreach (BoundPeer peer in _table.Neighbors(target, _findConcurrency, false))
            {
                peersToFind.Enqueue(new Tuple <BoundPeer, int>(peer, 0));
            }

            while (peersToFind.Any())
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (!peersToFind.TryDequeue(out Tuple <BoundPeer, int> tuple))
                {
                    continue;
                }

                tuple.Deconstruct(out BoundPeer viaPeer, out int curDepth);
                _logger.Debug("ViaPeer: {Peer}, curDepth: {curDepth}", viaPeer, curDepth);
                if (depth != -1 && curDepth >= depth)
                {
                    continue;
                }

                history.Add(viaPeer);
                IEnumerable <BoundPeer> foundPeers =
                    await GetNeighbors(viaPeer, target, timeout, cancellationToken);

                IEnumerable <BoundPeer> filteredPeers = foundPeers
                                                        .Where(peer =>
                                                               !history.Contains(peer) &&
                                                               !peersToFind.Any(t => t.Item1.Equals(peer)) &&
                                                               !peer.Address.Equals(_address))
                                                        .Take(_findConcurrency);
                int count = 0;
                foreach (var found in filteredPeers)
                {
                    try
                    {
                        await PingAsync(found, _requestTimeout, cancellationToken);

                        if (found.Address.Equals(target))
                        {
                            return(found);
                        }

                        peersToFind.Enqueue(new Tuple <BoundPeer, int>(found, curDepth + 1));

                        if (count++ >= _findConcurrency)
                        {
                            break;
                        }
                    }
                    catch (TaskCanceledException)
                    {
                        throw new TaskCanceledException(
                                  $"Task is cancelled during {nameof(FindSpecificPeerAsync)}()");
                    }
                    catch (PingTimeoutException)
                    {
                        // Ignore peer not responding
                    }
                    finally
                    {
                        history.Add(found);
                    }
                }
            }

            return(null);
        }