diff --git a/Lidgren.Network/NetPeer.LatencySimulation.cs b/Lidgren.Network/NetPeer.LatencySimulation.cs index ba3261d9..9ed96323 100644 --- a/Lidgren.Network/NetPeer.LatencySimulation.cs +++ b/Lidgren.Network/NetPeer.LatencySimulation.cs @@ -20,6 +20,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. //#define USE_RELEASE_STATISTICS using System; +using System.Buffers; using System.Collections.Generic; using System.Net; using System.Net.Sockets; @@ -36,9 +37,10 @@ public partial class NetPeer private readonly List m_delayedPackets = new List(); private MWCRandom m_latencyRandom = new MWCRandom(); - private sealed class DelayedPacket + private record struct DelayedPacket { public byte[] Data; + public int Length; public double DelayedUntil; public NetEndPoint Target; } @@ -84,13 +86,18 @@ internal void SendPacket(int numBytes, NetEndPoint target, int numMessages, out for (int i = 0; i < num; i++) { delay = m + (m_latencyRandom.NextSingle() * r); + var data = GetStorage(numBytes); + + Buffer.BlockCopy(m_sendBuffer, 0, data, 0, numBytes); // Enqueue delayed packet - DelayedPacket p = new DelayedPacket(); - p.Target = target; - p.Data = new byte[numBytes]; - Buffer.BlockCopy(m_sendBuffer, 0, p.Data, 0, numBytes); - p.DelayedUntil = NetTime.Now + delay; + var p = new DelayedPacket + { + Target = target, + Data = data, + Length = numBytes, + DelayedUntil = NetTime.Now + delay + }; m_delayedPackets.Add(p); } @@ -110,18 +117,20 @@ private void SendDelayedPackets() for (var i = 0; i < m_delayedPackets.Count; i++) { var p = m_delayedPackets[i]; - if (now < p.DelayedUntil) + if (now < p.DelayedUntil) continue; - - ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset); - + + ActuallySendPacket(p.Data, p.Length, p.Target, out connectionReset); + // Swap packet with last entry in list. // This does not preserve order (we don't care) but is O(1). var replaceIdx = m_delayedPackets.Count - 1; var replacement = m_delayedPackets[replaceIdx]; m_delayedPackets[i] = replacement; m_delayedPackets.RemoveAt(replaceIdx); - + + Recycle(p.Data); + // Make sure to decrement i so we re-process the element we just swapped in. i -= 1; } @@ -133,7 +142,11 @@ private void FlushDelayedPackets() { bool connectionReset; foreach (DelayedPacket p in m_delayedPackets) - ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset); + { + ActuallySendPacket(p.Data, p.Length, p.Target, out connectionReset); + Recycle(p.Data); + } + m_delayedPackets.Clear(); } catch { } @@ -156,20 +169,20 @@ internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, // TODO: refactor this check outta here if (target.Address.Equals(ba)) { - // Some networks do not allow + // Some networks do not allow // a global broadcast so we use the BroadcastAddress from the configuration - // this can be resolved to a local broadcast addresss e.g 192.168.x.255 + // this can be resolved to a local broadcast addresss e.g 192.168.x.255 targetCopy.Address = m_configuration.BroadcastAddress; targetCopy.Port = target.Port; realTarget = targetCopy; m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - + if (dualStack) { NetUtility.CopyEndpoint(realTarget, targetCopy2); //Maps to IPv6 for Dual Mode realTarget = targetCopy2; } - + } else if (dualStack) { @@ -193,7 +206,7 @@ internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, } if (sx.SocketErrorCode == SocketError.ConnectionReset) { - // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" + // connection reset by peer, aka connection forcibly closed aka "ICMP port unreachable" connectionReset = true; return false; } @@ -215,7 +228,7 @@ internal bool SendMTUPacket(int numBytes, NetEndPoint target) { if (!CanAutoExpandMTU) throw new NotSupportedException("MTU expansion not currently supported on this operating system"); - + try { // NOTE: Socket.DontFragment doesn't work on dual-stack sockets. @@ -223,7 +236,7 @@ internal bool SendMTUPacket(int numBytes, NetEndPoint target) // See: https://github.com/dotnet/runtime/issues/76410 if (m_socket.DualMode || target.AddressFamily == AddressFamily.InterNetwork) m_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true); - + int bytesSent = NetFastSocket.SendTo(m_socket, m_sendBuffer, 0, numBytes, SocketFlags.None, target); if (numBytes != bytesSent) LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!"); diff --git a/Lidgren.Network/NetReliableSenderChannel.cs b/Lidgren.Network/NetReliableSenderChannel.cs index 0a05dd71..79cb3956 100644 --- a/Lidgren.Network/NetReliableSenderChannel.cs +++ b/Lidgren.Network/NetReliableSenderChannel.cs @@ -67,7 +67,7 @@ internal override NetSendResult Enqueue(NetOutgoingMessage message) return NetSendResult.Queued; } - // call this regularely + // call this regularly internal override void SendQueuedMessages(double now) { // @@ -166,7 +166,7 @@ private void DestoreMessage(double now, int storeIndex, out bool resetTimeout) #endif // on each destore; reduce recyclingcount so that when all instances are destored, the outgoing message can be recycled Interlocked.Decrement(ref storedMessage.m_recyclingCount); - + if (storedMessage.m_recyclingCount <= 0) m_connection.m_peer.Recycle(storedMessage);