private void Receive(object sender, SocketAsyncEventArgs args)
        {
            var               cnd    = (Tuple <Socket, BufferValueReader>)args.UserToken;
            Socket            socket = cnd.Item1;
            BufferValueReader reader = cnd.Item2;

            if (args.BytesTransferred == 0 || args.SocketError != SocketError.Success)
            {
                reader.Dispose();
                args.Dispose();
                Interlocked.Decrement(ref this.pendingAsync);
                return;
            }

            int offset = args.Offset;

            reader.Position = offset;

            MessageHeader header = null;

            // We don't currently support partial messages, so an incomplete message is a bad one.
            if (!this.connectionlessSerializer.TryGetHeader(reader, args.BytesTransferred, ref header) || header.Message == null)
            {
                Interlocked.Decrement(ref this.pendingAsync);
                StartReceive(socket, args, reader);
                return;
            }

            if (header.ConnectionId == 0)
            {
                HandleConnectionlessMessage(args, header, ref reader);
            }
            else
            {
                HandleConnectionMessage(args, header, ref reader);
            }

            Interlocked.Decrement(ref this.pendingAsync);
            StartReceive(socket, args, reader);
        }
        List <Message> BufferMessages(ref byte[] buffer, ref int bufferOffset, ref int messageOffset, ref int remainingData, ref MessageHeader header, ref BufferValueReader reader, Func <MessageHeader, bool> messageIdCallback = null)
        {
            List <Message> messages = new List <Message>();

            string callCategory = null;

                        #if TRACE
            int c = GetNextCallId();
            callCategory = String.Format("{0} {1}:BufferMessages({2},{3},{4},{5},{6})", this.connectionType, c, buffer.Length, bufferOffset, messageOffset, remainingData, reader.Position);
                        #endif
            Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory);

            BufferValueReader currentReader = reader;

            int length = 0;
            while (remainingData >= BaseHeaderLength)
            {
                if (!TryGetHeader(currentReader, remainingData, ref header))
                {
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Message not ready", callCategory);
                    break;
                }

                if (header == null || header.Message == null)
                {
                    header = null;
                    Disconnect();
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (header not found)", callCategory);
                    return(null);
                }

                length = header.MessageLength;
                if (length > MaxMessageSize)
                {
                    header = null;
                    Disconnect();
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (bad message size)", callCategory);
                    return(null);
                }

                if (header.State == HeaderState.IV)
                {
                    DecryptMessage(header, ref currentReader);
                    header.IsStillEncrypted = false;
                    continue;
                }

                if (messageIdCallback != null && !messageIdCallback(header))
                {
                    header = null;
                    Disconnect();
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message id callback was false)", callCategory);
                    return(null);
                }

                if (remainingData < length)
                {
                    bufferOffset += remainingData;
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Message not fully received (boffset={0})", bufferOffset), callCategory);
                    break;
                }

                try
                {
                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Reading payload for message {0}", header.Message), callCategory);
                    header.Message.ReadPayload(header.SerializationContext, currentReader);

                    if (!header.Message.Encrypted && header.Message.Authenticated)
                    {
                        // Zero out length for message signing comparison
                                                #if SAFE
                        for (int i = LengthOffset + messageOffset; i < LengthOffset + sizeof(int) + messageOffset; ++i)
                        {
                            buffer[i] = 0;
                        }
                                                #else
                        fixed(byte *bptr = buffer)
                        * ((int *)(bptr + (LengthOffset + messageOffset))) = 0;
                                                #endif

                        int    payloadLength = reader.Position;
                        byte[] signature     = reader.ReadBytes();
                        if (!VerifyMessage(this.signingHashAlgorithm, header.Message, signature, buffer, messageOffset, payloadLength - messageOffset))
                        {
                            Disconnect(ConnectionResult.MessageAuthenticationFailed);
                            Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message auth failed)", callCategory);
                            return(null);
                        }
                    }
                } catch (Exception ex) {
                    header = null;
                    Disconnect();
                    Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting for error: " + ex, callCategory);
                    return(null);
                }

                messages.Add(header.Message);

                currentReader = reader;
                header        = null;

                if (length < buffer.Length)
                {
                    messageOffset += length;
                    bufferOffset   = messageOffset;
                    remainingData -= length;
                }
                else
                {
                    messageOffset          = 0;
                    bufferOffset           = 0;
                    remainingData          = 0;
                    currentReader.Position = 0;
                }

                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("EOL: moffset={0},boffest={1},rdata={2},rpos={3}", messageOffset, bufferOffset, remainingData, reader.Position), callCategory);
            }

            if (remainingData > 0 || messageOffset + BaseHeaderLength >= buffer.Length)
            {
                Trace.WriteLineIf(NTrace.TraceVerbose, (remainingData > 0) ? String.Format("Data remaining: {0:N0}", remainingData) : "Insufficient room for a header", callCategory);

                int knownRoomNeeded = (remainingData > BaseHeaderLength) ? remainingData : BaseHeaderLength;
                if (header != null && remainingData >= BaseHeaderLength)
                {
                    knownRoomNeeded = header.MessageLength;
                }

                int pos = reader.Position - messageOffset;

                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Room needed: {0:N0} bytes", knownRoomNeeded), callCategory);
                if (messageOffset + knownRoomNeeded <= buffer.Length)
                {
                    // bufferOffset is only moved on complete headers, so it's still == messageOffset.
                    bufferOffset = messageOffset + remainingData;
                    //reader.Position = pos;

                    Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exiting (sufficient room; boffest={0},rpos={1})", bufferOffset, pos), callCategory);
                    return(messages);
                }

                byte[] destinationBuffer = buffer;
                if (knownRoomNeeded > buffer.Length)
                {
                    reader.Dispose();

                    destinationBuffer = new byte[header.MessageLength];
                    reader            = new BufferValueReader(destinationBuffer);
                }

                Buffer.BlockCopy(buffer, messageOffset, destinationBuffer, 0, remainingData);
                reader.Position = pos;
                messageOffset   = 0;
                bufferOffset    = remainingData;
                buffer          = destinationBuffer;

                Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exiting (moved message to front, moffset={1},boffset={2},rpos={0})", reader.Position, messageOffset, bufferOffset), callCategory);
            }
            else
            {
                Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory);
            }

            return(messages);
        }