/// <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, NetworkPeer 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.PeerAddress.Endpoint}] "); 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.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); }
public NetworkPeerEventArgs(NetworkPeer peer, bool added) { this.Added = added; this.peer = peer; }
public NetworkPeerListener(NetworkPeer peer) { this.subscription = peer.MessageProducer.AddMessageListener(this); this.Peer = peer; }
/// <summary> /// Implements loop accepting connections from newly connected clients. /// </summary> private async Task AcceptClientsAsync() { this.logger.LogTrace("()"); this.logger.LogTrace("Accepting incoming connections."); try { while (!this.serverCancel.IsCancellationRequested) { // Used to record any errors occurring in the thread pool task. Exception error = null; TcpClient tcpClient = await Task.Run(() => { try { Task <TcpClient> acceptTask = this.tcpListener.AcceptTcpClientAsync(); acceptTask.Wait(this.serverCancel.Token); return(acceptTask.Result); } catch (Exception e) { // Record the error. error = e; return(null); } }).ConfigureAwait(false); // Raise the error. if (error != null) { throw error; } NetworkPeerClient client = this.networkPeerFactory.CreateNetworkPeerClient(tcpClient); this.logger.LogTrace("Connection accepted from client '{0}'.", client.RemoteEndPoint); var peerAddress = new NetworkAddress() { Endpoint = client.RemoteEndPoint, Time = this.dateTimeProvider.GetUtcNow() }; NetworkPeer networkPeer = this.networkPeerFactory.CreateNetworkPeer(peerAddress, this.Network, client, this.CreateNetworkPeerConnectionParameters()); this.ConnectedNetworkPeers.Add(networkPeer); networkPeer.StateChanged += this.Peer_StateChanged; this.AddConnectedClient(client); } } catch (OperationCanceledException) { this.logger.LogDebug("Shutdown detected, stop accepting connections."); } catch (Exception e) { this.logger.LogDebug("Exception occurred: {0}", e.ToString()); } this.logger.LogTrace("(-)"); }
private void ProcessMessageCore(IncomingMessage message) { if (message.Message.Payload is VersionPayload) { VersionPayload version = message.AssertPayload <VersionPayload>(); bool connectedToSelf = version.Nonce == this.Nonce; if ((message.NetworkPeer != null) && connectedToSelf) { NodeServerTrace.ConnectionToSelfDetected(); message.NetworkPeer.DisconnectAsync(); return; } if (message.NetworkPeer == null) { IPEndPoint remoteEndpoint = version.AddressFrom; if (!remoteEndpoint.Address.IsRoutable(this.AllowLocalPeers)) { // Send his own endpoint. remoteEndpoint = new IPEndPoint(((IPEndPoint)message.Socket.RemoteEndPoint).Address, this.Network.DefaultPort); } var peerAddress = new NetworkAddress() { Endpoint = remoteEndpoint, Time = DateTimeOffset.UtcNow }; NetworkPeer networkPeer = this.networkPeerFactory.CreateNetworkPeer(peerAddress, this.Network, CreateNetworkPeerConnectionParameters(), message.Socket, version); if (connectedToSelf) { networkPeer.SendMessage(CreateNetworkPeerConnectionParameters().CreateVersion(networkPeer.PeerAddress.Endpoint, this.Network)); NodeServerTrace.ConnectionToSelfDetected(); networkPeer.Disconnect(); return; } CancellationTokenSource cancel = new CancellationTokenSource(); cancel.CancelAfter(TimeSpan.FromSeconds(10.0)); try { this.ConnectedNetworkPeers.Add(networkPeer); networkPeer.StateChanged += Peer_StateChanged; networkPeer.RespondToHandShake(cancel.Token); } catch (OperationCanceledException ex) { NodeServerTrace.Error("The remote peer did not respond fast enough (10 seconds) to the handshake completion, dropping connection", ex); networkPeer.DisconnectAsync(); throw; } catch (Exception) { networkPeer.DisconnectAsync(); throw; } } } this.MessageReceived?.Invoke(this, message); }
/// <summary> /// Initializes the instance of the object and subscribes to the peer's message producer. /// </summary> /// <param name="peer">Connected network peer that we receive messages from.</param> public NetworkPeerListener(NetworkPeer peer) { this.asyncQueue = new AsyncQueue <IncomingMessage>(); this.messageProducerRegistration = peer.MessageProducer.AddMessageListener(this); this.peer = peer; }
/// <summary> /// Processes a new message received from a connected client peer. /// </summary> /// <param name="message">Message received from the client.</param> private void ProcessMessageCore(IncomingMessage message) { this.logger.LogTrace("({0}:'{1}')", nameof(message), message.Message.Command); if (message.Message.Payload is VersionPayload) { VersionPayload version = message.AssertPayload <VersionPayload>(); bool connectedToSelf = version.Nonce == this.Nonce; if (connectedToSelf) { this.logger.LogDebug("Connection to self detected and will be aborted."); } if ((message.NetworkPeer != null) && connectedToSelf) { message.NetworkPeer.DisconnectWithException(); this.logger.LogTrace("(-)[CONNECTED_TO_SELF]"); return; } if (message.NetworkPeer == null) { this.logger.LogDebug("First message received from peer '{0}'.", version.AddressFrom); IPEndPoint remoteEndpoint = version.AddressFrom; if (!remoteEndpoint.Address.IsRoutable(this.AllowLocalPeers)) { // Send his own endpoint. remoteEndpoint = new IPEndPoint(((IPEndPoint)message.Socket.RemoteEndPoint).Address, this.Network.DefaultPort); } var peerAddress = new NetworkAddress() { Endpoint = remoteEndpoint, Time = this.dateTimeProvider.GetUtcNow() }; NetworkPeer networkPeer = this.networkPeerFactory.CreateNetworkPeer(peerAddress, this.Network, CreateNetworkPeerConnectionParameters(), message.Socket, version); if (connectedToSelf) { networkPeer.SendMessage(CreateNetworkPeerConnectionParameters().CreateVersion(networkPeer.PeerAddress.Endpoint, this.Network, this.dateTimeProvider.GetTimeOffset())); networkPeer.Disconnect(); this.logger.LogTrace("(-)[CONNECTED_TO_SELF_2]"); return; } using (CancellationTokenSource cancel = new CancellationTokenSource()) { cancel.CancelAfter(TimeSpan.FromSeconds(10.0)); try { this.ConnectedNetworkPeers.Add(networkPeer); networkPeer.StateChanged += Peer_StateChanged; networkPeer.RespondToHandShake(cancel.Token); } catch (OperationCanceledException) { this.logger.LogTrace("Remote peer haven't responded within 10 seconds of the handshake completion, dropping connection."); networkPeer.DisconnectWithException(); this.logger.LogTrace("(-)[HANDSHAKE_TIMEDOUT]"); throw; } catch (Exception ex) { this.logger.LogTrace("Exception occurred: {0}", ex.ToString()); networkPeer.DisconnectWithException(); this.logger.LogTrace("(-)[HANDSHAKE_EXCEPTION]"); throw; } } } } this.logger.LogTrace("(-)"); }