mirror of
https://github.com/opensim/opensim.git
synced 2026-08-05 08:55:56 +08:00
Merge branch 'master' of ssh://3dhosting.de/var/git/careminster
Conflicts: OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
This commit is contained in:
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack
|
||||
IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource,
|
||||
AgentCircuitManager authenticateClass);
|
||||
|
||||
void NetworkStop();
|
||||
bool HandlesRegion(Location x);
|
||||
void AddScene(IScene x);
|
||||
|
||||
/// <summary>
|
||||
/// Add the given scene to be handled by this IClientNetworkServer.
|
||||
/// </summary>
|
||||
/// <param name='scene'></param>
|
||||
void AddScene(IScene scene);
|
||||
|
||||
/// <summary>
|
||||
/// Start sending and receiving data.
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Stop sending and receiving data.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using Mono.Addins;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Caps = OpenSim.Framework.Capabilities.Caps;
|
||||
using OpenSim.Capabilities.Handlers;
|
||||
|
||||
namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")]
|
||||
public class AvatarPickerSearchModule : INonSharedRegionModule
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private Scene m_scene;
|
||||
private IPeople m_People;
|
||||
private bool m_Enabled = false;
|
||||
|
||||
private string m_URL;
|
||||
|
||||
#region ISharedRegionModule Members
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty);
|
||||
// Cap doesn't exist
|
||||
if (m_URL != string.Empty)
|
||||
m_Enabled = true;
|
||||
}
|
||||
|
||||
public void AddRegion(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_scene = s;
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||
m_scene = null;
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_People = m_scene.RequestModuleInterface<IPeople>();
|
||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||
}
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void Close() { }
|
||||
|
||||
public string Name { get { return "AvatarPickerSearchModule"; } }
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
UUID capID = UUID.Random();
|
||||
|
||||
if (m_URL == "localhost")
|
||||
{
|
||||
// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
||||
caps.RegisterHandler(
|
||||
"AvatarPickerSearch",
|
||||
new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName);
|
||||
caps.RegisterHandler("AvatarPickerSearch", m_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,13 +282,19 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
|
||||
IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData);
|
||||
|
||||
IRequestHandler getObjectPhysicsDataHandler
|
||||
= new RestStreamHandler(
|
||||
"POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null);
|
||||
m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler);
|
||||
IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost);
|
||||
m_HostCapsObj.RegisterHandler("GetObjectCost", getObjectCostHandler);
|
||||
IRequestHandler ResourceCostSelectedHandler = new RestStreamHandler("POST", capsBase + m_ResourceCostSelectedPath, ResourceCostSelected);
|
||||
m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler);
|
||||
IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation);
|
||||
|
||||
IRequestHandler UpdateAgentInformationHandler
|
||||
= new RestStreamHandler(
|
||||
"POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null);
|
||||
m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler);
|
||||
|
||||
m_HostCapsObj.RegisterHandler(
|
||||
@@ -361,18 +367,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
foreach (OSD c in capsRequested)
|
||||
validCaps.Add(c.AsString());
|
||||
|
||||
Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps);
|
||||
|
||||
// Add the external too
|
||||
foreach (KeyValuePair<string, string> kvp in m_HostCapsObj.ExternalCapsHandlers)
|
||||
{
|
||||
if (!validCaps.Contains(kvp.Key))
|
||||
continue;
|
||||
|
||||
caps[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
string result = LLSDHelpers.SerialiseLLSDReply(caps);
|
||||
string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps));
|
||||
|
||||
//m_log.DebugFormat("[CAPS] CapsRequest {0}", result);
|
||||
|
||||
@@ -748,6 +743,10 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
inType = (sbyte)InventoryType.Sound;
|
||||
assType = (sbyte)AssetType.Sound;
|
||||
}
|
||||
else if (inventoryType == "snapshot")
|
||||
{
|
||||
inType = (sbyte)InventoryType.Snapshot;
|
||||
}
|
||||
else if (inventoryType == "animation")
|
||||
{
|
||||
inType = (sbyte)InventoryType.Animation;
|
||||
|
||||
@@ -65,6 +65,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
/// </value>
|
||||
public int DebugLevel { get; set; }
|
||||
|
||||
// Viewer post requests timeout in 60 secs
|
||||
// https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44
|
||||
//
|
||||
private const int VIEWER_TIMEOUT = 60 * 1000;
|
||||
// Just to be safe, we work on a 10 sec shorter cycle
|
||||
private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000);
|
||||
|
||||
protected Scene m_scene;
|
||||
|
||||
private Dictionary<UUID, int> m_ids = new Dictionary<UUID, int>();
|
||||
@@ -84,7 +91,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
scene.RegisterModuleInterface<IEventQueue>(this);
|
||||
|
||||
scene.EventManager.OnClientClosed += ClientClosed;
|
||||
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
|
||||
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
@@ -113,7 +119,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return;
|
||||
|
||||
scene.EventManager.OnClientClosed -= ClientClosed;
|
||||
scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
|
||||
scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
|
||||
|
||||
scene.UnregisterModuleInterface<IEventQueue>(this);
|
||||
@@ -182,14 +187,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
if (!queues.ContainsKey(agentId))
|
||||
{
|
||||
/*
|
||||
m_log.DebugFormat(
|
||||
"[EVENTQUEUE]: Adding new queue for agent {0} in region {1}",
|
||||
agentId, m_scene.RegionInfo.RegionName);
|
||||
*/
|
||||
queues[agentId] = new Queue<OSD>();
|
||||
}
|
||||
|
||||
|
||||
return queues[agentId];
|
||||
}
|
||||
}
|
||||
@@ -221,8 +224,17 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
Queue<OSD> queue = GetQueue(avatarID);
|
||||
if (queue != null)
|
||||
{
|
||||
lock (queue)
|
||||
queue.Enqueue(ev);
|
||||
}
|
||||
else
|
||||
{
|
||||
OSDMap evMap = (OSDMap)ev;
|
||||
m_log.WarnFormat(
|
||||
"[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
|
||||
avatarID, evMap["message"], m_scene.Name);
|
||||
}
|
||||
}
|
||||
catch (NullReferenceException e)
|
||||
{
|
||||
@@ -237,44 +249,14 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private void ClientClosed(UUID agentID, Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
int count = 0;
|
||||
while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
//m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
lock (queues)
|
||||
{
|
||||
queues.Remove(agentID);
|
||||
}
|
||||
|
||||
List<UUID> removeitems = new List<UUID>();
|
||||
lock (m_AvatarQueueUUIDMapping)
|
||||
{
|
||||
foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID);
|
||||
if (ky == agentID)
|
||||
{
|
||||
removeitems.Add(ky);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (UUID ky in removeitems)
|
||||
{
|
||||
UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky];
|
||||
m_AvatarQueueUUIDMapping.Remove(ky);
|
||||
|
||||
string eqgPath = GenerateEqgCapPath(eventQueueGetUuid);
|
||||
MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}",
|
||||
// eqgPath, agentID, m_scene.RegionInfo.RegionName);
|
||||
}
|
||||
}
|
||||
m_AvatarQueueUUIDMapping.Remove(agentID);
|
||||
|
||||
UUID searchval = UUID.Zero;
|
||||
|
||||
@@ -295,19 +277,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
foreach (UUID ky in removeitems)
|
||||
m_QueueUUIDAvatarMapping.Remove(ky);
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeChildAgent(ScenePresence avatar)
|
||||
{
|
||||
//m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName);
|
||||
//lock (m_ids)
|
||||
// {
|
||||
//if (m_ids.ContainsKey(avatar.UUID))
|
||||
//{
|
||||
// close the event queue.
|
||||
//m_ids[avatar.UUID] = -1;
|
||||
//}
|
||||
//}
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -323,9 +295,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
// Register an event queue for the client
|
||||
|
||||
//m_log.DebugFormat(
|
||||
// "[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
|
||||
// agentID, caps, m_scene.RegionInfo.RegionName);
|
||||
m_log.DebugFormat(
|
||||
"[EVENTQUEUE]: OnRegisterCaps: agentID {0} caps {1} region {2}",
|
||||
agentID, caps, m_scene.RegionInfo.RegionName);
|
||||
|
||||
// Let's instantiate a Queue for this agent right now
|
||||
TryGetQueue(agentID);
|
||||
@@ -359,28 +331,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
|
||||
}
|
||||
|
||||
string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID);
|
||||
|
||||
// Register this as a caps handler
|
||||
// FIXME: Confusingly, we need to register separate as a capability so that the client is told about
|
||||
// EventQueueGet when it receive capability information, but then we replace the rest handler immediately
|
||||
// afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but
|
||||
// really it should be possible to directly register the poll handler as a capability.
|
||||
caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null));
|
||||
// delegate(Hashtable m_dhttpMethod)
|
||||
// {
|
||||
// return ProcessQueue(m_dhttpMethod, agentID, caps);
|
||||
// }));
|
||||
|
||||
// This will persist this beyond the expiry of the caps handlers
|
||||
// TODO: Add EventQueueGet name/description for diagnostics
|
||||
MainServer.Instance.AddPollServiceHTTPHandler(
|
||||
eventQueueGetPath,
|
||||
new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000));
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
|
||||
// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName);
|
||||
caps.RegisterPollHandler(
|
||||
"EventQueueGet",
|
||||
new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS));
|
||||
|
||||
Random rnd = new Random(Environment.TickCount);
|
||||
lock (m_ids)
|
||||
@@ -398,7 +351,10 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
Queue<OSD> queue = GetQueue(agentID);
|
||||
if (queue != null)
|
||||
lock (queue)
|
||||
{
|
||||
//m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count);
|
||||
return queue.Count > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -414,16 +370,21 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
OSDMap ev = (OSDMap)element;
|
||||
m_log.DebugFormat(
|
||||
"Eq OUT {0,-30} to {1,-20} {2,-20}",
|
||||
ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName);
|
||||
ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public Hashtable GetEvents(UUID requestID, UUID pAgentId)
|
||||
{
|
||||
if (DebugLevel >= 2)
|
||||
m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName);
|
||||
m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name);
|
||||
|
||||
Queue<OSD> queue = GetQueue(pAgentId);
|
||||
if (queue == null)
|
||||
{
|
||||
return NoEvents(requestID, pAgentId);
|
||||
}
|
||||
|
||||
Queue<OSD> queue = TryGetQueue(pAgentId);
|
||||
OSD element;
|
||||
lock (queue)
|
||||
{
|
||||
@@ -750,34 +711,46 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
|
||||
public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID)
|
||||
public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
OSD item = EventQueueHelper.EnableSimulator(handle, endPoint);
|
||||
m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
|
||||
"[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
|
||||
|
||||
OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
|
||||
public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath)
|
||||
public virtual void EstablishAgentCommunication(UUID avatarID, IPEndPoint endPoint, string capsPath,
|
||||
ulong regionHandle, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath);
|
||||
m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
|
||||
"[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
|
||||
OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
|
||||
public virtual void TeleportFinishEvent(ulong regionHandle, byte simAccess,
|
||||
IPEndPoint regionExternalEndPoint,
|
||||
uint locationID, uint flags, string capsURL,
|
||||
UUID avatarID)
|
||||
UUID avatarID, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
|
||||
"[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
|
||||
|
||||
OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
|
||||
locationID, flags, capsURL, avatarID);
|
||||
locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
|
||||
public virtual void CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
|
||||
IPEndPoint newRegionExternalEndPoint,
|
||||
string capsURL, UUID avatarID, UUID sessionID)
|
||||
string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
|
||||
"[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
|
||||
|
||||
OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
|
||||
capsURL, avatarID, sessionID);
|
||||
capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
|
||||
@@ -794,12 +767,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
}
|
||||
|
||||
public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat,
|
||||
public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat,
|
||||
bool isModerator, bool textMute)
|
||||
{
|
||||
OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat,
|
||||
isModerator, textMute);
|
||||
Enqueue(item, toAgent);
|
||||
Enqueue(item, fromAgent);
|
||||
//m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,13 +70,15 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return llsdEvent;
|
||||
}
|
||||
|
||||
public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint)
|
||||
public static OSD EnableSimulator(ulong handle, IPEndPoint endPoint, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
OSDMap llsdSimInfo = new OSDMap(3);
|
||||
OSDMap llsdSimInfo = new OSDMap(5);
|
||||
|
||||
llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
|
||||
llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
|
||||
llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
|
||||
llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
|
||||
OSDArray arr = new OSDArray(1);
|
||||
arr.Add(llsdSimInfo);
|
||||
@@ -104,7 +106,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
public static OSD CrossRegion(ulong handle, Vector3 pos, Vector3 lookAt,
|
||||
IPEndPoint newRegionExternalEndPoint,
|
||||
string capsURL, UUID agentID, UUID sessionID)
|
||||
string capsURL, UUID agentID, UUID sessionID,
|
||||
int regionSizeX, int regionSizeY)
|
||||
{
|
||||
OSDArray lookAtArr = new OSDArray(3);
|
||||
lookAtArr.Add(OSD.FromReal(lookAt.X));
|
||||
@@ -130,11 +133,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
OSDArray agentDataArr = new OSDArray(1);
|
||||
agentDataArr.Add(agentDataMap);
|
||||
|
||||
OSDMap regionDataMap = new OSDMap(4);
|
||||
OSDMap regionDataMap = new OSDMap(6);
|
||||
regionDataMap.Add("RegionHandle", OSD.FromBinary(ulongToByteArray(handle)));
|
||||
regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
|
||||
regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
|
||||
regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
|
||||
regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
|
||||
OSDArray regionDataArr = new OSDArray(1);
|
||||
regionDataArr.Add(regionDataMap);
|
||||
@@ -148,8 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
}
|
||||
|
||||
public static OSD TeleportFinishEvent(
|
||||
ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
|
||||
uint locationID, uint flags, string capsURL, UUID agentID)
|
||||
ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
|
||||
uint locationID, uint flags, string capsURL, UUID agentID,
|
||||
int regionSizeX, int regionSizeY)
|
||||
{
|
||||
// not sure why flags get overwritten here
|
||||
if ((flags & (uint)TeleportFlags.IsFlying) != 0)
|
||||
@@ -167,6 +173,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
|
||||
// info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
|
||||
info.Add("TeleportFlags", OSD.FromUInteger(flags));
|
||||
info.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
info.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
|
||||
OSDArray infoArr = new OSDArray();
|
||||
infoArr.Add(info);
|
||||
@@ -194,12 +202,18 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return BuildEvent("ScriptRunningReply", body);
|
||||
}
|
||||
|
||||
public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap)
|
||||
public static OSD EstablishAgentCommunication(UUID agentID, string simIpAndPort, string seedcap,
|
||||
ulong regionHandle, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
OSDMap body = new OSDMap(3);
|
||||
body.Add("agent-id", new OSDUUID(agentID));
|
||||
body.Add("sim-ip-and-port", new OSDString(simIpAndPort));
|
||||
body.Add("seed-capability", new OSDString(seedcap));
|
||||
OSDMap body = new OSDMap(6)
|
||||
{
|
||||
{"agent-id", new OSDUUID(agentID)},
|
||||
{"sim-ip-and-port", new OSDString(simIpAndPort)},
|
||||
{"seed-capability", new OSDString(seedcap)},
|
||||
{"region-handle", OSD.FromULong(regionHandle)},
|
||||
{"region-size-x", OSD.FromInteger(regionSizeX)},
|
||||
{"region-size-y", OSD.FromInteger(regionSizeY)}
|
||||
};
|
||||
|
||||
return BuildEvent("EstablishAgentCommunication", body);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddForClient()
|
||||
public void TestAddForClient()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
@@ -88,15 +88,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveForClient()
|
||||
public void TestRemoveForClient()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
UUID spId = TestHelpers.ParseTail(0x1);
|
||||
|
||||
SceneHelpers.AddScenePresence(m_scene, spId);
|
||||
m_scene.IncomingCloseAgent(spId, false);
|
||||
m_scene.CloseAgent(spId, false);
|
||||
|
||||
// TODO: Add more assertions for the other aspects of event queues
|
||||
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
|
||||
|
||||
@@ -246,8 +246,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private Scene m_scene;
|
||||
private MeshCapsDataThrottler m_throttler;
|
||||
public PollServiceMeshEventArgs(UUID pId, Scene scene) :
|
||||
base(null, null, null, null, pId, int.MaxValue)
|
||||
public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
|
||||
base(null, uri, null, null, null, pId, int.MaxValue)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
|
||||
@@ -361,7 +361,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
string capUrl = "/CAPS/" + UUID.Random() + "/";
|
||||
|
||||
// Register this as a poll service
|
||||
PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
|
||||
PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
|
||||
|
||||
args.Type = PollServiceEventArgs.EventType.Mesh;
|
||||
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
|
||||
|
||||
@@ -84,6 +84,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>();
|
||||
|
||||
private string m_URL;
|
||||
|
||||
#region ISharedRegionModule Members
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
@@ -215,7 +217,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
private Scene m_scene;
|
||||
private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000);
|
||||
public PollServiceTextureEventArgs(UUID pId, Scene scene) :
|
||||
base(null, null, null, null, pId, int.MaxValue)
|
||||
base(null, "", null, null, null, pId, int.MaxValue)
|
||||
{
|
||||
m_scene = scene;
|
||||
// x is request id, y is userid
|
||||
@@ -368,7 +370,11 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
port = MainServer.Instance.SSLPort;
|
||||
protocol = "https";
|
||||
}
|
||||
caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
|
||||
IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
|
||||
if (handler != null)
|
||||
handler.RegisterExternalUserCapsHandler(agentID, caps, "GetTexture", capUrl);
|
||||
else
|
||||
caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
|
||||
m_pollservices[agentID] = args;
|
||||
m_capsDict[agentID] = capUrl;
|
||||
}
|
||||
@@ -380,13 +386,11 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private void DeregisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
string capUrl;
|
||||
PollServiceTextureEventArgs args;
|
||||
if (m_capsDict.TryGetValue(agentID, out capUrl))
|
||||
{
|
||||
MainServer.Instance.RemoveHTTPHandler("", capUrl);
|
||||
m_capsDict.Remove(agentID);
|
||||
}
|
||||
|
||||
MainServer.Instance.RemoveHTTPHandler("", m_URL);
|
||||
m_capsDict.Remove(agentID);
|
||||
|
||||
if (m_pollservices.TryGetValue(agentID, out args))
|
||||
{
|
||||
m_pollservices.Remove(agentID);
|
||||
|
||||
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
Quaternion rotation = Quaternion.Identity;
|
||||
Vector3 scale = Vector3.Zero;
|
||||
int state = 0;
|
||||
int lastattach = 0;
|
||||
|
||||
if (r.Type != OSDType.Map) // not a proper req
|
||||
return responsedata;
|
||||
@@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
ray_target_id = ObjMap["RayTargetId"].AsUUID();
|
||||
state = ObjMap["State"].AsInteger();
|
||||
lastattach = ObjMap["LastAttachPoint"].AsInteger();
|
||||
try
|
||||
{
|
||||
ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3();
|
||||
@@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
//session_id = rm["session_id"].AsUUID();
|
||||
state = rm["state"].AsInteger();
|
||||
lastattach = rm["last_attach_point"].AsInteger();
|
||||
try
|
||||
{
|
||||
ray_end = ((OSDArray)rm["ray_end"]).AsVector3();
|
||||
@@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
pbs.ProfileEnd = (ushort)profile_end;
|
||||
pbs.Scale = scale;
|
||||
pbs.State = (byte)state;
|
||||
pbs.LastAttachPoint = (byte)lastattach;
|
||||
|
||||
SceneObjectGroup obj = null; ;
|
||||
|
||||
|
||||
@@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
pbs.ProfileEnd = (ushort) obj.ProfileEnd;
|
||||
pbs.Scale = obj.Scale;
|
||||
pbs.State = (byte) 0;
|
||||
pbs.LastAttachPoint = (byte) 0;
|
||||
SceneObjectPart prim = new SceneObjectPart();
|
||||
prim.UUID = UUID.Random();
|
||||
prim.CreatorID = AgentId;
|
||||
|
||||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.7.6.*")]
|
||||
[assembly: AssemblyVersion("0.8.0.*")]
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_isGod = m_scene.Permissions.IsGod(agentID);
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
StreamReader reader = new StreamReader(request);
|
||||
string message = reader.ReadToEnd();
|
||||
|
||||
@@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
/// </summary>
|
||||
private OSDMap m_features = new OSDMap();
|
||||
|
||||
private string m_MapImageServerURL = string.Empty;
|
||||
private string m_SearchURL = string.Empty;
|
||||
private bool m_ExportSupported = false;
|
||||
|
||||
@@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
IConfig config = source.Configs["SimulatorFeatures"];
|
||||
if (config != null)
|
||||
{
|
||||
m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty);
|
||||
if (m_MapImageServerURL != string.Empty)
|
||||
{
|
||||
m_MapImageServerURL = m_MapImageServerURL.Trim();
|
||||
if (!m_MapImageServerURL.EndsWith("/"))
|
||||
m_MapImageServerURL = m_MapImageServerURL + "/";
|
||||
}
|
||||
|
||||
{
|
||||
m_SearchURL = config.GetString("SearchServerURI", string.Empty);
|
||||
|
||||
m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported);
|
||||
@@ -149,15 +140,16 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_features["PhysicsShapeTypes"] = typesMap;
|
||||
|
||||
// Extra information for viewers that want to use it
|
||||
OSDMap gridServicesMap = new OSDMap();
|
||||
if (m_MapImageServerURL != string.Empty)
|
||||
gridServicesMap["map-server-url"] = m_MapImageServerURL;
|
||||
// TODO: Take these out of here into their respective modules, like map-server-url
|
||||
OSDMap extrasMap = new OSDMap();
|
||||
if (m_SearchURL != string.Empty)
|
||||
gridServicesMap["search"] = m_SearchURL;
|
||||
m_features["GridServices"] = gridServicesMap;
|
||||
|
||||
extrasMap["search-server-url"] = m_SearchURL;
|
||||
if (m_ExportSupported)
|
||||
m_features["ExportSupported"] = true;
|
||||
extrasMap["ExportSupported"] = true;
|
||||
|
||||
if (extrasMap.Count > 0)
|
||||
m_features["OpenSimExtras"] = extrasMap;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,11 +64,18 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private Scene m_scene;
|
||||
private bool m_persistBakedTextures;
|
||||
private string m_URL;
|
||||
|
||||
private IBakedTextureModule m_BakedTextureModule;
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
|
||||
|
||||
IConfig appearanceConfig = source.Configs["Appearance"];
|
||||
if (appearanceConfig != null)
|
||||
m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
|
||||
@@ -280,23 +287,28 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
|
||||
caps, m_scene.AssetService, m_persistBakedTextures);
|
||||
// UUID capID = UUID.Random();
|
||||
|
||||
|
||||
|
||||
caps.RegisterHandler(
|
||||
"UploadBakedTexture",
|
||||
new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
|
||||
avatarhandler.UploadBakedTexture,
|
||||
//caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
|
||||
if (m_URL == "localhost")
|
||||
{
|
||||
UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
|
||||
caps, m_scene.AssetService, m_persistBakedTextures);
|
||||
|
||||
caps.RegisterHandler(
|
||||
"UploadBakedTexture",
|
||||
agentID.ToString()));
|
||||
|
||||
|
||||
|
||||
|
||||
new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
|
||||
avatarhandler.UploadBakedTexture,
|
||||
"UploadBakedTexture",
|
||||
agentID.ToString()));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
caps.RegisterHandler("UploadBakedTexture", m_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
private IInventoryService m_InventoryService;
|
||||
private ILibraryService m_LibraryService;
|
||||
|
||||
private bool m_Enabled;
|
||||
|
||||
private string m_fetchInventoryDescendents2Url;
|
||||
private string m_webFetchInventoryDescendentsUrl;
|
||||
|
||||
private static WebFetchInvDescHandler m_webFetchHandler;
|
||||
|
||||
private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
|
||||
private static Thread[] m_workerThreads = null;
|
||||
|
||||
private static DoubleQueue<aPollRequest> m_queue =
|
||||
@@ -83,22 +87,45 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
|
||||
m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
|
||||
|
||||
if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
|
||||
{
|
||||
m_Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRegion(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_scene = s;
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
|
||||
|
||||
foreach (Thread t in m_workerThreads)
|
||||
Watchdog.AbortThread(t.ManagedThreadId);
|
||||
|
||||
m_scene = null;
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene s)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_InventoryService = m_scene.InventoryService;
|
||||
m_LibraryService = m_scene.LibraryService;
|
||||
|
||||
@@ -106,7 +133,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
|
||||
|
||||
if (m_workerThreads == null)
|
||||
{
|
||||
@@ -140,12 +166,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
#endregion
|
||||
|
||||
~WebFetchInvDescModule()
|
||||
{
|
||||
foreach (Thread t in m_workerThreads)
|
||||
Watchdog.AbortThread(t.ManagedThreadId);
|
||||
}
|
||||
|
||||
private class PollServiceInventoryEventArgs : PollServiceEventArgs
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@@ -155,8 +175,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private Scene m_scene;
|
||||
|
||||
public PollServiceInventoryEventArgs(Scene scene, UUID pId) :
|
||||
base(null, null, null, null, pId, int.MaxValue)
|
||||
public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) :
|
||||
base(null, url, null, null, null, pId, int.MaxValue)
|
||||
{
|
||||
m_scene = scene;
|
||||
|
||||
@@ -278,53 +298,72 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
|
||||
|
||||
lock (responses)
|
||||
responses[requestID] = response;
|
||||
responses[requestID] = response;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
string capUrl = "/CAPS/" + UUID.Random() + "/";
|
||||
|
||||
// Register this as a poll service
|
||||
PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
|
||||
|
||||
args.Type = PollServiceEventArgs.EventType.Inventory;
|
||||
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
|
||||
|
||||
string hostName = m_scene.RegionInfo.ExternalHostName;
|
||||
uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
|
||||
string protocol = "http";
|
||||
|
||||
if (MainServer.Instance.UseSSL)
|
||||
{
|
||||
hostName = MainServer.Instance.SSLCommonName;
|
||||
port = MainServer.Instance.SSLPort;
|
||||
protocol = "https";
|
||||
}
|
||||
caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
|
||||
|
||||
m_capsDict[agentID] = capUrl;
|
||||
RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
|
||||
}
|
||||
|
||||
private void DeregisterCaps(UUID agentID, Caps caps)
|
||||
private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url)
|
||||
{
|
||||
string capUrl;
|
||||
|
||||
if (m_capsDict.TryGetValue(agentID, out capUrl))
|
||||
// disable the cap clause
|
||||
if (url == "")
|
||||
{
|
||||
MainServer.Instance.RemoveHTTPHandler("", capUrl);
|
||||
m_capsDict.Remove(agentID);
|
||||
return;
|
||||
}
|
||||
// handled by the simulator
|
||||
else if (url == "localhost")
|
||||
{
|
||||
capUrl = "/CAPS/" + UUID.Random() + "/";
|
||||
|
||||
// Register this as a poll service
|
||||
PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID);
|
||||
args.Type = PollServiceEventArgs.EventType.Inventory;
|
||||
|
||||
caps.RegisterPollHandler(capName, args);
|
||||
}
|
||||
// external handler
|
||||
else
|
||||
{
|
||||
capUrl = url;
|
||||
IExternalCapsModule handler = m_scene.RequestModuleInterface<IExternalCapsModule>();
|
||||
if (handler != null)
|
||||
handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl);
|
||||
else
|
||||
caps.RegisterHandler(capName, capUrl);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}",
|
||||
// capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
|
||||
}
|
||||
|
||||
// private void DeregisterCaps(UUID agentID, Caps caps)
|
||||
// {
|
||||
// string capUrl;
|
||||
//
|
||||
// if (m_capsDict.TryGetValue(agentID, out capUrl))
|
||||
// {
|
||||
// MainServer.Instance.RemoveHTTPHandler("", capUrl);
|
||||
// m_capsDict.Remove(agentID);
|
||||
// }
|
||||
// }
|
||||
|
||||
private void DoInventoryRequests()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
aPollRequest poolreq = m_queue.Dequeue();
|
||||
|
||||
poolreq.thepoll.Process(poolreq);
|
||||
if (poolreq != null && poolreq.thepoll != null)
|
||||
poolreq.thepoll.Process(poolreq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,12 +424,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// foreign user is visiting, we need to try again after the first fail to the local
|
||||
// asset service.
|
||||
string assetServerURL = string.Empty;
|
||||
if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL))
|
||||
if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL))
|
||||
{
|
||||
if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("="))
|
||||
assetServerURL = assetServerURL + "/";
|
||||
|
||||
m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
|
||||
// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id);
|
||||
AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived);
|
||||
return;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUpdates()
|
||||
{
|
||||
J2KImage image = GetHighestPriorityImage();
|
||||
|
||||
return image != null && image.IsDecoded;
|
||||
}
|
||||
|
||||
public bool ProcessImageQueue(int packetsToSend)
|
||||
{
|
||||
int packetsSent = 0;
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Net;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
|
||||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// hooked to put more data on the empty queue</summary>
|
||||
public event QueueEmpty OnQueueEmpty;
|
||||
|
||||
public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates;
|
||||
|
||||
/// <summary>AgentID for this client</summary>
|
||||
public readonly UUID AgentID;
|
||||
/// <summary>The remote address of the connected client</summary>
|
||||
@@ -160,6 +163,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private int m_maxRTO = 60000;
|
||||
public bool m_deliverPackets = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is the percentage of the udp texture queue to add to the task queue since
|
||||
/// textures are now generally handled through http.
|
||||
/// </summary>
|
||||
private double m_cannibalrate = 0.0;
|
||||
|
||||
private ClientInfo m_info = new ClientInfo();
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
@@ -197,6 +208,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Create an array of token buckets for this clients different throttle categories
|
||||
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||
|
||||
m_cannibalrate = rates.CannibalizeTextureRate;
|
||||
|
||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||
{
|
||||
ThrottleOutPacketType type = (ThrottleOutPacketType)i;
|
||||
@@ -241,20 +254,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
|
||||
// of pending and needed ACKs for every client every time some method wants information about
|
||||
// this connection is a recipe for poor performance
|
||||
ClientInfo info = new ClientInfo();
|
||||
info.pendingAcks = new Dictionary<uint, uint>();
|
||||
info.needAck = new Dictionary<uint, byte[]>();
|
||||
|
||||
info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||
info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||
info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||
info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||
info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||
info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||
info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||
info.totalThrottle = (int)m_throttleCategory.DripRate;
|
||||
m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||
m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||
m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||
m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||
m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||
m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||
m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||
m_info.totalThrottle = (int)m_throttleCategory.DripRate;
|
||||
|
||||
return info;
|
||||
return m_info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -348,6 +358,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
texture = Math.Max(texture, LLUDPServer.MTU);
|
||||
asset = Math.Max(asset, LLUDPServer.MTU);
|
||||
|
||||
// Since most textures are now delivered through http, make it possible
|
||||
// to cannibalize some of the bw from the texture throttle to use for
|
||||
// the task queue (e.g. object updates)
|
||||
task = task + (int)(m_cannibalrate * texture);
|
||||
texture = (int)((1 - m_cannibalrate) * texture);
|
||||
|
||||
//int total = resend + land + wind + cloud + task + texture + asset;
|
||||
//m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
|
||||
// AgentID, resend, land, wind, cloud, task, texture, asset, total);
|
||||
@@ -646,15 +662,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <param name="categories">Throttle categories to fire the callback for</param>
|
||||
private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
|
||||
{
|
||||
if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
|
||||
{
|
||||
m_isQueueEmptyRunning = true;
|
||||
|
||||
int start = Environment.TickCount & Int32.MaxValue;
|
||||
const int MIN_CALLBACK_MS = 30;
|
||||
|
||||
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
if (m_nextOnQueueEmpty == 0)
|
||||
m_nextOnQueueEmpty = 1;
|
||||
|
||||
// Use a value of 0 to signal that FireQueueEmpty is running
|
||||
m_nextOnQueueEmpty = 0;
|
||||
// Asynchronously run the callback
|
||||
Util.FireAndForget(FireQueueEmpty, categories);
|
||||
// m_nextOnQueueEmpty = 0;
|
||||
|
||||
m_categories = categories;
|
||||
|
||||
if (HasUpdates(m_categories))
|
||||
{
|
||||
// Asynchronously run the callback
|
||||
Util.FireAndForget(FireQueueEmpty, categories);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_isQueueEmptyRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_isQueueEmptyRunning;
|
||||
private ThrottleOutPacketTypeFlags m_categories = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Fires the OnQueueEmpty callback and sets the minimum time that it
|
||||
/// can be called again
|
||||
@@ -664,22 +703,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// signature</param>
|
||||
private void FireQueueEmpty(object o)
|
||||
{
|
||||
const int MIN_CALLBACK_MS = 30;
|
||||
// int start = Environment.TickCount & Int32.MaxValue;
|
||||
// const int MIN_CALLBACK_MS = 30;
|
||||
|
||||
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
||||
QueueEmpty callback = OnQueueEmpty;
|
||||
|
||||
int start = Environment.TickCount & Int32.MaxValue;
|
||||
// if (m_udpServer.IsRunningOutbound)
|
||||
// {
|
||||
ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
|
||||
QueueEmpty callback = OnQueueEmpty;
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
try { callback(categories); }
|
||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
||||
}
|
||||
if (callback != null)
|
||||
{
|
||||
// if (m_udpServer.IsRunningOutbound)
|
||||
// {
|
||||
try { callback(categories); }
|
||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
|
||||
// }
|
||||
}
|
||||
// }
|
||||
|
||||
m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
if (m_nextOnQueueEmpty == 0)
|
||||
m_nextOnQueueEmpty = 1;
|
||||
// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
|
||||
// if (m_nextOnQueueEmpty == 0)
|
||||
// m_nextOnQueueEmpty = 1;
|
||||
|
||||
// }
|
||||
|
||||
m_isQueueEmptyRunning = false;
|
||||
}
|
||||
internal void ForceThrottleSetting(int throttle, int setting)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using NDesk.Options;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenSim.Framework;
|
||||
@@ -62,20 +63,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
|
||||
}
|
||||
|
||||
public void NetworkStop()
|
||||
{
|
||||
m_udpServer.Stop();
|
||||
}
|
||||
|
||||
public void AddScene(IScene scene)
|
||||
{
|
||||
m_udpServer.AddScene(scene);
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"ClientLogoutsDueToNoReceives",
|
||||
"Number of times a client has been logged out because no packets were received before the timeout.",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.None,
|
||||
stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingUDPReceivesCount",
|
||||
"Number of UDP receives performed",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.UdpReceives,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingPacketsProcessedCount",
|
||||
"Number of inbound UDP packets processed",
|
||||
"Number of inbound UDP packets processed",
|
||||
"Number of inbound LL protocol packets processed",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
@@ -83,6 +105,86 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingPacketsMalformedCount",
|
||||
"Number of inbound UDP packets that could not be recognized as LL protocol packets.",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
|
||||
StatVerbosity.Info));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingPacketsOrphanedCount",
|
||||
"Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
|
||||
StatVerbosity.Info));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"IncomingPacketsResentCount",
|
||||
"Number of inbound packets that clients indicate are resends.",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"OutgoingUDPSendsCount",
|
||||
"Number of UDP sends performed",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.UdpSends,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"OutgoingPacketsResentCount",
|
||||
"Number of packets resent because a client did not acknowledge receipt",
|
||||
"",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = m_udpServer.PacketsResentCount,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"AverageUDPProcessTime",
|
||||
"Average number of milliseconds taken to process each incoming UDP packet in a sample.",
|
||||
"This is for initial receive processing which is separate from the later client LL packet processing stage.",
|
||||
"ms",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.None,
|
||||
stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond,
|
||||
// stat =>
|
||||
// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7),
|
||||
StatVerbosity.Debug));
|
||||
}
|
||||
|
||||
public bool HandlesRegion(Location x)
|
||||
@@ -107,10 +209,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// </summary>
|
||||
public class LLUDPServer : OpenSimUDPBase
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
|
||||
public const int MTU = 1400;
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
/// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
|
||||
public int ClientLogoutsDueToNoReceives { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default packet debug level given to new clients
|
||||
/// </summary>
|
||||
public int DefaultClientPacketDebugLevel { get; set; }
|
||||
|
||||
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||
public readonly float TickCountResolution;
|
||||
@@ -184,6 +294,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
protected bool m_sendPing;
|
||||
|
||||
private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
|
||||
|
||||
/// <summary>
|
||||
/// Event used to signal when queued packets are available for sending.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
|
||||
/// Some data is sent immediately and not queued. That data would not trigger this event.
|
||||
/// </remarks>
|
||||
private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
|
||||
|
||||
private Pool<IncomingPacket> m_incomingPacketPool;
|
||||
|
||||
/// <summary>
|
||||
@@ -204,7 +324,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
public Socket Server { get { return null; } }
|
||||
|
||||
private int m_malformedCount = 0; // Guard against a spamming attack
|
||||
/// <summary>
|
||||
/// Record how many packets have been resent
|
||||
/// </summary>
|
||||
internal int PacketsResentCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record how many packets have been sent
|
||||
/// </summary>
|
||||
internal int PacketsSentCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record how many incoming packets are indicated as resends by clients.
|
||||
/// </summary>
|
||||
internal int IncomingPacketsResentCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record how many inbound packets could not be recognized as LLUDP packets.
|
||||
/// </summary>
|
||||
public int IncomingMalformedPacketCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record how many inbound packets could not be associated with a simulator circuit.
|
||||
/// </summary>
|
||||
public int IncomingOrphanedPacketCount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Record current outgoing client for monitoring purposes.
|
||||
@@ -461,6 +604,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_scene = (Scene)scene;
|
||||
m_location = new Location(m_scene.RegionInfo.RegionHandle);
|
||||
|
||||
StatsManager.RegisterStat(
|
||||
new Stat(
|
||||
"InboxPacketsCount",
|
||||
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||
"Number of LL protocol packets waiting for the second stage of processing after initial receive.",
|
||||
"",
|
||||
"clientstack",
|
||||
scene.Name,
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = packetInbox.Count,
|
||||
StatVerbosity.Debug));
|
||||
|
||||
// XXX: These stats are also pool stats but we register them separately since they are currently not
|
||||
// turned on and off by EnablePools()/DisablePools()
|
||||
StatsManager.RegisterStat(
|
||||
@@ -520,6 +676,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (UsePools)
|
||||
EnablePoolStats();
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug", false, "debug lludp packet",
|
||||
"debug lludp packet [--default] <level> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Turn on packet debugging",
|
||||
"If level > 255 then all incoming and outgoing packets are logged.\n"
|
||||
+ "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n"
|
||||
+ "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n"
|
||||
+ "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n"
|
||||
+ "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n"
|
||||
+ "If level <= 0 then no packets are logged.\n"
|
||||
+ "If --default is specified then the level becomes the default logging level for all subsequent agents.\n"
|
||||
+ "In this case, you cannot also specify an avatar name.\n"
|
||||
+ "If an avatar name is given then only packets from that avatar are logged.",
|
||||
HandlePacketCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
@@ -559,10 +730,78 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
"debug lludp status",
|
||||
"Return status of LLUDP packet processing.",
|
||||
HandleStatusCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp toggle agentupdate",
|
||||
"debug lludp toggle agentupdate",
|
||||
"Toggle whether agentupdate packets are processed or simply discarded.",
|
||||
HandleAgentUpdateCommand);
|
||||
}
|
||||
|
||||
private void HandlePacketCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
bool setAsDefaultLevel = false;
|
||||
OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null);
|
||||
List<string> filteredArgs = optionSet.Parse(args);
|
||||
|
||||
string name = null;
|
||||
|
||||
if (filteredArgs.Count == 6)
|
||||
{
|
||||
if (!setAsDefaultLevel)
|
||||
{
|
||||
name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredArgs.Count > 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(filteredArgs[3], out newDebug))
|
||||
{
|
||||
if (setAsDefaultLevel)
|
||||
{
|
||||
DefaultClientPacketDebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scene.ForEachScenePresence(sp =>
|
||||
{
|
||||
if (name == null || sp.Name == name)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug for {0} ({1}) set to {2} in {3}",
|
||||
sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name);
|
||||
|
||||
sp.ControllingClient.DebugPacketLevel = newDebug;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [<first-name> <last-name>]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStartCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
|
||||
@@ -580,6 +819,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void HandleStopCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
|
||||
@@ -597,6 +839,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void HandlePoolCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
|
||||
@@ -627,8 +872,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
bool m_discardAgentUpdates;
|
||||
|
||||
private void HandleAgentUpdateCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
m_discardAgentUpdates = !m_discardAgentUpdates;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name);
|
||||
}
|
||||
|
||||
private void HandleStatusCommand(string module, string[] args)
|
||||
{
|
||||
if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene)
|
||||
return;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
|
||||
|
||||
@@ -636,6 +897,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
|
||||
}
|
||||
|
||||
public bool HandlesRegion(Location x)
|
||||
@@ -643,44 +907,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return x == m_location;
|
||||
}
|
||||
|
||||
public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
|
||||
{
|
||||
// CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
|
||||
if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
|
||||
allowSplitting = false;
|
||||
|
||||
if (allowSplitting && packet.HasVariableBlocks)
|
||||
{
|
||||
byte[][] datas = packet.ToBytesMultiple();
|
||||
int packetCount = datas.Length;
|
||||
|
||||
if (packetCount < 1)
|
||||
m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
|
||||
|
||||
for (int i = 0; i < packetCount; i++)
|
||||
{
|
||||
byte[] data = datas[i];
|
||||
m_scene.ForEachClient(
|
||||
delegate(IClientAPI client)
|
||||
{
|
||||
if (client is LLClientView)
|
||||
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] data = packet.ToBytes();
|
||||
m_scene.ForEachClient(
|
||||
delegate(IClientAPI client)
|
||||
{
|
||||
if (client is LLClientView)
|
||||
SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
|
||||
// {
|
||||
// // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way
|
||||
// if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting)
|
||||
// allowSplitting = false;
|
||||
//
|
||||
// if (allowSplitting && packet.HasVariableBlocks)
|
||||
// {
|
||||
// byte[][] datas = packet.ToBytesMultiple();
|
||||
// int packetCount = datas.Length;
|
||||
//
|
||||
// if (packetCount < 1)
|
||||
// m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length);
|
||||
//
|
||||
// for (int i = 0; i < packetCount; i++)
|
||||
// {
|
||||
// byte[] data = datas[i];
|
||||
// m_scene.ForEachClient(
|
||||
// delegate(IClientAPI client)
|
||||
// {
|
||||
// if (client is LLClientView)
|
||||
// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// byte[] data = packet.ToBytes();
|
||||
// m_scene.ForEachClient(
|
||||
// delegate(IClientAPI client)
|
||||
// {
|
||||
// if (client is LLClientView)
|
||||
// SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null);
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Start the process of sending a packet to the client.
|
||||
@@ -700,6 +964,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
|
||||
allowSplitting = false;
|
||||
|
||||
bool packetQueued = false;
|
||||
|
||||
if (allowSplitting && packet.HasVariableBlocks)
|
||||
{
|
||||
byte[][] datas = packet.ToBytesMultiple();
|
||||
@@ -711,16 +977,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
for (int i = 0; i < packetCount; i++)
|
||||
{
|
||||
byte[] data = datas[i];
|
||||
SendPacketData(udpClient, data, packet.Type, category, method);
|
||||
|
||||
if (!SendPacketData(udpClient, data, packet.Type, category, method))
|
||||
packetQueued = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] data = packet.ToBytes();
|
||||
SendPacketData(udpClient, data, packet.Type, category, method);
|
||||
packetQueued = SendPacketData(udpClient, data, packet.Type, category, method);
|
||||
}
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
|
||||
if (packetQueued)
|
||||
m_dataPresentEvent.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -734,7 +1005,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// The method to call if the packet is not acked by the client. If null, then a standard
|
||||
/// resend of the packet is done.
|
||||
/// </param>
|
||||
public void SendPacketData(
|
||||
/// <returns>true if the data was sent immediately, false if it was queued for sending</returns>
|
||||
public bool SendPacketData(
|
||||
LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
|
||||
{
|
||||
int dataLength = data.Length;
|
||||
@@ -807,7 +1079,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// packet so that it isn't sent before a queued update packet.
|
||||
bool requestQueue = type == PacketType.KillObject;
|
||||
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
|
||||
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
|
||||
{
|
||||
SendPacketFinal(outgoingPacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
#endregion Queue or Send
|
||||
}
|
||||
@@ -883,7 +1161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Fire this out on a different thread so that we don't hold up outgoing packet processing for
|
||||
// everybody else if this is being called due to an ack timeout.
|
||||
// This is the same as processing as the async process of a logout request.
|
||||
Util.FireAndForget(o => DeactivateClientDueToTimeout(client));
|
||||
Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -988,6 +1266,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref udpClient.PacketsResent);
|
||||
|
||||
// We're not going to worry about interlock yet since its not currently critical that this total count
|
||||
// is 100% correct
|
||||
PacketsResentCount++;
|
||||
}
|
||||
|
||||
#endregion Sequence Number Assignment
|
||||
@@ -995,6 +1277,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Stats tracking
|
||||
Interlocked.Increment(ref udpClient.PacketsSent);
|
||||
|
||||
// We're not going to worry about interlock yet since its not currently critical that this total count
|
||||
// is 100% correct
|
||||
PacketsSentCount++;
|
||||
|
||||
// Put the UDP payload on the wire
|
||||
AsyncBeginSend(buffer);
|
||||
|
||||
@@ -1002,6 +1288,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
|
||||
}
|
||||
|
||||
private void RecordMalformedInboundPacket(IPEndPoint endPoint)
|
||||
{
|
||||
// if (m_malformedCount < 100)
|
||||
// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
|
||||
|
||||
IncomingMalformedPacketCount++;
|
||||
|
||||
if ((IncomingMalformedPacketCount % 10000) == 0)
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
|
||||
IncomingMalformedPacketCount, endPoint);
|
||||
}
|
||||
|
||||
public override void PacketReceived(UDPPacketBuffer buffer)
|
||||
{
|
||||
// Debugging/Profiling
|
||||
@@ -1023,6 +1322,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
|
||||
// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
|
||||
|
||||
RecordMalformedInboundPacket(endPoint);
|
||||
|
||||
return; // Drop undersized packet
|
||||
}
|
||||
|
||||
@@ -1041,6 +1342,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}",
|
||||
// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
|
||||
|
||||
RecordMalformedInboundPacket(endPoint);
|
||||
|
||||
return; // Malformed header
|
||||
}
|
||||
|
||||
@@ -1056,34 +1359,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Only allocate a buffer for zerodecoding if the packet is zerocoded
|
||||
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
|
||||
}
|
||||
catch (MalformedDataException)
|
||||
{
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}",
|
||||
// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
|
||||
|
||||
return; // Drop short packet
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (m_malformedCount < 100)
|
||||
if (IncomingMalformedPacketCount < 100)
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
|
||||
|
||||
m_malformedCount++;
|
||||
|
||||
if ((m_malformedCount % 100000) == 0)
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
|
||||
}
|
||||
|
||||
// Fail-safe check
|
||||
if (packet == null)
|
||||
{
|
||||
m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:",
|
||||
buffer.DataLength, buffer.RemoteEndPoint);
|
||||
m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
|
||||
if (IncomingMalformedPacketCount < 100)
|
||||
{
|
||||
m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
|
||||
buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
|
||||
}
|
||||
|
||||
RecordMalformedInboundPacket(endPoint);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1127,12 +1419,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
queue.Enqueue(buffer);
|
||||
return;
|
||||
}
|
||||
else if (packet.Type == PacketType.CompleteAgentMovement)
|
||||
{
|
||||
// Send ack straight away to let the viewer know that we got it.
|
||||
SendAckImmediate(endPoint, packet.Header.Sequence);
|
||||
|
||||
// We need to copy the endpoint so that it doesn't get changed when another thread reuses the
|
||||
// buffer.
|
||||
object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
|
||||
|
||||
Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which agent this packet came from
|
||||
if (client == null || !(client is LLClientView))
|
||||
{
|
||||
//m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
|
||||
|
||||
IncomingOrphanedPacketCount++;
|
||||
|
||||
if ((IncomingOrphanedPacketCount % 10000) == 0)
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
|
||||
IncomingOrphanedPacketCount, endPoint);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1211,6 +1524,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#region Incoming Packet Accounting
|
||||
|
||||
// We're not going to worry about interlock yet since its not currently critical that this total count
|
||||
// is 100% correct
|
||||
if (packet.Header.Resent)
|
||||
IncomingPacketsResentCount++;
|
||||
|
||||
// Check the archive of received reliable packet IDs to see whether we already received this packet
|
||||
if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
|
||||
{
|
||||
@@ -1233,6 +1551,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
|
||||
#endregion BinaryStats
|
||||
|
||||
if (packet.Type == PacketType.AgentUpdate)
|
||||
{
|
||||
if (m_discardAgentUpdates)
|
||||
return;
|
||||
|
||||
((LLClientView)client).TotalAgentUpdates++;
|
||||
|
||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||
|
||||
LLClientView llClient = client as LLClientView;
|
||||
if (agentUpdate.AgentData.SessionID != client.SessionId
|
||||
|| agentUpdate.AgentData.AgentID != client.AgentId
|
||||
|| !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
|
||||
{
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#region Ping Check Handling
|
||||
|
||||
if (packet.Type == PacketType.StartPingCheck)
|
||||
@@ -1421,7 +1758,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
// We only want to send initial data to new clients, not ones which are being converted from child to root.
|
||||
if (client != null)
|
||||
client.SceneAgent.SendInitialDataToMe();
|
||||
{
|
||||
AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
|
||||
bool tp = (aCircuit.teleportFlags > 0);
|
||||
// Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
|
||||
if (!tp)
|
||||
client.SceneAgent.SendInitialDataToMe();
|
||||
}
|
||||
|
||||
// Now we know we can handle more data
|
||||
Thread.Sleep(200);
|
||||
@@ -1476,6 +1819,116 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCompleteMovementIntoRegion(object o)
|
||||
{
|
||||
IPEndPoint endPoint = null;
|
||||
IClientAPI client = null;
|
||||
|
||||
try
|
||||
{
|
||||
object[] array = (object[])o;
|
||||
endPoint = (IPEndPoint)array[0];
|
||||
CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
|
||||
|
||||
// Determine which agent this packet came from
|
||||
// We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
|
||||
// simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
|
||||
// and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
|
||||
// packets asynchronously, we need to account for this thread proceeding more quickly than the
|
||||
// UseCircuitCode thread.
|
||||
int count = 40;
|
||||
while (count-- > 0)
|
||||
{
|
||||
if (m_scene.TryGetClient(endPoint, out client))
|
||||
{
|
||||
if (!client.IsActive)
|
||||
{
|
||||
// This check exists to catch a condition where the client has been closed by another thread
|
||||
// but has not yet been removed from the client manager (and possibly a new connection has
|
||||
// not yet been established).
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
|
||||
endPoint, client.Name, m_scene.Name);
|
||||
}
|
||||
else if (client.SceneAgent == null)
|
||||
{
|
||||
// This check exists to catch a condition where the new client has been added to the client
|
||||
// manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
|
||||
// eager, then the new ScenePresence may not have registered a listener for this messsage
|
||||
// before we try to process it.
|
||||
// XXX: A better long term fix may be to add the SceneAgent before the client is added to
|
||||
// the client manager
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
|
||||
endPoint, client.Name, m_scene.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
|
||||
endPoint, m_scene.Name);
|
||||
}
|
||||
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
|
||||
endPoint, m_scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (!client.IsActive || client.SceneAgent == null)
|
||||
{
|
||||
// This check exists to catch a condition where the client has been closed by another thread
|
||||
// but has not yet been removed from the client manager.
|
||||
// The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
|
||||
// purposes.
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
|
||||
endPoint, client.Name, m_scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IncomingPacket incomingPacket1;
|
||||
|
||||
// Inbox insertion
|
||||
if (UsePools)
|
||||
{
|
||||
incomingPacket1 = m_incomingPacketPool.GetObject();
|
||||
incomingPacket1.Client = (LLClientView)client;
|
||||
incomingPacket1.Packet = packet;
|
||||
}
|
||||
else
|
||||
{
|
||||
incomingPacket1 = new IncomingPacket((LLClientView)client, packet);
|
||||
}
|
||||
|
||||
packetInbox.Enqueue(incomingPacket1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
|
||||
endPoint != null ? endPoint.ToString() : "n/a",
|
||||
client != null ? client.Name : "unknown",
|
||||
client != null ? client.AgentId.ToString() : "unknown",
|
||||
e.Message,
|
||||
e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an ack immediately to the given endpoint.
|
||||
/// </summary>
|
||||
@@ -1544,6 +1997,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
||||
client.OnLogout += LogoutHandler;
|
||||
client.DebugPacketLevel = DefaultClientPacketDebugLevel;
|
||||
|
||||
((LLClientView)client).DisableFacelights = m_disableFacelights;
|
||||
|
||||
@@ -1562,21 +2016,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// regular client pings.
|
||||
/// </remarks>
|
||||
/// <param name='client'></param>
|
||||
private void DeactivateClientDueToTimeout(LLClientView client)
|
||||
/// <param name='timeoutTicks'></param>
|
||||
private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
|
||||
{
|
||||
lock (client.CloseSyncLock)
|
||||
{
|
||||
{
|
||||
ClientLogoutsDueToNoReceives++;
|
||||
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
|
||||
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
|
||||
|
||||
StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
|
||||
"[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
|
||||
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
|
||||
|
||||
if (!client.SceneAgent.IsChildAgent)
|
||||
client.Kick("Simulator logged you out due to connection timeout");
|
||||
|
||||
client.CloseWithoutChecks(true);
|
||||
client.Kick("Simulator logged you out due to connection timeout.");
|
||||
}
|
||||
|
||||
m_scene.CloseAgent(client.AgentId, true);
|
||||
}
|
||||
|
||||
private void IncomingPacketHandler()
|
||||
@@ -1592,6 +2047,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
IncomingPacket incomingPacket = null;
|
||||
|
||||
/*
|
||||
// HACK: This is a test to try and rate limit packet handling on Mono.
|
||||
// If it works, a more elegant solution can be devised
|
||||
if (Util.FireAndForgetCount() < 2)
|
||||
@@ -1599,6 +2055,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
//m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
|
||||
Thread.Sleep(30);
|
||||
}
|
||||
*/
|
||||
|
||||
if (packetInbox.Dequeue(100, ref incomingPacket))
|
||||
{
|
||||
@@ -1694,8 +2151,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
// If nothing was sent, sleep for the minimum amount of time before a
|
||||
// token bucket could get more tokens
|
||||
//if (!m_packetSent)
|
||||
// Thread.Sleep((int)TickCountResolution);
|
||||
//
|
||||
// Instead, now wait for data present to be explicitly signalled. Evidence so far is that with
|
||||
// modern mono it reduces CPU base load since there is no more continuous polling.
|
||||
if (!m_packetSent)
|
||||
Thread.Sleep((int)TickCountResolution);
|
||||
m_dataPresentEvent.WaitOne(100);
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
}
|
||||
@@ -1912,7 +2374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (!client.IsLoggingOut)
|
||||
{
|
||||
client.IsLoggingOut = true;
|
||||
client.Close(false, false);
|
||||
m_scene.CloseAgent(client.AgentId, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,36 @@ namespace OpenMetaverse
|
||||
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
||||
public bool IsRunningOutbound { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of UDP receives.
|
||||
/// </summary>
|
||||
public int UdpReceives { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of UDP sends
|
||||
/// </summary>
|
||||
public int UdpSends { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of receives over which to establish a receive time average.
|
||||
/// </summary>
|
||||
private readonly static int s_receiveTimeSamples = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Current number of samples taken to establish a receive time average.
|
||||
/// </summary>
|
||||
private int m_currentReceiveTimeSamples;
|
||||
|
||||
/// <summary>
|
||||
/// Cumulative receive time for the sample so far.
|
||||
/// </summary>
|
||||
private int m_receiveTicksInCurrentSamplePeriod;
|
||||
|
||||
/// <summary>
|
||||
/// The average time taken for each require receive in the last sample.
|
||||
/// </summary>
|
||||
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
@@ -111,6 +141,8 @@ namespace OpenMetaverse
|
||||
|
||||
if (!IsRunningInbound)
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop");
|
||||
|
||||
const int SIO_UDP_CONNRESET = -1744830452;
|
||||
|
||||
IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
|
||||
@@ -151,6 +183,8 @@ namespace OpenMetaverse
|
||||
/// </summary>
|
||||
public void StartOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = true;
|
||||
}
|
||||
|
||||
@@ -158,10 +192,8 @@ namespace OpenMetaverse
|
||||
{
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
// 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 IsRunningInbound = false to inform the other
|
||||
// threads that the socket is closed.
|
||||
m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop");
|
||||
|
||||
IsRunningInbound = false;
|
||||
m_udpSocket.Close();
|
||||
}
|
||||
@@ -169,6 +201,8 @@ namespace OpenMetaverse
|
||||
|
||||
public void StopOutbound()
|
||||
{
|
||||
m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop");
|
||||
|
||||
IsRunningOutbound = false;
|
||||
}
|
||||
|
||||
@@ -257,7 +291,16 @@ namespace OpenMetaverse
|
||||
m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
catch (ObjectDisposedException e)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,17 +310,21 @@ namespace OpenMetaverse
|
||||
// to AsyncBeginReceive
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
UdpReceives++;
|
||||
|
||||
// Asynchronous mode will start another receive before the
|
||||
// callback for this packet is even fired. Very parallel :-)
|
||||
if (m_asyncPacketHandling)
|
||||
AsyncBeginReceive();
|
||||
|
||||
// get the buffer that was created in AsyncBeginReceive
|
||||
// this is the received data
|
||||
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
|
||||
|
||||
try
|
||||
{
|
||||
// get the buffer that was created in AsyncBeginReceive
|
||||
// this is the received data
|
||||
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
|
||||
|
||||
int startTick = Util.EnvironmentTickCount();
|
||||
|
||||
// get the length of data actually read from the socket, store it with the
|
||||
// buffer
|
||||
buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
|
||||
@@ -285,9 +332,42 @@ namespace OpenMetaverse
|
||||
// call the abstract method PacketReceived(), passing the buffer that
|
||||
// has just been filled from the socket read.
|
||||
PacketReceived(buffer);
|
||||
|
||||
// If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler)
|
||||
// then a particular stat may be inaccurate due to a race condition. We won't worry about this
|
||||
// since this should be rare and won't cause a runtime problem.
|
||||
if (m_currentReceiveTimeSamples >= s_receiveTimeSamples)
|
||||
{
|
||||
AverageReceiveTicksForLastSamplePeriod
|
||||
= (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples;
|
||||
|
||||
m_receiveTicksInCurrentSamplePeriod = 0;
|
||||
m_currentReceiveTimeSamples = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick);
|
||||
m_currentReceiveTimeSamples++;
|
||||
}
|
||||
}
|
||||
catch (SocketException se)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ",
|
||||
UdpReceives, se.ErrorCode),
|
||||
se);
|
||||
}
|
||||
catch (ObjectDisposedException e)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(
|
||||
string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e);
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
finally
|
||||
{
|
||||
// if (UsePools)
|
||||
@@ -298,14 +378,13 @@ namespace OpenMetaverse
|
||||
if (!m_asyncPacketHandling)
|
||||
AsyncBeginReceive();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncBeginSend(UDPPacketBuffer buf)
|
||||
{
|
||||
if (IsRunningOutbound)
|
||||
{
|
||||
// if (IsRunningOutbound)
|
||||
// {
|
||||
try
|
||||
{
|
||||
m_udpSocket.BeginSendTo(
|
||||
@@ -319,7 +398,7 @@ namespace OpenMetaverse
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void AsyncEndSend(IAsyncResult result)
|
||||
@@ -328,6 +407,8 @@ namespace OpenMetaverse
|
||||
{
|
||||
// UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState;
|
||||
m_udpSocket.EndSendTo(result);
|
||||
|
||||
UdpSends++;
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
|
||||
@@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return packet;
|
||||
}
|
||||
|
||||
// private byte[] decoded_header = new byte[10];
|
||||
private static PacketType GetType(byte[] bytes)
|
||||
{
|
||||
byte[] decoded_header = new byte[10 + 8];
|
||||
ushort id;
|
||||
PacketFrequency freq;
|
||||
bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0;
|
||||
|
||||
if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
|
||||
if (bytes[6] == 0xFF)
|
||||
{
|
||||
Helpers.ZeroDecode(bytes, 16, decoded_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
|
||||
}
|
||||
|
||||
if (decoded_header[6] == 0xFF)
|
||||
{
|
||||
if (decoded_header[7] == 0xFF)
|
||||
if (bytes[7] == 0xFF)
|
||||
{
|
||||
id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
|
||||
freq = PacketFrequency.Low;
|
||||
if (isZeroCoded && bytes[8] == 0)
|
||||
id = bytes[10];
|
||||
else
|
||||
id = (ushort)((bytes[8] << 8) + bytes[9]);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = decoded_header[7];
|
||||
freq = PacketFrequency.Medium;
|
||||
id = bytes[7];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
id = decoded_header[6];
|
||||
freq = PacketFrequency.High;
|
||||
id = bytes[6];
|
||||
}
|
||||
|
||||
return Packet.GetType(id, freq);
|
||||
|
||||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.7.6.*")]
|
||||
[assembly: AssemblyVersion("0.8.0.*")]
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Tests.Common;
|
||||
using OpenSim.Tests.Common.Mock;
|
||||
@@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
{
|
||||
base.SetUp();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
StatsManager.SimExtraStats = new SimExtraStatsCollector();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
public void TestLogoutClientDueToAck()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
TestHelpers.EnableLogging();
|
||||
|
||||
IniConfigSource ics = new IniConfigSource();
|
||||
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
||||
@@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
|
||||
ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
|
||||
Assert.That(spAfterAckTimeout, Is.Null);
|
||||
|
||||
// TestHelpers.DisableLogging();
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net.Config;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
@@ -53,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
{
|
||||
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
|
||||
Util.FireAndForgetMethod = FireAndForgetMethod.None;
|
||||
|
||||
using (
|
||||
Stream resource
|
||||
= GetType().Assembly.GetManifestResourceStream(
|
||||
@@ -72,9 +76,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
[TestFixtureTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
|
||||
// threads. Possibly, later tests should be rewritten not to worry about such things.
|
||||
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
UUID userId = TestHelpers.ParseTail(0x3);
|
||||
|
||||
J2KDecoderModule j2kdm = new J2KDecoderModule();
|
||||
|
||||
@@ -52,17 +52,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
public override void Update(int frames) {}
|
||||
public override void LoadWorldMap() {}
|
||||
|
||||
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
|
||||
public override ISceneAgent AddNewAgent(IClientAPI client, PresenceType type)
|
||||
{
|
||||
client.OnObjectName += RecordObjectNameCall;
|
||||
|
||||
// FIXME
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void RemoveClient(UUID agentID, bool someReason) {}
|
||||
// public override void CloseAllAgents(uint circuitcode) {}
|
||||
|
||||
public override bool CloseAgent(UUID agentID, bool force) { return true; }
|
||||
|
||||
public override bool CheckClient(UUID clientId, IPEndPoint endPoint) { return true; }
|
||||
|
||||
public override void OtherRegionUp(GridRegion otherRegion) { }
|
||||
|
||||
public override bool TryGetScenePresence(UUID uuid, out ScenePresence sp) { sp = null; return false; }
|
||||
|
||||
@@ -59,6 +59,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>Flag used to enable adaptive throttles</summary>
|
||||
public bool AdaptiveThrottlesEnabled;
|
||||
|
||||
/// <summary>Amount of the texture throttle to steal for the task throttle</summary>
|
||||
public double CannibalizeTextureRate;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
@@ -80,6 +83,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||
|
||||
AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
|
||||
|
||||
CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
|
||||
CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user