static void ValidateClient(TcpClient socket, Shape reference, ServerInfoMessage serverInfo, CreateShapeFunction createShape, ShapeValidationFunction validate, uint timeoutSec = 10u) { Stopwatch timer = new Stopwatch(); ServerInfoMessage readServerInfo = new ServerInfoMessage(); Dictionary <ulong, Resource> resources = new Dictionary <ulong, Resource>(); PacketBuffer packetBuffer = new PacketBuffer(64 * 1024); Shape shape = createShape(); bool endMsgReceived = false; bool serverInfoRead = false; bool shapeMsgRead = false; timer.Start(); // Keep looping until we get a CIdEnd ControlMessage or timeoutSec elapses. // Timeout ignored when debugger is attached. while (!endMsgReceived && (Debugger.IsAttached || timer.ElapsedMilliseconds / 1000u < timeoutSec)) { if (socket.Available <= 0) { Thread.Yield(); continue; } // Data available. Read from the network stream into a buffer and attempt to // read a valid message. packetBuffer.Append(socket.GetStream(), socket.Available); PacketBuffer completedPacket; bool crcOk = true; while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk) { Assert.True(crcOk); if (crcOk) { if (packetBuffer.DroppedByteCount != 0) { Console.Error.WriteLine("Dropped {0} bad bytes", packetBuffer.DroppedByteCount); packetBuffer.DroppedByteCount = 0; } Assert.Equal(PacketHeader.PacketMarker, completedPacket.Header.Marker); Assert.Equal(PacketHeader.PacketVersionMajor, completedPacket.Header.VersionMajor); Assert.Equal(PacketHeader.PacketVersionMinor, completedPacket.Header.VersionMinor); NetworkReader packetReader = new NetworkReader(completedPacket.CreateReadStream(true)); switch (completedPacket.Header.RoutingID) { case (int)RoutingID.ServerInfo: serverInfoRead = true; Assert.True(readServerInfo.Read(packetReader)); // Validate server info. Assert.Equal(serverInfo.TimeUnit, readServerInfo.TimeUnit); Assert.Equal(serverInfo.DefaultFrameTime, readServerInfo.DefaultFrameTime); Assert.Equal(serverInfo.CoordinateFrame, readServerInfo.CoordinateFrame); unsafe { for (int i = 0; i < ServerInfoMessage.ReservedBytes; ++i) { Assert.Equal(serverInfo.Reserved[i], readServerInfo.Reserved[i]); } } break; case (int)RoutingID.Control: { // Only interested in the CIdEnd message to mark the end of the stream. ControlMessage msg = new ControlMessage(); Assert.True(msg.Read(packetReader)); if (completedPacket.Header.MessageID == (int)ControlMessageID.End) { endMsgReceived = true; } break; } case (int)RoutingID.Mesh: HandleMeshMessage(completedPacket, packetReader, resources); break; default: if (completedPacket.Header.RoutingID == reference.RoutingID) { shapeMsgRead = true; HandleShapeMessage(completedPacket, packetReader, shape, reference); } break; } } } // else fail? } Assert.True(serverInfoRead); Assert.True(shapeMsgRead); Assert.True(endMsgReceived); // Validate the shape state. if (shapeMsgRead) { validate(shape, reference, resources); } }
private IEnumerator Run() { // Reconnection attempts so we don't hammer the system on failure. float connectionPollTimeSec = 0.25f; TcpClient socket = null; PacketBuffer packetBuffer = new PacketBuffer(4 * 1024); System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); ClientConnector connector = null; while (!_quitFlag) { // First try establish a connection. while (!_quitFlag && !_connection.Connected) { if (connector == null) { connector = new ClientConnector(_connection.EndPoint); } if (!connector.Connecting) { if (connector.Connected) { socket = connector.Accept(); connector = null; _connection.Connected = true; Status = NetworkThreadStatus.Connected; _currentFrame = _totalFrames = 0u; _packetQueue.Enqueue(BuildResetPacket()); } else { connector.Abort(); connector = null; if (!_connection.AutoReconnect) { // Failed connection and no auto reconnect. Status = NetworkThreadStatus.ConnectionFailed; break; } } } if (socket == null) { // Wait the timeout period before attempting to reconnect. yield return(Workthread.CreateWait(connectionPollTimeSec)); } } timer.Start(); // Read while connected. while (!_quitFlag && TcpClientUtil.Connected(socket)) { // We have a connection. Read messages while we can. if (socket.Available > 0) { // Data available. Read from the network stream into a buffer and attempt to // read a valid message. packetBuffer.Append(socket.GetStream(), socket.Available); PacketBuffer completedPacket; bool crcOk = true; while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk) { if (crcOk) { // Decode and decompress collated packets. This will just return the same packet // if not collated. _collatedDecoder.SetPacket(completedPacket); while ((completedPacket = _collatedDecoder.Next()) != null) { if (completedPacket.Header.RoutingID == (ushort)RoutingID.Control) { ushort controlMessageId = completedPacket.Header.MessageID; if (controlMessageId == (ushort)ControlMessageID.EndFrame) { timer.Stop(); FrameTime = timer.ElapsedMilliseconds * 1e-3f; timer.Reset(); timer.Start(); ++_currentFrame; ++_totalFrames; } } _packetQueue.Enqueue(completedPacket); } } else { // TODO: Log CRC failure. } } } else { yield return(null); } } // Disconnected. if (socket != null) { socket.LingerState.Enabled = false; socket.Close(); socket = null; } if (_connection.Connected) { Status = NetworkThreadStatus.Disconnected; _connection.Connected = false; } if (!_connection.AutoReconnect) { break; } Status = NetworkThreadStatus.Reconnecting; } }
private IEnumerator Run() { // Reconnection attempts so we don't hammer the system on failure. float connectionPollTimeSec = 0.25f; TcpClient socket = null; PacketBuffer packetBuffer = new PacketBuffer(4 * 1024); System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); ClientConnector connector = null; while (!_quitFlag) { // First try establish a connection. while (!_quitFlag && !_connection.Connected) { if (connector == null) { connector = new ClientConnector(_connection.EndPoint); } if (!connector.Connecting) { if (connector.Connected) { socket = connector.Accept(); connector = null; _connection.Connected = true; Status = NetworkThreadStatus.Connected; _currentFrame = _totalFrames = 0u; _packetQueue.Enqueue(BuildResetPacket()); } else { connector.Abort(); connector = null; if (!_connection.AutoReconnect) { // Failed connection and no auto reconnect. Status = NetworkThreadStatus.ConnectionFailed; break; } } } if (socket == null) { // Wait the timeout period before attempting to reconnect. yield return(Workthread.CreateWait(connectionPollTimeSec)); } } timer.Start(); // Read while connected. while (!_quitFlag && TcpClientUtil.Connected(socket)) { // We have a connection. Read messages while we can. if (socket.Available > 0) { // Data available. Read from the network stream into a buffer and attempt to // read a valid message. packetBuffer.Append(socket.GetStream(), socket.Available); PacketBuffer completedPacket; bool crcOk = true; while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk) { if (crcOk) { // Decode and decompress collated packets. This will just return the same packet // if not collated. _collatedDecoder.SetPacket(completedPacket); while ((completedPacket = _collatedDecoder.Next()) != null) { if (completedPacket.Header.RoutingID == (ushort)RoutingID.Control) { ushort controlMessageId = completedPacket.Header.MessageID; if (controlMessageId == (ushort)ControlMessageID.EndFrame) { // Add a frame flush flag to every end frame message to ensure the render thread renders. // TODO: consider a way to frame skip in a live visualisation link. byte[] packetData = completedPacket.Data; int memberOffset = PacketHeader.Size + Marshal.OffsetOf(typeof(ControlMessage), "ControlFlags").ToInt32(); uint controlFlags = BitConverter.ToUInt32(packetData, memberOffset); controlFlags = Endian.FromNetwork(controlFlags); // Add the flush flag controlFlags |= (uint)EndFrameFlag.Flush; // Convert back to bytes and copy into the packet buffer. byte[] frameNumberBytes = BitConverter.GetBytes(Endian.ToNetwork(controlFlags)); Array.Copy(frameNumberBytes, 0, packetData, memberOffset, frameNumberBytes.Length); // Recalculate the CRC as we've modified the packet. completedPacket.UpdateCrc(); // Update the frame timer.Stop(); FrameTime = timer.ElapsedMilliseconds * 1e-3f; timer.Reset(); timer.Start(); ++_currentFrame; ++_totalFrames; } } _packetQueue.Enqueue(completedPacket); } } else { // TODO: Log CRC failure. } } } else { yield return(null); } } // Disconnected. if (socket != null) { socket.LingerState.Enabled = false; socket.Close(); socket = null; } if (_connection.Connected) { Status = NetworkThreadStatus.Disconnected; _connection.Connected = false; } if (!_connection.AutoReconnect) { break; } Status = NetworkThreadStatus.Reconnecting; } }