Example #1
0
        /// <summary>
        ///   Process a get provider request.
        /// </summary>
        public DhtMessage ProcessGetProviders(DhtMessage request, DhtMessage response)
        {
            // Find providers for the content.
            var cid = new Cid {
                Hash = new MultiHash(request.Key)
            };

            response.ProviderPeers = ContentRouter
                                     .Get(cid)
                                     .Select(pid =>
            {
                var peer = pid == SwarmService.LocalPeer.Id
                        ? SwarmService.LocalPeer
                        : SwarmService.RegisterPeer(new Peer {
                    Id = pid
                });
                return(new DhtPeerMessage
                {
                    Id = peer.Id.ToArray(),
                    Addresses = peer.Addresses.Select(a => a.WithoutPeerId().ToArray()).ToArray()
                });
            })
                                     .Take(20)
                                     .ToArray();

            // Also return the closest peers
            return(ProcessFindNode(request, response));
        }
Example #2
0
        /// <summary>
        ///   Starts the distributed query.
        /// </summary>
        /// <param name="cancel">
        ///   Is used to stop the task.  When cancelled, the <see cref="TaskCanceledException"/> is raised.
        /// </param>
        /// <returns>
        ///   A task that represents the asynchronous operation.
        /// </returns>
        public async Task RunAsync(CancellationToken cancel)
        {
            Log.Debug($"Q{Id} run {QueryType} {QueryKey}");

            _runningQuery = CancellationTokenSource.CreateLinkedTokenSource(cancel);
            Dht.Stopped  += OnDhtStopped;
            _queryMessage = new DhtMessage
            {
                Type = QueryType,
                Key  = QueryKey?.ToArray(),
            };

            var tasks = Enumerable
                        .Range(1, ConcurrencyLevel)
                        .Select(i =>
            {
                var id = i;
                return(AskAsync(id));
            });

            try
            {
                await Task.WhenAll(tasks).ConfigureAwait(false);
            }
            catch (Exception)
            {
                // eat it
            }
            finally
            {
                Dht.Stopped -= OnDhtStopped;
            }

            Log.Debug($"Q{Id} found {_answers.Count} answers, visited {_visited.Count} peers, failed {_failedConnects}");
        }
Example #3
0
        /// <inheritdoc />
        public async Task ProcessMessageAsync(PeerConnection connection,
                                              Stream stream,
                                              CancellationToken cancel = default)
        {
            while (true)
            {
                var request = await ProtoBufHelper.ReadMessageAsync <DhtMessage>(stream, cancel).ConfigureAwait(false);

                _log.Debug($"got {request.Type} from {connection.RemotePeer}");
                var response = new DhtMessage
                {
                    Type            = request.Type,
                    ClusterLevelRaw = request.ClusterLevelRaw
                };
                switch (request.Type)
                {
                case MessageType.Ping:
                    response = ProcessPing(request, response);
                    break;

                case MessageType.FindNode:
                    response = ProcessFindNode(request, response);
                    break;

                case MessageType.GetProviders:
                    response = ProcessGetProviders(request, response);
                    break;

                case MessageType.AddProvider:
                    response = ProcessAddProvider(connection.RemotePeer, request, response);
                    break;

                case MessageType.PutValue:
                    break;

                case MessageType.GetValue:
                    break;

                default:
                    _log.Debug($"unknown {request.Type} from {connection.RemotePeer}");

                    // TODO: Should we close the stream?
                    continue;
                }

                if (response == null)
                {
                    continue;
                }

                Serializer.SerializeWithLengthPrefix(stream, response, PrefixStyle.Base128);
                await stream.FlushAsync(cancel).ConfigureAwait(false);
            }
        }
