/// <summary>
 /// Send a SYN and ACK diagram
 /// </summary>
 /// <param name="initSequenceNumber">Specify an initial sequence number</param>
 /// <returns></returns>
 public bool SendSynAndAckPacket(uint? initSequenceNumber = null, uUdpVer_Values? version = null)
 {
     if (Connected) return false;
     RdpeudpPacket SynAndAckPacket = new RdpeudpPacket();
     SynAndAckPacket.fecHeader.snSourceAck = SnSourceAck;
     SynAndAckPacket.fecHeader.uReceiveWindowSize = UReceiveWindowSize;
     SynAndAckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_SYN | RDPUDP_FLAG.RDPUDP_FLAG_ACK;
     if(version != null)
     {
         SynAndAckPacket.fecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNEX;
         SynAndAckPacket.SynDataEx = CreateSynExData((uUdpVer_Values)version);
     }
     SynAndAckPacket.SynData = CreateSynData(initSequenceNumber);
     SendPacket(SynAndAckPacket);
     // Set the OutSnAckOfAcksSeqNum value, number from which the receive thread decoding the state of the send packet.
     OutSnAckOfAcksSeqNum = SynAndAckPacket.SynData.Value.snInitialSequenceNumber + 1;
     return true;
 }
        /// <summary>
        /// Establish a UDP connection.
        /// </summary>
        /// <param name="udpTransportMode">Transport mode: Reliable or Lossy.</param>
        /// <param name="timeout">Wait time.</param>
        /// <param name="verifyPacket">Whether verify the received packet.</param>
        /// <returns>The accepted socket.</returns>
        private RdpeudpSocket EstablishUDPConnection(TransportMode udpTransportMode, TimeSpan timeout, bool verifyPacket = false, bool autoHanlde = false, uUdpVer_Values? uUdpVer =null)
        {
            // Start UDP listening.
            if(rdpeudpServer == null)
                rdpeudpServer = new RdpeudpServer((IPEndPoint)this.rdpbcgrAdapter.SessionContext.LocalIdentity, autoHanlde);
            if(!rdpeudpServer.Running)
                rdpeudpServer.Start();

            // Send a Server Initiate Multitransport Request PDU.
            byte[] securityCookie = new byte[16];
            Random rnd = new Random();
            rnd.NextBytes(securityCookie);
            Multitransport_Protocol_value requestedProtocol = Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECR;
            if (udpTransportMode == TransportMode.Lossy)
            {
                requestedProtocol = Multitransport_Protocol_value.INITITATE_REQUEST_PROTOCOL_UDPFECL;
            }
            this.rdpbcgrAdapter.SendServerInitiateMultitransportRequestPDU(++this.multitransportRequestId, requestedProtocol, securityCookie);

            // Create a UDP socket.
            RdpeudpServerSocket rdpudpSocket = rdpeudpServer.CreateSocket(((IPEndPoint)this.rdpbcgrAdapter.SessionContext.Identity).Address, udpTransportMode, timeout);
            if (rdpudpSocket == null)
            {
                this.Site.Assert.Fail("Failed to create a UDP socket for the Client : {0}", ((IPEndPoint)this.rdpbcgrAdapter.SessionContext.Identity).Address);
            }

            if (udpTransportMode == TransportMode.Reliable)
            {
                this.rdpeudpSocketR = rdpudpSocket;
            }
            else
            {
                this.rdpeudpSocketL = rdpudpSocket;
            }

            // Expect a SYN packet.
            RdpeudpPacket synPacket = rdpudpSocket.ExpectSynPacket(timeout);
            if (synPacket == null)
            {
                this.Site.Assert.Fail("Time out when waiting for the SYN packet");
            }

            // Verify the SYN packet.
            if (verifyPacket)
            {
                VerifySYNPacket(synPacket, udpTransportMode);
            }

            // Send a SYN and ACK packet.
            if (this.clientRdpudpVerfionInfoValidFlag == uSynExFlags_Values.RDPUDP_VERSION_INFO_VALID)
            {
                //Section 3.1.5.1.3: The uUdpVer field MUST be set to the highest RDP-UDP protocol version supported by both endpoints.
                uUdpVer = uUdpVer > this.clientUUdpVer ? this.clientUUdpVer : uUdpVer;
                SendSynAndAckPacket(udpTransportMode, SynAndAck_InvalidType.None, initSequenceNumber, uUdpVer);
            }
            else if(this.clientRdpudpVerfionInfoValidFlag == uSynExFlags_Values.None)
            {
                //Section 3.1.5.1.3: The highest version supported by both endpoints, which is RDPUDP_PROTOCOL_VERSION_1 if either this packet or the SYN packet does not specify a version, is the version that MUST be used by both endpoints.
                SendSynAndAckPacket(udpTransportMode, SynAndAck_InvalidType.None, initSequenceNumber, uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_1);
            }
            else
            {
                //Section 3.1.5.1.3: The RDPUDP_SYNEX_PAYLOAD structure (section 2.2.2.9) SHOULD only be present if it is also present in the received SYN packet.
                // When the
                SendSynAndAckPacket(udpTransportMode, SynAndAck_InvalidType.None, initSequenceNumber,null);
            }

            // Expect an ACK packet or ACK and Source Packet.
            RdpeudpPacket ackPacket = rdpudpSocket.ExpectACKPacket(timeout);
            if (ackPacket == null)
            {
                this.Site.Assert.Fail("Time out when waiting for the ACK packet to response the ACK and SYN packet");
            }

            // Verify the ACK packet.
            if (verifyPacket)
            {
                VerifyACKPacket(ackPacket);
            }

            // If the packet is an ACK and Source Packet, add the source packet to the un-processed packet.
            if (ackPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_DATA))
            {
                byte[] bytes = PduMarshaler.Marshal(ackPacket, false);
                RdpeudpBasePacket stackpacket = new RdpeudpBasePacket(bytes);
                rdpudpSocket.ReceivePacket(stackpacket);
            }

            rdpudpSocket.Connected = true;

            return rdpudpSocket;
        }
        /// <summary>
        /// Create RDPUDP_SYNDATAEX_PAYLOAD Structure
        /// </summary>
        /// <returns></returns>
        public RDPUDP_SYNDATAEX_PAYLOAD CreateSynExData(uUdpVer_Values version)
        {
            RDPUDP_SYNDATAEX_PAYLOAD SynExData = new RDPUDP_SYNDATAEX_PAYLOAD();
            SynExData.uSynExFlags = uSynExFlags_Values.RDPUDP_VERSION_INFO_VALID;

            //The uUdpVer field MUST be set to the highest RDP-UDP protocol version supported by both endpoints
            if((version & uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_2) != 0)
            {
                SynExData.uUdpVer = uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_2;
            }
            else
            {
                SynExData.uUdpVer = uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_1;
            }

            return SynExData;
        }
        /// <summary>
        /// Send SYN and ACK packet.
        /// </summary>
        /// <param name="udpTransportMode">Transport mode: Reliable or Lossy</param>
        /// <param name="invalidType">invalid type</param>
        public void SendSynAndAckPacket(TransportMode udpTransportMode, SynAndAck_InvalidType invalidType, uint? initSequenceNumber = null, uUdpVer_Values? uUdpVer= null)
        {
            RdpeudpServerSocket rdpeudpSocket = rdpeudpSocketR;
            if (udpTransportMode == TransportMode.Lossy)
            {
                rdpeudpSocket = rdpeudpSocketL;
            }

            if (invalidType == SynAndAck_InvalidType.None)
            {
                // If invalid type is None, send the packet directly.
                rdpeudpSocket.SendSynAndAckPacket(initSequenceNumber,uUdpVer);
                return;
            }

            // Create the SYN and ACK packet first.
            RdpeudpPacket SynAndAckPacket = CreateInvalidSynAndACKPacket(udpTransportMode, invalidType, initSequenceNumber);

            rdpeudpSocket.SendPacket(SynAndAckPacket);
        }