Exemplo n.º 1
0
 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);
        }