示例#1
0
        private async Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(peer.State), peer.State);

            try
            {
                if (peer.State == NetworkPeerState.HandShaked)
                {
                    this.ConnectionManager.AddConnectedPeer(peer);
                    this.infoLogger.LogInformation("Peer '{0}' connected ({1}), agent '{2}', height {3}", peer.RemoteSocketEndpoint, this.Inbound ? "inbound" : "outbound", peer.PeerVersion.UserAgent, peer.PeerVersion.StartHeight);
                    await peer.SendMessageAsync(new SendHeadersPayload()).ConfigureAwait(false);
                }

                if ((peer.State == NetworkPeerState.Failed) || (peer.State == NetworkPeerState.Offline))
                {
                    this.infoLogger.LogInformation("Peer '{0}' offline, reason: '{1}'.", peer.RemoteSocketEndpoint, peer.DisconnectReason?.Reason ?? "unknown");

                    this.ConnectionManager.RemoveConnectedPeer(peer, "Peer offline");
                }
            }
            catch (OperationCanceledException)
            {
            }

            this.logger.LogTrace("(-)");
        }
示例#2
0
        /// <inheritdoc/>
        public void Disconnect(string reason, Exception exception = null)
        {
            this.logger.LogDebug("Disconnect called with reason={0} and exception={1}", reason, exception?.ToString() ?? "null");

            if (Interlocked.CompareExchange(ref this.disconnected, 1, 0) == 1)
            {
                this.logger.LogTrace("(-)[DISCONNECTED]");
                return;
            }

            if (this.IsConnected)
            {
                this.SetStateAsync(NetworkPeerState.Disconnecting).GetAwaiter().GetResult();
            }

            this.Connection.Disconnect();

            if (this.DisconnectReason == null)
            {
                this.DisconnectReason = new NetworkPeerDisconnectReason()
                {
                    Reason    = reason,
                    Exception = exception
                };
            }

            NetworkPeerState newState = exception == null ? NetworkPeerState.Offline : NetworkPeerState.Failed;

            this.SetStateAsync(newState).GetAwaiter().GetResult();
        }
示例#3
0
        /// <summary>
        /// Sets a new network state of the peer.
        /// </summary>
        /// <param name="newState">New network state to be set.</param>
        /// <remarks>This method is not thread safe.</remarks>
        private async Task SetStateAsync(NetworkPeerState newState)
        {
            this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(newState), newState, nameof(this.State), this.State);

            NetworkPeerState previous = this.State;

            if (stateTransitionTable[previous].Contains(newState))
            {
                this.State = newState;

                await this.OnStateChangedAsync(previous).ConfigureAwait(false);

                if ((newState == NetworkPeerState.Failed) || (newState == NetworkPeerState.Offline))
                {
                    this.logger.LogTrace("Communication with the peer has been closed.");

                    this.ExecuteDisconnectedCallbackWhenSafe();
                }
            }
            else if (previous != newState)
            {
                this.logger.LogDebug("Illegal transition from {0} to {1} occurred.", previous, newState);
            }

            this.logger.LogTrace("(-)");
        }
示例#4
0
 void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
 {
     if (peer.State == NetworkPeerState.HandShaked)
     {
         this.Ping(null);
     }
 }
示例#5
0
        /// <summary>
        /// Calls event handlers when the network state of the peer is changed.
        /// </summary>
        /// <param name="previous">Previous network state of the peer.</param>
        private async Task OnStateChangedAsync(NetworkPeerState previous)
        {
            this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(previous), previous, nameof(this.State), this.State);

            bool insideCallback = this.onDisconnectedAsyncContext.Value == null;

            if (!insideCallback)
            {
                this.onDisconnectedAsyncContext.Value = new DisconnectedExecutionAsyncContext();
            }

            try
            {
                await this.StateChanged.ExecuteCallbacksAsync(this, previous).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred while calling state changed callbacks: {0}", e.ToString());
                throw;
            }
            finally
            {
                if (!insideCallback)
                {
                    if (this.onDisconnectedAsyncContext.Value.DisconnectCallbackRequested)
                    {
                        this.onDisconnected(this);
                    }

                    this.onDisconnectedAsyncContext.Value = null;
                }
            }

            this.logger.LogTrace("(-)");
        }
