public NetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, Socket socket, VersionPayload peerVersion, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.RemoteSocketEndpoint = ((IPEndPoint)socket.RemoteEndPoint);
            this.RemoteSocketAddress  = ((IPEndPoint)socket.RemoteEndPoint).Address;
            this.RemoteSocketPort     = ((IPEndPoint)socket.RemoteEndPoint).Port;

            this.loggerFactory = loggerFactory;
            this.logger        = loggerFactory.CreateLogger(this.GetType().FullName, $"[{this.RemoteSocketEndpoint}] ");

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

            this.dateTimeProvider = dateTimeProvider;

            this.Inbound     = true;
            this.Behaviors   = new NetworkPeerBehaviorsCollection(this);
            this.MyVersion   = parameters.CreateVersion(peerAddress.Endpoint, network, this.dateTimeProvider.GetTimeOffset());
            this.Network     = network;
            this.PeerAddress = peerAddress;
            this.connection  = new NetworkPeerConnection(this, socket, this.dateTimeProvider, this.loggerFactory);
            this.PeerVersion = peerVersion;
            this.LastSeen    = peerAddress.Time.UtcDateTime;
            this.ConnectedAt = this.dateTimeProvider.GetUtcNow();

            this.logger.LogTrace("Connected to advertised node '{0}'.", this.PeerAddress.Endpoint);
            this.State = NetworkPeerState.Connected;

            this.InitDefaultBehaviors(parameters);
            this.connection.BeginListen();

            this.logger.LogTrace("(-)");
        }
        /// <summary>
        /// Adds client's connection to the list of active connections.
        /// </summary>
        /// <param name="connection">Client's connection to add.</param>
        private void AddClientConnection(NetworkPeerConnection connection)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(connection), nameof(connection.Id), connection.Id);

            this.connectionsById.AddOrReplace(connection.Id, connection);
            connection.ShutdownComplete.Task.ContinueWith(unused => this.RemoveConnectedClient(connection));

            this.logger.LogTrace("(-)");
        }
        /// <summary>
        /// Dummy constructor for testing only.
        /// </summary>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Provider of time functions.</param>
        /// <remarks>TODO: Remove this constructor as soon as we can mock the node in tests.</remarks>
        public NetworkPeer(IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.dateTimeProvider = dateTimeProvider;
            this.loggerFactory    = loggerFactory;
            this.logger           = loggerFactory.CreateLogger(this.GetType().FullName);

            this.Behaviors   = new NetworkPeerBehaviorsCollection(this);
            this.PeerAddress = new NetworkAddress();
            this.Connection  = new NetworkPeerConnection(null, this, new TcpClient(), 0, this.ProcessMessageAsync, this.dateTimeProvider, this.loggerFactory);
        }
        /// <summary>
        /// Removes a connection from the list of active clients' connection.
        /// </summary>
        /// <param name="connection">Client to remove and disconnect.</param>
        private void RemoveConnectedClient(NetworkPeerConnection connection)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(connection), nameof(connection.Id), connection.Id);

            if (!this.connectionsById.TryRemove(connection.Id, out NetworkPeerConnection unused))
            {
                this.logger.LogError("Internal data integration error.");
            }

            this.logger.LogTrace("(-)");
        }
Пример #5
0
        /// <summary>
        /// Dummy constructor for testing only.
        /// </summary>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Provider of time functions.</param>
        /// <remarks>TODO: Remove this constructor as soon as we can mock the node in tests.</remarks>
        public NetworkPeer(IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.dateTimeProvider = dateTimeProvider;
            this.loggerFactory    = loggerFactory;
            this.logger           = loggerFactory.CreateLogger(this.GetType().FullName);

            this.Behaviors       = new NetworkPeerBehaviorsCollection(this);
            this.PeerEndPoint    = new IPEndPoint(IPAddress.Loopback, 1);
            this.Connection      = new NetworkPeerConnection(null, this, new TcpClient(), 0, this.ProcessMessageAsync, this.dateTimeProvider, this.loggerFactory);
            this.MessageReceived = new AsyncExecutionEvent <NetworkPeer, IncomingMessage>();
            this.StateChanged    = new AsyncExecutionEvent <NetworkPeer, NetworkPeerState>();
        }
