/// <summary>
        /// [TD Reference 3.2.5.3.4]
        /// Decode MCS Connect Response PDU with GCC Conference Create Response
        /// </summary>
        /// <param name="data">data to be parsed</param>
        /// <returns>decoded MCS Connect Response PDU with GCC Conference Create Response PDU</returns>
        public StackPacket DecodeMcsConnectResponsePDU(byte[] data)
        {
            // initialize
            int currentIndex = 0;
            Server_MCS_Connect_Response_Pdu_with_GCC_Conference_Create_Response pdu =
                new Server_MCS_Connect_Response_Pdu_with_GCC_Conference_Create_Response();

            // McsConnectResponse: TpktHeader
            pdu.tpktHeader = ParseTpktHeader(data, ref currentIndex);

            // McsConnectResponse: X224
            pdu.x224Data = ParseX224Data(data, ref currentIndex);

            // T125 Data: decode McsConnectResponse
            int t125DataLength = data.Length - currentIndex;
            if (t125DataLength <= 0)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }
            byte[] t125Data = new byte[t125DataLength];
            Array.Copy(data, currentIndex, t125Data, 0, t125Data.Length);
            Connect_Response mcsConnectResponse = new Connect_Response();
            Asn1DecodingBuffer decodeBuffer = new Asn1DecodingBuffer(t125Data);
            mcsConnectResponse.BerDecode(decodeBuffer);

            // McsConnectResponse:result
            pdu.mcsCrsp.result = (int)mcsConnectResponse.result.Value;
            byte[] userData = mcsConnectResponse.userData.ByteArrayValue;

            // T125 Data: decode McsConnectResponse's user data
            Asn1DecodingBuffer connectDataBuffer = new Asn1DecodingBuffer(userData);
            ConnectData connectData = new ConnectData();
            connectData.PerDecode(connectDataBuffer);

            // T125 Data: get Gcc data
            int gccDataLength = userData.Length - ConstValue.GCC_DATA_OFFSET;
            if (gccDataLength <= 0)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }
            byte[] gccData = new byte[gccDataLength];
            Array.Copy(userData, ConstValue.GCC_DATA_OFFSET, gccData, 0, gccData.Length);

            // T125 Data: decode Gcc user data
            ConnectGCCPDU gccPdu = new ConnectGCCPDU();
            Asn1DecodingBuffer gccPduBuffer = new Asn1DecodingBuffer(gccData);
            gccPdu.PerDecode(gccPduBuffer);

            // McsConnectResponse: H221Key
            ConferenceCreateResponse conferenceResponse = (ConferenceCreateResponse)gccPdu.GetData();
            H221NonStandardIdentifier identifier =
                (H221NonStandardIdentifier)conferenceResponse.userData.Elements[0].key.GetData();
            pdu.mcsCrsp.gccPdu.H221Key = Encoding.ASCII.GetString(identifier.ByteArrayValue);

            // McsConnectResponse: ccrResult
            pdu.mcsCrsp.gccPdu.ccrResult = (int)conferenceResponse.result.Value;

            // McsConnectResponse: nodeID
            pdu.mcsCrsp.gccPdu.nodeID = (int)conferenceResponse.nodeID.Value;

            // McsConnectResponse: tag
            pdu.mcsCrsp.gccPdu.tag = (int)conferenceResponse.tag.Value;

            // T125 Data: get Gcc user data
            byte[] gccUserData = conferenceResponse.userData.Elements[0].value.ByteArrayValue;

            // Reset current index
            currentIndex = 0;
            while (currentIndex < gccUserData.Length)
            {
                // Peek data type
                int tempIndex = currentIndex;
                TS_UD_HEADER_type_Values type =
                    (TS_UD_HEADER_type_Values)ParseUInt16(gccUserData, ref tempIndex, false);

                // Parse data by type
                switch (type)
                {
                    case TS_UD_HEADER_type_Values.SC_CORE:
                        pdu.mcsCrsp.gccPdu.serverCoreData = ParseTsUdScCore(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.SC_NET:
                        pdu.mcsCrsp.gccPdu.serverNetworkData = ParseTsUdScNet(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.SC_SECURITY:
                        pdu.mcsCrsp.gccPdu.serverSecurityData = ParseTsUdScSec1(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.SC_MCS_MSGCHANNEL:
                        pdu.mcsCrsp.gccPdu.serverMessageChannelData = ParseTsUdScMSGChannel(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.SC_MULTITRANSPORT:
                        pdu.mcsCrsp.gccPdu.serverMultitransportChannelData = ParseTsUdScMultiTransport(gccUserData, ref currentIndex);
                        break;

                    default:
                        throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
                }
            }

            // Check if data length exceeded expectation
            VerifyDataLength(gccUserData.Length, currentIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }
Пример #2
0
        /// <summary>
        /// Encode GCC Conference Create Request according to [T124].
        /// </summary>
        /// <param name="gccPdu">The data to be encoded.</param>
        /// <returns>The encoded data.</returns>
        private static byte[] EncodeGccRspData(ConnectGCCRsp gccPdu)
        {
            if (gccPdu == null)
            {
                return null;
            }

            #region Encode userData
            List<byte> userData = new List<byte>();

            #region Encode serverCoreData structure TS_UD_CS_CORE
            if (gccPdu.serverCoreData != null)
            {
                List<byte> coreData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.serverCoreData.header);
                RdpbcgrEncoder.EncodeStructure(coreData, (uint)gccPdu.serverCoreData.version);
                RdpbcgrEncoder.EncodeStructure(coreData, (uint)gccPdu.serverCoreData.clientRequestedProtocols);
                //earlyCapabilityFlags is optional.
                if(gccPdu.serverCoreData.earlyCapabilityFlags != 0)
                    RdpbcgrEncoder.EncodeStructure(coreData, (uint)gccPdu.serverCoreData.earlyCapabilityFlags);

                userData.AddRange(coreData.ToArray());
            }
            #endregion Encode serverCoreData structure TS_UD_CS_CORE

            #region Encode serverNetworkData TS_UD_CS_NET
            if (gccPdu.serverNetworkData != null)
            {
                List<byte> networkData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.serverNetworkData.header);
                RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.serverNetworkData.MCSChannelId);
                RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.serverNetworkData.channelCount);
                for (int i = 0; i < gccPdu.serverNetworkData.channelCount; ++i)
                {
                    RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.serverNetworkData.channelIdArray[i]);
                }
                if (gccPdu.serverNetworkData.Pad != null)
                {
                    RdpbcgrEncoder.EncodeBytes(networkData, gccPdu.serverNetworkData.Pad);
                }
                userData.AddRange(networkData.ToArray());
            }
            #endregion Encode serverNetworkData TS_UD_CS_NET

            #region Encode serverSecurityData TS_UD_CS_SEC
            if (gccPdu.serverSecurityData != null)
            {
                List<byte> securityData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(securityData, gccPdu.serverSecurityData.header);
                RdpbcgrEncoder.EncodeStructure(securityData, (uint)gccPdu.serverSecurityData.encryptionMethod);
                RdpbcgrEncoder.EncodeStructure(securityData, (uint)gccPdu.serverSecurityData.encryptionLevel);

                if (gccPdu.serverSecurityData.encryptionMethod != EncryptionMethods.ENCRYPTION_METHOD_NONE ||
                    gccPdu.serverSecurityData.encryptionLevel != EncryptionLevel.ENCRYPTION_LEVEL_NONE)
                {
                    RdpbcgrEncoder.EncodeStructure(securityData, gccPdu.serverSecurityData.serverRandomLen.actualData);
                    RdpbcgrEncoder.EncodeStructure(securityData, gccPdu.serverSecurityData.serverCertLen.actualData);
                    if (gccPdu.serverSecurityData.serverRandom != null)
                    {
                        RdpbcgrEncoder.EncodeBytes(securityData, gccPdu.serverSecurityData.serverRandom);
                    }

                    #region Encode certificate
                    if (gccPdu.serverSecurityData.serverCertificate != null)
                    {
                        RdpbcgrEncoder.EncodeStructure(securityData, (uint)gccPdu.serverSecurityData.serverCertificate.dwVersion);
                        if (gccPdu.serverSecurityData.serverCertificate.dwVersion == SERVER_CERTIFICATE_dwVersion_Values.CERT_CHAIN_VERSION_1)
                        {
                            PROPRIETARYSERVERCERTIFICATE cert = (PROPRIETARYSERVERCERTIFICATE)gccPdu.serverSecurityData.serverCertificate.certData;
                            RdpbcgrEncoder.EncodeStructure(securityData, (uint)cert.dwSigAlgId);
                            RdpbcgrEncoder.EncodeStructure(securityData, (uint)cert.dwKeyAlgId);
                            RdpbcgrEncoder.EncodeStructure(securityData, (ushort)cert.wPublicKeyBlobType);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.wPublicKeyBlobLen);
                            RdpbcgrEncoder.EncodeStructure(securityData, (uint)cert.PublicKeyBlob.magic);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.PublicKeyBlob.keylen);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.PublicKeyBlob.bitlen);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.PublicKeyBlob.datalen);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.PublicKeyBlob.pubExp);
                            RdpbcgrEncoder.EncodeBytes(securityData, cert.PublicKeyBlob.modulus);
                            RdpbcgrEncoder.EncodeStructure(securityData, (ushort)cert.wSignatureBlobType);
                            RdpbcgrEncoder.EncodeStructure(securityData, cert.wSignatureBlobLen);
                            RdpbcgrEncoder.EncodeBytes(securityData, cert.SignatureBlob);
                        }
                        else if (gccPdu.serverSecurityData.serverCertificate.dwVersion == SERVER_CERTIFICATE_dwVersion_Values.CERT_CHAIN_VERSION_2)
                        {
                            X509_CERTIFICATE_CHAIN cert = (X509_CERTIFICATE_CHAIN)gccPdu.serverSecurityData.serverCertificate.certData;
                            RdpbcgrEncoder.EncodeStructure(securityData, (uint)cert.NumCertBlobs);
                            for (int i = 0; i < cert.CertBlobArray.Length; i++)
                            {
                                RdpbcgrEncoder.EncodeStructure(securityData, cert.CertBlobArray[i].cbCert);
                                RdpbcgrEncoder.EncodeBytes(securityData, cert.CertBlobArray[i].abCert);
                            }
                            RdpbcgrEncoder.EncodeBytes(securityData, cert.Padding);
                        }
                    }
                    #endregion
                }
                userData.AddRange(securityData.ToArray());
            }
            #endregion Encode serverSecurityData TS_UD_CS_SEC

            #region Encode serverMessageChannelData TS_UD_SC_MCS_MSGCHANNEL
            if (gccPdu.serverMessageChannelData != null)
            {
                List<byte> msgChannelData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(msgChannelData, gccPdu.serverMessageChannelData.header);
                RdpbcgrEncoder.EncodeStructure(msgChannelData, gccPdu.serverMessageChannelData.MCSChannelID);
                userData.AddRange(msgChannelData.ToArray());
            }
            #endregion

            #region Encode serverMultitransportChannelData TS_UD_SC_MULTITRANSPORT
            if (gccPdu.serverMultitransportChannelData != null)
            {
                List<byte> multiTranChannelData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(multiTranChannelData, gccPdu.serverMultitransportChannelData.header);
                RdpbcgrEncoder.EncodeStructure(multiTranChannelData, (uint)gccPdu.serverMultitransportChannelData.flags);
                userData.AddRange(multiTranChannelData.ToArray());
            }
            #endregion

            #endregion Encode userData

            #region Filling GCC Conference Create Request
            ConferenceCreateResponse gccCCrsp = new ConferenceCreateResponse();
            gccCCrsp.nodeID = new UserID(gccPdu.nodeID);
            gccCCrsp.tag = new Asn1Integer(gccPdu.tag);
            gccCCrsp.result = new ConferenceCreateResponse_result(gccPdu.ccrResult);
            //gccCCrsp.extElem1 = new Asn1OpenExt();
            UserDataElement[] dataElements = new UserDataElement[1];
            dataElements[0] = new UserDataElement();
            dataElements[0].key = new Key(Key.h221NonStandard,
                                          new H221NonStandardIdentifier(gccPdu.H221Key));
            dataElements[0].value = new Asn1OctetString(userData.ToArray());
            gccCCrsp.userData = new UserData(dataElements);
            ConnectGCCPDU cGccPdu = new ConnectGCCPDU(ConnectGCCPDU.conferenceCreateResponse, gccCCrsp);
            #endregion Filling GCC Conference Create Request

            #region Encode ConnectData
            Asn1PerEncodingBuffer perBuffer = new Asn1PerEncodingBuffer(true);
            cGccPdu.PerEncode(perBuffer);
            byte[] asnEncodedData = perBuffer.ByteArrayData;
            Key key = new Key(Key.obj, new Asn1ObjectIdentifier(ConstValue.MCS_ATTRIBUTE_ID));
            ConnectData connectData = new ConnectData(key, new Asn1OctetString(asnEncodedData));
            Asn1PerEncodingBuffer perBuffer2 = new Asn1PerEncodingBuffer(true);
            connectData.PerEncode(perBuffer2);
            #endregion Encode ConnectData

            #region Workaround for Windows encoding issue

            //reset the ConnectPDULength to one-byte length: 0x2A
            byte[] returnButter = null;
            if ((perBuffer2.ByteArrayData[7] & 0x80) == 0x80)
            {
                //If length is two-byte, delete one byte
                returnButter = new byte[perBuffer2.ByteArrayData.Length - 1];
                Array.Copy(perBuffer2.ByteArrayData, returnButter, 7);
                Array.Copy(perBuffer2.ByteArrayData, 8, returnButter, 7, returnButter.Length - 7);
            }
            else
            {
                returnButter = new byte[perBuffer2.ByteArrayData.Length];
                Array.Copy(perBuffer2.ByteArrayData, returnButter, perBuffer2.ByteArrayData.Length);
            }
            returnButter[7] = 0x2A;

            #endregion

            return returnButter;
        }
        /// <summary>
        /// Decode MCS Connect Initial PDU with GCC Conference Create Initial
        /// </summary>
        /// <param name="data">data to be parsed</param>
        /// <returns>Decoded MCS Connect Initial PDU with GCC Conference Create Initial</returns>
        public StackPacket DecodeMcsConnectInitialPDU(byte[] data)
        {
            // initialize
            int currentIndex = 0;
            Client_MCS_Connect_Initial_Pdu_with_GCC_Conference_Create_Request pdu =
                new Client_MCS_Connect_Initial_Pdu_with_GCC_Conference_Create_Request();

            // McsConnectResponse: TpktHeader
            pdu.tpktHeader = ParseTpktHeader(data, ref currentIndex);

            // McsConnectResponse: X224
            pdu.x224Data = ParseX224Data(data, ref currentIndex);

            // T125 Data: decode McsConnectResponse
            int t125DataLength = data.Length - currentIndex;
            if (t125DataLength <= 0)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }
            byte[] t125Data = new byte[t125DataLength];
            Array.Copy(data, currentIndex, t125Data, 0, t125Data.Length);
            Connect_Initial mcsConnectInitial = new Connect_Initial();
            Asn1DecodingBuffer decodeBuffer = new Asn1DecodingBuffer(t125Data);
            mcsConnectInitial.BerDecode(decodeBuffer);

            // McsConnectResponse:result
            pdu.mcsCi.targetParameters.maxChannelIds = (long)mcsConnectInitial.targetParameters.maxChannelIds.Value;
            pdu.mcsCi.targetParameters.maxHeight = (long)mcsConnectInitial.targetParameters.maxHeight.Value;
            pdu.mcsCi.targetParameters.maxMcsPduSize = (long)mcsConnectInitial.targetParameters.maxMCSPDUsize.Value;
            pdu.mcsCi.targetParameters.maxTokenIds = (long)mcsConnectInitial.targetParameters.maxTokenIds.Value;
            pdu.mcsCi.targetParameters.maxUserIds = (long)mcsConnectInitial.targetParameters.maxUserIds.Value;
            pdu.mcsCi.targetParameters.minThroughput = (long)mcsConnectInitial.targetParameters.minThroughput.Value;
            pdu.mcsCi.targetParameters.numPriorities = (long)mcsConnectInitial.targetParameters.numPriorities.Value;
            pdu.mcsCi.targetParameters.protocolVersion = (long)mcsConnectInitial.targetParameters.protocolVersion.Value;

            pdu.mcsCi.minimumParameters.maxChannelIds = (long)mcsConnectInitial.minimumParameters.maxChannelIds.Value;
            pdu.mcsCi.minimumParameters.maxHeight = (long)mcsConnectInitial.minimumParameters.maxHeight.Value;
            pdu.mcsCi.minimumParameters.maxMcsPduSize = (long)mcsConnectInitial.minimumParameters.maxMCSPDUsize.Value;
            pdu.mcsCi.minimumParameters.maxTokenIds = (long)mcsConnectInitial.minimumParameters.maxTokenIds.Value;
            pdu.mcsCi.minimumParameters.maxUserIds = (long)mcsConnectInitial.minimumParameters.maxUserIds.Value;
            pdu.mcsCi.minimumParameters.minThroughput = (long)mcsConnectInitial.minimumParameters.minThroughput.Value;
            pdu.mcsCi.minimumParameters.numPriorities = (long)mcsConnectInitial.minimumParameters.numPriorities.Value;
            pdu.mcsCi.minimumParameters.protocolVersion = (long)mcsConnectInitial.minimumParameters.protocolVersion.Value;

            pdu.mcsCi.maximumParameters.maxChannelIds = (long)mcsConnectInitial.maximumParameters.maxChannelIds.Value;
            pdu.mcsCi.maximumParameters.maxHeight = (long)mcsConnectInitial.maximumParameters.maxHeight.Value;
            pdu.mcsCi.maximumParameters.maxMcsPduSize = (long)mcsConnectInitial.maximumParameters.maxMCSPDUsize.Value;
            pdu.mcsCi.maximumParameters.maxTokenIds = (long)mcsConnectInitial.maximumParameters.maxTokenIds.Value;
            pdu.mcsCi.maximumParameters.maxUserIds = (long)mcsConnectInitial.maximumParameters.maxUserIds.Value;
            pdu.mcsCi.maximumParameters.minThroughput = (long)mcsConnectInitial.maximumParameters.minThroughput.Value;
            pdu.mcsCi.maximumParameters.numPriorities = (long)mcsConnectInitial.maximumParameters.numPriorities.Value;
            pdu.mcsCi.maximumParameters.protocolVersion = (long)mcsConnectInitial.maximumParameters.protocolVersion.Value;

            // T125 User Data: get McsConnectResponse's user data
            //byte[] userData = new byte[mcsConnectInitial.userData.Length];
            //Stream mscInput = mcsConnectInitial.userData.toInputStream();
            //mscInput.Read(userData, 0, userData.Length);
            byte[] userData = mcsConnectInitial.userData.ByteArrayValue;

            // T125 User Data: decode McsConnectResponse's user data
            Asn1DecodingBuffer connectDataBuffer = new Asn1DecodingBuffer(userData);
            ConnectData connectData = new ConnectData();
            connectData.PerDecode(connectDataBuffer);

            // Gcc Data: get Gcc data
            int gccDataLength = userData.Length - ConstValue.GCC_CCI_DATA_OFFSET;
            if (gccDataLength <= 0)
            {
                throw new FormatException(ConstValue.ERROR_MESSAGE_DATA_INDEX_OUT_OF_RANGE);
            }
            byte[] gccData = new byte[gccDataLength];
            Array.Copy(userData, ConstValue.GCC_CCI_DATA_OFFSET, gccData, 0, gccData.Length);

            // Gcc Data: decode Gcc data
            ConnectGCCPDU gccPdu = new ConnectGCCPDU();
            Asn1DecodingBuffer gccPduBuffer = new Asn1DecodingBuffer(gccData);
            gccPdu.PerDecode(gccPduBuffer);

            // McsConnectResponse: H221Key
            ConferenceCreateRequest conferenceRequest = (ConferenceCreateRequest)gccPdu.GetData();
            H221NonStandardIdentifier identifier =
                (H221NonStandardIdentifier)conferenceRequest.userData.Elements[0].key.GetData();
            pdu.mcsCi.gccPdu.h221Key = Encoding.ASCII.GetString(identifier.ByteArrayValue);

            // Gcc User Data: get Gcc user data
            byte[] gccUserData = conferenceRequest.userData.Elements[0].value.ByteArrayValue;

            // Reset current index
            currentIndex = 0;
            while (currentIndex < gccUserData.Length)
            {
                // Peek data type
                int tempIndex = currentIndex;
                int orgIndex = currentIndex;
                TS_UD_HEADER_type_Values type =
                    (TS_UD_HEADER_type_Values)ParseUInt16(gccUserData, ref tempIndex, false);
                ushort userDataLength = ParseUInt16(gccUserData, ref tempIndex, false);

                // Parse data by type
                switch (type)
                {
                    case TS_UD_HEADER_type_Values.CS_CORE:
                        pdu.mcsCi.gccPdu.clientCoreData = ParseTsUdCsCore(gccUserData, ref currentIndex, userDataLength);
                        break;

                    case TS_UD_HEADER_type_Values.CS_NET:
                        pdu.mcsCi.gccPdu.clientNetworkData = ParseTsUdCsNet(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_SECURITY:
                        pdu.mcsCi.gccPdu.clientSecurityData = ParseTsUdCsSec(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_CLUSTER:
                        pdu.mcsCi.gccPdu.clientClusterData = ParseTsUdCsCluster(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_MONITOR:
                        pdu.mcsCi.gccPdu.clientMonitorData = ParseTsUdCsMon(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_MCS_MSGCHANNEL:
                        pdu.mcsCi.gccPdu.clientMessageChannelData = ParseTsUdCsMcsMsgChannel(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_MULTITRANSPORT:
                        pdu.mcsCi.gccPdu.clientMultitransportChannelData = ParseTsUdCsMultiTransport(gccUserData, ref currentIndex);
                        break;

                    case TS_UD_HEADER_type_Values.CS_MONITOR_EX:
                        pdu.mcsCi.gccPdu.clientMonitorExtendedData = ParseTsUdCsMonitorEX(gccUserData, ref currentIndex);
                        break;

                    default:
                        break;
                    //throw new FormatException(ConstValue.ERROR_MESSAGE_ENUM_UNRECOGNIZED);
                }
                currentIndex = orgIndex + userDataLength;
            }

            // Check if data length exceeded expectation
            VerifyDataLength(gccUserData.Length, currentIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }
Пример #4
0
        /// <summary>
        /// Encode GCC Conference Create Request according to [T124].
        /// </summary>
        /// <param name="gccPdu">The data to be encoded.</param>
        /// <returns>The encoded data.</returns>
        private static byte[] EncodeGccData(ConnectGCC gccPdu)
        {
            if (gccPdu == null)
            {
                return null;
            }

            #region Encode userData
            List<byte> userData = new List<byte>();

            #region Encode clientCoreData structure TS_UD_CS_CORE
            if (gccPdu.clientCoreData != null)
            {
                List<byte> coreData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.header);
                RdpbcgrEncoder.EncodeStructure(coreData, (uint)gccPdu.clientCoreData.version);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.desktopWidth);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.desktopHeight);
                RdpbcgrEncoder.EncodeStructure(coreData, (ushort)gccPdu.clientCoreData.colorDepth);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.SASSequence);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.keyboardLayout);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.clientBuild);
                RdpbcgrEncoder.EncodeUnicodeString(coreData, gccPdu.clientCoreData.clientName,
                                                   ConstValue.CLIENT_CORE_DATA_CLIENT_NAME_SIZE);
                RdpbcgrEncoder.EncodeStructure(coreData, (uint)gccPdu.clientCoreData.keyboardType);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.keyboardSubType);
                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.keyboardFunctionKey);
                RdpbcgrEncoder.EncodeUnicodeString(coreData, gccPdu.clientCoreData.imeFileName,
                                                   ConstValue.CLIENT_CORE_DATA_IME_FILE_NAME_SIZE);

                if (gccPdu.clientCoreData.postBeta2ColorDepth == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.postBeta2ColorDepth.actualData);

                if (gccPdu.clientCoreData.clientProductId == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.clientProductId.actualData);

                if (gccPdu.clientCoreData.serialNumber == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.serialNumber.actualData);

                if (gccPdu.clientCoreData.highColorDepth == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.highColorDepth.actualData);

                if (gccPdu.clientCoreData.supportedColorDepths == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.supportedColorDepths.actualData);

                if (gccPdu.clientCoreData.earlyCapabilityFlags == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.earlyCapabilityFlags.actualData);

                if (gccPdu.clientCoreData.clientDigProductId == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeUnicodeString(coreData, gccPdu.clientCoreData.clientDigProductId,
                                                   ConstValue.CLIENT_CORE_DATA_CLIENT_DIG_PRODUCT_ID_SIZE);

                if (gccPdu.clientCoreData.connnectionType == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.connnectionType.actualData);

                if (gccPdu.clientCoreData.pad1octets == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.pad1octets.actualData);

                if (gccPdu.clientCoreData.serverSelectedProtocol == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.serverSelectedProtocol.actualData);

                if (gccPdu.clientCoreData.desktopPhysicalWidth == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.desktopPhysicalWidth.actualData);

                if (gccPdu.clientCoreData.desktopPhysicalHeight == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.desktopPhysicalHeight.actualData);

                RdpbcgrEncoder.EncodeStructure(coreData, (ushort)gccPdu.clientCoreData.desktopOrientation);

                if (gccPdu.clientCoreData.desktopScaleFactor == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.desktopScaleFactor.actualData);

                if (gccPdu.clientCoreData.deviceScaleFactor == null)
                {
                    goto labelCoreEnd;
                }

                RdpbcgrEncoder.EncodeStructure(coreData, gccPdu.clientCoreData.deviceScaleFactor.actualData);

            labelCoreEnd:
                userData.AddRange(coreData.ToArray());
            }
            #endregion Encode clientCoreData structure TS_UD_CS_CORE

            #region Encode clientSecurityData TS_UD_CS_SEC
            if (gccPdu.clientSecurityData != null)
            {
                List<byte> securityData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(securityData, gccPdu.clientSecurityData.header);
                RdpbcgrEncoder.EncodeStructure(securityData, (uint)gccPdu.clientSecurityData.encryptionMethods);
                RdpbcgrEncoder.EncodeStructure(securityData, gccPdu.clientSecurityData.extEncryptionMethods);
                userData.AddRange(securityData.ToArray());
            }
            #endregion Encode clientSecurityData TS_UD_CS_SEC

            #region Encode clientNetworkData TS_UD_CS_NET
            if (gccPdu.clientNetworkData != null)
            {
                List<byte> networkData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.clientNetworkData.header);
                RdpbcgrEncoder.EncodeStructure(networkData, gccPdu.clientNetworkData.channelCount);
                for (int i = 0; i < gccPdu.clientNetworkData.channelCount; ++i)
                {
                    RdpbcgrEncoder.EncodeAnsiString(networkData,
                                                    gccPdu.clientNetworkData.channelDefArray[i].name,
                                                    ConstValue.CHANNEL_DEF_NAME_SIZE);
                    RdpbcgrEncoder.EncodeStructure(networkData,
                                                   (uint)gccPdu.clientNetworkData.channelDefArray[i].options);
                }

                userData.AddRange(networkData.ToArray());
            }
            #endregion Encode clientNetworkData TS_UD_CS_NET

            #region Encode clientClusterData TS_UD_CS_CLUSTER
            if (gccPdu.clientClusterData != null)
            {
                List<byte> clusterData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(clusterData, gccPdu.clientClusterData.header);
                RdpbcgrEncoder.EncodeStructure(clusterData, (uint)gccPdu.clientClusterData.Flags);
                RdpbcgrEncoder.EncodeStructure(clusterData, gccPdu.clientClusterData.RedirectedSessionID);
                userData.AddRange(clusterData.ToArray());
            }
            #endregion Encode clientClusterData TS_UD_CS_CLUSTER

            #region Encode clientMonitorData TS_UD_CS_MONITOR
            if (gccPdu.clientMonitorData != null)
            {
                List<byte> monitorData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(monitorData, gccPdu.clientMonitorData.header);
                RdpbcgrEncoder.EncodeStructure(monitorData, gccPdu.clientMonitorData.Flags);
                RdpbcgrEncoder.EncodeStructure(monitorData, gccPdu.clientMonitorData.monitorCount);

                for (int i = 0; i < gccPdu.clientMonitorData.monitorCount; ++i)
                {
                    RdpbcgrEncoder.EncodeStructure(monitorData,
                                                   gccPdu.clientMonitorData.monitorDefArray[i].left);
                    RdpbcgrEncoder.EncodeStructure(monitorData,
                                                   gccPdu.clientMonitorData.monitorDefArray[i].top);
                    RdpbcgrEncoder.EncodeStructure(monitorData,
                                                   gccPdu.clientMonitorData.monitorDefArray[i].right);
                    RdpbcgrEncoder.EncodeStructure(monitorData,
                                                   gccPdu.clientMonitorData.monitorDefArray[i].bottom);
                    RdpbcgrEncoder.EncodeStructure(monitorData,
                                                   (uint)gccPdu.clientMonitorData.monitorDefArray[i].flags);
                }

                userData.AddRange(monitorData.ToArray());
            }
            #endregion Encode clientMonitorData TS_UD_CS_MONITOR

            #region Encode clientMessageChannelData TS_UD_CS_MCS_MSGCHANNEL
            if (gccPdu.clientMessageChannelData != null)
            {
                List<byte> messageChannelData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(messageChannelData, gccPdu.clientMessageChannelData.header);
                RdpbcgrEncoder.EncodeStructure(messageChannelData, (uint)gccPdu.clientMessageChannelData.flags);
                userData.AddRange(messageChannelData.ToArray());
            }
            #endregion Encode clientMessageChannelData TS_UD_CS_MCS_MSGCHANNEL

            #region Encode clientMultitransportChannelData TS_UD_CS_MULTITRANSPORT
            if (gccPdu.clientMultitransportChannelData != null)
            {
                List<byte> multitransportChannelData = new List<byte>();
                RdpbcgrEncoder.EncodeStructure(multitransportChannelData, gccPdu.clientMultitransportChannelData.header);
                RdpbcgrEncoder.EncodeStructure(multitransportChannelData, (uint)gccPdu.clientMultitransportChannelData.flags);
                userData.AddRange(multitransportChannelData.ToArray());
            }
            #endregion Encode clientMultitransportChannelData TS_UD_CS_MONITOR_EX

            #region Encode clientMonitorExtendedData TS_UD_CS_MULTITRANSPORT

            if (gccPdu.clientMonitorExtendedData != null)
            {
                List<byte> monitorExtendData = new List<byte>();

                RdpbcgrEncoder.EncodeStructure(monitorExtendData, gccPdu.clientMonitorExtendedData.header);
                RdpbcgrEncoder.EncodeStructure(monitorExtendData, gccPdu.clientMonitorExtendedData.flags);
                RdpbcgrEncoder.EncodeStructure(monitorExtendData, gccPdu.clientMonitorExtendedData.monitorAttributeSize);
                RdpbcgrEncoder.EncodeStructure(monitorExtendData, gccPdu.clientMonitorExtendedData.monitorCount);

                foreach (var attribute in gccPdu.clientMonitorExtendedData.monitorAttributesArray)
                {
                    RdpbcgrEncoder.EncodeStructure(monitorExtendData, attribute.physicalWidth);
                    RdpbcgrEncoder.EncodeStructure(monitorExtendData, attribute.physicalHeight);
                    RdpbcgrEncoder.EncodeStructure(monitorExtendData, (uint)attribute.orientation);
                    RdpbcgrEncoder.EncodeStructure(monitorExtendData, attribute.desktopScaleFactor);
                    RdpbcgrEncoder.EncodeStructure(monitorExtendData, attribute.deviceScaleFactor);
                }

            }
            #endregion Encode clientMonitorExtendedData TS_UD_CS_MONITOR_EX

            #endregion Encode userData

            #region Filling GCC Conference Create Request
            ConferenceCreateRequest gccCCrq = new ConferenceCreateRequest();
            if (gccPdu.conferenceName != null)
            {
                gccCCrq.conferenceName = new ConferenceName(gccPdu.conferenceName);
            }

            if (gccPdu.convenerPassword != null)
            {
                gccCCrq.convenerPassword = new Password(gccPdu.convenerPassword);
            }

            if (gccPdu.password != null)
            {
                gccCCrq.password = new Password(gccPdu.password);
            }

            gccCCrq.lockedConference = new Asn1Boolean(gccPdu.lockedConference);
            gccCCrq.listedConference = new Asn1Boolean(gccPdu.listedConference);
            gccCCrq.conductibleConference = new Asn1Boolean(gccPdu.conductibleConference);
            gccCCrq.terminationMethod = new TerminationMethod(gccPdu.terminationMethod);

            if (gccPdu.conductorPrivileges != null)
            {
                List<Privilege> privilege = new List<Privilege>();
                foreach (int i in gccPdu.conductorPrivileges)
                {
                    privilege.Add(new Privilege(i));
                }

                gccCCrq.conductorPrivileges = new Asn1SetOf<Privilege>(privilege.ToArray());
            }

            if (gccPdu.conductedPrivileges != null)
            {
                List<Privilege> privilege = new List<Privilege>();
                foreach (int i in gccPdu.conductedPrivileges)
                {
                    privilege.Add(new Privilege(i));
                }

                gccCCrq.conductedPrivileges = new Asn1SetOf<Privilege>(privilege.ToArray());
            }

            if (gccPdu.nonConductedPrivileges != null)
            {
                List<Privilege> privilege = new List<Privilege>();
                foreach (int i in gccPdu.nonConductedPrivileges)
                {
                    privilege.Add(new Privilege(i));
                }

                gccCCrq.nonConductedPrivileges = new  Asn1SetOf<Privilege>(privilege.ToArray());
            }

            if (gccPdu.conferenceDescription != null)
            {
                gccCCrq.conferenceDescription = new TextString(gccPdu.conferenceDescription);
            }

            if (gccPdu.callerIdentifier != null)
            {
                gccCCrq.callerIdentifier = new TextString(gccPdu.callerIdentifier);
            }

            //gccCCrq.extElem1 = new Asn1OpenExt();

            UserDataElement[] dataElements = new UserDataElement[1];
            dataElements[0] = new UserDataElement();
            dataElements[0].key = new Key(Key.h221NonStandard,
                                          new H221NonStandardIdentifier(ConstValue.H221_NON_STANDARD_KEY));
            dataElements[0].value = new Asn1OctetString(userData.ToArray());
            gccCCrq.userData = new UserData(dataElements);

            ConnectGCCPDU cGccPdu = new ConnectGCCPDU(ConnectGCCPDU.conferenceCreateRequest, gccCCrq);
            #endregion Filling GCC Conference Create Request

            #region Encode ConnectData
            Asn1PerEncodingBuffer perBuffer = new Asn1PerEncodingBuffer(true);
            cGccPdu.PerEncode(perBuffer);
            byte[] asnEncodedData = perBuffer.ByteArrayData;
            Key key = new Key(Key.obj, new Asn1ObjectIdentifier(ConstValue.MCS_ATTRIBUTE_ID));
            ConnectData connectData = new ConnectData(key, new Asn1OctetString(asnEncodedData));
            Asn1PerEncodingBuffer perBuffer2 = new Asn1PerEncodingBuffer(true);
            connectData.PerEncode(perBuffer2);
            #endregion Encode ConnectData

            return perBuffer2.ByteArrayData;
        }