/// <summary>
        /// Called when the <see cref="PacketReceived"/> event is raised.
        /// </summary>
        /// <remarks>
        /// When overriding this method in a derived class, call the base implementation after your logic.
        /// </remarks>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="args">The packet data that was received.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="args"/> is <see langword="null"/>.</exception>
        protected virtual void OnDataArrived(object sender, DataArrivedEventArgs args)
        {
            Guard.NotNull(() => args, args);

            byte[] data = args.Data;
            int    position = 0, remaining = data.Length;

            while (PacketBuffer.FreeSpace == 0)
            {
                byte[] rawData = PacketBuffer.ExtractAndReset(0);
                if (rawData.Length > 0)
                {
                    Crypto.Decrypt(rawData);

                    var incomingPacketArgs = new PacketReceivedEventArgs(rawData);
                    OnPacketReceived(incomingPacketArgs);
                }

                if (remaining == 0)
                {
                    break;
                }

                int bufferred;
                int headerRemaining = HeaderBuffer.FreeSpace;
                if (headerRemaining > 0)
                {
                    bufferred = HeaderBuffer.AppendFill(data, position, headerRemaining);

                    // For the confused: if we didn't fill the header, it
                    // means the data array didn't have enough elements.
                    // We move on.
                    if (bufferred < headerRemaining)
                    {
                        break;
                    }

                    position  += bufferred;
                    remaining -= bufferred;
                }

                byte[] header = HeaderBuffer.ExtractAndReset(4);
                int    length;
                if (!Crypto.TryGetLength(header, out length))
                {
                    Close(@"Could not decode packet length.");
                    return;
                }

                PacketBuffer.Reset(length);

                bufferred  = PacketBuffer.AppendFill(data, position, remaining);
                position  += bufferred;
                remaining -= bufferred;
            }
        }