Пример #6
0
        /// <summary>
        /// Initializes an instance of the object for outbound network peers.
        /// </summary>
        /// <param name="peerAddress">Information about the peer including its network address, protocol version, time of last contact.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, or <c>null</c> to use default parameters.</param>
        /// <param name="networkPeerFactory">Factory for creating P2P network peers.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, INetworkPeerFactory networkPeerFactory, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
            : this(false, peerAddress, network, parameters, dateTimeProvider, loggerFactory)
        {
            NetworkPeerClient client = networkPeerFactory.CreateNetworkPeerClient(parameters);

            this.logger = loggerFactory.CreateLogger(this.GetType().FullName, $"[{client.Id}-{peerAddress.Endpoint}] ");
            this.logger.LogTrace("()");

            this.Connection = new NetworkPeerConnection(this, client, this.dateTimeProvider, this.loggerFactory);

            this.logger.LogTrace("(-)");
        }
Пример #7
0
        /// <summary>
        /// Initializes an instance of the object for outbound network peers.
        /// </summary>
        /// <param name="peerAddress">Information about the peer including its network address, protocol version, time of last contact.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, or <c>null</c> to use default parameters.</param>
        /// <param name="networkPeerFactory">Factory for creating P2P network peers.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, INetworkPeerFactory networkPeerFactory, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
            : this(false, peerAddress, network, parameters, dateTimeProvider, loggerFactory)
        {
            this.logger.LogTrace("()");

            NetworkPeerClient client = networkPeerFactory.CreateNetworkPeerClient(parameters);

            this.Connection = new NetworkPeerConnection(this, client, this.dateTimeProvider, this.loggerFactory);
            this.ConnectAsync(parameters.ConnectCancellation).GetAwaiter().GetResult();

            this.InitDefaultBehaviors(parameters);
            this.Connection.StartReceiveMessages();

            this.logger.LogTrace("(-)");
        }
Пример #8
0
        /// <summary>
        /// Initializes an instance of the object for outbound network peers.
        /// </summary>
        /// <param name="peerEndPoint">IP address and port on the side of the peer.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, or <c>null</c> to use default parameters.</param>
        /// <param name="networkPeerFactory">Factory for creating P2P network peers.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeer(IPEndPoint peerEndPoint, Network network, NetworkPeerConnectionParameters parameters, INetworkPeerFactory networkPeerFactory, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
            : this(false, peerEndPoint, network, parameters, dateTimeProvider, loggerFactory)
        {
            TcpClient client = new TcpClient(AddressFamily.InterNetworkV6);

            client.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
            client.Client.ReceiveBufferSize = parameters.ReceiveBufferSize;
            client.Client.SendBufferSize    = parameters.SendBufferSize;

            this.Connection = networkPeerFactory.CreateNetworkPeerConnection(this, client, this.ProcessMessageAsync);

            this.logger = loggerFactory.CreateLogger(this.GetType().FullName, $"[{this.Connection.Id}-{peerEndPoint}] ");
            this.logger.LogTrace("()");

            this.logger.LogTrace("(-)");
        }
Пример #9
0
        /// <summary>
        /// Initializes an instance of the object for inbound network peers with already established connection.
        /// </summary>
        /// <param name="peerAddress">Information about the peer including its network address, protocol version, time of last contact.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, or <c>null</c> to use default parameters.</param>
        /// <param name="client">Already connected network client.</param>
        /// <param name="peerVersion">Version message payload received from the peer.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, NetworkPeerClient client, VersionPayload peerVersion, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
            : this(true, peerAddress, network, parameters, dateTimeProvider, loggerFactory)
        {
            this.logger.LogTrace("()");

            this.RemoteSocketEndpoint = client.RemoteEndPoint;
            this.RemoteSocketAddress  = this.RemoteSocketEndpoint.Address;
            this.RemoteSocketPort     = this.RemoteSocketEndpoint.Port;

            this.PeerVersion = peerVersion;
            this.Connection  = new NetworkPeerConnection(this, client, this.dateTimeProvider, this.loggerFactory);
            this.ConnectedAt = this.dateTimeProvider.GetUtcNow();

            this.logger.LogTrace("Connected to advertised node '{0}'.", this.PeerAddress.Endpoint);
            this.State = NetworkPeerState.Connected;

            this.InitDefaultBehaviors(parameters);
            this.Connection.StartReceiveMessages();

            this.logger.LogTrace("(-)");
        }
