public void AddNodeAddress(IPEndPoint endpoint)
        {
            AddressManager addrman = AddressManagerBehavior.GetAddrman(this.AddNodeNodeGroup.NodeConnectionParameters);

            addrman.Add(new NetworkAddress(endpoint));
            this.AddNodeNodeGroup.MaximumNodeConnection++;
        }
예제 #2
0
        /// <summary>
        /// Connect to a random node on the network
        /// </summary>
        /// <param name="network">The network to connect to</param>
        /// <param name="parameters">The parameters used by the found node, use AddressManagerBehavior.GetAddrman for finding peers</param>
        /// <param name="connectedAddresses">The already connected addresses, the new address will be select outside of existing groups</param>
        /// <returns></returns>
        public static Node Connect(NetworkInfo network, NodeConnectionParameters parameters = null, IPAddress[] connectedAddresses = null)
        {
            connectedAddresses = connectedAddresses ?? new IPAddress[0];
            parameters         = parameters ?? new NodeConnectionParameters();
            var            addrman = AddressManagerBehavior.GetAddrman(parameters) ?? new AddressManager();
            DateTimeOffset start   = DateTimeOffset.UtcNow;

            while (true)
            {
                parameters.ConnectCancellation.ThrowIfCancellationRequested();
                if (addrman.Count == 0 || DateTimeOffset.UtcNow - start > TimeSpan.FromSeconds(10))
                {
                    addrman.DiscoverPeers(network, parameters);
                    start = DateTimeOffset.UtcNow;
                }
                NetworkAddress addr = null;
                while (true)
                {
                    addr = addrman.Select();
                    if (addr == null)
                    {
                        break;
                    }
                    if (!addr.Endpoint.Address.IsValid())
                    {
                        continue;
                    }
                    var groupExist = connectedAddresses.Any(a => a.GetGroup().SequenceEqual(addr.Endpoint.Address.GetGroup()));
                    if (groupExist)
                    {
                        continue;
                    }
                    break;
                }
                if (addr == null)
                {
                    continue;
                }
                try
                {
                    var timeout = new CancellationTokenSource(5000);
                    var param2  = parameters.Clone();
                    param2.ConnectCancellation = CancellationTokenSource.CreateLinkedTokenSource(parameters.ConnectCancellation, timeout.Token).Token;
                    var node = Node.Connect(network, addr.Endpoint, param2);
                    return(node);
                }
                catch (OperationCanceledException ex)
                {
                    if (ex.CancellationToken == parameters.ConnectCancellation)
                    {
                        throw;
                    }
                }
                catch (SocketException)
                {
                    parameters.ConnectCancellation.WaitHandle.WaitOne(500);
                }
            }
        }
