/// <summary> /// Send Data from this specified UDP transport /// </summary> /// <param name="data">Data to send</param> /// <returns>Return true if send success</returns> public bool Send(byte[] data) { if (!Connected) { return(false); } List <byte> dataList = new List <byte>(data); int payloadLength = 0; byte[] packetData; RdpeudpPacket packet; do { packet = new RdpeudpPacket(); // Fill in the common header. packet.fecHeader.snSourceAck = SnSourceAck; packet.fecHeader.uReceiveWindowSize = UReceiveWindowSize; packet.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_DATA | RDPUDP_FLAG.RDPUDP_FLAG_ACK; packet.ackVectorHeader = CreateAckVectorHeader(); packet.sourceHeader = CreateSourcePayloadHeader(); // Generate SourceHeader. packetData = PduMarshaler.Marshal(packet, false); // Measure the header lenght to figure out payload length. payloadLength = Math.Min(UUpStreamMtu - packetData.Length, dataList.Count); packet.payload = new byte[payloadLength]; dataList.CopyTo(0, packet.payload, 0, payloadLength); // Copy the data in to packet payload. string str = System.Text.Encoding.ASCII.GetString(packet.payload); SendPacket(packet); dataList.RemoveRange(0, payloadLength); } while (dataList.Count > 0); return(true); }
/// <summary> /// Expect a SYN and ACK Packet /// </summary> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectSynAndAckPacket(TimeSpan timeout) { if (Connected) { return(null); } DateTime endtime = DateTime.Now + timeout; while (DateTime.Now < endtime) { lock (unProcessedPacketBuffer) { for (int i = 0; i < unProcessedPacketBuffer.Count; i++) { RdpeudpPacket eudpPacket = unProcessedPacketBuffer[i]; if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN) && eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK)) { unProcessedPacketBuffer.RemoveAt(i); // Analyse the SYN packet. ProcessSynPacket(eudpPacket); return(eudpPacket); } } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return(null); }
/// <summary> /// Process Source payload if the packet has source payload data /// </summary> /// <param name="eudpPacket"></param> public void ProcessSourceData(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_DATA) && !eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC)) { lock (inPacketDic) { if (IsInReceiveWindow(eudpPacket.sourceHeader.Value.snSourceStart)) { SnSourceAck = Math.Max(SnSourceAck, eudpPacket.sourceHeader.Value.snSourceStart); InPacketState inPacketState = new InPacketState(); inPacketState.Packet = eudpPacket; inPacketDic[eudpPacket.sourceHeader.Value.snSourceStart] = inPacketState; UpdateReceiveWindow(); } // Increase received source packet numbers not be ack if (sourceNumNotAcked == 0) { ReceiveTimeForFirstNotACKSource = DateTime.Now; } sourceNumNotAcked++; } // Send ACK diagram if necessary. AckPacketReceived(); } }
/// <summary> /// Method used to process a received packet /// </summary> /// <param name="packet"></param> public void ReceivePacket(RdpeudpPacket eudpPacket) { // Update last receive time, which is used for keep alive timer LastReceiveDiagramTime = DateTime.Now; Monitor.Enter(receiveLock); if (!connected || !AutoHandle) { // If connection haven't been setuped, or Auto handle is false, this packet will not be processed automatically by this method. // It will buffer it for others to use it. lock (unProcessedPacketBuffer) unProcessedPacketBuffer.Add(eudpPacket); } else { // Process the received packet // In case the advised window size updated URemoteAdvisedWindowSize = eudpPacket.fecHeader.uReceiveWindowSize; // this value should update when receiving ACK if congestion algorithm is implemented USendWindowSize = URemoteAdvisedWindowSize; // Process Ack Vector Header if the packet contained ProcessAckVectorHeader(eudpPacket); // Process Source Data if the packet contained ProcessSourceData(eudpPacket); // Process FEC Payload data if the packet contained ProcessFECPayloadData(eudpPacket); // Process RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if the packet contained ProcessAckOfAckVectorHeader(eudpPacket); //TODO: Congestion control function } Monitor.Exit(receiveLock); }
/// <summary> /// Process RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if the packet have /// </summary> /// <param name="eudpPacket"></param> public void ProcessAckOfAckVectorHeader(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS)) { InSnAckOfAcksSeqNum = eudpPacket.ackOfAckVector.Value.snAckOfAcksSeqNum; } }
/// <summary> /// Send SYN Packet to init a RDPEUDP Connection /// </summary> /// <param name="initSequenceNumber">Specify a snInitialSequenceNumber</param> /// <returns></returns> public bool SendSynPacket(uint?initSequenceNumber = null, RDPUDP_PROTOCOL_VERSION?version = null) { if (Connected) { return(false); } RdpeudpPacket synPacket = new RdpeudpPacket(); synPacket.FecHeader.snSourceAck = UInt32.MaxValue; synPacket.FecHeader.uReceiveWindowSize = UReceiveWindowSize; synPacket.FecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_SYN; if (this.TransMode == TransportMode.Lossy) { synPacket.FecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } synPacket.SynData = CreateSynData(initSequenceNumber); if (version.HasValue) { synPacket.FecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNEX; var synDataEx = CreateSynExData((RDPUDP_PROTOCOL_VERSION)version); if (version.Value == RDPUDP_PROTOCOL_VERSION.RDPUDP_PROTOCOL_VERSION_3) { synDataEx.cookieHash = cookieHash; } synPacket.SynDataEx = synDataEx; } SendPacket(synPacket); // Set the OutSnResetSeqNum value, number from which the receive thread decoding the state of the send packet. OutSnResetSeqNum = synPacket.SynData.Value.snInitialSequenceNumber + 1; return(true); }
/// <summary> /// Process RDPUDP_FEC_PAYLOAD_HEADER Structure and FEC Payload /// </summary> /// <param name="eudpPacket"></param> public void ProcessFECPayloadData(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC)) { // TODO: process FEC payload, calculate lost packet with FEC data // then use UpdateReceiveWindow function to update window and process received data } }
/// <summary> /// Process RDPUDP_ACK_VECTOR_HEADER if the packet contains a RDPUDP_ACK_VECTOR_HEADER /// </summary> /// <param name="eudpPacket"></param> private void ProcessAckVectorHeader(RdpeudpPacket eudpPacket) { // Update OutSnAckOfAcksSeqNum if necessary UpdateOutSnAckOfAcksSeqNum(eudpPacket.fecHeader.snSourceAck); if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK) && !eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN)) { //Contains ack, analyze ack value, update outPacketDic, caculate RTT, and move send window if (eudpPacket.ackVectorHeader.Value.uAckVectorSize > 0) // Deal with ack vector. { uint currentposition = OutSnAckOfAcksSeqNum; lock (outPacketDic) { foreach (AckVector AckVectorElement in eudpPacket.ackVectorHeader.Value.AckVectorElement) { if (AckVectorElement.State == VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED) { // update outPacketDic only if this vector element is to ack received for (byte i = 0; i < AckVectorElement.Length + 1; i++, currentposition++) { if (outPacketDic.ContainsKey(currentposition)) { outPacketDic[currentposition].Acknowledged = true; } } } else { currentposition = currentposition + AckVectorElement.Length + 1; } } // If this packet is not a delay ack, calculate RTT, only the last acknowleged source packet is used to caculate RTT if (outPacketDic.ContainsKey(currentposition - 1)) { if (!eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACKDELAYED) && !outPacketDic[currentposition - 1].estimatedRTT) // Also make sure this packet has not been used to estimate RTT. If the packet has been used to estimated RTT, this packet may be a resent ACK for keep alive { RTT = new TimeSpan(RTT.Ticks / 8 * 7 + (DateTime.Now - outPacketDic[currentposition - 1].SendTime).Ticks / 8); // Count the RTT. outPacketDic[currentposition - 1].estimatedRTT = true; } } // Update send window, this method will update outPacketDic UpdateSendWindow(); } sendWindowLock.Set(); } } }
/// <summary> /// Establish Connection /// </summary> /// <param name="timeout"></param> /// <returns></returns> public bool Connect(TimeSpan timeout) { SendSynPacket(); RdpeudpPacket eudpPacket = ExpectSynAndAckPacket(timeout); if (eudpPacket == null) { return(false); } Connected = true; this.SendAcKPacket(); return(true); }
/// <summary> /// Process a Syn Packet /// </summary> /// <param name="eudpPacket"></param> public void ProcessSynPacket(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN) || eudpPacket.fecHeader.uFlags.Equals(RDPUDP_FLAG.RDPUDP_FLAG_SYN | RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY)) // Make sure this packet is a SYN Packet { UDownStreamMtu = (ushort)(Math.Min(Math.Min(eudpPacket.SynData.Value.uUpStreamMtu, UDownStreamMtu), (ushort)1232)); UUpStreamMtu = (ushort)(Math.Min(Math.Min(eudpPacket.SynData.Value.uDownStreamMtu, UUpStreamMtu), (ushort)1232)); USendWindowSize = eudpPacket.fecHeader.uReceiveWindowSize; TransMode = eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) ? TransportMode.Lossy : TransportMode.Reliable; SnSourceAck = eudpPacket.SynData.Value.snInitialSequenceNumber; InSnAckOfAcksSeqNum = eudpPacket.SynData.Value.snInitialSequenceNumber + 1; ReceiveWindowStartPosition = eudpPacket.SynData.Value.snInitialSequenceNumber + 1; } }
/// <summary> /// Expect a SYN and ACK Packet /// </summary> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectSynAndAckPacket(TimeSpan timeout) { if (Connected) { return(null); } DateTime endtime = DateTime.Now + timeout; while (DateTime.Now < endtime) { // Lock the ReceivePacket method if it is transferring to RDPEUDP2 to avoid processing RDPEUDP2 packets with the RDPEUDP logic. lock (receiveLock) { for (int i = 0; i < unprocessedPacketBuffer.Count; i++) { RdpeudpPacket eudpPacket = unprocessedPacketBuffer[i]; if (eudpPacket.FecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN) && eudpPacket.FecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK)) { unprocessedPacketBuffer.RemoveAt(i); if (eudpPacket.SynDataEx.HasValue) { if (eudpPacket.SynDataEx.Value.uUdpVer == RDPUDP_PROTOCOL_VERSION.RDPUDP_PROTOCOL_VERSION_3) { upgradedToRdpedup2 = true; DisposeTimers(); rdpeudp2Handler = new Rdpeudp2ProtocolHandler(AutoHandle, SendBytesByUdp, Close, ReceiveDataOnHigherLayer); rdpeudp2Handler.SocketConfig.RetransmitDuration = RTT * 2; rdpeudp2Handler.SocketConfig.DelayedAckTimeoutInMs = (int)(RTT.TotalMilliseconds / 2); return(eudpPacket); } } // Analyse the SYN packet. ProcessSynPacket(eudpPacket); return(eudpPacket); } } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return(null); }
/// <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) { 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; 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> /// Create a RdpeudpServerSocket /// The socket can only be created if the RdpeudpServer received corresponding SYN Packet /// </summary> /// <param name="remoteIP">IP adress</param> /// <param name="mode">connection mode</param> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpServerSocket CreateSocket(IPAddress remoteIP, TransportMode mode, TimeSpan timeout) { IPEndPoint remoteEndPoint; RdpeudpPacket synPacket = ExpectSyncPacket(remoteIP, mode, timeout, out remoteEndPoint); if (synPacket == null) { return(null); } RdpeudpServerSocket serverSock = new RdpeudpServerSocket(mode, remoteEndPoint, AutoHandle, packetsender, this); serverSock.ReceivePacket(synPacket); serverSocketDic[remoteEndPoint] = serverSock; return(serverSock); }
/// <summary> /// Send a RDPEUDP Packet /// </summary> /// <param name="packet"></param> /// <returns></returns> public bool SendPacket(RdpeudpPacket packet) { if (packet.sourceHeader.HasValue && AutoHandle) { // Deal with window area. OutPacketState packetState = new OutPacketState(); packetState.Packet = packet; packetState.Acknowledged = false; DateTime endTime = DateTime.Now + this.SocketConfig.Timeout; uint sendWindowsEndPos = SendWindowStartPosition + USendWindowSize; while (DateTime.Now < endTime) { //If source sequence number is in send slide window, send the packet. Otherwise, wait a sendingInterval if (!IsInSendWindow(packet.sourceHeader.Value.snSourceStart)) { sendWindowLock.WaitOne(this.SocketConfig.sendingInterval); } else { break; } } if (DateTime.Now > endTime) { // Time out. return(false); } packetState.SendTime = DateTime.Now; lock (outPacketDic) outPacketDic[packet.sourceHeader.Value.snSourceStart] = packetState; // Add RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if necessary UpdateOutSnAckOfAcksSeqNum(packet); } byte[] data = PduMarshaler.Marshal(packet, false); SendBytesByUDP(data); // Update Last send time, which is used for keep alive timer LastSendDiagramTime = DateTime.Now; return(true); }
/// <summary> /// Create Source Packet from byte data /// </summary> /// <param name="data"></param> /// <returns></returns> public RdpeudpPacket CreateSourcePacket(byte[] data) { if (data == null || data.Length == 0) { return(null); } RdpeudpPacket packet = new RdpeudpPacket(); // Fill in the common header. packet.fecHeader.snSourceAck = SnSourceAck; packet.fecHeader.uReceiveWindowSize = UReceiveWindowSize; packet.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_DATA | RDPUDP_FLAG.RDPUDP_FLAG_ACK; packet.ackVectorHeader = CreateAckVectorHeader(); packet.sourceHeader = CreateSourcePayloadHeader(); packet.payload = data; return(packet); }
/// <summary> /// Method used to process a received packet /// </summary> /// <param name="packet"></param> public void ReceivePacket(StackPacket packet) { // Transfer packet to RdpeudpPacket eudpPacket = new RdpeudpPacket(); byte[] packetBytes = packet.ToBytes(); if (!PduMarshaler.Unmarshal(packetBytes, eudpPacket, false)) { return; } // ETW Provider Dump Message string messageName = "RDPEUDP:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, DumpLevel_LayerTLS, eudpPacket.GetType().Name, packetBytes); ReceivePacket(eudpPacket); }
/// <summary> /// Used during sending source packet, Add RDPUDP_ACK_OF_ACKVECTOR_HEADER structure into the packet to update OutSnAckOfAcksSeqNum /// </summary> /// <param name="eudpPacket">Packet to be sent</param> private void UpdateOutSnAckOfAcksSeqNum(RdpeudpPacket eudpPacket) { if (newOutSnAckOfAcksSeqNum == null && SendWindowStartPosition - 1 - OutSnAckOfAcksSeqNum > this.SocketConfig.changeSnAckOfAcksSeqNumInterval) { Monitor.Enter(updateAckOfAckLock); if (newOutSnAckOfAcksSeqNum == null && SendWindowStartPosition - 1 - OutSnAckOfAcksSeqNum > this.SocketConfig.changeSnAckOfAcksSeqNumInterval) { newOutSnAckOfAcksSeqNum = SendWindowStartPosition - 1; RDPUDP_ACK_OF_ACKVECTOR_HEADER ackOfAckVector = new RDPUDP_ACK_OF_ACKVECTOR_HEADER(); ackOfAckVector.snAckOfAcksSeqNum = newOutSnAckOfAcksSeqNum.Value; eudpPacket.ackOfAckVector = ackOfAckVector; eudpPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS | eudpPacket.fecHeader.uFlags; seqNumofPacketWithAckOfAckVector = eudpPacket.sourceHeader.Value.snSourceStart; } Monitor.Exit(updateAckOfAckLock); } }
/// <summary> /// Establish Connection /// </summary> /// <param name="timeout"></param> /// <returns></returns> public bool Connect(TimeSpan timeout) { SendSynPacket(); RdpeudpPacket eudpPacket = ExpectSynAndAckPacket(timeout); if (eudpPacket == null) { return(false); } Connected = true; if (!upgradedToRdpedup2) { this.SendAckPacket(); } return(true); }
public RdpeudpPacket ExpectPacket(TimeSpan timeout) { DateTime endtime = DateTime.Now + timeout; while (DateTime.Now < endtime) { lock (unProcessedPacketBuffer) { if (unProcessedPacketBuffer.Count > 0) { RdpeudpPacket eudpPacket = unProcessedPacketBuffer[0]; unProcessedPacketBuffer.RemoveAt(0); return(eudpPacket); } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return(null); }
/// <summary> /// Send SYN Packet to init a RDPEUDP Connection /// </summary> /// <param name="initSequenceNumber">Specify a snInitialSequenceNumber</param> /// <returns></returns> public bool SendSynPacket(uint?initSequenceNumber = null) { if (Connected) { return(false); } RdpeudpPacket SynAndAckPacket = new RdpeudpPacket(); SynAndAckPacket.fecHeader.snSourceAck = UInt32.MaxValue; SynAndAckPacket.fecHeader.uReceiveWindowSize = UReceiveWindowSize; SynAndAckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_SYN; if (this.TransMode == TransportMode.Lossy) { SynAndAckPacket.fecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } 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); }
public bool RetransmitPacket(RdpeudpPacket packet) { if (!connected || packet.sourceHeader == null) { return(false); } if (!outPacketDic.ContainsKey(packet.sourceHeader.Value.snSourceStart)) { return(false); } if (outPacketDic[packet.sourceHeader.Value.snSourceStart].retransmitTimes >= this.SocketConfig.retransmitLimit) { //If a datagram has been retransmitted four times without a response, the sender terminates the connection this.Close(); } RDPUDP_SOURCE_PAYLOAD_HEADER sourceHeader = packet.sourceHeader.Value; Monitor.Enter(sequenceNumberLock); sourceHeader.snCoded = ++CurSnCoded; Monitor.Exit(sequenceNumberLock); packet.sourceHeader = sourceHeader; byte[] data = PduMarshaler.Marshal(packet, false); SendBytesByUDP(data); lock (outPacketDic) // Deal with outPacketDic and retransmit packet. { if (outPacketDic.ContainsKey(packet.sourceHeader.Value.snSourceStart)) { outPacketDic[packet.sourceHeader.Value.snSourceStart].retransmitTimes++; outPacketDic[packet.sourceHeader.Value.snSourceStart].SendTime = DateTime.Now; } } return(true); }
/// <summary> /// Send an ACK Datagrams /// </summary> /// <returns></returns> public bool SendAcKPacket(bool delayACK = false) { if (!connected) { return(false); } RdpeudpPacket AckPacket = new RdpeudpPacket(); AckPacket.fecHeader.snSourceAck = SnSourceAck; AckPacket.fecHeader.uReceiveWindowSize = UReceiveWindowSize; AckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK; if (delayACK) { AckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK | RDPUDP_FLAG.RDPUDP_FLAG_ACKDELAYED; } AckPacket.ackVectorHeader = CreateAckVectorHeader(); SendPacket(AckPacket); return(true); }
/// <summary> /// Expect a SYN Packet which is from specific remoteIP using specific connection mode /// </summary> /// <param name="remoteIP">IP address of remote endpoint</param> /// <param name="mode">connection mode</param> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectSyncPacket(IPAddress remoteIP, TransportMode mode, TimeSpan timeout, out IPEndPoint remoteEndPoint) { remoteEndPoint = null; DateTime endtime = DateTime.Now + timeout; RDPUDP_FLAG expectFlag = RDPUDP_FLAG.RDPUDP_FLAG_SYN; if (mode == TransportMode.Lossy) { expectFlag |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } while (DateTime.Now < endtime) { lock (this.unprocessedPacketBuffer) { for (int i = 0; i < unprocessedPacketBuffer.Count; i++) { StackPacketInfo spInfo = unprocessedPacketBuffer[i]; remoteEndPoint = spInfo.remoteEndpoint as IPEndPoint; if (remoteEndPoint.Address.Equals(remoteIP)) { RdpeudpPacket eudpPacket = new RdpeudpPacket(); if (PduMarshaler.Unmarshal(spInfo.packet.ToBytes(), eudpPacket, false)) { if (eudpPacket.fecHeader.uFlags.HasFlag(expectFlag)) { unprocessedPacketBuffer.RemoveAt(i); return(eudpPacket); } } } } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return(null); }
/// <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, RDPUDP_PROTOCOL_VERSION?version = null) { if (Connected) { return(false); } // Lock the ReceivePacket method if it is transferring to RDPEUDP2 to avoid processing RDPEUDP2 packets with the RDPEUDP logic. lock (receiveLock) { 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.HasValue) { synAndAckPacket.FecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNEX; synAndAckPacket.SynDataEx = CreateSynExData((RDPUDP_PROTOCOL_VERSION)version); } synAndAckPacket.SynData = CreateSynData(initSequenceNumber); SendPacket(synAndAckPacket); // Set the OutSnResetSeqNum value, number from which the receive thread decoding the state of the send packet. OutSnResetSeqNum = synAndAckPacket.SynData.Value.snInitialSequenceNumber + 1; if (version.HasValue && version.Value.HasFlag(RDPUDP_PROTOCOL_VERSION.RDPUDP_PROTOCOL_VERSION_3)) { upgradedToRdpedup2 = true; DisposeTimers(); rdpeudp2Handler = new Rdpeudp2ProtocolHandler(AutoHandle, SendBytesByUdp, Close, ReceiveDataOnHigherLayer); rdpeudp2Handler.SocketConfig.RetransmitDuration = RTT * 2; rdpeudp2Handler.SocketConfig.DelayedAckTimeoutInMs = (int)(RTT.TotalMilliseconds / 2); } } return(true); }
/// <summary> /// Expect an ACK packet /// </summary> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectACKPacket(TimeSpan timeout) { DateTime endtime = DateTime.Now + timeout; while (DateTime.Now < endtime) { lock (unProcessedPacketBuffer) { for (int i = 0; i < unProcessedPacketBuffer.Count; i++) { RdpeudpPacket eudpPacket = unProcessedPacketBuffer[i]; if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK)) { if (!Connected || (eudpPacket.ackVectorHeader.HasValue && eudpPacket.ackVectorHeader.Value.uAckVectorSize > 0)) { unProcessedPacketBuffer.RemoveAt(i); return(eudpPacket); } } } } } return(null); }
/// <summary> /// Expect a Syn Packet /// </summary> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectSynPacket(TimeSpan timeout) { if (Connected) { return(null); } DateTime endtime = DateTime.Now + timeout; while (DateTime.Now < endtime) { lock (unProcessedPacketBuffer) { for (int i = 0; i < unProcessedPacketBuffer.Count; i++) { RdpeudpPacket eudpPacket = unProcessedPacketBuffer[i]; RDPUDP_FLAG expectFlag = RDPUDP_FLAG.RDPUDP_FLAG_SYN; if (this.TransMode == TransportMode.Lossy) { expectFlag |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } if (eudpPacket.fecHeader.uFlags.HasFlag(expectFlag)) { unProcessedPacketBuffer.RemoveAt(i); // Analyse the SYN packet. ProcessSynPacket(eudpPacket); return(eudpPacket); } } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return(null); }
/// <summary> /// Create invalid SYN and ACK Packet /// </summary> /// <param name="udpTransportMode">Transport mode: reliable or lossy</param> /// <param name="invalidType">Invalid type</param> /// <param name="initSequenceNumber">init sequence</param> /// <returns></returns> private RdpeudpPacket CreateInvalidSynAndACKPacket(TransportMode udpTransportMode, SynAndAck_InvalidType invalidType, uint? initSequenceNumber = null) { RdpeudpServerSocket rdpeudpSocket = rdpeudpSocketR; if (udpTransportMode == TransportMode.Lossy) { rdpeudpSocket = rdpeudpSocketL; } // Create the SYN and ACK packet. RdpeudpPacket SynAndAckPacket = new RdpeudpPacket(); SynAndAckPacket.fecHeader.snSourceAck = rdpeudpSocket.SnSourceAck; SynAndAckPacket.fecHeader.uReceiveWindowSize = rdpeudpSocket.UReceiveWindowSize; SynAndAckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_SYN | RDPUDP_FLAG.RDPUDP_FLAG_ACK; RDPUDP_SYNDATA_PAYLOAD SynPayload = rdpeudpSocket.CreateSynData(initSequenceNumber); switch (invalidType) { case SynAndAck_InvalidType.LargerUpStreamMtu: SynPayload.uUpStreamMtu = 1232 + 1; break; case SynAndAck_InvalidType.SamllerUpStreamMtu: SynPayload.uUpStreamMtu = 1132 - 1; break; case SynAndAck_InvalidType.LargerDownStreamMtu: SynPayload.uDownStreamMtu = 1232 + 1; break; case SynAndAck_InvalidType.SamllerDownStreamMtu: SynPayload.uDownStreamMtu = 1132 - 1; break; } SynAndAckPacket.SynData = SynPayload; return SynAndAckPacket; }
/// <summary> /// Send Data from this specified UDP transport /// </summary> /// <param name="data">Data to send</param> /// <returns>Return true if send success</returns> public bool Send(byte[] data) { if (!Connected) return false; List<byte> dataList = new List<byte>(data); int payloadLength = 0; byte[] packetData; RdpeudpPacket packet; do { packet = new RdpeudpPacket(); // Fill in the common header. packet.fecHeader.snSourceAck = SnSourceAck; packet.fecHeader.uReceiveWindowSize = UReceiveWindowSize; packet.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_DATA | RDPUDP_FLAG.RDPUDP_FLAG_ACK; packet.ackVectorHeader = CreateAckVectorHeader(); packet.sourceHeader = CreateSourcePayloadHeader(); // Generate SourceHeader. packetData = PduMarshaler.Marshal(packet, false); // Measure the header lenght to figure out payload length. payloadLength = Math.Min(UUpStreamMtu - packetData.Length, dataList.Count); packet.payload = new byte[payloadLength]; dataList.CopyTo(0, packet.payload, 0, payloadLength); // Copy the data in to packet payload. string str = System.Text.Encoding.ASCII.GetString(packet.payload); SendPacket(packet); dataList.RemoveRange(0, payloadLength); } while (dataList.Count > 0); return true; }
public bool RetransmitPacket(RdpeudpPacket packet) { if (!connected || packet.sourceHeader == null) return false; if (!outPacketDic.ContainsKey(packet.sourceHeader.Value.snSourceStart)) { return false; } if (outPacketDic[packet.sourceHeader.Value.snSourceStart].retransmitTimes >= this.SocketConfig.retransmitLimit) { //If a datagram has been retransmitted four times without a response, the sender terminates the connection this.Close(); } RDPUDP_SOURCE_PAYLOAD_HEADER sourceHeader = packet.sourceHeader.Value; Monitor.Enter(sequenceNumberLock); sourceHeader.snCoded = ++CurSnCoded; Monitor.Exit(sequenceNumberLock); packet.sourceHeader = sourceHeader; byte[] data = PduMarshaler.Marshal(packet, false); SendBytesByUDP(data); lock (outPacketDic) // Deal with outPacketDic and retransmit packet. { if (outPacketDic.ContainsKey(packet.sourceHeader.Value.snSourceStart)) { outPacketDic[packet.sourceHeader.Value.snSourceStart].retransmitTimes++; outPacketDic[packet.sourceHeader.Value.snSourceStart].SendTime = DateTime.Now; } } return true; }
/// <summary> /// Send an ACK Datagrams /// </summary> /// <returns></returns> public bool SendAcKPacket(bool delayACK = false) { if (!connected) return false; RdpeudpPacket AckPacket = new RdpeudpPacket(); AckPacket.fecHeader.snSourceAck = SnSourceAck; AckPacket.fecHeader.uReceiveWindowSize = UReceiveWindowSize; AckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK; if (delayACK) { AckPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK | RDPUDP_FLAG.RDPUDP_FLAG_ACKDELAYED; } AckPacket.ackVectorHeader = CreateAckVectorHeader(); SendPacket(AckPacket); return true; }
public byte[] CreateFECPayload(RdpeudpPacket[] sourcePackets, out byte uFecIndex) { throw new NotImplementedException(); }
/// <summary> /// Used during sending source packet, Add RDPUDP_ACK_OF_ACKVECTOR_HEADER structure into the packet to update OutSnAckOfAcksSeqNum /// </summary> /// <param name="eudpPacket">Packet to be sent</param> private void UpdateOutSnAckOfAcksSeqNum(RdpeudpPacket eudpPacket) { if (newOutSnAckOfAcksSeqNum == null && SendWindowStartPosition - 1 - OutSnAckOfAcksSeqNum > this.SocketConfig.changeSnAckOfAcksSeqNumInterval) { Monitor.Enter(updateAckOfAckLock); if (newOutSnAckOfAcksSeqNum == null && SendWindowStartPosition - 1 - OutSnAckOfAcksSeqNum > this.SocketConfig.changeSnAckOfAcksSeqNumInterval) { newOutSnAckOfAcksSeqNum = SendWindowStartPosition - 1; RDPUDP_ACK_OF_ACKVECTOR_HEADER ackOfAckVector = new RDPUDP_ACK_OF_ACKVECTOR_HEADER(); ackOfAckVector.snAckOfAcksSeqNum = newOutSnAckOfAcksSeqNum.Value; eudpPacket.ackOfAckVector = ackOfAckVector; eudpPacket.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS | eudpPacket.fecHeader.uFlags; seqNumofPacketWithAckOfAckVector = eudpPacket.sourceHeader.Value.snSourceStart; } Monitor.Exit(updateAckOfAckLock); } }
/// <summary> /// Verify an ACK Packet. /// </summary> /// <param name="ackPacket">The ACK packet.</param> private void VerifyACKPacket(RdpeudpPacket ackPacket) { if (ackPacket == null) { this.Site.Assert.Fail("The ACK Packet should not be null!"); } if ((ackPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_ACK) == 0) { this.Site.Assert.Fail("The RDPUDP_FLAG_ACK flag MUST be set in ACK packet!"); } }
/// <summary> /// Method used to process a received packet /// </summary> /// <param name="packet"></param> public void ReceivePacket(RdpeudpPacket eudpPacket) { // Update last receive time, which is used for keep alive timer LastReceiveDiagramTime = DateTime.Now; Monitor.Enter(receiveLock); if (!connected || !AutoHandle) { // If connection haven't been setuped, or Auto handle is false, this packet will not be processed automatically by this method. // It will buffer it for others to use it. lock (unProcessedPacketBuffer) unProcessedPacketBuffer.Add(eudpPacket); } else { // Process the received packet // In case the advised window size updated URemoteAdvisedWindowSize = eudpPacket.fecHeader.uReceiveWindowSize; // this value should update when receiving ACK if congestion algorithm is implemented USendWindowSize = URemoteAdvisedWindowSize; // Process Ack Vector Header if the packet contained ProcessAckVectorHeader(eudpPacket); // Process Source Data if the packet contained ProcessSourceData(eudpPacket); // Process FEC Payload data if the packet contained ProcessFECPayloadData(eudpPacket); // Process RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if the packet contained ProcessAckOfAckVectorHeader(eudpPacket); //TODO: Congestion control function } Monitor.Exit(receiveLock); }
/// <summary> /// Process a Syn Packet /// </summary> /// <param name="eudpPacket"></param> public void ProcessSynPacket(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN) || eudpPacket.fecHeader.uFlags.Equals(RDPUDP_FLAG.RDPUDP_FLAG_SYN | RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY)) // Make sure this packet is a SYN Packet { UDownStreamMtu = (ushort)(Math.Min(Math.Min(eudpPacket.SynData.Value.uUpStreamMtu, UDownStreamMtu), (ushort)1232)); UUpStreamMtu = (ushort)(Math.Min(Math.Min(eudpPacket.SynData.Value.uDownStreamMtu, UUpStreamMtu), (ushort)1232)); USendWindowSize = eudpPacket.fecHeader.uReceiveWindowSize; TransMode = eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) ? TransportMode.Lossy : TransportMode.Reliable; SnSourceAck = eudpPacket.SynData.Value.snInitialSequenceNumber; InSnAckOfAcksSeqNum = eudpPacket.SynData.Value.snInitialSequenceNumber + 1; ReceiveWindowStartPosition = eudpPacket.SynData.Value.snInitialSequenceNumber + 1; } }
/// <summary> /// Process RDPUDP_FEC_PAYLOAD_HEADER Structure and FEC Payload /// </summary> /// <param name="eudpPacket"></param> public void ProcessFECPayloadData(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC)) { // TODO: process FEC payload, calculate lost packet with FEC data // then use UpdateReceiveWindow function to update window and process received data } }
/// <summary> /// Expect a SYN Packet which is from specific remoteIP using specific connection mode /// </summary> /// <param name="remoteIP">IP address of remote endpoint</param> /// <param name="mode">connection mode</param> /// <param name="timeout"></param> /// <returns></returns> public RdpeudpPacket ExpectSyncPacket(IPAddress remoteIP, TransportMode mode, TimeSpan timeout, out IPEndPoint remoteEndPoint) { remoteEndPoint = null; DateTime endtime = DateTime.Now + timeout; RDPUDP_FLAG expectFlag = RDPUDP_FLAG.RDPUDP_FLAG_SYN; if (mode == TransportMode.Lossy) { expectFlag |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } while (DateTime.Now < endtime) { lock (this.unprocessedPacketBuffer) { for (int i = 0; i < unprocessedPacketBuffer.Count; i++) { StackPacketInfo spInfo = unprocessedPacketBuffer[i]; remoteEndPoint = spInfo.remoteEndpoint as IPEndPoint; if (remoteEndPoint.Address.Equals(remoteIP)) { RdpeudpPacket eudpPacket = new RdpeudpPacket(); if (PduMarshaler.Unmarshal(spInfo.packet.ToBytes(), eudpPacket, false)) { if (eudpPacket.fecHeader.uFlags.HasFlag(expectFlag)) { unprocessedPacketBuffer.RemoveAt(i); return eudpPacket; } } } } } // If not receive a Packet, wait a while Thread.Sleep(RdpeudpSocketConfig.ReceivingInterval); } return null; }
/// <summary> /// 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. /// </summary> public void ProcessSynDataExPayload(RdpeudpPacket eudpPacket) { if(eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYNEX) && eudpPacket.SynDataEx != null) { if(eudpPacket.SynDataEx.Value.uUdpVer.HasFlag(uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_2)) { HighestVersion = uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_2; return; } } HighestVersion = uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_1; }
/// <summary> /// Compute the FEC data with the input sources data arrays. /// </summary> /// <param name="sourcePackes">Array of RdpudpPackets used to calculate FEC data</param> /// <param name="uFecIndex">This value is generated by the FEC engine</param> /// <returns>FEC data.</returns> public static byte[] Encode(RdpeudpPacket[] sourcePackes, out byte uFecIndex) { throw new NotImplementedException(); }
public byte[] FECRecover(RdpeudpPacket[] sourcePackets, byte uFecIndex, byte[] fecData, uint targetIndex) { throw new NotImplementedException(); }
/// <summary> /// Send a udp packet. /// </summary> /// <param name="udpTransportMode">Transport mode: reliable or lossy.</param> /// <param name="packet">The packet to send.</param> private void SendPacket(TransportMode udpTransportMode, RdpeudpPacket packet) { RdpeudpSocket rdpeudpSocket = rdpeudpSocketR; if (udpTransportMode == TransportMode.Lossy) { rdpeudpSocket = rdpeudpSocketL; } rdpeudpSocket.SendPacket(packet); }
/// <summary> /// Verify SYN packet. /// </summary> /// <param name="synPacket">The SYN packet.</param> /// <param name="udpTransportMode">Transport mode: reliable or lossy.</param> private void VerifySYNPacket(RdpeudpPacket synPacket, TransportMode udpTransportMode) { if (synPacket == null) { this.Site.Assert.Fail("The SYN Packet should not be null!"); } if (synPacket.fecHeader.snSourceAck != uint.MaxValue) { this.Site.Assert.Fail("The snSourceAck variable MUST be set to -1 (max value of uint)!"); } if((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYN) == 0) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYN flag MUST be set in SYN packet!"); } if (udpTransportMode == TransportMode.Reliable) { if ((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) == RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYNLOSSY flag MUST not be set when choose reliable UDP connection!"); } } else { if ((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) == 0) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYNLOSSY flag MUST be set When choose lossy UDP connection!"); } } if (synPacket.SynData == null) { this.Site.Assert.Fail("The SYN Packet should contain a RDPUDP_SYNDATA_PAYLOAD structure!"); } if (synPacket.SynData.Value.uUpStreamMtu > 1232 || synPacket.SynData.Value.uUpStreamMtu < 1132) { this.Site.Assert.Fail("The uUpStreamMtu field MUST be set to a value in the range of 1132 to 1232."); } if (synPacket.SynData.Value.uDownStreamMtu > 1232 || synPacket.SynData.Value.uDownStreamMtu < 1132) { this.Site.Assert.Fail("The uDownStreamMtu field MUST be set to a value in the range of 1132 to 1232."); } // The RDPUDP_FLAG_SYNEX flag and RDPUDP_SYNDATAEX_PAYLOAD structure should appear at the same time. if ((synPacket.SynDataEx == null) ^ ((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYNEX) == 0)) { this.Site.Assert.Fail("Section 3.1.5.1.1: The RDPUDP_FLAG_SYNEX flag MUST be set only when the RDPUDP_SYNDATAEX_PAYLOAD structure is included. Section 3.1.5.1.1: The RDPUDP_SYNEX_PAYLOAD structure MUST be appended to the UDP datagram if the RDPUDP_FLAG_SYNEX flag is set in uFlags."); } //Section 3.1.5.1.1: Not appending RDPUDP_SYNDATAEX_PAYLOAD structure implies that RDPUDP_PROTOCOL_VERSION_1 is the highest protocol version supported. if (synPacket.SynDataEx == null) { this.clientUUdpVer = uUdpVer_Values.RDPUDP_PROTOCOL_VERSION_1; this.clientRdpudpVerfionInfoValidFlag = null; } else { this.clientUUdpVer = synPacket.SynDataEx.Value.uUdpVer; this.clientRdpudpVerfionInfoValidFlag = synPacket.SynDataEx.Value.uSynExFlags; //Section 3.1.5.1.1: The RDPUDP_VERSION_INFO_VALID flag MUST be set only if the structure contains a valid RDP-UDP protocol version. if (synPacket.SynDataEx.Value.uSynExFlags.HasFlag(uSynExFlags_Values.RDPUDP_VERSION_INFO_VALID) && ((int)synPacket.SynDataEx.Value.uUdpVer & 0xfffc) != 0) { this.Site.Assert.Fail("Section 3.1.5.1.1: The RDPUDP_VERSION_INFO_VALID flag MUST be set only if the structure contains a valid RDP-UDP protocol version"); } } }
/// <summary> /// Method used to process a received packet /// </summary> /// <param name="packet"></param> public void ReceivePacket(StackPacket packet) { // Transfer packet to RdpeudpPacket eudpPacket = new RdpeudpPacket(); byte[] packetBytes = packet.ToBytes(); if (!PduMarshaler.Unmarshal(packetBytes, eudpPacket, false)) { return; } // ETW Provider Dump Message string messageName = "RDPEUDP:ReceivedPDU"; ExtendedLogger.DumpMessage(messageName, DumpLevel_LayerTLS, eudpPacket.GetType().Name, packetBytes); ReceivePacket(eudpPacket); }
/// <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> /// Process Source payload if the packet has source payload data /// </summary> /// <param name="eudpPacket"></param> public void ProcessSourceData(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_DATA) && !eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC)) { lock (inPacketDic) { if(IsInReceiveWindow(eudpPacket.sourceHeader.Value.snSourceStart)) { SnSourceAck = Math.Max(SnSourceAck, eudpPacket.sourceHeader.Value.snSourceStart); InPacketState inPacketState = new InPacketState(); inPacketState.Packet = eudpPacket; inPacketDic[eudpPacket.sourceHeader.Value.snSourceStart] = inPacketState; UpdateReceiveWindow(); } // Increase received source packet numbers not be ack if (sourceNumNotAcked == 0) { ReceiveTimeForFirstNotACKSource = DateTime.Now; } sourceNumNotAcked++; } // Send ACK diagram if necessary. AckPacketReceived(); } }
/// <summary> /// Send a RDPEUDP Packet /// </summary> /// <param name="packet"></param> /// <returns></returns> public bool SendPacket(RdpeudpPacket packet) { if (packet.sourceHeader.HasValue && AutoHandle) { // Deal with window area. OutPacketState packetState = new OutPacketState(); packetState.Packet = packet; packetState.Acknowledged = false; DateTime endTime = DateTime.Now + this.SocketConfig.Timeout; uint sendWindowsEndPos = SendWindowStartPosition + USendWindowSize; while (DateTime.Now < endTime) { //If source sequence number is in send slide window, send the packet. Otherwise, wait a sendingInterval if (!IsInSendWindow(packet.sourceHeader.Value.snSourceStart)) { sendWindowLock.WaitOne(this.SocketConfig.sendingInterval); } else { break; } } if (DateTime.Now > endTime) { // Time out. return false; } packetState.SendTime = DateTime.Now; lock (outPacketDic) outPacketDic[packet.sourceHeader.Value.snSourceStart] = packetState; // Add RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if necessary UpdateOutSnAckOfAcksSeqNum(packet); } byte[] data = PduMarshaler.Marshal(packet, false); SendBytesByUDP(data); // Update Last send time, which is used for keep alive timer LastSendDiagramTime = DateTime.Now; return true; }
/// <summary> /// Process RDPUDP_ACK_VECTOR_HEADER if the packet contains a RDPUDP_ACK_VECTOR_HEADER /// </summary> /// <param name="eudpPacket"></param> private void ProcessAckVectorHeader(RdpeudpPacket eudpPacket) { // Update OutSnAckOfAcksSeqNum if necessary UpdateOutSnAckOfAcksSeqNum(eudpPacket.fecHeader.snSourceAck); if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK) && !eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN)) { //Contains ack, analyze ack value, update outPacketDic, caculate RTT, and move send window if (eudpPacket.ackVectorHeader.Value.uAckVectorSize > 0) // Deal with ack vector. { uint currentposition = OutSnAckOfAcksSeqNum; lock (outPacketDic) { foreach (AckVector AckVectorElement in eudpPacket.ackVectorHeader.Value.AckVectorElement) { if (AckVectorElement.State == VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED) { // update outPacketDic only if this vector element is to ack received for (byte i = 0; i < AckVectorElement.Length + 1; i++, currentposition++) { if (outPacketDic.ContainsKey(currentposition)) { outPacketDic[currentposition].Acknowledged = true; } } } else { currentposition = currentposition + AckVectorElement.Length + 1; } } // If this packet is not a delay ack, calculate RTT, only the last acknowleged source packet is used to caculate RTT if (outPacketDic.ContainsKey(currentposition - 1)) { if (!eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACKDELAYED) && !outPacketDic[currentposition - 1].estimatedRTT) // Also make sure this packet has not been used to estimate RTT. If the packet has been used to estimated RTT, this packet may be a resent ACK for keep alive { RTT = new TimeSpan(RTT.Ticks / 8 * 7 + (DateTime.Now - outPacketDic[currentposition - 1].SendTime).Ticks / 8); // Count the RTT. outPacketDic[currentposition - 1].estimatedRTT = true; } } // Update send window, this method will update outPacketDic UpdateSendWindow(); } sendWindowLock.Set(); } } }
/// <summary> /// Verify SYN packet. /// </summary> /// <param name="synPacket">The SYN packet.</param> /// <param name="udpTransportMode">Transport mode: reliable or lossy.</param> private void VerifySYNPacket(RdpeudpPacket synPacket, TransportMode udpTransportMode) { if (synPacket == null) { this.Site.Assert.Fail("The SYN Packet should not be null!"); } if (synPacket.fecHeader.snSourceAck != uint.MaxValue) { this.Site.Assert.Fail("The snSourceAck variable MUST be set to -1 (max value of uint)!"); } if((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYN) == 0) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYN flag MUST be set in SYN packet!"); } if (udpTransportMode == TransportMode.Reliable) { if ((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) == RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYNLOSSY flag MUST not be set when choose reliable UDP connection!"); } } else { if ((synPacket.fecHeader.uFlags & RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY) == 0) { this.Site.Assert.Fail("The RDPUDP_FLAG_SYNLOSSY flag MUST be set When choose lossy UDP connection!"); } } if (synPacket.SynData == null) { this.Site.Assert.Fail("The SYN Packet should contain a RDPUDP_SYNDATA_PAYLOAD structure!"); } if (synPacket.SynData.Value.uUpStreamMtu > 1232 || synPacket.SynData.Value.uUpStreamMtu < 1132) { this.Site.Assert.Fail("The uUpStreamMtu field MUST be set to a value in the range of 1132 to 1232."); } if (synPacket.SynData.Value.uDownStreamMtu > 1232 || synPacket.SynData.Value.uDownStreamMtu < 1132) { this.Site.Assert.Fail("The uDownStreamMtu field MUST be set to a value in the range of 1132 to 1232."); } }
/// <summary> /// Compute the source data in the specified index. /// </summary> /// <param name="sourcePackes">Array of RdpudpPackets received.</param> /// <param name="uFecIndex">Generated by the FEC engine when encoding</param> /// <param name="fecData">Fec data</param> /// <param name="targetIdx">The index in which the data to be decoded.</param> /// <returns>The target source data.</returns> public static byte[] Decode(RdpeudpPacket[] sourcePackets, byte uFecIndex, byte[] fecData, uint targetIdx) { throw new NotImplementedException(); }
/// <summary> /// Create Source Packet from byte data /// </summary> /// <param name="data"></param> /// <returns></returns> public RdpeudpPacket CreateSourcePacket(byte[] data) { if (data == null || data.Length == 0) { return null; } RdpeudpPacket packet = new RdpeudpPacket(); // Fill in the common header. packet.fecHeader.snSourceAck = SnSourceAck; packet.fecHeader.uReceiveWindowSize = UReceiveWindowSize; packet.fecHeader.uFlags = RDPUDP_FLAG.RDPUDP_FLAG_DATA | RDPUDP_FLAG.RDPUDP_FLAG_ACK; packet.ackVectorHeader = CreateAckVectorHeader(); packet.sourceHeader = CreateSourcePayloadHeader(); packet.payload = data; return packet; }
/// <summary> /// Send SYN Packet to init a RDPEUDP Connection /// </summary> /// <param name="initSequenceNumber">Specify a snInitialSequenceNumber</param> /// <returns></returns> public bool SendSynPacket(uint? initSequenceNumber = 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; if (this.TransMode == TransportMode.Lossy) { SynAndAckPacket.fecHeader.uFlags |= RDPUDP_FLAG.RDPUDP_FLAG_SYNLOSSY; } 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> /// Process RDPUDP_ACK_OF_ACKVECTOR_HEADER Structure if the packet have /// </summary> /// <param name="eudpPacket"></param> public void ProcessAckOfAckVectorHeader(RdpeudpPacket eudpPacket) { if (eudpPacket.fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS)) { InSnAckOfAcksSeqNum = eudpPacket.ackOfAckVector.Value.snAckOfAcksSeqNum; } }