Esempio n. 1
0
        public void Remove_DoesNotExist()
        {
            var manager = new ConnectionManager();
            var peer    = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peer, Stream = Stream.Null
            };

            Assert.IsFalse(manager.Remove(a));
            Assert.IsFalse(manager.IsConnected(peer));
            Assert.AreEqual(0, manager.Connections.Count());
            Assert.IsNull(a.Stream);
        }
Esempio n. 2
0
        async Task <PeerConnection> DialAsync(Peer remote, MultiAddress addr, CancellationToken cancel)
        {
            // TODO: HACK: Currenty only the ipfs/p2p is supported.
            // short circuit to make life faster.
            if (addr.Protocols.Count != 3 ||
                !(addr.Protocols[2].Name == "ipfs" || addr.Protocols[2].Name == "p2p"))
            {
                throw new Exception($"Cannnot dial; unknown protocol in '{addr}'.");
            }

            // Establish the transport stream.
            Stream stream = null;

            foreach (var protocol in addr.Protocols)
            {
                cancel.ThrowIfCancellationRequested();
                if (TransportRegistry.Transports.TryGetValue(protocol.Name, out Func <IPeerTransport> transport))
                {
                    stream = await transport().ConnectAsync(addr, cancel);

                    if (cancel.IsCancellationRequested)
                    {
                        stream?.Dispose();
                        continue;
                    }
                    break;
                }
            }
            if (stream == null)
            {
                throw new Exception("Missing a known transport protocol name.");
            }

            // Build the connection.
            remote.ConnectedAddress = addr;
            var connection = new PeerConnection
            {
                IsIncoming = false,
                LocalPeer  = LocalPeer,
                // TODO: LocalAddress
                LocalPeerKey  = LocalPeerKey,
                RemotePeer    = remote,
                RemoteAddress = addr,
                Stream        = stream
            };

            return(connection);
        }
Esempio n. 3
0
        public void PeerDisconnectedEvent_ConnectionClose()
        {
            int gotEvent = 0;
            var manager  = new ConnectionManager();

            manager.PeerDisconnected += (s, e) => gotEvent += 1;
            var peerA = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peerA, Stream = Stream.Null
            };

            manager.Add(a);
            a.Dispose();
            Assert.AreEqual(1, gotEvent);
        }
Esempio n. 4
0
        public void PeerDisconnectedEvent_RemovingPeer()
        {
            bool gotEvent = false;
            var  manager  = new ConnectionManager();

            manager.PeerDisconnected += (s, e) => gotEvent = true;
            var peerA = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peerA, Stream = Stream.Null
            };

            manager.Add(a);

            manager.Remove(peerA.Id);
            Assert.IsTrue(gotEvent);
        }
Esempio n. 5
0
        public void Maintains_PeerConnectedAddress()
        {
            var address1 = "/ip4/127.0.0.1/tcp/4007";
            var address2 = "/ip4/127.0.0.2/tcp/4007";

            var manager = new ConnectionManager();
            var peer    = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peer, RemoteAddress = address1, Stream = Stream.Null
            };
            var b = new PeerConnection {
                RemotePeer = peer, RemoteAddress = address2, Stream = Stream.Null
            };

            Assert.AreSame(a, manager.Add(a));
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());
            Assert.IsNotNull(a.Stream);
            Assert.AreEqual(address1, peer.ConnectedAddress);

            Assert.AreSame(b, manager.Add(b));
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(2, manager.Connections.Count());
            Assert.IsNotNull(a.Stream);
            Assert.IsNotNull(b.Stream);
            Assert.AreEqual(address1, peer.ConnectedAddress);

            Assert.IsTrue(manager.Remove(a));
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());
            Assert.IsNull(a.Stream);
            Assert.IsNotNull(b.Stream);
            Assert.AreEqual(address2, peer.ConnectedAddress);

            Assert.IsTrue(manager.Remove(b));
            Assert.IsFalse(manager.IsConnected(peer));
            Assert.AreEqual(0, manager.Connections.Count());
            Assert.IsNull(a.Stream);
            Assert.IsNull(b.Stream);
            Assert.IsNull(peer.ConnectedAddress);
        }
