Beispiel #1
0
        private static async Task <byte[]> FillBufferAsync(Stream stream, int buffer_size, CancellationToken cancellationToken)
        {
            TR.Enter();
            const int MAX_SIZE = 1024;

            byte[] buffer = new byte[buffer_size < MAX_SIZE ? buffer_size : MAX_SIZE];
            using (MemoryStream ms = new MemoryStream())
            {
                while (buffer_size > 0)
                {
                    int           count = buffer_size < MAX_SIZE ? buffer_size : MAX_SIZE;
                    IndentContext ic    = TR.SaveContextAndShuffle();
                    count = await stream.ReadAsync(buffer, 0, count, cancellationToken);

                    TR.RestoreContext(ic);
                    if (count <= 0)
                    {
                        TR.Exit();
                        throw new IOException();
                    }
                    ms.Write(buffer, 0, count);
                    buffer_size -= count;
                }
                return(TR.Exit(ms.ToArray()));
            }
        }
Beispiel #2
0
        public async Task <bool> ConnectAsync()
        {
            TR.Enter();
            IPAddress address = ListenerEndpoint.Address;

            if (address.IsIPv4MappedToIPv6)
            {
                address = address.MapToIPv4();
            }
            IndentContext ic = TR.SaveContextAndShuffle();

            try
            {
                TR.Log(ListenerEndpoint.ToString());
                await socket.ConnectAsync(address, ListenerEndpoint.Port);

                TR.RestoreContext(ic);
                OnConnected();
            }
            catch (SocketException)
            {
                TR.RestoreContext(ic);
                Disconnect(false);
                return(TR.Exit(false));
            }
            return(TR.Exit(true));
        }
Beispiel #3
0
        protected override async Task <Message> ReceiveMessageAsync(TimeSpan timeout)
        {
            await Task.Yield();

            TR.Enter();
            CancellationTokenSource source = new CancellationTokenSource(timeout);

            //Stream.ReadAsync doesn't support CancellationToken
            //see: https://stackoverflow.com/questions/20131434/cancel-networkstream-readasync-using-tcplistener
            source.Token.Register(() => Disconnect(false));
            IndentContext ic = TR.SaveContextAndShuffle();

            try
            {
                Message msg = await Message.DeserializeFromAsync(stream, source.Token);

                TR.RestoreContext(ic);
                return(TR.Exit(msg));
            }
            catch (ArgumentException) { TR.Log(); }
            catch (ObjectDisposedException) { TR.Log(); }
            catch (Exception ex) when(ex is FormatException || ex is IOException || ex is OperationCanceledException)
            {
                TR.Log();
                Disconnect(false);
            }
            finally
            {
                TR.RestoreContext(ic);
                TR.Log();
                source.Dispose();
            }
            return(TR.Exit((Message)null));
        }
Beispiel #4
0
 private IEnumerable <IPEndPoint> GetIPEndPointsFromSeedList(int seedsToTake)
 {
     TR.Log();
     if (seedsToTake > 0)
     {
         Random rand = new Random();
         foreach (string hostAndPort in Settings.Default.SeedList.OrderBy(p => rand.Next()))
         {
             if (seedsToTake == 0)
             {
                 break;
             }
             string[]      p = hostAndPort.Split(':');
             IPEndPoint    seed;
             IndentContext ic = TR.SaveContextAndShuffle();
             try
             {
                 seed = GetIPEndpointFromHostPortAsync(p[0], int.Parse(p[1])).Result;
                 TR.RestoreContext(ic);
             }
             catch (AggregateException)
             {
                 TR.RestoreContext(ic);
                 continue;
             }
             if (seed == null)
             {
                 continue;
             }
             seedsToTake--;
             yield return(TR.Log(seed));
         }
     }
     TR.Log();
 }
Beispiel #5
0
        public UInt32 CheckIndent(ParserRuleContext context, IndentContext indentCtx)
        {
            if (indentCtx is null)
            {
                return(0);
            }

            var indent = (UInt32)indentCtx.GetText().Length;

            Debug.Assert(indent < Int32.MaxValue);

            if (Indent == 0)
            {
                Indent = indent;
            }

            if (indent % Indent > 0)
            {
                CompilerContext.InvalidIndentation(context);
                // guess where it should go
                return((UInt32)Math.Round((double)indent / Indent));
            }

            return(indent / Indent);
        }
