private bool ReadAndRoutePacket(NodePacketType packetType, byte [] packetData, int packetLength) { try { // The buffer is publicly visible so that InterningBinaryReader doesn't have to copy to an intermediate buffer. // Since the buffer is publicly visible dispose right away to discourage outsiders from holding a reference to it. using (var packetStream = new MemoryStream(packetData, 0, packetLength, /*writeable*/ false, /*bufferIsPubliclyVisible*/ true)) { ITranslator readTranslator = BinaryTranslator.GetReadTranslator(packetStream, _sharedReadBuffer); _packetFactory.DeserializeAndRoutePacket(_nodeId, packetType, readTranslator); } } catch (IOException e) { CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in ReadAndRoutPacket: {0}", e); _packetFactory.RoutePacket(_nodeId, new NodeShutdown(NodeShutdownReason.ConnectionFailed)); Close(); return(false); } return(true); }
private void RunReadLoop(Stream localReadPipe, Stream localWritePipe, ConcurrentQueue <INodePacket> localPacketQueue, AutoResetEvent localPacketAvailable, AutoResetEvent localTerminatePacketPump) { // Ordering of the wait handles is important. The first signalled wait handle in the array // will be returned by WaitAny if multiple wait handles are signalled. We prefer to have the // terminate event triggered so that we cannot get into a situation where packets are being // spammed to the endpoint and it never gets an opportunity to shutdown. CommunicationsUtilities.Trace("Entering read loop."); byte[] headerByte = new byte[5]; #if FEATURE_APM IAsyncResult result = localReadPipe.BeginRead(headerByte, 0, headerByte.Length, null, null); #else Task <int> readTask = CommunicationsUtilities.ReadAsync(localReadPipe, headerByte, headerByte.Length); #endif bool exitLoop = false; do { // Ordering is important. We want packetAvailable to supercede terminate otherwise we will not properly wait for all // packets to be sent by other threads which are shutting down, such as the logging thread. WaitHandle[] handles = new WaitHandle[] { #if FEATURE_APM result.AsyncWaitHandle, #else ((IAsyncResult)readTask).AsyncWaitHandle, #endif localPacketAvailable, localTerminatePacketPump }; int waitId = WaitHandle.WaitAny(handles); switch (waitId) { case 0: { int bytesRead = 0; try { #if FEATURE_APM bytesRead = localReadPipe.EndRead(result); #else bytesRead = readTask.Result; #endif } catch (Exception e) { // Lost communications. Abort (but allow node reuse) CommunicationsUtilities.Trace("Exception reading from server. {0}", e); ExceptionHandling.DumpExceptionToFile(e); ChangeLinkStatus(LinkStatus.Inactive); exitLoop = true; break; } if (bytesRead != headerByte.Length) { // Incomplete read. Abort. if (bytesRead == 0) { CommunicationsUtilities.Trace("Parent disconnected abruptly"); } else { CommunicationsUtilities.Trace("Incomplete header read from server. {0} of {1} bytes read", bytesRead, headerByte.Length); } ChangeLinkStatus(LinkStatus.Failed); exitLoop = true; break; } NodePacketType packetType = (NodePacketType)Enum.ToObject(typeof(NodePacketType), headerByte[0]); try { _packetFactory.DeserializeAndRoutePacket(0, packetType, BinaryTranslator.GetReadTranslator(localReadPipe, _sharedReadBuffer)); } catch (Exception e) { // Error while deserializing or handling packet. Abort. CommunicationsUtilities.Trace("Exception while deserializing packet {0}: {1}", packetType, e); ExceptionHandling.DumpExceptionToFile(e); ChangeLinkStatus(LinkStatus.Failed); exitLoop = true; break; } #if FEATURE_APM result = localReadPipe.BeginRead(headerByte, 0, headerByte.Length, null, null); #else readTask = CommunicationsUtilities.ReadAsync(localReadPipe, headerByte, headerByte.Length); #endif } break; case 1: case 2: try { // Write out all the queued packets. INodePacket packet; while (localPacketQueue.TryDequeue(out packet)) { MemoryStream packetStream = new MemoryStream(); ITranslator writeTranslator = BinaryTranslator.GetWriteTranslator(packetStream); packetStream.WriteByte((byte)packet.Type); // Pad for packet length packetStream.Write(BitConverter.GetBytes((int)0), 0, 4); // Reset the position in the write buffer. packet.Translate(writeTranslator); // Now write in the actual packet length packetStream.Position = 1; packetStream.Write(BitConverter.GetBytes((int)packetStream.Length - 5), 0, 4); localWritePipe.Write(packetStream.GetBuffer(), 0, (int)packetStream.Length); } } catch (Exception e) { // Error while deserializing or handling packet. Abort. CommunicationsUtilities.Trace("Exception while serializing packets: {0}", e); ExceptionHandling.DumpExceptionToFile(e); ChangeLinkStatus(LinkStatus.Failed); exitLoop = true; break; } if (waitId == 2) { CommunicationsUtilities.Trace("Disconnecting voluntarily"); ChangeLinkStatus(LinkStatus.Failed); exitLoop = true; } break; default: ErrorUtilities.ThrowInternalError("waitId {0} out of range.", waitId); break; } }while (!exitLoop); }