Esempio n. 1
0
        public async Task ProcessGetProvidersMessage_HasCloserPeers()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                dht.RoutingTable.Add(other);
                Cid cid     = "zBunRGrmCGokA1oMESGGTfrtcMFsVA8aEtcNzM54akPWXF97uXCqTjF3GZ9v8YzxHrG66J8QhtPFWwZebRZ2zeUEELu67";
                var request = new DhtMessage
                {
                    Type = MessageType.GetProviders,
                    Key  = cid.Hash.ToArray()
                };
                var response = dht.ProcessGetProviders(request, new DhtMessage());
                Assert.AreNotEqual(0, response.CloserPeers.Length);
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 2
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 == Swarm.LocalPeer.Id)
                         ? Swarm.LocalPeer
                         : Swarm.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));
        }
Esempio n. 3
0
        public async Task ProcessFindNodeMessage_Self()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                var request = new DhtMessage
                {
                    Type = MessageType.FindNode,
                    Key  = self.Id.ToArray()
                };
                var response = dht.ProcessFindNode(request, new DhtMessage());
                Assert.AreEqual(1, response.CloserPeers.Length);
                var ok = response.CloserPeers[0].TryToPeer(out Peer found);
                Assert.IsTrue(ok);
                Assert.AreEqual(self, found);
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 4
0
        public async Task ProcessGetProvidersMessage_HasProvider()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                swarm.RegisterPeer(other);
                Cid cid = "zBunRGrmCGokA1oMESGGTfrtcMFsVA8aEtcNzM54akPWXF97uXCqTjF3GZ9v8YzxHrG66J8QhtPFWwZebRZ2zeUEELu67";
                dht.ContentRouter.Add(cid, other.Id);
                var request = new DhtMessage
                {
                    Type = MessageType.GetProviders,
                    Key  = cid.Hash.ToArray()
                };
                var response = dht.ProcessGetProviders(request, new DhtMessage());
                Assert.AreEqual(1, response.ProviderPeers.Length);
                response.ProviderPeers[0].TryToPeer(out Peer found);
                Assert.AreEqual(other, found);
                Assert.AreNotEqual(0, found.Addresses.Count());
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 5
0
        public async Task ProcessFindNodeMessage_InSwarm()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var other = await swarm.RegisterPeerAsync("/ip4/127.0.0.1/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1h");

            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                dht.RoutingTable.Add(other);
                var request = new DhtMessage
                {
                    Type = MessageType.FindNode,
                    Key  = other.Id.ToArray()
                };
                var response = dht.ProcessFindNode(request, new DhtMessage());
                Assert.AreEqual(1, response.CloserPeers.Length);
                var ok = response.CloserPeers[0].TryToPeer(out Peer found);
                Assert.IsTrue(ok);
                Assert.AreEqual(other, found);
                CollectionAssert.AreEqual(
                    other.Addresses.Select(a => a.WithoutPeerId()).ToArray(),
                    found.Addresses.Select(a => a.WithoutPeerId()).ToArray());
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 6
0
        public async Task ProcessFindNodeMessage_NoOtherPeers()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                var request = new DhtMessage
                {
                    Type = MessageType.FindNode,
                    Key  = new MultiHash("QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1h").ToArray()
                };
                var response = dht.ProcessFindNode(request, new DhtMessage());
                Assert.AreEqual(0, response.CloserPeers.Length);
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 7
0
        public async Task ProcessFindNodeMessage_InRoutingTable()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                dht.RoutingTable.Add(other);
                var request = new DhtMessage
                {
                    Type = MessageType.FindNode,
                    Key  = other.Id.ToArray()
                };
                var response = dht.ProcessFindNode(request, new DhtMessage());
                Assert.AreEqual(1, response.CloserPeers.Length);
                var ok = response.CloserPeers[0].TryToPeer(out Peer found);
                Assert.IsTrue(ok);
                Assert.AreEqual(other, found);
                CollectionAssert.AreEqual(other.Addresses.ToArray(),
                                          found.Addresses.Select(a => a.WithoutPeerId()).ToArray());
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 8
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}");
        }
Esempio n. 9
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 Peer peer) ? peer : (Peer)null)
                            .Where(p => p != null)
                            .Where(p => p == remotePeer)
                            .Where(p => p.Addresses.Count() > 0);

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

            // There is no response for this request.
            return(null);
        }
