Пример #1
0
        public static async void HandleConnectResponse(ClientPacket packet, Session session)
        {
            ulong check = packet.Payload.ReadUInt64(); // 13626398284849559039 - sent in previous packet

            var result = await DatabaseManager.Character.SelectPreparedStatementAsync(CharacterPreparedStatement.CharacterListSelect, session.Id);

            CharacterListSelectCallback(result, session);

            // looks like account settings/info, expansion information ect? (this is needed for world entry)
            var packet75e5         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var packet75e5Fragment = new ServerPacketFragment(5, FragmentOpcode.Unknown75E5);

            packet75e5Fragment.Payload.Write(1ul);
            packet75e5Fragment.Payload.Write(1ul);
            packet75e5Fragment.Payload.Write(1ul);
            packet75e5Fragment.Payload.Write(2ul);
            packet75e5Fragment.Payload.Write(0ul);
            packet75e5Fragment.Payload.Write(1ul);
            packet75e5.Fragments.Add(packet75e5Fragment);

            NetworkManager.SendPacket(ConnectionType.Login, packet75e5, session);

            var patchStatus = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);

            patchStatus.Fragments.Add(new ServerPacketFragment(5, FragmentOpcode.PatchStatus));

            NetworkManager.SendPacket(ConnectionType.Login, patchStatus, session);
        }
Пример #2
0
        public static async void CharacterDelete(ClientPacketFragment fragment, Session session)
        {
            string account       = fragment.Payload.ReadString16L();
            uint   characterSlot = fragment.Payload.ReadUInt32();

            if (account != session.Account)
            {
                session.SendCharacterError(CharacterError.Delete);
                return;
            }

            var cachedCharacter = session.CachedCharacters.SingleOrDefault(c => c.SlotId == characterSlot);

            if (cachedCharacter == null)
            {
                session.SendCharacterError(CharacterError.Delete);
                return;
            }

            // TODO: check if character is already pending removal

            var characterDelete         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var characterDeleteFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterDelete);

            characterDelete.Fragments.Add(characterDeleteFragment);

            NetworkManager.SendPacket(ConnectionType.Login, characterDelete, session);

            DatabaseManager.Character.DeleteOrRestore(WorldManager.GetUnixTime() + 3600ul, cachedCharacter.Guid.Low);

            var result = await DatabaseManager.Character.GetByAccount(session.Id);

            AuthenticationHandler.CharacterListSelectCallback(result, session);
        }
Пример #3
0
        public void SendCharacterError(CharacterError error)
        {
            var characterError         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var characterErrorFragment = new ServerPacketFragment(0x09, GameMessageOpcode.CharacterError);

            characterErrorFragment.Payload.Write((uint)error);
            characterError.Fragments.Add(characterErrorFragment);

            NetworkManager.SendPacket(ConnectionType.Login, characterError, this);
        }
Пример #4
0
            private ServerPacketFragment CreateServerFragment(ushort index)
            {
                log.DebugFormat("Creating ServerFragment for index {0}", index);
                if (index >= Count)
                {
                    throw new ArgumentOutOfRangeException("index", index, "Passed index is greater then computed count");
                }

                var position = index * ServerPacketFragment.MaxFragmentDataSize;

                if (position > DataLength)
                {
                    throw new ArgumentOutOfRangeException("index", index, "Passed index computes to invalid position size");
                }

                if (DataRemaining <= 0)
                {
                    throw new InvalidOperationException("There is no data remaining");
                }

                var dataToSend = DataLength - position;

                if (dataToSend > ServerPacketFragment.MaxFragmentDataSize)
                {
                    dataToSend = ServerPacketFragment.MaxFragmentDataSize;
                }

                if (DataRemaining < dataToSend)
                {
                    throw new InvalidOperationException("More data to send then data remaining!");
                }

                // Read data starting at position reading dataToSend bytes
                Message.Data.Seek(position, SeekOrigin.Begin);
                byte[] data = new byte[dataToSend];
                Message.Data.Read(data, 0, (int)dataToSend);

                // Build ServerPacketFragment structure
                ServerPacketFragment fragment = new ServerPacketFragment(data);

                fragment.Header.Sequence = Sequence;
                fragment.Header.Id       = 0x80000000;
                fragment.Header.Count    = Count;
                fragment.Header.Index    = index;
                fragment.Header.Group    = (ushort)Message.Group;

                DataRemaining -= dataToSend;
                log.DebugFormat("Done creating ServerFragment for index {0}. After reading {1} DataRemaining {2}", index, dataToSend, DataRemaining);
                return(fragment);
            }
