/// <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("(-)"); }
/// <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(); }
/// <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); }
/// <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("(-)"); }
/// <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); }
/// <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)); }
/// <inheritdoc/> public NetworkPeer CreateConnectedNetworkPeer(Network network, NetworkAddress endpoint, NetworkPeerConnectionParameters parameters) { return(new NetworkPeer(endpoint, network, parameters, this.dateTimeProvider, this.loggerFactory)); }
/// <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)); }
/// <inheritdoc/> public NetworkPeer CreateConnectedNetworkPeer(Network network, string endpoint, NetworkPeerConnectionParameters parameters) { return(this.CreateConnectedNetworkPeer(network, Utils.ParseIpEndpoint(endpoint, network.DefaultPort), parameters)); }
/// <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)); }
/// <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()); }
/// <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("(-)"); }
/// <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)); }
/// <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)); }