예제 #3
0
        internal void StartConnecting()
        {
            if (_Disconnect.IsCancellationRequested)
            {
                return;
            }
            if (_ConnectedNodes.Count >= MaximumNodeConnection)
            {
                return;
            }
            if (_Connecting)
            {
                return;
            }
            Task.Factory.StartNew(() =>
            {
                if (Monitor.TryEnter(cs))
                {
                    _Connecting = true;
                    try
                    {
                        while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection)
                        {
                            Logs.NodeServer.LogInformation("Connected nodes {connectedNodeCount} / {maximumNodeCount} ", _ConnectedNodes.Count, MaximumNodeConnection);
                            var parameters = _ConnectionParameters.Clone();
                            parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this));
                            parameters.ConnectCancellation = _Disconnect.Token;
                            var addrman = AddressManagerBehavior.GetAddrman(parameters);

                            if (addrman == null)
                            {
                                addrman = _DefaultAddressManager;
                                AddressManagerBehavior.SetAddrman(parameters, addrman);
                            }

                            Node node = null;
                            try
                            {
                                var groupSelector = CustomGroupSelector != null ? CustomGroupSelector :
                                                    AllowSameGroup ? WellKnownGroupSelectors.ByRandom : null;

                                var connectedPeers = _ConnectedNodes.Where(n => n.Peer is { }).Select(n => n.Peer.Endpoint).ToArray();
                                node = Node.Connect(_Network, parameters, connectedPeers, groupSelector);
                                using (var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token))
                                {
                                    timeout.CancelAfter(5000);
                                    node.VersionHandshake(_Requirements, timeout.Token);
                                    Logs.NodeServer.LogInformation("Node successfully connected to and handshaked");
                                }
                            }
                            catch (OperationCanceledException ex)
                            {
                                if (_Disconnect.Token.IsCancellationRequested)
                                {
                                    break;
                                }
                                Logs.NodeServer.LogError(default, ex, "Timeout for picked node");
예제 #4
0
        public void AddNodeAddress(IPEndPoint endpoint)
        {
            this.logger.LogTrace("({0}:'{1}')", nameof(endpoint), endpoint);

            AddressManager addrman = AddressManagerBehavior.GetAddrman(this.AddNodeNodeGroup.NodeConnectionParameters);

            addrman.Add(new NetworkAddress(endpoint));
            this.AddNodeNodeGroup.MaximumNodeConnection++;

            this.logger.LogTrace("(-)");
        }
예제 #5
0
        public Server(IPAddress externalAddress, NetworkInfo network, NodeConnectionParameters nodeConnectionParameters)
        {
            _Server = new NodeServer(network, internalPort: network.DefaultPort);
            OwnResource(_Server);

            if (externalAddress != null)
            {
                var            externalEndpoint = new IPEndPoint(externalAddress, network.DefaultPort);
                AddressManager addressManager   = AddressManagerBehavior.GetAddrman(nodeConnectionParameters);
                addressManager.Add(new NetworkAddress(externalEndpoint));
                addressManager.Connected(new NetworkAddress(externalEndpoint));
                _Server.ExternalEndpoint = externalEndpoint;
            }

            _Server.InboundNodeConnectionParameters = nodeConnectionParameters;
            _Server.AllowLocalPeers = false;             //TODO

            NodeServerTrace.Information($"Server setup at {externalAddress}");
        }
예제 #6
0
 protected bool AddressManagerContains(NodeServer nodeServer, IPEndPoint ipEndPoint)
 {
     return(AddressManagerContains(AddressManagerBehavior.GetAddrman(nodeServer.InboundNodeConnectionParameters.TemplateBehaviors), ipEndPoint));
 }
예제 #7
0
 protected bool AddressManagerContains(Node node, IPEndPoint ipEndPoint)
 {
     return(AddressManagerContains(AddressManagerBehavior.GetAddrman(node), ipEndPoint));
 }
예제 #8
0
        internal void StartConnecting()
        {
            if (_Disconnect.IsCancellationRequested)
            {
                return;
            }
            if (_ConnectedNodes.Count >= MaximumNodeConnection)
            {
                return;
            }
            if (_Connecting)
            {
                return;
            }
            Task.Factory.StartNew(() =>
            {
                if (Monitor.TryEnter(cs))
                {
                    _Connecting = true;
                    TraceCorrelationScope scope = null;
                    try
                    {
                        while (!_Disconnect.IsCancellationRequested && _ConnectedNodes.Count < MaximumNodeConnection)
                        {
                            scope = scope ?? _Trace.Open();

                            NodeServerTrace.Information("Connected nodes : " + _ConnectedNodes.Count + "/" + MaximumNodeConnection);
                            var parameters = _ConnectionParameters.Clone();
                            parameters.TemplateBehaviors.Add(new NodesGroupBehavior(this));
                            parameters.ConnectCancellation = _Disconnect.Token;
                            var addrman = AddressManagerBehavior.GetAddrman(parameters);

                            if (addrman == null)
                            {
                                addrman = _DefaultAddressManager;
                                AddressManagerBehavior.SetAddrman(parameters, addrman);
                            }

                            Node node = null;
                            try
                            {
                                node        = Node.Connect(_Network, parameters, AllowSameGroup ? null : _ConnectedNodes.Select(n => n.RemoteSocketAddress).ToArray());
                                var timeout = CancellationTokenSource.CreateLinkedTokenSource(_Disconnect.Token);
                                timeout.CancelAfter(5000);
                                node.VersionHandshake(_Requirements, timeout.Token);
                                NodeServerTrace.Information("Node successfully connected to and handshaked");
                            }
                            catch (OperationCanceledException ex)
                            {
                                if (_Disconnect.Token.IsCancellationRequested)
                                {
                                    throw;
                                }
                                NodeServerTrace.Error("Timeout for picked node", ex);
                                if (node != null)
                                {
                                    node.DisconnectAsync("Handshake timeout", ex);
                                }
                            }
                            catch (Exception ex)
                            {
                                NodeServerTrace.Error("Error while connecting to node", ex);
                                if (node != null)
                                {
                                    node.DisconnectAsync("Error while connecting", ex);
                                }
                            }
                        }
                    }
                    finally
                    {
                        Monitor.Exit(cs);
                        _Connecting = false;
                        if (scope != null)
                        {
                            scope.Dispose();
                        }
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }
예제 #9
0
        public async Task Connect(NetworkInfo networkInfo)
        {
            IPAddress ipAddress = null;

            WireSerialization.Instance.Magic = networkInfo.Magic;
            NodeServerTrace.Information($"Magic is {networkInfo.Magic}");

            var natManager = new NATManager(networkInfo.DefaultPort);

#if DEBUG
            if (networkInfo.IsLANHost)
            {
                ipAddress = natManager.InternalIPAddress ?? IPAddress.Loopback;
                networkInfo.PeersToFind = 0;
            }
            else if (networkInfo.IsLANClient)
            {
                var ipAddressStr = (natManager.InternalIPAddress ?? IPAddress.Loopback).ToString();
                networkInfo.PeersToFind = 1;

                if (networkInfo.Seeds.Count == 0 && !networkInfo.Seeds.Contains(ipAddressStr))
                {
                    networkInfo.Seeds.Add(ipAddressStr);
                }
            }
            else
#endif
            if (!string.IsNullOrEmpty(networkInfo.ExternalIPAddress))
            {
                ipAddress = IPAddress.Parse(networkInfo.ExternalIPAddress);
            }
            else if (networkInfo.DisableUPnP)
            {
                StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Disabled;
            }
            else
            {
                StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Initializing;
                await natManager.Init();

                if (natManager.DeviceFound &&
                    natManager.Mapped.Value &&
                    natManager.ExternalIPVerified.HasValue &&
                    natManager.ExternalIPVerified.Value)
                {
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasValidAddress;
                    ipAddress = natManager.ExternalIPAddress;
                }
                else
                {
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasInvalidAddress;
                }
            }

            _BroadcastHubBehavior = new BroadcastHubBehavior();
            _MinerBehavior        = new MinerBehavior();

            _NodeConnectionParameters.TemplateBehaviors.Add(_BroadcastHubBehavior);
            _NodeConnectionParameters.TemplateBehaviors.Add(_MinerBehavior);
            _NodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(_BlockChain, _BroadcastHubBehavior.BroadcastHub));
            _NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_BlockChain));

            AddressManagerBehavior.GetAddrman(_NodeConnectionParameters).PeersToFind = networkInfo.PeersToFind;

            if (ipAddress != null)
            {
                _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.AdvertizeDiscover;                //parameters.Advertize = true;
                _NodeConnectionParameters.AddressFrom = new System.Net.IPEndPoint(ipAddress, networkInfo.DefaultPort);
            }
            else
            {
                _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.Discover;
            }

            if (ipAddress != null)
            {
                _Server = new Server(ipAddress, networkInfo, _NodeConnectionParameters);
                OwnResource(_Server);

                if (_Server.Start())
                {
                    NodeServerTrace.Information($"Server started at {ipAddress}:{networkInfo.DefaultPort}");
                    StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Accepting;
                }
                else
                {
                    NodeServerTrace.Information($"Could not start server at {ipAddress}:{networkInfo.DefaultPort}");
                }
            }

            if (networkInfo.Seeds.Count == 0)
            {
                NodeServerTrace.Information("No seeds defined");
            }
            else
            {
                _NodesGroup = new NodesGroup(networkInfo, _NodeConnectionParameters);
                OwnResource(_NodesGroup);

                _NodesGroup.AllowSameGroup        = true;          //TODO
                _NodesGroup.MaximumNodeConnection = networkInfo.MaximumNodeConnection;

#if TRACE
                _NodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) =>
                {
                    NodeServerTrace.Information("Peer found: " + e.Node.RemoteSocketAddress + ":" + e.Node.RemoteSocketPort);
                };
#endif

                _NodesGroup.Connect();
            }
        }
예제 #10
0
        internal Node(NetworkAddress peer, NetworkInfo network, NodeConnectionParameters parameters)
        {
            parameters = parameters ?? new NodeConnectionParameters();
            var addrman = AddressManagerBehavior.GetAddrman(parameters);

            Inbound    = false;
            _Behaviors = new NodeBehaviorsCollection(this);
            _MyVersion = parameters.CreateVersion(peer.Endpoint, network);
            Network    = network;
            _Peer      = peer;
            LastSeen   = peer.Time;

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

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

            _Connection = new NodeConnection(this, socket);
            socket.ReceiveBufferSize = parameters.ReceiveBufferSize;
            socket.SendBufferSize    = parameters.SendBufferSize;
            using (TraceCorrelation.Open())
            {
                try
                {
                    var completed = new ManualResetEvent(false);
                    var args      = new SocketAsyncEventArgs();
                    args.RemoteEndPoint = peer.Endpoint;
                    args.Completed     += (s, a) =>
                    {
                        Utils.SafeSet(completed);
                    };
                    if (!socket.ConnectAsync(args))
                    {
                        completed.Set();
                    }
                    WaitHandle.WaitAny(new WaitHandle[] { completed, parameters.ConnectCancellation.WaitHandle });
                    parameters.ConnectCancellation.ThrowIfCancellationRequested();
                    if (args.SocketError != SocketError.Success)
                    {
                        throw new SocketException((int)args.SocketError);
                    }
                    var remoteEndpoint = (IPEndPoint)(socket.RemoteEndPoint ?? args.RemoteEndPoint);
                    _RemoteSocketAddress = remoteEndpoint.Address;
                    _RemoteSocketPort    = remoteEndpoint.Port;
                    State       = NodeState.Connected;
                    ConnectedAt = DateTimeOffset.UtcNow;
                    NodeServerTrace.Information("Outbound connection successfull");
                    if (addrman != null)
                    {
                        addrman.Attempt(Peer);
                    }
                }
                catch (OperationCanceledException)
                {
                    Utils.SafeCloseSocket(socket);
                    NodeServerTrace.Information("Connection to node cancelled");
                    State = NodeState.Offline;
                    if (addrman != null)
                    {
                        addrman.Attempt(Peer);
                    }
                    throw;
                }
                catch (Exception ex)
                {
                    Utils.SafeCloseSocket(socket);
                    NodeServerTrace.Error("Error connecting to the remote endpoint ", ex);
                    DisconnectReason = new NodeDisconnectReason()
                    {
                        Reason    = "Unexpected exception while connecting to socket",
                        Exception = ex
                    };
                    State = NodeState.Failed;
                    if (addrman != null)
                    {
                        addrman.Attempt(Peer);
                    }
                    throw;
                }
                InitDefaultBehaviors(parameters);
                _Connection.BeginListen();
            }
        }