A SEGMENT_INFO_MESSAGE is a request message sent by the client to the hosted cache containing the segment hash of data (HoD) for the previously offered segment, as well as the range of block hashes in the segment. Whether a SEGMENT_INFO_MESSAGE is sent depends on the hosted cache's response to the previous INITIAL_OFFER_MESSAGE containing the same HoHoDk.
        /// <summary>
        /// Convert the segmentInforMessageStack struct defined in stack to adapter 
        /// </summary>
        /// <param name="segmentInforMessageStack">The segmentInforMessageStack message</param>
        /// <returns>Return the segmentInforMessageStack type defined in adapter</returns>
        public static SegmentInfoMessage ConvertFromStackForSegmentInfoMsg(SEGMENT_INFO_MESSAGE segmentInforMessageStack)
        {
            SegmentInfoMessage segmentInforMessage;
            segmentInforMessage.ConnectionInfo = ConvertFromStackForConnInfo(segmentInforMessageStack.ConnectionInfo);
            segmentInforMessage.ContentTag = segmentInforMessageStack.ContentTag;
            segmentInforMessage.MsgHeader = ConvertFromStackForMsgHeader(segmentInforMessageStack.MsgHeader);
            segmentInforMessage.SegmentInfo = segmentInforMessageStack.SegmentInfo;

            return segmentInforMessage;
        }
        /// <summary>
        /// Transform the SEGMENT_INFO_MESSAGE to a byte array
        /// </summary>
        /// <param name="segmentInfoMsg">The SEGMENT_INFO_MESSAGE message</param>
        /// <returns>The result array</returns>
        public static byte[] EncodeSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMsg)
        {
            List<byte> list = new List<byte>();

            // Encode MESSAGE_HEADER
            list.Add(segmentInfoMsg.MsgHeader.MinorVersion);
            list.Add(segmentInfoMsg.MsgHeader.MajorVersion);
            list.AddRange(GetBytesFromUshort((ushort)segmentInfoMsg.MsgHeader.MsgType, false));
            if (segmentInfoMsg.MsgHeader.Padding == null)
            {
                segmentInfoMsg.MsgHeader.Padding = new byte[4];
            }

            list.AddRange(segmentInfoMsg.MsgHeader.Padding);

            // Encode CONNECTION_INFORMATION
            list.AddRange(GetBytesFromUint16(segmentInfoMsg.ConnectionInfo.Port, false));
            if (segmentInfoMsg.ConnectionInfo.Padding == null)
            {
                segmentInfoMsg.ConnectionInfo.Padding = new byte[6];
            }

            list.AddRange(segmentInfoMsg.ConnectionInfo.Padding);

            // Encode CONTENT_TAG
            list.AddRange(segmentInfoMsg.ContentTag);

            // Encode segment infomation.
            list.AddRange(GetBytesFromUshort(segmentInfoMsg.SegmentInfo.Version, true));
            list.AddRange(GetBytesFromUint((uint)segmentInfoMsg.SegmentInfo.dwHashAlgo, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.dwOffsetInFirstSegment, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.dwOffsetInFirstSegment, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.cSegments, true));

            for (int i = 0; i < segmentInfoMsg.SegmentInfo.segments.Length; i++)
            {
                list.AddRange(GetBytesFromUlong(segmentInfoMsg.SegmentInfo.segments[i].ullOffsetInContent, true));
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.segments[i].cbSegment, true));
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.segments[i].cbBlockSize, true));
                list.AddRange(segmentInfoMsg.SegmentInfo.segments[i].SegmentHashOfData);
                list.AddRange(segmentInfoMsg.SegmentInfo.segments[i].SegmentSecret);
            }

            for (int j = 0; j < segmentInfoMsg.SegmentInfo.blocks.Length; j++)
            {
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.blocks[j].cBlocks, true));
                list.AddRange(segmentInfoMsg.SegmentInfo.blocks[j].BlockHashes);
            }

            return list.ToArray();
        }
        /// <summary>
        /// Transform the SEGMENT_INFO_MESSAGE to a byte array
        /// </summary>
        /// <param name="segmentInfoMsg">The SEGMENT_INFO_MESSAGE message</param>
        /// <returns>The result array</returns>
        public static byte[] EncodeSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMsg)
        {
            List <byte> list = new List <byte>();

            // Encode MESSAGE_HEADER
            list.Add(segmentInfoMsg.MsgHeader.MinorVersion);
            list.Add(segmentInfoMsg.MsgHeader.MajorVersion);
            list.AddRange(GetBytesFromUshort((ushort)segmentInfoMsg.MsgHeader.MsgType, false));
            if (segmentInfoMsg.MsgHeader.Padding == null)
            {
                segmentInfoMsg.MsgHeader.Padding = new byte[4];
            }

            list.AddRange(segmentInfoMsg.MsgHeader.Padding);

            // Encode CONNECTION_INFORMATION
            list.AddRange(GetBytesFromUint16(segmentInfoMsg.ConnectionInfo.Port, false));
            if (segmentInfoMsg.ConnectionInfo.Padding == null)
            {
                segmentInfoMsg.ConnectionInfo.Padding = new byte[6];
            }

            list.AddRange(segmentInfoMsg.ConnectionInfo.Padding);

            // Encode CONTENT_TAG
            list.AddRange(segmentInfoMsg.ContentTag);

            // Encode segment infomation.
            list.AddRange(GetBytesFromUshort(segmentInfoMsg.SegmentInfo.Version, true));
            list.AddRange(GetBytesFromUint((uint)segmentInfoMsg.SegmentInfo.dwHashAlgo, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.dwOffsetInFirstSegment, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.dwOffsetInFirstSegment, true));
            list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.cSegments, true));

            for (int i = 0; i < segmentInfoMsg.SegmentInfo.segments.Length; i++)
            {
                list.AddRange(GetBytesFromUlong(segmentInfoMsg.SegmentInfo.segments[i].ullOffsetInContent, true));
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.segments[i].cbSegment, true));
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.segments[i].cbBlockSize, true));
                list.AddRange(segmentInfoMsg.SegmentInfo.segments[i].SegmentHashOfData);
                list.AddRange(segmentInfoMsg.SegmentInfo.segments[i].SegmentSecret);
            }

            for (int j = 0; j < segmentInfoMsg.SegmentInfo.blocks.Length; j++)
            {
                list.AddRange(GetBytesFromUint(segmentInfoMsg.SegmentInfo.blocks[j].cBlocks, true));
                list.AddRange(segmentInfoMsg.SegmentInfo.blocks[j].BlockHashes);
            }

            return(list.ToArray());
        }
        /// <summary>
        /// Validate the SEGMENT_INFO_MESSAGE related RS
        /// </summary>
        /// <param name="segmentInfoMessage">The send message SEGMENT_INFO_MESSAGE</param>
        private void ValidateSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMessage)
        {
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R87, Validate this by confirm the ContentTag in the send SEGMENT_INFO_MESSAGE is not null.
                Record SEGMENT_INFO_MESSAGE.ContentTag is not null or not, 0 represents not null and 1 represents null,
                Record the actual value is {0}",
                (segmentInfoMessage.ContentTag != null).ToString());

            // Capture MS-PCHC R87
            this.Site.CaptureRequirementIfIsNotNull(
                segmentInfoMessage.ContentTag,
                87,
                @"[In SEGMENT_INFO_MESSAGE Request Received] Regardless of whether an INITIAL_OFFER_MESSAGE
                has previously been received from this client, the hosted cache MUST perform the following actions:
                The ContentTag is described in the SEGMENT_INFO_MESSAGE request.");
        }
        /// <summary>
        /// Capture SEGMENT_INFO_MESSAGE message RS
        /// </summary>
        /// <param name="segmentInfoMsg">A SEGMENT_INFO_MESSAGE message.</param>
        /// <param name="platformOsVersion">The operation system.</param>
        private void ValidateSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMsg, string platformOsVersion)
        {
            // Validate the MessageHeader in SEGMENT_INFO_MESSAGE.
            this.ValidateRequestMessageHeader(segmentInfoMsg.MsgHeader);

            // Validate the connectionInformation in SEGMENT_INFO_MESSAGE.
            this.ValidateConnectionInformation(segmentInfoMsg.ConnectionInfo);

            // Valdiate the SegmentInformation in SEGMENT_INFO_MESSAGE.
            this.ValidateSegmentInformation(segmentInfoMsg.SegmentInfo);

            // Validate the SegmentInformation about Pccrc
            this.ValidateSegmentInformationFromPccrc(segmentInfoMsg.SegmentInfo);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R22:The value of PCHCMessageType.SEGMENT_INFO_MESSAGE is {0}.",
                (int)segmentInfoMsg.MsgHeader.MsgType);

            // Capture MS-PCHC R22
            Site.CaptureRequirementIfAreEqual<PCHCMessageType>(
                PCHCMessageType.SEGMENT_INFO_MESSAGE,
                (PCHCMessageType)segmentInfoMsg.MsgHeader.MsgType,
                22,
                @"[In MESSAGE_HEADER][Type (2 bytes):a 16-bit unsigned integer that specifies the message type]The
                value 0x0002 represent message which is a SEGMENT_INFO_MESSAGE. ");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R36:The segmentInfoMsg is an instance of SEGMENT_INFO_MESSAGE which of cause consists of
                [MessageHeader, ConnectionInformation, ContentTag, SegmentInformation (variable)]");

            // Capture MS-PCHC R36
            Site.CaptureRequirement(
                36,
                @"[In SEGMENT_INFO_MESSAGE] A SEGMENT_INFO_MESSAGE consists of the following fields[MessageHeader,
                ConnectionInformation, ContentTag, SegmentInformation (variable)].");

            int sizeofMsgHeader = System.Runtime.InteropServices.Marshal.SizeOf(segmentInfoMsg.MsgHeader);

            // Capture MS-PCHC R37 and MS-PCHC R129
            Site.Assert.AreEqual<int>(
                8,
                sizeofMsgHeader,
                @"Verify MS-PCHC_R37 and MS-PCHC_R129:The messageHeader is an instance of MessageHeader[8 bytes].");

            // Capture MS-PCHC R129
            Site.CaptureRequirement(
                129,
                @"[In Request Messages] MessageHeader (8 bytes): A MESSAGE_HEADER structure (section 2.2.1.1).");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R37:The value of PCHCMessageType.SEGMENT_INFO_MESSAGE is {0}.",
                (int)segmentInfoMsg.MsgHeader.MsgType);

            // Capture MS-PCHC R37
            Site.CaptureRequirementIfAreEqual<PCHCMessageType>(
                PCHCMessageType.SEGMENT_INFO_MESSAGE,
                (PCHCMessageType)segmentInfoMsg.MsgHeader.MsgType,
                37,
                @"[In SEGMENT_INFO_MESSAGE] A SEGMENT_INFO_MESSAGE consists of MessageHeader (8 bytes):
                A MESSAGE_HEADER structure (section 2.2.1.1), with the Type field set to 0x0002.");

            int sizeofConnectInfo = System.Runtime.InteropServices.Marshal.SizeOf(segmentInfoMsg.ConnectionInfo);

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R38:The segmentInfoMsg Contains a CONNECTION_INFORMATION(8 bytes),
                but the actual size of the ConnectionInfo is: {0}.",
                sizeofConnectInfo);

            Site.CaptureRequirementIfAreEqual<int>(
                8,
                sizeofConnectInfo,
                38,
                @"[In SEGMENT_INFO_MESSAGE] A SEGMENT_INFO_MESSAGE consists of ConnectionInformation (8 bytes):
                A CONNECTION_INFORMATION structure (section 2.2.1.2).");

            // Capture MS-PCHC R39
            int size = segmentInfoMsg.ContentTag.Length;
            Site.CaptureRequirementIfAreEqual<int>(
                16,
                size,
                39,
                @"[In SEGMENT_INFO_MESSAGE] A SEGMENT_INFO_MESSAGE consists of ContentTag (16 bytes):
                A structure consisting of 16 bytes of opaque data.");

            // Add the debug information
            Site.Log.Add(
                LogEntryKind.Debug,
                @"Verify MS-PCHC_R41:[In SEGMENT_INFO_MESSAGE] [ContentTag ] The tag of
                SEGMENT_INFO_MESSAGE is added to the information being sent by the client to the hosted cache.");

            // Capture MS-PCHC R41
            // If MS-PCHC_R39 is verified successfully, specify the ContentTag is added in.
            // So MS-PCHC_R41 is captured directly.
            Site.CaptureRequirement(
                41,
                @"[In SEGMENT_INFO_MESSAGE] [ContentTag ] The tag of SEGMENT_INFO_MESSAGE is added to the
                information being sent by the client to the hosted cache.");

            string contentTag = Encoding.ASCII.GetString(segmentInfoMsg.ContentTag);
            int endIndex = contentTag.IndexOf('\0');
            string contentTagNoSpace = contentTag.Substring(0, endIndex);
            bool isEqualASC = contentTagNoSpace.Equals("WinINet")
                 || contentTagNoSpace.Equals("WebIO")
                 || contentTagNoSpace.Equals("BITS-4.0");
            byte[] contentTagByteValue = new byte[16]
                {
                    0x35, 0xDB, 0x04, 0x5D, 0x14, 0x23, 0x45, 0x53, 0xA0, 0x51, 0x0D, 0xC2, 0xE1, 0x5E, 0x6C, 0x4C
                };
            bool isEqualContentTagByteArray = true;
            for (int i = 0; i < 16; i++)
            {
                isEqualContentTagByteArray = isEqualContentTagByteArray && (segmentInfoMsg.ContentTag[i] == contentTagByteValue[i]);
            }

            if (platformOsVersion.ToLower().Equals(ClientRoleOSVersion.Win2K8.ToString().ToLower())
                || platformOsVersion.ToLower().Equals(ClientRoleOSVersion.Win2K8R2.ToString().ToLower())
                || platformOsVersion.ToLower().Equals(ClientRoleOSVersion.Win7.ToString().ToLower())
                || platformOsVersion.ToLower().Equals(ClientRoleOSVersion.WinVista.ToString().ToLower()))
            {
                // Add the debug information
                Site.Log.Add(
                    LogEntryKind.Debug,
                    @"Verify MS-PCHC_R124:The segmentInfoMsg Contain a CONTENT_TAG[16 bytes]. The CONTENT_TAG's
                    expected values can be:The ASCII string WinINet.The ASCII string WebIO. The ASCII string BITS-4.0.
                    The binary byte array: 0x35, 0xDB, 0x04, 0x5D, 0x14, 0x23, 0x45, 0x53, 0xA0, 0x51, 0x0D,
                    0xC2, 0xE1, 0x5E, 0x6C, 0x4C. The actual value is: {0}",
                    contentTagNoSpace);

                // Capture MS-PCHC R124
                Site.CaptureRequirementIfIsTrue(
                    isEqualASC || isEqualContentTagByteArray,
                    124,
                    @"<3> Section 3.2.1: In the Windows implementation, the values of the content tag can be the following:
                    The ASCII string ""WinINet"".
                    The ASCII string ""WebIO"".
                    The ASCII string ""BITS-4.0"".
                    The binary byte array {0x35, 0xDB, 0x04, 0x5D, 0x14, 0x23, 0x45, 0x53, 0xA0, 0x51, 0x0D, 0xC2, 0xE1,
                    0x5E, 0x6C, 0x4C}.");
            }
        }
 /// <summary>
 /// Send the SEGMENT_INFO_MESSAGE request.
 /// </summary>
 /// <param name="segmentInfoMessage">The SEGMENT_INFO_MESSAGE message.</param>
 /// <returns>The repsonse message RESPONSE_MESSAGE from the hosted cache.</returns>
 public RESPONSE_MESSAGE SendSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMessage)
 {
     return this.responseMessage = this.SendByte(EncodeMessage.EncodeSegmentInfoMessage(segmentInfoMessage));
 }
 /// <summary>
 /// Send the SEGMENT_INFO_MESSAGE request.
 /// </summary>
 /// <param name="segmentInfoMessage">The SEGMENT_INFO_MESSAGE message.</param>
 /// <returns>The repsonse message RESPONSE_MESSAGE from the hosted cache.</returns>
 public RESPONSE_MESSAGE SendSegmentInfoMessage(SEGMENT_INFO_MESSAGE segmentInfoMessage)
 {
     return(this.responseMessage = this.SendByte(EncodeMessage.EncodeSegmentInfoMessage(segmentInfoMessage)));
 }