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();
        }
 public IMarshalledResult Marshal(int senderIdentity, Message message, ITransportDeliveryCharacteristics tdc)
 {
     IMarshalledResult submr = subMarshaller.Marshal(senderIdentity, message, tdc);
     // Hmm, maybe this would be better as a generator, just in case the
     // sub-marshaller returns an infinite message.
     MarshalledResult mr = new MarshalledResult();
     while (submr.HasPackets)
     {
         TransportPacket packet = submr.RemovePacket();
         // Need to account for LWMCFv1.1 header for non-LWMCFv1.1 marshallers
         uint contentLength = (uint)packet.Length -
             (subMarshallerIsLwmcf11 ? LWMCFv11.HeaderSize : 0);
         // If this packet fits within the normal transport packet length
         // then we don't have to fragment it.
         if (LWMCFv11.HeaderSize + contentLength < tdc.MaximumPacketSize)
         {
             // Message fits within the transport packet length, so sent unmodified
             //     <pre>[byte:message-type] [byte:channelId] [uint32:packet-size]
             //         [bytes:content]</pre>
             if (!subMarshallerIsLwmcf11)
             {
                 // need to prefix the LWMCFv1.1 header
                 packet.Prepend(LWMCFv11.EncodeHeader(message.MessageType,
                     message.ChannelId, (uint)packet.Length));
             }
             mr.AddPacket(packet);
         }
         else
         {
             FragmentMessage(message, tdc, packet, mr);
         }
     }
     submr.Dispose();
     return mr;
 }
Example #3
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);
        }
Example #4
0
 public IMarshalledResult Marshal(int senderIdentity, Message message, ITransportDeliveryCharacteristics tdc)
 {
     IMarshalledResult mr = subMarshaller.Marshal(senderIdentity, message, tdc);
     MarshalledResult result = new MarshalledResult();
     while (mr.HasPackets)
     {
         TransportPacket packet = mr.RemovePacket();
         byte[] encoded = Encode(packet.ToArray());
         // FIXME: this is a bit awkward: if encoded is small, then
         // we're likely better off copying these into a contiguous
         // block of memory.  But if big, then we're probably better
         // off using these byte arrays as the backing store.
         TransportPacket newPacket = new TransportPacket(
             DataConverter.Converter.GetBytes(senderIdentity),
             ByteUtils.EncodeLength((uint)encoded.Length),
             encoded);
         result.AddPacket(newPacket);
     }
     mr.Dispose();
     return result;
 }
Example #5
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;
        }