/// <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); } }
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(); }); }
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(); }); }
/// <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 _); } }
/// <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); }