internal RUDPSocketError BeginConnect(RUDPSocket rudp, int timeOut) { //---- Add it to our list of "connected" sockets RegisterConnectedSocket(rudp); return(RUDPStack.BeginConnect(rudp, timeOut)); }
internal void Dispose() { _receiveBuffer = null; _connectedRDUPs.Clear(); _acceptingRDUP = null; _socket = null; }
internal PMTUDiscovery(RUDPSocket rudp) { _rudp = rudp; // Start with minimum MTU to insure correct communication _rudp._mtu = MinMTU; }
internal RUDPSocket OnEndAccept(IPEndPoint remoteEndPoint, int packetId) { // Create the new socket RUDPSocket acceptSocket = new RUDPSocket(); acceptSocket._physical = this; acceptSocket._status = RUDPSocketStatus.Connected; acceptSocket._remoteEndPoint = remoteEndPoint; acceptSocket._incomingPackets.CurrentPacketId = packetId; // Add it to our list of "connected" sockets RUDPStack.RegisterRUDPSocket(acceptSocket); RegisterConnectedSocket(acceptSocket); // Release it RUDPSocket previousAcceptingRDUP = _acceptingRDUP; _acceptingRDUPLock.EnterWriteLock(); _acceptingRDUP = null; _acceptingRDUPLock.ExitWriteLock(); // End the accept previousAcceptingRDUP.OnEndAccept(acceptSocket); return(acceptSocket); }
internal long TSReceived; // Time Stamp : when message is received internal RUDPIngoingPacket(RUDPSocket rudp, int packetId, byte[] payload, RUDPPacketChannel channel, long tsReceived) { RUDP = rudp; PacketId = packetId; Channel = channel; Payload = payload; TSReceived = tsReceived; }
internal FragmentInformation(RUDPSocket rudpSocket, bool isReliable, byte[] payload, int offset, int size, RUDPSendIAsyncResult asyncResult) { rudp = rudpSocket; IsReliable = isReliable; Offset = offset; Size = size; Payload = payload; AsyncResult = asyncResult; }
internal void BeginAccept(RUDPSocket rudp, AsyncCallback callback, Object state) { rudp._status = RUDPSocketStatus.Accepting; //---- Only one socket accept on this port _acceptingRDUPLock.EnterWriteLock(); _acceptingRDUP = rudp; _acceptingRDUPLock.ExitWriteLock(); //---- Unregister for the stack RUDPStack.BeginAccept(rudp); }
internal void OnEndAccept(RUDPSocket acceptedSocket) { RUDPAcceptIAsyncResult result = null; Interlocked.Exchange <RUDPAcceptIAsyncResult>(ref result, _asyncResultAccept); if (result == null) { return; } Interlocked.Exchange <RUDPAcceptIAsyncResult>(ref _asyncResultAccept, null); result.AcceptedSocket = acceptedSocket; result.ForceAsyncCall = true; result.SetAsCompleted(RUDPSocketError.Success, false); }
public IAsyncResult BeginAccept(AsyncCallback callback, Object state) { RUDPAcceptIAsyncResult asyncResult = new RUDPAcceptIAsyncResult(this, callback, state); Interlocked.Exchange <RUDPAcceptIAsyncResult>(ref _asyncResultAccept, asyncResult); //---- Check if we do not already have a socket if (_acceptedRUDPSockets.Count > 0) { RUDPSocket rudp = _acceptedRUDPSockets[0]; lock (_acceptedRUDPSockets) _acceptedRUDPSockets.RemoveAt(0); OnEndAccept(rudp); } else { //-- Request an accept _physical.BeginAccept(this, callback, state); } return(asyncResult); }
internal static void Shutdown(RUDPSocket rudp) { if (rudp._status == RUDPSocketStatus.Accepting) { rudp.Reset(RUDPSocketStatus.Closed); return; } if (rudp._status == RUDPSocketStatus.Closed || rudp._isShutingDown) return; if (rudp._status == RUDPSocketStatus.Closing || rudp._status == RUDPSocketStatus.ClosingACKed) return; if (rudp._status == RUDPSocketStatus.Connecting) { rudp.Reset(RUDPSocketStatus.Closed); return; } //---- Send the tear down message //-- Update the status rudp._isShutingDown = true; rudp._status = RUDPSocketStatus.Closing; //-- Wait for sending while (!rudp._controlWindow.CanSend(0)) { if (rudp._status != RUDPSocketStatus.Closing) return; Thread.Sleep(100); } //-- Send the tear down message PushPacketToSend(rudp, true, RUDPPacketChannel.TearDown, null, 0, 0); //---- Currently closing the connection, wait for the end of the operation long startTime = HiResTimer.MicroSeconds; //-- Wait until closed // Wait until "ClosingACKed" // Wait until we have receive the "TearDown" message too and send the ACK // Wait until "Time out" while (rudp._status == RUDPSocketStatus.Closing && rudp._outgoingPackets.Count > 0 && (HiResTimer.MicroSeconds - startTime) < rudp._sto) { Thread.Sleep(100); } //---- Set the status as closed rudp.Reset(RUDPSocketStatus.Closed); //---- Notify rudp._physical.OnDisconnected(rudp, RUDPSocketError.Shutdown); }
/// <summary> /// Close the socket. Send the tear down message. /// </summary> internal static void Close(RUDPSocket rudp) { if (rudp._status == RUDPSocketStatus.Closed) return; if (rudp._status == RUDPSocketStatus.Accepting) { rudp.Reset(RUDPSocketStatus.Closed); return; } AsyncShutdown(rudp); }
internal static RUDPSocketError BeginConnect(RUDPSocket rudp, int timeOut) { Trace("Connecting to :" + rudp._remoteEndPoint); if (rudp._status == RUDPSocketStatus.Connected) return RUDPSocketError.IsConnected; if (rudp._status == RUDPSocketStatus.Connecting) return RUDPSocketError.AlreadyInProgress; //---- Set the status rudp.Reset(RUDPSocketStatus.Connecting); //---- Register for the stack RUDPStack.RegisterRUDPSocket(rudp); //---- Send a ping if (rudp.IsRendezVousMode) PushPacketToSend(rudp, true, RUDPPacketChannel.PingRendezVous, null, 0, 0); else PushPacketToSend(rudp, true, RUDPPacketChannel.Ping, null, 0, 0); return RUDPSocketError.Success; }
internal static void RegisterRUDPSocket(RUDPSocket rudp) { int controlThreadId = -1; int count = Int32.MaxValue; for (int index = 0; index < _controlThreadInformations.Length; index++) if (_controlThreadInformations[index]._rudpSockets.Count < count) { controlThreadId = index; count = _controlThreadInformations[index]._rudpSockets.Count; } // Register the socket rudp._controlThreadId = controlThreadId; _controlThreadInformations[controlThreadId]._rudpSocketsLock.EnterWriteLock(); if (!_controlThreadInformations[controlThreadId]._rudpSockets.Contains(rudp)) _controlThreadInformations[controlThreadId]._rudpSockets.Add(rudp); _controlThreadInformations[controlThreadId]._rudpSocketsLock.ExitWriteLock(); }
/// <summary> /// Called when we have an error on a socket. /// </summary> static internal void OnSocketUnhandledError(RUDPSocket rudp, RUDPSocketError error, RUDPSendIAsyncResult sendAsyncResult) { //---- Disconnect the socket OnDisconnected(rudp, DisconnectionReason.SocketError); //---- Handle the error and forward it to the socket if (rudp._status == RUDPSocketStatus.Connecting) rudp.OnEndConnect(error); else { // On Send Error if (sendAsyncResult != null) rudp.OnEndSend(error, sendAsyncResult); // ELSE ... HOW TO GET sendAsyncResult when NULL ????? // On Receive Error RUDPReceiveIAsyncResult receiveAsyncResult = null; Interlocked.Exchange<RUDPReceiveIAsyncResult>(ref receiveAsyncResult, rudp._asyncResultReceive); if (receiveAsyncResult != null) { Interlocked.Exchange<RUDPReceiveIAsyncResult>(ref rudp._asyncResultReceive, null); rudp.OnEndReceive(error, null, true, receiveAsyncResult); } } }
private static void KeepAliveTimer(RUDPSocket rudp, long now) { long lastSendTS = Math.Max(rudp._lastSendTS, rudp._lastACKSendTS); //---- Send a keep alive (if possible) if (rudp._status == RUDPSocketStatus.Connected && (now - lastSendTS) > RUDPStack.KeepAliveInterval && rudp._controlWindow.CanSend(0)) { PushPacketToSend(rudp, true, RUDPPacketChannel.KeepAlive, new byte[0], 0, 0); } }
internal void OnEndSend(RUDPSocket rudp, RUDPSendIAsyncResult asyncResult) { rudp.OnEndSend(RUDPSocketError.Success, asyncResult); }
internal void Close(RUDPSocket rudp) { RUDPStack.Close(rudp); }
internal RUDPSocketNetworkInformation(RUDPSocket rudp) { _rudp = rudp; }
internal void Shutdown(RUDPSocket rudp) { RUDPStack.Shutdown(rudp); }
internal RUDPSendIAsyncResult(RUDPSocket rudp, AsyncCallback callback, Object state, int size) : base(rudp, callback, state) { _size = size; }
internal static bool PushPacketToSend(RUDPSocket rudp, bool reliablePacket, RUDPPacketChannel channel, byte[] payload, int offset, int payloadLength) { int packetId = -1; if (reliablePacket) packetId = Interlocked.Increment(ref rudp._ougoingPacketId); //---- Get the SACKs SACKSlot slot1 = null; SACKSlot slot2 = null; SACKSlot slot3 = null; SACKSlot slot4 = null; rudp._sackWindow.GetSLACKSlots(out slot1, out slot2, out slot3, out slot4); //---- Copy the payload to send byte[] rudpPayload = MakePacketPayload(rudp, packetId, channel, slot1, slot2, slot3, slot4, payload, offset, payloadLength); //---- Create a packet RUDPOutgoingPacket packet = NewOutgoingPacket(packetId, rudp._sequence, rudpPayload, channel); packet.CurrentCwnd = rudp._controlWindow.CWND; if (reliablePacket) { //---- Notify the control window rudp._controlWindow.OnSend(packetId, rudp._sequence, payloadLength); //---- Increment sequence number Interlocked.Exchange(ref rudp._sequence, rudp._sequence + payloadLength); } //---- In the "resend list" if (reliablePacket) { rudp._outgoingPacketsLock.EnterWriteLock(); rudp._outgoingPackets.Add(packet); rudp._outgoingPacketsLock.ExitWriteLock(); } //---- Send the packet packet.TSFirstSend = HiResTimer.MicroSeconds; if (!SocketSendPacket(rudp, packet, packet.Payload, packet.TSFirstSend)) { // Nothing to do... socket is closed and reseted ! return false; } return true; }
internal AbstractWindow(RUDPSocket rudp) { _rudp = rudp; }
private static bool SocketSendACK(RUDPSocket rudp, PhysicalSocket physical, IPEndPoint remoteEndPoint, byte[] rudpPayload) { try { physical._socket.SendTo(rudpPayload, remoteEndPoint); //physical._socket.BeginSendTo(rudpPayload, 0, rudpPayload.Length, SocketFlags.None, rudp._remoteEndPoint, null, null); } catch (SocketException exception) { if (rudp != null) OnSocketUnhandledError(rudp, SocketErrorToRUDPSocketError(exception.SocketErrorCode), null); return false; } if (rudp != null) rudp._lastACKSendTS = HiResTimer.MicroSeconds; return true; }
internal void UnregisterConnectedSocket(RUDPSocket rudp) { _connectedRDUPsLock.EnterWriteLock(); _connectedRDUPs.Remove(rudp._remoteEndPoint); _connectedRDUPsLock.ExitWriteLock(); }
internal RUDPAsyncResult(RUDPSocket rudp, AsyncCallback callback, Object state) { _rudp = rudp; _asyncCallback = callback; _asyncState = state; }
private static void BandwidthTimer(RUDPSocket rudp, long now) { //---- Send 2 packets if (rudp._status == RUDPSocketStatus.Connected && (now - rudp._lastBandwidthTS) > RUDPStack.BandwidthInterval) { // Too small packet size can lead to overestimation byte[] fullMSSPacket = new byte[rudp._mtu - UDPHeaderLength - RUDPHeaderLength]; BinaryHelper.WriteLong(now, fullMSSPacket, 0); PushPacketToSend(rudp, false, RUDPPacketChannel.Bandwidth01, fullMSSPacket, 0, fullMSSPacket.Length); PushPacketToSend(rudp, false, RUDPPacketChannel.Bandwidth02, fullMSSPacket, 0, fullMSSPacket.Length); rudp._lastBandwidthTS = now; } }
internal static FragmentInformation NewFragmentInformation(RUDPSocket rudpSocket, bool isReliable, byte[] payload, int offset, int size, RUDPSendIAsyncResult asyncResult) { //return new FragmentInformation(rudpSocket, isReliable, payload, offset, size, asyncResult); FragmentInformation fragment; if (!_fragmentsPools.TryDequeue(out fragment)) { for (int index = 0; index < 100; index++) _fragmentsPools.Enqueue(new FragmentInformation(null, false, null, -1, -1, null)); return new FragmentInformation(rudpSocket, isReliable, payload, offset, size, asyncResult); } fragment.rudp = rudpSocket; fragment.IsReliable = isReliable; fragment.Offset = offset; fragment.Size = size; fragment.Payload = payload; fragment.AsyncResult = asyncResult; return fragment; }
internal RUDPSocketError BeginConnect(RUDPSocket rudp, int timeOut) { //---- Add it to our list of "connected" sockets RegisterConnectedSocket(rudp); return RUDPStack.BeginConnect(rudp, timeOut); }
internal static void UnregisterRUDPSocket(RUDPSocket rudp) { if (rudp._controlThreadId > -1) { int controlThreadId = rudp._controlThreadId; _controlThreadInformations[controlThreadId]._rudpSocketsLock.EnterWriteLock(); _controlThreadInformations[controlThreadId]._rudpSockets.Remove(rudp); rudp._controlThreadId = -1; _controlThreadInformations[controlThreadId]._rudpSocketsLock.ExitWriteLock(); } }
internal void RegisterConnectedSocket(RUDPSocket rudp) { _connectedRDUPsLock.EnterWriteLock(); _connectedRDUPs.Add(rudp._remoteEndPoint, rudp); _connectedRDUPsLock.ExitWriteLock(); }
internal static bool BeginAccept(RUDPSocket rudp) { Trace("Accepting at :" + rudp._remoteEndPoint); if (rudp._status != RUDPSocketStatus.Accepting) return false; //---- Register for the stack RUDPStack.RegisterRUDPSocket(rudp); return true; }
internal void OnDisconnected(RUDPSocket rudp, RUDPSocketError error) { UnregisterConnectedSocket(rudp); rudp.OnDisconnected(error); }
private static void AsyncShutdown(RUDPSocket rudp) { ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncShutdownCB), rudp); }
internal static void OnDisconnected(RUDPSocket rudp, DisconnectionReason reason) { if (rudp._status == RUDPSocketStatus.Closed) return; //---- Reset rudp._outgoingPacketsLock.EnterWriteLock(); rudp._outgoingPackets.Clear(); rudp._outgoingPacketsLock.ExitWriteLock(); rudp.Reset(RUDPSocketStatus.Closed); //---- Notify if (reason != DisconnectionReason.ConnectionClosed) { RUDPSocketError error = RUDPSocketError.ConnectionReset; if (reason == DisconnectionReason.SocketError) error = RUDPSocketError.SocketError; if (reason == DisconnectionReason.TimeOut) error = RUDPSocketError.ConnectionReset; rudp._physical.OnDisconnected(rudp, error); } }
internal static RUDPSocketError SendPayload(RUDPSocket rudp, byte[] payload, int offset, int payloadLength, bool reliable, RUDPSendIAsyncResult asyncResult) { // We are no longer active if (!_isStackRunning) return RUDPSocketError.SystemNotReady; //---- Only when connected if (rudp._status != RUDPSocketStatus.Connected) return RUDPSocketError.NotConnected; //---- Fragmentation asyncResult.ForceAsyncCall = true; FragmentInformation fragments = NewFragmentInformation(rudp, reliable, payload, offset, payloadLength, asyncResult); //----- Async send rudp._fragmentsLock.EnterWriteLock(); rudp._fragments.AddFirst(fragments); rudp._fragmentsLock.ExitWriteLock(); ForceFragmentsSending(rudp._controlThreadId); //---- If possible send Sync... otherwise relate to control thread /* if (!SendFragments(fragments)) { rudp._fragmentsLock.EnterWriteLock(); rudp._fragments.AddFirst(fragments); rudp._fragmentsLock.ExitWriteLock(); _protocolControlEvent.Set(); } */ //---- Synchrone send /* while (!SendFragments(fragments)) fragments.rudp._controlWindow.WaitObject.WaitOne(); */ return fragments.Error; }
private static bool TransmissionTimer(RUDPSocket rudp, ControlThreadInformation controlInformation) { if (rudp._fragments.Count < 1) return true; rudp._fragmentsLock.EnterReadLock(); FragmentInformation fragments = rudp._fragments.Last.Value; rudp._fragmentsLock.ExitReadLock(); if (SendFragments(fragments, controlInformation)) { rudp._fragmentsLock.EnterWriteLock(); rudp._fragments.RemoveLast(); rudp._fragmentsLock.ExitWriteLock(); ReleaseFragmentInformation(fragments); return true; } // Else continue for other socket // will try to send packet during next loop ForceFragmentsSending(controlInformation.ControlThreadId); return false; }
/// <summary> /// Create the RUDP packet : HEADER + payload /// </summary> internal static byte[] MakePacketPayload(RUDPSocket rudp, int packetId, RUDPPacketChannel channel, SACKSlot slot1, SACKSlot slot2, SACKSlot slot3, SACKSlot slot4, byte[] payload, int offset, int payloadLength) { //---- Here we make the payload while we will send: /** * We create a header * The format is: * -------------- * - 1 byte : protocol version * - 1 byte : header information * - 1 byte : channel * - 4 bytes : message ID * - 4 bytes : advertized congestion window size * - 4 bytes : payloadLength * - 4 X (4 + 4) : 32 bytes for 4 SACK slots * - the payload bytes */ int headerOffset = 0; byte[] packetPayload = PayloadManager.Allocate(channel, RUDPHeaderLength + payloadLength); //---- Protocol version packetPayload[headerOffset] = (byte)1; headerOffset++; //---- Header information // 3 bits : number of ACK slots // sack slot (3 bits) byte sacksSlotCount = 0; if (slot1 != null) sacksSlotCount++; if (slot2 != null) sacksSlotCount++; if (slot3 != null) sacksSlotCount++; if (slot4 != null) sacksSlotCount++; packetPayload[headerOffset] = 0; // Reset (Because buffer reused) packetPayload[headerOffset] |= sacksSlotCount; headerOffset++; //---- Channel packetPayload[headerOffset] = (byte)channel; headerOffset++; //---- Message Id BinaryHelper.WriteInt(packetId, packetPayload, headerOffset); headerOffset += 4; //---- Control information : Advertised window if (rudp == null) BinaryHelper.WriteInt(-1, packetPayload, headerOffset); else BinaryHelper.WriteInt((int)rudp._controlWindow.AdvertisedWindow, packetPayload, headerOffset); headerOffset += 4; //---- Payload length BinaryHelper.WriteInt(payloadLength, packetPayload, headerOffset); headerOffset += 4; //---- SACK Slots if (slot1 != null) { BinaryHelper.WriteInt(slot1.StartPacketId, packetPayload, headerOffset); headerOffset += 4; BinaryHelper.WriteInt(slot1.EndPacketId, packetPayload, headerOffset); headerOffset += 4; } else { // Reset (Because buffer reused) Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8); headerOffset += 8; } if (slot2 != null) { BinaryHelper.WriteInt(slot2.StartPacketId, packetPayload, headerOffset); headerOffset += 4; BinaryHelper.WriteInt(slot2.EndPacketId, packetPayload, headerOffset); headerOffset += 4; } else { // Reset (Because buffer reused) Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8); headerOffset += 8; } if (slot3 != null) { BinaryHelper.WriteInt(slot3.StartPacketId, packetPayload, headerOffset); headerOffset += 4; BinaryHelper.WriteInt(slot3.EndPacketId, packetPayload, headerOffset); headerOffset += 4; } else { // Reset (Because buffer reused) Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8); headerOffset += 8; } if (slot4 != null) { BinaryHelper.WriteInt(slot4.StartPacketId, packetPayload, headerOffset); headerOffset += 4; BinaryHelper.WriteInt(slot4.EndPacketId, packetPayload, headerOffset); headerOffset += 4; } else { // Reset (Because buffer reused) Buffer.BlockCopy(Clean8Bytes, 0, packetPayload, headerOffset, 8); headerOffset += 8; } if (payload == null) return packetPayload; //---- Payload Buffer.BlockCopy(payload, offset, packetPayload, headerOffset, payloadLength); return packetPayload; }
private static bool RetransmissionTimer(RUDPSocket rudp, long now, ControlThreadInformation controlInformation) { int count = rudp._outgoingPackets.Count; bool hasDoFastRetransmit = false; controlInformation._chargeCheckStopWatch.Reset(); controlInformation._chargeCheckStopWatch.Start(); for (int index = 0; index < count; index++) { rudp._outgoingPacketsLock.EnterReadLock(); RUDPOutgoingPacket packet = rudp._outgoingPackets[index]; rudp._outgoingPacketsLock.ExitReadLock(); //---- Not yet sended if (packet.TSLastSend < 0) continue; //---- It is ACKed if (packet.IsACKed) { rudp._outgoingPacketsLock.EnterWriteLock(); rudp._outgoingPackets.RemoveAt(index); rudp._outgoingPacketsLock.ExitWriteLock(); ReleaseOutgoingPacket(packet); index--; count--; continue; } //---- Check for time out if (packet.TSFirstSend > -1 && (now - packet.TSFirstSend) > rudp._sto) { //-- Normal time out // Send connection Reset with ACK OnDisconnected(rudp, DisconnectionReason.TimeOut); return true; } //---- Retransmission or not ? bool fastRetransmit = (packet.PacketId >= rudp._fastRetransmitStartPacketId && packet.PacketId <= rudp._fastRetransmitEndPacketId); if (!fastRetransmit && (now - packet.TSLastSend) < rudp._rto) continue; hasDoFastRetransmit = hasDoFastRetransmit | fastRetransmit; //---- Get the SACK slots to send with SACKSlot slot1 = null, slot2 = null, slot3 = null, slot4 = null; rudp._sackWindow.GetSLACKSlots(out slot1, out slot2, out slot3, out slot4); // Update the payload for the SACK slots UpdatePacketPayload(packet.Payload, slot1, slot2, slot3, slot4); #if CONSOLE_TRACE string acksList = ""; if (slot1 != null) acksList += " [" + slot1.StartPacketId + " <-> " + slot1.EndPacketId + "]"; if (slot2 != null) acksList += " [" + slot2.StartPacketId + " <-> " + slot2.EndPacketId + "]"; if (slot3 != null) acksList += " [" + slot3.StartPacketId + " <-> " + slot3.EndPacketId + "]"; if (slot4 != null) acksList += " [" + slot4.StartPacketId + " <-> " + slot4.EndPacketId + "]"; #endif // Send #if CONSOLE_TRACE Trace("Resend packet(" + rudp.Handle + "): " + packet.PacketId + " RTO=" + rudp._rto + "RTT=" + rudp._rtt + " ACKs:" + acksList); #endif if (SocketSendPacket(rudp, packet, packet.Payload, now)) { rudp._controlWindow.OnTimeOut(packet); // Update packet.Retransmission++; } if (controlInformation._chargeCheckStopWatch.ElapsedMilliseconds > 0) return false; } //---- Reset fast retransmit if (hasDoFastRetransmit) rudp.OnEndFastRetransmit(); return true; }
private static bool SocketSendPacket(RUDPSocket rudp, RUDPOutgoingPacket packet, byte[] rudpPayload, long now) { //---- Send the request try { rudp._physical._socket.SendTo(rudpPayload, rudp._remoteEndPoint); //rudp._physical._socket.BeginSendTo(rudpPayload, 0, rudpPayload.Length, SocketFlags.None, rudp._remoteEndPoint, null, null); } catch (SocketException exception) { if (exception.ErrorCode == (int)SocketError.MessageSize && packet.Channel == RUDPPacketChannel.MTUTuning) { // ICMP type 3 subtype 4 // ICMP message, tell that this packet is too big rudp._pmtuDiscovery.OnICMPError(packet); return true; } OnSocketUnhandledError(rudp, SocketErrorToRUDPSocketError(exception.SocketErrorCode), null); return false; } rudp._lastSendTS = now; packet.TSLastSend = now; return true; }
private static void ACKTimer(RUDPSocket rudp, long now) { int acksCount = rudp._sackWindow.ACKCount; if (acksCount < 1) return; //now = HiResTimer.MicroSeconds; //---- Delayed ACKs if (acksCount < 2) if (rudp._lastACKSendTS > -1 && (now - rudp._lastACKSendTS) < DelayACKTime) return; /* bool sendACKDueToTimeOut = (acksCount < 2 && rudp._lastACKSendTS > -1 && (now - rudp._lastACKSendTS) >= DelayACKTime); long delayedACKTS = 0; if (sendACKDueToTimeOut) { delayedACKTS = now - rudp._lastACKSendTS; } */ rudp._lastACKSendTS = HiResTimer.MicroSeconds; //---- Prepare the SACKs list List<SACKSlot> sackSlots = rudp._sackWindow.PrepareACKList(); for (int index = 0; index < sackSlots.Count; index++) { //---- Get the SACK slots to send with SACKSlot slot1 = null, slot2 = null, slot3 = null, slot4 = null; if (sackSlots.Count > 0) { slot1 = sackSlots[0]; sackSlots.RemoveAt(0); } if (sackSlots.Count > 0) { slot2 = sackSlots[0]; sackSlots.RemoveAt(0); } if (sackSlots.Count > 0) { slot3 = sackSlots[0]; sackSlots.RemoveAt(0); } if (sackSlots.Count > 0) { slot4 = sackSlots[0]; sackSlots.RemoveAt(0); } #if CONSOLE_TRACE if (slot1 != null) Trace("Send ACK(" + rudp.Handle + "): " + slot1.StartPacketId + " <-> " + slot1.EndPacketId); if (slot2 != null) Trace("Send ACK(" + rudp.Handle + "): " + slot2.StartPacketId + " <-> " + slot2.EndPacketId); if (slot3 != null) Trace("Send ACK(" + rudp.Handle + "): " + slot3.StartPacketId + " <-> " + slot3.EndPacketId); if (slot4 != null) Trace("Send ACK(" + rudp.Handle + "): " + slot4.StartPacketId + " <-> " + slot4.EndPacketId); #endif byte[] packetPayload = MakePacketPayload(rudp, -1, RUDPPacketChannel.ACK, slot1, slot2, slot3, slot4, null, 0, 0); SocketSendACK(rudp, rudp._physical, rudp._remoteEndPoint, packetPayload); PayloadManager.Deallocate(RUDPPacketChannel.ACK, packetPayload); } }
private static void HandleACKs(RUDPSocket rudp, SACKSlot slot1, SACKSlot slot2, SACKSlot slot3, SACKSlot slot4) { // No ack if (slot1 == null) return; int maxId = slot1.EndPacketId; if (slot4 != null) maxId = slot4.EndPacketId; else if (slot3 != null) maxId = slot3.EndPacketId; else if (slot2 != null) maxId = slot2.EndPacketId; #if CONSOLE_TRACE if (slot1 != null) Trace("Handle ACK[1](" + rudp.Handle + "): " + slot1.StartPacketId + " <-> " + slot1.EndPacketId); if (slot2 != null) Trace("Handle ACK[2](" + rudp.Handle + "): " + slot2.StartPacketId + " <-> " + slot2.EndPacketId); if (slot3 != null) Trace("Handle ACK[3](" + rudp.Handle + "): " + slot3.StartPacketId + " <-> " + slot3.EndPacketId); if (slot4 != null) Trace("Handle ACK[4](" + rudp.Handle + "): " + slot4.StartPacketId + " <-> " + slot4.EndPacketId); #endif //---- Prepare the list of packets List<RUDPOutgoingPacket> toACKPackets = new List<RUDPOutgoingPacket>(); RUDPOutgoingPacket lastPacket = null; double currentRTT = Double.MaxValue; rudp._outgoingPacketsLock.EnterReadLock(); try { for (int index = 0; index < rudp._outgoingPackets.Count; index++) { RUDPOutgoingPacket packet = rudp._outgoingPackets[index]; if (packet.PacketId > maxId) break; if (packet.IsACKed) continue; if (slot4 != null) if (packet.PacketId >= slot4.StartPacketId && packet.PacketId <= slot4.EndPacketId) { if (packet.Retransmission < 1) { lastPacket = packet; currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend); } toACKPackets.Add(packet); continue; } if (slot3 != null) if (packet.PacketId >= slot3.StartPacketId && packet.PacketId <= slot3.EndPacketId) { if (packet.Retransmission < 1) { lastPacket = packet; currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend); } toACKPackets.Add(packet); continue; } if (slot2 != null) if (packet.PacketId >= slot2.StartPacketId && packet.PacketId <= slot2.EndPacketId) { if (packet.Retransmission < 1) { lastPacket = packet; currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend); } toACKPackets.Add(packet); continue; } if (packet.PacketId >= slot1.StartPacketId && packet.PacketId <= slot1.EndPacketId) { if (packet.Retransmission < 1) { lastPacket = packet; currentRTT = Math.Min(currentRTT, HiResTimer.MicroSeconds - lastPacket.TSFirstSend); } toACKPackets.Add(packet); } } } finally { rudp._outgoingPacketsLock.ExitReadLock(); } //---- If no good packet, use current RTT if (lastPacket == null) currentRTT = rudp.RTT; if (currentRTT < 1) currentRTT = 1; //---- Set the ACK for all the packets for (int index = 0; index < toACKPackets.Count; index++) { RUDPOutgoingPacket packet = toACKPackets[index]; SetPacketACKed(rudp, packet, currentRTT); } }
internal RUDPReceiveIAsyncResult(RUDPSocket rudp, AsyncCallback callback, Object state) : base(rudp, callback, state) { }
private static void SetPacketACKed(RUDPSocket rudp, RUDPOutgoingPacket packet, double currentRTT) { lock (packet) { if (packet.IsACKed) return; rudp._controlWindow.OnACK(packet, currentRTT); // Mark as ACKed packet.IsACKed = true; } Trace("Packet ACKed(" + rudp.Handle + "): " + packet.PacketId + " " + packet.Channel); //---- Ping ACK if ((packet.Channel == RUDPPacketChannel.Ping || packet.Channel == RUDPPacketChannel.PingRendezVous) && rudp._status == RUDPSocketStatus.Connecting) { rudp._status = RUDPSocketStatus.Connected; // MTU tuning if (rudp._usePMTUDiscovery) rudp._pmtuDiscovery.StartTuning(); // connection done rudp.OnEndConnect(RUDPSocketError.Success); return; } //---- Tear Down ACK : It was a tear down message, it has been received, we can close if (packet.Channel == RUDPPacketChannel.TearDown && rudp._status == RUDPSocketStatus.Closing) { rudp._status = RUDPSocketStatus.ClosingACKed; // Remove it to our list of "connected" sockets if (rudp._remoteEndPoint != null) { // Unregister for the stack UnregisterRUDPSocket(rudp); rudp._physical.UnregisterConnectedSocket(rudp); } } }