示例#6
0
 /// <inheritdoc/>
 private void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
 {
     if ((peer.State == NetworkPeerState.Failed) || (peer.State == NetworkPeerState.Disconnecting) || (peer.State == NetworkPeerState.Offline))
     {
         this.peerConnector.RemovePeer(peer, "Peer disconnected");
     }
 }
示例#7
0
 /// <summary>Sync when handshake is finished.</summary>
 private async Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
 {
     if (peer.State == NetworkPeerState.HandShaked)
     {
         await this.ResyncAsync().ConfigureAwait(false);
     }
 }
示例#8
0
        /// <inheritdoc/>
        public void Disconnect(string reason, Exception exception = null)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(reason), reason);

            if (Interlocked.CompareExchange(ref this.disconnected, 1, 0) == 1)
            {
                this.logger.LogTrace("(-)[DISCONNECTED]");
                return;
            }

            if (this.IsConnected)
            {
                this.SetStateAsync(NetworkPeerState.Disconnecting).GetAwaiter().GetResult();
            }

            this.Connection.Disconnect();

            if (this.DisconnectReason == null)
            {
                this.DisconnectReason = new NetworkPeerDisconnectReason()
                {
                    Reason    = reason,
                    Exception = exception
                };
            }

            NetworkPeerState newState = exception == null ? NetworkPeerState.Offline : NetworkPeerState.Failed;

            this.SetStateAsync(newState).GetAwaiter().GetResult();

            this.logger.LogTrace("(-)");
        }
        private Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            try
            {
                if (peer.State == NetworkPeerState.HandShaked)
                {
                    this.connectionManager.AddConnectedPeer(peer);
                    this.infoLogger.LogInformation("Peer '{0}' connected ({1}), agent '{2}', height {3}", peer.RemoteSocketEndpoint, peer.Inbound ? "inbound" : "outbound", peer.PeerVersion.UserAgent, peer.PeerVersion.StartHeight);

                    peer.SendMessage(new SendHeadersPayload());
                }

                if ((peer.State == NetworkPeerState.Failed) || (peer.State == NetworkPeerState.Offline))
                {
                    this.infoLogger.LogInformation("Peer '{0}' ({1}) offline, reason: '{2}.{3}'", peer.RemoteSocketEndpoint, peer.Inbound ? "inbound" : "outbound", peer.DisconnectReason?.Reason ?? "unknown", peer.DisconnectReason?.Exception?.Message != null ? string.Format(" {0}.", peer.DisconnectReason.Exception.Message) : string.Empty);

                    this.connectionManager.RemoveConnectedPeer(peer, "Peer offline");
                }
            }
            catch (OperationCanceledException)
            {
            }

            return(Task.CompletedTask);
        }
示例#10
0
        /// <summary>
        /// Calls event handlers when the network state of the peer is changed.
        /// </summary>
        /// <param name="previous">Previous network state of the peer.</param>
        private async Task OnStateChangedAsync(NetworkPeerState previous)
        {
            // Creates a context that can be used to postpone / flag disconnect.
            bool iCreatedContext = this.onDisconnectedAsyncContext.Value == null;

            if (iCreatedContext)
            {
                this.onDisconnectedAsyncContext.Value = new DisconnectedExecutionAsyncContext();
            }

            try
            {
                await this.StateChanged.ExecuteCallbacksAsync(this, previous).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred while calling state changed callbacks: {0}", e.ToString());
                throw;
            }
            finally
            {
                // Only the caller that created the context should process and remove it.
                if (iCreatedContext)
                {
                    if (this.onDisconnectedAsyncContext.Value.DisconnectCallbackRequested)
                    {
                        this.onDisconnected(this);
                    }

                    this.onDisconnectedAsyncContext.Value = null;
                }
            }
        }
        /// <summary>
        /// Initializes an instance of the object.
        /// </summary>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="peer">Network peer the node is connected to, or will connect to.</param>
        /// <param name="client">Initialized TCP client, which may or may not be already connected.</param>
        /// <param name="clientId">Unique identifier of the connection.</param>
        /// <param name="processMessageAsync">Callback to be called when a new message arrives from the peer.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeerConnection(Network network, INetworkPeer peer, TcpClient client, int clientId, ProcessMessageAsync <IncomingMessage> processMessageAsync, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
            this.logger        = this.loggerFactory.CreateLogger(this.GetType().FullName, $"[{clientId}-{peer.PeerEndPoint}] ");

            this.network          = network;
            this.dateTimeProvider = dateTimeProvider;

            this.peer = peer;
            this.setPeerStateOnShutdown = NetworkPeerState.Offline;
            this.tcpClient = client;
            this.Id        = clientId;

            this.stream           = this.tcpClient.Connected ? this.tcpClient.GetStream() : null;
            this.ShutdownComplete = new TaskCompletionSource <bool>();
            this.DisposeComplete  = new TaskCompletionSource <bool>();

            this.shutdownLock = new object();
            this.writeLock    = new AsyncLock();

            this.CancellationSource = new CancellationTokenSource();

            this.MessageProducer             = new MessageProducer <IncomingMessage>();
            this.messageListener             = new CallbackMessageListener <IncomingMessage>(processMessageAsync);
            this.messageProducerRegistration = this.MessageProducer.AddMessageListener(this.messageListener);
        }