Esempio n. 6
0
        public void Add_Duplicate_SameConnection()
        {
            var manager = new ConnectionManager();
            var peer    = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peer, Stream = Stream.Null
            };

            Assert.AreSame(a, manager.Add(a));
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());
            Assert.IsNotNull(a.Stream);

            Assert.AreSame(a, manager.Add(a));
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());
            Assert.IsNotNull(a.Stream);
        }
Esempio n. 7
0
        public void IsConnected_NotActive()
        {
            var manager = new ConnectionManager();
            var peer    = new Peer {
                Id = aId
            };
            var connection = new PeerConnection {
                RemotePeer = peer, Stream = Stream.Null
            };

            Assert.IsFalse(manager.IsConnected(peer));

            manager.Add(connection);
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());

            connection.Stream = null;
            Assert.IsFalse(manager.IsConnected(peer));
            Assert.AreEqual(0, manager.Connections.Count());
        }
Esempio n. 8
0
        public void Remove_PeerId()
        {
            var manager = new ConnectionManager();
            var peer    = new Peer {
                Id = aId
            };
            var a = new PeerConnection {
                RemotePeer = peer, Stream = Stream.Null
            };

            manager.Add(a);
            Assert.IsTrue(manager.IsConnected(peer));
            Assert.AreEqual(1, manager.Connections.Count());
            Assert.IsNotNull(a.Stream);

            Assert.IsTrue(manager.Remove(peer.Id));
            Assert.IsFalse(manager.IsConnected(peer));
            Assert.AreEqual(0, manager.Connections.Count());
            Assert.IsNull(a.Stream);
        }
Esempio n. 9
0
        public void Stats()
        {
            var stream     = new MemoryStream();
            var connection = new PeerConnection {
                Stream = stream
            };

            Assert.AreEqual(0, connection.BytesRead);
            Assert.AreEqual(0, connection.BytesWritten);

            var buffer = new byte[] { 1, 2, 3 };

            connection.Stream.Write(buffer, 0, 3);
            Assert.AreEqual(0, connection.BytesRead);
            Assert.AreEqual(3, connection.BytesWritten);

            stream.Position = 0;
            connection.Stream.ReadByte();
            connection.Stream.ReadByte();
            Assert.AreEqual(2, connection.BytesRead);
            Assert.AreEqual(3, connection.BytesWritten);
        }
Esempio n. 10
0
        public void Disposing()
        {
            var closeCount = 0;
            var stream     = new MemoryStream();
            var connection = new PeerConnection {
                Stream = stream
            };

            connection.Closed += (s, e) =>
            {
                ++closeCount;
            };
            Assert.IsNotNull(connection.Stream);

            connection.Dispose();
            Assert.IsNull(connection.Stream);

            // Can be disposed multiple times.
            connection.Dispose();

            Assert.AreEqual(1, closeCount);
        }
Esempio n. 11
0
        /// <summary>
        ///   Adds a new connection.
        /// </summary>
        /// <param name="connection">
        ///   The <see cref="PeerConnection"/> to add.
        /// </param>
        /// <returns>
        ///   The connection that should be used.
        /// </returns>
        /// <remarks>
        ///   If a connection already exists to the peer, the specified
        ///   <paramref name="connection"/> is closed and existing connection
        ///   is returned.
        /// </remarks>
        public PeerConnection Add(PeerConnection connection)
        {
            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }
            if (connection.RemotePeer == null)
            {
                throw new ArgumentNullException("connection.RemotePeer");
            }
            if (connection.RemotePeer.Id == null)
            {
                throw new ArgumentNullException("connection.RemotePeer.Id");
            }

            connections.AddOrUpdate(
                Key(connection.RemotePeer),
                (key) => new List <PeerConnection> {
                connection
            },
                (key, conns) =>
            {
                if (!conns.Contains(connection))
                {
                    conns.Add(connection);
                }
                return(conns);
            }
                );

            if (connection.RemotePeer.ConnectedAddress == null)
            {
                connection.RemotePeer.ConnectedAddress = connection.RemoteAddress;
            }
            connection.Closed += (s, e) => Remove(e);
            return(connection);
        }
