/// <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, TcpClient client, IDateTimeProvider dateTimeProvider, INetworkPeerFactory networkPeerFactory, ILoggerFactory loggerFactory)
            : this(true, peerAddress, network, parameters, dateTimeProvider, loggerFactory)
        {
            this.Connection = networkPeerFactory.CreateNetworkPeerConnection(this, client, this.ProcessMessageAsync);

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

            this.RemoteSocketEndpoint = this.PeerAddress.Endpoint;
            this.RemoteSocketAddress  = this.RemoteSocketEndpoint.Address;
            this.RemoteSocketPort     = this.RemoteSocketEndpoint.Port;

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

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

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

            this.logger.LogTrace("(-)");
        }
        /// <summary>
        /// Initializes behaviors from the default template.
        /// </summary>
        /// <param name="parameters">Various settings and requirements related to how the connections with peers are going to be established, including the default behaviors template.</param>
        private void InitDefaultBehaviors(NetworkPeerConnectionParameters parameters)
        {
            this.logger.LogTrace("()");

            this.advertize = parameters.Advertize;
            this.preferredTransactionOptions = parameters.PreferredTransactionOptions;

            foreach (INetworkPeerBehavior behavior in parameters.TemplateBehaviors)
            {
                this.Behaviors.Add(behavior.Clone());
            }

            if ((this.State == NetworkPeerState.Connected) || (this.State == NetworkPeerState.HandShaked))
            {
                foreach (INetworkPeerBehavior behavior in this.Behaviors)
                {
                    behavior.Attach(this);
                }
            }

            this.logger.LogTrace("(-)");
        }
示例#3
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="dateTimeProvider">Provider of time functions.</param>
        /// <param name="networkPeerFactory">Factory for creating P2P network peers.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        /// <param name="selfEndpointTracker">Tracker for endpoints known to be self.</param>
        /// <param name="onDisconnected">Callback that is invoked when peer has finished disconnecting, or <c>null</c> when no notification after the disconnection is required.</param>
        public NetworkPeer(IPEndPoint peerEndPoint,
                           Network network,
                           NetworkPeerConnectionParameters parameters,
                           TcpClient client,
                           IDateTimeProvider dateTimeProvider,
                           INetworkPeerFactory networkPeerFactory,
                           ILoggerFactory loggerFactory,
                           ISelfEndpointTracker selfEndpointTracker,
                           IAsyncProvider asyncProvider,
                           Action <INetworkPeer> onDisconnected          = null,
                           Action <IPEndPoint, Payload> onSendingMessage = null)
            : this(true, peerEndPoint, network, parameters, dateTimeProvider, loggerFactory, selfEndpointTracker, asyncProvider, onDisconnected, onSendingMessage)
        {
            this.Connection = networkPeerFactory.CreateNetworkPeerConnection(this, client, this.ProcessMessageAsync);

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

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

            this.InitDefaultBehaviors(this.ConnectionParameters);
            this.Connection.StartReceiveMessages();
        }
