private void FragmentMessage(Message message, ITransportDeliveryCharacteristics tdc, 
            TransportPacket packet, MarshalledResult mr)
        {
            // <item> if the message is the first fragment, then the high-bit is
            //     set on the message-type; the number of fragments is encoded using
            //     the adaptive <see cref="ByteUtils.EncodeLength(int)"/> format.
            //     <pre>[byte:message-type'] [byte:channelId] [uint32:packet-size]
            //         [byte:seqno] [bytes:encoded-#-fragments] [bytes:frag]</pre>
            // </item>
            // <item> for all subsequent fragments; seqno' = seqno | 128;
            //     the number of fragments is encoded using the adaptive
            //     <see cref="ByteUtils.EncodeLength(int)"/> format.
            //     <pre>[byte:message-type'] [byte:channelId] [uint32:packet-size]
            //         [byte:seqno'] [bytes:encoded-fragment-#] [bytes:frag]</pre>

            // Although we use an adaptive scheme for encoding the number,
            // we assume a maximum of 4 bytes for encoding # frags
            // for a total of 4 extra bytes bytes; we determine the frag
            // size from the message size - MaxHeaderSize
            const uint maxFragHeaderSize = 1 /*seqno*/ + 4;
            const uint maxHeaderSize = LWMCFv11.HeaderSize + maxFragHeaderSize;
            uint maxPacketSize = Math.Max(maxHeaderSize, tdc.MaximumPacketSize - maxHeaderSize);
            // round up the number of possible fragments
            uint numFragments = (uint)(packet.Length + maxPacketSize - 1) / maxPacketSize;
            Debug.Assert(numFragments > 1);
            uint seqNo = AllocateOutgoingSeqNo(tdc);
            for (uint fragNo = 0; fragNo < numFragments; fragNo++)
            {
                TransportPacket newPacket = new TransportPacket();
                Stream s = newPacket.AsWriteStream();
                uint fragSize = (uint)Math.Min(maxPacketSize,
                    packet.Length - (fragNo * maxPacketSize));
                if (fragNo == 0)
                {
                    s.WriteByte((byte)seqNo);
                    ByteUtils.EncodeLength(numFragments, s);
                }
                else
                {
                    s.WriteByte((byte)(seqNo | 128));
                    ByteUtils.EncodeLength(fragNo, s);
                }
                newPacket.Prepend(LWMCFv11.EncodeHeader((MessageType)((byte)message.MessageType | 128),
                    message.ChannelId, (uint)(fragSize + s.Length)));
                newPacket.Append(packet, (int)(fragNo * maxPacketSize), (int)fragSize);
                mr.AddPacket(newPacket);
            }
            packet.Dispose();
        }
Beispiel #2
0
        public void TestPrepending()
        {
            // Ensure small packets
            TransportPacket.ReservedInitialBytes = 0;
            TransportPacket.MaxSegmentSize = TransportPacket.MinSegmentSize;

            TransportPacket packet = new TransportPacket(new byte[] { 9 });
            packet.Prepend(new byte[] { 4, 5, 6, 7, 8 });
            packet.Prepend(new byte[] { 0, 1, 2, 3 });

            Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, packet.ToArray());
            CheckDisposed(packet);
            CheckForUndisposedSegments();
        }
Beispiel #3
0
 public void Inject(uint seqNo, TransportPacket payload)
 {
     Debug.Assert(PacketHeaderSize == 4);
     payload.Prepend(DataConverter.Converter.GetBytes(seqNo));
     NotifyPacketReceived(payload);
 }
Beispiel #4
0
 public void TestDisposal()
 {
     TransportPacket packet = new TransportPacket(10);
     packet.Dispose();
     try
     {
         packet.Grow(20);
         Assert.Fail("should have thrown ObjectDisposedException");
     } catch(ObjectDisposedException) { /* expected */ }
     try
     {
         packet.RemoveBytes(0,2);
         Assert.Fail("should have thrown ObjectDisposedException");
     } catch(ObjectDisposedException) { /* expected */ }
     try
     {
         packet.ByteAt(0);
         Assert.Fail("should have thrown ObjectDisposedException");
     } catch(ObjectDisposedException) { /* expected */ }
     try
     {
         packet.Consolidate();
         Assert.Fail("should have thrown ObjectDisposedException");
     } catch(ObjectDisposedException) { /* expected */ }
     try
     {
         packet.Prepend(new byte[0]);
         Assert.Fail("should have thrown ObjectDisposedException");
     }
     catch (ObjectDisposedException) { /* expected */ }
     try
     {
         packet.Append(new byte[0]);
         Assert.Fail("should have thrown ObjectDisposedException");
     }
     catch (ObjectDisposedException) { /* expected */ }
     try
     {
         Console.WriteLine(packet.Length);
         Assert.Fail("should have thrown ObjectDisposedException");
     }
     catch (ObjectDisposedException) { /* expected */ }
 }
