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).ConfigureAwait(false); if (cancel.IsCancellationRequested) { stream?.Dispose(); continue; } break; } } if (stream == null) { throw new Exception("Missing a known transport protocol name."); } // Build the connection. var connection = new PeerConnection { IsIncoming = false, LocalPeer = LocalPeer, // TODO: LocalAddress LocalPeerKey = LocalPeerKey, RemotePeer = remote, RemoteAddress = addr, Stream = stream }; // Are we communicating to a private network? if (NetworkProtector != null) { connection.Stream = await NetworkProtector.ProtectAsync(connection).ConfigureAwait(false); } return(connection); }
/// <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 _); } }