public void Listen() { if (socket != null) { throw new InvalidOperationException("Already listening"); } using (_Trace.Open()) { try { socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); #if !NOIPDUALMODE socket.DualMode = true; #endif socket.Bind(LocalEndpoint); socket.Listen(8); NodeServerTrace.Information("Listening..."); BeginAccept(); } catch (Exception ex) { NodeServerTrace.Error("Error while opening the Protocol server", ex); throw; } } }
public void Listen() { if (socket != null) { throw new InvalidOperationException("Already listening"); } using (_Trace.Open()) { try { socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); socket.Bind(LocalEndpoint); socket.Listen(8); NodeServerTrace.Information("Listening..."); BeginAccept(); } catch (Exception ex) { NodeServerTrace.Error("Error while opening the Protocol server", ex); throw; } } }
public void DisconnectAsync(string reason, Exception exception = null) { if (!IsConnected) { return; } if (Interlocked.CompareExchange(ref _Disconnecting, 1, 0) == 1) { return; } using (TraceCorrelation.Open()) { NodeServerTrace.Information("Disconnection request " + reason); State = NodeState.Disconnecting; _Connection.Cancel.Cancel(); if (DisconnectReason == null) { DisconnectReason = new NodeDisconnectReason() { Reason = reason, Exception = exception } } ; } }
public void VersionHandshake(CancellationToken cancellationToken = default(CancellationToken)) { using (var listener = CreateListener() .Where(p => p.Message.Payload is VersionPayload || p.Message.Payload is RejectPayload || p.Message.Payload is VerAckPayload)) { using (TraceCorrelation.Open()) { SendMessage(MyVersion); var payload = listener.ReceivePayload <Payload>(cancellationToken); if (payload is RejectPayload) { throw new InvalidOperationException("Handshake rejected : " + ((RejectPayload)payload).Reason); } var version = (VersionPayload)payload; _PeerVersion = version; Version = version.Version; if (!version.AddressReceiver.Address.Equals(MyVersion.AddressFrom.Address)) { NodeServerTrace.Warning("Different external address detected by the node " + version.AddressReceiver.Address + " instead of " + MyVersion.AddressFrom.Address); } if (version.Version < ProtocolVersion.MIN_PEER_PROTO_VERSION) { NodeServerTrace.Warning("Outdated version " + version.Version + " disconnecting"); Disconnect(); return; } SendMessage(new VerAckPayload()); listener.ReceivePayload <VerAckPayload>(cancellationToken); State = NodeState.HandShaked; } } }
public Chain BuildChain(Chain chain, CancellationToken cancellationToken = default(CancellationToken)) { AssertState(NodeState.HandShaked, cancellationToken); using (TraceCorrelation.Open()) { NodeServerTrace.Information("Building chain"); if (FullVersion.StartHeight <= chain.Height) { NodeServerTrace.Information("Local chain already ahead"); return(chain); } while (chain.Height < FullVersion.StartHeight) { NodeServerTrace.Information("Chain progress : " + chain.Height + "/" + FullVersion.StartHeight); SendMessage(new GetHeadersPayload() { BlockLocators = chain.Tip.GetLocator() }); var headers = this.RecieveMessage <HeadersPayload>(cancellationToken); foreach (var header in headers.Headers) { var prev = chain.GetBlock(header.HashPrevBlock); if (prev == null || prev.Height != chain.Height) { NodeServerTrace.Error("Block Header received out of order " + header.GetHash(), null); throw new InvalidOperationException("Block Header received out of order"); } var chained = chain.CreateChainedBlock(header); chain.SetTip(chained); } } } return(chain); }
public void Listen() { if (socket != null) { throw new InvalidOperationException("Already listening"); } using (_Trace.Open()) { try { socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Bind(LocalEndpoint); socket.Listen(8); NodeServerTrace.Information("Listening..."); BeginAccept(); } catch (Exception ex) { NodeServerTrace.Error("Error while opening the Protocol server", ex); throw; } } }
public void BeginListen() { new Thread(() => { using (TraceCorrelation.Open(false)) { NodeServerTrace.Information("Listening"); _PingListener = new EventLoopMessageListener <IncomingMessage>(MessageReceived); Node.MessageProducer.AddMessageListener(_PingListener); try { while (!Cancel.Token.IsCancellationRequested) { PerformanceCounter counter; var message = Message.ReadNext(Socket, Node.Network, Node.Version, Cancel.Token, out counter); Node.LastSeen = DateTimeOffset.UtcNow; Node.MessageProducer.PushMessage(new IncomingMessage() { Message = message, Socket = Socket, Node = Node }); Node.Counter.Add(counter); } } catch (OperationCanceledException) { } catch (Exception ex) { if (Node.State != NodeState.Disconnecting) { Node.State = NodeState.Failed; NodeServerTrace.Error("Connection to server stopped unexpectedly", ex); } } NodeServerTrace.Information("Stop listening"); if (Node.State != NodeState.Failed) { Node.State = NodeState.Offline; } Dispose(); _Cancel.Cancel(); _Disconnected.Set(); } }).Start(); }
public void RespondToHandShake(CancellationToken cancellation = default(CancellationToken)) { using (TraceCorrelation.Open()) { var listener = new PollMessageListener <IncomingMessage>(); using (MessageProducer.AddMessageListener(listener)) { NodeServerTrace.Information("Responding to handshake"); SendMessage(MyVersion); listener.ReceiveMessage().AssertPayload <VerAckPayload>(); SendMessage(new VerAckPayload()); _State = NodeState.HandShaked; } } }
public void Disconnect() { if (State < NodeState.Connected) { _Connection.Disconnected.WaitOne(); return; } using (TraceCorrelation.Open()) { NodeServerTrace.Information("Disconnection request"); State = NodeState.Disconnecting; _Connection.Cancel.Cancel(); _Connection.Disconnected.WaitOne(); } }
public Chain BuildChain(ObjectStream <ChainChange> changes = null, CancellationToken cancellationToken = default(CancellationToken)) { if (changes == null) { changes = new StreamObjectStream <ChainChange>(); } var chain = new Chain(Network, changes); TraceCorrelation trace = new TraceCorrelation(NodeServerTrace.Trace, "Build chain"); using (trace.Open()) { using (var pool = CreateNodeSet(3)) { int height = pool.GetNodes().Max(o => o.FullVersion.StartHeight); var listener = new PollMessageListener <IncomingMessage>(); pool.SendMessage(new GetHeadersPayload() { BlockLocators = chain.Tip.GetLocator() }); using (pool.MessageProducer.AddMessageListener(listener)) { while (chain.Height != height) { var before = chain.Tip; var headers = listener.RecieveMessage(cancellationToken).Message.Payload as HeadersPayload; if (headers != null) { foreach (var header in headers.Headers) { chain.GetOrAdd(header); } if (before.HashBlock != chain.Tip.HashBlock) { NodeServerTrace.Information("Chain progress : " + chain.Height + "/" + height); pool.SendMessage(new GetHeadersPayload() { BlockLocators = chain.Tip.GetLocator() }); } } } } } } return(chain); }
public IEnumerable <Block> GetBlocks(IEnumerable <uint256> neededBlocks, CancellationToken cancellationToken = default(CancellationToken)) { AssertState(NodeState.HandShaked, cancellationToken); using (TraceCorrelation.Open()) { NodeServerTrace.Information("Downloading blocks"); int simultaneous = 70; PerformanceSnapshot lastSpeed = null; using (var listener = CreateListener() .OfType <BlockPayload>()) { foreach (var invs in neededBlocks .Select(b => new InventoryVector() { Type = InventoryType.MSG_BLOCK, Hash = b }) .Partition(simultaneous)) { NodeServerTrace.Information("Speed " + lastSpeed); var begin = Counter.Snapshot(); var invsByHash = invs.ToDictionary(k => k.Hash); this.SendMessage(new GetDataPayload(invs.ToArray())); Block[] downloadedBlocks = new Block[invs.Count]; while (invsByHash.Count != 0) { var block = listener.ReceivePayload <BlockPayload>(cancellationToken).Object; var thisHash = block.GetHash(); if (invsByHash.ContainsKey(thisHash)) { downloadedBlocks[invs.IndexOf(invsByHash[thisHash])] = block; invsByHash.Remove(thisHash); } } var end = Counter.Snapshot(); lastSpeed = end - begin; foreach (var downloadedBlock in downloadedBlocks) { yield return(downloadedBlock); } } } } }
private void ProcessMessage(IncomingMessage message) { this.AllMessages.PushMessage(message); TraceCorrelation trace = null; if (message.NetworkPeer != null) { trace = message.NetworkPeer.TraceCorrelation; } else { trace = new TraceCorrelation(NodeServerTrace.Trace, "Processing inbound message " + message.Message); } using (trace.Open(false)) { this.ProcessMessageCore(message); } }
/// <summary> /// /// </summary> /// <param name="cancellation"></param> public void RespondToHandShake(CancellationToken cancellation = default(CancellationToken)) { using (TraceCorrelation.Open()) { using (var list = CreateListener().Where(m => m.IsPayloadTypeOf(typeof(VerAckPayload), typeof(RejectPayload)))) { NodeServerTrace.Information("Responding to handshake"); SendMessageAsync(MyVersion); var message = list.ReceiveMessage(cancellation); message.IfPayloadIs <RejectPayload>(reject => { throw new ProtocolException("Version rejected " + reject.Code + " : " + reject.Reason); }); SendMessageAsync(new VerAckPayload()); State = NodeState.HandShaked; } } }
internal Node(Peer peer, Network network, VersionPayload myVersion, CancellationToken cancellation) { _MyVersion = myVersion; Version = _MyVersion.Version; Network = network; _Peer = peer; LastSeen = peer.NetworkAddress.Time; var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); #if !NOIPDUALMODE socket.DualMode = true; #endif _Connection = new NodeConnection(this, socket); using (TraceCorrelation.Open()) { try { var ar = socket.BeginConnect(Peer.NetworkAddress.Endpoint, null, null); WaitHandle.WaitAny(new WaitHandle[] { ar.AsyncWaitHandle, cancellation.WaitHandle }); cancellation.ThrowIfCancellationRequested(); socket.EndConnect(ar); State = NodeState.Connected; NodeServerTrace.Information("Outbound connection successfull"); } catch (OperationCanceledException) { Utils.SafeCloseSocket(socket); NodeServerTrace.Information("Connection to node cancelled"); State = NodeState.Offline; return; } catch (Exception ex) { Utils.SafeCloseSocket(socket); NodeServerTrace.Error("Error connecting to the remote endpoint ", ex); State = NodeState.Failed; throw; } _Connection.BeginListen(); } }
public void VersionHandshake(CancellationToken cancellationToken = default(CancellationToken)) { var listener = new PollMessageListener <IncomingMessage>(); using (MessageProducer.AddMessageListener(listener)) { using (TraceCorrelation.Open()) { var myVersion = CreateVersionPayload(); SendMessage(myVersion); var version = listener.RecieveMessage(cancellationToken).AssertPayload <VersionPayload>(); _FullVersion = version; Version = version.Version; if (version.Nonce == NodeServer.Nonce) { NodeServerTrace.ConnectionToSelfDetected(); Disconnect(); throw new InvalidOperationException("Impossible to connect to self"); } if (!version.AddressReciever.Address.Equals(ExternalEndpoint.Address)) { NodeServerTrace.Warning("Different external address detected by the node " + version.AddressReciever.Address + " instead of " + ExternalEndpoint.Address); } NodeServer.ExternalAddressDetected(version.AddressReciever.Address); if (version.Version < ProtocolVersion.MIN_PEER_PROTO_VERSION) { NodeServerTrace.Warning("Outdated version " + version.Version + " disconnecting"); Disconnect(); return; } SendMessage(new VerAckPayload()); listener.RecieveMessage(cancellationToken).AssertPayload <VerAckPayload>(); State = NodeState.HandShaked; if (NodeServer.AdvertizeMyself) { AdvertiseMyself(); } } } }
public IEnumerable <ChainedBlock> GetHeadersFromFork(ChainedBlock currentTip, uint256 hashStop = null, CancellationToken cancellationToken = default(CancellationToken)) { AssertState(NodeState.HandShaked, cancellationToken); using (TraceCorrelation.Open()) { NodeServerTrace.Information("Building chain"); using (var listener = this.CreateListener().OfType <HeadersPayload>()) { while (true) { SendMessage(new GetHeadersPayload() { BlockLocators = currentTip.GetLocator(), HashStop = hashStop }); var headers = listener.ReceivePayload <HeadersPayload>(cancellationToken); if (headers.Headers.Count == 0) { break; } foreach (var header in headers.Headers) { var prev = currentTip.FindAncestorOrSelf(header.HashPrevBlock); if (prev == null) { NodeServerTrace.Error("Block Header received out of order " + header.GetHash(), null); throw new InvalidOperationException("Block Header received out of order"); } currentTip = new ChainedBlock(header, header.GetHash(), prev); yield return(currentTip); } if (currentTip.HashBlock == hashStop) { break; } } } } }
internal Node(NetworkAddress peer, NetworkInfo network, NodeConnectionParameters parameters) { parameters = parameters ?? new NodeConnectionParameters(); var addrman = AddressManagerBehavior.GetAddrman(parameters); Inbound = false; _Behaviors = new NodeBehaviorsCollection(this); _MyVersion = parameters.CreateVersion(peer.Endpoint, network); Network = network; _Peer = peer; LastSeen = peer.Time; var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); _Connection = new NodeConnection(this, socket); socket.ReceiveBufferSize = parameters.ReceiveBufferSize; socket.SendBufferSize = parameters.SendBufferSize; using (TraceCorrelation.Open()) { try { var completed = new ManualResetEvent(false); var args = new SocketAsyncEventArgs(); args.RemoteEndPoint = peer.Endpoint; args.Completed += (s, a) => { Utils.SafeSet(completed); }; if (!socket.ConnectAsync(args)) { completed.Set(); } WaitHandle.WaitAny(new WaitHandle[] { completed, parameters.ConnectCancellation.WaitHandle }); parameters.ConnectCancellation.ThrowIfCancellationRequested(); if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } var remoteEndpoint = (IPEndPoint)(socket.RemoteEndPoint ?? args.RemoteEndPoint); _RemoteSocketAddress = remoteEndpoint.Address; _RemoteSocketPort = remoteEndpoint.Port; State = NodeState.Connected; ConnectedAt = DateTimeOffset.UtcNow; NodeServerTrace.Information("Outbound connection successfull"); if (addrman != null) { addrman.Attempt(Peer); } } catch (OperationCanceledException) { Utils.SafeCloseSocket(socket); NodeServerTrace.Information("Connection to node cancelled"); State = NodeState.Offline; if (addrman != null) { addrman.Attempt(Peer); } throw; } catch (Exception ex) { Utils.SafeCloseSocket(socket); NodeServerTrace.Error("Error connecting to the remote endpoint ", ex); DisconnectReason = new NodeDisconnectReason() { Reason = "Unexpected exception while connecting to socket", Exception = ex }; State = NodeState.Failed; if (addrman != null) { addrman.Attempt(Peer); } throw; } InitDefaultBehaviors(parameters); _Connection.BeginListen(); } }
public Chain BuildChain(ObjectStream<ChainChange> changes = null, CancellationToken cancellationToken = default(CancellationToken)) { if(changes == null) changes = new StreamObjectStream<ChainChange>(); var chain = new Chain(Network, changes); TraceCorrelation trace = new TraceCorrelation(NodeServerTrace.Trace, "Build chain"); using(trace.Open()) { using(var pool = CreateNodeSet(3)) { int height = pool.GetNodes().Max(o => o.FullVersion.StartHeight); var listener = new PollMessageListener<IncomingMessage>(); pool.SendMessage(new GetHeadersPayload() { BlockLocators = chain.Tip.GetLocator() }); using(pool.MessageProducer.AddMessageListener(listener)) { while(chain.Height != height) { var before = chain.Tip; var headers = listener.RecieveMessage(cancellationToken).Message.Payload as HeadersPayload; if(headers != null) { foreach(var header in headers.Headers) { chain.GetOrAdd(header); } if(before.HashBlock != chain.Tip.HashBlock) { NodeServerTrace.Information("Chain progress : " + chain.Height + "/" + height); pool.SendMessage(new GetHeadersPayload() { BlockLocators = chain.Tip.GetLocator() }); } } } } } } return chain; }
internal void DiscoverPeers(Network network, NodeConnectionParameters parameters, int peerToFind) { var traceCorrelation = new TraceCorrelation(NodeServerTrace.Trace, "Discovering nodes"); var found = 0; using (traceCorrelation.Open()) { while (found < peerToFind) { parameters.ConnectCancellation.ThrowIfCancellationRequested(); NodeServerTrace.PeerTableRemainingPeerToGet(-found + peerToFind); var peers = new List <NetworkAddress>(); peers.AddRange(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; } } var peerTableFull = new CancellationTokenSource(); var loopCancel = CancellationTokenSource .CreateLinkedTokenSource(peerTableFull.Token, parameters.ConnectCancellation).Token; try { Parallel.ForEach(peers, new ParallelOptions { MaxDegreeOfParallelism = 5, CancellationToken = loopCancel }, p => { var 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; } } } } }
/// <summary> /// Fill the PeerTable with fresh addresses /// </summary> public void DiscoverPeers(int peerToFind = 990) { TraceCorrelation traceCorrelation = new TraceCorrelation(NodeServerTrace.Trace, "Discovering nodes"); List <Task> tasks = new List <Task>(); using (traceCorrelation.Open()) { while (CountPeerRequired(peerToFind) != 0) { NodeServerTrace.PeerTableRemainingPeerToGet(CountPeerRequired(peerToFind)); CancellationTokenSource cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(40)); var peers = PeerTable.GetActivePeers(1000); if (peers.Length == 0) { PopulateTableWithDNSNodes(); PopulateTableWithHardNodes(); peers = PeerTable.GetActivePeers(1000); } CancellationTokenSource peerTableFull = new CancellationTokenSource(); NodeSet connected = new NodeSet(); try { Parallel.ForEach(peers, new ParallelOptions() { MaxDegreeOfParallelism = 5, CancellationToken = peerTableFull.Token, }, p => { Node n = null; try { n = GetNodeByPeer(p, cancellation.Token); if (n.State < NodeState.HandShaked) { connected.AddNode(n); n.VersionHandshake(cancellation.Token); } n.SendMessage(new GetAddrPayload()); Thread.Sleep(2000); } catch (Exception) { if (n != null) { n.Disconnect(); } } if (CountPeerRequired(peerToFind) == 0) { peerTableFull.Cancel(); } else { NodeServerTrace.Information("Need " + CountPeerRequired(peerToFind) + " more peers"); } }); } catch (OperationCanceledException) { } finally { connected.DisconnectAll(); } } NodeServerTrace.Trace.TraceInformation("Peer table is now full"); } }
/// <summary> /// Fill the PeerTable with fresh addresses /// </summary> public void DiscoverPeers(int peerToFind = 990) { TraceCorrelation traceCorrelation = new TraceCorrelation(NodeServerTrace.Trace, "Discovering nodes"); List<Task> tasks = new List<Task>(); using(traceCorrelation.Open()) { while(CountPeerRequired(peerToFind) != 0) { NodeServerTrace.PeerTableRemainingPeerToGet(CountPeerRequired(peerToFind)); CancellationTokenSource cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(40)); var peers = PeerTable.GetActivePeers(1000); if(peers.Length == 0) { PopulateTableWithDNSNodes(); PopulateTableWithHardNodes(); peers = PeerTable.GetActivePeers(1000); } CancellationTokenSource peerTableFull = new CancellationTokenSource(); NodeSet connected = new NodeSet(); try { Parallel.ForEach(peers, new ParallelOptions() { MaxDegreeOfParallelism = 5, CancellationToken = peerTableFull.Token, }, p => { Node n = null; try { n = GetNodeByPeer(p, cancellation.Token); if(n.State < NodeState.HandShaked) { connected.AddNode(n); n.VersionHandshake(cancellation.Token); } n.SendMessage(new GetAddrPayload()); Thread.Sleep(2000); } catch(Exception) { if(n != null) n.Disconnect(); } if(CountPeerRequired(peerToFind) == 0) peerTableFull.Cancel(); else NodeServerTrace.Information("Need " + CountPeerRequired(peerToFind) + " more peers"); }); } catch(OperationCanceledException) { } finally { connected.DisconnectAll(); } } NodeServerTrace.Trace.TraceInformation("Peer table is now full"); } }
public NodeSet CreateNodeSet(int size) { if(size > 1000) throw new ArgumentOutOfRangeException("size", "size should be less than 1000"); TraceCorrelation trace = new TraceCorrelation(NodeServerTrace.Trace, "Creating node set of size " + size); NodeSet set = new NodeSet(); using(trace.Open()) { while(set.Count() < size) { var peerToGet = size - set.Count(); var activePeers = PeerTable.GetActivePeers(1000); activePeers = activePeers.Where(p => !set.Contains(p.NetworkAddress.Endpoint)).ToArray(); if(activePeers.Length < peerToGet) { DiscoverPeers(size); continue; } NodeServerTrace.Information("Need " + peerToGet + " more nodes"); BlockingCollection<Node> handshakedNodes = new BlockingCollection<Node>(peerToGet); CancellationTokenSource handshakedFull = new CancellationTokenSource(); try { Parallel.ForEach(activePeers, new ParallelOptions() { MaxDegreeOfParallelism = 10, CancellationToken = handshakedFull.Token }, p => { if(set.Contains(p.NetworkAddress.Endpoint)) return; Node node = null; try { node = GetNodeByPeer(p, handshakedFull.Token); node.VersionHandshake(handshakedFull.Token); if(node != null && node.State != NodeState.HandShaked) node.Disconnect(); if(!handshakedNodes.TryAdd(node)) { handshakedFull.Cancel(); node.Disconnect(); } else { var remaining = (size - set.Count() - handshakedNodes.Count); if(remaining == 0) { handshakedFull.Cancel(); } else NodeServerTrace.Information("Need " + remaining + " more nodes"); } } catch(Exception) { if(node != null) node.Disconnect(); } }); } catch(OperationCanceledException) { } set.AddNodes(handshakedNodes.ToArray()); } } return set; }
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; } } } }
public NodeSet CreateNodeSet(int size) { if (size > 1000) { throw new ArgumentOutOfRangeException("size", "size should be less than 1000"); } TraceCorrelation trace = new TraceCorrelation(NodeServerTrace.Trace, "Creating node set of size " + size); NodeSet set = new NodeSet(); using (trace.Open()) { while (set.Count() < size) { var peerToGet = size - set.Count(); var activePeers = PeerTable.GetActivePeers(1000); activePeers = activePeers.Where(p => !set.Contains(p.NetworkAddress.Endpoint)).ToArray(); if (activePeers.Length < peerToGet) { DiscoverPeers(size); continue; } NodeServerTrace.Information("Need " + peerToGet + " more nodes"); BlockingCollection <Node> handshakedNodes = new BlockingCollection <Node>(peerToGet); CancellationTokenSource handshakedFull = new CancellationTokenSource(); try { Parallel.ForEach(activePeers, new ParallelOptions() { MaxDegreeOfParallelism = 10, CancellationToken = handshakedFull.Token }, p => { if (set.Contains(p.NetworkAddress.Endpoint)) { return; } Node node = null; try { node = GetNodeByPeer(p, handshakedFull.Token); node.VersionHandshake(handshakedFull.Token); if (node != null && node.State != NodeState.HandShaked) { node.Disconnect(); } if (!handshakedNodes.TryAdd(node)) { handshakedFull.Cancel(); node.Disconnect(); } else { var remaining = (size - set.Count() - handshakedNodes.Count); if (remaining == 0) { handshakedFull.Cancel(); } else { NodeServerTrace.Information("Need " + remaining + " more nodes"); } } } catch (Exception) { if (node != null) { node.Disconnect(); } } }); } catch (OperationCanceledException) { } set.AddNodes(handshakedNodes.ToArray()); } } return(set); }
/// <summary> /// Try to connect to a single endpoint /// The connected endpoint will be added to the nodes collection /// </summary> /// <param name="force">Connect even if MaximumNodeConnection limit was reached</param> /// <returns>A connected node or null</returns> public Node TryConnectNode(IPEndPoint endPoint, bool force = false) { // this is not expected to be performance critical so // only use a single lock. placing a lock before the // check should avoid connecting to a node already connected lock (tcs) { // first look for the node maybe its already connected var node = this.ConnectedNodes.FindByEndpoint(endPoint); if (node != null) { return(node); } if (!force && _ConnectedNodes.Count >= MaximumNodeConnection) { return(null); } var scope = _Trace.Open(); NodeServerTrace.Information("Connected nodes : " + _ConnectedNodes.Count + "/" + MaximumNodeConnection); var parameters = _ConnectionParameters.Clone(); parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this)); parameters.ConnectCancellation = _Disconnect.Token; try { node = Node.Connect(_Network, endPoint, parameters); 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 (SocketException) { _ConnectionParameters.ConnectCancellation.WaitHandle.WaitOne(500); } catch (Exception ex) { NodeServerTrace.Error("Error while connecting to node", ex); if (node != null) { node.DisconnectAsync("Error while connecting", ex); } } finally { scope?.Dispose(); } return(node); } }
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); }