/// <summary> /// Process Auto Detect feature /// </summary> /// <param name="pdu"></param> public override void ProcessSubHeaders(RdpemtBasePDU pdu) { if (pdu == null || pdu.TunnelHeader == null) { return; } if (detectBandwidth) { // if detect device, count bytes bandwidthMeasurePayloadByteCount += ((uint)pdu.TunnelHeader.PayloadLength + pdu.TunnelHeader.HeaderLength); } RDP_TUNNEL_SUBHEADER[] RDPTunnelSubHeaders = pdu.TunnelHeader.SubHeaders; if (RDPTunnelSubHeaders != null) { foreach (RDP_TUNNEL_SUBHEADER RDPTunnelSubHeader in RDPTunnelSubHeaders) { if (RDPTunnelSubHeader.SubHeaderType == RDP_TUNNEL_SUBHEADER_TYPE_Values.TYPE_ID_AUTODETECT_REQUEST) { uint sequenceNumber = (uint)(RDPTunnelSubHeader.SubHeaderData[1] << 8) + RDPTunnelSubHeader.SubHeaderData[0]; uint responseType = (uint)(RDPTunnelSubHeader.SubHeaderData[3] << 8) + RDPTunnelSubHeader.SubHeaderData[2]; if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_START_AFTER_CONNECTTIME_OR_LOSSYUDP || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_START_AFTER_CONNECTTIME_OR_RELIABLEUDP) { // Start bandwidth detect bandwidthMeasureStartTime = DateTime.Now; bandwidthMeasurePayloadByteCount = 0; detectBandwidth = true; } else if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_LOSSYUDP || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_RELIABLEUDP) { detectBandwidth = false; TimeSpan duration = DateTime.Now - bandwidthMeasureStartTime; this.timeDelta = (uint)duration.TotalMilliseconds; bwStopSequenceNumber = (ushort)sequenceNumber; // Send RDP_BW_RESULTS if (AutoHandle) { byte[] subHeader = GenerateSubHander_BWResult(); List <byte[]> subHeaders = new List <byte[]>(); subHeaders.Add(subHeader); RDP_TUNNEL_DATA tunnelData = CreateTunnelDataPdu(null, subHeaders, RDP_TUNNEL_SUBHEADER_TYPE_Values.TYPE_ID_AUTODETECT_RESPONSE); this.SendRdpemtPacket(tunnelData); } } else if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_NETCHAR_RESULT_BANDWIDTH_AVERAGERTT || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_NETCHAR_RESULT_BASERTT_BANDWIDTH_AVERAGERTT) { // Update bandwidth RDP_NETCHAR_RESULT ncRes = RdpemtUtility.ParseRdpNetCharResult(RDPTunnelSubHeader.SubHeaderData); this.bandwidth = ncRes.bandwidth; } } } } }
/// <summary> /// Process Auto Detect feature /// </summary> /// <param name="pdu"></param> public override void ProcessSubHeaders(RdpemtBasePDU pdu) { RDP_TUNNEL_SUBHEADER[] RDPTunnelSubHeaders = pdu.TunnelHeader.SubHeaders; if (RDPTunnelSubHeaders != null) { foreach (RDP_TUNNEL_SUBHEADER RDPTunnelSubHeader in RDPTunnelSubHeaders) { if (RDPTunnelSubHeader.SubHeaderType == RDP_TUNNEL_SUBHEADER_TYPE_Values.TYPE_ID_AUTODETECT_RESPONSE) { uint responseType = (uint)(RDPTunnelSubHeader.SubHeaderData[3] << 8) + RDPTunnelSubHeader.SubHeaderData[2]; if (responseType == (uint)AUTO_DETECT_RESPONSE_TYPE.RDP_BW_RESULTS_AFTER_CONNECT) { RDP_BW_RESULTS bwRes = RdpemtUtility.ParseRdpBWResults(RDPTunnelSubHeader.SubHeaderData); this.bandwidth = (bwRes.byteCount * 8) / bwRes.timeDelta; } } } } }
/// <summary> /// Decode bytes data /// This method will buffer data cannot decoded this time, and merged it with data from next call /// </summary> /// <param name="newData"></param> /// <returns></returns> public RdpemtBasePDU[] Decode(byte[] newData) { int index = 0; buffer.AddRange(newData); byte[] data = buffer.ToArray(); List <RdpemtBasePDU> pduList = new List <RdpemtBasePDU>(); RdpemtBasePDU emtPacket = DecodeRdpemtPacket(data, ref index); while (emtPacket != null) { pduList.Add(emtPacket); emtPacket = DecodeRdpemtPacket(data, ref index); } buffer.RemoveRange(0, index); return(pduList.ToArray()); }
/// <summary> /// Process Auto Detect feature /// </summary> /// <param name="pdu"></param> public override void ProcessSubHeaders(RdpemtBasePDU pdu) { if (pdu == null || pdu.TunnelHeader == null) { return; } if (detectBandwidth) { // if detect device, count bytes bandwidthMeasurePayloadByteCount += ((uint)pdu.TunnelHeader.PayloadLength + pdu.TunnelHeader.HeaderLength); } RDP_TUNNEL_SUBHEADER[] RDPTunnelSubHeaders = pdu.TunnelHeader.SubHeaders; if (RDPTunnelSubHeaders != null) { foreach (RDP_TUNNEL_SUBHEADER RDPTunnelSubHeader in RDPTunnelSubHeaders) { if (RDPTunnelSubHeader.SubHeaderType == RDP_TUNNEL_SUBHEADER_TYPE_Values.TYPE_ID_AUTODETECT_REQUEST) { uint sequenceNumber = (uint)(RDPTunnelSubHeader.SubHeaderData[1] << 8) + RDPTunnelSubHeader.SubHeaderData[0]; uint responseType = (uint)(RDPTunnelSubHeader.SubHeaderData[3] << 8) + RDPTunnelSubHeader.SubHeaderData[2]; if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_START_AFTER_CONNECTTIME_OR_LOSSYUDP || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_START_AFTER_CONNECTTIME_OR_RELIABLEUDP) { // Start bandwidth detect bandwidthMeasureStartTime = DateTime.Now; bandwidthMeasurePayloadByteCount = 0; detectBandwidth = true; } else if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_LOSSYUDP || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_BW_STOP_AFTER_CONNECTTIME_OR_RELIABLEUDP) { detectBandwidth = false; TimeSpan duration = DateTime.Now - bandwidthMeasureStartTime; this.timeDelta = (uint)duration.TotalMilliseconds; bwStopSequenceNumber = (ushort)sequenceNumber; // Send RDP_BW_RESULTS if (AutoHandle) { byte[] subHeader = GenerateSubHander_BWResult(); List<byte[]> subHeaders = new List<byte[]>(); subHeaders.Add(subHeader); RDP_TUNNEL_DATA tunnelData = CreateTunnelDataPdu(null, subHeaders, RDP_TUNNEL_SUBHEADER_TYPE_Values.TYPE_ID_AUTODETECT_RESPONSE); this.SendRdpemtPacket(tunnelData); } } else if (responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_NETCHAR_RESULT_BANDWIDTH_AVERAGERTT || responseType == (uint)AUTO_DETECT_REQUEST_TYPE.RDP_NETCHAR_RESULT_BASERTT_BANDWIDTH_AVERAGERTT) { // Update bandwidth RDP_NETCHAR_RESULT ncRes = RdpemtUtility.ParseRdpNetCharResult(RDPTunnelSubHeader.SubHeaderData); this.bandwidth = ncRes.bandwidth; } } } } }
/// <summary> /// Send Tunnel Data /// </summary> /// <param name="tunnelData">Tunnel Data to sent</param> public void SendRdpemtPacket(RdpemtBasePDU rdpemtPacket) { byte[] encodedData = PduMarshaler.Marshal(rdpemtPacket); this.secureChannel.Send(encodedData); }
/// <summary> /// abstract method to deal with auto detect /// The process is quick different between server and client /// </summary> /// <param name="pdu"></param> public abstract void ProcessSubHeaders(RdpemtBasePDU pdu);
/// <summary> /// Call this method to decode byte array to MS-RDPEMT packets /// </summary> /// <param name="action">The action value in header</param> /// <param name="data">Data in bytes to be decoded</param> /// <returns>The decoded packet</returns> public static RdpemtBasePDU DecodeRdpemtPacket(byte[] data, ref int index) { if (data == null || data.Length - index < 4) { return(null); } byte action = (byte)(0xF & data[index]); byte[] payloadLenData = new byte[2]; Array.Copy(data, index + 1, payloadLenData, 0, 2); if (!BitConverter.IsLittleEndian) { // Reverse the sequence if it is not little endian Array.Reverse(payloadLenData); } ushort payloadLength = BitConverter.ToUInt16(payloadLenData, 0); byte headerLength = data[index + 3]; int expectLen = payloadLength + headerLength; if (expectLen > data.Length) { return(null); } byte[] toDecodeData = new byte[expectLen]; Array.Copy(data, index, toDecodeData, 0, expectLen); index += expectLen; RdpemtBasePDU rePdu = null; if (action == (byte)RDP_TUNNEL_ACTION_Values.RDPTUNNEL_ACTION_CREATEREQUEST) { RDP_TUNNEL_CREATEREQUEST createReq = new RDP_TUNNEL_CREATEREQUEST(); bool bResult = PduMarshaler.Unmarshal(toDecodeData, createReq); if (bResult) { rePdu = createReq; } } else if (action == (byte)RDP_TUNNEL_ACTION_Values.RDPTUNNEL_ACTION_CREATERESPONSE) { RDP_TUNNEL_CREATERESPONSE createRes = new RDP_TUNNEL_CREATERESPONSE(); bool bResult = PduMarshaler.Unmarshal(toDecodeData, createRes); if (bResult) { rePdu = createRes; } } else if (action == (byte)RDP_TUNNEL_ACTION_Values.RDPTUNNEL_ACTION_DATA) { RDP_TUNNEL_DATA tunnelData = new RDP_TUNNEL_DATA(); bool bResult = PduMarshaler.Unmarshal(toDecodeData, tunnelData); if (bResult) { rePdu = tunnelData; } } else { throw new NotSupportedException("Unknow action in RDP_TUNNEL_HEADER:" + action); } if (rePdu == null) { throw new NotSupportedException("Decode for RDPEMT PDU failed, Action:" + action); } return(rePdu); }