Merge branch 'teravuswork' into avination
commit
0bf66434bc
|
@ -45,16 +45,53 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
{
|
{
|
||||||
public class GetMeshHandler
|
public class GetMeshHandler
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log =
|
private static readonly ILog m_log =
|
||||||
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
private IAssetService m_assetService;
|
private IAssetService m_assetService;
|
||||||
|
|
||||||
|
public const string DefaultFormat = "vnd.ll.mesh";
|
||||||
|
|
||||||
public GetMeshHandler(IAssetService assService)
|
public GetMeshHandler(IAssetService assService)
|
||||||
{
|
{
|
||||||
m_assetService = assService;
|
m_assetService = assService;
|
||||||
}
|
}
|
||||||
|
public Hashtable Handle(Hashtable request)
|
||||||
|
{
|
||||||
|
Hashtable ret = new Hashtable();
|
||||||
|
ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
|
||||||
|
ret["content_type"] = "text/plain";
|
||||||
|
ret["keepalive"] = false;
|
||||||
|
ret["reusecontext"] = false;
|
||||||
|
ret["int_bytes"] = 0;
|
||||||
|
string MeshStr = (string)request["mesh_id"];
|
||||||
|
|
||||||
|
|
||||||
|
//m_log.DebugFormat("[GETMESH]: called {0}", MeshStr);
|
||||||
|
|
||||||
|
if (m_assetService == null)
|
||||||
|
{
|
||||||
|
m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service");
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID meshID;
|
||||||
|
if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID))
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID);
|
||||||
|
|
||||||
|
|
||||||
|
ret = ProcessGetMesh(request, UUID.Zero, null);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
|
public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
|
||||||
{
|
{
|
||||||
Hashtable responsedata = new Hashtable();
|
Hashtable responsedata = new Hashtable();
|
||||||
|
@ -62,6 +99,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
responsedata["content_type"] = "text/plain";
|
responsedata["content_type"] = "text/plain";
|
||||||
responsedata["keepalive"] = false;
|
responsedata["keepalive"] = false;
|
||||||
responsedata["str_response_string"] = "Request wasn't what was expected";
|
responsedata["str_response_string"] = "Request wasn't what was expected";
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
|
||||||
string meshStr = string.Empty;
|
string meshStr = string.Empty;
|
||||||
|
|
||||||
|
@ -77,6 +115,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
responsedata["content_type"] = "text/plain";
|
responsedata["content_type"] = "text/plain";
|
||||||
responsedata["keepalive"] = false;
|
responsedata["keepalive"] = false;
|
||||||
responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh.";
|
responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh.";
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
return responsedata;
|
return responsedata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +125,100 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
{
|
{
|
||||||
if (mesh.Type == (SByte)AssetType.Mesh)
|
if (mesh.Type == (SByte)AssetType.Mesh)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Hashtable headers = new Hashtable();
|
||||||
|
responsedata["headers"] = headers;
|
||||||
|
|
||||||
|
string range = String.Empty;
|
||||||
|
|
||||||
|
if (((Hashtable)request["headers"])["range"] != null)
|
||||||
|
range = (string)((Hashtable)request["headers"])["range"];
|
||||||
|
|
||||||
|
else if (((Hashtable)request["headers"])["Range"] != null)
|
||||||
|
range = (string)((Hashtable)request["headers"])["Range"];
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics
|
||||||
|
{
|
||||||
|
// Range request
|
||||||
|
int start, end;
|
||||||
|
if (TryParseRange(range, out start, out end))
|
||||||
|
{
|
||||||
|
// Before clamping start make sure we can satisfy it in order to avoid
|
||||||
|
// sending back the last byte instead of an error status
|
||||||
|
if (start >= mesh.Data.Length)
|
||||||
|
{
|
||||||
|
responsedata["int_response_code"] = 404; //501; //410; //404;
|
||||||
|
responsedata["content_type"] = "text/plain";
|
||||||
|
responsedata["keepalive"] = false;
|
||||||
|
responsedata["str_response_string"] = "This range doesnt exist.";
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 3;
|
||||||
|
return responsedata;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end = Utils.Clamp(end, 0, mesh.Data.Length - 1);
|
||||||
|
start = Utils.Clamp(start, 0, end);
|
||||||
|
int len = end - start + 1;
|
||||||
|
|
||||||
|
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
|
||||||
|
|
||||||
|
if (start > 20000)
|
||||||
|
{
|
||||||
|
responsedata["int_lod"] = 3;
|
||||||
|
}
|
||||||
|
else if (start < 4097)
|
||||||
|
{
|
||||||
|
responsedata["int_lod"] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responsedata["int_lod"] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (start == 0 && len == mesh.Data.Length) // well redudante maybe
|
||||||
|
{
|
||||||
|
responsedata["int_response_code"] = (int) System.Net.HttpStatusCode.OK;
|
||||||
|
responsedata["bin_response_data"] = mesh.Data;
|
||||||
|
responsedata["int_bytes"] = mesh.Data.Length;
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 3;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responsedata["int_response_code"] =
|
||||||
|
(int) System.Net.HttpStatusCode.PartialContent;
|
||||||
|
headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end,
|
||||||
|
mesh.Data.Length);
|
||||||
|
|
||||||
|
byte[] d = new byte[len];
|
||||||
|
Array.Copy(mesh.Data, start, d, 0, len);
|
||||||
|
responsedata["bin_response_data"] = d;
|
||||||
|
responsedata["int_bytes"] = len;
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]);
|
||||||
responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
|
responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
|
||||||
responsedata["content_type"] = "application/vnd.ll.mesh";
|
responsedata["content_type"] = "application/vnd.ll.mesh";
|
||||||
responsedata["int_response_code"] = 200;
|
responsedata["int_response_code"] = 200;
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
|
||||||
|
responsedata["content_type"] = "application/vnd.ll.mesh";
|
||||||
|
responsedata["int_response_code"] = 200;
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Optionally add additional mesh types here
|
// Optionally add additional mesh types here
|
||||||
else
|
else
|
||||||
|
@ -97,6 +227,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
responsedata["content_type"] = "text/plain";
|
responsedata["content_type"] = "text/plain";
|
||||||
responsedata["keepalive"] = false;
|
responsedata["keepalive"] = false;
|
||||||
responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh.";
|
responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh.";
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 1;
|
||||||
return responsedata;
|
return responsedata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,11 +238,28 @@ namespace OpenSim.Capabilities.Handlers
|
||||||
responsedata["content_type"] = "text/plain";
|
responsedata["content_type"] = "text/plain";
|
||||||
responsedata["keepalive"] = false;
|
responsedata["keepalive"] = false;
|
||||||
responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!";
|
responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!";
|
||||||
|
responsedata["reusecontext"] = false;
|
||||||
|
responsedata["int_lod"] = 0;
|
||||||
return responsedata;
|
return responsedata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return responsedata;
|
return responsedata;
|
||||||
}
|
}
|
||||||
|
private bool TryParseRange(string header, out int start, out int end)
|
||||||
|
{
|
||||||
|
if (header.StartsWith("bytes="))
|
||||||
|
{
|
||||||
|
string[] rangeValues = header.Substring(6).Split('-');
|
||||||
|
if (rangeValues.Length == 2)
|
||||||
|
{
|
||||||
|
if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1135,6 +1135,8 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
void SetChildAgentThrottle(byte[] throttle);
|
void SetChildAgentThrottle(byte[] throttle);
|
||||||
|
|
||||||
|
void SetAgentThrottleSilent(int throttle, int setting);
|
||||||
|
|
||||||
void SendAvatarDataImmediate(ISceneEntity avatar);
|
void SendAvatarDataImmediate(ISceneEntity avatar);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -53,7 +53,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
LslHttp = 1,
|
LslHttp = 1,
|
||||||
Inventory = 2,
|
Inventory = 2,
|
||||||
Texture = 3
|
Texture = 3,
|
||||||
|
Mesh = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
public PollServiceEventArgs(
|
public PollServiceEventArgs(
|
||||||
|
|
|
@ -27,11 +27,14 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Mono.Addins;
|
using Mono.Addins;
|
||||||
|
using OpenSim.Framework.Monitoring;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
@ -58,7 +61,43 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
private bool m_Enabled = true;
|
private bool m_Enabled = true;
|
||||||
private string m_URL;
|
private string m_URL;
|
||||||
|
|
||||||
#region IRegionModuleBase Members
|
struct aPollRequest
|
||||||
|
{
|
||||||
|
public PollServiceMeshEventArgs thepoll;
|
||||||
|
public UUID reqID;
|
||||||
|
public Hashtable request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class aPollResponse
|
||||||
|
{
|
||||||
|
public Hashtable response;
|
||||||
|
public int bytes;
|
||||||
|
public int lod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private static GetMeshHandler m_getMeshHandler;
|
||||||
|
|
||||||
|
private IAssetService m_assetService = null;
|
||||||
|
|
||||||
|
private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
|
||||||
|
private static Thread[] m_workerThreads = null;
|
||||||
|
|
||||||
|
private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
|
||||||
|
new OpenMetaverse.BlockingQueue<aPollRequest>();
|
||||||
|
|
||||||
|
private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
|
||||||
|
|
||||||
|
#region ISharedRegionModule Members
|
||||||
|
|
||||||
|
~GetMeshModule()
|
||||||
|
{
|
||||||
|
foreach (Thread t in m_workerThreads)
|
||||||
|
Watchdog.AbortThread(t.ManagedThreadId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public Type ReplaceableInterface
|
public Type ReplaceableInterface
|
||||||
{
|
{
|
||||||
|
@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
// Cap doesn't exist
|
// Cap doesn't exist
|
||||||
if (m_URL != string.Empty)
|
if (m_URL != string.Empty)
|
||||||
m_Enabled = true;
|
m_Enabled = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRegion(Scene pScene)
|
public void AddRegion(Scene pScene)
|
||||||
|
@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_scene = pScene;
|
m_scene = pScene;
|
||||||
|
|
||||||
|
m_assetService = pScene.AssetService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveRegion(Scene scene)
|
public void RemoveRegion(Scene scene)
|
||||||
|
@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||||
|
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
|
||||||
|
m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
|
||||||
|
|
||||||
m_scene = null;
|
m_scene = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
|
m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
|
||||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||||
|
// We'll reuse the same handler for all requests.
|
||||||
|
m_getMeshHandler = new GetMeshHandler(m_assetService);
|
||||||
|
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
|
||||||
|
m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
|
||||||
|
|
||||||
|
if (m_workerThreads == null)
|
||||||
|
{
|
||||||
|
m_workerThreads = new Thread[2];
|
||||||
|
|
||||||
|
for (uint i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
|
||||||
|
String.Format("MeshWorkerThread{0}", i),
|
||||||
|
ThreadPriority.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
int.MaxValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void DoMeshRequests()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
aPollRequest poolreq = m_queue.Dequeue();
|
||||||
|
|
||||||
|
poolreq.thepoll.Process(poolreq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
|
||||||
|
public void ThrottleUpdate(ScenePresence p)
|
||||||
|
{
|
||||||
|
byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
|
||||||
|
UUID user = p.UUID;
|
||||||
|
int imagethrottle = ExtractTaskThrottle(throttles);
|
||||||
|
PollServiceMeshEventArgs args;
|
||||||
|
if (m_pollservices.TryGetValue(user, out args))
|
||||||
|
{
|
||||||
|
args.UpdateThrottle(imagethrottle, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ExtractTaskThrottle(byte[] pthrottles)
|
||||||
|
{
|
||||||
|
|
||||||
|
byte[] adjData;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
byte[] newData = new byte[7 * 4];
|
||||||
|
Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
Array.Reverse(newData, i * 4, 4);
|
||||||
|
|
||||||
|
adjData = newData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
adjData = pthrottles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0.125f converts from bits to bytes
|
||||||
|
//int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
//pos += 4;
|
||||||
|
// int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
//pos += 4;
|
||||||
|
// int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
// pos += 4;
|
||||||
|
// int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
// pos += 4;
|
||||||
|
pos += 16;
|
||||||
|
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
// pos += 4;
|
||||||
|
//int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
|
||||||
|
//int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PollServiceMeshEventArgs : PollServiceEventArgs
|
||||||
|
{
|
||||||
|
private List<Hashtable> requests =
|
||||||
|
new List<Hashtable>();
|
||||||
|
private Dictionary<UUID, aPollResponse> responses =
|
||||||
|
new Dictionary<UUID, aPollResponse>();
|
||||||
|
|
||||||
|
private Scene m_scene;
|
||||||
|
private MeshCapsDataThrottler m_throttler;
|
||||||
|
public PollServiceMeshEventArgs(UUID pId, Scene scene) :
|
||||||
|
base(null, null, null, null, pId, int.MaxValue)
|
||||||
|
{
|
||||||
|
m_scene = scene;
|
||||||
|
m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene);
|
||||||
|
// x is request id, y is userid
|
||||||
|
HasEvents = (x, y) =>
|
||||||
|
{
|
||||||
|
lock (responses)
|
||||||
|
{
|
||||||
|
bool ret = m_throttler.hasEvents(x, responses);
|
||||||
|
m_throttler.ProcessTime();
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GetEvents = (x, y) =>
|
||||||
|
{
|
||||||
|
lock (responses)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return responses[x].response;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
m_throttler.ProcessTime();
|
||||||
|
responses.Remove(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// x is request id, y is request data hashtable
|
||||||
|
Request = (x, y) =>
|
||||||
|
{
|
||||||
|
aPollRequest reqinfo = new aPollRequest();
|
||||||
|
reqinfo.thepoll = this;
|
||||||
|
reqinfo.reqID = x;
|
||||||
|
reqinfo.request = y;
|
||||||
|
|
||||||
|
m_queue.Enqueue(reqinfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
// this should never happen except possible on shutdown
|
||||||
|
NoEvents = (x, y) =>
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
lock (requests)
|
||||||
|
{
|
||||||
|
Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
|
||||||
|
requests.Remove(request);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Hashtable response = new Hashtable();
|
||||||
|
|
||||||
|
response["int_response_code"] = 500;
|
||||||
|
response["str_response_string"] = "Script timeout";
|
||||||
|
response["content_type"] = "text/plain";
|
||||||
|
response["keepalive"] = false;
|
||||||
|
response["reusecontext"] = false;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Process(aPollRequest requestinfo)
|
||||||
|
{
|
||||||
|
Hashtable response;
|
||||||
|
|
||||||
|
UUID requestID = requestinfo.reqID;
|
||||||
|
|
||||||
|
// If the avatar is gone, don't bother to get the texture
|
||||||
|
if (m_scene.GetScenePresence(Id) == null)
|
||||||
|
{
|
||||||
|
response = new Hashtable();
|
||||||
|
|
||||||
|
response["int_response_code"] = 500;
|
||||||
|
response["str_response_string"] = "Script timeout";
|
||||||
|
response["content_type"] = "text/plain";
|
||||||
|
response["keepalive"] = false;
|
||||||
|
response["reusecontext"] = false;
|
||||||
|
|
||||||
|
lock (responses)
|
||||||
|
responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response = m_getMeshHandler.Handle(requestinfo.request);
|
||||||
|
lock (responses)
|
||||||
|
{
|
||||||
|
responses[requestID] = new aPollResponse()
|
||||||
|
{
|
||||||
|
bytes = (int)response["int_bytes"],
|
||||||
|
lod = (int)response["int_lod"],
|
||||||
|
response = response
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
m_throttler.ProcessTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
|
||||||
|
{
|
||||||
|
m_throttler.UpdateThrottle(pimagethrottle, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RegisterCaps(UUID agentID, Caps caps)
|
public void RegisterCaps(UUID agentID, Caps caps)
|
||||||
{
|
{
|
||||||
// UUID capID = UUID.Random();
|
// UUID capID = UUID.Random();
|
||||||
|
|
||||||
//caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
|
|
||||||
if (m_URL == "localhost")
|
if (m_URL == "localhost")
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
string capUrl = "/CAPS/" + UUID.Random() + "/";
|
||||||
GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
|
|
||||||
IRequestHandler reqHandler
|
// Register this as a poll service
|
||||||
= new RestHTTPHandler(
|
PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
|
||||||
"GET",
|
|
||||||
"/CAPS/" + UUID.Random(),
|
args.Type = PollServiceEventArgs.EventType.Mesh;
|
||||||
httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
|
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
|
||||||
"GetMesh",
|
|
||||||
agentID.ToString());
|
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("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
|
||||||
|
m_pollservices.Add(agentID, args);
|
||||||
|
m_capsDict[agentID] = capUrl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
caps.RegisterHandler("GetMesh", reqHandler);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -136,6 +389,143 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
caps.RegisterHandler("GetMesh", m_URL);
|
caps.RegisterHandler("GetMesh", m_URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void DeregisterCaps(UUID agentID, Caps caps)
|
||||||
|
{
|
||||||
|
string capUrl;
|
||||||
|
PollServiceMeshEventArgs args;
|
||||||
|
if (m_capsDict.TryGetValue(agentID, out capUrl))
|
||||||
|
{
|
||||||
|
MainServer.Instance.RemoveHTTPHandler("", capUrl);
|
||||||
|
m_capsDict.Remove(agentID);
|
||||||
|
}
|
||||||
|
if (m_pollservices.TryGetValue(agentID, out args))
|
||||||
|
{
|
||||||
|
m_pollservices.Remove(agentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class MeshCapsDataThrottler
|
||||||
|
{
|
||||||
|
|
||||||
|
private volatile int currenttime = 0;
|
||||||
|
private volatile int lastTimeElapsed = 0;
|
||||||
|
private volatile int BytesSent = 0;
|
||||||
|
private int Lod3 = 0;
|
||||||
|
private int Lod2 = 0;
|
||||||
|
private int Lod1 = 0;
|
||||||
|
private int UserSetThrottle = 0;
|
||||||
|
private int UDPSetThrottle = 0;
|
||||||
|
private int CapSetThrottle = 0;
|
||||||
|
private float CapThrottleDistributon = 0.30f;
|
||||||
|
private readonly Scene m_scene;
|
||||||
|
private ThrottleOutPacketType Throttle;
|
||||||
|
|
||||||
|
public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene)
|
||||||
|
{
|
||||||
|
ThrottleBytes = pBytes;
|
||||||
|
lastTimeElapsed = Util.EnvironmentTickCount();
|
||||||
|
Throttle = ThrottleOutPacketType.Task;
|
||||||
|
m_scene = pScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
|
||||||
|
{
|
||||||
|
PassTime();
|
||||||
|
// Note, this is called IN LOCK
|
||||||
|
bool haskey = responses.ContainsKey(key);
|
||||||
|
if (!haskey)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
aPollResponse response;
|
||||||
|
if (responses.TryGetValue(key, out response))
|
||||||
|
{
|
||||||
|
|
||||||
|
// Normal
|
||||||
|
if (BytesSent + response.bytes <= ThrottleBytes)
|
||||||
|
{
|
||||||
|
BytesSent += response.bytes;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Lod3 Over
|
||||||
|
else if (response.bytes > ThrottleBytes && Lod3 <= (((ThrottleBytes * .30f) % 50000) + 1))
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref Lod3);
|
||||||
|
BytesSent += response.bytes;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Lod2 Over
|
||||||
|
else if (response.bytes > ThrottleBytes && Lod2 <= (((ThrottleBytes * .30f) % 10000) + 1))
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref Lod2);
|
||||||
|
BytesSent += response.bytes;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return haskey;
|
||||||
|
}
|
||||||
|
public void SubtractBytes(int bytes,int lod)
|
||||||
|
{
|
||||||
|
BytesSent -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessTime()
|
||||||
|
{
|
||||||
|
PassTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void PassTime()
|
||||||
|
{
|
||||||
|
currenttime = Util.EnvironmentTickCount();
|
||||||
|
int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
|
||||||
|
//processTimeBasedActions(responses);
|
||||||
|
if (currenttime - timeElapsed >= 1000)
|
||||||
|
{
|
||||||
|
lastTimeElapsed = Util.EnvironmentTickCount();
|
||||||
|
BytesSent -= ThrottleBytes;
|
||||||
|
if (BytesSent < 0) BytesSent = 0;
|
||||||
|
if (BytesSent < ThrottleBytes)
|
||||||
|
{
|
||||||
|
Lod3 = 0;
|
||||||
|
Lod2 = 0;
|
||||||
|
Lod1 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void AlterThrottle(int setting, ScenePresence p)
|
||||||
|
{
|
||||||
|
p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ThrottleBytes
|
||||||
|
{
|
||||||
|
get { return CapSetThrottle; }
|
||||||
|
set { CapSetThrottle = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
|
||||||
|
{
|
||||||
|
// Client set throttle !
|
||||||
|
UserSetThrottle = pimagethrottle;
|
||||||
|
CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
|
||||||
|
UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
|
||||||
|
if (CapSetThrottle < 4068)
|
||||||
|
CapSetThrottle = 4068; // at least two discovery mesh
|
||||||
|
p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
|
||||||
|
ProcessTime();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,8 +364,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
poolreq.thepoll.Process(poolreq);
|
poolreq.thepoll.Process(poolreq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class CapsDataThrottler
|
internal sealed class CapsDataThrottler
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -441,3 +439,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
public int ThrottleBytes;
|
public int ThrottleBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -11883,6 +11883,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the throttles from values supplied by the client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="throttles"></param>
|
||||||
|
public void SetAgentThrottleSilent(int throttle, int setting)
|
||||||
|
{
|
||||||
|
m_udpClient.ForceThrottleSetting(throttle,setting);
|
||||||
|
//m_udpClient.SetThrottles(throttles);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the current throttles for this client as a packed byte array
|
/// Get the current throttles for this client as a packed byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -682,6 +682,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (m_nextOnQueueEmpty == 0)
|
if (m_nextOnQueueEmpty == 0)
|
||||||
m_nextOnQueueEmpty = 1;
|
m_nextOnQueueEmpty = 1;
|
||||||
}
|
}
|
||||||
|
internal void ForceThrottleSetting(int throttle, int setting)
|
||||||
|
{
|
||||||
|
m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
|
/// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
|
||||||
|
|
|
@ -1428,6 +1428,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetAgentThrottleSilent(int throttle, int setting)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
public byte[] GetThrottlesPacked(float multiplier)
|
public byte[] GetThrottlesPacked(float multiplier)
|
||||||
{
|
{
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
|
|
|
@ -596,6 +596,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||||
|
|
||||||
public virtual void SetChildAgentThrottle(byte[] throttle)
|
public virtual void SetChildAgentThrottle(byte[] throttle)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAgentThrottleSilent(int throttle, int setting)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public byte[] GetThrottlesPacked(float multiplier)
|
public byte[] GetThrottlesPacked(float multiplier)
|
||||||
{
|
{
|
||||||
|
|
|
@ -520,6 +520,12 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
|
|
||||||
public virtual void SetChildAgentThrottle(byte[] throttle)
|
public virtual void SetChildAgentThrottle(byte[] throttle)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAgentThrottleSilent(int throttle, int setting)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public byte[] GetThrottlesPacked(float multiplier)
|
public byte[] GetThrottlesPacked(float multiplier)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
|
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
|
||||||
</configSections>
|
</configSections>
|
||||||
<runtime>
|
<runtime>
|
||||||
|
<supportedRuntime version="v2.0.50727"/>
|
||||||
|
|
||||||
<gcConcurrent enabled="true" />
|
<gcConcurrent enabled="true" />
|
||||||
<gcServer enabled="true" />
|
<gcServer enabled="true" />
|
||||||
</runtime>
|
</runtime>
|
||||||
|
@ -12,11 +14,14 @@
|
||||||
<log4net>
|
<log4net>
|
||||||
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
<appender name="Console" type="OpenSim.Framework.Console.OpenSimAppender, OpenSim.Framework.Console">
|
||||||
<layout type="log4net.Layout.PatternLayout">
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
<conversionPattern value="%date{HH:mm:ss} - %message%newline" />
|
<conversionPattern value="%date{HH:mm:ss} - %message" />
|
||||||
|
<!-- console log with milliseconds. Useful for debugging -->
|
||||||
|
<!-- <conversionPattern value="%date{HH:mm:ss.fff} - %message" /> -->
|
||||||
</layout>
|
</layout>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
|
||||||
<file value="OpenSim.32BitLaunch.log" />
|
<file value="OpenSim.log" />
|
||||||
<appendToFile value="true" />
|
<appendToFile value="true" />
|
||||||
<layout type="log4net.Layout.PatternLayout">
|
<layout type="log4net.Layout.PatternLayout">
|
||||||
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
<conversionPattern value="%date %-5level - %logger %message%newline" />
|
||||||
|
@ -28,5 +33,10 @@
|
||||||
<appender-ref ref="Console" />
|
<appender-ref ref="Console" />
|
||||||
<appender-ref ref="LogFileAppender" />
|
<appender-ref ref="LogFileAppender" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
|
<logger name="OpenSim.Region.ScriptEngine.XEngine">
|
||||||
|
<level value="INFO"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
</log4net>
|
</log4net>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
Loading…
Reference in New Issue