示例#4
0
        /// <summary>
        /// Initializes parts of the object that are common for both inbound and outbound peers.
        /// </summary>
        /// <param name="inbound"><c>true</c> for inbound peers, <c>false</c> for outbound peers.</param>
        /// <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="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        /// <param name="selfEndpointTracker">Tracker for endpoints known to be self.</param>
        /// <param name="onDisconnected">Callback that is invoked when peer has finished disconnecting, or <c>null</c> when no notification after the disconnection is required.</param>
        private NetworkPeer(bool inbound,
                            IPEndPoint peerEndPoint,
                            Network network,
                            NetworkPeerConnectionParameters parameters,
                            IDateTimeProvider dateTimeProvider,
                            ILoggerFactory loggerFactory,
                            ISelfEndpointTracker selfEndpointTracker,
                            Action <INetworkPeer> onDisconnected          = null,
                            Action <IPEndPoint, Payload> onSendingMessage = null)
        {
            this.dateTimeProvider = dateTimeProvider;

            this.preferredTransactionOptions = parameters.PreferredTransactionOptions;
            this.SupportedTransactionOptions = parameters.PreferredTransactionOptions & ~TransactionOptions.All;

            this.State                = inbound ? NetworkPeerState.Connected : NetworkPeerState.Created;
            this.Inbound              = inbound;
            this.PeerEndPoint         = peerEndPoint;
            this.RemoteSocketEndpoint = this.PeerEndPoint;
            this.RemoteSocketAddress  = this.RemoteSocketEndpoint.Address;
            this.RemoteSocketPort     = this.RemoteSocketEndpoint.Port;

            this.Network             = network;
            this.Behaviors           = new List <INetworkPeerBehavior>();
            this.selfEndpointTracker = selfEndpointTracker;

            this.onDisconnectedAsyncContext = new AsyncLocal <DisconnectedExecutionAsyncContext>();

            this.ConnectionParameters = parameters ?? new NetworkPeerConnectionParameters();
            this.MyVersion            = this.ConnectionParameters.CreateVersion(this.selfEndpointTracker.MyExternalAddress, this.PeerEndPoint, network, this.dateTimeProvider.GetTimeOffset());

            this.MessageReceived  = new AsyncExecutionEvent <INetworkPeer, IncomingMessage>();
            this.StateChanged     = new AsyncExecutionEvent <INetworkPeer, NetworkPeerState>();
            this.onDisconnected   = onDisconnected;
            this.onSendingMessage = onSendingMessage;

            this.asyncQueue = new AsyncQueue <Payload>(this.SendMessageHandledAsync);
        }
示例#5
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>
        /// <param name="selfEndpointTracker">Tracker for endpoints known to be self.</param>
        /// <param name="onDisconnected">Callback that is invoked when peer has finished disconnecting, or <c>null</c> when no notification after the disconnection is required.</param>
        public NetworkPeer(IPEndPoint peerEndPoint,
                           Network network,
                           NetworkPeerConnectionParameters parameters,
                           INetworkPeerFactory networkPeerFactory,
                           IDateTimeProvider dateTimeProvider,
                           ILoggerFactory loggerFactory,
                           ISelfEndpointTracker selfEndpointTracker,
                           Action <INetworkPeer> onDisconnected = null)
            : this(false, peerEndPoint, network, parameters, dateTimeProvider, loggerFactory, selfEndpointTracker, onDisconnected)
        {
            var 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("(-)");
        }
示例#6
0
        /// <inheritdoc/>
        public async Task <NetworkPeer> CreateConnectedNetworkPeerAsync(Network network, NetworkAddress peerAddress, NetworkPeerConnectionParameters parameters = null)
        {
            Guard.NotNull(network, nameof(network));
            Guard.NotNull(peerAddress, nameof(peerAddress));

            var peer = new NetworkPeer(peerAddress, network, parameters, this, this.dateTimeProvider, this.loggerFactory);

            try
            {
                await peer.ConnectAsync(peer.Parameters.ConnectCancellation).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                peer.Dispose("Connection failed", e);
                throw;
            }
            return(peer);
        }
示例#7
0
        /// <inheritdoc/>
        public async Task <NetworkPeer> CreateConnectedNetworkPeerAsync(Network network, IPEndPoint endPoint, NetworkPeerConnectionParameters parameters = null)
        {
            Guard.NotNull(network, nameof(network));
            Guard.NotNull(endPoint, nameof(endPoint));

            var peerAddress = new NetworkAddress()
            {
                Time     = this.dateTimeProvider.GetTimeOffset(),
                Endpoint = endPoint
            };

            return(await this.CreateConnectedNetworkPeerAsync(network, peerAddress, parameters));
        }
示例#8
0
 /// <inheritdoc/>
 public NetworkPeer CreateConnectedNetworkPeer(Network network, NetworkAddress endpoint, NetworkPeerConnectionParameters parameters)
 {
     return(new NetworkPeer(endpoint, network, parameters, this.dateTimeProvider, this.loggerFactory));
 }
