diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index 3efab8e7ec..5e89c388f4 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -141,6 +141,11 @@ namespace OpenSim.Framework.Capabilities
m_capsActive.Reset();
}
+ ~Caps()
+ {
+ m_capsActive.Dispose();
+ }
+
///
/// Register a handler. This allows modules to register handlers.
///
diff --git a/OpenSim/Framework/AgentUpdateArgs.cs b/OpenSim/Framework/AgentUpdateArgs.cs
index eaa7902d8d..f04d692092 100644
--- a/OpenSim/Framework/AgentUpdateArgs.cs
+++ b/OpenSim/Framework/AgentUpdateArgs.cs
@@ -82,6 +82,7 @@ namespace OpenSim.Framework
public Vector3 ClientAgentPosition;
public bool UseClientAgentPosition;
public bool NeedsCameraCollision;
+ public uint lastpacketSequence;
public AgentUpdateArgs()
{
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs
index 4b88923875..9049b4b801 100644
--- a/OpenSim/Framework/Console/RemoteConsole.cs
+++ b/OpenSim/Framework/Console/RemoteConsole.cs
@@ -34,6 +34,7 @@ using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
+using System.Timers;
using OpenMetaverse;
using Nini.Config;
using OpenSim.Framework.Servers.HttpServer;
@@ -41,90 +42,232 @@ using log4net;
namespace OpenSim.Framework.Console
{
- public class ConsoleConnection
- {
- public int last;
- public long lastLineSeen;
- public bool newConnection = true;
- }
-
// A console that uses REST interfaces
//
public class RemoteConsole : CommandConsole
{
- private IHttpServer m_Server = null;
- private IConfigSource m_Config = null;
+ // Connection specific data, indexed by a session ID
+ // we create when a client connects.
+ protected class ConsoleConnection
+ {
+ // Last activity from the client
+ public int last;
- private List m_Scrollback = new List();
- private ManualResetEvent m_DataEvent = new ManualResetEvent(false);
- private List m_InputData = new List();
- private long m_LineNumber = 0;
- private Dictionary m_Connections =
+ // Last line of scrollback posted to this client
+ public long lastLineSeen;
+
+ // True if this is a new connection, e.g. has never
+ // displayed a prompt to the user.
+ public bool newConnection = true;
+ }
+
+ // A line in the scrollback buffer.
+ protected class ScrollbackEntry
+ {
+ // The line number of this entry
+ public long lineNumber;
+
+ // The text to send to the client
+ public string text;
+
+ // The level this should be logged as. Omitted for
+ // prompts and input echo.
+ public string level;
+
+ // True if the text above is a prompt, e.g. the
+ // client should turn on the cursor / accept input
+ public bool isPrompt;
+
+ // True if the requested input is a command. A
+ // client may offer help or validate input if
+ // this is set. If false, input should be sent
+ // as typed.
+ public bool isCommand;
+
+ // True if this text represents a line of text that
+ // was input in response to a prompt. A client should
+ // turn off the cursor and refrain from sending commands
+ // until a new prompt is received.
+ public bool isInput;
+ }
+
+ // Data that is relevant to all connections
+
+ // The scrollback buffer
+ protected List m_Scrollback = new List();
+
+ // Monotonously incrementing line number. This may eventually
+ // wrap. No provision is made for that case because 64 bits
+ // is a long, long time.
+ protected long m_lineNumber = 0;
+
+ // These two variables allow us to send the correct
+ // information about the prompt status to the client,
+ // irrespective of what may have run off the top of the
+ // scrollback buffer;
+ protected bool m_expectingInput = false;
+ protected bool m_expectingCommand = true;
+ protected string m_lastPromptUsed;
+
+ // This is the list of things received from clients.
+ // Note: Race conditions can happen. If a client sends
+ // something while nothing is expected, it will be
+ // intepreted as input to the next prompt. For
+ // commands this is largely correct. For other prompts,
+ // YMMV.
+ // TODO: Find a better way to fix this
+ protected List m_InputData = new List();
+
+ // Event to allow ReadLine to wait synchronously even though
+ // everthing else is asynchronous here.
+ protected ManualResetEvent m_DataEvent = new ManualResetEvent(false);
+
+ // The list of sessions we maintain. Unlike other console types,
+ // multiple users on the same console are explicitly allowed.
+ protected Dictionary m_Connections =
new Dictionary();
- private string m_UserName = String.Empty;
- private string m_Password = String.Empty;
- private string m_AllowedOrigin = String.Empty;
+
+ // Timer to control expiration of sessions that have been
+ // disconnected.
+ protected System.Timers.Timer m_expireTimer = new System.Timers.Timer(5000);
+
+ // The less interesting stuff that makes the actual server
+ // work.
+ protected IHttpServer m_Server = null;
+ protected IConfigSource m_Config = null;
+
+ protected string m_UserName = String.Empty;
+ protected string m_Password = String.Empty;
+ protected string m_AllowedOrigin = String.Empty;
+
public RemoteConsole(string defaultPrompt) : base(defaultPrompt)
{
+ // There is something wrong with this architecture.
+ // A prompt is sent on every single input, so why have this?
+ // TODO: Investigate and fix.
+ m_lastPromptUsed = defaultPrompt;
+
+ // Start expiration of sesssions.
+ m_expireTimer.Elapsed += DoExpire;
+ m_expireTimer.Start();
}
public void ReadConfig(IConfigSource config)
{
m_Config = config;
+ // We're pulling this from the 'Network' section for legacy
+ // compatibility. However, this is so essentially insecure
+ // that TLS and client certs should be used instead of
+ // a username / password.
IConfig netConfig = m_Config.Configs["Network"];
+
if (netConfig == null)
return;
+ // Get the username and password.
m_UserName = netConfig.GetString("ConsoleUser", String.Empty);
m_Password = netConfig.GetString("ConsolePass", String.Empty);
+
+ // Woefully underdocumented, this is what makes javascript
+ // console clients work. Set to "*" for anywhere or (better)
+ // to specific addresses.
m_AllowedOrigin = netConfig.GetString("ConsoleAllowedOrigin", String.Empty);
}
public void SetServer(IHttpServer server)
{
+ // This is called by the framework to give us the server
+ // instance (means: port) to work with.
m_Server = server;
+ // Add our handlers
m_Server.AddHTTPHandler("/StartSession/", HandleHttpStartSession);
m_Server.AddHTTPHandler("/CloseSession/", HandleHttpCloseSession);
m_Server.AddHTTPHandler("/SessionCommand/", HandleHttpSessionCommand);
}
public override void Output(string text, string level)
+ {
+ Output(text, level, false, false, false);
+ }
+
+ protected void Output(string text, string level, bool isPrompt, bool isCommand, bool isInput)
{
+ // Increment the line number. It was 0 and they start at 1
+ // so we need to pre-increment.
+ m_lineNumber++;
+
+ // Create and populate the new entry.
+ ScrollbackEntry newEntry = new ScrollbackEntry();
+
+ newEntry.lineNumber = m_lineNumber;
+ newEntry.text = text;
+ newEntry.level = level;
+ newEntry.isPrompt = isPrompt;
+ newEntry.isCommand = isCommand;
+ newEntry.isInput = isInput;
+
+ // Add a line to the scrollback. In some cases, that may not
+ // actually be a line of text.
lock (m_Scrollback)
{
+ // Prune the scrollback to the length se send as connect
+ // burst to give the user some context.
while (m_Scrollback.Count >= 1000)
m_Scrollback.RemoveAt(0);
- m_LineNumber++;
- m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text);
+
+ m_Scrollback.Add(newEntry);
}
+
+ // Let the rest of the system know we have output something.
FireOnOutput(text.Trim());
+
+ // Also display it for debugging.
System.Console.WriteLine(text.Trim());
}
public override void Output(string text)
{
- Output(text, "normal");
+ // Output plain (non-logging style) text.
+ Output(text, String.Empty, false, false, false);
}
public override string ReadLine(string p, bool isCommand, bool e)
{
- if (isCommand)
- Output("+++"+p);
- else
- Output("-++"+p);
+ // Output the prompt an prepare to wait. This
+ // is called on a dedicated console thread and
+ // needs to be synchronous. Old architecture but
+ // not worth upgrading.
+ if (isCommand)
+ {
+ m_expectingInput = true;
+ m_expectingCommand = true;
+ Output(p, String.Empty, true, true, false);
+ m_lastPromptUsed = p;
+ }
+ else
+ {
+ m_expectingInput = true;
+ Output(p, String.Empty, true, false, false);
+ }
+
+ // Here is where we wait for the user to input something.
m_DataEvent.WaitOne();
string cmdinput;
+ // Check for empty input. Read input if not empty.
lock (m_InputData)
{
if (m_InputData.Count == 0)
{
m_DataEvent.Reset();
+ m_expectingInput = false;
+ m_expectingCommand = false;
+
return "";
}
@@ -135,8 +278,19 @@ namespace OpenSim.Framework.Console
}
+ m_expectingInput = false;
+ m_expectingCommand = false;
+
+ // Echo to all the other users what we have done. This
+ // will also go to ourselves.
+ Output (cmdinput, String.Empty, false, false, true);
+
+ // If this is a command, we need to resolve and execute it.
if (isCommand)
{
+ // This call will actually execute the command and create
+ // any output associated with it. The core just gets an
+ // empty string so it will call again immediately.
string[] cmd = Commands.Resolve(Parser.Parse(cmdinput));
if (cmd.Length != 0)
@@ -151,18 +305,23 @@ namespace OpenSim.Framework.Console
return String.Empty;
}
}
+
+ // Return the raw input string if not a command.
return cmdinput;
}
- private Hashtable CheckOrigin(Hashtable result)
+ // Very simplistic static access control header.
+ protected Hashtable CheckOrigin(Hashtable result)
{
if (!string.IsNullOrEmpty(m_AllowedOrigin))
result["access_control_allow_origin"] = m_AllowedOrigin;
+
return result;
}
+
/* TODO: Figure out how PollServiceHTTPHandler can access the request headers
* in order to use m_AllowedOrigin as a regular expression
- private Hashtable CheckOrigin(Hashtable headers, Hashtable result)
+ protected Hashtable CheckOrigin(Hashtable headers, Hashtable result)
{
if (!string.IsNullOrEmpty(m_AllowedOrigin))
{
@@ -177,18 +336,23 @@ namespace OpenSim.Framework.Console
}
*/
- private void DoExpire()
+ protected void DoExpire(Object sender, ElapsedEventArgs e)
{
+ // Iterate the list of console connections and find those we
+ // haven't heard from for longer then the longpoll interval.
+ // Remove them.
List expired = new List();
lock (m_Connections)
{
+ // Mark the expired ones
foreach (KeyValuePair kvp in m_Connections)
{
if (System.Environment.TickCount - kvp.Value.last > 500000)
expired.Add(kvp.Key);
}
+ // Delete them
foreach (UUID id in expired)
{
m_Connections.Remove(id);
@@ -197,10 +361,10 @@ namespace OpenSim.Framework.Console
}
}
- private Hashtable HandleHttpStartSession(Hashtable request)
+ // Start a new session.
+ protected Hashtable HandleHttpStartSession(Hashtable request)
{
- DoExpire();
-
+ // The login is in the form of a http form post
Hashtable post = DecodePostString(request["body"].ToString());
Hashtable reply = new Hashtable();
@@ -208,6 +372,7 @@ namespace OpenSim.Framework.Console
reply["int_response_code"] = 401;
reply["content_type"] = "text/plain";
+ // Check user name and password
if (m_UserName == String.Empty)
return reply;
@@ -220,22 +385,28 @@ namespace OpenSim.Framework.Console
return reply;
}
+ // Set up the new console connection record
ConsoleConnection c = new ConsoleConnection();
c.last = System.Environment.TickCount;
c.lastLineSeen = 0;
+ // Assign session ID
UUID sessionID = UUID.Random();
+ // Add connection to list.
lock (m_Connections)
{
m_Connections[sessionID] = c;
}
+ // This call is a CAP. The URL is the authentication.
string uri = "/ReadResponses/" + sessionID.ToString() + "/";
m_Server.AddPollServiceHTTPHandler(
- uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, Drop, sessionID, 25000)); // 25 secs timeout
+ uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout
+ // Our reply is an XML document.
+ // TODO: Change this to Linq.Xml
XmlDocument xmldoc = new XmlDocument();
XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
"", "");
@@ -252,12 +423,13 @@ namespace OpenSim.Framework.Console
rootElement.AppendChild(id);
XmlElement prompt = xmldoc.CreateElement("", "Prompt", "");
- prompt.AppendChild(xmldoc.CreateTextNode(DefaultPrompt));
+ prompt.AppendChild(xmldoc.CreateTextNode(m_lastPromptUsed));
rootElement.AppendChild(prompt);
rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc));
+ // Set up the response and check origin
reply["str_response_string"] = xmldoc.InnerXml;
reply["int_response_code"] = 200;
reply["content_type"] = "text/xml";
@@ -266,10 +438,9 @@ namespace OpenSim.Framework.Console
return reply;
}
- private Hashtable HandleHttpCloseSession(Hashtable request)
+ // Client closes session. Clean up.
+ protected Hashtable HandleHttpCloseSession(Hashtable request)
{
- DoExpire();
-
Hashtable post = DecodePostString(request["body"].ToString());
Hashtable reply = new Hashtable();
@@ -316,10 +487,9 @@ namespace OpenSim.Framework.Console
return reply;
}
- private Hashtable HandleHttpSessionCommand(Hashtable request)
+ // Command received from the client.
+ protected Hashtable HandleHttpSessionCommand(Hashtable request)
{
- DoExpire();
-
Hashtable post = DecodePostString(request["body"].ToString());
Hashtable reply = new Hashtable();
@@ -327,6 +497,7 @@ namespace OpenSim.Framework.Console
reply["int_response_code"] = 404;
reply["content_type"] = "text/plain";
+ // Check the ID
if (post["ID"] == null)
return reply;
@@ -334,21 +505,25 @@ namespace OpenSim.Framework.Console
if (!UUID.TryParse(post["ID"].ToString(), out id))
return reply;
+ // Find the connection for that ID.
lock (m_Connections)
{
if (!m_Connections.ContainsKey(id))
return reply;
}
+ // Empty post. Just error out.
if (post["COMMAND"] == null)
return reply;
+ // Place the input data in the buffer.
lock (m_InputData)
{
m_DataEvent.Set();
m_InputData.Add(post["COMMAND"].ToString());
}
+ // Create the XML reply document.
XmlDocument xmldoc = new XmlDocument();
XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
"", "");
@@ -372,7 +547,8 @@ namespace OpenSim.Framework.Console
return reply;
}
- private Hashtable DecodePostString(string data)
+ // Decode a HTTP form post to a Hashtable
+ protected Hashtable DecodePostString(string data)
{
Hashtable result = new Hashtable();
@@ -396,6 +572,7 @@ namespace OpenSim.Framework.Console
return result;
}
+ // Close the CAP receiver for the responses for a given client.
public void CloseConnection(UUID id)
{
try
@@ -409,7 +586,9 @@ namespace OpenSim.Framework.Console
}
}
- private bool HasEvents(UUID RequestID, UUID sessionID)
+ // Check if there is anything to send. Return true if this client has
+ // lines pending.
+ protected bool HasEvents(UUID RequestID, UUID sessionID)
{
ConsoleConnection c = null;
@@ -420,22 +599,15 @@ namespace OpenSim.Framework.Console
c = m_Connections[sessionID];
}
c.last = System.Environment.TickCount;
- if (c.lastLineSeen < m_LineNumber)
+ if (c.lastLineSeen < m_lineNumber)
return true;
return false;
}
- private void Drop(UUID RequestID, UUID sessionID)
- {
- lock (m_Connections)
- {
- if (m_Connections.ContainsKey(sessionID))
- m_Connections.Remove(sessionID);
- }
- }
-
- private Hashtable GetEvents(UUID RequestID, UUID sessionID)
+ // Send all pending output to the client.
+ protected Hashtable GetEvents(UUID RequestID, UUID sessionID)
{
+ // Find the connection that goes with this client.
ConsoleConnection c = null;
lock (m_Connections)
@@ -444,12 +616,15 @@ namespace OpenSim.Framework.Console
return NoEvents(RequestID, UUID.Zero);
c = m_Connections[sessionID];
}
+
+ // If we have nothing to send, send the no events response.
c.last = System.Environment.TickCount;
- if (c.lastLineSeen >= m_LineNumber)
+ if (c.lastLineSeen >= m_lineNumber)
return NoEvents(RequestID, UUID.Zero);
Hashtable result = new Hashtable();
+ // Create the response document.
XmlDocument xmldoc = new XmlDocument();
XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
"", "");
@@ -458,30 +633,53 @@ namespace OpenSim.Framework.Console
XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession",
"");
- if (c.newConnection)
- {
- c.newConnection = false;
- Output("+++" + DefaultPrompt);
- }
+ //if (c.newConnection)
+ //{
+ // c.newConnection = false;
+ // Output("+++" + DefaultPrompt);
+ //}
lock (m_Scrollback)
{
- long startLine = m_LineNumber - m_Scrollback.Count;
+ long startLine = m_lineNumber - m_Scrollback.Count;
long sendStart = startLine;
if (sendStart < c.lastLineSeen)
sendStart = c.lastLineSeen;
- for (long i = sendStart ; i < m_LineNumber ; i++)
+ for (long i = sendStart ; i < m_lineNumber ; i++)
{
+ ScrollbackEntry e = m_Scrollback[(int)(i - startLine)];
+
XmlElement res = xmldoc.CreateElement("", "Line", "");
- long line = i + 1;
- res.SetAttribute("Number", line.ToString());
- res.AppendChild(xmldoc.CreateTextNode(m_Scrollback[(int)(i - startLine)]));
+ res.SetAttribute("Number", e.lineNumber.ToString());
+ res.SetAttribute("Level", e.level);
+ // Don't include these for the scrollback, we'll send the
+ // real state later.
+ if (!c.newConnection)
+ {
+ res.SetAttribute("Prompt", e.isPrompt ? "true" : "false");
+ res.SetAttribute("Command", e.isCommand ? "true" : "false");
+ res.SetAttribute("Input", e.isInput ? "true" : "false");
+ }
+ else if (i == m_lineNumber - 1) // Last line for a new connection
+ {
+ res.SetAttribute("Prompt", m_expectingInput ? "true" : "false");
+ res.SetAttribute("Command", m_expectingCommand ? "true" : "false");
+ res.SetAttribute("Input", (!m_expectingInput) ? "true" : "false");
+ }
+ else
+ {
+ res.SetAttribute("Input", e.isInput ? "true" : "false");
+ }
+
+ res.AppendChild(xmldoc.CreateTextNode(e.text));
rootElement.AppendChild(res);
}
}
- c.lastLineSeen = m_LineNumber;
+
+ c.lastLineSeen = m_lineNumber;
+ c.newConnection = false;
xmldoc.AppendChild(rootElement);
@@ -495,7 +693,9 @@ namespace OpenSim.Framework.Console
return result;
}
- private Hashtable NoEvents(UUID RequestID, UUID id)
+ // This is really just a no-op. It generates what is sent
+ // to the client if the poll times out without any events.
+ protected Hashtable NoEvents(UUID RequestID, UUID id)
{
Hashtable result = new Hashtable();
diff --git a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
index 9056548a51..4ff8cbabfa 100644
--- a/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
+++ b/OpenSim/Framework/DoubleDictionaryThreadAbortSafe.cs
@@ -55,6 +55,11 @@ namespace OpenSim.Framework
Dictionary2 = new Dictionary(capacity);
}
+ ~DoubleDictionaryThreadAbortSafe()
+ {
+ rwLock.Dispose();
+ }
+
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
bool gotLock = false;
diff --git a/OpenSim/Framework/LocklessQueue.cs b/OpenSim/Framework/LocklessQueue.cs
index 9bd9baf321..7ccbba7b55 100644
--- a/OpenSim/Framework/LocklessQueue.cs
+++ b/OpenSim/Framework/LocklessQueue.cs
@@ -93,7 +93,10 @@ namespace OpenSim.Framework
if (oldHead == oldTail)
{
if (oldHeadNext == null)
+ {
+ count = 0;
return false;
+ }
CAS(ref tail, oldTail, oldHeadNext);
}
@@ -118,8 +121,7 @@ namespace OpenSim.Framework
{
// ugly
T item;
- while(count > 0)
- Dequeue(out item);
+ while(Dequeue(out item));
Init();
}
diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs
index 2c20ef7719..c270d98ee7 100644
--- a/OpenSim/Framework/TaskInventoryDictionary.cs
+++ b/OpenSim/Framework/TaskInventoryDictionary.cs
@@ -64,6 +64,13 @@ namespace OpenSim.Framework
///
private volatile System.Threading.ReaderWriterLockSlim m_itemLock = new System.Threading.ReaderWriterLockSlim();
+
+ ~TaskInventoryDictionary()
+ {
+ m_itemLock.Dispose();
+ m_itemLock = null;
+ }
+
///
/// Are we readlocked by the calling thread?
///
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 51d87bdf2d..2bbf785661 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -1062,11 +1062,10 @@ namespace OpenSim.Framework
if (WebUtil.DebugLevel >= 5)
WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
- Stream requestStream = null;
try
{
- requestStream = request.GetRequestStream();
- requestStream.Write(data, 0, length);
+ using(Stream requestStream = request.GetRequestStream())
+ requestStream.Write(data,0,length);
}
catch (Exception e)
{
@@ -1076,9 +1075,6 @@ namespace OpenSim.Framework
}
finally
{
- if (requestStream != null)
- requestStream.Dispose();
-
// capture how much time was spent writing
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 46c6a19e9d..8ba26e83f9 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -346,12 +346,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private bool m_VelocityInterpolate = false;
private const uint MaxTransferBytesPerPacket = 600;
- ///
- /// List used in construction of data blocks for an object update packet. This is to stop us having to
- /// continually recreate it.
- ///
- protected List m_fullUpdateDataBlocksBuilder;
-
///
/// Maintain a record of all the objects killed. This allows us to stop an update being sent from the
/// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
@@ -511,7 +505,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene = scene;
m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
m_entityProps = new PriorityQueue(m_scene.Entities.Count);
- m_fullUpdateDataBlocksBuilder = new List();
m_killRecord = new List();
// m_attachmentsSent = new HashSet();
@@ -594,13 +587,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(disable, ThrottleOutPacketType.Unknown);
}
- // Shutdown the image manager
- ImageManager.Close();
// Fire the callback for this connection closing
if (OnConnectionClosed != null)
OnConnectionClosed(this);
+
// Flush all of the packets out of the UDP server for this client
if (m_udpServer != null)
m_udpServer.Flush(m_udpClient);
@@ -615,8 +607,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Disable UDP handling for this client
m_udpClient.Shutdown();
-
-
+
+ m_udpClient.OnQueueEmpty -= HandleQueueEmpty;
+ m_udpClient.HasUpdates -= HandleHasUpdates;
+ m_udpClient.OnPacketStats -= PopulateStats;
+
+ // Shutdown the image manager
+ ImageManager.Close();
+ ImageManager = null;
+
+ m_entityUpdates = null;
+ m_entityProps = null;
+ m_killRecord.Clear();
+ GroupsInView.Clear();
+ m_scene = null;
//m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
//GC.Collect();
//m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
@@ -814,7 +818,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void ProcessSpecificPacketAsync(object state)
{
AsyncPacketProcess packetObject = (AsyncPacketProcess)state;
-
+
try
{
packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack);
@@ -4095,19 +4099,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ResendPrimUpdate(update);
}
+ private List objectUpdateBlocks = new List();
+ private List compressedUpdateBlocks = new List();
+ private List terseUpdateBlocks = new List();
+ private List terseAgentUpdateBlocks = new List();
+
private void ProcessEntityUpdates(int maxUpdatesBytes)
{
- OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>();
- OpenSim.Framework.Lazy> compressedUpdateBlocks = new OpenSim.Framework.Lazy>();
- OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>();
- OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>();
-
OpenSim.Framework.Lazy> objectUpdates = new OpenSim.Framework.Lazy>();
OpenSim.Framework.Lazy> compressedUpdates = new OpenSim.Framework.Lazy>();
OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>();
OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>();
-
// Check to see if this is a flush
if (maxUpdatesBytes <= 0)
{
@@ -4328,7 +4331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
else
ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId);
- objectUpdateBlocks.Value.Add(ablock);
+ objectUpdateBlocks.Add(ablock);
objectUpdates.Value.Add(update);
maxUpdatesBytes -= ablock.Length;
@@ -4337,7 +4340,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
ObjectUpdateCompressedPacket.ObjectDataBlock ablock =
CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags);
- compressedUpdateBlocks.Value.Add(ablock);
+ compressedUpdateBlocks.Add(ablock);
compressedUpdates.Value.Add(update);
maxUpdatesBytes -= ablock.Length;
}
@@ -4348,14 +4351,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
// ALL presence updates go into a special list
ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
- terseAgentUpdateBlocks.Value.Add(ablock);
+ terseAgentUpdateBlocks.Add(ablock);
terseAgentUpdates.Value.Add(update);
}
else
{
// Everything else goes here
ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
- terseUpdateBlocks.Value.Add(ablock);
+ terseUpdateBlocks.Add(ablock);
terseUpdates.Value.Add(update);
}
maxUpdatesBytes -= ablock.Length;
@@ -4366,74 +4369,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Packet Sending
-// const float TIME_DILATION = 1.0f;
ushort timeDilation;
-// if(updatesThisCall > 0)
-// timeDilation = Utils.FloatToUInt16(avgTimeDilation/updatesThisCall, 0.0f, 1.0f);
-// else
-// timeDilation = ushort.MaxValue; // 1.0;
+
+ if(m_scene == null)
+ return;
timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
- if (terseAgentUpdateBlocks.IsValueCreated)
+ if (terseAgentUpdateBlocks.Count > 0)
{
- List blocks = terseAgentUpdateBlocks.Value;
-
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
- packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
+ packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count];
- for (int i = 0; i < blocks.Count; i++)
- packet.ObjectData[i] = blocks[i];
+ for (int i = 0; i < terseAgentUpdateBlocks.Count; i++)
+ packet.ObjectData[i] = terseAgentUpdateBlocks[i];
+
+ terseAgentUpdateBlocks.Clear();
OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
}
- if (objectUpdateBlocks.IsValueCreated)
+ if (objectUpdateBlocks.Count > 0)
{
- List blocks = objectUpdateBlocks.Value;
-
ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
- packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
+ packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count];
- for (int i = 0; i < blocks.Count; i++)
- packet.ObjectData[i] = blocks[i];
+ for (int i = 0; i < objectUpdateBlocks.Count; i++)
+ packet.ObjectData[i] = objectUpdateBlocks[i];
+
+ objectUpdateBlocks.Clear();
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
}
- if (compressedUpdateBlocks.IsValueCreated)
+ if (compressedUpdateBlocks.Count > 0)
{
- List blocks = compressedUpdateBlocks.Value;
-
ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
- packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
+ packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count];
- for (int i = 0; i < blocks.Count; i++)
- packet.ObjectData[i] = blocks[i];
+ for (int i = 0; i < compressedUpdateBlocks.Count; i++)
+ packet.ObjectData[i] = compressedUpdateBlocks[i];
+
+ compressedUpdateBlocks.Clear();
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
}
- if (terseUpdateBlocks.IsValueCreated)
+ if (terseUpdateBlocks.Count > 0)
{
- List blocks = terseUpdateBlocks.Value;
-
ImprovedTerseObjectUpdatePacket packet
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
PacketType.ImprovedTerseObjectUpdate);
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
packet.RegionData.TimeDilation = timeDilation;
- packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
+ packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count];
- for (int i = 0; i < blocks.Count; i++)
- packet.ObjectData[i] = blocks[i];
+ for (int i = 0; i < terseUpdateBlocks.Count; i++)
+ packet.ObjectData[i] = terseUpdateBlocks[i];
+
+ terseUpdateBlocks.Clear();
OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
}
@@ -4634,6 +4635,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories)
{
+ if(m_scene == null)
+ return;
+
if ((categories & ThrottleOutPacketTypeFlags.Task) != 0)
{
int maxUpdateBytes = m_udpClient.GetCatBytesCanSend(ThrottleOutPacketType.Task, 30);
@@ -4828,21 +4832,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true));
}
+ List objectFamilyBlocks = new
+ List();
+ List objectPropertiesBlocks =
+ new List();
+ List needPhysics = new List();
+
private void ProcessEntityPropertyRequests(int maxUpdateBytes)
{
- OpenSim.Framework.Lazy> objectFamilyBlocks =
- new OpenSim.Framework.Lazy>();
+// OpenSim.Framework.Lazy> familyUpdates =
+// new OpenSim.Framework.Lazy>();
- OpenSim.Framework.Lazy> objectPropertiesBlocks =
- new OpenSim.Framework.Lazy>();
-
- OpenSim.Framework.Lazy> familyUpdates =
- new OpenSim.Framework.Lazy>();
-
- OpenSim.Framework.Lazy> propertyUpdates =
- new OpenSim.Framework.Lazy>();
+// OpenSim.Framework.Lazy> propertyUpdates =
+// new OpenSim.Framework.Lazy>();
- List needPhysics = new List();
EntityUpdate iupdate;
Int32 timeinqueue; // this is just debugging code & can be dropped later
@@ -4860,8 +4863,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
SceneObjectPart sop = (SceneObjectPart)update.Entity;
ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags);
- objectFamilyBlocks.Value.Add(objPropDB);
- familyUpdates.Value.Add(update);
+ objectFamilyBlocks.Add(objPropDB);
+// familyUpdates.Value.Add(update);
maxUpdateBytes -= objPropDB.Length;
}
}
@@ -4873,23 +4876,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
SceneObjectPart sop = (SceneObjectPart)update.Entity;
needPhysics.Add(sop);
ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop);
- objectPropertiesBlocks.Value.Add(objPropDB);
- propertyUpdates.Value.Add(update);
+ objectPropertiesBlocks.Add(objPropDB);
+// propertyUpdates.Value.Add(update);
maxUpdateBytes -= objPropDB.Length;
}
}
}
- if (objectPropertiesBlocks.IsValueCreated)
+ if (objectPropertiesBlocks.Count > 0)
{
- List blocks = objectPropertiesBlocks.Value;
- List updates = propertyUpdates.Value;
-
ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties);
- packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count];
- for (int i = 0; i < blocks.Count; i++)
- packet.ObjectData[i] = blocks[i];
+ packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count];
+ for (int i = 0; i < objectPropertiesBlocks.Count; i++)
+ packet.ObjectData[i] = objectPropertiesBlocks[i];
+
+ objectPropertiesBlocks.Clear();
packet.Header.Zerocoded = true;
// Pass in the delegate so that if this packet needs to be resent, we send the current properties
@@ -4898,7 +4900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
//OutPacket(packet, ThrottleOutPacketType.Task, true,
// delegate(OutgoingPacket oPacket)
// {
- // ResendPropertyUpdates(updates, oPacket);
+ // ResendPropertyUpdates(propertyUpdates.Value, oPacket);
// });
OutPacket(packet, ThrottleOutPacketType.Task, true);
@@ -4909,23 +4911,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Int32 fpcnt = 0;
// Int32 fbcnt = 0;
- if (objectFamilyBlocks.IsValueCreated)
- {
- List blocks = objectFamilyBlocks.Value;
-
+ if (objectFamilyBlocks.Count > 0)
+ {
// one packet per object block... uggh...
- for (int i = 0; i < blocks.Count; i++)
+ for (int i = 0; i < objectFamilyBlocks.Count; i++)
{
ObjectPropertiesFamilyPacket packet =
(ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily);
- packet.ObjectData = blocks[i];
+ packet.ObjectData = objectFamilyBlocks[i];
packet.Header.Zerocoded = true;
// Pass in the delegate so that if this packet needs to be resent, we send the current properties
// of the object rather than the properties when the packet was created
- List updates = new List();
- updates.Add(familyUpdates.Value[i]);
+// List updates = new List();
+// updates.Add(familyUpdates.Value[i]);
// HACK : Remove intelligent resending until it's fixed in core
//OutPacket(packet, ThrottleOutPacketType.Task, true,
// delegate(OutgoingPacket oPacket)
@@ -4937,6 +4937,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// fpcnt++;
// fbcnt++;
}
+ objectFamilyBlocks.Clear();
}
if(needPhysics.Count > 0)
@@ -4962,6 +4963,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId);
}
+ needPhysics.Clear();
}
// m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt);
@@ -6251,9 +6253,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return false;
}
+ uint seq = packet.Header.Sequence;
+
TotalAgentUpdates++;
// dont let ignored updates pollute this throttles
- if(SceneAgent == null || SceneAgent.IsChildAgent || SceneAgent.IsInTransit)
+ if(SceneAgent == null || SceneAgent.IsChildAgent ||
+ SceneAgent.IsInTransit || seq <= m_thisAgentUpdateArgs.lastpacketSequence )
{
// throttle reset is done at MoveAgentIntoRegion()
// called by scenepresence on completemovement
@@ -6261,6 +6266,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true;
}
+ m_thisAgentUpdateArgs.lastpacketSequence = seq;
+
bool movement = CheckAgentMovementUpdateSignificance(x);
bool camera = CheckAgentCameraUpdateSignificance(x);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index d59b7614ed..e85cee2524 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -120,13 +120,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Circuit code that this client is connected on
public readonly uint CircuitCode;
/// Sequence numbers of packets we've received (for duplicate checking)
- public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
+ public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200);
/// Packets we have sent that need to be ACKed by the client
- public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
+ public UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
/// ACKs that are queued up, waiting to be sent to the client
- public readonly DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue();
+ public DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue();
/// Current packet sequence number
public int CurrentSequence;
@@ -170,7 +170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private double m_nextOnQueueEmpty = 0;
/// Throttle bucket for this agent's connection
- private readonly AdaptiveTokenBucket m_throttleClient;
+ private AdaptiveTokenBucket m_throttleClient;
public AdaptiveTokenBucket FlowThrottle
{
get { return m_throttleClient; }
@@ -179,10 +179,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Throttle buckets for each packet category
private readonly TokenBucket[] m_throttleCategories;
/// Outgoing queues for throttled packets
- private readonly DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT];
+ private DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT];
/// A container that can hold one packet for each outbox, used to store
/// dequeued packets that are being held for throttling
- private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
+ private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
/// A reference to the LLUDPServer that is managing this client
private readonly LLUDPServer m_udpServer;
@@ -288,14 +288,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
{
m_packetOutboxes[i].Clear();
+ m_throttleCategories[i] = null;
m_nextPackets[i] = null;
}
// pull the throttle out of the scene throttle
m_throttleClient.Parent.UnregisterRequest(m_throttleClient);
+ m_throttleClient = null;
OnPacketStats = null;
OnQueueEmpty = null;
- }
+ PendingAcks.Clear();
+ NeedAcks.Clear();
+ NeedAcks = null;
+ PendingAcks = null;
+ m_nextPackets = null;
+ m_packetOutboxes = null;
+ }
///
/// Gets information about this client connection
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index ffdb6398a9..af33d17b7e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -326,7 +326,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected double m_tickLastOutgoingPacketHandler;
/// Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped
- protected int m_elapsedMSOutgoingPacketHandler;
+ protected double m_elapsedMSOutgoingPacketHandler;
/// Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed
protected int m_elapsed100MSOutgoingPacketHandler;
@@ -2074,18 +2074,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Update elapsed time
double thisTick = Util.GetTimeStampMS();
- int deltaMS = (int)(thisTick - m_tickLastOutgoingPacketHandler);
- m_tickLastOutgoingPacketHandler = thisTick;
// update some 1ms resolution chained timers
-
- m_elapsedMSOutgoingPacketHandler += deltaMS;
+ m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler;
+ m_tickLastOutgoingPacketHandler = thisTick;
// Check for pending outgoing resends every 100ms
- if (m_elapsedMSOutgoingPacketHandler >= 100)
+ if (m_elapsedMSOutgoingPacketHandler >= 100.0)
{
m_resendUnacked = true;
- m_elapsedMSOutgoingPacketHandler = 0;
+ m_elapsedMSOutgoingPacketHandler = 0.0;
m_elapsed100MSOutgoingPacketHandler += 1;
}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index 7b9661b80c..d4603f80a5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -193,7 +193,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Parent = parent;
RequestedDripRate = dripRate;
RequestedBurst = MaxBurst;
- m_lastDrip = Util.GetTimeStampMS() + 50.0;
+ m_lastDrip = Util.GetTimeStampMS() + 100000.0; // skip first drip
}
#endregion Constructor
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
index b546a99603..c9d5697b23 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs
@@ -74,6 +74,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Holds information about pending removals
private LocklessQueue m_pendingRemoves = new LocklessQueue();
+
+ public void Clear()
+ {
+ m_packets.Clear();
+ m_pendingAdds = null;
+ m_pendingAcknowledgements = null;
+ m_pendingRemoves = null;
+ }
+
///
/// Add an unacked packet to the collection
///
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
index 6c1cc525b2..2afd74e36e 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
@@ -36,6 +36,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
{
public class UserAccountCache : IUserAccountCacheModule
{
+ private const double CACHE_ALIEN_EXPIRATION_SECONDS = 172800; // 48 hours
private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour!
private const double CACHE_NULL_EXPIRATION_SECONDS = 600; // 10minutes
@@ -60,21 +61,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
{
if (account == null)
m_UUIDCache.AddOrUpdate(userID, null, CACHE_NULL_EXPIRATION_SECONDS);
- else
+ else if(account.LocalToGrid)
{
m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS);
m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS);
}
-
+ else
+ {
+ m_UUIDCache.AddOrUpdate(userID, account, CACHE_ALIEN_EXPIRATION_SECONDS);
+ m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_ALIEN_EXPIRATION_SECONDS);
+ }
//m_log.DebugFormat("[USER CACHE]: cached user {0}", userID);
}
}
- public void Invalidate(UUID userID)
- {
- lock(accessLock)
- m_UUIDCache.Remove(userID);
- }
public UserAccount Get(UUID userID, out bool inCache)
{
@@ -114,6 +114,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
return null;
}
+ public void Invalidate(UUID userID)
+ {
+ m_UUIDCache.Remove(userID);
+ }
+
+ public void Remove(UUID id)
+ {
+ lock(accessLock)
+ {
+ if (!m_UUIDCache.Contains(id))
+ return;
+
+ UserAccount account = null;
+ if (m_UUIDCache.TryGetValue(id, out account) && account != null)
+ m_NameCache.Remove(account.Name);
+ m_UUIDCache.Remove(id);
+ }
+ }
+
public void Remove(string name)
{
lock(accessLock)
diff --git a/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs
index ed269896a9..027a7e2e5a 100644
--- a/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs
@@ -26,8 +26,10 @@
*/
using OpenSim.Region.Framework.Scenes;
+using OpenMetaverse;
public interface IUserAccountCacheModule
{
void Remove(string name);
+ void Remove(UUID id);
}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ca32940cd2..c349369604 100755
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -4141,7 +4141,8 @@ namespace OpenSim.Region.Framework.Scenes
{
IUserAccountCacheModule cache = RequestModuleInterface();
if (cache != null)
- cache.Remove(acd.firstname + " " + acd.lastname);
+// cache.Remove(acd.firstname + " " + acd.lastname);
+ cache.Remove(acd.AgentID);
// Remove any preexisting circuit - we don't want duplicates
// This is a stab at preventing avatar "ghosting"
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 3378eade7c..2cfdd946f9 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1104,7 +1104,7 @@ namespace OpenSim.Region.Framework.Scenes
AdjustKnownSeeds();
- RegisterToEvents();
+ RegisterToClientEvents();
SetDirectionVectors();
Appearance = appearance;
@@ -1171,7 +1171,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public void RegisterToEvents()
+ public void RegisterToClientEvents()
{
ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
ControllingClient.OnAgentUpdate += HandleAgentUpdate;
@@ -1189,6 +1189,22 @@ namespace OpenSim.Region.Framework.Scenes
// ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange);
// ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement);
}
+
+ public void RemoveClientEvents()
+ {
+ ControllingClient.OnCompleteMovementToRegion -= CompleteMovement;
+ ControllingClient.OnAgentUpdate -= HandleAgentUpdate;
+ ControllingClient.OnAgentCameraUpdate -= HandleAgentCamerasUpdate;
+ ControllingClient.OnAgentRequestSit -= HandleAgentRequestSit;
+ ControllingClient.OnAgentSit -= HandleAgentSit;
+ ControllingClient.OnSetAlwaysRun -= HandleSetAlwaysRun;
+ ControllingClient.OnStartAnim -= HandleStartAnim;
+ ControllingClient.OnStopAnim -= HandleStopAnim;
+ ControllingClient.OnChangeAnim -= avnHandleChangeAnim;
+ ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls;
+ ControllingClient.OnAutoPilotGo -= MoveToTarget;
+ ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles;
+ }
private void SetDirectionVectors()
{
@@ -2318,7 +2334,7 @@ namespace OpenSim.Region.Framework.Scenes
Vector3 tocam = CameraPosition - posAdjusted;
float distTocamlen = tocam.LengthSquared();
- if (distTocamlen > 0.08f && distTocamlen < 400)
+ if (distTocamlen > 0.01f && distTocamlen < 400)
{
distTocamlen = (float)Math.Sqrt(distTocamlen);
tocam *= (1.0f / distTocamlen);
@@ -4378,16 +4394,12 @@ namespace OpenSim.Region.Framework.Scenes
m_log.DebugFormat(
"[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}",
knownRegions.Count, Scene.RegionInfo.RegionName);
- //DumpKnownRegions();
Util.RegionHandleToRegionLoc(newRegionHandle, out newRegionX, out newRegionY);
uint x, y;
spRegionSizeInfo regInfo;
- // this should not be here
- IEventQueue eventQueue = Scene.RequestModuleInterface();
-
foreach (ulong handle in knownRegions)
{
// Don't close the agent on this region yet
@@ -4400,16 +4412,10 @@ namespace OpenSim.Region.Framework.Scenes
Util.RegionHandleToRegionLoc(handle, out x, out y);
if (m_knownChildRegionsSizeInfo.TryGetValue(handle, out regInfo))
{
-
- // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
- // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY,
regInfo.sizeX, regInfo.sizeY, newRegionSizeX, newRegionSizeY))
{
byebyeRegions.Add(handle);
- // this should not be here
-// if(eventQueue != null)
-/// eventQueue.DisableSimulator(handle,UUID);
}
}
else
@@ -4445,6 +4451,32 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public void closeAllChildAgents()
+ {
+ List byebyeRegions = new List();
+ List knownRegions = KnownRegionHandles;
+ foreach (ulong handle in knownRegions)
+ {
+ if (handle != Scene.RegionInfo.RegionHandle)
+ {
+ byebyeRegions.Add(handle);
+ RemoveNeighbourRegion(handle);
+ Scene.CapsModule.DropChildSeed(UUID, handle);
+ }
+ }
+
+ if (byebyeRegions.Count > 0)
+ {
+ m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
+
+ AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID);
+ string auth = string.Empty;
+ if (acd != null)
+ auth = acd.SessionID.ToString();
+ m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions);
+ }
+ }
+
#endregion
///
@@ -5000,12 +5032,16 @@ namespace OpenSim.Region.Framework.Scenes
RemoveFromPhysicalScene();
m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
+ RemoveClientEvents();
// if (Animator != null)
// Animator.Close();
Animator = null;
+ scriptedcontrols.Clear();
+ ControllingClient = null;
LifecycleState = ScenePresenceState.Removed;
+ IsDeleted = true;
}
public void AddAttachment(SceneObjectGroup gobj)
diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs
index d9ea4a4991..0cdaa60c15 100644
--- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs
+++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Mesh.cs
@@ -39,6 +39,24 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
{
public class MeshBuildingData
{
+ private class vertexcomp : IEqualityComparer
+ {
+ public bool Equals(Vertex v1, Vertex v2)
+ {
+ if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z)
+ return true;
+ else
+ return false;
+ }
+ public int GetHashCode(Vertex v)
+ {
+ int a = v.X.GetHashCode();
+ int b = v.Y.GetHashCode();
+ int c = v.Z.GetHashCode();
+ return (a << 16) ^ (b << 8) ^ c;
+ }
+ }
+
public Dictionary m_vertices;
public List m_triangles;
public float m_obbXmin;
@@ -49,6 +67,21 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
public float m_obbZmax;
public Vector3 m_centroid;
public int m_centroidDiv;
+
+ public MeshBuildingData()
+ {
+ vertexcomp vcomp = new vertexcomp();
+ m_vertices = new Dictionary(vcomp);
+ m_triangles = new List();
+ m_centroid = Vector3.Zero;
+ m_centroidDiv = 0;
+ m_obbXmin = float.MaxValue;
+ m_obbXmax = float.MinValue;
+ m_obbYmin = float.MaxValue;
+ m_obbYmax = float.MinValue;
+ m_obbZmin = float.MaxValue;
+ m_obbZmax = float.MinValue;
+ }
}
[Serializable()]
@@ -76,50 +109,20 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
public int RefCount { get; set; }
public AMeshKey Key { get; set; }
- private class vertexcomp : IEqualityComparer
+ public Mesh(bool forbuild)
{
- public bool Equals(Vertex v1, Vertex v2)
- {
- if (v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z)
- return true;
- else
- return false;
- }
- public int GetHashCode(Vertex v)
- {
- int a = v.X.GetHashCode();
- int b = v.Y.GetHashCode();
- int c = v.Z.GetHashCode();
- return (a << 16) ^ (b << 8) ^ c;
- }
- }
-
- public Mesh()
- {
- vertexcomp vcomp = new vertexcomp();
-
- m_bdata = new MeshBuildingData();
- m_bdata.m_vertices = new Dictionary(vcomp);
- m_bdata.m_triangles = new List();
- m_bdata.m_centroid = Vector3.Zero;
- m_bdata.m_centroidDiv = 0;
- m_bdata.m_obbXmin = float.MaxValue;
- m_bdata.m_obbXmax = float.MinValue;
- m_bdata.m_obbYmin = float.MaxValue;
- m_bdata.m_obbYmax = float.MinValue;
- m_bdata.m_obbZmin = float.MaxValue;
- m_bdata.m_obbZmax = float.MinValue;
+ if(forbuild)
+ m_bdata = new MeshBuildingData();
m_obb = new Vector3(0.5f, 0.5f, 0.5f);
m_obboffset = Vector3.Zero;
}
-
public Mesh Scale(Vector3 scale)
{
if (m_verticesPtr == null || m_indicesPtr == null)
return null;
- Mesh result = new Mesh();
+ Mesh result = new Mesh(false);
float x = scale.X;
float y = scale.Y;
@@ -167,7 +170,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
public Mesh Clone()
{
- Mesh result = new Mesh();
+ Mesh result = new Mesh(false);
if (m_bdata != null)
{
@@ -514,8 +517,6 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
if (m_indicesPtr == IntPtr.Zero)
indexes = getIndexListAsInt();
- pinMemory();
-
float x, y, z;
if (m_bdata.m_centroidDiv > 0)
@@ -543,55 +544,53 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
m_obb = new Vector3(x, y, z);
releaseBuildingMeshData();
+ pinMemory();
}
+
public bool ToStream(Stream st)
{
if (m_indicesPtr == IntPtr.Zero || m_verticesPtr == IntPtr.Zero)
return false;
- BinaryWriter bw = new BinaryWriter(st);
bool ok = true;
try
{
+ using(BinaryWriter bw = new BinaryWriter(st))
+ {
+ bw.Write(m_vertexCount);
+ bw.Write(m_indexCount);
- bw.Write(m_vertexCount);
- bw.Write(m_indexCount);
-
- for (int i = 0; i < 3 * m_vertexCount; i++)
- bw.Write(vertices[i]);
- for (int i = 0; i < m_indexCount; i++)
- bw.Write(indexes[i]);
- bw.Write(m_obb.X);
- bw.Write(m_obb.Y);
- bw.Write(m_obb.Z);
- bw.Write(m_obboffset.X);
- bw.Write(m_obboffset.Y);
- bw.Write(m_obboffset.Z);
+ for (int i = 0; i < 3 * m_vertexCount; i++)
+ bw.Write(vertices[i]);
+ for (int i = 0; i < m_indexCount; i++)
+ bw.Write(indexes[i]);
+ bw.Write(m_obb.X);
+ bw.Write(m_obb.Y);
+ bw.Write(m_obb.Z);
+ bw.Write(m_obboffset.X);
+ bw.Write(m_obboffset.Y);
+ bw.Write(m_obboffset.Z);
+ bw.Flush();
+ bw.Close();
+ }
}
catch
{
ok = false;
}
- if (bw != null)
- {
- bw.Flush();
- bw.Close();
- }
-
return ok;
}
public static Mesh FromStream(Stream st, AMeshKey key)
{
- Mesh mesh = new Mesh();
- mesh.releaseBuildingMeshData();
+ Mesh mesh = new Mesh(false);
bool ok = true;
- using(BinaryReader br = new BinaryReader(st))
+ try
{
- try
+ using(BinaryReader br = new BinaryReader(st))
{
mesh.m_vertexCount = br.ReadInt32();
mesh.m_indexCount = br.ReadInt32();
@@ -613,10 +612,10 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
mesh.m_obboffset.Y = br.ReadSingle();
mesh.m_obboffset.Z = br.ReadSingle();
}
- catch
- {
- ok = false;
- }
+ }
+ catch
+ {
+ ok = false;
}
if (ok)
diff --git a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs
index ca94034b10..2ae0881e78 100644
--- a/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs
+++ b/OpenSim/Region/PhysicsModules/ubOdeMeshing/Meshmerizer.cs
@@ -182,7 +182,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
///
private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
{
- Mesh box = new Mesh();
+ Mesh box = new Mesh(true);
List vertices = new List();
// bottom
@@ -357,7 +357,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
int numCoords = coords.Count;
int numFaces = faces.Count;
- Mesh mesh = new Mesh();
+ Mesh mesh = new Mesh(true);
// Add the corresponding triangles to the mesh
for (int i = 0; i < numFaces; i++)
{
@@ -1483,6 +1483,7 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
lock (diskLock)
{
+ Stream stream = null;
try
{
if (!Directory.Exists(dir))
@@ -1490,8 +1491,8 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
Directory.CreateDirectory(dir);
}
- using(Stream stream = File.Open(filename, FileMode.Create))
- ok = mesh.ToStream(stream);
+ stream = File.Open(filename, FileMode.Create);
+ ok = mesh.ToStream(stream);
}
catch (IOException e)
{
@@ -1500,6 +1501,11 @@ namespace OpenSim.Region.PhysicsModule.ubODEMeshing
filename, e.Message, e.StackTrace);
ok = false;
}
+ finally
+ {
+ if(stream != null)
+ stream.Dispose();
+ }
if (!ok && File.Exists(filename))
{
diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs
index 86fda36e81..38629b29d7 100644
--- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs
+++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs
@@ -579,13 +579,13 @@ namespace OpenSim.Server.Handlers.Grid
if (request.ContainsKey("SCOPEID"))
UUID.TryParse(request["SCOPEID"].ToString(), out scopeID);
else
- m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get neighbours");
+ m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get RegionFlags");
UUID regionID = UUID.Zero;
if (request.ContainsKey("REGIONID"))
UUID.TryParse(request["REGIONID"].ToString(), out regionID);
else
- m_log.WarnFormat("[GRID HANDLER]: no regionID in request to get neighbours");
+ m_log.WarnFormat("[GRID HANDLER]: no regionID in request to get RegionFlags");
int flags = m_GridService.GetRegionFlags(scopeID, regionID);
// m_log.DebugFormat("[GRID HANDLER]: flags for region {0}: {1}", regionID, flags);
diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
index 2e8ffe5aae..a9359f3cd0 100644
--- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
+++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
@@ -72,8 +72,11 @@ namespace OpenSim.Services.AuthenticationService
{
realID = UUID.Zero;
- m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}", principalID);
+ m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null);
AuthenticationData data = m_Database.Get(principalID);
+ UserAccount user = null;
+ if (m_UserAccountService != null)
+ user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID);
if (data == null || data.Data == null)
{
@@ -97,7 +100,53 @@ namespace OpenSim.Services.AuthenticationService
return GetToken(principalID, lifetime);
}
- m_log.DebugFormat("[AUTH SERVICE]: Authenticating FAIL for {0} ", principalID);
+ if (user == null)
+ {
+ m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID);
+ return String.Empty;
+ }
+
+ int impersonateFlag = 1 << 6;
+
+ if ((user.UserFlags & impersonateFlag) == 0)
+ return String.Empty;
+
+ m_log.DebugFormat("[PASS AUTH]: Attempting impersonation");
+
+ List accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200");
+ if (accounts == null || accounts.Count == 0)
+ return String.Empty;
+
+ foreach (UserAccount a in accounts)
+ {
+ data = m_Database.Get(a.PrincipalID);
+ if (data == null || data.Data == null ||
+ !data.Data.ContainsKey("passwordHash") ||
+ !data.Data.ContainsKey("passwordSalt"))
+ {
+ continue;
+ }
+
+// m_log.DebugFormat("[PASS AUTH]: Trying {0}", data.PrincipalID);
+
+ hashed = Util.Md5Hash(password + ":" +
+ data.Data["passwordSalt"].ToString());
+
+ if (data.Data["passwordHash"].ToString() == hashed)
+ {
+ m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID);
+ realID = a.PrincipalID;
+ return GetToken(principalID, lifetime);
+ }
+// else
+// {
+// m_log.DebugFormat(
+// "[AUTH SERVICE]: Salted hash {0} of given password did not match salted hash of {1} for PrincipalID {2}. Authentication failure.",
+// hashed, data.Data["passwordHash"], data.PrincipalID);
+// }
+ }
+
+ m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID);
return String.Empty;
}
}
diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
index e0bc9168ec..019c0d34b2 100644
--- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
+++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs
@@ -625,6 +625,7 @@ namespace Amib.Threading.Internal
if (!_isDisposed)
{
Cleanup();
+ _headWaiterEntry.Close();
}
_isDisposed = true;
}