Beispiel #6
0
        public async Task ConnectToPeerAsync(IPEndPoint remoteEndpoint)
        {
            TR.Enter();
            if (remoteEndpoint.Port == Port && LocalAddresses.Contains(remoteEndpoint.Address.MapToIPv6()))
            {
                TR.Exit(); return;
            }
            lock (unconnectedPeers)
            {
                unconnectedPeers.Remove(remoteEndpoint);
            }
            lock (connectedPeers)
            {
                if (connectedPeers.Any(p => remoteEndpoint.Equals(p.ListenerEndpoint)))
                {
                    TR.Exit();
                    return;
                }
            }
            TR.Log();
            TcpRemoteNode remoteNode = new TcpRemoteNode(this, remoteEndpoint);

            TR.Log();
            IndentContext ic        = TR.SaveContextAndShuffle();
            bool          connected = await remoteNode.ConnectAsync();

            TR.RestoreContext(ic);
            if (connected)
            {
                TR.Log();
                OnConnected(remoteNode);
            }
            TR.Exit();
        }
Beispiel #7
0
        public async Task <IPEndPoint> GetIPEndpointFromHostPortAsync(string hostNameOrAddress, int port)
        {
            TR.Enter();
            if (IPAddress.TryParse(hostNameOrAddress, out IPAddress ipAddress))
            {
                ipAddress = ipAddress.MapToIPv6();
            }
            else
            {
                IPHostEntry entry;
                try
                {
                    IndentContext ic = TR.SaveContextAndShuffle();
                    entry = await Dns.GetHostEntryAsync(hostNameOrAddress);

                    TR.RestoreContext(ic);
                }
                catch (SocketException)
                {
                    return(TR.Exit((IPEndPoint)null));
                }
                ipAddress = entry.AddressList.FirstOrDefault(p => p.AddressFamily == AddressFamily.InterNetwork || p.IsIPv6Teredo)?.MapToIPv6();
                if (ipAddress == null)
                {
                    return(TR.Exit((IPEndPoint)null));
                }
            }

            return(TR.Exit(new IPEndPoint(ipAddress, port)));
        }
Beispiel #8
0
        private async void AcceptPeers()
        {
#if !NET47
            //There is a bug in .NET Core 2.0 that blocks async method which returns void.
            await Task.Yield();
#endif
            TR.Enter();
            while (!cancellationTokenSource.IsCancellationRequested)
            {
                Socket        socket;
                IndentContext ic = TR.SaveContextAndShuffle();
                try
                {
                    socket = await listener.AcceptSocketAsync();
                }
                catch (ObjectDisposedException)
                {
                    break;
                }
                catch (SocketException)
                {
                    continue;
                }
                finally
                {
                    TR.RestoreContext(ic);
                }
                TcpRemoteNode remoteNode = new TcpRemoteNode(this, socket);
                OnConnected(remoteNode);
            }
            TR.Exit();
        }
Beispiel #9
0
        public static async Task <Message> DeserializeFromAsync(Stream stream, CancellationToken cancellationToken)
        {
            TR.Enter();
            uint          payload_length;
            IndentContext ic = TR.SaveContextAndShuffle();

            byte[] buffer = await FillBufferAsync(stream, 24, cancellationToken);

            TR.RestoreContext(ic);
            Message message = new Message();

            using (MemoryStream ms = new MemoryStream(buffer, false))
                using (BinaryReader reader = new BinaryReader(ms, Encoding.UTF8))
                {
                    if (reader.ReadUInt32() != Magic)
                    {
                        TR.Exit();
                        throw new FormatException();
                    }
                    message.Command = reader.ReadFixedString(12);
                    payload_length  = reader.ReadUInt32();
                    if (payload_length > PayloadMaxSize)
                    {
                        TR.Exit();
                        throw new FormatException();
                    }
                    message.Checksum = reader.ReadUInt32();
                }
            if (payload_length > 0)
            {
                ic = TR.SaveContextAndShuffle();
                message.Payload = await FillBufferAsync(stream, (int)payload_length, cancellationToken);

                TR.RestoreContext(ic);
            }
            else
            {
                message.Payload = new byte[0];
            }
            if (GetChecksum(message.Payload) != message.Checksum)
            {
                TR.Exit();
                throw new FormatException();
            }
            return(TR.Exit(message));
        }
Beispiel #10
0
        private async Task ProcessWebSocketAsync(HttpContext context)
        {
            TR.Enter();
            if (!context.WebSockets.IsWebSocketRequest)
            {
                TR.Exit();
                return;
            }
            IndentContext ic = TR.SaveContextAndShuffle();
            WebSocket     ws = await context.WebSockets.AcceptWebSocketAsync();

            TR.RestoreContext(ic);
            WebSocketRemoteNode remoteNode = new WebSocketRemoteNode(this, ws, new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort));

            OnConnected(remoteNode);
            TR.Exit();
        }
