public DiscardingSequences(ITransportDeliveryCharacteristics tdc, uint windowSize, uint capacity) : base(tdc) { sw = new SlidingWindowManager(windowSize, capacity); sw.FrameExpired += _ExpireFrame; }
public ReliableSequences(ITransportDeliveryCharacteristics tdc) : base(tdc) { }
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(); }
private TransportPacket UnmarshalFragInProgress(byte seqNo, uint fragNo, TransportPacket frag, ITransportDeliveryCharacteristics tdc) { Sequences sequences; if (!accumulatedReceived.TryGetValue(tdc, out sequences)) { accumulatedReceived[tdc] = sequences = Sequences.ForTransport(tdc, windowSize, SeqNoCapacity); } return sequences.ReceivedFrag(seqNo, fragNo, frag); }
public void Unmarshal(TransportPacket input, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { // <item>Message fits within the transport packet length, so sent unmodified // <pre>[byte:message-type] [byte:channelId] [uint32:packet-size] // [bytes:content]</pre> // </item> // <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> // Fastpath: if the message-type doesn't have the high-bit set, // then this is a non-fragmented message if ((input.ByteAt(0) & 128) == 0) { // If the submarshaller uses LWMCFv1.1 then we would have just // sent the packet as-is; if not, then we'll have prefixed a // LWMCFv1.1 header which must be first removed if (!subMarshallerIsLwmcf11) { input.RemoveBytes(0, (int)LWMCFv11.HeaderSize); } subMarshaller.Unmarshal(input, tdc, messageAvailable); return; } MessageType type; byte channelId; uint contentLength; Stream s = input.AsReadStream(); LWMCFv11.DecodeHeader(out type, out channelId, out contentLength, s); byte seqNo = (byte)s.ReadByte(); TransportPacket subPacket; if ((seqNo & 128) == 0) { // This starts a new message uint numFrags = (uint)ByteUtils.DecodeLength(s); subPacket = UnmarshalFirstFragment(seqNo, numFrags, input.SplitOut((int)(s.Length - s.Position)), tdc); } else { // This is a message in progress seqNo = (byte)(seqNo & ~128); uint fragNo = (uint)ByteUtils.DecodeLength(s); subPacket = UnmarshalFragInProgress(seqNo, fragNo, input.SplitOut((int)(s.Length - s.Position)), tdc); } if (subPacket != null) { subMarshaller.Unmarshal(subPacket, tdc, messageAvailable); subPacket.Dispose(); } }
private uint AllocateOutgoingSeqNo(ITransportDeliveryCharacteristics tdc) { lock (this) { uint seqNo; if (!outgoingSeqNo.TryGetValue(tdc, out seqNo)) { seqNo = 0; } outgoingSeqNo[tdc] = (seqNo + 1) % SeqNoCapacity; return seqNo; } }
public IMarshalledResult Marshal(Message m, ITransportDeliveryCharacteristics tdc) { return Marshaller.Marshal(0, m, tdc); }
public virtual void Unmarshal(TransportPacket tp, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { Debug.Assert(messageAvailable != null, "callers must provide a messageAvailale handler"); Stream input = tp.AsReadStream(); MessageType type; byte channelId; uint length; LWMCFv11.DecodeHeader(out type, out channelId, out length, input); Message m = UnmarshalContent(channelId, type, new WrappedStream(input, length), length); if (m == null) { throw new MarshallingException(String.Format( "Cannot unmarshal the provided content: channel={0}, type={1}, len={2}", channelId, type, length)); } messageAvailable(this, new MessageEventArgs(tdc as ITransport, m)); }
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; }
public void Unmarshal(TransportPacket packet, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { Debug.Assert(messageAvailable != null, "callers must provide a messageAvailable handler"); Stream input = packet.AsReadStream(); int encoderId = DataConverter.Converter.ToInt32(ByteUtils.Read(input, 4), 0); uint length = ByteUtils.DecodeLength(input); byte[] decoded = Decode(encoderId, ByteUtils.Read(input, length)); TransportPacket subPacket = TransportPacket.On(decoded); input.Close(); subMarshaller.Unmarshal(subPacket, tdc, (sender, mea) => messageAvailable(this, mea)); }
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); }
protected override void MarshalContents(Message m, Stream output, ITransportDeliveryCharacteristics tdc) { // Individual marshalling methods are **NO LONGER RESPONSIBLE** for encoding // the payload length switch (m.MessageType) { case MessageType.Binary: MarshalBinary(((BinaryMessage)m).Bytes, output); break; case MessageType.String: MarshalString(((StringMessage)m).Text, output); break; case MessageType.Object: MarshalObject(((ObjectMessage)m).Object, output); break; case MessageType.Tuple1D: case MessageType.Tuple2D: case MessageType.Tuple3D: MarshalTupleMessage((TupleMessage)m, output); break; default: base.MarshalContents(m, output, tdc); break; } }
/// <summary> /// Marshal the contents of the message <see cref="m"/> onto the stream <see cref="output"/>. /// The channelId and message type have already been placed on <see cref="output"/>. /// This method is **not responsible** for encoding the message payload length. /// </summary> /// <param name="m">the message contents to be marshalled</param> /// <param name="output">the destination for the marshalled message payload</param> /// <param name="tdc">the characteristics of the transport that is to be used for sending</param> protected virtual void MarshalContents(Message m, Stream output, ITransportDeliveryCharacteristics tdc) { // Individual marshalling methods are **NO LONGER RESPONSIBLE** for encoding // the payload length switch (m.MessageType) { case MessageType.Session: MarshalSessionAction((SessionMessage)m, output); break; case MessageType.System: // channelId is the system message type MarshalSystemMessage((SystemMessage)m, output); break; default: throw new MarshallingException(String.Format("ERROR: {0} cannot handle messages of type {1}", this.GetType().Name, m.GetType().Name)); } }
protected Sequences(ITransportDeliveryCharacteristics tdc) { this.tdc = tdc; }
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; }
internal static Sequences ForTransport(ITransportDeliveryCharacteristics tdc, uint seqWindowSize, uint seqCapacity) { if(tdc.Reliability == Reliability.Reliable) { return new ReliableSequences(tdc); // seqWindowSize, seqCapacity } return new DiscardingSequences(tdc, seqWindowSize, seqCapacity); }
/// <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; }