Beispiel #1
0
        public void Listen(int maxIncoming = 8)
        {
            if (this.socket != null)
            {
                throw new InvalidOperationException("Already listening");
            }

            using (this.trace.Open())
            {
                try
                {
                    this.socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
                    this.socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);

                    this.socket.Bind(this.LocalEndpoint);
                    this.socket.Listen(maxIncoming);
                    NodeServerTrace.Information("Listening...");
                    this.BeginAccept();
                }
                catch (Exception ex)
                {
                    NodeServerTrace.Error("Error while opening the Protocol server", ex);
                    throw;
                }
            }
        }
Beispiel #2
0
        public void Dispose()
        {
            if (!this.cancel.IsCancellationRequested)
            {
                this.cancel.Cancel();
                this.trace.LogInside(() => NodeServerTrace.Information("Stopping network peer server..."));
                lock (this.resources)
                {
                    foreach (IDisposable resource in this.resources)
                    {
                        resource.Dispose();
                    }
                }

                try
                {
                    this.ConnectedNetworkPeers.DisconnectAll();
                }
                finally
                {
                    if (this.socket != null)
                    {
                        Utils.SafeCloseSocket(this.socket);
                        this.socket = null;
                    }
                }
            }
        }
Beispiel #3
0
 internal void ExternalAddressDetected(IPAddress ipAddress)
 {
     if (!this.ExternalEndpoint.Address.IsRoutable(this.AllowLocalPeers) && ipAddress.IsRoutable(this.AllowLocalPeers))
     {
         NodeServerTrace.Information("New externalAddress detected " + ipAddress);
         this.ExternalEndpoint = new IPEndPoint(ipAddress, this.ExternalEndpoint.Port);
     }
 }
Beispiel #4
0
        public async Task <bool> EnsureMapping()
        {
            NodeServerTrace.Information("EnsureMapping");

            var device = await GetNatDeviceAsync();

            return(device == null ? false : await device.GetSpecificMappingAsync(Protocol.Tcp, _ServerPort).ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    NodeServerTrace.Error("GetExternalIP", t.Exception);
                    return false;
                }

                var mapping = t.Result;

                try
                {
                    if (mapping != null && !mapping.PrivateIP.Equals(InternalIPAddress))
                    {
                        NodeServerTrace.Information($"existing mapping mismatch. got: {mapping.PrivateIP}, need: {InternalIPAddress}");

                        _NatDevice.DeletePortMapAsync(mapping).Wait();
                        mapping = null;
                    }

                    if (mapping == null)
                    {
                        NodeServerTrace.Information($"creaing mapping with IP: {InternalIPAddress}");

                        _NatDevice.CreatePortMapAsync(
                            new Mapping(
                                Protocol.Tcp,
                                InternalIPAddress,
                                _ServerPort,
                                _ServerPort,
                                0,                                 //TODO: session lifetime?
                                MAPPING_DESC
                                )
                            ).Wait();
                    }

                    IEnumerable <Mapping> exisingMappings = _NatDevice.GetAllMappingsAsync().Result;

                    return exisingMappings.Count(exisintMapping => exisintMapping.PublicPort == _ServerPort) == 1;
                }
                catch (Exception e)
                {
                    NodeServerTrace.Error("Mapping", e);
                    return false;
                }
            }));
        }
Beispiel #5
0
 public bool Start()
 {
     try
     {
         _Server.Listen();
         NodeServerTrace.Information("Server listening");
         return(true);
     }
     catch (Exception e)
     {
         NodeServerTrace.Error("Listen", e);
     }
     return(false);
 }
Beispiel #6
0
        private void BeginAccept()
        {
            if (this.cancel.IsCancellationRequested)
            {
                NodeServerTrace.Information("Stop accepting connection...");
                return;
            }

            NodeServerTrace.Information("Accepting connection...");
            var args = new SocketAsyncEventArgs();

            args.Completed += Accept_Completed;
            if (!this.socket.AcceptAsync(args))
            {
                this.EndAccept(args);
            }
        }
Beispiel #7
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}");
        }