Example #4
0
        /// <summary>
        ///   Advertise that we can provide the CID to the X closest peers
        ///   of the CID.
        /// </summary>
        /// <param name="cid">
        ///   The CID to advertise.ipfs
        /// </param>
        /// <remarks>
        ///   This starts a background process to send the AddProvider message
        ///   to the 4 closest peers to the <paramref name="cid"/>.
        /// </remarks>
        public void Advertise(Cid cid)
        {
            _ = Task.Run(async() =>
            {
                var advertsNeeded = 4;
                var message       = new DhtMessage
                {
                    Type          = MessageType.AddProvider,
                    Key           = cid.Hash.ToArray(),
                    ProviderPeers = new[]
                    {
                        new DhtPeerMessage
                        {
                            Id        = SwarmService.LocalPeer.Id.ToArray(),
                            Addresses = SwarmService.LocalPeer.Addresses
                                        .Select(a => a.WithoutPeerId().ToArray())
                                        .ToArray()
                        }
                    }
                };

                var peers = RoutingTable
                            .NearestPeers(cid.Hash)
                            .Where(p => p != SwarmService.LocalPeer);

                foreach (var peer in peers)
                {
                    try
                    {
                        await using (var stream = await SwarmService.DialAsync(peer, ToString()))
                        {
                            Serializer.SerializeWithLengthPrefix(stream, message, PrefixStyle.Base128);
                            await stream.FlushAsync();
                        }

                        if (--advertsNeeded == 0)
                        {
                            break;
                        }
                    }
                    catch (Exception)
                    {
                        // eat it.  This is fire and forget.
                    }
                }
            });
        }
Example #5
0
        /// <summary>
        ///   Process a find node request.
        /// </summary>
        public DhtMessage ProcessFindNode(DhtMessage request, DhtMessage response)
        {
            // Some random walkers generate a random Key that is not hashed.
            MultiHash peerId;

            try
            {
                peerId = new MultiHash(request.Key);
            }
            catch (Exception)
            {
                _log.Error($"Bad FindNode request key {request.Key.ToHexString()}");
                peerId = MultiHash.ComputeHash(request.Key);
            }

            // Do we know the peer?.
            var found = SwarmService.LocalPeer.Id == peerId ? SwarmService.LocalPeer : SwarmService.KnownPeers.FirstOrDefault(p => p.Id == peerId);

            // Find the closer peers.
            var closerPeers = new List <Peer>();

            if (found != null)
            {
                closerPeers.Add(found);
            }
            else
            {
                closerPeers.AddRange(RoutingTable.NearestPeers(peerId).Take(CloserPeerCount));
            }

            // Build the response.
            response.CloserPeers = closerPeers
                                   .Select(peer => new DhtPeerMessage
            {
                Id        = peer.Id.ToArray(),
                Addresses = peer.Addresses.Select(a => a.WithoutPeerId().ToArray()).ToArray()
            })
                                   .ToArray();

            if (_log.IsDebugEnabled)
            {
                _log.Debug($"returning {response.CloserPeers.Length.ToString()} closer peers");
            }

            return(response);
        }
Example #6
0
        /// <summary>
        ///   Process an add provider request.
        /// </summary>
        public DhtMessage ProcessAddProvider(Peer remotePeer, DhtMessage request, DhtMessage response)
        {
            if (request.ProviderPeers == null)
            {
                return(null);
            }

            Cid cid;

            try
            {
                cid = new Cid {
                    Hash = new MultiHash(request.Key)
                };
            }
            catch (Exception)
            {
                _log.Error($"Bad AddProvider request key {request.Key.ToHexString()}");
                return(null);
            }

            var providers = request.ProviderPeers
                            .Select(p => p.TryToPeer(out var peer) ? peer : (Peer)null)
                            .Where(p => p != null)
                            .Where(p => p == remotePeer)
                            .Where(p => p.Addresses.Any());

            //.Where(p => SwarmService.IsAllowed(p));

            foreach (var provider in providers)
            {
                SwarmService.RegisterPeer(provider);
                ContentRouter.Add(cid, provider.Id);
            }

            // There is no response for this request.
            return(null);
        }
Example #7
0
 /// <summary>
 ///   Process a ping request.
 /// </summary>
 /// <remarks>
 ///   Simply return the <paramref name="request"/>.
 /// </remarks>
 private static DhtMessage ProcessPing(DhtMessage request, DhtMessage response)
 {
     return(request);
 }