private int HandleBandwidthLimit(Peer peer, Protocol.BandwidthLimit command) { peer.IncomingBandwidth = command.IncomingBandwidth; peer.OutgoingBandwidth = command.OutgoingBandwidth; if (peer.IncomingBandwidth == 0u && OutgoingBandwidth == 0u) { peer.WindowSize = MAXIMUM_WINDOW_SIZE; } else { peer.WindowSize = (Math.Min(peer.IncomingBandwidth, OutgoingBandwidth) / Peer.WINDOW_SIZE_SCALE) * MINIMUM_WINDOW_SIZE; } peer.WindowSize = Utils.Clamp(peer.WindowSize, MINIMUM_WINDOW_SIZE, MAXIMUM_WINDOW_SIZE); return(0); }
public void BandwidthThrottle() { uint timeCurrent = GetTime(); uint elapsedTime = timeCurrent - BandwidthThrottleEpoch; if (elapsedTime < Version.BandwidthThrottleInterval) { return; } uint peersTotal = 0; uint dataTotal = 0; foreach (var peer in Peers) { if (peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) { continue; } peersTotal++; dataTotal += peer.OutgoingDataTotal; } if (peersTotal == 0) { return; } uint peersRemaining = peersTotal; bool needsAdjustment = true; uint bandwidth = OutgoingBandwidth == 0 ? ~0u : (OutgoingBandwidth * elapsedTime) / 1000u; uint throttle = 0; while (peersRemaining > 0 && needsAdjustment) { needsAdjustment = false; if (dataTotal < bandwidth) { throttle = Peer.PACKET_THROTTLE_SCALE; } else { throttle = (bandwidth * Peer.PACKET_THROTTLE_SCALE) / dataTotal; } foreach (var peer in Peers) { uint peerBandwidth = 0; if ((peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) || peer.IncomingBandwidth == 0 || peer.OutgoingBandwidthThrottleEpoch == timeCurrent) { continue; } peerBandwidth = (peer.IncomingBandwidth * elapsedTime) / 1000; if ((throttle * peer.OutgoingDataTotal) / Peer.PACKET_THROTTLE_SCALE <= peerBandwidth) { continue; } peer.PacketThrottleLimit = (peerBandwidth * Peer.PACKET_THROTTLE_SCALE) / peer.OutgoingDataTotal; if (peer.PacketThrottleLimit == 0) { peer.PacketThrottleLimit = 1; } if (peer.PacketThrottle > peer.PacketThrottleLimit) { peer.PacketThrottle = peer.PacketThrottleLimit; } peer.OutgoingBandwidthThrottleEpoch = timeCurrent; needsAdjustment = true; peersRemaining--; bandwidth -= peerBandwidth; dataTotal -= peerBandwidth; } } if (peersRemaining > 0) { foreach (var peer in Peers) { if ((peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) || peer.OutgoingBandwidthThrottleEpoch == timeCurrent) { continue; } peer.PacketThrottleLimit = throttle; if (peer.PacketThrottle > peer.PacketThrottleLimit) { peer.PacketThrottle = peer.PacketThrottleLimit; } } } if (RecalculateBandwidthLimits) { RecalculateBandwidthLimits = false; peersRemaining = peersTotal; bandwidth = IncomingBandwidth; needsAdjustment = true; uint bandwidthLimit = 0; if (bandwidth != 0) { while (peersRemaining > 0 && needsAdjustment) { needsAdjustment = false; bandwidthLimit = bandwidth / peersRemaining; foreach (var peer in Peers) { if ((peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) || peer.IncomingBandwidthThrottleEpoch == timeCurrent) { continue; } if (peer.OutgoingBandwidth > 0 && peer.OutgoingBandwidth >= bandwidthLimit) { continue; } peer.IncomingBandwidthThrottleEpoch = timeCurrent; needsAdjustment = true; peersRemaining--; bandwidth -= peer.OutgoingBandwidth; } } } foreach (var peer in Peers) { if (peer.State != PeerState.CONNECTED && peer.State != PeerState.DISCONNECT_LATER) { continue; } var command = new Protocol.BandwidthLimit { Flags = ProtocolFlag.ACKNOWLEDGE, ChannelID = 0xFF, OutgoingBandwidth = OutgoingBandwidth, }; if (peer.IncomingBandwidthThrottleEpoch == timeCurrent) { command.IncomingBandwidth = peer.OutgoingBandwidth; } else { command.IncomingBandwidth = bandwidthLimit; } peer.QueueOutgoingCommand(command, null, 0, 0); } } BandwidthThrottleEpoch = timeCurrent; foreach (var peer in Peers) { peer.IncomingDataTotal = 0; peer.OutgoingDataTotal = 0; } }