Esempio n. 12
0
        /// <summary>
        ///   Remove a connection.
        /// </summary>
        /// <param name="connection">
        ///   The <see cref="PeerConnection"/> to remove.
        /// </param>
        /// <returns>
        ///   <b>true</b> if the connection was removed; otherwise, <b>false</b>.
        /// </returns>
        /// <remarks>
        ///    The <paramref name="connection"/> is removed from the list of
        ///    connections and is closed.
        /// </remarks>
        public bool Remove(PeerConnection connection)
        {
            if (connection == null)
            {
                return(false);
            }

            if (!connections.TryGetValue(Key(connection.RemotePeer), out List <PeerConnection> originalConns))
            {
                connection.Dispose();
                return(false);
            }
            if (!originalConns.Contains(connection))
            {
                connection.Dispose();
                return(false);
            }

            var newConns = new List <PeerConnection>();

            newConns.AddRange(originalConns.Where(c => c != connection));
            connections.TryUpdate(Key(connection.RemotePeer), newConns, originalConns);

            connection.Dispose();
            if (newConns.Count > 0)
            {
                var last = newConns.Last();
                last.RemotePeer.ConnectedAddress = last.RemoteAddress;
            }
            else
            {
                connection.RemotePeer.ConnectedAddress = null;
                PeerDisconnected?.Invoke(this, connection.RemotePeer.Id);
            }
            return(true);
        }
Esempio n. 13
0
        /// <summary>
        ///   Called when a remote peer is connecting to the local peer.
        /// </summary>
        /// <param name="stream">
        ///   The stream to the remote peer.
        /// </param>
        /// <param name="local">
        ///   The local peer's address.
        /// </param>
        /// <param name="remote">
        ///   The remote peer's address.
        /// </param>
        /// <remarks>
        ///   Establishes the protocols of the connection.  Any exception is simply
        ///   logged as warning.
        /// </remarks>
        async void OnRemoteConnect(Stream stream, MultiAddress local, MultiAddress remote)
        {
            // If the remote is already trying to establish a connection, then we
            // can just refuse this one.
            if (!pendingRemoteConnections.TryAdd(remote, null))
            {
                log.Debug($"Duplicate remote connection from {remote}");
                stream.Dispose();
                return;
            }

            try
            {
                log.Debug($"{LocalPeer.Id} got remote connection");
                log.Debug("local " + local);
                log.Debug("remote " + remote);

                // TODO: Check the policies

                var connection = new PeerConnection
                {
                    IsIncoming    = true,
                    LocalPeer     = LocalPeer,
                    LocalAddress  = local,
                    LocalPeerKey  = LocalPeerKey,
                    RemoteAddress = remote,
                    Stream        = stream
                };

                // Are we communicating to a private network?
                if (NetworkProtector != null)
                {
                    connection.Stream = await NetworkProtector.ProtectAsync(connection).ConfigureAwait(false);
                }

                // Mount the protocols.
                MountProtocols(connection);

                // Start the handshake
                // TODO: Isn't connection cancel token required.
                connection.ReadMessages(default(CancellationToken));

                // Wait for security to be established.
                await connection.SecurityEstablished.Task.ConfigureAwait(false);

                // TODO: Maybe connection.LocalPeerKey = null;

                // Wait for the handshake to complete.
                var muxer = await connection.MuxerEstablished.Task;

                // Need details on the remote peer.
                Identify1 identify = null;
                lock (protocols)
                {
                    identify = protocols.OfType <Identify1>().First();
                }
                connection.RemotePeer = await identify.GetRemotePeer(connection, default(CancellationToken)).ConfigureAwait(false);

                connection.RemotePeer    = RegisterPeer(connection.RemotePeer);
                connection.RemoteAddress = new MultiAddress($"{remote}/ipfs/{connection.RemotePeer.Id}");
                var actual = Manager.Add(connection);
                if (actual == connection)
                {
                    ConnectionEstablished?.Invoke(this, connection);
                }
            }
            catch (Exception e)
            {
                log.Warn("Remote connect failed", e);
                try
                {
                    stream.Dispose();
                }
                catch (Exception)
                {
                    // eat it.
                }
            }
            finally
            {
                pendingRemoteConnections.TryRemove(remote, out object _);
            }
        }
