/// <summary> /// Discover peers using TCP port scan /// </summary> /// <param name="discoverTimeMS"></param> /// <returns></returns> private static Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> DiscoverPeersTCP(int discoverTimeMS) { #region Determine All Possible Peers/Port Combinations //Get a list of all IPEndPoint that we should try and connect to //This requires the network and peer portion of current IP addresses List<IPEndPoint> allIPEndPointsToConnect = new List<IPEndPoint>(); //Look at all possible addresses foreach (var iFace in NetworkInterface.GetAllNetworkInterfaces()) { bool interfaceValid = false; var unicastAddresses = iFace.GetIPProperties().UnicastAddresses; //Check if this adaptor is allowed if (HostInfo.RestrictLocalAdaptorNames != null) { foreach (var currentName in HostInfo.RestrictLocalAdaptorNames) { if (iFace.Name == currentName) { interfaceValid = true; break; } } } else interfaceValid = true; //If the interface is not allowed move to the next adaptor if (!interfaceValid) continue; //If the adaptor is allowed we can now investigate the individual addresses foreach (var address in unicastAddresses) { //We are only interested in IPV4 ranges. A TCPPortScan on an IPV6 range may take a while if (address.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPRange.IsAutoAssignedAddress(address.Address)) { //Check if we have restricted the addresses bool addressAllowed = true; if (HostInfo.IP.RestrictLocalAddressRanges != null) addressAllowed = IPRange.Contains(HostInfo.IP.RestrictLocalAddressRanges, address.Address); if (addressAllowed) { //Generate all possible IPEndPoints for the current address and subnetmask //We have a special catch for the loopback address which has a very large range List<IPAddress> addressesInRange; if (address.Address.Equals(IPAddress.Loopback)) addressesInRange = new List<IPAddress>() { IPAddress.Loopback }; else { IPRange range = new IPRange(address.Address, address.IPv4Mask); addressesInRange = range.AllAddressesInRange(); } foreach (IPAddress currentAddressInRange in addressesInRange) { for (int port = MinTargetLocalIPPort; port <= MaxTargetLocalIPPort; port++) allIPEndPointsToConnect.Add(new IPEndPoint(currentAddressInRange, port)); } } } } } #endregion #region Send Discovery Packet & Wait //For each address send the discovery packet SendReceiveOptions nullOptions = new SendReceiveOptions<NullSerializer>(); StreamTools.StreamSendWrapper sendStream = new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(new MemoryStream(new byte[0]))); int previousConnectionTimeout = NetworkComms.ConnectionEstablishTimeoutMS; NetworkComms.ConnectionEstablishTimeoutMS = 1000; AutoResetEvent allSendsCompleteEvent = new AutoResetEvent(false); long interlockedCompletedCount = 0; object _syncRoot = new object(); List<Connection> allConnections = new List<Connection>(); //Get unconnected TCP connections foreach (IPEndPoint remoteEndPoint in allIPEndPointsToConnect) { Connection conn = TCPConnection.GetConnection(new ConnectionInfo(remoteEndPoint), false); conn.AppendIncomingPacketHandler<byte[]>(discoveryPacketType, PeerDiscoveryHandler); allConnections.Add(conn); } using (Packet sendPacket = new Packet(discoveryPacketType, sendStream, nullOptions)) { foreach (Connection conn in allConnections) { Connection innerConnection = conn; //The longest wait for the port scan is the TCP connect timeout //The thread pool will start a large number of threads (each of which does very little) // to greatly speed this up _tcpPortScanThreadPool.EnqueueItem(QueueItemPriority.Normal, (state) => { try { try { innerConnection.EstablishConnection(); innerConnection.SendPacket<byte[]>(sendPacket); } catch (CommsException) { } lock (_syncRoot) { interlockedCompletedCount++; if (interlockedCompletedCount == allIPEndPointsToConnect.Count) allSendsCompleteEvent.Set(); } } catch (Exception) { } }, null); } allSendsCompleteEvent.WaitOne(); } NetworkComms.ConnectionEstablishTimeoutMS = previousConnectionTimeout; sendStream.ThreadSafeStream.Dispose(true); AutoResetEvent sleep = new AutoResetEvent(false); //We wait at least 1 second so that connected peers can respond //If we do not wait and close all connections immediately we may miss some replies #if NET2 sleep.WaitOne(Math.Max(discoverTimeMS, 500), false); #else sleep.WaitOne(Math.Max(discoverTimeMS, 500)); #endif //Close any connections we may have established foreach (Connection conn in allConnections) { try { conn.CloseConnection(false); } catch (CommsException) { } } #endregion #region Return Discovered Peers Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> result = new Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>>(); lock (_syncRoot) { foreach (var idPair in _discoveredPeers) { if (!result.ContainsKey(idPair.Key)) result.Add(idPair.Key, new Dictionary<ConnectionType, List<EndPoint>>()); foreach (var typePair in idPair.Value) { if (!result[idPair.Key].ContainsKey(typePair.Key)) result[idPair.Key].Add(typePair.Key, new List<EndPoint>()); foreach (var endPoint in typePair.Value) if (!result[idPair.Key][typePair.Key].Contains(endPoint.Key)) result[idPair.Key][typePair.Key].Add(endPoint.Key); } } } return result; #endregion }
/// <summary> /// Discover peers using UDP broadcast /// </summary> /// <param name="discoverTimeMS"></param> /// <returns></returns> private static Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> DiscoverPeersUDP(int discoverTimeMS) { SendReceiveOptions nullOptions = new SendReceiveOptions<NullSerializer>(); StreamTools.StreamSendWrapper sendStream = new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(new MemoryStream(new byte[0]))); using (Packet sendPacket = new Packet(discoveryPacketType, sendStream, nullOptions)) { for (int port = MinTargetLocalIPPort; port <= MaxTargetLocalIPPort; port++) UDPConnection.SendObject<byte[]>(sendPacket, new IPEndPoint(IPAddress.Broadcast, port), nullOptions, ApplicationLayerProtocolStatus.Enabled); } sendStream.ThreadSafeStream.Dispose(true); AutoResetEvent sleep = new AutoResetEvent(false); #if NET2 sleep.WaitOne(discoverTimeMS, false); #else sleep.WaitOne(discoverTimeMS); #endif Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> result = new Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>>(); lock (_syncRoot) { foreach (var idPair in _discoveredPeers) { if(!result.ContainsKey(idPair.Key)) result.Add(idPair.Key, new Dictionary<ConnectionType,List<EndPoint>>()); foreach(var typePair in idPair.Value) { if(!result[idPair.Key].ContainsKey(typePair.Key)) result[idPair.Key].Add(typePair.Key, new List<EndPoint>()); foreach(var endPoint in typePair.Value) if(!result[idPair.Key][typePair.Key].Contains(endPoint.Key)) result[idPair.Key][typePair.Key].Add(endPoint.Key); } } } return result; }