Beispiel #1
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.
        /// </remarks>
        async void OnRemoteConnect(Stream stream, MultiAddress local, MultiAddress remote)
        {
            log.Debug("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
            };

            // 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;
            // 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));

            connection.RemotePeer    = RegisterPeer(connection.RemotePeer);
            connection.RemoteAddress = new MultiAddress($"{remote}/ipfs/{connection.RemotePeer.Id}");
            connection.RemotePeer.ConnectedAddress = connection.RemoteAddress;

            var actual = Manager.Add(connection);

            if (actual == connection)
            {
                ConnectionEstablished?.Invoke(this, connection);
            }
        }
Beispiel #2
0
        public async Task InvalidPublicKey()
        {
            var peerA = new Peer
            {
                Addresses = new MultiAddress[]
                {
                    "/ip4/127.0.0.1/tcp/4002/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb"
                },
                AgentVersion    = "agent/1",
                Id              = "QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb",
                ProtocolVersion = "protocol/1",
                PublicKey       =
                    "BADSpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfBYU9c0n28u02N/XCJY8yIsRqRVO5Zw+6kDHCremt2flHT4AaWnwGLAG9YyQJbRTvWN9nW2LK7Pv3uoIlvUSTnZEP0SXB5oZeqtxUdi6tuvcyqTIfsUSanLQucYITq8Qw3IMBzk+KpWNm98g9A/Xy30MkUS8mrBIO9pHmIZa55fvclDkTvLxjnGWA2avaBfJvHgMSTu0D2CQcmJrvwyKMhLCSIbQewZd2V7vc6gtxbRovKlrIwDTmDBXbfjbLljOuzg2yBLyYxXlozO9blpttbnOpU4kTspUVJXglmjsv7YSIJS3UKt3544l/srHbqlwC5CgOgjlwNfYPadO8kmBfAgMBAAE="
            };
            var peerB = new Peer
            {
                Id = peerA.Id
            };
            var ms         = new MemoryStream();
            var connection = new PeerConnection
            {
                LocalPeer  = peerA,
                RemotePeer = peerB,
                Stream     = ms
            };

            // Generate identify msg.
            var identify = new Identify1();
            await identify.ProcessMessageAsync(connection, ms);

            // Process identify msg.
            ms.Position = 0;
            ExceptionAssert.Throws <InvalidDataException>(() =>
            {
                identify.UpdateRemotePeerAsync(peerB, ms, CancellationToken.None).Wait();
            });
        }
Beispiel #3
0
        public async Task MustHavePublicKey()
        {
            var peerA = new Peer
            {
                Addresses = new MultiAddress[]
                {
                    "/ip4/127.0.0.1/tcp/4002/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb"
                },
                AgentVersion    = "agent/1",
                Id              = "QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb",
                ProtocolVersion = "protocol/1",
                PublicKey       = ""
            };
            var peerB = new Peer
            {
                Id = peerA.Id
            };
            var ms         = new MemoryStream();
            var connection = new PeerConnection
            {
                LocalPeer  = peerA,
                RemotePeer = peerB,
                Stream     = ms
            };

            // Generate identify msg.
            var identify = new Identify1();
            await identify.ProcessMessageAsync(connection, ms);

            // Process identify msg.
            ms.Position = 0;
            ExceptionAssert.Throws <InvalidDataException>(() =>
            {
                identify.UpdateRemotePeerAsync(peerB, ms, CancellationToken.None).Wait();
            });
        }
Beispiel #4
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 _);
            }
        }
Beispiel #5
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);
        }