示例#12
0
 void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
 {
     if (peer.State == NetworkPeerState.HandShaked)
     {
         this.BroadcastHub.NetworkPeers.TryAdd(peer, peer);
         this.AnnounceAll();
     }
 }
示例#13
0
        private async Task AssertStateAsync(INetworkPeer peer, NetworkPeerState peerState, CancellationToken cancellationToken = default(CancellationToken))
        {
            if ((peerState == NetworkPeerState.HandShaked) && (peer.State == NetworkPeerState.Connected))
                await peer.VersionHandshakeAsync(cancellationToken);

            if (peerState != peer.State)
                throw new InvalidOperationException("Invalid Node state, needed=" + peerState + ", current= " + this.State);
        }
        private void AttachedNode_StateChanged(NetworkPeer node, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(node), node.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(node.State), node.State);

            this.TrySync();

            this.logger.LogTrace("(-)");
        }
示例#15
0
        /// <summary>Resyncs the peer whenever state is changed.</summary>
        private async Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(peer.State), peer.State);

            await this.ResyncAsync().ConfigureAwait(false);

            this.logger.LogTrace("(-)");
        }
        private void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(peer.State), peer.State);

            this.TrySyncAsync().GetAwaiter().GetResult();

            this.logger.LogTrace("(-)");
        }
        /// <inheritdoc/>
        private Task OnStateChangedAsync(NetworkPeer peer, NetworkPeerState oldState)
        {
            if ((peer.State == NetworkPeerState.Failed) || (peer.State == NetworkPeerState.Disconnecting) || (peer.State == NetworkPeerState.Offline))
            {
                this.peerConnector.RemovePeer(peer, "Peer disconnected");
            }

            return(Task.CompletedTask);
        }
示例#18
0
 private void Peer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
 {
     if ((peer.State == NetworkPeerState.Disconnecting) ||
         (peer.State == NetworkPeerState.Failed) ||
         (peer.State == NetworkPeerState.Offline))
     {
         this.ConnectedNetworkPeers.Remove(peer);
     }
 }
        /// <summary>
        /// Reads messages from the connection stream.
        /// </summary>
        private async Task ReceiveMessagesAsync()
        {
            this.logger.LogTrace("()");

            try
            {
                while (!this.CancellationSource.Token.IsCancellationRequested)
                {
                    Message message = await this.ReadAndParseMessageAsync(this.peer.Version, this.CancellationSource.Token).ConfigureAwait(false);

                    this.logger.LogTrace("Received message: '{0}'", message);

                    this.peer.LastSeen = this.dateTimeProvider.GetUtcNow();
                    this.peer.Counter.AddRead(message.MessageSize);

                    var incommingMessage = new IncomingMessage()
                    {
                        Message     = message,
                        Length      = message.MessageSize,
                        NetworkPeer = this.peer
                    };

                    this.MessageProducer.PushMessage(incommingMessage);
                }
            }
            catch (Exception ex)
            {
                if (ex is OperationCanceledException)
                {
                    this.logger.LogTrace("Receiving cancelled.");
                }
                else
                {
                    this.logger.LogTrace("Exception occurred: '{0}'", ex.ToString());

                    if (this.peer.DisconnectReason == null)
                    {
                        this.peer.DisconnectReason = new NetworkPeerDisconnectReason()
                        {
                            Reason    = "Unexpected exception while waiting for a message",
                            Exception = ex
                        };
                    }

                    // We can not set the peer state directly here because it would
                    // trigger state changing event handlers and could cause deadlock.
                    if (this.peer.State != NetworkPeerState.Offline)
                    {
                        this.setPeerStateOnShutdown = NetworkPeerState.Failed;
                    }
                }

                this.CallShutdown();
            }

            this.logger.LogTrace("(-)");
        }
