private bool ResendPackages(IEnumerable <OutgoingPacket> packetList) { var now = Util.Now; foreach (var outgoingPacket in packetList) { // Check if the packet timed out completely if (outgoingPacket.FirstSendTime < now - PacketTimeout) { ColorDbg.WriteResend(outgoingPacket, "TIMEOUT"); return(true); } // Check if we should retransmit a packet because it probably got lost if (outgoingPacket.LastSendTime < now - currentRto) { ColorDbg.WriteResend(outgoingPacket, "RESEND"); currentRto = currentRto + currentRto; if (currentRto > MaxRetryInterval) { currentRto = MaxRetryInterval; } SendRaw(outgoingPacket); } } return(false); }
private void AddOutgoingPacket(OutgoingPacket packet, PacketFlags flags = PacketFlags.None) { lock (sendLoopLock) { var ids = GetPacketCounter(packet.PacketType); if (ts3Crypt.CryptoInitComplete) { IncPacketCounter(packet.PacketType); } packet.PacketId = ids.Id; packet.GenerationId = ids.Generation; packet.ClientId = ClientId; packet.PacketFlags |= flags; switch (packet.PacketType) { case PacketType.Voice: case PacketType.VoiceWhisper: packet.PacketFlags |= PacketFlags.Unencrypted; NetUtil.H2N(packet.PacketId, packet.Data, 0); break; case PacketType.Command: case PacketType.CommandLow: packet.PacketFlags |= PacketFlags.Newprotocol; packetAckManager.Add(packet.PacketId, packet); break; case PacketType.Ping: lastSentPingId = packet.PacketId; packet.PacketFlags |= PacketFlags.Unencrypted; break; case PacketType.Pong: packet.PacketFlags |= PacketFlags.Unencrypted; break; case PacketType.Ack: case PacketType.AckLow: break; // Nothing to do case PacketType.Init1: packet.PacketFlags |= PacketFlags.Unencrypted; packetAckManager.Add(packet.PacketId, packet); break; default: throw Util.UnhandledDefault(packet.PacketType); } ColorDbg.WritePkgOut(packet); ts3Crypt.Encrypt(packet); packet.FirstSendTime = Util.Now; SendRaw(packet); } }
public void ReceiveInitAck() { // this method is a bit hacky since it removes ALL Init1 packets // from the sendQueue instead of the one with the preceding // init step id (see Ts3Crypt.ProcessInit1). // But usually this should be no problem since the init order is linear lock (sendLoopLock) { ColorDbg.WriteDetail("Cleaned Inits", "INIT"); var remPacket = packetAckManager.Values.Where(x => x.PacketType == PacketType.Init1).ToArray(); foreach (var packet in remPacket) { packetAckManager.Remove(packet.PacketId); } } }
private void UpdateRto(TimeSpan sampleRtt) { // Timeout calculation (see: https://tools.ietf.org/html/rfc6298) // SRTT_{i+1} = (1-a) * SRTT_i + a * RTT // DevRTT_{i+1} = (1-b) * DevRTT_i + b * | RTT - SRTT_{i+1} | // Timeout_{i+1} = SRTT_{i+1} + max(ClockRes, 4 * DevRTT_{i+1}) if (smoothedRtt < TimeSpan.Zero) { smoothedRtt = sampleRtt; } else { smoothedRtt = TimeSpan.FromTicks((long)((1 - AlphaSmooth) * smoothedRtt.Ticks + AlphaSmooth * sampleRtt.Ticks)); } smoothedRttVar = TimeSpan.FromTicks((long)((1 - BetaSmooth) * smoothedRttVar.Ticks + BetaSmooth * Math.Abs(sampleRtt.Ticks - smoothedRtt.Ticks))); currentRto = smoothedRtt + Util.Max(ClockResolution, TimeSpan.FromTicks(4 * smoothedRttVar.Ticks)); ColorDbg.WriteRtt(smoothedRtt, smoothedRttVar, currentRto); }
public IncomingPacket FetchPacket() { while (true) { if (Closed) { return(null); } if (TryFetchPacket(receiveQueue, out var packet)) { return(packet); } if (TryFetchPacket(receiveQueueLow, out packet)) { return(packet); } var dummy = new IPEndPoint(IPAddress.Any, 0); byte[] buffer; try { buffer = udpClient.Receive(ref dummy); } catch (IOException) { return(null); } catch (SocketException) { return(null); } if (dummy.Address.Equals(remoteAddress.Address) && dummy.Port != remoteAddress.Port) { continue; } packet = Ts3Crypt.GetIncommingPacket(buffer); // Invalid packet, ignore if (packet == null) { ColorDbg.WritePkgRaw(buffer, "DROPPING"); continue; } GenerateGenerationId(packet); if (!ts3Crypt.Decrypt(packet)) { continue; } NetworkStats.LogInPacket(packet); ColorDbg.WritePkgIn(packet); switch (packet.PacketType) { case PacketType.Voice: break; case PacketType.VoiceWhisper: break; case PacketType.Command: packet = ReceiveCommand(packet, receiveQueue, PacketType.Ack); break; case PacketType.CommandLow: packet = ReceiveCommand(packet, receiveQueueLow, PacketType.AckLow); break; case PacketType.Ping: ReceivePing(packet); break; case PacketType.Pong: ReceivePong(packet); break; case PacketType.Ack: packet = ReceiveAck(packet); break; case PacketType.AckLow: break; case PacketType.Init1: ReceiveInitAck(); break; default: throw Util.UnhandledDefault(packet.PacketType); } if (packet != null) { return(packet); } } }