Пример #10
0
        /// <summary>
        /// Initializes an instance of the object for inbound network peers with already established connection.
        /// </summary>
        /// <param name="peerEndPoint">IP address and port on the side of the peer.</param>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, or <c>null</c> to use default parameters.</param>
        /// <param name="client">Already connected network client.</param>
        /// <param name="peerVersion">Version message payload received from the peer.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeer(IPEndPoint peerEndPoint, Network network, NetworkPeerConnectionParameters parameters, TcpClient client, IDateTimeProvider dateTimeProvider, INetworkPeerFactory networkPeerFactory, ILoggerFactory loggerFactory)
            : this(true, peerEndPoint, network, parameters, dateTimeProvider, loggerFactory)
        {
            this.Connection = networkPeerFactory.CreateNetworkPeerConnection(this, client, this.ProcessMessageAsync);

            this.logger = loggerFactory.CreateLogger(this.GetType().FullName, $"[{this.Connection.Id}-{peerEndPoint}] ");
            this.logger.LogTrace("()");

            this.RemoteSocketEndpoint = this.PeerEndPoint;
            this.RemoteSocketAddress  = this.RemoteSocketEndpoint.Address;
            this.RemoteSocketPort     = this.RemoteSocketEndpoint.Port;

            this.ConnectedAt = this.dateTimeProvider.GetUtcNow();

            this.logger.LogTrace("Connected to peer '{0}'.", this.PeerEndPoint);
            this.State = NetworkPeerState.Connected;

            this.InitDefaultBehaviors(this.Parameters);
            this.Connection.StartReceiveMessages();

            this.logger.LogTrace("(-)");
        }
Пример #11
0
        public NetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
            this.logger        = loggerFactory.CreateLogger(this.GetType().FullName, $"[{peerAddress.Endpoint}] ");

            this.logger.LogTrace("()");
            this.dateTimeProvider = dateTimeProvider;

            parameters       = parameters ?? new NetworkPeerConnectionParameters();
            this.Inbound     = false;
            this.Behaviors   = new NetworkPeerBehaviorsCollection(this);
            this.MyVersion   = parameters.CreateVersion(peerAddress.Endpoint, network, this.dateTimeProvider.GetTimeOffset());
            this.Network     = network;
            this.PeerAddress = peerAddress;
            this.LastSeen    = peerAddress.Time.UtcDateTime;

            var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

            socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);

            this.connection = new NetworkPeerConnection(this, socket, this.dateTimeProvider, this.loggerFactory);

            socket.ReceiveBufferSize = parameters.ReceiveBufferSize;
            socket.SendBufferSize    = parameters.SendBufferSize;
            try
            {
                using (var completedEvent = new ManualResetEvent(false))
                {
                    using (var nodeSocketEventManager = NodeSocketEventManager.Create(completedEvent, peerAddress.Endpoint))
                    {
                        this.logger.LogTrace("Connecting to '{0}'.", peerAddress.Endpoint);

                        // If the socket connected straight away (synchronously) unblock all threads.
                        if (!socket.ConnectAsync(nodeSocketEventManager.SocketEvent))
                        {
                            completedEvent.Set();
                        }

                        // Otherwise wait for the socket connection to complete OR if the operation got cancelled.
                        WaitHandle.WaitAny(new WaitHandle[] { completedEvent, parameters.ConnectCancellation.WaitHandle });

                        parameters.ConnectCancellation.ThrowIfCancellationRequested();

                        if (nodeSocketEventManager.SocketEvent.SocketError != SocketError.Success)
                        {
                            throw new SocketException((int)nodeSocketEventManager.SocketEvent.SocketError);
                        }

                        var remoteEndpoint = (IPEndPoint)(socket.RemoteEndPoint ?? nodeSocketEventManager.SocketEvent.RemoteEndPoint);
                        this.RemoteSocketAddress  = remoteEndpoint.Address;
                        this.RemoteSocketEndpoint = remoteEndpoint;
                        this.RemoteSocketPort     = remoteEndpoint.Port;

                        this.State       = NetworkPeerState.Connected;
                        this.ConnectedAt = this.dateTimeProvider.GetUtcNow();

                        this.logger.LogTrace("Outbound connection to '{0}' established.", peerAddress.Endpoint);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                this.logger.LogTrace("Connection to '{0}' cancelled.", peerAddress.Endpoint);
                Utils.SafeCloseSocket(socket);
                this.State = NetworkPeerState.Offline;

                throw;
            }
            catch (Exception ex)
            {
                this.logger.LogTrace("Exception occurred: {0}", ex.ToString());
                Utils.SafeCloseSocket(socket);
                this.DisconnectReason = new NetworkPeerDisconnectReason()
                {
                    Reason    = "Unexpected exception while connecting to socket",
                    Exception = ex
                };

                this.State = NetworkPeerState.Failed;

                throw;
            }

            this.InitDefaultBehaviors(parameters);
            this.connection.BeginListen();

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