Beispiel #5
0
        public void TestInplacePrepending()
        {
            TransportPacket.ReservedInitialBytes = 10;

            TransportPacket packet = new TransportPacket(new byte[] { 9 });
            packet.Prepend(new byte[] { 4, 5, 6, 7, 8 });
            packet.Prepend(new byte[] { 0, 1, 2, 3 });

            Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, packet.ToArray());
            Assert.AreEqual(1, ((IList<ArraySegment<byte>>)packet).Count);
            CheckDisposed(packet);
            CheckForUndisposedSegments();
        }
Beispiel #6
0
        public void TestConsolidate()
        {
            // Ensure result wilbe distributed across multiple packets
            TransportPacket.ReservedInitialBytes = 0;

            TransportPacket packet = new TransportPacket(new byte[] { 9 });
            packet.Prepend(new byte[] { 4, 5, 6, 7, 8 });
            packet.Prepend(new byte[] { 0, 1, 2, 3 });
            Assert.IsTrue(((IList<ArraySegment<byte>>)packet).Count > 1);

            packet.Consolidate();
            Assert.AreEqual(1, ((IList<ArraySegment<byte>>)packet).Count);
            Assert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, packet.ToArray());
            CheckDisposed(packet);
            CheckForUndisposedSegments();
        }
 protected override void WritePacketHeader(TransportPacket packet)
 {
     packet.Prepend(DataConverter.Converter.GetBytes(nextOutgoingPacketSeqNo++));
 }
Beispiel #8
0
        public override IMarshalledResult Marshal(int senderIdentity, Message msg, ITransportDeliveryCharacteristics tdc)
        {
            // This marshaller doesn't use <see cref="senderIdentity"/>.
            if (msg is RawMessage)
            {
                MarshalledResult mr = new MarshalledResult();
                TransportPacket tp = new TransportPacket();

                // NB: SystemMessages use ChannelId to encode the sysmsg descriptor
                RawMessage rm = (RawMessage)msg;
                tp.Prepend(LWMCFv11.EncodeHeader(msg.MessageType, msg.ChannelId, (uint)rm.Bytes.Length));
                tp.Append(rm.Bytes);
                mr.AddPacket(tp);
                return mr;
            }
            return base.Marshal(senderIdentity, msg, tdc);
        }
Beispiel #9
0
        /// <summary>
        /// Marshal the given message to the provided stream in a form suitable to
        /// be sent out on the provided transport.
        /// </summary>
        /// <param name="senderIdentity">the identity of the sender</param>
        /// <param name="msg">the message being sent, that is to be marshalled</param>
        /// <param name="tdc">the characteristics of the transport that will send the marshalled form</param>
        /// <returns>the marshalled representation</returns>
        public virtual IMarshalledResult Marshal(int senderIdentity, Message msg, ITransportDeliveryCharacteristics tdc)
        {
            // This marshaller doesn't use <see cref="senderIdentity"/>.
            MarshalledResult mr = new MarshalledResult();
            TransportPacket tp = new TransportPacket();

            // We use TransportPacket.Prepend to add the marshalling header in-place
            // after the marshalling.
            Stream output = tp.AsWriteStream();
            Debug.Assert(output.CanSeek);
            MarshalContents(msg, output, tdc);
            output.Flush();
            // System messages don't have a channelId -- we encode their system message
            // type as the channelId instead
            tp.Prepend(LWMCFv11.EncodeHeader(msg.MessageType,
                msg.MessageType == MessageType.System
                    ? (byte)((SystemMessage)msg).Descriptor : msg.ChannelId,
                (uint)output.Position));
            mr.AddPacket(tp);
            return mr;
        }
Beispiel #10
0
        /// <summary>Send a packet to server.</summary>
        /// <param name="packet">The packet to send.</param>
        public override void SendPacket(TransportPacket packet)
        {
            InvalidStateException.Assert(Active, "Cannot send on disposed transport", this);
            ContractViolation.Assert(packet.Length > 0, "Cannot send 0-byte messages!");
            ContractViolation.Assert(packet.Length - PacketHeaderSize <= MaximumPacketSize,
                String.Format("Packet exceeds transport capacity: {0} > {1}; try increasing transport's MaximumPacketSize",
                    packet.Length - PacketHeaderSize, MaximumPacketSize));

            //DebugUtils.DumpMessage(this + "SendPacket", buffer, offset, length);
            Debug.Assert(PacketHeaderSize > 0);
            packet.Prepend(DataConverter.Converter.GetBytes((uint)packet.Length));

            lock (this)
            {
                outstanding.Enqueue(packet);
            }
            FlushOutstandingPackets();
        }