Пример #5
0
        private static void SendCharacterCreateResponse(Session session, CharacterGenerationVerificationResponse response, ObjectGuid guid = null, string charName = "")
        {
            var charCreateResponse = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var charCreateFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterCreateResponse);

            charCreateFragment.Payload.Write((uint)response);

            if (response == CharacterGenerationVerificationResponse.Ok)
            {
                charCreateFragment.Payload.WriteGuid(guid);
                charCreateFragment.Payload.WriteString16L(charName);
                charCreateFragment.Payload.Write(0u);
            }

            charCreateResponse.Fragments.Add(charCreateFragment);
            NetworkManager.SendPacket(ConnectionType.Login, charCreateResponse, session);
        }
Пример #6
0
        public static void SendServerMessage(Session session, string message, ChatMessageType chatMessageType)
        {
            var textboxString         = new ServerPacket(0x18, PacketHeaderFlags.EncryptedChecksum);
            var textboxStringFragment = new ServerPacketFragment(0x09, GameMessageOpcode.ServerMessage);

            textboxStringFragment.Payload.WriteString16L(message);
            textboxStringFragment.Payload.Write((int)chatMessageType);
            textboxString.Fragments.Add(textboxStringFragment);

            if (session == null)
            {
                // TODO: broadcast
            }
            else
            {
                NetworkManager.SendPacket(ConnectionType.World, textboxString, session);
            }
        }
Пример #7
0
        private static void SendCharacterCreateResponse(Session session, uint responseCode, uint guid = 0, string charName = null)
        {
            var charCreateResponse = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var charCreateFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterCreateResponse);

            if (responseCode == 1)
            {
                charCreateFragment.Payload.Write(responseCode);
                charCreateFragment.Payload.Write(guid);
                charCreateFragment.Payload.WriteString16L(charName);
                charCreateFragment.Payload.Write(0u);
            }
            else
            {
                charCreateFragment.Payload.Write(responseCode);
            }
            charCreateResponse.Fragments.Add(charCreateFragment);
            NetworkManager.SendPacket(ConnectionType.Login, charCreateResponse, session);
        }
Пример #8
0
        public static void CharacterListSelectCallback(MySqlResult result, Session session)
        {
            var characterList     = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var characterFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterList);

            characterFragment.Payload.Write(0u);
            characterFragment.Payload.Write(result.Count);

            session.CachedCharacters.Clear();
            for (byte i = 0; i < result.Count; i++)
            {
                uint   lowGuid = result.Read <uint>(i, "guid");
                string name    = result.Read <string>(i, "name");

                characterFragment.Payload.Write(lowGuid);
                characterFragment.Payload.WriteString16L(name);

                ulong deleteTime = result.Read <ulong>(i, "deleteTime");
                characterFragment.Payload.Write(deleteTime != 0ul ? (uint)(WorldManager.GetUnixTime() - deleteTime) : 0u);

                session.CachedCharacters.Add(new CachedCharacter(lowGuid, i, name));
            }

            characterFragment.Payload.Write(0u);
            characterFragment.Payload.Write(11u /*slotCount*/);
            characterFragment.Payload.WriteString16L(session.Account);
            characterFragment.Payload.Write(0u /*useTurbineChat*/);
            characterFragment.Payload.Write(0u /*hasThroneOfDestiny*/);
            characterList.Fragments.Add(characterFragment);

            NetworkManager.SendPacket(ConnectionType.Login, characterList, session);

            var serverName         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var serverNameFragment = new ServerPacketFragment(9, FragmentOpcode.ServerName);

            serverNameFragment.Payload.Write(0u);
            serverNameFragment.Payload.Write(0u);
            serverNameFragment.Payload.WriteString16L(ConfigManager.Config.Server.WorldName);
            serverName.Fragments.Add(serverNameFragment);

            NetworkManager.SendPacket(ConnectionType.Login, serverName, session);
        }