Beispiel #8
0
        public NATManager(int serverPort)         //TODO: check internet connection is active
        {
            IPAddress[] PrivateIPs = NBitcoin.Utils.GetAllLocalIPv4();

            _ServerPort = serverPort;

            if (PrivateIPs.Count() == 0)
            {
                NodeServerTrace.Information("Warning, local addresses not found");
                InternalIPAddress = null;
            }
            else
            {
                InternalIPAddress = PrivateIPs.First();

                if (PrivateIPs.Count() > 1)
                {
                    NodeServerTrace.Information("Warning, found " + PrivateIPs.Count() + " internal addresses");
                }
            }
        }
Beispiel #9
0
 private void FireCallbacks(List <Operation> operations)
 {
     foreach (var operation in operations)
     {
         var newOperation = this.NewOperation;
         if (newOperation != null)
         {
             foreach (var handler in newOperation.GetInvocationList().Cast <NewTrackerOperation>())
             {
                 try
                 {
                     handler.DynamicInvoke(this, operation);
                 }
                 catch (TargetInvocationException ex)
                 {
                     NodeServerTrace.Error("Error while calling Tracker callback", ex.InnerException);
                 }
             }
         }
     }
 }
Beispiel #10
0
        public async Task <NatDevice> GetNatDeviceAsync()
        {
            var nat = new NatDiscoverer();
            var cts = new CancellationTokenSource(TIMEOUT);

            if (_NatDevice != null)
            {
                return(_NatDevice);
            }

            await _SemaphoreSlim.WaitAsync();

            NodeServerTrace.Information("NAT Device discovery started");

            return(await nat.DiscoverDeviceAsync(PortMapper.Upnp, cts).ContinueWith(t =>
            {
                _SemaphoreSlim.Release();
                DeviceFound = t.Status != TaskStatus.Faulted;

                if (!DeviceFound)
                {
                    NodeServerTrace.Information("NAT Device not found");

                    HasError = !(t.Exception.InnerException is NatDeviceNotFoundException);

                    if (HasError)
                    {
                        NodeServerTrace.Error("NAT Device discovery", t.Exception);
                    }
                    return null;
                }
                else
                {
                    _NatDevice = t.Result;
                }

                return _NatDevice;
            }));
        }
Beispiel #11
0
        public async Task <bool> VerifyExternalIP()
        {
            NodeServerTrace.Information("VerifyExternalIP");

            var device = await GetNatDeviceAsync();

            return(device == null ? false : await device.GetExternalIPAsync().ContinueWith(t =>
            {
                if (t.IsFaulted)
                {
                    NodeServerTrace.Error("GetExternalIP", t.Exception);
                    return false;
                }

                ExternalIPAddress = t.Result;

                if (ExternalIPAddress == null)
                {
                    return false;
                }

                //try
                //{
                //	IPAddress ipAddress = ExternalTestingServicesHelper.GetExternalIPAsync().Result;

                //	bool match = ipAddress.Equals(ExternalIPAddress);

                //	Trace.Information("External IP " + (match ? "match" : "do not match"));

                //	return match;
                //}
                //catch (Exception e)
                //{
                //	Trace.Error("GetExternalIP", e);
                //	return false;
                //}
                return ExternalIPAddress.IsRoutable(false);
            }));
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        private void EndAccept(SocketAsyncEventArgs args)
        {
            using (this.trace.Open())
            {
                Socket client = null;
                try
                {
                    if (args.SocketError != SocketError.Success)
                    {
                        throw new SocketException((int)args.SocketError);
                    }

                    client = args.AcceptSocket;
                    if (this.cancel.IsCancellationRequested)
                    {
                        return;
                    }

                    NodeServerTrace.Information("Client connection accepted : " + client.RemoteEndPoint);
                    var cancel = CancellationTokenSource.CreateLinkedTokenSource(this.cancel.Token);
                    cancel.CancelAfter(TimeSpan.FromSeconds(10));

                    var stream = new NetworkStream(client, false);
                    while (true)
                    {
                        if (this.ConnectedNetworkPeers.Count >= this.MaxConnections)
                        {
                            NodeServerTrace.Information("MaxConnections limit reached");
                            Utils.SafeCloseSocket(client);
                            break;
                        }
                        cancel.Token.ThrowIfCancellationRequested();

                        PerformanceCounter counter;
                        Message            message = Message.ReadNext(stream, this.Network, this.Version, cancel.Token, out counter);
                        this.messageProducer.PushMessage(new IncomingMessage()
                        {
                            Socket      = client,
                            Message     = message,
                            Length      = counter.ReadBytes,
                            NetworkPeer = null,
                        });

                        if (message.Payload is VersionPayload)
                        {
                            break;
                        }

                        NodeServerTrace.Error("The first message of the remote peer did not contained a Version payload", null);
                    }
                }
                catch (OperationCanceledException)
                {
                    Utils.SafeCloseSocket(client);
                    if (!this.cancel.Token.IsCancellationRequested)
                    {
                        NodeServerTrace.Error("The remote connecting failed to send a message within 10 seconds, dropping connection", null);
                    }
                }
                catch (Exception ex)
                {
                    if (this.cancel.IsCancellationRequested)
                    {
                        return;
                    }

                    if (client == null)
                    {
                        NodeServerTrace.Error("Error while accepting connection ", ex);
                        Thread.Sleep(3000);
                    }
                    else
                    {
                        Utils.SafeCloseSocket(client);
                        NodeServerTrace.Error("Invalid message received from the remote connecting peer", ex);
                    }
                }

                this.BeginAccept();
            }
        }
Beispiel #14
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();
            }
        }
