Exemple #1
0
 public void Dispose()
 {
     if (!_Cancel.IsCancellationRequested)
     {
         _Cancel.Cancel();
         _Trace.LogInside(() => NodeServerTrace.Information("Stopping node server..."));
         lock (_Resources)
         {
             foreach (var resource in _Resources)
             {
                 resource.Dispose();
             }
         }
         try
         {
             _ConnectedNodes.DisconnectAll();
         }
         finally
         {
             if (socket != null)
             {
                 Utils.SafeCloseSocket(socket);
                 socket = null;
             }
         }
     }
 }
Exemple #2
0
        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;
                }
            }
        }
Exemple #3
0
 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();
 }
Exemple #4
0
 internal void ExternalAddressDetected(IPAddress iPAddress)
 {
     if (!ExternalEndpoint.Address.IsRoutable(AllowLocalPeers) && iPAddress.IsRoutable(AllowLocalPeers))
     {
         NodeServerTrace.Information("New externalAddress detected " + iPAddress);
         ExternalEndpoint = new IPEndPoint(iPAddress, ExternalEndpoint.Port);
     }
 }
Exemple #5
0
        private void BeginAccept()
        {
            if (_Cancel.IsCancellationRequested)
            {
                NodeServerTrace.Information("Stop accepting connection...");
                return;
            }
            NodeServerTrace.Information("Accepting connection...");
            var args = new SocketAsyncEventArgs();

            args.Completed += Accept_Completed;
            if (!socket.AcceptAsync(args))
            {
                EndAccept(args);
            }
        }
Exemple #6
0
 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);
             }
         });
     }
 }
Exemple #7
0
        /// <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);
            }
        }
Exemple #8
0
        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);
        }
Exemple #9
0
        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;
                        }
                    }
                }
            }
        }
Exemple #10
0
        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);
            }
        }
Exemple #11
0
        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();
            }
        }