示例#20
0
        private Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            if (peer.State == NetworkPeerState.HandShaked)
            {
                this.Ping(null);
            }

            return(Task.CompletedTask);
        }
 private void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState previousState)
 {
     if ((this.Mode & PeerAddressManagerBehaviourMode.Discover) != 0)
     {
         if (peer.State == NetworkPeerState.HandShaked)
         {
             this.peerAddressManager.PeerHandshaked(peer.PeerEndPoint, this.dateTimeProvider.GetUtcNow());
         }
     }
 }
示例#22
0
        private Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState previousState)
        {
            if ((this.Mode & PeerAddressManagerBehaviourMode.Discover) != 0)
            {
                if (peer.State == NetworkPeerState.HandShaked)
                {
                    this.peerAddressManager.PeerHandshaked(peer.PeerEndPoint, this.dateTimeProvider.GetUtcNow());
                }
            }

            return(Task.CompletedTask);
        }
        private void AssertState(NetworkPeer peer, NetworkPeerState nodeState, CancellationToken cancellationToken = default(CancellationToken))
        {
            if ((nodeState == NetworkPeerState.HandShaked) && (peer.State == NetworkPeerState.Connected))
            {
                peer.VersionHandshake(cancellationToken);
            }

            if (nodeState != peer.State)
            {
                throw new InvalidOperationException("Invalid Node state, needed=" + nodeState + ", current= " + this.State);
            }
        }
        /// <summary>
        /// Callback that is called when a network status of a connected client peer changes.
        /// <para>The peer is removed from the list of connected peers if the connection has been terminated for any reason.</para>
        /// </summary>
        /// <param name="peer">The connected peer.</param>
        /// <param name="oldState">Previous state of the peer. New state of the peer is stored in its <see cref="NetworkPeer.State"/> property.</param>
        private void Peer_StateChanged(NetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}.{5}:{6})", nameof(peer), peer.PeerAddress.Endpoint, nameof(oldState), oldState, nameof(peer), nameof(peer.State), peer.State);

            if ((peer.State == NetworkPeerState.Disconnecting) ||
                (peer.State == NetworkPeerState.Failed) ||
                (peer.State == NetworkPeerState.Offline))
            {
                this.ConnectedNetworkPeers.Remove(peer, "Peer disconnected");
            }

            this.logger.LogTrace("(-)");
        }
        private async Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(peer), peer.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(peer.State), peer.State);

            try
            {
                await this.TrySyncAsync().ConfigureAwait(false);
            }
            catch (OperationCanceledException)
            {
            }

            this.logger.LogTrace("(-)");
        }
示例#26
0
        /// <summary>
        /// Callback that is called when a network status of a connected client peer changes.
        /// <para>The peer is removed from the list of connected peers if the connection has been terminated for any reason.</para>
        /// </summary>
        /// <param name="peer">The connected peer.</param>
        /// <param name="oldState">Previous state of the peer. New state of the peer is stored in its <see cref="INetworkPeer.State"/> property.</param>
        private Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}.{5}:{6})", nameof(peer), peer.PeerEndPoint, nameof(oldState), oldState, nameof(peer), nameof(peer.State), peer.State);

            if ((peer.State == NetworkPeerState.Disconnecting) ||
                (peer.State == NetworkPeerState.Failed) ||
                (peer.State == NetworkPeerState.Offline))
            {
                peer.StateChanged.Unregister(this.OnStateChangedAsync);
                this.ConnectedNetworkPeers.Remove(peer, "Peer disconnected");
            }

            this.logger.LogTrace("(-)");
            return(Task.CompletedTask);
        }
示例#27
0
        private async Task OnStateChangedAsync(INetworkPeer sender, NetworkPeerState arg)
        {
            if (arg == NetworkPeerState.HandShaked)
            {
                this.StartFeeFilterBroadcast(sender);
            }

            if (arg == NetworkPeerState.Disconnecting)
            {
                if (this.asyncLoop != null)
                {
                    this.asyncLoop?.Dispose();
                    this.asyncLoop = null;
                }
            }
        }
