Beispiel #1
0
        /// <summary>
        /// Read and return the next IPacket from the stream
        /// </summary>
        public IPacket Read()
        {
#if ADD_GUARD_BYTES
            byte[] preamble = new byte[4];
            m_Stream.Read(preamble, 0, 4);

            //now compare it against the preamble.
            CompareArrays(preamble, PacketWriter.s_PreambleGuardPattern);
#endif

            int packetSize = (int)m_Reader.ReadUInt64();

            //if the packet size is less than one, that's obviously wrong
            if (packetSize < 1)
            {
                throw new GibraltarSerializationException("The size of the next packet is smaller than 1 byte or negative, which can't be correct.  The packet stream is corrupted.", true);
            }

            // TODO: There's got to be a more efficient way to get this done
            byte[] buffer = new byte[packetSize];
            m_Stream.Read(buffer, 0, packetSize);
            IFieldReader bufferReader = new FieldReader(new MemoryStream(buffer), m_Reader.Strings, m_MajorVersion, m_MinorVersion);

            PacketDefinition definition;
            int typeIndex = (int)bufferReader.ReadUInt32();
            if (typeIndex >= m_cachedTypes.Count)
            {
                definition = PacketDefinition.ReadPacketDefinition(bufferReader);
                if (string.IsNullOrEmpty(definition.TypeName))
                {
                    //we're hosed...  we won't be able to parse this packet.
                    throw new GibraltarSerializationException("The type name of the definition is null, which can't be correct.  The packet stream is corrupted.", true);
                }

                m_cachedTypes.Add(definition);
                m_cachedTypes.Commit();
            }
            else
            {
                definition = m_cachedTypes[typeIndex];
            }

            IPacketFactory factory = m_PacketFactory.GetPacketFactory(definition.TypeName);
            IPacket        packet  = factory.CreatePacket(definition, bufferReader);

            //we used to populate a packet cache here, but a cached packet should be read just once - it shouldn't be in the stream
            //(and I changed PacketWriter to enforce that)

#if ADD_GUARD_BYTES
            byte[] postamble = new byte[4];
            m_Stream.Read(postamble, 0, 4);

            //now compare it against the preamble.
            CompareArrays(postamble, PacketWriter.s_PostambleGuardPattern);
#endif

            return(packet);
        }
Beispiel #2
0
        /// <summary>
        /// Write the data needed to serialize the state of the packet
        /// </summary>
        /// <param name="packet">Object to be serialized, must implement IPacket</param>
        public void Write(IPacket packet)
        {
            //Before we do anything - is this a cached packet that's already been written out?
            ICachedPacket cachedPacket = packet as ICachedPacket;

            if (cachedPacket != null)
            {
                //it is cacheable - is it in the cache?
                if (m_PacketCache.Contains(cachedPacket))
                {
                    //good to go, we're done.
                    return;
                }
            }

            //First, we need to find out if there are any packets this guy depends on.  If there are,
            //they have to be serialized out first.  They may have been - they could be cached.
            //to do this, we'll need to get the definition.
            PacketDefinition previewDefinition;
            int previewTypeIndex = m_CachedTypes.IndexOf(packet);

            if (previewTypeIndex < 0)
            {
                //we're going to get the definition, BUT we're not going to cache it yet.
                //This is because we recurse on our self if there are required packets, and if one of those
                //packets is our same type, IT has to write out the definition so that it's on the stream
                //before the packet itself.
                previewDefinition = PacketDefinition.CreatePacketDefinition(packet);
            }
            else
            {
                previewDefinition = m_CachedTypes[previewTypeIndex];
            }

            Dictionary <IPacket, IPacket> requiredPackets = previewDefinition.GetRequiredPackets(packet);

            foreach (IPacket requiredPacket in requiredPackets.Values)
            {
                Write(requiredPacket); //this will handle if it's a cached packet and shouldn't be written out.
            }

            //Begin our "transactional" phase
            try
            {
                // This routine is written to either write a complete packet, or to write nothing.
                // As we build up the packet, we will write to a MemoryStream.  Only after we've
                // built up the complete packet will we write it to the actual stream.
                m_Buffer.SetLength(0);
                m_Buffer.Position = 0;

                // The first time a packet type is written, we send along a packet definition
                PacketDefinition definition;
                int typeIndex = m_CachedTypes.IndexOf(packet);
                if (typeIndex < 0)
                {
                    // Record that we've seen this type so we don't bother sending the PacketDefinition again
                    definition = PacketDefinition.CreatePacketDefinition(packet);
                    typeIndex  = m_CachedTypes.Count;
                    m_CachedTypes.Add(definition);

                    // Each packet always starts with a packet type index.  And the first time a new
                    // index is used, it is followed by the packet definition.
                    m_BufferWriter.Write((UInt32)typeIndex);
                    definition.WriteDefinition(m_BufferWriter);
                }
                else
                {
                    // If this type has been written before, just send the type index
                    m_BufferWriter.Write((UInt32)typeIndex);
                    definition = m_CachedTypes[typeIndex];
                }

                // if it's cacheable then we need to add it to our packet cache before we write it out
                if (definition.IsCachable)
                {
                    // In the case of an ICachedPacket, we need to add it to the cache.
                    // we'd have already bailed if it was in there.
                    // Note: Use previous cast for efficiency, but we must recast here *if* packet gets reassigned above
                    // Currently it does not get reassigned, so cachedPacket which we cast packet into above is still valid.
                    m_PacketCache.AddOrGet(cachedPacket);
                }

                //Finally, and it really is a long journey, we ask the definition to write out
                //the individual fields for the packet
                definition.WriteFields(packet, m_BufferWriter);
            }
            catch (Exception ex)
            {
                GC.KeepAlive(ex);
                Rollback();
                throw;
            }

#if ADD_GUARD_BYTES
            m_Stream.Write(s_PreambleGuardPattern, 0, s_PreambleGuardPattern.Length);
#endif

            // Write the data to the stream preceded by the length of this packet
            // NOTE: The logic below is careful to ensure that the length and payload is written in one call
            //       This is necessary to ensure that the GZipStream writes the whole packet in edge cases
            //       of writing the very last packet as an application is exiting.

            var          payloadLength = (int)m_Buffer.Position; // get the actual length of the payload
            MemoryStream encodedLength = FieldWriter.WriteLength(payloadLength);
            var          lengthLength  = (int)encodedLength.Length;

            var packetBytes = new byte[lengthLength + payloadLength];

            encodedLength.Position = 0; // reset the position in preparation to read the data back
            encodedLength.Read(packetBytes, 0, lengthLength);

            m_Buffer.Position = 0; // reset the position in preparation to read the data back
            m_Buffer.Read(packetBytes, lengthLength, payloadLength);

            m_Stream.Write(packetBytes, 0, packetBytes.Length);

#if ADD_GUARD_BYTES
            m_Stream.Write(s_PostambleGuardPattern, 0, s_PostambleGuardPattern.Length);
#endif

            Commit();
        }