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("(-)"); }
/// <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(); }
/// <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("(-)"); }
void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState) { if (peer.State == NetworkPeerState.HandShaked) { this.Ping(null); } }
/// <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("(-)"); }
/// <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"); } }
/// <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); } }
/// <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); }
/// <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); }
void AttachedPeer_StateChanged(NetworkPeer peer, NetworkPeerState oldState) { if (peer.State == NetworkPeerState.HandShaked) { this.BroadcastHub.NetworkPeers.TryAdd(peer, peer); this.AnnounceAll(); } }
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("(-)"); }
/// <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); }
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("(-)"); }
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()); } } }
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("(-)"); }
/// <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); }
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; } } }
/// <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("(-)"); }