Пример #9
0
        public static void CharacterRestore(ClientPacketFragment fragment, Session session)
        {
            ObjectGuid guid = fragment.Payload.ReadGuid();

            var cachedCharacter = session.CachedCharacters.SingleOrDefault(c => c.Guid.Full == guid.Full);

            if (cachedCharacter == null)
            {
                return;
            }

            DatabaseManager.Character.DeleteOrRestore(0, guid.Low);

            var characterRestore         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var characterRestoreFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterRestoreResponse);

            characterRestoreFragment.Payload.Write(1u /* Verification OK flag */);
            characterRestoreFragment.Payload.WriteGuid(guid);
            characterRestoreFragment.Payload.WriteString16L(cachedCharacter.Name);
            characterRestoreFragment.Payload.Write(0u /* secondsGreyedOut */);
            characterRestore.Fragments.Add(characterRestoreFragment);

            NetworkManager.SendPacket(ConnectionType.Login, characterRestore, session);
        }
Пример #10
0
        public static void CharacterListSelectCallback(List <CachedCharacter> characters, Session session)
        {
            var characterList     = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var characterFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterList);

            characterFragment.Payload.Write(0u);
            characterFragment.Payload.Write(characters.Count);

            session.CachedCharacters.Clear();
            foreach (var character in characters)
            {
                characterFragment.Payload.Write(character.LowGuid);
                characterFragment.Payload.WriteString16L(character.Name);
                characterFragment.Payload.Write(character.DeleteTime != 0ul ? (uint)(WorldManager.GetUnixTime() - character.DeleteTime) : 0u);
                session.CachedCharacters.Add(character);
            }

            characterFragment.Payload.Write(0u);
            characterFragment.Payload.Write(11u /*slotCount*/);
            characterFragment.Payload.WriteString16L(session.Account);
            characterFragment.Payload.Write(0u /*useTurbineChat*/);
            characterFragment.Payload.Write(0u /*hasThroneOfDestiny*/);
            characterList.Fragments.Add(characterFragment);

            NetworkManager.SendPacket(ConnectionType.Login, characterList, session);

            var serverName         = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum);
            var serverNameFragment = new ServerPacketFragment(9, FragmentOpcode.ServerName);

            serverNameFragment.Payload.Write(0u);
            serverNameFragment.Payload.Write(0u);
            serverNameFragment.Payload.WriteString16L(ConfigManager.Config.Server.WorldName);
            serverName.Fragments.Add(serverNameFragment);

            NetworkManager.SendPacket(ConnectionType.Login, serverName, session);
        }
