All pastes #387411 Raw Edit

tobz

public text v1 · immutable
·published 2007-03-09 10:34 UTC
rendered paste body
        /// <summary>
        /// Pass recieved data into the packet buffer and try to parse.
        /// </summary>
        /// <param name="num_bytes">number of bytes waiting to be read</param>
        protected override void OnReceive(int num_bytes)
        {
            try
            {
                short pakSize;

                // decrypt the packet if needed
                if (IsEncrypted)
                {
                    pakSize = GetExpectedLength(true);
                }
                else
                {
                    pakSize = GetExpectedLength(false);
                }

                // we received just enough data for the full message. not too litt,e not too much
                if (pakSize + 2 == num_bytes)
                {
                    byte[] fullMessage = new byte[num_bytes];

                    Array.Copy(m_inBuf, 0, fullMessage, 0, num_bytes);

                    Array.Clear(m_inBuf, 0, num_bytes);

                    m_inOffset = 0;

                    RealmPacketIn packet = new RealmPacketIn(fullMessage);

                    TryHandlePacket(packet);

                    return;
                }
                // we received an excess of data
                else if (pakSize + 2 < num_bytes)
                {
                    // get only the data we need
                    byte[] fullMessage = new byte[pakSize + 2];
                    Array.Copy(m_inBuf, 0, fullMessage, 0, pakSize + 2);

                    // shift the remaining data to the top
                    Array.Copy(m_inBuf, m_inOffset, m_inBuf, 0, m_inBuf.Length - m_inOffset);

                    // set the offset to the end of the data that was in excess
                    m_inOffset = num_bytes - (pakSize + 2);

                    RealmPacketIn packet = new RealmPacketIn(fullMessage);

                    TryHandlePacket(packet);

                    return;
                }
                else
                {
                    // partial packet. we don't touch the offset and just let it async read more data.

                    return;
                }
            }
            catch (InsufficientDataException e)
            {
                m_srvr.Warning(this, e);
            }
        }

        protected short GetExpectedLength(bool encrypted)
        {
            short pakSize;

            if (encrypted)
            {
                byte[] decryptedHeader = new byte[6];

                Array.Copy(m_inBuf, 0, decryptedHeader, 0, 6);

                DecryptHeader(decryptedHeader);

                pakSize = IPAddress.NetworkToHostOrder((short) (decryptedHeader[0] | (decryptedHeader[1] << 8)));
            }
            else
            {
                pakSize = IPAddress.NetworkToHostOrder((short) (m_inBuf[0] | (m_inBuf[1] << 8)));
            }

            return pakSize;
        }

        /// <summary>
        /// Attempts to parse the packet
        /// </summary>
        /// <param name="packet">the packet to parse</param>
        protected void TryHandlePacket(RealmPacketIn packet)
        {
            try
            {
                if (IsEncrypted)
                    Decrypt(packet, 0);

                packet.Initialize();

                if (packet.Parse(this))
                {
                }
                else
                {
                }
            }
            catch (Exception e)
            {
                m_srvr.Warning(this, e);
            }
        }

        /// <summary>
        /// Write packet out across network
        /// </summary>
        /// <param name="packet">packet to send</param>
        public virtual void Send(RealmPacketOut packet)
        {
            byte[] packetBytes = packet.GetBytes();

            Encrypt(packetBytes);
            Send(packetBytes);
        }

        /// <summary>
        /// Encrypts the byte array
        /// </summary>
        /// <param name="data">The raw packet data to encrypt</param>
        private void Encrypt(byte[] data)
        {
            if (IsEncrypted)
            {
                byte[] SS_Hash = Account.SessionKey.GetBytes(40);
                for (int t = 0; t < 4; t++)
                {
                    byte a = m_cryptKey[3];
                    a = (byte) (SS_Hash[a] ^ data[t]);
                    byte d = m_cryptKey[2];
                    a += d;
                    data[t] = a;
                    m_cryptKey[2] = a;
                    a = m_cryptKey[3];
                    a++;
                    m_cryptKey[3] = (byte) (a%40);
                }
            }
        }

        /// <summary>
        /// Decrypts the header of an incoming packet, returning to the original packet position
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="startPos"></param>
        private void Decrypt(RealmPacketIn packet, long startPos)
        {
            long endPos = packet.Position;
            packet.Position = startPos;
            byte[] header = packet.ReadBytes(6);
            DecryptHeader(header);
            packet.Position = startPos;
            packet.BaseStream.Write(header, 0, 6);
            packet.Position = endPos;
        }

        /// <summary>
        /// Decrypts the byte array
        /// </summary>
        /// <param name="data"></param>
        private void DecryptHeader(byte[] data)
        {
            byte[] SS_Hash = Account.SessionKey.GetBytes();
            for (int t = 0; t < 6; t++)
            {
                byte a = m_cryptKey[0];
                m_cryptKey[0] = data[t];

                byte b = data[t];
                b = (byte) (b - a);

                byte d = m_cryptKey[1];
                a = SS_Hash[d];
                a = (byte) (a ^ b);
                data[t] = a;

                a = m_cryptKey[1];
                a++;
                m_cryptKey[1] = (byte) (a%40);
            }
        }