Exemplo n.º 1
0
        private void ListenerLoop()
        {
            try
            {
                NetworkStream ns = _tcpClient.GetStream();

                while (ns.CanRead)
                {
                    #region Read header and payload from network

                    Header  header;
                    Payload payload;
                    try
                    {
                        header  = new Header(BinaryReader);
                        payload =
                            (header.Length == 0)
                                                        ? new Payload(header.Command, null)
                                                        : new Payload(header.Command, BinaryReader.ReadBytes(header.Length));
                    }
                    catch (Exception e)
                    {
                        string excptionStr = e.ToString();
                        if ((e is IOException) || (e is SocketException))
                        {
                            excptionStr = "";
                        }
                        Debug.WriteLine("соединение " + NetworkAddress + " потерено " + excptionStr);
                        Bitmessage.NodeIsDisconnected.Set();
                        break;
                    }

                    #endregion Read header and payload from network

                    bool checksum = header.Checksum.SequenceEqual(payload.Checksum());

                    if (checksum && payload.IsValid)
                    {
                        debug("Command=" + header.Command);

                        #region Save payload to Inventory

                        if ((header.Command == "msg") || (header.Command == "pubkey") || (header.Command == "broadcast") || (header.Command == "getpubkey"))
                        {
                            _nodeConnectionInventory.Insert(payload.InventoryVector);
                            payload.SaveAsync(Bitmessage);
                        }

                        #endregion Save to Inventory

                        #region VERSION

                        if (header.Command == "version")
                        {
                            var v = new Version(payload);
                            debug("Подключились с " + v.UserAgent);
                            if ((v.Value != 1) && (v.Value != 2))
                            {
                                Stop("Version = " + v.Value);
                            }
                            else if (v.Nonce == Version.EightBytesOfRandomDataUsedToDetectConnectionsToSelf)
                            {
                                Bitmessage.DeleteNode(NetworkAddress);
                                Stop("DetectConnectionsToSelf");
                            }
                            else
                            {
                                Send(new Verack());
                            }
                        }

                        #endregion VERSION

                        #region INV

                        else if (header.Command == "inv")
                        {
                            var inputInventory = new Inv(payload.SentData);
                            var buff4GetData   = new MemoryInventory(inputInventory.Count);

                            debug("прислали inv. Inventory.Count=" + inputInventory.Count);

                            //lock (Bitmessage.MemoryInventory)
                            //{
                            foreach (byte[] inventoryVector in inputInventory)
                            {
                                _nodeConnectionInventory.Insert(inventoryVector);
                                if (!Bitmessage.MemoryInventory.Exists(inventoryVector))
                                {
                                    Bitmessage.MemoryInventory.AddWait(inventoryVector);
                                    buff4GetData.Insert(inventoryVector);
                                }
                            }
                            //}

                            if (buff4GetData.Count > 0)
                            {
                                debug("SendGetdata count=" + buff4GetData.Count);
                                Send(new GetData(buff4GetData));
                            }
                            else
                            {
                                debug("All know, don't send GetData");
                            }
                        }

                        #endregion

                        #region verack

                        else if (header.Command == "verack")
                        {
                            Send(new Inv(Bitmessage.MemoryInventory));

                            NetworkAddress.TimeLastSeen = DateTime.UtcNow;
                            NetworkAddress.SaveAsync(Bitmessage.DB);
                        }

                        #endregion

                        #region getpubkey

                        else if (header.Command == "getpubkey")
                        {
                            var getpubkey = new GetPubkey(payload);

                            PrivateKey pk = Bitmessage.FindPrivateKey(getpubkey);
                            if ((pk != null) &&
                                (pk.LastPubkeySendTime.ToUnix() <
                                 (DateTime.UtcNow.ToUnix() - Payload.LengthOfTimeToHoldOnToAllPubkeys)))
                            {
                                pk.SendAsync(Bitmessage);
                            }
                        }

                        #endregion getpubkey

                        #region pubkey

                        else if (header.Command == "pubkey")
                        {
                            int pos    = payload.FirstByteAfterTime;
                            var pubkey = new Pubkey(payload.SentData, ref pos, true);

                            if (pubkey.Status == Status.Valid)
                            {
                                pubkey.SaveAsync(Bitmessage.DB);
                                Bitmessage.OnReceivePubkey(pubkey);
                            }
                            else
                            {
                                Bitmessage.OnReceiveInvalidPubkey(pubkey);
                            }
                        }

                        #endregion PUBKEY

                        #region msg

                        else if (header.Command == "msg")
                        {
                            var msg = new Msg(Bitmessage, payload);
                            msg.SaveAsync(Bitmessage.DB);

                            if (msg.Status == Status.Valid)
                            {
                                Bitmessage.OnReceiveMsg(msg);
                            }
                            else
                            {
                                Bitmessage.OnReceiveInvalidMsg(msg);
                            }
                        }

                        #endregion MSG

                        #region broadcast

                        else if (header.Command == "broadcast")
                        {
                            var broadcast = new Broadcast(Bitmessage, payload);
                            broadcast.SaveAsync(Bitmessage.DB);

                            if (broadcast.Status == Status.Valid)
                            {
                                Bitmessage.OnReceiveBroadcast(broadcast);
                            }
                            else
                            {
                                Bitmessage.OnReceiveInvalidBroadcast(broadcast);
                            }
                        }

                        #endregion BROADCAST

                        #region addr

                        else if (header.Command == "addr")
                        {
                            int    pos = 0;
                            UInt64 numberOfAddressesIncluded = payload.SentData.ReadVarInt(ref pos);
                            if ((numberOfAddressesIncluded > 0) && (numberOfAddressesIncluded < 1001))
                            {
                                if (payload.Length != (pos + (38 * (int)numberOfAddressesIncluded)))
                                {
                                    throw new Exception(
                                              "addr message does not contain the correct amount of data. Ignoring.");
                                }

                                while (pos < payload.Length)
                                {
                                    NetworkAddress networkAddress = NetworkAddress.GetFromAddrList(payload.SentData,
                                                                                                   ref pos);
                                    Bitmessage.AddNode(networkAddress);
                                }
                            }
                        }

                        #endregion addr

                        #region getdata

                        else if (header.Command == "getdata")
                        {
                            debug("Load getdata");
                            var getData = new GetData(payload.SentData);

                            foreach (byte[] hash in getData.Inventory)
                            {
                                Payload.SendAsync(this, hash.ToHex(false));
                            }
                        }

                        #endregion getdata

                        #region ping

                        else if (header.Command == "ping")
                        {
                            Send(new Pong());
                        }

                        #endregion ping

                        #region pong

                        else if (header.Command == "pong")
                        {
                        }

                        #endregion pong

                        else
                        {
                            debug("unknown command");
                        }
                    }
                    else
                    {
                        debug("checksum error");
                    }
                }
                _tcpClient.Close();
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch (Exception e)
            {
                debug("Закрываю соединение " + e);
            }             // ReSharper restore EmptyGeneralCatchClause

            Bitmessage.NodeIsDisconnected.Set();
        }