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 EventLoopMessageListener(Action <T> processMessage) { new Thread(new ThreadStart(() => { try { while (!cancellationSource.IsCancellationRequested) { var message = _MessageQueue.Take(cancellationSource.Token); if (message != null) { try { processMessage(message); } catch (Exception ex) { NodeServerTrace.Error("Unexpected expected during message loop", ex); } } } } catch (OperationCanceledException) { } })).Start(); }
public void PushMessage(T message) { if (message != null) { Task.Factory.StartNew(() => { try { _Process(message); } catch (Exception ex) { NodeServerTrace.Error("Unexpected expected during message loop", ex); } }); } }
/// <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); }
private void ProcessMessageCore(IncomingMessage message) { if (message.Message.Payload is VersionPayload) { var version = message.AssertPayload <VersionPayload>(); var connectedToSelf = version.Nonce == Nonce; if (message.Node != null && connectedToSelf) { NodeServerTrace.ConnectionToSelfDetected(); message.Node.DisconnectAsync(); return; } if (message.Node == null) { var remoteEndpoint = version.AddressFrom; if (!remoteEndpoint.Address.IsRoutable(AllowLocalPeers)) { //Send his own endpoint remoteEndpoint = new IPEndPoint(((IPEndPoint)message.Socket.RemoteEndPoint).Address, Network.DefaultPort); } var peer = new NetworkAddress() { Endpoint = remoteEndpoint, Time = DateTimeOffset.UtcNow }; var node = new Node(peer, Network, CreateNodeConnectionParameters(), message.Socket, version); if (connectedToSelf) { node.SendMessage(CreateNodeConnectionParameters().CreateVersion(node.Peer.Endpoint, Network)); NodeServerTrace.ConnectionToSelfDetected(); node.Disconnect(); return; } CancellationTokenSource cancel = new CancellationTokenSource(); cancel.CancelAfter(TimeSpan.FromSeconds(10.0)); try { ConnectedNodes.Add(node); node.StateChanged += node_StateChanged; node.RespondToHandShake(cancel.Token); } catch (OperationCanceledException ex) { NodeServerTrace.Error("The remote node did not respond fast enough (10 seconds) to the handshake completion, dropping connection", ex); node.DisconnectAsync(); throw; } catch (Exception) { node.DisconnectAsync(); throw; } } } var messageReceived = MessageReceived; if (messageReceived != null) { messageReceived(this, message); } }
private void EndAccept(SocketAsyncEventArgs args) { using (_Trace.Open()) { Socket client = null; try { if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } client = args.AcceptSocket; if (_Cancel.IsCancellationRequested) { return; } NodeServerTrace.Information("Client connection accepted : " + client.RemoteEndPoint); var cancel = CancellationTokenSource.CreateLinkedTokenSource(_Cancel.Token); cancel.CancelAfter(TimeSpan.FromSeconds(10)); var stream = new NetworkStream(client, false); while (true) { cancel.Token.ThrowIfCancellationRequested(); PerformanceCounter counter; var message = Message.ReadNext(stream, Network, Version, cancel.Token, out counter); _MessageProducer.PushMessage(new IncomingMessage() { Socket = client, Message = message, Length = counter.ReadenBytes, Node = null, }); if (message.Payload is VersionPayload) { break; } else { NodeServerTrace.Error("The first message of the remote peer did not contained a Version payload", null); } } } catch (OperationCanceledException) { Utils.SafeCloseSocket(client); if (!_Cancel.Token.IsCancellationRequested) { NodeServerTrace.Error("The remote connecting failed to send a message within 10 seconds, dropping connection", null); } } catch (Exception ex) { if (_Cancel.IsCancellationRequested) { return; } if (client == null) { NodeServerTrace.Error("Error while accepting connection ", ex); Thread.Sleep(3000); } else { Utils.SafeCloseSocket(client); NodeServerTrace.Error("Invalid message received from the remote connecting node", ex); } } BeginAccept(); } }