public TestServerWrapper(IPEndPoint serverEndPoint, ICdpTimeout timeout) { this.success = false; this.server = null; CdpServerForTests cdpServer = new CdpServerForTests(); server = new CdpServerOverUdp(serverEndPoint); new Thread(() => { try { server.Run(cdpServer, new Byte[256], timeout); } catch (Exception e) { if (!success) { Console.WriteLine("[Server] '{0}': {1}", e.GetType().Name, e); } } finally { Console.WriteLine("[Server] Stopped"); } }).Start(); Thread.Sleep(100); // wait for server to start }
//Int32 lastPayloadIDReceived; public CdpServerDatagramHandler(CdpTransmitter transmitter, ICdpServerHandler serverHandler, ICdpTimeout timeout) { this.transmitter = transmitter; this.serverHandler = serverHandler; this.timeout = timeout; //this.lastPayloadIDReceived = Cdp.MaxPayloadID; }
public void Run(ICdpServer server, Byte[] maxDatagramBuffer, ICdpTimeout timeout) { Cdp.UdpServerLoop(server, udpSocket, endPoint, maxDatagramBuffer, timeout); }
public void ControllerSendPayloadWithAck(UInt32 offsetLimit, ICdpTimeout timeout) { // 1. Check for acks/resends/halts Byte[] bufferToSend = GetRequestedBuffer(offsetLimit); try { // Cdp Header UInt32 payloadID = nextPayloadID++; bufferToSend[0] = (Byte)(((Byte)CdpFlagValue.PayloadWithAck << 4) | (0x0F & (payloadID >> 8))); bufferToSend[1] = (Byte)payloadID; // // Send the datagram // connectedDatagramTransmitter.Send(bufferToSend, 0, offsetLimit); Int64 stopwatchTicksAfterSend = Stopwatch.GetTimestamp(); Int32 timeoutMillis = timeout.WaitForAckInitialRetryTimeout(averageLatency); if (timeoutMillis < 0) { throw new InvalidOperationException(String.Format( "The ICdpTimeout class '{0}' returned negative ({1}) when calling WaitForAckInitialTimeout({2})", timeout.GetType().Name, timeoutMillis, averageLatency)); } Int32 retries = 0; // Keep resending the datagram until a header is recevied or timeout is reached while (true) { Console.WriteLine("Send Retry {0}", retries); Int32 bytesRead = connectedDatagramTransmitter.ReceiveBlocking(headerBuffer, 0, 2, timeoutMillis); if (bytesRead < 0) { Int32 elapsedMillis = (Stopwatch.GetTimestamp() - stopwatchTicksAfterSend).StopwatchTicksAsInt32Milliseconds(); timeoutMillis = timeout.WaitForAckRetryOrTimeout(retries, averageLatency, elapsedMillis, timeoutMillis); if (timeoutMillis <= 0) { throw new TimeoutException(String.Format("Timed out waiting for ack: {0} retries {1} milliseconds elapsed", retries, elapsedMillis)); } // Retry sending the packet connectedDatagramTransmitter.Send(bufferToSend, 0, offsetLimit); retries++; continue; } // // Check the datagram // if (bytesRead == 0) { // It's just a heart beat packet } else { Byte receivedFlagValue = (Byte)(headerBuffer[0] >> 4); UInt32 receivedPayloadID = (UInt32)((0xF00 & (headerBuffer[0] << 8)) | (0xFF & headerBuffer[1])); if (receivedFlagValue == (Byte)CdpFlagValue.Ack) { if (receivedPayloadID == payloadID) { Console.WriteLine("[CdpDebug] Received ACK for payload id {0}", payloadID); break; } Console.WriteLine("[CdpDebug] Got an ack for an old payload id {0}?", receivedPayloadID); } else if (receivedFlagValue == (Byte)CdpFlagValue.Halt) { throw new CdpBadHaltException(); } else if (receivedFlagValue == (Byte)CdpFlagValue.Resend) { if (receivedPayloadID <= payloadID) { UInt32 index = datagramQueue.PayloadIDToIndex(receivedPayloadID); if (index >= 0) { if (receivedPayloadID < payloadID) { do { Console.WriteLine("[Debug] Queue Index {0} Payload ID {1}", index, receivedPayloadID + index); CdpBufferPoolDatagram datagram = datagramQueue.queue[index]; connectedDatagramTransmitter.Send(datagram.datagram, 0, datagram.length); index++; } while (receivedPayloadID + index < payloadID); } connectedDatagramTransmitter.Send(bufferToSend, 0, offsetLimit); } } } else { Console.WriteLine("Unknown flag value {0} from '{1}' (Maybe I should throw an exception? TBD)", receivedFlagValue, connectedDatagramTransmitter.RemoteEndPoint); } } // // Get next timeout // { Int32 elapsedMillis = (Stopwatch.GetTimestamp() - stopwatchTicksAfterSend).StopwatchTicksAsInt32Milliseconds(); timeoutMillis = timeout.WaitForAckRetryOrTimeout(retries, averageLatency, elapsedMillis, timeoutMillis); if (timeoutMillis <= 0) { throw new TimeoutException(String.Format("Timed out waiting for ack: {0} retries {1} milliseconds elapsed", retries, elapsedMillis)); } } } datagramQueue.EmptyAndFree(); // free the queue because everything has been acked } finally { Cdp.BufferPool.FreeBuffer(bufferToSend); } }
public static void UdpServerLoop(ICdpServer server, Socket udpSocket, EndPoint listenEndPoint, Byte[] maxDatagramBuffer, ICdpTimeout timeout) { Dictionary <EndPoint, CdpServerDatagramHandler> endPointToHandler = new Dictionary <EndPoint, CdpServerDatagramHandler>(); //Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); udpSocket.Bind(listenEndPoint); try { while (true) { EndPoint from = listenEndPoint; int bytesRead; try { bytesRead = udpSocket.ReceiveFrom(maxDatagramBuffer, ref from); } catch (SocketException e) { Boolean stopServerGracefully = server.SocketException(e); if (stopServerGracefully) { throw new NotImplementedException("Stop server gracefully not implemented"); } continue; } if (bytesRead <= 0) { // it's just a heartbeat Console.WriteLine("[CdpDebug] Got a heartbeat from '{0}'", from); continue; } CdpServerDatagramHandler handler; // // Handle new connection // if (!endPointToHandler.TryGetValue(from, out handler)) { CdpTransmitter transmitter = new CdpTransmitter(new UdpConnectedServerTransmitter(udpSocket, from)); ICdpServerHandler serverHandler; Int32 maxSendBeforeAck; Boolean refuseConnection = server.NewConnection(transmitter, out serverHandler, out maxSendBeforeAck); if (refuseConnection) { handler.Closed(); server.ConnectionClosed(from); throw new NotImplementedException("Refusing connection is not yet implemented"); } if (serverHandler == null) { handler.Closed(); server.ConnectionClosed(from); throw new InvalidOperationException("You provided a null payload handler"); } handler = new CdpServerDatagramHandler(transmitter, serverHandler, timeout); endPointToHandler.Add(from, handler); } Boolean closeClient = handler.Datagram(maxDatagramBuffer, 0, bytesRead); if (closeClient) { handler.Closed(); server.ConnectionClosed(from); endPointToHandler.Remove(from); } } } finally { if (udpSocket != null) { udpSocket.Close(); } } }