public void TestWriteStream() { /// This tests ReplaceBytes too. byte[] bytes = new byte[271]; // so it doesn't align with a segment size for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)(i % 256); } TransportPacket tp = new TransportPacket(); Stream stream = tp.AsWriteStream(); long initialPosition = stream.Position; Assert.AreEqual(0, initialPosition); for (int i = 0; i < 255; i++) { stream.Write(bytes, i, bytes.Length - i); stream.Write(bytes, 0, i); } stream.Flush(); Assert.AreEqual(bytes.Length * 255, tp.Length); byte[] copy = tp.ToArray(); Assert.AreEqual(bytes.Length * 255, copy.Length); stream.Position = initialPosition; for (int i = 0; i < 255; i++) { for (int j = 0; j < bytes.Length; j++) { Assert.AreEqual(bytes[(i + j) % bytes.Length], copy[i * bytes.Length + j]); Assert.AreEqual(bytes[(i + j) % bytes.Length], stream.ReadByte()); } } Assert.AreEqual(stream.Length, stream.Position); stream.Position = initialPosition; stream.Position = stream.Length; CheckDisposed(tp); CheckForUndisposedSegments(); }
public void TestWriteStreamLargeWrite() { byte[] bytes = new byte[TransportPacket.MaxSegmentSize * 3 + 13]; for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte) (i%256); } TransportPacket tp = new TransportPacket(); Stream stream = tp.AsWriteStream(); Assert.AreEqual(0, stream.Position); stream.Write(bytes, 0, bytes.Length); stream.Flush(); Assert.AreEqual(bytes.Length, tp.Length); Assert.AreEqual(bytes, tp.ToArray()); }
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 TestToArray() { 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 }); byte[] original = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; Assert.AreEqual(original, packet.ToArray()); for (int i = 0; i < packet.Length; i++) { for (int count = 0; count < packet.Length - i; count++) { byte[] sub = packet.ToArray(i, count); for (int j = 0; j < count; j++) { Assert.AreEqual(original[i + j], sub[j]); } } } CheckDisposed(packet); CheckForUndisposedSegments(); }
public void TestNewTransportPacket() { TransportPacket.MaxSegmentSize = TransportPacket.MinSegmentSize; 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 }); // Ensure that new TransportPacket() properly copies out TransportPacket copy = new TransportPacket(packet, 1, 8); Assert.AreEqual(packet.ToArray(1, 8), copy.ToArray()); CheckDisposed(packet, copy); CheckForUndisposedSegments(); }
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 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(); }
/// <summary> /// Wraps ITransport.SendPacket(byte[],int,int). In addition, writes data to a sink if /// MillipedeTransport initialized with Mode.Record. /// </summary> /// <see cref="ITransport.SendPacket"/> public void SendPacket(TransportPacket packet) { switch (recorder.Mode) { case MillipedeMode.Unconfigured: case MillipedeMode.PassThrough: default: underlyingTransport.SendPacket(packet); // underlyingTransport is responsible for disposing of packet return; case MillipedeMode.Record: try { packet.Retain(); // since underlyingTransport will dispose of packet underlyingTransport.SendPacket(packet); recorder.Record(new MillipedeEvent(milliDescriptor, MillipedeEventType.SentPacket, packet.ToArray())); packet.Dispose(); } catch(GTException ex) { recorder.Record(new MillipedeEvent(milliDescriptor, MillipedeEventType.Exception, ex)); throw; } return; case MillipedeMode.Playback: MillipedeEvent e = recorder.WaitForReplayEvent(milliDescriptor, MillipedeEventType.Exception, MillipedeEventType.SentPacket, MillipedeEventType.Error); if(e.Type == MillipedeEventType.Exception) { throw (Exception)e.Context; } if (e.Type == MillipedeEventType.Error && ErrorEvent != null) { ErrorEvent((ErrorSummary)e.Context); } return; } }
public void TestBasics() { byte[] source = new byte[] { 0, 1, 2, 3, 4 }; TransportPacket p = new TransportPacket(source, 1, 4); Assert.AreEqual(4, p.Length); Assert.AreEqual(1, ((IList<ArraySegment<byte>>)p).Count); Assert.AreEqual(4, ((IList<ArraySegment<byte>>)p)[0].Count); byte[] result = p.ToArray(); Assert.AreEqual(4, result.Length); for (int i = 0; i < 4; i++) { Assert.AreEqual(source[1 + i], result[i]); } CheckDisposed(p); 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(); }
public override void SendPacket(TransportPacket packet) { ContractViolation.Assert(packet.Length > 0, "cannot send 0-byte packets"); ContractViolation.Assert(packet.Length <= MaximumPacketSize, String.Format("packet exceeds maximum packet size: {0} > {1}", packet.Length, MaximumPacketSize)); handle.Put(packet.ToArray()); NotifyPacketSent(packet); }
/// <summary> /// Send a packet on the UDP socket. /// </summary> /// <exception cref="SocketException">thrown if there is a socket error</exception> public int Send(TransportPacket packet, EndPoint remote) { // Is our throwing a SocketException considered out of line? if (!Active) { throw new SocketException((int)SocketError.Shutdown); } // Sadly SentTo does not support being provided a IList<ArraySegment<byte>> packet.Consolidate(); // try to reduce to a single segment IList<ArraySegment<byte>> bytes = packet; if (bytes.Count == 1) { return udpClient.Client.SendTo(bytes[0].Array, bytes[0].Offset, bytes[0].Count, SocketFlags.None, remote); } // hopefully this won't happen often; we could maintain our own bytearray pool return udpClient.Client.SendTo(packet.ToArray(), SocketFlags.None, remote); }
/// <summary> /// Handle incoming packets from previously-unknown remote endpoints. /// We check if the packet indicates a handshake and, if so, negotiate. /// Otherwise we send a GT error message and disregard the packet. /// </summary> /// <param name="ep">the remote endpoint</param> /// <param name="packet">the first packet</param> protected void PreviouslyUnseenUdpEndpoint(EndPoint ep, TransportPacket packet) { TransportPacket response; Stream ms; // This is the GT (UDP) protocol 1.0: // bytes 0 - 3: the protocol version (the result from ProtocolDescriptor) // bytes 4 - n: the number of bytes in the capability dictionary (see ByteUtils.EncodeLength) // bytes n+1 - end: the capability dictionary // The # bytes in the dictionary isn't actually necessary in UDP, but oh well foreach(TransportFactory<UdpHandle> factory in factories) { if(packet.Length >= factory.ProtocolDescriptor.Length && ByteUtils.Compare(packet.ToArray(0, factory.ProtocolDescriptor.Length), factory.ProtocolDescriptor)) { packet.RemoveBytes(0, factory.ProtocolDescriptor.Length); ms = packet.AsReadStream(); Dictionary<string, string> dict = null; try { uint count = ByteUtils.DecodeLength(ms); // we don't use it dict = ByteUtils.DecodeDictionary(ms); if(ms.Position != ms.Length) { byte[] rest = packet.ToArray(); log.Info(String.Format( "{0} bytes still left at end of UDP handshake packet: {1} ({2})", rest.Length, ByteUtils.DumpBytes(rest, 0, rest.Length), ByteUtils.AsPrintable(rest, 0, rest.Length))); } ITransport result = factory.CreateTransport(UdpHandle.Bind(udpMultiplexer, ep)); if (ShouldAcceptTransport(result, dict)) { // Send confirmation // NB: following uses the format specified by LWMCF v1.1 response = new TransportPacket(LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.Acknowledged, (uint)factory.ProtocolDescriptor.Length)); response.Append(factory.ProtocolDescriptor); udpMultiplexer.Send(response, ep); NotifyNewTransport(result, dict); } else { // NB: following follows the format specified by LWMCF v1.1 response = new TransportPacket(LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.IncompatibleVersion, 0)); udpMultiplexer.Send(response, ep); result.Dispose(); } return; } catch(Exception e) { log.Warn(String.Format("Error decoding handshake from remote {0}", ep), e); } } } // If we can figure out some way to say: the packet is an invalid form: // response = new TransportPacket(); // ms = response.AsWriteStream(); // log.Info("Undecipherable packet (ignored)"); // // NB: following follows the format specified by LWMCF v1.1 // LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.UnknownConnexion, // (uint)ProtocolDescriptor.Length, ms); // ms.Write(ProtocolDescriptor, 0, ProtocolDescriptor.Length); // ms.Flush(); // udpMultiplexer.Send(response, ep); response = new TransportPacket(); ms = response.AsWriteStream(); log.Info("Unknown protocol version: " + ByteUtils.DumpBytes(packet.ToArray(), 0, 4) + " [" + ByteUtils.AsPrintable(packet.ToArray(), 0, 4) + "]"); // NB: following follows the format specified by LWMCF v1.1 LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.IncompatibleVersion, 0, ms); ms.Flush(); udpMultiplexer.Send(response, ep); }
protected void ClientReceivedPacket(TransportPacket packet, ITransport transport) { byte[] received = packet.ToArray(); bool ok = true; if (received[0] != (byte)(clientPacketCount + clientMissedOffset)) { Console.WriteLine("client: ERROR: expected packet#" + (clientPacketCount + clientMissedOffset) + " but received packet #" + received[0]); ok = false; } else { Debug("client: received expected packet#{0}", (byte)(clientPacketCount + clientMissedOffset)); } if (!CheckPacket(received, "client")) { ok = false; } Console.Write(ok ? '+' : '!'); clientPacketCount++; }
public void TestMultiSegments() { byte[] source = new byte[] { 0, 1, 2, 3, 4 }; TransportPacket p = new TransportPacket(source, 1, 4); Assert.AreEqual(4, p.Length); Assert.AreEqual(1, ((IList<ArraySegment<byte>>)p).Count); for (int i = 0; i < 10; i++) { p.Append(source, 1, 4); } Assert.AreEqual(4 * 11, p.Length); byte[] result = p.ToArray(); Assert.AreEqual(4 * 11, result.Length); for (int j = 0; j < 11; j++) { for (int i = 0; i < 4; i++) { Assert.AreEqual(source[1 + i], result[4 * j + i]); } } CheckDisposed(p); CheckForUndisposedSegments(); }
protected void ServerReceivedPacket(TransportPacket packet, ITransport transport) { byte[] received = packet.ToArray(); if (received[0] != (byte)(serverPacketCount + serverMissedOffset)) { Console.WriteLine("server: ERROR: expected packet#" + (serverPacketCount + serverMissedOffset) + " but received packet #" + received[0]); } else { Debug("server: received expected packet#{0}", (byte)(serverPacketCount + serverMissedOffset)); } CheckPacket(received, "server"); Debug("==> server: replying with byte array"); packet.Retain(); // must retain since SendPacket() will dispose server.SendPacket(packet); serverPacketCount++; }
/// <summary> /// ITransports use a observer-pattern (implemented with events and callbacks) to notify /// other GT2 components. Since these other componets register to the MillipedeTransport, /// there must be a mechanism to forward notifications from the ITransport to other GT2 /// components. /// </summary> /// <see cref="ITransport.PacketReceived"/> private void _underlyingTransports_PacketReceivedEvent(TransportPacket packet, ITransport transport) { recorder.Record(new MillipedeEvent(milliDescriptor, MillipedeEventType.PacketReceived, packet.ToArray())); if (PacketReceived == null) { return; } PacketReceived(packet, this); }