public void Disposing() { var closeCount = 0; var stream = new MemoryStream(); var connection = new PeerConnection { Stream = stream }; connection.Closed += (s, e) => { ++closeCount; }; Assert.IsTrue(connection.IsActive); Assert.IsNotNull(connection.Stream); connection.Dispose(); Assert.IsFalse(connection.IsActive); Assert.IsNull(connection.Stream); // Can be disposed multiple times. connection.Dispose(); Assert.IsFalse(connection.IsActive); Assert.AreEqual(1, closeCount); }
/// <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; } return(true); }
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); }
/// <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); }