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; }
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); }
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; }
/// <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; }