Beispiel #15
0
        void AttachedNode_MessageReceived(Node node, IncomingMessage message)
        {
            message.IfPayloadIs <Types.Block>(async bk =>
            {
                var result = await new HandleBlockAction(bk).Publish();

                switch (result.BkResultEnum)
                {
                case BlockChain.BlockVerificationHelper.BkResultEnum.Accepted:
                    foreach (var other in Nodes)
                    {
                        if (other != AttachedNode && other.State == NodeState.HandShaked)
                        {
                            other.SendMessageAsync(bk);
                        }
                    }
                    break;

                case BlockChain.BlockVerificationHelper.BkResultEnum.AcceptedOrphan:
                    StatusMessageProducer.LastOrphan = bk.header.blockNumber;
                    node.SendMessageAsync(new GetDataPayload(new InventoryVector[] {
                        new InventoryVector(InventoryType.MSG_BLOCK, result.MissingParent)
                    }));
                    break;

                case BlockChain.BlockVerificationHelper.BkResultEnum.Rejected:
                    if (result.MissingParent != null)
                    {
                        node.SendMessageAsync(new GetDataPayload(new InventoryVector[] {
                            new InventoryVector(InventoryType.MSG_BLOCK, result.MissingParent)
                        }));
                    }

                    //TODO: refine possible state (don't reject blocks that were requested by GetTip; reply with DUPLICATE instead of INVALID, ...)
                    node.SendMessageAsync(new RejectPayload()
                    {
                        Hash    = Consensus.Merkle.blockHeaderHasher.Invoke(bk.header),
                        Code    = RejectCode.INVALID,
                        Message = "bk"
                    });
                    break;
                }
            });

            message.IfPayloadIs <GetTipPayload>(getTip =>
            {
                var tip = _BlockChain.Tip;

                if (tip != null)
                {
                    var bk = new GetBlockAction()
                    {
                        BkHash = tip.Key
                    }.Publish().Result;

                    if (bk != null)
                    {
                        NodeServerTrace.Information("Sending tip: " + tip.Value.header.blockNumber);
                        node.SendMessageAsync(bk);
                    }
                    else
                    {
                        NodeServerTrace.Information("Missing or invalid tip block requested");
                    }
                }
                else
                {
                    NodeServerTrace.Information("No tip to send");
                }
            });

            message.IfPayloadIs <GetDataPayload>(getData =>
            {
                foreach (var inventory in getData.Inventory.Where(i => i.Type == InventoryType.MSG_BLOCK))
                {
                    var bk = new GetBlockAction()
                    {
                        BkHash = inventory.Hash
                    }.Publish().Result;

                    if (bk != null)
                    {
                        NodeServerTrace.Information("Sending block: " + bk.header.blockNumber);
                        node.SendMessageAsync(bk);
                    }
                    else
                    {
                        NodeServerTrace.Information("Missing or invalid block requested");
                    }
                }
            });
        }