Beispiel #11
0
        private async void StartSendLoop()
        {
#if !NET47
            //There is a bug in .NET Core 2.0 that blocks async method which returns void.
            await Task.Yield();
#endif
            TR.Enter();
            while (disposed == 0)
            {
                Message message = null;
                lock (message_queue_high)
                {
                    if (message_queue_high.Count > 0)
                    {
                        message = message_queue_high.Dequeue();
                    }
                }
                if (message == null)
                {
                    lock (message_queue_low)
                    {
                        if (message_queue_low.Count > 0)
                        {
                            message = message_queue_low.Dequeue();
                        }
                    }
                }
                if (message == null)
                {
                    for (int i = 0; i < 10 && disposed == 0; i++)
                    {
                        Thread.Sleep(100);
                    }
                }
                else
                {
                    IndentContext ic = TR.SaveContextAndShuffle();
                    await SendMessageAsync(message);

                    TR.RestoreContext(ic);
                }
            }
            TR.Exit();
        }
Beispiel #12
0
 public static void RestoreContext(IndentContext iu)
 {
 }
Beispiel #13
0
        internal async void StartProtocol()
        {
#if !NET47
            //There is a bug in .NET Core 2.0 that blocks async method which returns void.
            await Task.Yield();
#endif
            TR.Enter();

            bool          messageSent = false;
            IndentContext ic          = TR.SaveContextAndShuffle();
            try
            {
                TR.Log("message : {0} to {1}", "version", RemoteEndpoint.Address);
                messageSent = await SendMessageAsync(Message.Create("version", VersionPayload.Create(localNode.Port, localNode.Nonce, localNode.UserAgent)));
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (!messageSent)
            {
                TR.Exit();
                return;
            }
            Message message = null;
            ic = TR.SaveContextAndShuffle();
            try
            {
                message = await ReceiveMessageAsync(HalfMinute);
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (message == null)
            {
                return;
            }
            TR.Log("message : {0} from {1}", message.Command, RemoteEndpoint.Address);
            if (message.Command != "version")
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            try
            {
                Version = message.Payload.AsSerializable <VersionPayload>();
            }
            catch (EndOfStreamException)
            {
                TR.Log();
                Disconnect(false);
                TR.Exit();
                return;
            }
            catch (FormatException)
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            if (Version.Nonce == localNode.Nonce)
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            bool isSelf;
            lock (localNode.connectedPeers)
            {
                isSelf = localNode.connectedPeers.Where(p => p != this).Any(p => p.RemoteEndpoint.Address.Equals(RemoteEndpoint.Address) && p.Version?.Nonce == Version.Nonce);
            }
            if (isSelf)
            {
                TR.Log();
                Disconnect(false);
                TR.Exit();
                return;
            }
            if (ListenerEndpoint == null && Version.Port > 0)
            {
                ListenerEndpoint = new IPEndPoint(RemoteEndpoint.Address, Version.Port);
            }

            ic = TR.SaveContextAndShuffle();
            try
            {
                messageSent = await SendMessageAsync(Message.Create("verack"));

                TR.Log("message : {0} to {1}", "verack", RemoteEndpoint.Address);
            }
            finally
            {
                TR.RestoreContext(ic);
            }
            if (!messageSent)
            {
                TR.Exit();
                return;
            }
            ic = TR.SaveContextAndShuffle();
            try
            {
                message = await ReceiveMessageAsync(HalfMinute);
            }
            finally
            {
                TR.RestoreContext(ic);
            }

            if (message == null)
            {
                TR.Exit();
                return;
            }
            TR.Log("message : {0} from {1}", message.Command, RemoteEndpoint.Address);
            if (message.Command != "verack")
            {
                TR.Log();
                Disconnect(true);
                TR.Exit();
                return;
            }
            if (Blockchain.Default?.HeaderHeight < Version.StartHeight)
            {
                TR.Log("local header height : {0}, remote height : {1}, {2}", Blockchain.Default?.HeaderHeight, Version.StartHeight, RemoteEndpoint.Address);
                EnqueueMessage("getheaders", GetBlocksPayload.Create(Blockchain.Default.CurrentHeaderHash));
                TR.Log("current header hash : {0}", Blockchain.Default.CurrentHeaderHash.ToString());
            }
            StartSendLoop();
            while (disposed == 0)
            {
                if (Blockchain.Default != null)
                {
                    if (missions.Count == 0 && Blockchain.Default.Height < Version.StartHeight)
                    {
                        TR.Log("local height : {0}, remote height : {1}, {2}", Blockchain.Default.Height, Version.StartHeight, RemoteEndpoint.Address);
                        EnqueueMessage("getblocks", GetBlocksPayload.Create(Blockchain.Default.CurrentBlockHash));
                    }
                }
                TimeSpan timeout = missions.Count == 0 ? HalfHour : OneMinute;
                ic = TR.SaveContextAndShuffle();
                try
                {
                    message = await ReceiveMessageAsync(timeout);
                }
                finally
                {
                    TR.RestoreContext(ic);
                }
                if (message == null)
                {
                    break;
                }
                if (DateTime.Now - mission_start > OneMinute &&
                    message.Command != "block" && message.Command != "consensus" && message.Command != "tx")
                {
                    TR.Log();
                    Disconnect(false);
                    break;
                }
                try
                {
                    OnMessageReceived(message);
                }
                catch (EndOfStreamException)
                {
                    TR.Log();
                    Disconnect(false);
                    break;
                }
                catch (FormatException)
                {
                    TR.Log();
                    Disconnect(true);
                    break;
                }
            }
            TR.Exit();
        }
Beispiel #14
0
        private void ConnectToPeersLoop()
        {
            TR.Enter();
            Dictionary <Task, IPAddress> tasksDict = new Dictionary <Task, IPAddress>();
            DateTime lastSufficientPeersTimestamp  = DateTime.UtcNow;
            Dictionary <IPAddress, Task> currentlyConnectingIPs = new Dictionary <IPAddress, Task>();

            void connectToPeers(IEnumerable <IPEndPoint> ipEndPoints)
            {
                TR.Enter();
                foreach (var ipEndPoint in ipEndPoints)
                {
                    // Protect from the case same IP is in the endpoint array twice
                    if (currentlyConnectingIPs.ContainsKey(ipEndPoint.Address))
                    {
                        continue;
                    }

                    TR.Log(ipEndPoint.ToString());
                    IndentContext iu          = TR.SaveContextAndShuffle();
                    var           connectTask = ConnectToPeerAsync(ipEndPoint);
                    TR.RestoreContext(iu);

                    // Completed tasks that run synchronously may use a non-unique cached task object.
                    if (connectTask.IsCompleted)
                    {
                        continue;
                    }

                    tasksDict.Add(connectTask, ipEndPoint.Address);
                    currentlyConnectingIPs.Add(ipEndPoint.Address, connectTask);
                }
                TR.Exit();
            }

            while (!cancellationTokenSource.IsCancellationRequested)
            {
                int connectedCount   = connectedPeers.Count;
                int unconnectedCount = unconnectedPeers.Count;
                if (connectedCount < ConnectedMax)
                {
                    if (unconnectedCount > 0)
                    {
                        IPEndPoint[] endpoints;
                        lock (unconnectedPeers)
                        {
                            endpoints = unconnectedPeers.Where(x => !currentlyConnectingIPs.ContainsKey(x.Address))
                                        .Take(ConnectedMax - connectedCount).ToArray();
                        }

                        connectToPeers(endpoints);
                    }

                    if (connectedCount > 0)
                    {
                        if (unconnectedCount + connectedCount < DesiredAvailablePeers)
                        {
                            lock (connectedPeers)
                            {
                                foreach (RemoteNode node in connectedPeers)
                                {
                                    node.RequestPeers();
                                }
                            }

                            if (lastSufficientPeersTimestamp < DateTime.UtcNow.AddSeconds(-180))
                            {
                                IEnumerable <IPEndPoint> endpoints = GetIPEndPointsFromSeedList(2);
                                connectToPeers(endpoints);
                                lastSufficientPeersTimestamp = DateTime.UtcNow;
                            }
                        }
                        else
                        {
                            lastSufficientPeersTimestamp = DateTime.UtcNow;
                        }
                    }
                    else
                    {
                        IEnumerable <IPEndPoint> endpoints = GetIPEndPointsFromSeedList(5);
                        connectToPeers(endpoints);
                        lastSufficientPeersTimestamp = DateTime.UtcNow;
                    }
                }

                try
                {
                    var tasksArray = tasksDict.Keys.ToArray();
                    if (tasksArray.Length > 0)
                    {
                        Task.WaitAny(tasksArray, 5000, cancellationTokenSource.Token);

                        foreach (var task in tasksArray)
                        {
                            if (!task.IsCompleted)
                            {
                                continue;
                            }
                            if (tasksDict.TryGetValue(task, out IPAddress ip))
                            {
                                currentlyConnectingIPs.Remove(ip);
                            }
                            // Clean-up task no longer running.
                            tasksDict.Remove(task);
                            task.Dispose();
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    break;
                }

                for (int i = 0; i < 50 && !cancellationTokenSource.IsCancellationRequested; i++)
                {
                    Thread.Sleep(100);
                }
            }
            TR.Log("ConnectToPeersLoop() exit!!!");
            TR.Exit();
        }