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 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(); }
public void Inject(uint seqNo, TransportPacket payload) { Debug.Assert(PacketHeaderSize == 4); payload.Prepend(DataConverter.Converter.GetBytes(seqNo)); NotifyPacketReceived(payload); }
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 */ } }
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(); }
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++)); }
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); }
/// <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; }
/// <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(); }