private ServerPacketFragment CreateServerFragment(ushort index) { packetLog.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 * PacketFragment.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 > PacketFragment.MaxFragmentDataSize) { dataToSend = PacketFragment.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, 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.Queue = (ushort)Message.Group; DataRemaining -= dataToSend; packetLog.DebugFormat("Done creating ServerFragment for index {0}. After reading {1} DataRemaining {2}", index, dataToSend, DataRemaining); return(fragment); }
/// <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, GameMessageGroup group) { packetLog.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); } packetLog.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; } int availableSpace = ServerPacket.MaxPacketSize; // 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) { packetLog.DebugFormat("[{0}] Sending large fragment", session.LoggingIdentifier); ServerPacketFragment spf = firstMessage.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= 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); if (packet.Data != null) { availableSpace -= (int)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) { packetLog.DebugFormat("[{0}] Sending tail fragment", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetTailFragment(); packet.Fragments.Add(spf); availableSpace -= spf.Length; } // Otherwise will this message fit in the remaining space? else if (availableSpace >= fragment.NextSize) { packetLog.DebugFormat("[{0}] Sending small message", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= 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 { packetLog.DebugFormat("[{0}] No messages, just sending optional headers", session.LoggingIdentifier); if (writeOptionalHeaders) { writeOptionalHeaders = false; WriteOptionalHeaders(bundle, packet); if (packet.Data != null) { availableSpace -= (int)packet.Data.Length; } } } EnqueueSend(packet); } }