Packet data is generally broken into multiple variable sized byte chunks or 'partial packets'. This class provides features to effortlessly rebuild whole packets.
        /// <summary>
        /// Create a new connection object
        /// </summary>
        /// <param name="connectionInfo">ConnectionInfo corresponding to the new connection</param>
        /// <param name="defaultSendReceiveOptions">The SendReceiveOptions which should be used as connection defaults</param>
        protected Connection(ConnectionInfo connectionInfo, SendReceiveOptions defaultSendReceiveOptions)
        {
            //If the application layer protocol is disabled the serialiser must be NullSerializer
            //and no data processors are allowed.
            if (connectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Disabled)
            {
                if (defaultSendReceiveOptions.Options.ContainsKey("ReceiveConfirmationRequired"))
                    throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
                        " options specified the ReceiveConfirmationRequired option. Please provide compatible send receive options in order to successfully" +
                        " instantiate this unmanaged connection.", "defaultSendReceiveOptions");

                if (defaultSendReceiveOptions.DataSerializer != DPSManager.GetDataSerializer<NullSerializer>())
                    throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
                        " options serialiser was not NullSerializer. Please provide compatible send receive options in order to successfully" +
                        " instantiate this unmanaged connection.", "defaultSendReceiveOptions");

                if (defaultSendReceiveOptions.DataProcessors.Count > 0)
                    throw new ArgumentException("Attempted to create an unmanaged connection when the provided send receive" +
                        " options contains data processors. Data processors may not be used with unmanaged connections." +
                        " Please provide compatible send receive options in order to successfully instantiate this unmanaged connection.", "defaultSendReceiveOptions");
            }

            SendTimesMSPerKBCache = new CommsMath();            
            packetBuilder = new PacketBuilder();

            //Initialise the sequence counter using the global value
            //Subsequent values on this connection are guaranteed to be sequential
            packetSequenceCounter = Interlocked.Increment(ref NetworkComms.totalPacketSendCount);

            ConnectionInfo = connectionInfo;

            if (defaultSendReceiveOptions != null)
                ConnectionDefaultSendReceiveOptions = defaultSendReceiveOptions;
            else
                ConnectionDefaultSendReceiveOptions = NetworkComms.DefaultSendReceiveOptions;

            //Add any listener specific packet handlers if required
            if (connectionInfo.ConnectionListener != null)
                connectionInfo.ConnectionListener.AddListenerPacketHandlersToConnection(this);

            if (NetworkComms.commsShutdown) throw new ConnectionSetupException("Attempting to create new connection after global NetworkComms.Net shutdown has been initiated.");

            if (ConnectionInfo.ConnectionType == ConnectionType.Undefined || ConnectionInfo.RemoteEndPoint == null)
                throw new ConnectionSetupException("ConnectionType and RemoteEndPoint must be defined within provided ConnectionInfo.");

            //If a connection already exists with this info then we can throw an exception here to prevent duplicates
            if (NetworkComms.ConnectionExists(connectionInfo.RemoteEndPoint, connectionInfo.LocalEndPoint, connectionInfo.ConnectionType, connectionInfo.ApplicationLayerProtocol))
                throw new ConnectionSetupException("A " + connectionInfo.ConnectionType.ToString() + " connection already exists with info " + connectionInfo);

            //We add a reference in the constructor to ensure any duplicate connection problems are picked up here
            NetworkComms.AddConnectionReferenceByRemoteEndPoint(this);
        }
        /// <summary>
        /// Attempts to use the data provided in packetBuilder to recreate something useful. If we don't have enough data 
        /// yet that value is set in packetBuilder.
        /// </summary>
        /// <param name="packetBuilder">The <see cref="PacketBuilder"/> containing incoming cached data</param>
        protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder)
        {
            int loopCounter = 0;
            try
            {
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read.");

                if (packetBuilder.TotalPartialPacketCount == 0)
                    throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder.");

                //Loop until we are finished with this packetBuilder
                while (true)
                {
                    //If we have ended up with a null packet at the front, probably due to some form of concatenation we can pull it off here
                    //It is possible we have concatenation of several null packets along with real data so we loop until the firstByte is greater than 0
                    if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled && packetBuilder.FirstByte() == 0)
                    {
                        #region Ignore Null Packet
                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString());

                        packetBuilder.ClearNTopBytes(1);

                        //Reset the expected bytes to 0 so that the next check starts from scratch
                        packetBuilder.TotalBytesExpected = 0;

                        //If we have run out of data completely then we can return immediately
                        if (packetBuilder.TotalBytesCached == 0) return;
                        #endregion
                    }
                    else
                    {
                        int packetHeaderSize = 0;
                        PacketHeader topPacketHeader;

                        #region Set topPacketHeader
                        if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
                        {
                            //First determine the expected size of a header packet
                            packetHeaderSize = packetBuilder.FirstByte() + 1;

                            //Do we have enough data to build a header?
                            if (packetBuilder.TotalBytesCached < packetHeaderSize)
                            {
                                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("     ... require " + packetHeaderSize + " bytes for packet header, only " + packetBuilder.TotalBytesCached + " bytes cached.");

                                //Set the expected number of bytes and then return
                                packetBuilder.TotalBytesExpected = packetHeaderSize;
                                return;
                            }

                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("     ... deserializing header using " + packetHeaderSize + " bytes, " + packetBuilder.TotalBytesCached + " bytes cached.");

                            //We have enough for a header
                            using (MemoryStream headerStream = packetBuilder.ReadDataSection(1, packetHeaderSize - 1))
                                topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions);
                        }
                        else
                            topPacketHeader = new PacketHeader(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged), packetBuilder.TotalBytesCached);
                        #endregion

                        //Idiot test
                        if (topPacketHeader.PacketType == null)
                            throw new SerialisationException("packetType value in packetHeader should never be null");

                        //We can now use the header to establish if we have enough payload data
                        //First case is when we have not yet received enough data
                        if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.TotalPayloadSize)
                        {
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("     ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " total packet bytes.");

                            //Set the expected number of bytes and then return
                            packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.TotalPayloadSize;
                            return;
                        }
                        //Second case is we have enough data
                        else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.TotalPayloadSize)
                        {
                            #region Handle Packet
                            //We can either have exactly the right amount or even more than we were expecting
                            //We may have too much data if we are sending high quantities and the packets have been concatenated
                            SendReceiveOptions incomingPacketSendReceiveOptions = IncomingPacketSendReceiveOptions(topPacketHeader);
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Received packet of type '" + topPacketHeader.PacketType + "' from " + ConnectionInfo + ", containing " + packetHeaderSize.ToString() + " header bytes and " + topPacketHeader.TotalPayloadSize.ToString() + " payload bytes.");

                            bool isReservedPacketType = (topPacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged) &&
                                NetworkComms.ReservedPacketTypeNames.ContainsKey(topPacketHeader.PacketType));

                            //Get the packet sequence number if logging
                            string packetSeqNumStr = "";
                            if (NetworkComms.LoggingEnabled)
                                packetSeqNumStr = (topPacketHeader.ContainsOption(PacketHeaderLongItems.PacketSequenceNumber) ? ". pSeq#-" + topPacketHeader.GetOption(PacketHeaderLongItems.PacketSequenceNumber).ToString() + "." : "");

                            //Only reserved packet types get completed inline by default
                            if (isReservedPacketType)
                            {
#if WINDOWS_PHONE || NETFX_CORE
                                QueueItemPriority priority = QueueItemPriority.Normal;
#else
                                QueueItemPriority priority = (QueueItemPriority)Thread.CurrentThread.Priority;
#endif
                                PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions);
                                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
                                NetworkComms.CompleteIncomingItemTask(item);
                            }
                            else
                            {
                                QueueItemPriority itemPriority = (incomingPacketSendReceiveOptions.Options.ContainsKey("ReceiveHandlePriority") ? (QueueItemPriority)Enum.Parse(typeof(QueueItemPriority), incomingPacketSendReceiveOptions.Options["ReceiveHandlePriority"]) : QueueItemPriority.Normal);
                                PriorityQueueItem item = new PriorityQueueItem(itemPriority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions);

                                //QueueItemPriority.Highest is the only priority that is executed inline
                                if (itemPriority == QueueItemPriority.Highest)
                                {
                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
                                    NetworkComms.CompleteIncomingItemTask(item);
                                }
                                else
                                {
#if NETFX_CORE
                                    NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ") with priority " + itemPriority.ToString() + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr);
#else
                                    int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
                                    if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr);
#endif
                                }
                            }
                            
                            //We clear the bytes we have just handed off
                            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " bytes from incoming packet builder from connection with " + ConnectionInfo +".");
                            packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.TotalPayloadSize);

                            //Reset the expected bytes to 0 so that the next check starts from scratch
                            packetBuilder.TotalBytesExpected = 0;

                            //If we have run out of data completely then we can return immediately
                            if (packetBuilder.TotalBytesCached == 0) return;
                            #endregion
                        }
                        else
                            throw new CommunicationException("This should be impossible!");   
                    }

                    loopCounter++;
                }
            }
            catch (Exception ex)
            {
                //Any error, throw an exception.
                if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Fatal("A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information.");

                if (this is IPConnection)
                {
                    //Log the exception in DOS protection if enabled
                    if (IPConnection.DOSProtection.Enabled && ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint))
                        IPConnection.DOSProtection.LogMalformedData(ConnectionInfo.RemoteIPEndPoint.Address);
                }

                LogTools.LogException(ex, "CommsError", "A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. Loop counter " + loopCounter.ToString() + ". Packet builder contained " + packetBuilder.TotalBytesCached + " total cached bytes.");
                CloseConnection(true, 45);
            }
        }