Esempio n. 10
0
        public async Task ProcessFindNodeMessage_BadNodeId()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };

            swarm.RegisterPeerAddress("/ip4/127.0.0.1/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1a");
            swarm.RegisterPeerAddress("/ip4/127.0.0.2/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1b");
            swarm.RegisterPeerAddress("/ip4/127.0.0.3/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1c");
            swarm.RegisterPeerAddress("/ip4/127.0.0.4/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1d");
            swarm.RegisterPeerAddress("/ip4/127.0.0.5/tcp/4001/ipfs/QmdpwjdB94eNm2Lcvp9JqoCxswo3AKQqjLuNZyLixmCM1e");
            var dht = new Dht1 {
                Swarm = swarm, CloserPeerCount = 3
            };
            await dht.StartAsync();

            try
            {
                dht.RoutingTable.Add(other);
                var request = new DhtMessage
                {
                    Type = MessageType.FindNode,
                    Key  = new byte[] { 0xFF, 1, 2, 3 }
                };
                var response = dht.ProcessFindNode(request, new DhtMessage());
                Assert.AreEqual(3, response.CloserPeers.Length);
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 11
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?.
            Peer found = null;

            if (Swarm.LocalPeer.Id == peerId)
            {
                found = Swarm.LocalPeer;
            }
            else
            {
                found = Swarm.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} closer peers");
            }
            return(response);
        }
Esempio n. 12
0
        /// <inheritdoc />
        public async Task ProcessMessageAsync(PeerConnection connection, Stream stream, CancellationToken cancel = default(CancellationToken))
        {
            while (true)
            {
                var request = await ProtoBufHelper.ReadMessageAsync <DhtMessage>(stream, cancel);

                log.Debug($"got message from {connection.RemotePeer}");
                var response = new DhtMessage();
                // TODO: process the request

                ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, response, PrefixStyle.Base128);
                await stream.FlushAsync(cancel);
            }
        }
Esempio n. 13
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.
 /// </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() =>
     {
         int advertsNeeded = 4;
         var message       = new DhtMessage
         {
             Type          = MessageType.AddProvider,
             Key           = cid.Hash.ToArray(),
             ProviderPeers = new DhtPeerMessage[]
             {
                 new DhtPeerMessage
                 {
                     Id        = Swarm.LocalPeer.Id.ToArray(),
                     Addresses = Swarm.LocalPeer.Addresses
                                 .Select(a => a.WithoutPeerId().ToArray())
                                 .ToArray()
                 }
             }
         };
         var peers = RoutingTable
                     .NearestPeers(cid.Hash)
                     .Where(p => p != Swarm.LocalPeer);
         foreach (var peer in peers)
         {
             try
             {
                 using (var stream = await Swarm.DialAsync(peer, this.ToString()))
                 {
                     ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, message, PrefixStyle.Base128);
                     await stream.FlushAsync();
                 }
                 if (--advertsNeeded == 0)
                 {
                     break;
                 }
             }
             catch (Exception)
             {
                 // eat it.  This is fire and forget.
             }
         }
     });
 }
Esempio n. 14
0
        /// <inheritdoc />
        public async Task ProcessMessageAsync(PeerConnection connection, Stream stream, CancellationToken cancel = default(CancellationToken))
        {
            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;

                default:
                    log.Debug($"unknown {request.Type} from {connection.RemotePeer}");
                    // TODO: Should we close the stream?
                    continue;
                }
                if (response != null)
                {
                    ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, response, PrefixStyle.Base128);
                    await stream.FlushAsync(cancel).ConfigureAwait(false);
                }
            }
        }
Esempio n. 15
0
        public async Task ProcessAddProviderMessage()
        {
            var swarm = new Swarm {
                LocalPeer = self
            };
            var dht = new Dht1 {
                Swarm = swarm
            };
            await dht.StartAsync();

            try
            {
                Cid cid     = "zBunRGrmCGokA1oMESGGTfrtcMFsVA8aEtcNzM54akPWXF97uXCqTjF3GZ9v8YzxHrG66J8QhtPFWwZebRZ2zeUEELu67";
                var request = new DhtMessage
                {
                    Type          = MessageType.AddProvider,
                    Key           = cid.Hash.ToArray(),
                    ProviderPeers = new DhtPeerMessage[]
                    {
                        new DhtPeerMessage
                        {
                            Id        = other.Id.ToArray(),
                            Addresses = other.Addresses.Select(a => a.ToArray()).ToArray()
                        }
                    }
                };
                var response = dht.ProcessAddProvider(other, request, new DhtMessage());
                Assert.IsNull(response);
                var providers = dht.ContentRouter.Get(cid).ToArray();
                Assert.AreEqual(1, providers.Length);
                Assert.AreEqual(other.Id, providers[0]);

                var provider = swarm.KnownPeers.Single(p => p == other);
                Assert.AreNotEqual(0, provider.Addresses.Count());
            }
            finally
            {
                await dht.StopAsync();
            }
        }
Esempio n. 16
0
 /// <summary>
 ///   Process a ping request.
 /// </summary>
 /// <remarks>
 ///   Simply return the <paramref name="request"/>.
 /// </remarks>
 DhtMessage ProcessPing(DhtMessage request, DhtMessage response)
 {
     return(request);
 }