Пример #11
0
        // TODO: packet pipe really needs a rework...
        private static bool ConstructPacket(out byte[] buffer, ConnectionType type, ServerPacket packet, Session session, bool useHeaders = false)
        {
            var connectionData = (type == ConnectionType.Login ? session.LoginConnection : session.WorldConnection);

            using (var packetStream = new MemoryStream())
            {
                using (var packetWriter = new BinaryWriter(packetStream))
                {
                    packetWriter.Seek((int)PacketHeader.HeaderSize, SeekOrigin.Begin);
                    packetWriter.Write(packet.Data.ToArray());

                    if (packet.Fragments.Count > 0)
                    {
                        packet.Header.Flags |= PacketHeaderFlags.BlobFragments;

                        for (int i = 0; i < packet.Fragments.Count; i++)
                        {
                            var fragment = (ServerPacketFragment)packet.Fragments[i];

                            uint fragmentsRequired = ((uint)fragment.Data.Length / PacketFragment.MaxFragmentDataSize);
                            if ((fragment.Data.Length % PacketFragment.MaxFragmentDataSize) != 0)
                            {
                                fragmentsRequired++;
                            }

                            if (fragmentsRequired > 1u)
                            {
                                fragment.Data.Seek(0L, SeekOrigin.Begin);

                                uint dataToSend  = (uint)fragment.Data.Length;
                                uint fragmentSeq = connectionData.FragmentSequence++;

                                for (uint j = 0u; j < fragmentsRequired; j++)
                                {
                                    uint fragmentSize = dataToSend > PacketFragment.MaxFragmentDataSize ? PacketFragment.MaxFragmentDataSize : dataToSend;

                                    byte[] data = new byte[fragmentSize];
                                    fragment.Data.Read(data, 0, (int)fragmentSize);

                                    var newPacket   = new ServerPacket(packet.Header.Id, PacketHeaderFlags.EncryptedChecksum | PacketHeaderFlags.BlobFragments);
                                    var newFragment = new ServerPacketFragment(fragment.Header.Group);
                                    newFragment.Header.Sequence = fragmentSeq;
                                    newFragment.Header.Id       = 0x80000000;
                                    newFragment.Header.Count    = (ushort)fragmentsRequired;
                                    newFragment.Header.Index    = (ushort)j;
                                    newFragment.Data.Write(data, 0, (int)fragmentSize);
                                    newPacket.Fragments.Add(newFragment);

                                    SendPacket(type, newPacket, session, true);

                                    dataToSend -= fragmentSize;
                                }

                                buffer = null;
                                return(false);
                            }

                            fragment.Header.Size = (ushort)(PacketFragmentHeader.HeaderSize + fragment.Payload.BaseStream.Length);

                            if (!useHeaders)
                            {
                                fragment.Header.Sequence = connectionData.FragmentSequence++;
                                fragment.Header.Id       = 0x80000000; // this seems to be a global incremental value
                                fragment.Header.Count    = 1;
                                fragment.Header.Index    = (ushort)i;
                            }

                            packetWriter.Write(fragment.Header.GetRaw());
                            packetWriter.Write(fragment.Data.ToArray());
                        }
                    }

                    if (packet.Header.HasFlag(PacketHeaderFlags.EncryptedChecksum) && connectionData.PacketSequence < 2)
                    {
                        connectionData.PacketSequence = 2;
                    }

                    packet.Header.Sequence = connectionData.PacketSequence++;
                    packet.Header.Size     = (ushort)(packetWriter.BaseStream.Length - PacketHeader.HeaderSize);
                    packet.Header.Table    = 0x14;
                    packet.Header.Time     = (ushort)connectionData.ServerTime;

                    uint issacXor;
                    packet.Header.Checksum = packet.CalculateChecksum(session, type, 0u, out issacXor);

                    packetWriter.Seek(0, SeekOrigin.Begin);
                    packetWriter.Write(packet.Header.GetRaw());

                    if (type == ConnectionType.World && packet.Header.Sequence >= 2u)
                    {
                        session.CachedPackets.TryAdd(packet.Header.Sequence, new CachedPacket(issacXor, packet));
                    }

                    buffer = packetStream.ToArray();
                    return(true);
                }
            }
        }
