From fc41f2e461255d051958160cabad3b0edf096566 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 8 Oct 2009 07:55:06 -0700 Subject: [PATCH 01/19] Added guards against the exception reported: #2009-10-08 12:58:34,462 ERROR - OpenSim.Application [APPLICATION]: #APPLICATION EXCEPTION DETECTED: System.UnhandledExceptionEventArgs # #Exception: System.Exception: Object reference not set to an instance of an object. ---> System.NullReferenceException: Object reference not set to an instance of an object. # at OpenSim.Region.ClientStack.LindenUDP.J2KImage.SendFirstPacket(LLClientView client) in c:\Opensim\OpenSim\Region\ClientStack\LindenUDP\J2KImage.cs:line 230 # at OpenSim.Region.ClientStack.LindenUDP.J2KImage.SendPackets(LLClientView client, Int32 maxpack) in c:\Opensim\OpenSim\Region\ClientStack\LindenUDP\J2KImage.cs:line 84 --- OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs index 2f1face8cf..5877779d2b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs @@ -74,6 +74,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP public bool SendPackets(LLClientView client, int maxpack) { + if (client == null) + return false; + if (m_currentPacket <= m_stopPacket) { int count = 0; @@ -202,6 +205,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool SendFirstPacket(LLClientView client) { + if (client == null) + return false; + if (m_asset == null) { m_log.Warn("[J2KIMAGE]: Sending ImageNotInDatabase for texture " + TextureID); @@ -234,6 +240,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool SendPacket(LLClientView client) { + if (client == null) + return false; + bool complete = false; int imagePacketSize = ((int)m_currentPacket == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE; From a0dd9f4bb4c1a88c2692066c54923c7f91429df5 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 8 Oct 2009 22:25:14 +0100 Subject: [PATCH 02/19] Fork UDPBase from libOMV into opensim --- .../ClientStack/LindenUDP/LLUDPServer.cs | 2 +- .../ClientStack/LindenUDP/OpenSimUDPBase.cs | 340 ++++++++++++++++++ 2 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 2c5ad85432..1e6927fadf 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// The LLUDP server for a region. This handles incoming and outgoing /// packets for all UDP connections to the region /// - public class LLUDPServer : UDPBase + public class LLUDPServer : OpenSimUDPBase { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs new file mode 100644 index 0000000000..aaefbc6ce3 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2006, Clutch, Inc. + * Original Author: Jeff Cesnik + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.Net; +using System.Net.Sockets; +using System.Threading; +using OpenMetaverse; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + /// + /// + /// + public abstract class OpenSimUDPBase + { + // these abstract methods must be implemented in a derived class to actually do + // something with the packets that are sent and received. + protected abstract void PacketReceived(UDPPacketBuffer buffer); + protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); + + // the port to listen on + internal int udpPort; + + // the UDP socket + private Socket udpSocket; + + // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). + // since there are potentially many "reader" threads in the internal .NET IOCP + // thread pool, this is a cheaper synchronization primitive than using + // a Mutex object. This allows many UDP socket "reads" concurrently - when + // Stop() is called, it attempts to obtain a writer lock which will then + // wait until all outstanding operations are completed before shutting down. + // this avoids the problem of closing the socket with outstanding operations + // and trying to catch the inevitable ObjectDisposedException. + private ReaderWriterLock rwLock = new ReaderWriterLock(); + + // number of outstanding operations. This is a reference count + // which we use to ensure that the threads exit cleanly. Note that + // we need this because the threads will potentially still need to process + // data even after the socket is closed. + private int rwOperationCount = 0; + + // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. + private volatile bool shutdownFlag = true; + + // the remote endpoint to communicate with + protected IPEndPoint remoteEndPoint = null; + + + /// + /// Initialize the UDP packet handler in server mode + /// + /// Port to listening for incoming UDP packets on + public OpenSimUDPBase(int port) + { + udpPort = port; + } + + /// + /// Initialize the UDP packet handler in client mode + /// + /// Remote UDP server to connect to + public OpenSimUDPBase(IPEndPoint endPoint) + { + remoteEndPoint = endPoint; + udpPort = 0; + } + + /// + /// + /// + public void Start() + { + if (shutdownFlag) + { + if (remoteEndPoint == null) + { + // Server mode + + // create and bind the socket + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + udpSocket.Bind(ipep); + } + else + { + // Client mode + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + udpSocket.Bind(ipep); + //udpSocket.Connect(remoteEndPoint); + } + + // we're not shutting down, we're starting up + shutdownFlag = false; + + // kick off an async receive. The Start() method will return, the + // actual receives will occur asynchronously and will be caught in + // AsyncEndRecieve(). + AsyncBeginReceive(); + } + } + + /// + /// + /// + public void Stop() + { + if (!shutdownFlag) + { + // wait indefinitely for a writer lock. Once this is called, the .NET runtime + // will deny any more reader locks, in effect blocking all other send/receive + // threads. Once we have the lock, we set shutdownFlag to inform the other + // threads that the socket is closed. + rwLock.AcquireWriterLock(-1); + shutdownFlag = true; + udpSocket.Close(); + rwLock.ReleaseWriterLock(); + + // wait for any pending operations to complete on other + // threads before exiting. + const int FORCE_STOP = 100; + int i = 0; + while (rwOperationCount > 0 && i < FORCE_STOP) + { + Thread.Sleep(10); + ++i; + } + + if (i >= FORCE_STOP) + { + Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", + Helpers.LogLevel.Warning); + } + } + } + + /// + /// + /// + public bool IsRunning + { + get { return !shutdownFlag; } + } + + private void AsyncBeginReceive() + { + // this method actually kicks off the async read on the socket. + // we aquire a reader lock here to ensure that no other thread + // is trying to set shutdownFlag and close the socket. + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + // increment the count of pending operations + Interlocked.Increment(ref rwOperationCount); + + // allocate a packet buffer + //WrappedObject wrappedBuffer = Pool.CheckOut(); + UDPPacketBuffer buf = new UDPPacketBuffer(); + + try + { + // kick off an async read + udpSocket.BeginReceiveFrom( + //wrappedBuffer.Instance.Data, + buf.Data, + 0, + UDPPacketBuffer.BUFFER_SIZE, + SocketFlags.None, + //ref wrappedBuffer.Instance.RemoteEndPoint, + ref buf.RemoteEndPoint, + new AsyncCallback(AsyncEndReceive), + //wrappedBuffer); + buf); + } + catch (SocketException) + { + // something bad happened + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncBeginReceive()", + // Helpers.LogLevel.Error, se); + + // an error occurred, therefore the operation is void. Decrement the reference count. + Interlocked.Decrement(ref rwOperationCount); + } + } + + // we're done with the socket for now, release the reader lock. + rwLock.ReleaseReaderLock(); + } + + private void AsyncEndReceive(IAsyncResult iar) + { + // Asynchronous receive operations will complete here through the call + // to AsyncBeginReceive + + // aquire a reader lock + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + // get the buffer that was created in AsyncBeginReceive + // this is the received data + //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; + //UDPPacketBuffer buffer = wrappedBuffer.Instance; + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + + try + { + // get the length of data actually read from the socket, store it with the + // buffer + buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); + + // this operation is now complete, decrement the reference count + Interlocked.Decrement(ref rwOperationCount); + + // we're done with the socket, release the reader lock + rwLock.ReleaseReaderLock(); + + // call the abstract method PacketReceived(), passing the buffer that + // has just been filled from the socket read. + PacketReceived(buffer); + } + catch (SocketException) + { + // an error occurred, therefore the operation is void. Decrement the reference count. + Interlocked.Decrement(ref rwOperationCount); + + // we're done with the socket for now, release the reader lock. + rwLock.ReleaseReaderLock(); + } + finally + { + // start another receive - this keeps the server going! + AsyncBeginReceive(); + + //wrappedBuffer.Dispose(); + } + } + else + { + // nothing bad happened, but we are done with the operation + // decrement the reference count and release the reader lock + Interlocked.Decrement(ref rwOperationCount); + rwLock.ReleaseReaderLock(); + } + } + + public void AsyncBeginSend(UDPPacketBuffer buf) + { + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + try + { + Interlocked.Increment(ref rwOperationCount); + udpSocket.BeginSendTo( + buf.Data, + 0, + buf.DataLength, + SocketFlags.None, + buf.RemoteEndPoint, + new AsyncCallback(AsyncEndSend), + buf); + } + catch (SocketException) + { + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncBeginSend()", + // Helpers.LogLevel.Error, se); + } + } + + rwLock.ReleaseReaderLock(); + } + + private void AsyncEndSend(IAsyncResult iar) + { + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + + try + { + int bytesSent = udpSocket.EndSendTo(iar); + + // note that call to the abstract PacketSent() method - we are passing the number + // of bytes sent in a separate parameter, since we can't use buffer.DataLength which + // is the number of bytes to send (or bytes received depending upon whether this + // buffer was part of a send or a receive). + PacketSent(buffer, bytesSent); + } + catch (SocketException) + { + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncEndSend()", + // Helpers.LogLevel.Error, se); + } + } + + Interlocked.Decrement(ref rwOperationCount); + rwLock.ReleaseReaderLock(); + } + } +} From 51ea39199bc875aa0803231aa1dfc43471fcabd6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 8 Oct 2009 15:42:08 -0700 Subject: [PATCH 03/19] Putting the lock back in TryGetValue. --- .../LindenUDP/LLUDPClientCollection.cs | 18 +- .../ClientStack/LindenUDP/OpenSimUDPBase.cs | 680 +++++++++--------- 2 files changed, 349 insertions(+), 349 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index f6ccf01bc0..dbb9861acc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -224,16 +224,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP ////return success; - //lock (m_sync) - // return Dictionary1.TryGetValue(key, out value); + lock (m_sync) + return Dictionary1.TryGetValue(key, out value); - try - { - return Dictionary1.TryGetValue(key, out value); - } - catch { } - value = null; - return false; + //try + //{ + // return Dictionary1.TryGetValue(key, out value); + //} + //catch { } + //value = null; + //return false; } public bool TryGetValue(IPEndPoint key, out LLUDPClient value) diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index aaefbc6ce3..218aaacc78 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs @@ -1,340 +1,340 @@ -/* - * Copyright (c) 2006, Clutch, Inc. - * Original Author: Jeff Cesnik - * All rights reserved. - * - * - 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. - * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.Net; -using System.Net.Sockets; -using System.Threading; -using OpenMetaverse; - -namespace OpenSim.Region.ClientStack.LindenUDP -{ - /// - /// - /// - public abstract class OpenSimUDPBase - { - // these abstract methods must be implemented in a derived class to actually do - // something with the packets that are sent and received. - protected abstract void PacketReceived(UDPPacketBuffer buffer); - protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); - - // the port to listen on - internal int udpPort; - - // the UDP socket - private Socket udpSocket; - - // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). - // since there are potentially many "reader" threads in the internal .NET IOCP - // thread pool, this is a cheaper synchronization primitive than using - // a Mutex object. This allows many UDP socket "reads" concurrently - when - // Stop() is called, it attempts to obtain a writer lock which will then - // wait until all outstanding operations are completed before shutting down. - // this avoids the problem of closing the socket with outstanding operations - // and trying to catch the inevitable ObjectDisposedException. - private ReaderWriterLock rwLock = new ReaderWriterLock(); - - // number of outstanding operations. This is a reference count - // which we use to ensure that the threads exit cleanly. Note that - // we need this because the threads will potentially still need to process - // data even after the socket is closed. - private int rwOperationCount = 0; - - // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. - private volatile bool shutdownFlag = true; - - // the remote endpoint to communicate with - protected IPEndPoint remoteEndPoint = null; - - - /// - /// Initialize the UDP packet handler in server mode - /// - /// Port to listening for incoming UDP packets on - public OpenSimUDPBase(int port) - { - udpPort = port; - } - - /// - /// Initialize the UDP packet handler in client mode - /// - /// Remote UDP server to connect to - public OpenSimUDPBase(IPEndPoint endPoint) - { - remoteEndPoint = endPoint; - udpPort = 0; - } - - /// - /// - /// - public void Start() - { - if (shutdownFlag) - { - if (remoteEndPoint == null) - { - // Server mode - - // create and bind the socket - IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); - udpSocket = new Socket( - AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp); - udpSocket.Bind(ipep); - } - else - { - // Client mode - IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); - udpSocket = new Socket( - AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp); - udpSocket.Bind(ipep); - //udpSocket.Connect(remoteEndPoint); - } - - // we're not shutting down, we're starting up - shutdownFlag = false; - - // kick off an async receive. The Start() method will return, the - // actual receives will occur asynchronously and will be caught in - // AsyncEndRecieve(). - AsyncBeginReceive(); - } - } - - /// - /// - /// - public void Stop() - { - if (!shutdownFlag) - { - // wait indefinitely for a writer lock. Once this is called, the .NET runtime - // will deny any more reader locks, in effect blocking all other send/receive - // threads. Once we have the lock, we set shutdownFlag to inform the other - // threads that the socket is closed. - rwLock.AcquireWriterLock(-1); - shutdownFlag = true; - udpSocket.Close(); - rwLock.ReleaseWriterLock(); - - // wait for any pending operations to complete on other - // threads before exiting. - const int FORCE_STOP = 100; - int i = 0; - while (rwOperationCount > 0 && i < FORCE_STOP) - { - Thread.Sleep(10); - ++i; - } - - if (i >= FORCE_STOP) - { - Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", - Helpers.LogLevel.Warning); - } - } - } - - /// - /// - /// - public bool IsRunning - { - get { return !shutdownFlag; } - } - - private void AsyncBeginReceive() - { - // this method actually kicks off the async read on the socket. - // we aquire a reader lock here to ensure that no other thread - // is trying to set shutdownFlag and close the socket. - rwLock.AcquireReaderLock(-1); - - if (!shutdownFlag) - { - // increment the count of pending operations - Interlocked.Increment(ref rwOperationCount); - - // allocate a packet buffer - //WrappedObject wrappedBuffer = Pool.CheckOut(); - UDPPacketBuffer buf = new UDPPacketBuffer(); - - try - { - // kick off an async read - udpSocket.BeginReceiveFrom( - //wrappedBuffer.Instance.Data, - buf.Data, - 0, - UDPPacketBuffer.BUFFER_SIZE, - SocketFlags.None, - //ref wrappedBuffer.Instance.RemoteEndPoint, - ref buf.RemoteEndPoint, - new AsyncCallback(AsyncEndReceive), - //wrappedBuffer); - buf); - } - catch (SocketException) - { - // something bad happened - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncBeginReceive()", - // Helpers.LogLevel.Error, se); - - // an error occurred, therefore the operation is void. Decrement the reference count. - Interlocked.Decrement(ref rwOperationCount); - } - } - - // we're done with the socket for now, release the reader lock. - rwLock.ReleaseReaderLock(); - } - - private void AsyncEndReceive(IAsyncResult iar) - { - // Asynchronous receive operations will complete here through the call - // to AsyncBeginReceive - - // aquire a reader lock - rwLock.AcquireReaderLock(-1); - - if (!shutdownFlag) - { - // get the buffer that was created in AsyncBeginReceive - // this is the received data - //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; - //UDPPacketBuffer buffer = wrappedBuffer.Instance; - UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; - - try - { - // get the length of data actually read from the socket, store it with the - // buffer - buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); - - // this operation is now complete, decrement the reference count - Interlocked.Decrement(ref rwOperationCount); - - // we're done with the socket, release the reader lock - rwLock.ReleaseReaderLock(); - - // call the abstract method PacketReceived(), passing the buffer that - // has just been filled from the socket read. - PacketReceived(buffer); - } - catch (SocketException) - { - // an error occurred, therefore the operation is void. Decrement the reference count. - Interlocked.Decrement(ref rwOperationCount); - - // we're done with the socket for now, release the reader lock. - rwLock.ReleaseReaderLock(); - } - finally - { - // start another receive - this keeps the server going! - AsyncBeginReceive(); - - //wrappedBuffer.Dispose(); - } - } - else - { - // nothing bad happened, but we are done with the operation - // decrement the reference count and release the reader lock - Interlocked.Decrement(ref rwOperationCount); - rwLock.ReleaseReaderLock(); - } - } - - public void AsyncBeginSend(UDPPacketBuffer buf) - { - rwLock.AcquireReaderLock(-1); - - if (!shutdownFlag) - { - try - { - Interlocked.Increment(ref rwOperationCount); - udpSocket.BeginSendTo( - buf.Data, - 0, - buf.DataLength, - SocketFlags.None, - buf.RemoteEndPoint, - new AsyncCallback(AsyncEndSend), - buf); - } - catch (SocketException) - { - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncBeginSend()", - // Helpers.LogLevel.Error, se); - } - } - - rwLock.ReleaseReaderLock(); - } - - private void AsyncEndSend(IAsyncResult iar) - { - rwLock.AcquireReaderLock(-1); - - if (!shutdownFlag) - { - UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; - - try - { - int bytesSent = udpSocket.EndSendTo(iar); - - // note that call to the abstract PacketSent() method - we are passing the number - // of bytes sent in a separate parameter, since we can't use buffer.DataLength which - // is the number of bytes to send (or bytes received depending upon whether this - // buffer was part of a send or a receive). - PacketSent(buffer, bytesSent); - } - catch (SocketException) - { - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncEndSend()", - // Helpers.LogLevel.Error, se); - } - } - - Interlocked.Decrement(ref rwOperationCount); - rwLock.ReleaseReaderLock(); - } - } -} +/* + * Copyright (c) 2006, Clutch, Inc. + * Original Author: Jeff Cesnik + * All rights reserved. + * + * - 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. + * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.Net; +using System.Net.Sockets; +using System.Threading; +using OpenMetaverse; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + /// + /// + /// + public abstract class OpenSimUDPBase + { + // these abstract methods must be implemented in a derived class to actually do + // something with the packets that are sent and received. + protected abstract void PacketReceived(UDPPacketBuffer buffer); + protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); + + // the port to listen on + internal int udpPort; + + // the UDP socket + private Socket udpSocket; + + // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). + // since there are potentially many "reader" threads in the internal .NET IOCP + // thread pool, this is a cheaper synchronization primitive than using + // a Mutex object. This allows many UDP socket "reads" concurrently - when + // Stop() is called, it attempts to obtain a writer lock which will then + // wait until all outstanding operations are completed before shutting down. + // this avoids the problem of closing the socket with outstanding operations + // and trying to catch the inevitable ObjectDisposedException. + private ReaderWriterLock rwLock = new ReaderWriterLock(); + + // number of outstanding operations. This is a reference count + // which we use to ensure that the threads exit cleanly. Note that + // we need this because the threads will potentially still need to process + // data even after the socket is closed. + private int rwOperationCount = 0; + + // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. + private volatile bool shutdownFlag = true; + + // the remote endpoint to communicate with + protected IPEndPoint remoteEndPoint = null; + + + /// + /// Initialize the UDP packet handler in server mode + /// + /// Port to listening for incoming UDP packets on + public OpenSimUDPBase(int port) + { + udpPort = port; + } + + /// + /// Initialize the UDP packet handler in client mode + /// + /// Remote UDP server to connect to + public OpenSimUDPBase(IPEndPoint endPoint) + { + remoteEndPoint = endPoint; + udpPort = 0; + } + + /// + /// + /// + public void Start() + { + if (shutdownFlag) + { + if (remoteEndPoint == null) + { + // Server mode + + // create and bind the socket + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + udpSocket.Bind(ipep); + } + else + { + // Client mode + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + udpSocket.Bind(ipep); + //udpSocket.Connect(remoteEndPoint); + } + + // we're not shutting down, we're starting up + shutdownFlag = false; + + // kick off an async receive. The Start() method will return, the + // actual receives will occur asynchronously and will be caught in + // AsyncEndRecieve(). + AsyncBeginReceive(); + } + } + + /// + /// + /// + public void Stop() + { + if (!shutdownFlag) + { + // wait indefinitely for a writer lock. Once this is called, the .NET runtime + // will deny any more reader locks, in effect blocking all other send/receive + // threads. Once we have the lock, we set shutdownFlag to inform the other + // threads that the socket is closed. + rwLock.AcquireWriterLock(-1); + shutdownFlag = true; + udpSocket.Close(); + rwLock.ReleaseWriterLock(); + + // wait for any pending operations to complete on other + // threads before exiting. + const int FORCE_STOP = 100; + int i = 0; + while (rwOperationCount > 0 && i < FORCE_STOP) + { + Thread.Sleep(10); + ++i; + } + + if (i >= FORCE_STOP) + { + Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", + Helpers.LogLevel.Warning); + } + } + } + + /// + /// + /// + public bool IsRunning + { + get { return !shutdownFlag; } + } + + private void AsyncBeginReceive() + { + // this method actually kicks off the async read on the socket. + // we aquire a reader lock here to ensure that no other thread + // is trying to set shutdownFlag and close the socket. + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + // increment the count of pending operations + Interlocked.Increment(ref rwOperationCount); + + // allocate a packet buffer + //WrappedObject wrappedBuffer = Pool.CheckOut(); + UDPPacketBuffer buf = new UDPPacketBuffer(); + + try + { + // kick off an async read + udpSocket.BeginReceiveFrom( + //wrappedBuffer.Instance.Data, + buf.Data, + 0, + UDPPacketBuffer.BUFFER_SIZE, + SocketFlags.None, + //ref wrappedBuffer.Instance.RemoteEndPoint, + ref buf.RemoteEndPoint, + new AsyncCallback(AsyncEndReceive), + //wrappedBuffer); + buf); + } + catch (SocketException) + { + // something bad happened + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncBeginReceive()", + // Helpers.LogLevel.Error, se); + + // an error occurred, therefore the operation is void. Decrement the reference count. + Interlocked.Decrement(ref rwOperationCount); + } + } + + // we're done with the socket for now, release the reader lock. + rwLock.ReleaseReaderLock(); + } + + private void AsyncEndReceive(IAsyncResult iar) + { + // Asynchronous receive operations will complete here through the call + // to AsyncBeginReceive + + // aquire a reader lock + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + // get the buffer that was created in AsyncBeginReceive + // this is the received data + //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; + //UDPPacketBuffer buffer = wrappedBuffer.Instance; + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + + try + { + // get the length of data actually read from the socket, store it with the + // buffer + buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); + + // this operation is now complete, decrement the reference count + Interlocked.Decrement(ref rwOperationCount); + + // we're done with the socket, release the reader lock + rwLock.ReleaseReaderLock(); + + // call the abstract method PacketReceived(), passing the buffer that + // has just been filled from the socket read. + PacketReceived(buffer); + } + catch (SocketException) + { + // an error occurred, therefore the operation is void. Decrement the reference count. + Interlocked.Decrement(ref rwOperationCount); + + // we're done with the socket for now, release the reader lock. + rwLock.ReleaseReaderLock(); + } + finally + { + // start another receive - this keeps the server going! + AsyncBeginReceive(); + + //wrappedBuffer.Dispose(); + } + } + else + { + // nothing bad happened, but we are done with the operation + // decrement the reference count and release the reader lock + Interlocked.Decrement(ref rwOperationCount); + rwLock.ReleaseReaderLock(); + } + } + + public void AsyncBeginSend(UDPPacketBuffer buf) + { + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + try + { + Interlocked.Increment(ref rwOperationCount); + udpSocket.BeginSendTo( + buf.Data, + 0, + buf.DataLength, + SocketFlags.None, + buf.RemoteEndPoint, + new AsyncCallback(AsyncEndSend), + buf); + } + catch (SocketException) + { + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncBeginSend()", + // Helpers.LogLevel.Error, se); + } + } + + rwLock.ReleaseReaderLock(); + } + + private void AsyncEndSend(IAsyncResult iar) + { + rwLock.AcquireReaderLock(-1); + + if (!shutdownFlag) + { + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + + try + { + int bytesSent = udpSocket.EndSendTo(iar); + + // note that call to the abstract PacketSent() method - we are passing the number + // of bytes sent in a separate parameter, since we can't use buffer.DataLength which + // is the number of bytes to send (or bytes received depending upon whether this + // buffer was part of a send or a receive). + PacketSent(buffer, bytesSent); + } + catch (SocketException) + { + //Logger.Log( + // "A SocketException occurred in UDPServer.AsyncEndSend()", + // Helpers.LogLevel.Error, se); + } + } + + Interlocked.Decrement(ref rwOperationCount); + rwLock.ReleaseReaderLock(); + } + } +} From bec4d0c564a0ed421a021d1446f2851a07517381 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Oct 2009 16:54:50 +0100 Subject: [PATCH 04/19] fix test suite (and hopefully the panda build) by commenting out LindenUDP.Tests.dll references --- .nant/local.include | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.nant/local.include b/.nant/local.include index f78c6a6987..266864b7e8 100644 --- a/.nant/local.include +++ b/.nant/local.include @@ -58,10 +58,12 @@ + @@ -115,16 +117,18 @@ + @@ -238,10 +242,12 @@ + From 1c220e173c37d835542983898dc01b004112b4a9 Mon Sep 17 00:00:00 2001 From: Rob Smart Date: Fri, 9 Oct 2009 16:13:55 +0100 Subject: [PATCH 05/19] Adding a hair item to the default wearables, fixes newly created avatars appearing as a cloud --- OpenSim/Framework/AvatarAppearance.cs | 4 ++++ OpenSim/Framework/AvatarWearable.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 3f4214e580..56fcc150aa 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -66,6 +66,8 @@ namespace OpenSim.Framework private static UUID SHIRT_ITEM = new UUID("77c41e39-38f9-f75a-0000-585989bf0000"); private static UUID PANTS_ASSET = new UUID("00000000-38f9-1111-024e-222222111120"); private static UUID PANTS_ITEM = new UUID("77c41e39-38f9-f75a-0000-5859892f1111"); + private static UUID HAIR_ASSET = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66"); + private static UUID HAIR_ITEM = new UUID("d342e6c1-b9d2-11dc-95ff-0800200c9a66"); public readonly static int VISUALPARAM_COUNT = 218; @@ -238,6 +240,8 @@ namespace OpenSim.Framework m_wearables[BODY].ItemID = BODY_ITEM; m_wearables[SKIN].AssetID = SKIN_ASSET; m_wearables[SKIN].ItemID = SKIN_ITEM; + m_wearables[HAIR].AssetID = HAIR_ASSET; + m_wearables[HAIR].ItemID = HAIR_ITEM; m_wearables[SHIRT].AssetID = SHIRT_ASSET; m_wearables[SHIRT].ItemID = SHIRT_ITEM; m_wearables[PANTS].AssetID = PANTS_ASSET; diff --git a/OpenSim/Framework/AvatarWearable.cs b/OpenSim/Framework/AvatarWearable.cs index 4a5253ceb3..87d9e617b8 100644 --- a/OpenSim/Framework/AvatarWearable.cs +++ b/OpenSim/Framework/AvatarWearable.cs @@ -60,6 +60,10 @@ namespace OpenSim.Framework // Body defaultWearables[0].ItemID = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9"); defaultWearables[0].AssetID = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); + + // Hair + defaultWearables[2].ItemID = new UUID("d342e6c1-b9d2-11dc-95ff-0800200c9a66"); + defaultWearables[2].AssetID = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66"); // Skin defaultWearables[1].ItemID = new UUID("77c41e39-38f9-f75a-024e-585989bfabc9"); From b6678faf3499c85cbe4e1655acc907e29c30eb59 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Oct 2009 17:28:16 +0100 Subject: [PATCH 06/19] * Apply http://opensimulator.org/mantis/view.php?id=3933 * Remove client servers when regions are closed or removed * Thanks randomhuman! --- OpenSim/Region/Application/OpenSimBase.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 4592c318b5..3df3a1cb47 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -459,7 +459,8 @@ namespace OpenSim scene.DeleteAllSceneObjects(); m_sceneManager.CloseScene(scene); - + ShutdownClientServer(scene.RegionInfo); + if (!cleanup) return; @@ -519,7 +520,7 @@ namespace OpenSim } m_sceneManager.CloseScene(scene); - + ShutdownClientServer(scene.RegionInfo); } /// @@ -653,12 +654,10 @@ namespace OpenSim storageManager, m_moduleLoader, false, m_configSettings.PhysicalPrim, m_configSettings.See_into_region_from_neighbor, m_config.Source, m_version); } - - public void handleRestartRegion(RegionInfo whichRegion) + + protected void ShutdownClientServer(RegionInfo whichRegion) { - m_log.Info("[OPENSIM]: Got restart signal from SceneManager"); - - // Shutting down the client server + // Close and remove the clientserver for a region bool foundClientServer = false; int clientServerElement = 0; Location location = new Location(whichRegion.RegionHandle); @@ -678,6 +677,13 @@ namespace OpenSim m_clientServers[clientServerElement].NetworkStop(); m_clientServers.RemoveAt(clientServerElement); } + } + + public void handleRestartRegion(RegionInfo whichRegion) + { + m_log.Info("[OPENSIM]: Got restart signal from SceneManager"); + + ShutdownClientServer(whichRegion); IScene scene; CreateRegion(whichRegion, true, out scene); } From f1f239758f10ee4dfa1360a5fc0aa98d025f9035 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Oct 2009 17:43:25 +0100 Subject: [PATCH 07/19] Apply http://opensimulator.org/mantis/view.php?id=4066 If XEngine compile fails, show script name in error message in-world as well as the exception itself Thanks Luca Peck --- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index e6951337e6..847da8c194 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -642,7 +642,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptErrorMessage += "Failed to compile script in object: '" + part.ParentGroup.RootPart.Name + "' Script name: '" + item.Name + "' Error message: " + e.Message.ToString(); m_ScriptFailCount++; - string text = "Error compiling script:\n" + e.Message.ToString(); + string text = "Error compiling script '" + item.Name + "':\n" + e.Message.ToString(); if (text.Length > 1000) text = text.Substring(0, 1000); World.SimChat(Utils.StringToBytes(text), From 16a9a2604bbb258de9b2c3589d1551a357704204 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Oct 2009 18:19:51 +0100 Subject: [PATCH 08/19] Remove another lindenudp tests reference. Maybe this will make panda happy --- .nant/local.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nant/local.include b/.nant/local.include index 266864b7e8..5e02665f2a 100644 --- a/.nant/local.include +++ b/.nant/local.include @@ -277,7 +277,7 @@ - + From 8231cb22316e9492dd9e295ac9156689bede2ec3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Oct 2009 11:32:53 -0700 Subject: [PATCH 09/19] Putting this to exactly what it was yesterday around this time, so we can do the 100-ppl load test in WP. We need to carefully play with this code in order to understand all the problems. --- .../LindenUDP/LLUDPClientCollection.cs | 18 +- .../ClientStack/LindenUDP/OpenSimUDPBase.cs | 575 ++++++++++++------ 2 files changed, 411 insertions(+), 182 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index dbb9861acc..784426fb61 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -247,16 +247,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP ////return success; - lock (m_sync) - return Dictionary2.TryGetValue(key, out value); - - //try - //{ + //lock (m_sync) // return Dictionary2.TryGetValue(key, out value); - //} - //catch { } - //value = null; - //return false; + + try + { + return Dictionary2.TryGetValue(key, out value); + } + catch { } + value = null; + return false; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs index 218aaacc78..43a68ec98e 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs @@ -1,29 +1,30 @@ -/* - * Copyright (c) 2006, Clutch, Inc. - * Original Author: Jeff Cesnik - * All rights reserved. - * - * - 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. - * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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. - */ +//--------- Modified Version ------------------- +///* +// * Copyright (c) 2006, Clutch, Inc. +// * Original Author: Jeff Cesnik +// * All rights reserved. +// * +// * - 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. +// * - Neither the name of the openmetaverse.org 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 System.Net; @@ -31,6 +32,317 @@ using System.Net.Sockets; using System.Threading; using OpenMetaverse; +//namespace OpenSim.Region.ClientStack.LindenUDP +//{ +// /// +// /// +// /// +// public abstract class OpenSimUDPBase +// { +// // these abstract methods must be implemented in a derived class to actually do +// // something with the packets that are sent and received. +// protected abstract void PacketReceived(UDPPacketBuffer buffer); +// protected abstract void PacketSent(UDPPacketBuffer buffer, int bytesSent); + +// // the port to listen on +// internal int udpPort; + +// // the UDP socket +// private Socket udpSocket; + +// // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). +// // since there are potentially many "reader" threads in the internal .NET IOCP +// // thread pool, this is a cheaper synchronization primitive than using +// // a Mutex object. This allows many UDP socket "reads" concurrently - when +// // Stop() is called, it attempts to obtain a writer lock which will then +// // wait until all outstanding operations are completed before shutting down. +// // this avoids the problem of closing the socket with outstanding operations +// // and trying to catch the inevitable ObjectDisposedException. +// private ReaderWriterLock rwLock = new ReaderWriterLock(); + +// // number of outstanding operations. This is a reference count +// // which we use to ensure that the threads exit cleanly. Note that +// // we need this because the threads will potentially still need to process +// // data even after the socket is closed. +// private int rwOperationCount = 0; + +// // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. +// private volatile bool shutdownFlag = true; + +// // the remote endpoint to communicate with +// protected IPEndPoint remoteEndPoint = null; + + +// /// +// /// Initialize the UDP packet handler in server mode +// /// +// /// Port to listening for incoming UDP packets on +// public OpenSimUDPBase(int port) +// { +// udpPort = port; +// } + +// /// +// /// Initialize the UDP packet handler in client mode +// /// +// /// Remote UDP server to connect to +// public OpenSimUDPBase(IPEndPoint endPoint) +// { +// remoteEndPoint = endPoint; +// udpPort = 0; +// } + +// /// +// /// +// /// +// public void Start() +// { +// if (shutdownFlag) +// { +// if (remoteEndPoint == null) +// { +// // Server mode + +// // create and bind the socket +// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); +// udpSocket = new Socket( +// AddressFamily.InterNetwork, +// SocketType.Dgram, +// ProtocolType.Udp); +// udpSocket.Bind(ipep); +// } +// else +// { +// // Client mode +// IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); +// udpSocket = new Socket( +// AddressFamily.InterNetwork, +// SocketType.Dgram, +// ProtocolType.Udp); +// udpSocket.Bind(ipep); +// //udpSocket.Connect(remoteEndPoint); +// } + +// // we're not shutting down, we're starting up +// shutdownFlag = false; + +// // kick off an async receive. The Start() method will return, the +// // actual receives will occur asynchronously and will be caught in +// // AsyncEndRecieve(). +// AsyncBeginReceive(); +// } +// } + +// /// +// /// +// /// +// public void Stop() +// { +// if (!shutdownFlag) +// { +// // wait indefinitely for a writer lock. Once this is called, the .NET runtime +// // will deny any more reader locks, in effect blocking all other send/receive +// // threads. Once we have the lock, we set shutdownFlag to inform the other +// // threads that the socket is closed. +// rwLock.AcquireWriterLock(-1); +// shutdownFlag = true; +// udpSocket.Close(); +// rwLock.ReleaseWriterLock(); + +// // wait for any pending operations to complete on other +// // threads before exiting. +// const int FORCE_STOP = 100; +// int i = 0; +// while (rwOperationCount > 0 && i < FORCE_STOP) +// { +// Thread.Sleep(10); +// ++i; +// } + +// if (i >= FORCE_STOP) +// { +// Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", +// Helpers.LogLevel.Warning); +// } +// } +// } + +// /// +// /// +// /// +// public bool IsRunning +// { +// get { return !shutdownFlag; } +// } + +// private void AsyncBeginReceive() +// { +// // this method actually kicks off the async read on the socket. +// // we aquire a reader lock here to ensure that no other thread +// // is trying to set shutdownFlag and close the socket. +// rwLock.AcquireReaderLock(-1); + +// if (!shutdownFlag) +// { +// // increment the count of pending operations +// Interlocked.Increment(ref rwOperationCount); + +// // allocate a packet buffer +// //WrappedObject wrappedBuffer = Pool.CheckOut(); +// UDPPacketBuffer buf = new UDPPacketBuffer(); + +// try +// { +// // kick off an async read +// udpSocket.BeginReceiveFrom( +// //wrappedBuffer.Instance.Data, +// buf.Data, +// 0, +// UDPPacketBuffer.BUFFER_SIZE, +// SocketFlags.None, +// //ref wrappedBuffer.Instance.RemoteEndPoint, +// ref buf.RemoteEndPoint, +// new AsyncCallback(AsyncEndReceive), +// //wrappedBuffer); +// buf); +// } +// catch (SocketException) +// { +// // something bad happened +// //Logger.Log( +// // "A SocketException occurred in UDPServer.AsyncBeginReceive()", +// // Helpers.LogLevel.Error, se); + +// // an error occurred, therefore the operation is void. Decrement the reference count. +// Interlocked.Decrement(ref rwOperationCount); +// } +// } + +// // we're done with the socket for now, release the reader lock. +// rwLock.ReleaseReaderLock(); +// } + +// private void AsyncEndReceive(IAsyncResult iar) +// { +// // Asynchronous receive operations will complete here through the call +// // to AsyncBeginReceive + +// // aquire a reader lock +// rwLock.AcquireReaderLock(-1); + +// if (!shutdownFlag) +// { +// // get the buffer that was created in AsyncBeginReceive +// // this is the received data +// //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; +// //UDPPacketBuffer buffer = wrappedBuffer.Instance; +// UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + +// try +// { +// // get the length of data actually read from the socket, store it with the +// // buffer +// buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); + +// // this operation is now complete, decrement the reference count +// Interlocked.Decrement(ref rwOperationCount); + +// // we're done with the socket, release the reader lock +// rwLock.ReleaseReaderLock(); + +// // call the abstract method PacketReceived(), passing the buffer that +// // has just been filled from the socket read. +// PacketReceived(buffer); +// } +// catch (SocketException) +// { +// // an error occurred, therefore the operation is void. Decrement the reference count. +// Interlocked.Decrement(ref rwOperationCount); + +// // we're done with the socket for now, release the reader lock. +// rwLock.ReleaseReaderLock(); +// } +// finally +// { +// // start another receive - this keeps the server going! +// AsyncBeginReceive(); + +// //wrappedBuffer.Dispose(); +// } +// } +// else +// { +// // nothing bad happened, but we are done with the operation +// // decrement the reference count and release the reader lock +// Interlocked.Decrement(ref rwOperationCount); +// rwLock.ReleaseReaderLock(); +// } +// } + +// public void AsyncBeginSend(UDPPacketBuffer buf) +// { +// rwLock.AcquireReaderLock(-1); + +// if (!shutdownFlag) +// { +// try +// { +// Interlocked.Increment(ref rwOperationCount); +// udpSocket.BeginSendTo( +// buf.Data, +// 0, +// buf.DataLength, +// SocketFlags.None, +// buf.RemoteEndPoint, +// new AsyncCallback(AsyncEndSend), +// buf); +// } +// catch (SocketException) +// { +// //Logger.Log( +// // "A SocketException occurred in UDPServer.AsyncBeginSend()", +// // Helpers.LogLevel.Error, se); +// } +// } + +// rwLock.ReleaseReaderLock(); +// } + +// private void AsyncEndSend(IAsyncResult iar) +// { +// rwLock.AcquireReaderLock(-1); + +// if (!shutdownFlag) +// { +// UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + +// try +// { +// int bytesSent = udpSocket.EndSendTo(iar); + +// // note that call to the abstract PacketSent() method - we are passing the number +// // of bytes sent in a separate parameter, since we can't use buffer.DataLength which +// // is the number of bytes to send (or bytes received depending upon whether this +// // buffer was part of a send or a receive). +// PacketSent(buffer, bytesSent); +// } +// catch (SocketException) +// { +// //Logger.Log( +// // "A SocketException occurred in UDPServer.AsyncEndSend()", +// // Helpers.LogLevel.Error, se); +// } +// } + +// Interlocked.Decrement(ref rwOperationCount); +// rwLock.ReleaseReaderLock(); +// } +// } +//} + +//--------- Original Version ------------------- + + namespace OpenSim.Region.ClientStack.LindenUDP { /// @@ -49,29 +361,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // the UDP socket private Socket udpSocket; - // the ReaderWriterLock is used solely for the purposes of shutdown (Stop()). - // since there are potentially many "reader" threads in the internal .NET IOCP - // thread pool, this is a cheaper synchronization primitive than using - // a Mutex object. This allows many UDP socket "reads" concurrently - when - // Stop() is called, it attempts to obtain a writer lock which will then - // wait until all outstanding operations are completed before shutting down. - // this avoids the problem of closing the socket with outstanding operations - // and trying to catch the inevitable ObjectDisposedException. - private ReaderWriterLock rwLock = new ReaderWriterLock(); - - // number of outstanding operations. This is a reference count - // which we use to ensure that the threads exit cleanly. Note that - // we need this because the threads will potentially still need to process - // data even after the socket is closed. - private int rwOperationCount = 0; - - // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. + // the all important shutdownFlag. private volatile bool shutdownFlag = true; // the remote endpoint to communicate with protected IPEndPoint remoteEndPoint = null; - /// /// Initialize the UDP packet handler in server mode /// @@ -98,29 +393,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (shutdownFlag) { - if (remoteEndPoint == null) - { - // Server mode + const int SIO_UDP_CONNRESET = -1744830452; - // create and bind the socket - IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); - udpSocket = new Socket( - AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp); - udpSocket.Bind(ipep); - } - else + IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); + udpSocket = new Socket( + AddressFamily.InterNetwork, + SocketType.Dgram, + ProtocolType.Udp); + try { - // Client mode - IPEndPoint ipep = new IPEndPoint(Settings.BIND_ADDR, udpPort); - udpSocket = new Socket( - AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp); - udpSocket.Bind(ipep); - //udpSocket.Connect(remoteEndPoint); + // this udp socket flag is not supported under mono, + // so we'll catch the exception and continue + udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); } + catch (SocketException) + { + Logger.DebugLog("UDP SIO_UDP_CONNRESET flag not supported on this platform"); + } + udpSocket.Bind(ipep); // we're not shutting down, we're starting up shutdownFlag = false; @@ -143,26 +433,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // will deny any more reader locks, in effect blocking all other send/receive // threads. Once we have the lock, we set shutdownFlag to inform the other // threads that the socket is closed. - rwLock.AcquireWriterLock(-1); shutdownFlag = true; udpSocket.Close(); - rwLock.ReleaseWriterLock(); - - // wait for any pending operations to complete on other - // threads before exiting. - const int FORCE_STOP = 100; - int i = 0; - while (rwOperationCount > 0 && i < FORCE_STOP) - { - Thread.Sleep(10); - ++i; - } - - if (i >= FORCE_STOP) - { - Logger.Log("UDPBase.Stop() forced shutdown while waiting on pending operations", - Helpers.LogLevel.Warning); - } } } @@ -176,20 +448,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void AsyncBeginReceive() { - // this method actually kicks off the async read on the socket. - // we aquire a reader lock here to ensure that no other thread - // is trying to set shutdownFlag and close the socket. - rwLock.AcquireReaderLock(-1); + // allocate a packet buffer + //WrappedObject wrappedBuffer = Pool.CheckOut(); + UDPPacketBuffer buf = new UDPPacketBuffer(); if (!shutdownFlag) { - // increment the count of pending operations - Interlocked.Increment(ref rwOperationCount); - - // allocate a packet buffer - //WrappedObject wrappedBuffer = Pool.CheckOut(); - UDPPacketBuffer buf = new UDPPacketBuffer(); - try { // kick off an async read @@ -199,38 +463,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP 0, UDPPacketBuffer.BUFFER_SIZE, SocketFlags.None, - //ref wrappedBuffer.Instance.RemoteEndPoint, ref buf.RemoteEndPoint, - new AsyncCallback(AsyncEndReceive), + AsyncEndReceive, //wrappedBuffer); buf); } - catch (SocketException) + catch (SocketException e) { - // something bad happened - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncBeginReceive()", - // Helpers.LogLevel.Error, se); + if (e.SocketErrorCode == SocketError.ConnectionReset) + { + Logger.Log("SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + udpPort, Helpers.LogLevel.Error); + bool salvaged = false; + while (!salvaged) + { + try + { + udpSocket.BeginReceiveFrom( + //wrappedBuffer.Instance.Data, + buf.Data, + 0, + UDPPacketBuffer.BUFFER_SIZE, + SocketFlags.None, + ref buf.RemoteEndPoint, + AsyncEndReceive, + //wrappedBuffer); + buf); + salvaged = true; + } + catch (SocketException) { } + catch (ObjectDisposedException) { return; } + } - // an error occurred, therefore the operation is void. Decrement the reference count. - Interlocked.Decrement(ref rwOperationCount); + Logger.Log("Salvaged the UDP listener on port " + udpPort, Helpers.LogLevel.Info); + } } + catch (ObjectDisposedException) { } } - - // we're done with the socket for now, release the reader lock. - rwLock.ReleaseReaderLock(); } private void AsyncEndReceive(IAsyncResult iar) { // Asynchronous receive operations will complete here through the call // to AsyncBeginReceive - - // aquire a reader lock - rwLock.AcquireReaderLock(-1); - if (!shutdownFlag) { + // start another receive - this keeps the server going! + AsyncBeginReceive(); + // get the buffer that was created in AsyncBeginReceive // this is the received data //WrappedObject wrappedBuffer = (WrappedObject)iar.AsyncState; @@ -243,98 +522,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP // buffer buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); - // this operation is now complete, decrement the reference count - Interlocked.Decrement(ref rwOperationCount); - - // we're done with the socket, release the reader lock - rwLock.ReleaseReaderLock(); - // call the abstract method PacketReceived(), passing the buffer that // has just been filled from the socket read. PacketReceived(buffer); } - catch (SocketException) - { - // an error occurred, therefore the operation is void. Decrement the reference count. - Interlocked.Decrement(ref rwOperationCount); - - // we're done with the socket for now, release the reader lock. - rwLock.ReleaseReaderLock(); - } - finally - { - // start another receive - this keeps the server going! - AsyncBeginReceive(); - - //wrappedBuffer.Dispose(); - } - } - else - { - // nothing bad happened, but we are done with the operation - // decrement the reference count and release the reader lock - Interlocked.Decrement(ref rwOperationCount); - rwLock.ReleaseReaderLock(); + catch (SocketException) { } + catch (ObjectDisposedException) { } + //finally { wrappedBuffer.Dispose(); } } } public void AsyncBeginSend(UDPPacketBuffer buf) { - rwLock.AcquireReaderLock(-1); - if (!shutdownFlag) { try { - Interlocked.Increment(ref rwOperationCount); udpSocket.BeginSendTo( buf.Data, 0, buf.DataLength, SocketFlags.None, buf.RemoteEndPoint, - new AsyncCallback(AsyncEndSend), + AsyncEndSend, buf); } - catch (SocketException) - { - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncBeginSend()", - // Helpers.LogLevel.Error, se); - } + catch (SocketException) { } + catch (ObjectDisposedException) { } } - - rwLock.ReleaseReaderLock(); } - private void AsyncEndSend(IAsyncResult iar) + void AsyncEndSend(IAsyncResult result) { - rwLock.AcquireReaderLock(-1); - - if (!shutdownFlag) + try { - UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; + int bytesSent = udpSocket.EndSendTo(result); - try - { - int bytesSent = udpSocket.EndSendTo(iar); - - // note that call to the abstract PacketSent() method - we are passing the number - // of bytes sent in a separate parameter, since we can't use buffer.DataLength which - // is the number of bytes to send (or bytes received depending upon whether this - // buffer was part of a send or a receive). - PacketSent(buffer, bytesSent); - } - catch (SocketException) - { - //Logger.Log( - // "A SocketException occurred in UDPServer.AsyncEndSend()", - // Helpers.LogLevel.Error, se); - } + PacketSent(buf, bytesSent); } - - Interlocked.Decrement(ref rwOperationCount); - rwLock.ReleaseReaderLock(); + catch (SocketException) { } + catch (ObjectDisposedException) { } } } } + From c146f2c8c4eb60d063196972d5c0dd2ec550b27e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Oct 2009 13:49:55 -0700 Subject: [PATCH 10/19] Use the cache, Luke! --- .../Communications/CommunicationsManager.cs | 33 +++++-------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs index 2410f31901..9c028424a3 100644 --- a/OpenSim/Framework/Communications/CommunicationsManager.cs +++ b/OpenSim/Framework/Communications/CommunicationsManager.cs @@ -210,34 +210,17 @@ namespace OpenSim.Framework.Communications private string[] doUUIDNameRequest(UUID uuid) { string[] returnstring = new string[0]; - bool doLookup = false; + CachedUserInfo uinfo = UserProfileCacheService.GetUserDetails(uuid); - lock (m_nameRequestCache) + if ((uinfo != null) && (uinfo.UserProfile != null)) { - if (m_nameRequestCache.ContainsKey(uuid)) + returnstring = new string[2]; + returnstring[0] = uinfo.UserProfile.FirstName; + returnstring[1] = uinfo.UserProfile.SurName; + lock (m_nameRequestCache) { - returnstring = m_nameRequestCache[uuid]; - } - else - { - // we don't want to lock the dictionary while we're doing the lookup - doLookup = true; - } - } - - if (doLookup) { - UserProfileData profileData = m_userService.GetUserProfile(uuid); - if (profileData != null) - { - returnstring = new string[2]; - // UUID profileId = profileData.ID; - returnstring[0] = profileData.FirstName; - returnstring[1] = profileData.SurName; - lock (m_nameRequestCache) - { - if (!m_nameRequestCache.ContainsKey(uuid)) - m_nameRequestCache.Add(uuid, returnstring); - } + if (!m_nameRequestCache.ContainsKey(uuid)) + m_nameRequestCache.Add(uuid, returnstring); } } From c8cc14a98bbbe4d20949370b56912065957eed67 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Oct 2009 14:25:01 -0700 Subject: [PATCH 11/19] This is to *try* to avoid the exception we are seeing repeatedly: #13:53:03 - [LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag #13:53:03 - [Scene]: Failed with exception System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. # at System.Buffer.BlockCopy (System.Array src, Int32 srcOffset, System.Array dst, Int32 dstOffset, Int32 count) [0x000b7] in /home/grid/install/mono24/mono-2.4.2.3/mcs/class/corlib/System/Buffer.cs:116 # at OpenSim.Region.ClientStack.LindenUDP.LLUDPServer.SendPacketData (OpenSim.Region.ClientStack.LindenUDP.LLUDPClient client, System.Byte[] data, Int32 dataLength, PacketType type, Boolean doZerocode, ThrottleOutPacketType category) [0x00060] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs:290 # at OpenSim.Region.ClientStack.LindenUDP.LLUDPServer.SendPacket (OpenSim.Region.ClientStack.LindenUDP.LLUDPClient client, OpenMetaverse.Packets.Packet packet, ThrottleOutPacketType category, Boolean allowSplitting) [0x00077] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs:265 # at OpenSim.Region.ClientStack.LindenUDP.LLClientView.OutPacket (OpenMetaverse.Packets.Packet packet, ThrottleOutPacketType throttlePacketType) [0x00000] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs:5244 # at OpenSim.Region.ClientStack.LindenUDP.LLClientView.SendCoarseLocationUpdate (System.Collections.Generic.List`1 users, System.Collections.Generic.List`1 CoarseLocations) [0x0012a] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs:3424 # at OpenSim.Region.Framework.Scenes.ScenePresence.SendCoarseLocationsDefault (UUID sceneId, OpenSim.Region.Framework.Scenes.ScenePresence p) [0x000fa] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/Framework/Scenes/ScenePresence.cs:2536 # at OpenSim.Region.Framework.Scenes.ScenePresence.SendCoarseLocations () [0x0000d] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/Framework/Scenes/ScenePresence.cs:2491 # at OpenSim.Region.Framework.Scenes.ScenePresence.Update () [0x00011] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/Framework/Scenes/ScenePresence.cs:2404 # at OpenSim.Region.Framework.Scenes.SceneGraph.UpdateEntities () [0x0001b] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/Framework/Scenes/SceneGraph.cs:164 # at OpenSim.Region.Framework.Scenes.Scene.Update () [0x000dc] in /home/grid/PLAZA/wrightplaza/opensim/OpenSim/Region/Framework/Scenes/Scene.cs:1031 On Region: Wright Plaza --- OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 1e6927fadf..03902770ed 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -287,11 +287,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP // instead m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); + // + buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength); + // Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } } else { + // ??? will it fit? Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } buffer.DataLength = dataLength; From f29bd8036dac4e3129b937cceda9606d496a20b7 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Oct 2009 14:36:08 -0700 Subject: [PATCH 12/19] A slight improvement on name fetching -- using the local name cache, since it exists. --- OpenSim/Framework/Communications/CommunicationsManager.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs index 9c028424a3..4bf9018862 100644 --- a/OpenSim/Framework/Communications/CommunicationsManager.cs +++ b/OpenSim/Framework/Communications/CommunicationsManager.cs @@ -209,6 +209,12 @@ namespace OpenSim.Framework.Communications private string[] doUUIDNameRequest(UUID uuid) { + lock (m_nameRequestCache) + { + if (m_nameRequestCache.ContainsKey(uuid)) + return m_nameRequestCache[uuid]; + } + string[] returnstring = new string[0]; CachedUserInfo uinfo = UserProfileCacheService.GetUserDetails(uuid); From 3f78ff6ee0837c0179be5f43d485d9ca23ee454b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Oct 2009 19:16:03 -0700 Subject: [PATCH 13/19] Slight variation on the locking scheme: now locking always, except the ForEach, which gets a copy of the Array. I think the ForEach was the big gorilla. --- .../LindenUDP/LLUDPClientCollection.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs index 784426fb61..dbb9861acc 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClientCollection.cs @@ -247,16 +247,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP ////return success; - //lock (m_sync) - // return Dictionary2.TryGetValue(key, out value); - - try - { + lock (m_sync) return Dictionary2.TryGetValue(key, out value); - } - catch { } - value = null; - return false; + + //try + //{ + // return Dictionary2.TryGetValue(key, out value); + //} + //catch { } + //value = null; + //return false; } From 798bce592f7c467bbfdf2be8820d626520f378dc Mon Sep 17 00:00:00 2001 From: "Teravus Ovares (Dan Olivares)" Date: Sat, 10 Oct 2009 01:16:34 -0400 Subject: [PATCH 14/19] * Move the 'On Collision Update Movement Animation' routine to above the 'm_invulnerable' test. It doesn't fix anything but it should really be there anyway. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 3996cdcaaa..0352c64f6c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3417,7 +3417,13 @@ namespace OpenSim.Region.Framework.Scenes // Event called by the physics plugin to tell the avatar about a collision. private void PhysicsCollisionUpdate(EventArgs e) { - if ((e == null) || m_invulnerable) + if (e == null) + return; + + if (Velocity.X > 0 || Velocity.Y > 0) + UpdateMovementAnimations(); + + if (m_invulnerable) return; CollisionEventUpdate collisionData = (CollisionEventUpdate)e; Dictionary coldata = collisionData.m_objCollisionList; @@ -3455,8 +3461,7 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerAvatarKill(killerObj, this); } - if (Velocity.X > 0 || Velocity.Y > 0) - UpdateMovementAnimations(); + } public void setHealthWithUpdate(float health) From 5f94889044656211d05b62c7253b1aad19a23eab Mon Sep 17 00:00:00 2001 From: "Teravus Ovares (Dan Olivares)" Date: Sat, 10 Oct 2009 01:49:06 -0400 Subject: [PATCH 15/19] * Fix incorrect math on the Velocity check in PhysicsCollisionUpdate. This may reduce avatar flailing. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 0352c64f6c..af85424ba3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3420,7 +3420,7 @@ namespace OpenSim.Region.Framework.Scenes if (e == null) return; - if (Velocity.X > 0 || Velocity.Y > 0) + if ((Math.Abs(Velocity.X) > 0.05f) || (Math.Abs(Velocity.Y) > 0.05f)) UpdateMovementAnimations(); if (m_invulnerable) From d7654c3bda9c6fea93ddc258b00e41eb568faa18 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 10 Oct 2009 00:26:43 -0700 Subject: [PATCH 16/19] Adjust velocity threshold for triggering flailing. Thanks to KittoFlora for researching this. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index af85424ba3..7ea9314115 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3420,7 +3420,7 @@ namespace OpenSim.Region.Framework.Scenes if (e == null) return; - if ((Math.Abs(Velocity.X) > 0.05f) || (Math.Abs(Velocity.Y) > 0.05f)) + if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) UpdateMovementAnimations(); if (m_invulnerable) From 4ffe936ba837eb47dc235317a54f5fa16af514ce Mon Sep 17 00:00:00 2001 From: "Teravus Ovares (Dan Olivares)" Date: Sat, 10 Oct 2009 03:53:53 -0400 Subject: [PATCH 17/19] * Make ODECharacter respect the scene's requested collision update time * Set the Scene collision update time to 500 ms --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 15 +++++++++++++-- OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index af85424ba3..e9040e97dc 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3409,7 +3409,7 @@ namespace OpenSim.Region.Framework.Scenes scene.AddPhysicsActorTaint(m_physicsActor); //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; - m_physicsActor.SubscribeEvents(1000); + m_physicsActor.SubscribeEvents(500); m_physicsActor.LocalID = LocalId; } diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index a00ba11d14..7a86b6ef9b 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -98,6 +98,7 @@ namespace OpenSim.Region.Physics.OdePlugin private bool m_alwaysRun = false; private bool m_hackSentFall = false; private bool m_hackSentFly = false; + private int m_requestedUpdateFrequency = 0; private PhysicsVector m_taintPosition = new PhysicsVector(0, 0, 0); public uint m_localID = 0; public bool m_returnCollisions = false; @@ -1184,26 +1185,31 @@ namespace OpenSim.Region.Physics.OdePlugin public override void SubscribeEvents(int ms) { + m_requestedUpdateFrequency = ms; m_eventsubscription = ms; _parent_scene.addCollisionEventReporting(this); } public override void UnSubscribeEvents() { _parent_scene.remCollisionEventReporting(this); + m_requestedUpdateFrequency = 0; m_eventsubscription = 0; } public void AddCollisionEvent(uint CollidedWith, float depth) { if (m_eventsubscription > 0) - CollisionEventsThisFrame.addCollider(CollidedWith,depth); + { + CollisionEventsThisFrame.addCollider(CollidedWith, depth); + } } public void SendCollisions() { - if (m_eventsubscription > 0) + if (m_eventsubscription > m_requestedUpdateFrequency) { base.SendCollisionUpdate(CollisionEventsThisFrame); CollisionEventsThisFrame = new CollisionEventUpdate(); + m_eventsubscription = 0; } } public override bool SubscribedEvents() @@ -1309,5 +1315,10 @@ namespace OpenSim.Region.Physics.OdePlugin } } + + internal void AddCollisionFrameTime(int p) + { + m_eventsubscription += p; + } } } diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index f5ab1de1e8..083b7db37f 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2928,6 +2928,7 @@ namespace OpenSim.Region.Physics.OdePlugin { case ActorTypes.Agent: OdeCharacter cobj = (OdeCharacter)obj; + cobj.AddCollisionFrameTime(100); cobj.SendCollisions(); break; case ActorTypes.Prim: From 8271528b1fe49d99cf5b64d3644864ba4aa097c1 Mon Sep 17 00:00:00 2001 From: "Teravus Ovares (Dan Olivares)" Date: Sat, 10 Oct 2009 04:01:36 -0400 Subject: [PATCH 18/19] * comment out the velocity test, using updates every 500 ms as set in ScenePresence.AddToPhysicalScene. * This causes time to be counted in ODECharacter and, when a collision occurs, the physics scene will report the collisions only if the the difference of last time it reported the collisions from now was more then the set ms. * This is cool because the time accrues while collisions are not taking place and when they do take place again, you get an immediate update. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 ++++-- OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index e20b8f2d6d..15fb11f19b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3420,8 +3420,10 @@ namespace OpenSim.Region.Framework.Scenes if (e == null) return; - if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) - UpdateMovementAnimations(); + //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) + // The Physics Scene will send updates every 500 ms grep: m_physicsActor.SubscribeEvents( + // as of this comment the interval is set in AddToPhysicalScene + UpdateMovementAnimations(); if (m_invulnerable) return; diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 7a86b6ef9b..bd81d50f39 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -1318,6 +1318,9 @@ namespace OpenSim.Region.Physics.OdePlugin internal void AddCollisionFrameTime(int p) { + // protect it from overflow crashing + if (m_eventsubscription + p >= int.MaxValue) + m_eventsubscription = 0; m_eventsubscription += p; } } From ef03b2d936fe623029bc414f00e001f17aaa85bc Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 10 Oct 2009 10:18:16 +0100 Subject: [PATCH 19/19] Fix selling objects --- .../CoreModules/World/Permissions/PermissionsModule.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 901144a289..fe9de1b3c5 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -556,6 +556,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions // Customize the EveryoneMask uint objectEveryoneMask = ApplyObjectModifyMasks(task.EveryoneMask, objflags); + if (objectOwner != UUID.Zero) + objectEveryoneMask |= (uint)PrimFlags.ObjectAnyOwner; if (m_bypassPermissions) return objectOwnerMask; @@ -578,12 +580,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions { // Admin objects should not be editable by the above if (!IsAdministrator(objectOwner)) - return objectOwnerMask; + return objectOwnerMask; } - if ((objectOwnerMask & (uint)PermissionMask.Transfer) != 0 && task.ObjectSaleType != 0) - objectEveryoneMask |= (uint)PrimFlags.ObjectTransfer; - // Group permissions if ((task.GroupID != UUID.Zero) && IsGroupMember(task.GroupID, user, 0)) return objectGroupMask | objectEveryoneMask;