/// <summary> /// Discover attempts to find the external IP address of this peer. This is done by first trying to set /// UPNP with port forwarding (gives us the external address), query UPNP for the external address, and /// pinging a well-known peer. The fallback is NAT-PMP. /// </summary> /// <param name="peerAddress">The peer address. Since pings are used the peer ID can be Number160.Zero.</param> /// <param name="configuration"></param> /// <param name="tcsDiscover"></param> /// <returns>The future discover. This holds also the real ID of the peer we send the discover request.</returns> private TcsDiscover Discover(PeerAddress peerAddress, IConnectionConfiguration configuration, TcsDiscover tcsDiscover) { var taskCc = _peer.ConnectionBean.Reservation.CreateAsync(1, 2); Utils.Utils.AddReleaseListener(taskCc, TcsDiscover.Task); taskCc.ContinueWith(tcc => { if (!tcc.IsFaulted) { Discover(tcsDiscover, peerAddress, tcc.Result, configuration); } else { tcsDiscover.SetException(tcc.TryGetException()); } }); return(tcsDiscover); }
/// <summary> /// Needs 3 connections. Cleans up channel creator, which means they will be released. /// </summary> /// <param name="tcsDiscover"></param> /// <param name="peerAddress"></param> /// <param name="cc"></param> /// <param name="configuration"></param> private void Discover(TcsDiscover tcsDiscover, PeerAddress peerAddress, ChannelCreator cc, IConnectionConfiguration configuration) { _peer.PingRpc.AddPeerReachableListener(new DiscoverPeerReachableListener(tcsDiscover)); var taskResponseTcp = _peer.PingRpc.PingTcpDiscoverAsync(peerAddress, cc, configuration, SenderAddress); taskResponseTcp.ContinueWith(taskResponse => { var serverAddress = _peer.PeerBean.ServerPeerAddress; if (!taskResponse.IsFaulted) { var tmp = taskResponseTcp.Result.NeighborsSet(0).Neighbors; tcsDiscover.SetReporter(taskResponseTcp.Result.Sender); if (tmp.Count == 1) { var seenAs = tmp.First(); Logger.Info("This peer is seen as {0} by peer {1}. This peer sees itself as {2}.", seenAs, peerAddress, _peer.PeerAddress.InetAddress); if (!_peer.PeerAddress.InetAddress.Equals(seenAs.InetAddress)) { // check if we have this interface on that we can listen to var bindings = new Bindings().AddAddress(seenAs.InetAddress); var status = DiscoverNetworks.DiscoverInterfaces(bindings); Logger.Info("2nd interface discovery: {0}.", status); if (bindings.FoundAddresses.Count > 0 && bindings.FoundAddresses.Contains(seenAs.InetAddress)) { serverAddress = serverAddress.ChangeAddress(seenAs.InetAddress); _peer.PeerBean.SetServerPeerAddress(serverAddress); Logger.Info("This peer had the wrong interface. Changed it to {0}.", serverAddress); } else { // now we know our internal IP, where we receive packets var ports = _peer.ConnectionBean.ChannelServer.ChannelServerConfiguration.PortsForwarding; if (ports.IsManualPort) { serverAddress = serverAddress.ChangePorts(ports.TcpPort, ports.UdpPort); serverAddress = serverAddress.ChangeAddress(seenAs.InetAddress); _peer.PeerBean.SetServerPeerAddress(serverAddress); Logger.Info("This peer had manual ports. Changed it to {0}.", serverAddress); } else { // we need to find a relay, because there is a NAT in the way tcsDiscover.SetExternalHost( "We are most likely behind a NAT. Try to UPNP, NAT-PMP or relay " + peerAddress, taskResponseTcp.Result.Recipient.InetAddress, seenAs.InetAddress); return; } } } // else -> we announce exactly how the other peer sees us var taskResponse1 = _peer.PingRpc.PingTcpProbeAsync(peerAddress, cc, configuration); taskResponse1.ContinueWith(tr1 => { if (tr1.IsFaulted) { tcsDiscover.SetException(new TaskFailedException("TcsDiscover (2): We need at least the TCP connection.", tr1)); } }); var taskResponse2 = _peer.PingRpc.PingUdpProbeAsync(peerAddress, cc, configuration); taskResponse2.ContinueWith(tr2 => { if (tr2.IsFaulted) { Logger.Warn("TcsDiscover (2): UDP failed connection."); } }); // from here we probe, set the timeout here tcsDiscover.Timeout(serverAddress, _peer.ConnectionBean.Timer, DiscoverTimeoutSec); return; } tcsDiscover.SetException(new TaskFailedException(String.Format("Peer {0} did not report our IP address.", peerAddress))); } else { tcsDiscover.SetException(new TaskFailedException("TcsDiscover (1): We need at least the TCP connection.", taskResponse)); } }); }