Пример #12
0
        /// <summary>
        /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice),
        /// into 1 or more packets, combining multiple messages into one packet or spliting large message across
        /// several packets as needed.
        ///
        /// 1 Create Packet
        /// 2 If first packet for this bundle, fill any optional headers
        /// 3 Append messages that will fit
        /// 4 If we have more messages, create additional packets.
        /// 5 If any packet is greater than the max packet size, split it across two fragments
        /// </summary>
        /// <param name="bundle"></param>
        private void SendBundle(NetworkBundle bundle)
        {
            bool firstPacket = true;

            MessageFragment carryOverMessage = null;

            while (firstPacket || carryOverMessage != null || bundle.Messages.Count > 0)
            {
                ServerPacket packet       = new ServerPacket();
                PacketHeader packetHeader = packet.Header;

                if (bundle.EncryptedChecksum)
                {
                    packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum;
                }

                uint availableSpace = Packet.MaxPacketDataSize;

                if (firstPacket)
                {
                    firstPacket = false;

                    if (bundle.SendAck) //0x4000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.AckSequence;
                        packet.BodyWriter.Write(lastReceivedSequence);
                    }

                    if (bundle.TimeSync) //0x1000000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.TimeSynch;
                        packet.BodyWriter.Write(ConnectionData.ServerTime);
                    }

                    if (bundle.ClientTime != -1f) //0x4000000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.EchoResponse;
                        packet.BodyWriter.Write(bundle.ClientTime);
                        packet.BodyWriter.Write((float)ConnectionData.ServerTime - bundle.ClientTime);
                    }

                    availableSpace -= (uint)packet.Data.Length;
                }

                if (carryOverMessage != null || bundle.Messages.Count > 0)
                {
                    packetHeader.Flags |= PacketHeaderFlags.BlobFragments;
                    int fragmentCount = 0;
                    while (carryOverMessage != null || bundle.Messages.Count > 0)
                    {
                        MessageFragment currentMessageFragment;

                        if (carryOverMessage != null) // If we have a carryOverMessage, use that
                        {
                            currentMessageFragment = carryOverMessage;
                            carryOverMessage       = null;
                        }
                        else // If we don't have a carryOverMessage, go ahead and dequeue next message from the bundle
                        {
                            currentMessageFragment = new MessageFragment(bundle.Messages.Dequeue());
                        }

                        var currentGameMessage = currentMessageFragment.message;

                        availableSpace -= PacketFragmentHeader.HeaderSize; // Account for fragment header

                        // Compute amount of data to send based on the total length and current position
                        uint dataToSend = (uint)currentGameMessage.Data.Length - currentMessageFragment.position;

                        if (dataToSend > availableSpace) // Message is too large to fit in packet
                        {
                            carryOverMessage = currentMessageFragment;
                            if (fragmentCount == 0) // If this is first message in packet, this is just a really large message, so proceed with splitting it
                            {
                                dataToSend = availableSpace;
                            }
                            else // Otherwise there are other messages already, so we'll break and come back and see if the message will fit
                            {
                                break;
                            }
                        }

                        if (currentMessageFragment.count == 0) // Compute number of fragments if we have not already
                        {
                            uint remainingData = (uint)currentGameMessage.Data.Length - dataToSend;
                            currentMessageFragment.count = (ushort)(Math.Ceiling((double)remainingData / PacketFragment.MaxFragmentDataSize) + 1);
                        }

                        // Set sequence, if new, pull next sequence from ConnectionData, if it is a carryOver, reuse that sequence
                        currentMessageFragment.sequence = currentMessageFragment.sequence == 0 ? ConnectionData.FragmentSequence++ : currentMessageFragment.sequence;

                        // Build ServerPacketFragment structure
                        ServerPacketFragment fragment       = new ServerPacketFragment();
                        PacketFragmentHeader fragmentHeader = fragment.Header;
                        fragmentHeader.Sequence = currentMessageFragment.sequence;
                        fragmentHeader.Id       = 0x80000000;
                        fragmentHeader.Count    = currentMessageFragment.count;
                        fragmentHeader.Index    = currentMessageFragment.index;
                        fragmentHeader.Group    = (ushort)currentMessageFragment.message.Group;

                        // Read data starting at current position reading dataToSend bytes
                        currentGameMessage.Data.Seek(currentMessageFragment.position, SeekOrigin.Begin);
                        fragment.Content = new byte[dataToSend];
                        currentGameMessage.Data.Read(fragment.Content, 0, (int)dataToSend);

                        // Increment position and index
                        currentMessageFragment.position = currentMessageFragment.position + dataToSend;
                        currentMessageFragment.index++;

                        // Add fragment to packet
                        packet.AddFragment(fragment);
                        fragmentCount++;

                        // Deduct consumed space
                        availableSpace -= dataToSend;

                        // Smallest message I am aware of requires HeaderSize + 4 bytes, so if we have less space then that, go ahead and break
                        if (availableSpace <= PacketFragmentHeader.HeaderSize + 4)
                        {
                            break;
                        }
                    }
                }

                PacketQueue.Enqueue(packet);
            }
        }