Esempio n. 14
0
        /// <summary>
        ///   Establish a duplex stream between the local and remote peer.
        /// </summary>
        /// <param name="remote"></param>
        /// <param name="addrs"></param>
        /// <param name="cancel"></param>
        /// <returns></returns>
        async Task <PeerConnection> Dial(Peer remote, IEnumerable <MultiAddress> addrs, CancellationToken cancel)
        {
            log.Debug($"Dialing {remote}");

            if (remote == LocalPeer)
            {
                throw new Exception("Cannot dial self.");
            }

            // If no addresses, then ask peer routing.
            if (Router != null && addrs.Count() == 0)
            {
                var found = await Router.FindPeerAsync(remote.Id, cancel).ConfigureAwait(false);

                addrs            = found.Addresses;
                remote.Addresses = addrs;
            }

            // Get the addresses we can use to dial the remote.
            var possibleAddresses = (await Task.WhenAll(addrs.Select(a => a.ResolveAsync(cancel))).ConfigureAwait(false))
                                    .SelectMany(a => a)
                                    .Select(a => a.WithPeerId(remote.Id))
                                    .Distinct()
                                    .ToArray();

            // TODO: filter out self addresses and others.
            if (possibleAddresses.Length == 0)
            {
                throw new Exception($"{remote} has no known address.");
            }

            // Try the various addresses in parallel.  The first one to complete wins.
            PeerConnection connection = null;

            try
            {
                using (var timeout = new CancellationTokenSource(TransportConnectionTimeout))
                    using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, cancel))
                    {
                        var attempts = possibleAddresses
                                       .Select(a => DialAsync(remote, a, cts.Token));
                        connection = await TaskHelper.WhenAnyResult(attempts, cts.Token).ConfigureAwait(false);

                        cts.Cancel(); // stop other dialing tasks.
                    }
            }
            catch (Exception e)
            {
                var attemped = string.Join(", ", possibleAddresses.Select(a => a.ToString()));
                log.Trace($"Cannot dial {attemped}");
                throw new Exception($"Cannot dial {remote}.", e);
            }

            // Do the connection handshake.
            try
            {
                MountProtocols(connection);
                IEncryptionProtocol[] security = null;
                lock (protocols)
                {
                    security = protocols.OfType <IEncryptionProtocol>().ToArray();
                }
                await connection.InitiateAsync(security, cancel).ConfigureAwait(false);

                await connection.MuxerEstablished.Task.ConfigureAwait(false);

                Identify1 identify = null;
                lock (protocols)
                {
                    identify = protocols.OfType <Identify1>().First();
                }
                await identify.GetRemotePeer(connection, cancel).ConfigureAwait(false);
            }
            catch (Exception)
            {
                connection.Dispose();
                throw;
            }

            var actual = Manager.Add(connection);

            if (actual == connection)
            {
                ConnectionEstablished?.Invoke(this, connection);
            }

            return(actual);
        }
Esempio n. 15
0
 public Task <Stream> ProtectAsync(PeerConnection connection, CancellationToken cancel = default(CancellationToken))
 {
     Interlocked.Increment(ref Count);
     return(Task.FromResult(connection.Stream));
 }
Esempio n. 16
0
 /// <summary>
 ///   Is invoked by the <see cref="Swarm"/> when a peer is connected to.
 /// </summary>
 void Swarm_ConnectionEstablished(object sender, PeerConnection connection)
 {
     SetReachable(connection.RemotePeer);
 }