示例#28
0
        /// <summary>
        /// Calls event handlers when the network state of the peer is changed.
        /// </summary>
        /// <param name="previous">Previous network state of the peer.</param>
        private async Task OnStateChangedAsync(NetworkPeerState previous)
        {
            this.logger.LogTrace("({0}:{1},{2}:{3})", nameof(previous), previous, nameof(this.State), this.State);

            try
            {
                await this.StateChanged.ExecuteCallbacksAsync(this, previous).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred while calling state changed callbacks: {0}", e.ToString());
                throw;
            }

            this.logger.LogTrace("(-)");
        }
        Task OnStateChangedAsync(INetworkPeer peer, NetworkPeerState previousState)
        {
            if ((this.Mode & PeerAddressManagerBehaviourMode.Discover) != 0)
            {
                if (peer.State == NetworkPeerState.HandShaked)
                {
                    this.peerAddressManager.PeerHandshaked(peer.PeerEndPoint, this.dateTimeProvider.GetUtcNow());
                }
            }

            if (peer.Inbound && peer.State == NetworkPeerState.HandShaked &&
                (this.Mode == PeerAddressManagerBehaviourMode.Advertise ||
                 this.Mode == PeerAddressManagerBehaviourMode.AdvertiseDiscover))
            {
                this.logger.LogDebug("[INBOUND] {0}:{1}, {2}:{3}, {4}:{5}", nameof(peer.RemoteSocketAddress),
                                     peer.RemoteSocketAddress, nameof(peer.RemoteSocketEndpoint), peer.RemoteSocketEndpoint,
                                     nameof(peer.RemoteSocketPort), peer.RemoteSocketPort);
                this.logger.LogDebug("[INBOUND] {0}:{1}, {2}:{3}", nameof(peer.PeerVersion.AddressFrom),
                                     peer.PeerVersion?.AddressFrom, nameof(peer.PeerVersion.AddressReceiver),
                                     peer.PeerVersion?.AddressReceiver);
                this.logger.LogDebug("[INBOUND] {0}:{1}", nameof(peer.PeerEndPoint), peer.PeerEndPoint);

                IPEndPoint inboundPeerEndPoint = null;

                // Use AddressFrom if it is not a Loopback address as this means the inbound node was configured with a different external endpoint.
                if (!peer.PeerVersion.AddressFrom.Match(new IPEndPoint(IPAddress.Loopback,
                                                                       this.AttachedPeer.Network.DefaultPort)))
                {
                    inboundPeerEndPoint = peer.PeerVersion.AddressFrom;
                }
                else
                {
                    // If it is a Loopback address use PeerEndpoint but combine it with the AdressFrom's port as that is the
                    // other node's listening port.
                    inboundPeerEndPoint = new IPEndPoint(peer.PeerEndPoint.Address, peer.PeerVersion.AddressFrom.Port);
                }

                this.logger.LogDebug("{0}", inboundPeerEndPoint);

                this.peerAddressManager.AddPeer(inboundPeerEndPoint, IPAddress.Loopback);
            }

            return(Task.CompletedTask);
        }
        private void AttachedNode_StateChanged(NetworkPeer node, NetworkPeerState oldState)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3},{4}:{5})", nameof(node), node.RemoteSocketEndpoint, nameof(oldState), oldState, nameof(node.State), node.State);

            if (node.State == NetworkPeerState.HandShaked)
            {
                this.ConnectionManager.AddConnectedNode(node);
                this.infoLogger.LogInformation("Node '{0}' connected ({1}), agent '{2}', height {3}", node.RemoteSocketEndpoint, this.Inbound ? "inbound" : "outbound", node.PeerVersion.UserAgent, node.PeerVersion.StartHeight);
                node.SendMessageAsync(new SendHeadersPayload());
            }

            if ((node.State == NetworkPeerState.Failed) || (node.State == NetworkPeerState.Offline))
            {
                this.infoLogger.LogInformation("Node '{0}' offline, reason: '{1}'.", node.RemoteSocketEndpoint, node.DisconnectReason?.Reason ?? "unknown");
                this.ConnectionManager.RemoveConnectedNode(node);
            }

            this.logger.LogTrace("(-)");
        }