/// <summary> /// Connect to a random node on the network /// </summary> /// <param name="network">The network to connect to</param> /// <param name="parameters">The parameters used by the found node, use AddressManagerBehavior.GetAddrman for finding peers</param> /// <param name="connectedAddresses">The already connected addresses, the new address will be select outside of existing groups</param> /// <returns></returns> public static Node Connect(NetworkInfo network, NodeConnectionParameters parameters = null, IPAddress[] connectedAddresses = null) { connectedAddresses = connectedAddresses ?? new IPAddress[0]; parameters = parameters ?? new NodeConnectionParameters(); var addrman = AddressManagerBehavior.GetAddrman(parameters) ?? new AddressManager(); DateTimeOffset start = DateTimeOffset.UtcNow; while (true) { parameters.ConnectCancellation.ThrowIfCancellationRequested(); if (addrman.Count == 0 || DateTimeOffset.UtcNow - start > TimeSpan.FromSeconds(10)) { addrman.DiscoverPeers(network, parameters); start = DateTimeOffset.UtcNow; } NetworkAddress addr = null; while (true) { addr = addrman.Select(); if (addr == null) { break; } if (!addr.Endpoint.Address.IsValid()) { continue; } var groupExist = connectedAddresses.Any(a => a.GetGroup().SequenceEqual(addr.Endpoint.Address.GetGroup())); if (groupExist) { continue; } break; } if (addr == null) { continue; } try { var timeout = new CancellationTokenSource(5000); var param2 = parameters.Clone(); param2.ConnectCancellation = CancellationTokenSource.CreateLinkedTokenSource(parameters.ConnectCancellation, timeout.Token).Token; var node = Node.Connect(network, addr.Endpoint, param2); return(node); } catch (OperationCanceledException ex) { if (ex.CancellationToken == parameters.ConnectCancellation) { throw; } } catch (SocketException) { parameters.ConnectCancellation.WaitHandle.WaitOne(500); } } }
internal void StartConnecting() { if (_Disconnect.IsCancellationRequested) { return; } if (_ConnectedNodes.Count >= MaximumNodeConnection) { return; } if (_Connecting) { return; } Task.Factory.StartNew(() => { if (Monitor.TryEnter(cs)) { _Connecting = true; try { while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection) { Logs.NodeServer.LogInformation("Connected nodes {connectedNodeCount} / {maximumNodeCount} ", _ConnectedNodes.Count, MaximumNodeConnection); var parameters = _ConnectionParameters.Clone(); parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this)); parameters.ConnectCancellation = _Disconnect.Token; var addrman = AddressManagerBehavior.GetAddrman(parameters); if (addrman == null) { addrman = _DefaultAddressManager; AddressManagerBehavior.SetAddrman(parameters, addrman); } Node node = null; try { var groupSelector = CustomGroupSelector != null ? CustomGroupSelector : AllowSameGroup ? WellKnownGroupSelectors.ByRandom : null; var connectedPeers = _ConnectedNodes.Where(n => n.Peer is { }).Select(n => n.Peer.Endpoint).ToArray(); node = Node.Connect(_Network, parameters, connectedPeers, groupSelector); using (var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token)) { timeout.CancelAfter(5000); node.VersionHandshake(_Requirements, timeout.Token); Logs.NodeServer.LogInformation("Node successfully connected to and handshaked"); } } catch (OperationCanceledException ex) { if (_Disconnect.Token.IsCancellationRequested) { break; } Logs.NodeServer.LogError(default, ex, "Timeout for picked node");
public NodesGroup( Network network, NodeConnectionParameters connectionParameters = null, NodeRequirement requirements = null) { AllowSameGroup = false; MaximumNodeConnection = 8; _Network = network; cs = new object(); _ConnectedNodes = new NodesCollection(); _ConnectionParameters = connectionParameters ?? new NodeConnectionParameters(); _ConnectionParameters = _ConnectionParameters.Clone(); _Requirements = requirements ?? new NodeRequirement(); _Disconnect = new CancellationTokenSource(); }
public NodesGroup( Network network, NodeConnectionParameters connectionParameters = null, NodeRequirement requirements = null) { AllowSameGroup = false; MaximumNodeConnection = 8; _Network = network; cs = new object(); _ConnectedNodes = new NodesCollection(); _ConnectionParameters = connectionParameters ?? new NodeConnectionParameters(); _ConnectionParameters = _ConnectionParameters.Clone(); _Requirements = requirements ?? new NodeRequirement(); _Disconnect = new CancellationTokenSource(); }
internal void DiscoverPeers(Network network, NodeConnectionParameters parameters) { int peerToFind = 1000; TraceCorrelation traceCorrelation = new TraceCorrelation(NodeServerTrace.Trace, "Discovering nodes"); int found = 0; using(traceCorrelation.Open()) { while(found < peerToFind) { parameters.ConnectCancellation.ThrowIfCancellationRequested(); NodeServerTrace.PeerTableRemainingPeerToGet(-found + peerToFind); List<NetworkAddress> peers = new List<NetworkAddress>(); peers.AddRange(this.GetAddr()); if(peers.Count == 0) { PopulateTableWithDNSNodes(network, peers); PopulateTableWithHardNodes(network, peers); peers = new List<NetworkAddress>(peers.OrderBy(a => RandomUtils.GetInt32())); } CancellationTokenSource peerTableFull = new CancellationTokenSource(); CancellationToken loopCancel = CancellationTokenSource.CreateLinkedTokenSource(peerTableFull.Token, parameters.ConnectCancellation).Token; try { Parallel.ForEach(peers, new ParallelOptions() { MaxDegreeOfParallelism = 5, CancellationToken = loopCancel, }, p => { CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); var cancelConnection = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, loopCancel); Node n = null; try { var param2 = parameters.Clone(); param2.ConnectCancellation = cancelConnection.Token; var addrman = param2.TemplateBehaviors.Find<AddressManagerBehavior>(); param2.TemplateBehaviors.Clear(); param2.TemplateBehaviors.Add(addrman); n = Node.Connect(network, p.Endpoint, param2); n.VersionHandshake(cancelConnection.Token); n.MessageReceived += (s, a) => { var addr = (a.Message.Payload as AddrPayload); if(addr != null) { Interlocked.Add(ref found, addr.Addresses.Length); if(found >= peerToFind) peerTableFull.Cancel(); } }; n.SendMessageAsync(new GetAddrPayload()); loopCancel.WaitHandle.WaitOne(2000); } catch { } finally { if(n != null) n.DisconnectAsync(); } if(found >= peerToFind) peerTableFull.Cancel(); else NodeServerTrace.Information("Need " + (-found + peerToFind) + " more peers"); }); } catch(OperationCanceledException) { if(parameters.ConnectCancellation.IsCancellationRequested) throw; } } } }
internal void StartConnecting() { if (_Disconnect.IsCancellationRequested) { return; } if (_ConnectedNodes.Count >= MaximumNodeConnection) { return; } if (_Connecting) { return; } Task.Factory.StartNew(() => { if (Monitor.TryEnter(cs)) { _Connecting = true; TraceCorrelationScope scope = null; try { while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection) { scope = scope ?? _Trace.Open(); NodeServerTrace.Information("Connected nodes : " + _ConnectedNodes.Count + "/" + MaximumNodeConnection); var parameters = _ConnectionParameters.Clone(); parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this)); parameters.ConnectCancellation = _Disconnect.Token; var addrman = AddressManagerBehavior.GetAddrman(parameters); if (addrman == null) { addrman = _DefaultAddressManager; AddressManagerBehavior.SetAddrman(parameters, addrman); } Node node = null; try { node = Node.Connect(_Network, parameters, AllowSameGroup ? null : _ConnectedNodes.Select(n => n.RemoteSocketAddress).ToArray()); var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token); timeout.CancelAfter(5000); node.VersionHandshake(_Requirements, timeout.Token); NodeServerTrace.Information("Node successfully connected to and handshaked"); } catch (OperationCanceledException ex) { if (_Disconnect.Token.IsCancellationRequested) { throw; } NodeServerTrace.Error("Timeout for picked node", ex); if (node != null) { node.DisconnectAsync("Handshake timeout", ex); } } catch (Exception ex) { NodeServerTrace.Error("Error while connecting to node", ex); if (node != null) { node.DisconnectAsync("Error while connecting", ex); } } } } finally { Monitor.Exit(cs); _Connecting = false; if (scope != null) { scope.Dispose(); } } } }, TaskCreationOptions.LongRunning); }
public void DiscoverPeers(Network network, NodeConnectionParameters parameters, int peerToFind) { TraceCorrelation traceCorrelation = new TraceCorrelation(NodeServerTrace.Trace, "Discovering nodes"); int found = 0; using (traceCorrelation.Open()) { while (found < peerToFind) { parameters.ConnectCancellation.ThrowIfCancellationRequested(); NodeServerTrace.PeerTableRemainingPeerToGet(-found + peerToFind); List <NetworkAddress> peers = new List <NetworkAddress>(); peers.AddRange(this.GetAddr()); if (peers.Count == 0) { PopulateTableWithDNSNodes(network, peers); PopulateTableWithHardNodes(network, peers); peers = new List <NetworkAddress>(peers.OrderBy(a => RandomUtils.GetInt32())); if (peers.Count == 0) { return; } } CancellationTokenSource peerTableFull = new CancellationTokenSource(); CancellationToken loopCancel = CancellationTokenSource.CreateLinkedTokenSource(peerTableFull.Token, parameters.ConnectCancellation).Token; try { Parallel.ForEach(peers, new ParallelOptions() { MaxDegreeOfParallelism = 5, CancellationToken = loopCancel, }, p => { CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); var cancelConnection = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, loopCancel); Node n = null; try { var param2 = parameters.Clone(); param2.ConnectCancellation = cancelConnection.Token; var addrman = param2.TemplateBehaviors.Find <AddressManagerBehavior>(); param2.TemplateBehaviors.Clear(); param2.TemplateBehaviors.Add(addrman); n = Node.Connect(network, p.Endpoint, param2); n.VersionHandshake(cancelConnection.Token); n.MessageReceived += (s, a) => { var addr = (a.Message.Payload as AddrPayload); if (addr != null) { Interlocked.Add(ref found, addr.Addresses.Length); if (found >= peerToFind) { peerTableFull.Cancel(); } } }; n.SendMessageAsync(new GetAddrPayload()); loopCancel.WaitHandle.WaitOne(2000); } catch { } finally { if (n != null) { n.DisconnectAsync(); } } if (found >= peerToFind) { peerTableFull.Cancel(); } else { NodeServerTrace.Information("Need " + (-found + peerToFind) + " more peers"); } }); } catch (OperationCanceledException) { if (parameters.ConnectCancellation.IsCancellationRequested) { throw; } } } } }
internal void DiscoverPeers(Network network, NodeConnectionParameters parameters, int peerToFind) { TimeSpan backoff = TimeSpan.Zero; Logs.NodeServer.LogTrace("Discovering nodes"); int found = 0; { while (found < peerToFind) { Thread.Sleep(backoff); backoff = backoff == TimeSpan.Zero ? TimeSpan.FromSeconds(1.0) : TimeSpan.FromSeconds(backoff.TotalSeconds * 2); if (backoff > TimeSpan.FromSeconds(10.0)) { backoff = TimeSpan.FromSeconds(10.0); } parameters.ConnectCancellation.ThrowIfCancellationRequested(); Logs.NodeServer.LogTrace("Remaining peer to get {remainingPeerCount}", (-found + peerToFind)); List <NetworkAddress> peers = new List <NetworkAddress>(); peers.AddRange(this.GetAddr()); if (peers.Count == 0) { PopulateTableWithDNSNodes(network, peers).GetAwaiter().GetResult(); PopulateTableWithHardNodes(network, peers); peers = new List <NetworkAddress>(peers.OrderBy(a => RandomUtils.GetInt32())); if (peers.Count == 0) { return; } } CancellationTokenSource peerTableFull = new CancellationTokenSource(); CancellationToken loopCancel = CancellationTokenSource.CreateLinkedTokenSource(peerTableFull.Token, parameters.ConnectCancellation).Token; try { Parallel.ForEach(peers, new ParallelOptions() { MaxDegreeOfParallelism = 5, CancellationToken = loopCancel, }, p => { using (CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5))) using (var cancelConnection = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, loopCancel)) { Node n = null; try { var param2 = parameters.Clone(); param2.ConnectCancellation = cancelConnection.Token; var addrman = param2.TemplateBehaviors.Find <AddressManagerBehavior>(); param2.TemplateBehaviors.Clear(); param2.TemplateBehaviors.Add(addrman); n = Node.Connect(network, p.Endpoint, param2); n.VersionHandshake(cancelConnection.Token); n.MessageReceived += (s, a) => { var addr = (a.Message.Payload as AddrPayload); if (addr != null) { Interlocked.Add(ref found, addr.Addresses.Length); backoff = TimeSpan.FromSeconds(0); if (found >= peerToFind) { peerTableFull.Cancel(); } } }; n.SendMessageAsync(new GetAddrPayload()); loopCancel.WaitHandle.WaitOne(2000); } catch { } finally { if (n != null) { n.DisconnectAsync(); } } } if (found >= peerToFind) { peerTableFull.Cancel(); } else { Logs.NodeServer.LogInformation("Need {neededPeerCount} more peers", (-found + peerToFind)); } }); } catch (OperationCanceledException) { if (parameters.ConnectCancellation.IsCancellationRequested) { throw; } } } } }