public void TestTryDecodePieceMessge()
        {
            PieceMessage message;
            int          offset = 0;

            byte[] data = "0000000B070000000500000006ABCD".ToByteArray();
            bool   isIncomplete;

            if (PieceMessage.TryDecode(data, ref offset, data.Length, out message, out isIncomplete))
            {
                Assert.AreEqual(15, message.Length);
                Assert.AreEqual(5, message.PieceIndex);
                Assert.AreEqual(6, message.BlockOffset);
                Assert.AreEqual(171, message.Data[0]);
                Assert.AreEqual(205, message.Data[1]);
                Assert.AreEqual(false, isIncomplete);
                Assert.AreEqual(data.Length, offset);
                CollectionAssert.AreEqual(data, message.Encode());
            }
            else
            {
                Assert.Fail();
            }
        }
        /// <summary>
        /// Asynchronous write callback.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void Receive(IAsyncResult ar)
        {
            AsyncReadData data      = ar.AsyncState as AsyncReadData;
            int           bytesRead = 0;
            int           offset    = data.OffsetStart;
            PeerMessage   message;
            PieceMessage  pieceMessage;
            bool          isIncomplete;

            lock (this.locker)
            {
                if (!this.IsDisposed)
                {
                    try
                    {
                        // read data
                        bytesRead = this.stream.EndRead(ar);

                        if (bytesRead > 0)
                        {
                            data.OffsetEnd += bytesRead;

                            // walk through the array and try to decode messages
                            while (offset <= data.OffsetEnd)
                            {
                                if (PieceMessage.TryDecode(data.Buffer, ref offset, data.OffsetEnd, out pieceMessage, out isIncomplete, this.PieceData))
                                {
                                    // successfully decoded message
                                    this.OnMessageReceived(this, new PeerMessgeReceivedEventArgs((PeerMessage)pieceMessage));

                                    // remember where we left off
                                    data.OffsetStart = offset;
                                }
                                else if (PeerMessage.TryDecode(data.Buffer, ref offset, data.OffsetEnd, out message, out isIncomplete))
                                {
                                    // successfully decoded message
                                    this.OnMessageReceived(this, new PeerMessgeReceivedEventArgs(message));

                                    // remember where we left off
                                    data.OffsetStart = offset;
                                }
                                else if (isIncomplete)
                                {
                                    // message of variable length is present but incomplete -> stop advancing
                                    break;
                                }
                                else
                                {
                                    // move to next byte
                                    offset++;
                                }
                            }

                            if (data.OffsetStart == data.OffsetEnd)
                            {
                                // reset offset
                                data.OffsetStart = 0;
                                data.OffsetEnd   = 0;
                            }
                            else if (data.OffsetStart > 0 &&
                                     data.OffsetStart < data.OffsetEnd)
                            {
                                // move data to beginning of the buffere
                                for (int i = data.OffsetStart; i < data.OffsetEnd; i++)
                                {
                                    data.Buffer[i - data.OffsetStart] = data.Buffer[i];
                                }

                                // reset offset
                                data.OffsetEnd   = data.OffsetEnd - data.OffsetStart;
                                data.OffsetStart = 0;
                            }
                            else if (data.OffsetStart > data.OffsetEnd)
                            {
                                throw new PeerWireProtocolException("Invalid data.");
                            }

                            this.tm.Read(bytesRead);

                            // resume reading
                            if (!this.IsDisposed)
                            {
                                this.stream.BeginRead(data.Buffer, data.OffsetEnd, data.Buffer.Length - data.OffsetEnd, this.Receive, data);
                            }
                        }
                        else
                        {
                            // we received no data
                            Debug.WriteLine($"received no data from {this.Endpoint}");
                        }
                    }
                    catch (IOException ex)
                    {
                        Debug.WriteLine($"could not read data from {this.Endpoint}: {ex.Message}");

                        this.OnCommunicationError(this, new CommunicationErrorEventArgs(ex.Message));
                    }
                }
            }
        }