Example #1
0
            /// <summary>
            /// Sends the specified packet to this node.
            /// </summary>
            /// <param name="packet">The packet to send.</param>
            public void SendData(INodePacket packet)
            {
                MemoryStream writeStream     = new MemoryStream();
                ITranslator  writeTranslator = BinaryTranslator.GetWriteTranslator(writeStream);

                try
                {
                    writeStream.WriteByte((byte)packet.Type);

                    // Pad for the packet length
                    writeStream.Write(BitConverter.GetBytes((int)0), 0, 4);
                    packet.Translate(writeTranslator);

                    // Now plug in the real packet length
                    writeStream.Position = 1;
                    writeStream.Write(BitConverter.GetBytes((int)writeStream.Length - 5), 0, 4);

                    byte[] writeStreamBuffer = writeStream.GetBuffer();

                    for (int i = 0; i < writeStream.Length; i += MaxPacketWriteSize)
                    {
                        int lengthToWrite = Math.Min((int)writeStream.Length - i, MaxPacketWriteSize);
                        if ((int)writeStream.Length - i <= MaxPacketWriteSize)
                        {
                            // We are done, write the last bit asynchronously.  This is actually the general case for
                            // most packets in the build, and the asynchronous behavior here is desirable.
#if FEATURE_APM
                            _serverToClientStream.BeginWrite(writeStreamBuffer, i, lengthToWrite, PacketWriteComplete, null);
#else
                            _serverToClientStream.WriteAsync(writeStreamBuffer, i, lengthToWrite);
#endif
                            return;
                        }
                        else
                        {
                            // If this packet is longer that we can write in one go, then we need to break it up.  We can't
                            // return out of this function and let the rest of the system continue because another operation
                            // might want to send data immediately afterward, and that could result in overlapping writes
                            // to the pipe on different threads.
#if FEATURE_APM
                            IAsyncResult result = _serverToClientStream.BeginWrite(writeStream.GetBuffer(), i, lengthToWrite, null, null);
                            _serverToClientStream.EndWrite(result);
#else
                            _serverToClientStream.Write(writeStreamBuffer, i, lengthToWrite);
#endif
                        }
                    }
                }
                catch (IOException e)
                {
                    // Do nothing here because any exception will be caught by the async read handler
                    CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e);
                }
                catch (ObjectDisposedException) // This happens if a child dies unexpectedly
                {
                    // Do nothing here because any exception will be caught by the async read handler
                }
            }
Example #2
0
            /// <summary>
            /// Actually writes and sends the packet. This can't be called in parallel
            /// because it reuses the _writeBufferMemoryStream, and this is why we use
            /// the _packetWriteDrainTask to serially chain invocations one after another.
            /// </summary>
            /// <param name="packet">The packet to send.</param>
            private void SendDataCore(INodePacket packet)
            {
                MemoryStream writeStream = _writeBufferMemoryStream;

                // clear the buffer but keep the underlying capacity to avoid reallocations
                writeStream.SetLength(0);

                ITranslator writeTranslator = BinaryTranslator.GetWriteTranslator(writeStream);

                try
                {
                    writeStream.WriteByte((byte)packet.Type);

                    // Pad for the packet length
                    WriteInt32(writeStream, 0);
                    packet.Translate(writeTranslator);

                    int writeStreamLength = (int)writeStream.Position;

                    // Now plug in the real packet length
                    writeStream.Position = 1;
                    WriteInt32(writeStream, writeStreamLength - 5);

                    byte[] writeStreamBuffer = writeStream.GetBuffer();

                    for (int i = 0; i < writeStreamLength; i += MaxPacketWriteSize)
                    {
                        int lengthToWrite = Math.Min(writeStreamLength - i, MaxPacketWriteSize);
                        _serverToClientStream.Write(writeStreamBuffer, i, lengthToWrite);
                    }
                    if (IsExitPacket(packet))
                    {
                        _exitPacketState = ExitPacketState.ExitPacketSent;
                    }
                }
                catch (IOException e)
                {
                    // Do nothing here because any exception will be caught by the async read handler
                    CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e);
                }
                catch (ObjectDisposedException) // This happens if a child dies unexpectedly
                {
                    // Do nothing here because any exception will be caught by the async read handler
                }
            }
Example #3
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);
        }