Пример #13
0
        /// <summary>
        /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice),
        /// into 1 or more packets, combining multiple messages into one packet or spliting large message across
        /// several packets as needed.
        ///
        /// 1 Create Packet
        /// 2 If first packet for this bundle, fill any optional headers
        /// 3 Append fragments that will fit
        /// 3.1 Check each fragment to see if it is a partial fit
        /// 4 If we have a partial message remaining or more messages, create additional packets.
        /// </summary>
        /// <param name="bundle"></param>
        private void SendBundle(NetworkBundle bundle)
        {
            bool firstPacket = true;

            MessageFragment carryOverMessage = null;

            while (firstPacket || carryOverMessage != null || bundle.Messages.Count > 0)
            {
                ServerPacket packet       = new ServerPacket();
                PacketHeader packetHeader = packet.Header;
                if (bundle.encryptedChecksum)
                {
                    packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum;
                }

                uint availableSpace = Packet.MaxPacketDataSize;

                if (firstPacket)
                {
                    firstPacket = false;
                    if (bundle.SendAck) //0x4000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.AckSequence;
                        packet.BodyWriter.Write(lastReceivedSequence);
                    }
                    if (bundle.TimeSync) //0x1000000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.TimeSynch;
                        packet.BodyWriter.Write(ConnectionData.ServerTime);
                    }
                    if (bundle.ClientTime != -1f) //0x4000000
                    {
                        packetHeader.Flags |= PacketHeaderFlags.EchoResponse;
                        packet.BodyWriter.Write(bundle.ClientTime);
                        packet.BodyWriter.Write((float)ConnectionData.ServerTime - bundle.ClientTime);
                    }
                    availableSpace -= (uint)packet.Data.Length;
                }

                if (carryOverMessage != null || bundle.Messages.Count > 0)
                {
                    packetHeader.Flags |= PacketHeaderFlags.BlobFragments;

                    while (carryOverMessage != null || bundle.Messages.Count > 0)
                    {
                        if (availableSpace <= PacketFragmentHeader.HeaderSize + 4)
                        {
                            break;
                        }

                        MessageFragment currentMessageFragment;

                        if (carryOverMessage != null)
                        {
                            currentMessageFragment = carryOverMessage;
                            carryOverMessage       = null;
                            currentMessageFragment.index++;
                        }
                        else
                        {
                            currentMessageFragment = new MessageFragment(bundle.Messages.Dequeue());
                        }

                        var currentGameMessage = currentMessageFragment.message;

                        ServerPacketFragment fragment       = new ServerPacketFragment();
                        PacketFragmentHeader fragmentHeader = fragment.Header;
                        availableSpace -= PacketFragmentHeader.HeaderSize;

                        currentMessageFragment.sequence = currentMessageFragment.sequence == 0 ? ConnectionData.FragmentSequence++ : currentMessageFragment.sequence;

                        uint dataToSend = (uint)currentGameMessage.Data.Length - currentMessageFragment.position;
                        if (dataToSend > availableSpace)
                        {
                            dataToSend       = availableSpace;
                            carryOverMessage = currentMessageFragment;
                        }

                        if (currentMessageFragment.count == 0)
                        {
                            uint remainingData = (uint)currentGameMessage.Data.Length - dataToSend;
                            currentMessageFragment.count = (ushort)(Math.Ceiling((double)remainingData / PacketFragment.MaxFragmentDataSize) + 1);
                        }

                        fragmentHeader.Sequence = currentMessageFragment.sequence;
                        fragmentHeader.Id       = 0x80000000;
                        fragmentHeader.Count    = currentMessageFragment.count;
                        fragmentHeader.Index    = currentMessageFragment.index;
                        fragmentHeader.Group    = (ushort)currentMessageFragment.message.Group;

                        currentGameMessage.Data.Seek(currentMessageFragment.position, SeekOrigin.Begin);
                        fragment.Content = new byte[dataToSend];
                        currentGameMessage.Data.Read(fragment.Content, 0, (int)dataToSend);

                        currentMessageFragment.position = currentMessageFragment.position + dataToSend;

                        availableSpace -= dataToSend;

                        packet.AddFragment(fragment);
                        //break;
                    }
                }

                PacketQueue.Enqueue(packet);
            }
        }