示例#9
0
        /// <inheritdoc/>
        public NetworkPeer CreateConnectedNetworkPeer(Network network, IPEndPoint endpoint, NetworkPeerConnectionParameters parameters)
        {
            var peerAddress = new NetworkAddress()
            {
                Time     = DateTimeOffset.UtcNow,
                Endpoint = endpoint
            };

            return(this.CreateConnectedNetworkPeer(network, peerAddress, parameters));
        }
示例#10
0
 /// <inheritdoc/>
 public NetworkPeer CreateConnectedNetworkPeer(Network network, string endpoint, NetworkPeerConnectionParameters parameters)
 {
     return(this.CreateConnectedNetworkPeer(network, Utils.ParseIpEndpoint(endpoint, network.DefaultPort), parameters));
 }
示例#11
0
 /// <inheritdoc/>
 public NetworkPeer CreateNetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, Socket socket, VersionPayload peerVersion)
 {
     return(new NetworkPeer(peerAddress, network, parameters, socket, peerVersion, this.dateTimeProvider, this.loggerFactory));
 }
示例#12
0
        /// <summary>
        /// Initializes parts of the object that are common for both inbound and outbound peers.
        /// </summary>
        /// <param name="inbound"><c>true</c> for inbound peers, <c>false</c> for outbound peers.</param>
        /// <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="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        private NetworkPeer(bool inbound, NetworkAddress peerAddress, Network network, NetworkPeerConnectionParameters parameters, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.loggerFactory    = loggerFactory;
            this.logger           = loggerFactory.CreateLogger(this.GetType().FullName, $"[{peerAddress.Endpoint}] ");
            this.dateTimeProvider = dateTimeProvider;

            this.MessageProducer = new MessageProducer <IncomingMessage>();

            this.preferredTransactionOptions = network.NetworkOptions;
            this.SupportedTransactionOptions = network.NetworkOptions & ~NetworkOptions.All;

            this.Inbound     = inbound;
            this.LastSeen    = peerAddress.Time.UtcDateTime;
            this.PeerAddress = peerAddress;
            this.Network     = network;
            this.Behaviors   = new NetworkPeerBehaviorsCollection(this);

            parameters     = parameters ?? new NetworkPeerConnectionParameters();
            this.MyVersion = parameters.CreateVersion(peerAddress.Endpoint, network, this.dateTimeProvider.GetTimeOffset());
        }
示例#13
0
        /// <inheritdoc/>
        public INetworkPeer CreateNetworkPeer(TcpClient client, NetworkPeerConnectionParameters parameters = null)
        {
            Guard.NotNull(client, nameof(client));

            return(new NetworkPeer((IPEndPoint)client.Client.RemoteEndPoint, this.network, parameters, client, this.dateTimeProvider, this, this.loggerFactory));
        }
        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("(-)");
        }
示例#15
0
        /// <inheritdoc/>
        public async Task <NetworkPeer> CreateConnectedNetworkPeerAsync(Network network, string endPoint, NetworkPeerConnectionParameters parameters)
        {
            Guard.NotNull(network, nameof(network));
            Guard.NotNull(endPoint, nameof(endPoint));

            return(await this.CreateConnectedNetworkPeerAsync(network, Utils.ParseIpEndpoint(endPoint, network.DefaultPort), parameters));
        }
示例#16
0
        /// <inheritdoc/>
        public NetworkPeer CreateNetworkPeer(NetworkAddress peerAddress, Network network, NetworkPeerClient client, VersionPayload peerVersion, NetworkPeerConnectionParameters parameters = null)
        {
            Guard.NotNull(peerAddress, nameof(peerAddress));
            Guard.NotNull(network, nameof(network));
            Guard.NotNull(client, nameof(client));
            Guard.NotNull(client.RemoteEndPoint, $"{nameof(client)}.{nameof(client.RemoteEndPoint)}");

            return(new NetworkPeer(peerAddress, network, parameters, client, peerVersion, this.dateTimeProvider, this.loggerFactory));
        }