From 60a1b4a91a16c49271e32165bd8cdc0b8e8ddb8a Mon Sep 17 00:00:00 2001 From: Paul Whittemore Date: Mon, 5 Dec 2016 01:26:01 -0400 Subject: [PATCH] Updates to for Halcyon compatibility - OutgoingPacket moved back to OpenMetaverse scope (separate file) from NetworkManager, and now restores the pool- and refcount-related functionality. - UDPPacketBuffer BufferSize is a constant so now DEFAULT_BUFFER_SIZE. - Added a Halcyon-compatible UDPPacketBuffer constructor that accepts a specific buffer, etc. - Added CopyFrom methods to assign UDPPacketBuffer Data. --- OpenMetaverse/NetworkManager.cs | 27 ------ OpenMetaverse/ObjectPool.cs | 40 ++++++++- OpenMetaverse/OutgoingPacket.cs | 146 ++++++++++++++++++++++++++++++++ OpenMetaverse/Simulator.cs | 18 ++-- OpenMetaverse/UDPBase.cs | 4 +- 5 files changed, 194 insertions(+), 41 deletions(-) create mode 100644 OpenMetaverse/OutgoingPacket.cs diff --git a/OpenMetaverse/NetworkManager.cs b/OpenMetaverse/NetworkManager.cs index fb4531b3..87907f79 100644 --- a/OpenMetaverse/NetworkManager.cs +++ b/OpenMetaverse/NetworkManager.cs @@ -82,33 +82,6 @@ namespace OpenMetaverse } } - /// - /// Holds a simulator reference and a serialized packet, these structs are put in - /// the packet outbox for sending - /// - public class OutgoingPacket - { - /// Reference to the simulator this packet is destined for - public readonly Simulator Simulator; - /// Packet that needs to be sent - public readonly UDPPacketBuffer Buffer; - /// Sequence number of the wrapped packet - public uint SequenceNumber; - /// Number of times this packet has been resent - public int ResendCount; - /// Environment.TickCount when this packet was last sent over the wire - public int TickCount; - /// Type of the packet - public PacketType Type; - - public OutgoingPacket(Simulator simulator, UDPPacketBuffer buffer, PacketType type) - { - Simulator = simulator; - Buffer = buffer; - this.Type = type; - } - } - #endregion Structs #region Delegates diff --git a/OpenMetaverse/ObjectPool.cs b/OpenMetaverse/ObjectPool.cs index b69799b3..75a42679 100644 --- a/OpenMetaverse/ObjectPool.cs +++ b/OpenMetaverse/ObjectPool.cs @@ -9,7 +9,7 @@ namespace OpenMetaverse public class UDPPacketBuffer { /// Size of the byte array used to store raw packet data - public const int BufferSize = 4096; + public const int DEFAULT_BUFFER_SIZE = 4096; /// Raw packet data buffer public readonly byte[] Data; /// Length of the data to transmit @@ -26,7 +26,7 @@ namespace OpenMetaverse /// public UDPPacketBuffer() { - Data = new byte[BufferSize]; + Data = new byte[DEFAULT_BUFFER_SIZE]; // Will be modified later by BeginReceiveFrom() RemoteEndPoint = new IPEndPoint(Settings.BIND_ADDR, 0); } @@ -37,7 +37,7 @@ namespace OpenMetaverse /// EndPoint of the remote host public UDPPacketBuffer(IPEndPoint endPoint) { - Data = new byte[BufferSize]; + Data = new byte[DEFAULT_BUFFER_SIZE]; RemoteEndPoint = endPoint; } @@ -52,6 +52,40 @@ namespace OpenMetaverse RemoteEndPoint = endPoint; } + /// + /// Create an allocated UDP packet buffer for sending a packet + /// + public UDPPacketBuffer(byte[] buffer, int bufferSize, IPEndPoint destination, int category, bool fromBufferPool) + { + Data = new byte[bufferSize]; + this.CopyFrom(buffer, bufferSize); + DataLength = bufferSize; + + RemoteEndPoint = destination; + BytesLeasedFromPool = fromBufferPool; + } + + /// + /// Create an allocated UDP packet buffer for sending a packet + /// + /// EndPoint of the remote host + /// The actual buffer to use for packet data (no allocation). + public UDPPacketBuffer(IPEndPoint endPoint, byte[] data) + { + Data = data; + RemoteEndPoint = endPoint; + } + + public void CopyFrom(Array src, int length) + { + Buffer.BlockCopy(src, 0, this.Data, 0, length); + } + + public void CopyFrom(Array src) + { + this.CopyFrom(src, src.Length); + } + public void ResetEndpoint() { RemoteEndPoint = new IPEndPoint(Settings.BIND_ADDR, 0); diff --git a/OpenMetaverse/OutgoingPacket.cs b/OpenMetaverse/OutgoingPacket.cs new file mode 100644 index 00000000..19192e53 --- /dev/null +++ b/OpenMetaverse/OutgoingPacket.cs @@ -0,0 +1,146 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using OpenMetaverse; +using System.Net; +using OpenMetaverse.Packets; + +namespace OpenMetaverse +{ + /// + /// Holds a simulator client reference and a serialized packet, + /// along with some network statistics and related info. + /// + public sealed class OutgoingPacket + { + /// Reference to the simulator this packet is destined for + public readonly object Client; + /// Packet that needs to be sent + public readonly UDPPacketBuffer Buffer; + /// Sequence number of the wrapped packet + public uint SequenceNumber; + /// Number of times this packet has been resent + public int ResendCount; + /// Environment.TickCount when this packet was last sent over the wire + public int TickCount; + /// Type of the packet + public PacketType Type; + /// + /// This is a caller-managed field representing the number of bytes to use/used in Buffer + /// + public int DataSize; + + /// + /// Reference count to be used on this packet to know when it's safe to return to the pool + /// + private int _refCount; + /// + /// Lock to protect the reference count + /// + private object _refCountLock = new object(); + + /// Category this packet belongs to + public int Category; + + private bool _fromPool = false; + public bool BufferFromPool + { + get { return _fromPool; } + } + + public OutgoingPacket(Simulator simulator, UDPPacketBuffer buffer, PacketType type) + { + Client = simulator; + Buffer = buffer; + this.Type = type; + } + + public Simulator Simulator + { + get { return Client is Simulator ? Client as Simulator : null; } + } + + /// + /// The endpoint this data is headed for + /// + public IPEndPoint Destination + { + get { return Buffer.RemoteEndPoint is IPEndPoint ? Buffer.RemoteEndPoint as IPEndPoint : null; } + } + + /// + /// Default constructor + /// + public OutgoingPacket(object client, byte[] buffer, int category, int dataSize, IPEndPoint destination, + bool fromBufferPool, Packets.PacketType type) + { + SequenceNumber = 0; + ResendCount = 0; + TickCount = 0; + + Client = client; + Category = category; + _fromPool = fromBufferPool; + Type = type; + DataSize = dataSize; + Buffer = new UDPPacketBuffer(buffer, dataSize, destination, category, fromBufferPool); + } + + public void AddRef() + { + if (BufferFromPool) + { + lock (_refCountLock) + { + ++_refCount; + } + } + } + + public void DecRef(Interfaces.IByteBufferPool returnPool) + { + if (BufferFromPool) + { + bool returnToBuffer = false; + lock (_refCountLock) + { + if (--_refCount <= 0) + { + returnToBuffer = true; + } + } + + if (returnToBuffer) + { + Array data = Buffer.Data; + returnPool.ReturnBytes(Buffer.Data); + } + } + } + } +} diff --git a/OpenMetaverse/Simulator.cs b/OpenMetaverse/Simulator.cs index e5b1950f..4923c624 100644 --- a/OpenMetaverse/Simulator.cs +++ b/OpenMetaverse/Simulator.cs @@ -478,7 +478,7 @@ namespace OpenMetaverse /// (for duplicate checking) internal IncomingPacketIDCollection PacketArchive; /// Packets we sent out that need ACKs from the simulator - internal SortedDictionary NeedAck = new SortedDictionary(); + internal SortedDictionary NeedAck = new SortedDictionary(); /// Sequence number for pause/resume internal int pauseSerial; /// Indicates if UDP connection to the sim is fully established @@ -730,7 +730,7 @@ namespace OpenMetaverse CloseCircuitPacket close = new CloseCircuitPacket(); UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint); byte[] data = close.ToBytes(); - Buffer.BlockCopy(data, 0, buf.Data, 0, data.Length); + buf.CopyFrom(data); buf.DataLength = data.Length; AsyncBeginSend(buf); @@ -867,18 +867,18 @@ namespace OpenMetaverse // Remove the MSG_ZEROCODED flag and send the unencoded data // instead data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); - Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + buffer.CopyFrom(data, dataLength); } } else { - Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); + buffer.CopyFrom(data, dataLength); } buffer.DataLength = dataLength; #region Queue or Send - NetworkManager.OutgoingPacket outgoingPacket = new NetworkManager.OutgoingPacket(this, buffer, type); + OutgoingPacket outgoingPacket = new OutgoingPacket(this, buffer, type); // Send ACK and logout packets directly, everything else goes through the queue if (Client.Settings.THROTTLE_OUTGOING_PACKETS == false || @@ -902,7 +902,7 @@ namespace OpenMetaverse #endregion } - internal void SendPacketFinal(NetworkManager.OutgoingPacket outgoingPacket) + internal void SendPacketFinal(OutgoingPacket outgoingPacket) { UDPPacketBuffer buffer = outgoingPacket.Buffer; byte flags = buffer.Data[0]; @@ -1235,19 +1235,19 @@ namespace OpenMetaverse { if (NeedAck.Count <= 0) return; - NetworkManager.OutgoingPacket[] array; + OutgoingPacket[] array; lock (NeedAck) { // Create a temporary copy of the outgoing packets array to iterate over - array = new NetworkManager.OutgoingPacket[NeedAck.Count]; + array = new OutgoingPacket[NeedAck.Count]; NeedAck.Values.CopyTo(array, 0); } int now = Environment.TickCount; // Resend packets - foreach (NetworkManager.OutgoingPacket outgoing in array) + foreach (OutgoingPacket outgoing in array) { if (outgoing.TickCount == 0 || now - outgoing.TickCount <= Client.Settings.RESEND_TIMEOUT) continue; diff --git a/OpenMetaverse/UDPBase.cs b/OpenMetaverse/UDPBase.cs index 2ac82620..146c50c0 100644 --- a/OpenMetaverse/UDPBase.cs +++ b/OpenMetaverse/UDPBase.cs @@ -149,7 +149,7 @@ namespace OpenMetaverse //wrappedBuffer.Instance.Data, buf.Data, 0, - UDPPacketBuffer.BufferSize, + UDPPacketBuffer.DEFAULT_BUFFER_SIZE, SocketFlags.None, ref buf.RemoteEndPoint, AsyncEndReceive, @@ -170,7 +170,7 @@ namespace OpenMetaverse //wrappedBuffer.Instance.Data, buf.Data, 0, - UDPPacketBuffer.BufferSize, + UDPPacketBuffer.DEFAULT_BUFFER_SIZE, SocketFlags.None, ref buf.RemoteEndPoint, AsyncEndReceive,