Пример #14
0
        /// <summary>
        /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice),
        /// into 1 or more packets, combining multiple messages into one packet or spliting large message across
        /// several packets as needed.
        /// </summary>
        /// <param name="bundle"></param>
        private void SendBundle(NetworkBundle bundle)
        {
            log.DebugFormat("[{0}] Sending Bundle", session.LoggingIdentifier);
            bool writeOptionalHeaders = true;

            List <MessageFragment> fragments = new List <MessageFragment>();

            // Pull all messages out and create MessageFragment objects
            while (bundle.HasMoreMessages)
            {
                var message  = bundle.Dequeue();
                var fragment = new MessageFragment(message, ConnectionData.FragmentSequence++);
                fragments.Add(fragment);
            }

            log.DebugFormat("[{0}] Bundle Fragment Count: {1}", session.LoggingIdentifier, fragments.Count);

            // Loop through while we have fragements
            while (fragments.Count > 0 || writeOptionalHeaders)
            {
                ServerPacket packet       = new ServerPacket();
                PacketHeader packetHeader = packet.Header;

                if (fragments.Count > 0)
                {
                    packetHeader.Flags |= PacketHeaderFlags.BlobFragments;
                }

                if (bundle.EncryptedChecksum)
                {
                    packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum;
                }

                uint availableSpace = Packet.MaxPacketDataSize;

                // Pull first message and see if it is a large one
                var firstMessage = fragments.FirstOrDefault();
                if (firstMessage != null)
                {
                    // If a large message send only this one, filling the whole packet
                    if (firstMessage.DataRemaining >= availableSpace)
                    {
                        log.DebugFormat("[{0}] Sending large fragment", session.LoggingIdentifier);
                        ServerPacketFragment spf = firstMessage.GetNextFragment();
                        packet.Fragments.Add(spf);
                        availableSpace -= (uint)spf.Length;
                        if (firstMessage.DataRemaining <= 0)
                        {
                            fragments.Remove(firstMessage);
                        }
                    }
                    // Otherwise we'll write any optional headers and process any small messages that will fit
                    else
                    {
                        if (writeOptionalHeaders)
                        {
                            writeOptionalHeaders = false;
                            WriteOptionalHeaders(bundle, packet);
                            availableSpace -= (uint)packet.Data.Length;
                        }

                        // Create a list to remove completed messages after iterator
                        List <MessageFragment> removeList = new List <MessageFragment>();

                        foreach (MessageFragment fragment in fragments)
                        {
                            // Is this a large fragment and does it have a tail that needs sending?
                            if (!fragment.TailSent && availableSpace >= fragment.TailSize)
                            {
                                log.DebugFormat("[{0}] Sending tail fragment", session.LoggingIdentifier);
                                ServerPacketFragment spf = fragment.GetTailFragment();
                                packet.Fragments.Add(spf);
                                availableSpace -= (uint)spf.Length;
                            }
                            // Otherwise will this message fit in the remaining space?
                            else if (availableSpace >= fragment.NextSize)
                            {
                                log.DebugFormat("[{0}] Sending small message", session.LoggingIdentifier);
                                ServerPacketFragment spf = fragment.GetNextFragment();
                                packet.Fragments.Add(spf);
                                availableSpace -= (uint)spf.Length;
                            }
                            // If message is out of data, set to remove it
                            if (fragment.DataRemaining <= 0)
                            {
                                removeList.Add(fragment);
                            }
                        }

                        // Remove all completed messages
                        fragments.RemoveAll(x => removeList.Contains(x));
                    }
                }
                // If no messages, write optional headers
                else
                {
                    log.DebugFormat("[{0}] No messages, just sending optional headers", session.LoggingIdentifier);
                    if (writeOptionalHeaders)
                    {
                        writeOptionalHeaders = false;
                        WriteOptionalHeaders(bundle, packet);
                        availableSpace -= (uint)packet.Data.Length;
                    }
                }

                EnqueueSend(packet);
            }
        }
Пример #15
0
 public void AddFragment(ServerPacketFragment fragment)
 {
     fragments.Add(fragment);
 }