public void TestResendsAfterLosingAcks() { Cdp.TryStaticInit(Cdp.MaxPayloadWithIDOverUdp); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Loopback, testUdpPort); FixedRetryTimeout timeout = new FixedRetryTimeout(100, 6); using (TestServerWrapper server = new TestServerWrapper(serverEndPoint, timeout)) { Cdp.TryStaticInit(Cdp.MaxPayloadWithIDOverUdp); // // // UdpConnectedClientTransmitter udpTransmitter = new UdpConnectedClientTransmitter(serverEndPoint); ClumsyTransmitter clumsyTransmitter = new ClumsyTransmitter(udpTransmitter, Console.Out); CdpTransmitter transmitter = new CdpTransmitter(clumsyTransmitter); Int64 startTicks = Stopwatch.GetTimestamp(); Console.WriteLine("[Sender {0} millis] Sending...", (Stopwatch.GetTimestamp() - startTicks).StopwatchTicksAsInt64Milliseconds()); UInt32 offset; Byte[] datagram = transmitter.RequestSendBuffer(10, out offset); for (Byte i = 0; i < 10; i++) { datagram[offset++] = (Byte)('A' + i); } clumsyTransmitter.DropAllReceivedDatagramsForTheNext(400); transmitter.ControllerSendPayloadWithAck(offset, timeout); server.TestSucceeded(); } }
public void SimpleTestMethod() { Cdp.TryStaticInit(Cdp.MaxPayloadWithIDOverUdp); VirtualDatagramTransmitter transmitter = new VirtualDatagramTransmitter(); transmitter.Print(Console.Out); byte[] sendBuffer = new Byte[] { 0, 1, 2, 3, 4 }; byte[] receiveBuffer; Int32 length; // // Send Buffer // transmitter.Send(sendBuffer, 0, (UInt32)sendBuffer.Length); Assert.AreEqual(1, transmitter.DatagramsInSendQueue); // // Receive Buffer // receiveBuffer = new Byte[sendBuffer.Length]; length = transmitter.otherTransmitter.ReceiveNonBlocking(receiveBuffer, 0, (UInt32)receiveBuffer.Length); Assert.AreEqual(sendBuffer.Length, length); Assert.AreEqual(0, transmitter.DatagramsInSendQueue); CdpTest.AssertEqual(sendBuffer, receiveBuffer); length = transmitter.otherTransmitter.ReceiveNonBlocking(receiveBuffer, 0, (UInt32)sendBuffer.Length); Assert.AreEqual(-1, length); // // Send the buffer 5 times // for (int i = 0; i < 5; i++) { sendBuffer[0] = (Byte)i; transmitter.Send(sendBuffer, 0, (UInt32)sendBuffer.Length); Assert.AreEqual(i + 1, transmitter.DatagramsInSendQueue); } transmitter.Print(Console.Out); for (int i = 0; i < 5; i++) { Console.WriteLine("Receiving datagram {0}", i + 1); receiveBuffer = new Byte[sendBuffer.Length]; length = transmitter.otherTransmitter.ReceiveNonBlocking(receiveBuffer, 0, (UInt32)receiveBuffer.Length); Assert.AreEqual(sendBuffer.Length, length); Assert.AreEqual(4 - i, transmitter.DatagramsInSendQueue); sendBuffer[0] = (Byte)i; CdpTest.AssertEqual(sendBuffer, receiveBuffer); } length = transmitter.otherTransmitter.ReceiveNonBlocking(receiveBuffer, 0, (UInt32)sendBuffer.Length); Assert.AreEqual(-1, length); }
public void TestMethod1() { Cdp.TryStaticInit(Cdp.MaxPayloadWithIDOverUdp); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Loopback, testUdpPort); FixedRetryTimeout timeout = new FixedRetryTimeout(500, 6); using (TestServerWrapper server = new TestServerWrapper(serverEndPoint, timeout)) { UdpConnectedClientTransmitter udpTransmitter = new UdpConnectedClientTransmitter(serverEndPoint); CdpTransmitter transmitter = new CdpTransmitter(udpTransmitter); UInt32 offset; Byte[] myMessage; Byte[] payloadBuffer; // // Send and wait for ack // myMessage = Encoding.UTF8.GetBytes("This should be a normal payload with an immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; Console.WriteLine("[Client] Sending Payload With Ack..."); transmitter.ControllerSendPayloadWithAck(offset, timeout); // // Send heartbeat // Console.WriteLine("[Client] Sending Heartbeat..."); transmitter.SendHearbeat(); // // Send Random Payload // myMessage = Encoding.UTF8.GetBytes("This should be a random payload"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; Console.WriteLine("[Client] Sending Random Payload..."); transmitter.ControllerSendRandomPayload(offset); // // Send Payload no ack // myMessage = Encoding.UTF8.GetBytes("This should be the first payload with no immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; Console.WriteLine("[Client] Sending Payload No Ack..."); transmitter.ControllerSendPayloadNoAck(offset); // // Send Payload no ack // myMessage = Encoding.UTF8.GetBytes("This should be the second payload with no immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; Console.WriteLine("[Client] Sending Payload No Ack..."); transmitter.ControllerSendPayloadNoAck(offset); // // Send and wait for ack // myMessage = Encoding.UTF8.GetBytes("This should be a normal payload with an immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; Console.WriteLine("[Client] Sending Payload With Ack..."); transmitter.ControllerSendPayloadWithAck(offset, timeout); // // Send Halt // Console.WriteLine("[Client] Sending Halt..."); transmitter.SendHaltNoPayload(); server.TestSucceeded(); Console.WriteLine("[Client] Done (Success)"); } }
// // This function implements an algorithm in the CDP protocol // specification. See CDP documentation to see the pseudocode for this function. // // Returns true to close the client // public Boolean Datagram(Byte[] datagram, Int32 offset, Int32 length) { /* * Console.WriteLine("[CdpDebug] Got Datagram {0} Bytes: {1}", * length, (length <= 0) ? "<null>" : (length < 10) ? BitConverter.ToString(datagram, offset, length) : * BitConverter.ToString(datagram, offset, 10) + "..."); */ if (length <= 0) { return(false); // just a heartbeat } Byte flagValue = (Byte)(datagram[offset] >> 4); // // Check if it is a halt or an out of order datagram // if (flagValue > 7) { if (flagValue == (Byte)CdpFlagValue.Halt) { serverHandler.Halt(); return(true); // true to close client } if (flagValue == (Byte)CdpFlagValue.Resend) { throw new NotImplementedException(); } // The packet is a handler packet, so it should be ignored return(false); } // // Check if it contains a payload with an id // if (flagValue < 6) { if (length < 2) { // The datagram is not valid CDP, halt Console.WriteLine("[CdpDebug] Received Invalid CDP from client, because it has a flag value of {0}, but the datagram is not long enough for the id", flagValue); transmitter.SendHaltNoPayload(); serverHandler.Halt(); return(true); } UInt32 payloadID = (UInt32)((0xF00 & (datagram[offset] << 8)) | (0xFF & datagram[offset + 1])); while (true) { Int32 payloadDiff = Cdp.PayloadDiff(payloadID, transmitter.nextPayloadID); if (payloadDiff == 0) { break; } // Check if it's a resend if (payloadDiff == Cdp.MaxPayloadID) { if (flagValue < 4 && ((flagValue & (Byte)CdpFlagValueFlag.ImmediateAck) != 0)) { Console.WriteLine("[CdpDebug] Got a resend of payload {0}. The payload requested an ACK but the ACK must have been lost.", payloadID); // Resend the ack transmitter.HandlerSendHeader((Byte)CdpFlagValue.Ack, payloadID); } } if (payloadDiff >= 0x800) { // The packet is a resend so ignore it Console.WriteLine("[CdpDebug] Received resend of payload id {0}", payloadID); return(false); } //throw new NotImplementedException(String.Format("Received payload id of {0} but the diff is {1} so it is out of order. Out of order packets are not yet implemented", // payloadID, payloadDiff)); // Request a resend transmitter.HandlerSendHeader((Byte)CdpFlagValue.Resend, transmitter.nextPayloadID); return(false); } // Update last payload id received transmitter.nextPayloadID++; // // If it's not a close or halt with payload, send immediate ack if requested // if (flagValue < 4 && ((flagValue & (Byte)CdpFlagValueFlag.ImmediateAck) != 0)) { Console.WriteLine("[CdpDebug] (FlagValue={0}) Sending Ack of payload id {1}", flagValue, payloadID); // Ack the payload transmitter.HandlerSendHeader((Byte)CdpFlagValue.Ack, payloadID); } // Handle the payload Boolean closeClient = serverHandler.Payload(datagram, offset + 2, length - 2); if (closeClient) { // close the connection transmitter.SendHaltNoPayload(); serverHandler.Halt(); return(true); // don't keep client alive } if (flagValue >= 4) // Either Close or Halt { if (flagValue == 5) // It was a close { Boolean acknowledgeClose = serverHandler.Close(); if (acknowledgeClose) { throw new NotImplementedException(); } else { transmitter.SendHaltNoPayload(); } } serverHandler.Halt(); return(true); } if ((flagValue & (Byte)CdpFlagValueFlag.GiveControl) != 0) { Int32 sendBufferOffsetLimit; Boolean requestImmediateAck; serverHandler.GotControl(null, out sendBufferOffsetLimit, out requestImmediateAck); } return(false); } else if (flagValue == (Byte)CdpFlagValue.RandomPayload) { return(serverHandler.RandomPayload(datagram, 1, length - 1)); } else { // The datagram is not valid CDP, halt Console.WriteLine("[CdpDebug] Received Invalid CDP from client, unrecognized flag value of {0}", flagValue); transmitter.SendHaltNoPayload(); serverHandler.Halt(); return(true); } }
public void Run(ICdpServer server, Byte[] maxDatagramBuffer, ICdpTimeout timeout) { Cdp.UdpServerLoop(server, udpSocket, endPoint, maxDatagramBuffer, timeout); }
static Int32 Main(string[] args) { CdpCatOptions optionsParser = new CdpCatOptions(); if (args.Length <= 0) { optionsParser.PrintUsage(); return(-1); } List <String> nonOptionArgs = optionsParser.Parse(args); Cdp.StaticInit(optionsParser.maxPayload.ArgValue); ICdpTimeout timeout = new MyCdpTimeout(); if (optionsParser.listenPort.set) { IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, optionsParser.listenPort.ArgValue); MyCdpServer cdpServer = new MyCdpServer(); Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); Cdp.UdpServerLoop(cdpServer, udpSocket, localEndPoint, new Byte[optionsParser.maxPayload.ArgValue], timeout); return(-1); } else { if (nonOptionArgs.Count < 2) { Console.WriteLine("Missing command line arguments"); optionsParser.PrintUsage(); return(-1); } UInt16 port = UInt16.Parse(nonOptionArgs[1]); EndPoint serverEndPoint = new IPEndPoint(EndPoints.ParseIPOrResolveHost(nonOptionArgs[0], DnsPriority.IPv4ThenIPv6), port); UdpConnectedClientTransmitter udpTransmitter = new UdpConnectedClientTransmitter(serverEndPoint); CdpTransmitter transmitter = new CdpTransmitter(udpTransmitter); UInt32 offset; Byte[] myMessage; Byte[] payloadBuffer; transmitter.SendHearbeat(); myMessage = Encoding.UTF8.GetBytes("This should be a random payload"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); transmitter.ControllerSendRandomPayload(offset + (UInt32)myMessage.Length); myMessage = Encoding.UTF8.GetBytes("This should be the first payload with no immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, (UInt32)myMessage.Length); transmitter.ControllerSendPayloadNoAck(offset + (UInt32)myMessage.Length); myMessage = Encoding.UTF8.GetBytes("This should be the second payload with no immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, (UInt32)myMessage.Length); transmitter.ControllerSendPayloadNoAck(offset + (UInt32)myMessage.Length); // // Send and wait for ack // myMessage = Encoding.UTF8.GetBytes("This should be a normal payload with an immediate ack"); payloadBuffer = transmitter.RequestSendBuffer((UInt32)myMessage.Length, out offset); Array.Copy(myMessage, 0, payloadBuffer, offset, myMessage.Length); offset += (UInt32)myMessage.Length; transmitter.ControllerSendPayloadWithAck(offset, timeout); transmitter.SendHaltNoPayload(); return(0); } }