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(); } }
public void TestSubset() { byte[] source = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // We test for various subsets that overlap partially or fully with the different segments for (int sourceStart = 0; sourceStart < source.Length / 2; sourceStart++) { for (int sourceEnd = source.Length - 1; sourceEnd - sourceStart > 0; sourceEnd--) { int sourceCount = sourceEnd - sourceStart + 1; TransportPacket packet = new TransportPacket(source, sourceStart, sourceCount); Assert.AreEqual(sourceCount, packet.Length); Assert.AreEqual(1, ((IList<ArraySegment<byte>>)packet).Count); for (int i = 0; i < 10; i++) { packet.Append(source, sourceStart, sourceCount); } Assert.AreEqual(sourceCount * 11, packet.Length); const int subsetStart = 4; int subsetCount = Math.Min(17, packet.Length - 2); TransportPacket subset = packet.Subset(subsetStart, subsetCount); Assert.AreEqual(subsetCount, subset.Length); byte[] result = subset.ToArray(); Assert.AreEqual(subsetCount, result.Length); for (int i = 0; i < result.Length; i++) { Assert.AreEqual(source[sourceStart + ((subsetStart + i) % sourceCount)], result[i]); Assert.AreEqual(source[sourceStart + ((subsetStart + i) % sourceCount)], subset.ByteAt(i)); Assert.AreEqual(packet.ByteAt(subsetStart + i), subset.ByteAt(i)); } // And ensure the subset has the same backing byte array is still referenced // sourceEquivIndex = the equivalent index in source to subset[0] int sourceEquivIndex = sourceStart + (subsetStart % sourceCount); Assert.AreEqual(source[sourceEquivIndex], packet.ByteAt(subsetStart)); Assert.AreEqual(source[sourceEquivIndex], subset.ByteAt(0)); packet.Replace(subsetStart, new byte[] { 255 }, 0, 1); Assert.AreEqual(255, packet.ByteAt(subsetStart)); Assert.AreEqual(255, subset.ByteAt(0)); packet.Replace(subsetStart, source, sourceEquivIndex, 1); Assert.AreEqual(source[sourceEquivIndex], packet.ByteAt(subsetStart)); Assert.AreEqual(source[sourceEquivIndex], subset.ByteAt(0)); CheckNotDisposed(subset); /// Ensure that disposing of the subset doesn't dispose the parent packet for (int i = 0; i < packet.Length; i++) { Assert.AreEqual(source[sourceStart + (i % sourceCount)], packet.ByteAt(i)); } CheckDisposed(packet); } } CheckForUndisposedSegments(); }
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 TestRemoveBytes() { byte[] bytes = new byte[256]; for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)(i % 256); } byte[] reversed = new byte[bytes.Length]; Buffer.BlockCopy(bytes, 0, reversed, 0, bytes.Length); Array.Reverse(reversed); TransportPacket tp = new TransportPacket(); Stream stream = tp.AsWriteStream(); // we'll make 256 copies of [0,1,...,254,255,255,254,...,1,0] for (int i = 0; i < 256; i++) { stream.Write(bytes, 0, bytes.Length); stream.Write(reversed, 0, reversed.Length); } stream.Flush(); Assert.AreEqual((bytes.Length + reversed.Length) * 256, tp.Length); byte[] copy = tp.ToArray(); Assert.AreEqual((bytes.Length + reversed.Length) * 256, tp.Length); // Now remove successively larger chunks from between the bytes/reversed // boundary points int nextIndex = 0; // the start into the next bytes/reverse pair for (int i = 0; i < bytes.Length / 2; i++) { Assert.AreEqual(0, tp.ByteAt(nextIndex)); Assert.AreEqual(1, tp.ByteAt(nextIndex + 1)); Assert.AreEqual(bytes.Length - 2, tp.ByteAt(nextIndex + bytes.Length - 2)); Assert.AreEqual(bytes.Length - 1, tp.ByteAt(nextIndex + bytes.Length - 1)); Assert.AreEqual(bytes.Length - 1, tp.ByteAt(nextIndex + bytes.Length)); Assert.AreEqual(bytes.Length - 2, tp.ByteAt(nextIndex + bytes.Length +1)); Assert.AreEqual(1, tp.ByteAt(nextIndex + bytes.Length + reversed.Length - 2)); Assert.AreEqual(0, tp.ByteAt(nextIndex + bytes.Length + reversed.Length - 1)); // remove 2i bytes from the end of the bytes copy extending tp.RemoveBytes(nextIndex + bytes.Length - i, 2 * i); Assert.AreEqual((bytes.Length + reversed.Length) * 256 - 2 * i * (i+1) / 2, tp.Length); Assert.AreEqual(0, tp.ByteAt(nextIndex)); Assert.AreEqual(bytes.Length - i - 1, tp.ByteAt(nextIndex + bytes.Length - i - 1)); Assert.AreEqual(bytes.Length - i - 1, tp.ByteAt(nextIndex + bytes.Length - i)); Assert.AreEqual(0, tp.ByteAt(nextIndex + bytes.Length + reversed.Length - 2*i - 1)); nextIndex += bytes.Length + reversed.Length - 2 * i; } CheckDisposed(tp); CheckForUndisposedSegments(); }
public void TestByteAt() { TransportPacket packet = new TransportPacket(); packet.Append(new byte[] {0, 1, 2, 3}); packet.Append(new byte[] {4, 5, 6, 7, 8}); packet.Append(new byte[] {9}); for(int i = 0; i < 10; i++) { Assert.AreEqual(i, packet.ByteAt(i)); packet.BytesAt(i, 1, (b,offset) => Assert.AreEqual(i, b[offset])); } packet.BytesAt(0, 10, (bytes, offset) => { for(int i = 0; i < 10; i++) { Assert.AreEqual(i, bytes[i]); } }); try { packet.ByteAt(10); Assert.Fail("Should have thrown ArgumentOutOfRange"); } catch (ArgumentOutOfRangeException) { /*ignore*/ } try { packet.BytesAt(10,1, (b,o) => Assert.Fail("should have thrown AOOR")); Assert.Fail("Should have thrown ArgumentOutOfRange"); } catch (ArgumentOutOfRangeException) { /*ignore*/ } try { packet.BytesAt(8, 8, (b, o) => Assert.Fail("should have thrown AOOR")); Assert.Fail("Should have thrown ArgumentOutOfRange"); } catch (ArgumentOutOfRangeException) { /*ignore*/ } CheckDisposed(packet); CheckForUndisposedSegments(); }