Esempio n. 1
0
        // Transfers raw incoming data into the security object. Call TransferIncoming to
        // obtain a list of ready to process packets.
        public void Recv(TransferBuffer raw_buffer)
        {
            List<TransferBuffer> incoming_buffers_tmp = new List<TransferBuffer>();
            lock (m_class_lock)
            {
                int length = raw_buffer.Size - raw_buffer.Offset;
                int index = 0;
                while (length > 0)
                {
                    int max_length = length;
                    int calc_length = m_recv_buffer.Buffer.Length - m_recv_buffer.Size;

                    if (max_length > calc_length)
                    {
                        max_length = calc_length;
                    }
                    length -= max_length;

                    Buffer.BlockCopy(raw_buffer.Buffer, raw_buffer.Offset + index, m_recv_buffer.Buffer, m_recv_buffer.Size, max_length);

                    m_recv_buffer.Size += max_length;
                    index += max_length;

                    // Loop while we have data to process
                    while (m_recv_buffer.Size > 0)
                    {
                        // If we do not have a current packet object, try to allocate one.
                        if (m_current_buffer == null)
                        {
                            // We need at least two bytes to allocate a packet.
                            if (m_recv_buffer.Size < 2)
                            {
                                break;
                            }

                            // Calculate the packet size.
                            int packet_size = m_recv_buffer.Buffer[1] << 8 | m_recv_buffer.Buffer[0];

                            // Check to see if this packet is encrypted.
                            if ((packet_size & 0x8000) > 0)
                            {
                                // If so, calculate the total payload size.
                                packet_size &= 0x7FFF; // Mask off the encryption.
                                if (m_security_flags.blowfish == 1)
                                {
                                    packet_size = 2 + m_blowfish.GetOutputLength(packet_size + 4);
                                }
                                else
                                {
                                    packet_size += 6;
                                }
                            }
                            else
                            {
                                // The packet is unencrypted. The final size is simply
                                // header size + payload size.
                                packet_size += 6;
                            }

                            // Allocate the final buffer the packet will be written to
                            m_current_buffer = new TransferBuffer(packet_size, 0, packet_size);
                        }

                        // Calculate how many bytes are left to receive in the packet.
                        int max_copy_count = m_current_buffer.Size - m_current_buffer.Offset;

                        // If we need more bytes than we currently have, update the size.
                        if (max_copy_count > m_recv_buffer.Size)
                        {
                            max_copy_count = m_recv_buffer.Size;
                        }

                        // Copy the buffer data to the packet buffer
                        Buffer.BlockCopy(m_recv_buffer.Buffer, 0, m_current_buffer.Buffer, m_current_buffer.Offset, max_copy_count);

                        // Update how many bytes we now have
                        m_current_buffer.Offset += max_copy_count;
                        m_recv_buffer.Size -= max_copy_count;

                        // If there is data remaining in the buffer, copy it over the data
                        // we just removed (sliding buffer).
                        if (m_recv_buffer.Size > 0)
                        {
                            Buffer.BlockCopy(m_recv_buffer.Buffer, max_copy_count, m_recv_buffer.Buffer, 0, m_recv_buffer.Size);
                        }

                        // Check to see if the current packet is now complete.
                        if (m_current_buffer.Size == m_current_buffer.Offset)
                        {
                            // If so, dispatch it to the manager class for processing by the system.
                            m_current_buffer.Offset = 0;
                            incoming_buffers_tmp.Add(m_current_buffer);

                            // Set the current packet to null so we can process the next packet
                            // in the stream.
                            m_current_buffer = null;
                        }
                        else
                        {
                            // Otherwise, we are done with this loop, since we need more
                            // data for the current packet.
                            break;
                        }
                    }
                }

                if (incoming_buffers_tmp.Count > 0)
                {
                    foreach (TransferBuffer buffer in incoming_buffers_tmp)
                    {
                        PacketReader packet_data = null;
                        try
                        {
                            bool packet_encrypted = false;

                            int packet_size = buffer.Buffer[1] << 8 | buffer.Buffer[0];
                            if ((packet_size & 0x8000) > 0)
                            {
                                if (m_security_flags.blowfish == 1)
                                {
                                    packet_size &= 0x7FFF;
                                    packet_encrypted = true;
                                }
                                else
                                {
                                    packet_size &= 0x7FFF;
                                }
                            }

                            if (packet_encrypted)
                            {
                                byte[] decrypted = m_blowfish.Decode(buffer.Buffer, 2, buffer.Size - 2);
                                byte[] new_buffer = new byte[6 + packet_size];
                                Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, new_buffer, 0, 2);
                                Buffer.BlockCopy(decrypted, 0, new_buffer, 2, 4 + packet_size);
                                buffer.Buffer = null;
                                buffer.Buffer = new_buffer;
                            }

                            packet_data = new PacketReader(buffer.Buffer);
                            packet_size = packet_data.ReadUInt16();
                            ushort packet_opcode = packet_data.ReadUInt16();
                            byte packet_security_count = packet_data.ReadByte();
                            byte packet_security_crc = packet_data.ReadByte();

                            // Client object whose bytes the server might need to verify
                            if (m_client_security)
                            {
                                if (m_security_flags.security_bytes == 1)
                                {
                                    byte expected_count = GenerateCountByte(true);
                                    if (packet_security_count != expected_count)
                                    {
                                        throw (new Exception("[SecurityAPI::Recv] Count byte mismatch."));
                                    }

                                    if (packet_encrypted || (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0))
                                    {
                                        if (packet_encrypted || m_enc_opcodes.Contains(packet_opcode))
                                        {
                                            packet_size |= 0x8000;
                                            Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, buffer.Buffer, 0, 2);
                                        }
                                    }

                                    buffer.Buffer[5] = 0;

                                    byte expected_crc = GenerateCheckByte(buffer.Buffer);
                                    if (packet_security_crc != expected_crc)
                                    {
                                        throw (new Exception("[SecurityAPI::Recv] CRC byte mismatch."));
                                    }

                                    buffer.Buffer[4] = 0;

                                    if (packet_encrypted || (m_security_flags.security_bytes == 1 && m_security_flags.blowfish == 0))
                                    {
                                        if (packet_encrypted || m_enc_opcodes.Contains(packet_opcode))
                                        {
                                            packet_size &= 0x7FFF;
                                            Buffer.BlockCopy(BitConverter.GetBytes((ushort)packet_size), 0, buffer.Buffer, 0, 2);
                                        }
                                    }
                                }
                            }

                            if (packet_opcode == 0x5000 || packet_opcode == 0x9000) // New logic processing!
                            {
                                Handshake(packet_opcode, packet_data, packet_encrypted);

                                // Pass the handshake packets to the user so they can at least see them.
                                // They do not need to actually do anything with them. This was added to
                                // help debugging and make output logs complete.

                                //CA2000 dont care
                                Packet packet = new Packet(packet_opcode, packet_encrypted, false, buffer.Buffer, 6, packet_size);
                                packet.Lock();
                                m_incoming_packets.Add(packet);
                            }
                            else
                            {
                                if (m_client_security)
                                {
                                    // Make sure the client accepted the security system first
                                    if (!m_accepted_handshake)
                                    {
                                        throw (new Exception("[SecurityAPI::Recv] The client has not accepted the handshake."));
                                    }
                                }
                                if (packet_opcode == 0x600D) // Auto process massive messages for the user
                                {
                                    byte mode = packet_data.ReadByte();
                                    if (mode == 1)
                                    {
                                        m_massive_count = packet_data.ReadUInt16();
                                        ushort contained_packet_opcode = packet_data.ReadUInt16();
                                        m_massive_packet = new Packet(contained_packet_opcode, packet_encrypted, true);
                                    }
                                    else
                                    {
                                        if (m_massive_packet == null)
                                        {
                                            throw (new Exception("[SecurityAPI::Recv] A malformed 0x600D packet was received."));
                                        }
                                        m_massive_packet.WriteUInt8Array(packet_data.ReadBytes(packet_size - 1));
                                        m_massive_count--;
                                        if (m_massive_count == 0)
                                        {
                                            m_massive_packet.Lock();
                                            m_incoming_packets.Add(m_massive_packet);
                                            m_massive_packet = null;
                                        }
                                    }
                                }
                                else
                                {
                                    //CA2000 dont care
                                    Packet packet = new Packet(packet_opcode, packet_encrypted, false, buffer.Buffer, 6, packet_size);
                                    packet.Lock();
                                    m_incoming_packets.Add(packet);
                                }
                            }
                        }
                        finally
                        {
                            if (packet_data != null)
                            {
                                packet_data.Close();
                            }
                        }
                    }
                }
            }
        }