From 66d74e76b19a6586991fdada2661514143d9585b Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sun, 3 Mar 2013 09:40:44 -0500 Subject: Add method to remove JsonRpc Handlers from the server --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 6 ++++++ OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs | 2 ++ 2 files changed, 8 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 70c531c..58312ab 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1912,6 +1912,12 @@ namespace OpenSim.Framework.Servers.HttpServer m_rpcHandlers.Remove(method); } + public void RemoveJsonRPCHandler(string method) + { + lock(jsonRpcHandlers) + jsonRpcHandlers.Remove(method); + } + public bool RemoveLLSDHandler(string path, LLSDMethod handler) { lock (m_llsdHandlers) diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs index 71ca3ff..d162bc1 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -140,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer void RemoveStreamHandler(string httpMethod, string path); void RemoveXmlRPCHandler(string method); + + void RemoveJsonRPCHandler(string method); string GetHTTP404(string host); -- cgit v1.1 From b272b91317b1fd6c01aee57a0086a26dc233b03e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 5 Mar 2013 23:59:39 +0000 Subject: minor: Fix mono compiler warning in MonitorModule --- OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index 4c9ee06..64feec1 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -414,8 +414,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring } private void RegisterStatsManagerRegionStatistics() { - string regionName = m_scene.RegionInfo.RegionName; - MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); }); MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); }); MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); }); -- cgit v1.1 From a9f380d1241b765d5bf278b5dcf6ab91f0015e85 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 6 Mar 2013 00:22:58 +0000 Subject: Fix bug in osGetPrimitiveParams() so that it works for prims with the same owner as the script and not ones with different owners. Addresses http://opensimulator.org/mantis/view.php?id=6560 --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index ab087af..dd7ee24 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10920,7 +10920,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSL_List result = new LSL_List(); - if (obj != null && obj.OwnerID != m_host.OwnerID) + if (obj != null && obj.OwnerID == m_host.OwnerID) { LSL_List remaining = GetPrimParams(obj, rules, ref result); -- cgit v1.1 From 30e06b0742512caf08d1ab67505f9ab381dae9f5 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 5 Mar 2013 20:32:06 -0800 Subject: Convert doubles passed back through the MOD interface into LSL_Floats --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index d0922aa..21bae27 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -266,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { llist[i] = new LSL_Float((float)result[i]); } + else if (result[i] is double) + { + llist[i] = new LSL_Float((double)result[i]); + } else if (result[i] is UUID) { llist[i] = new LSL_Key(result[i].ToString()); -- cgit v1.1 From 9875e840f7e71f0b253c0b2aa90d47edc9c77b64 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 5 Mar 2013 20:33:17 -0800 Subject: Per discussions with justincc... split the JsonStore type functions into one for node type and one for value type. Define and export constants for both nodes and values. --- .../Framework/Interfaces/IJsonStoreModule.cs | 14 +++++- .../Scripting/JsonStore/JsonStore.cs | 39 ++++++++++++++++- .../Scripting/JsonStore/JsonStoreModule.cs | 36 +++++++++++++++- .../Scripting/JsonStore/JsonStoreScriptModule.cs | 39 ++++++++++++++--- .../JsonStore/Tests/JsonStoreScriptModuleTests.cs | 50 +++++++++++----------- 5 files changed, 143 insertions(+), 35 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs index 345f01b..b67312e 100644 --- a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs @@ -41,6 +41,16 @@ namespace OpenSim.Region.Framework.Interfaces Value = 3 } + public enum JsonStoreValueType + { + Undefined = 0, + Boolean = 1, + Integer = 2, + Float = 3, + String = 4, + UUID = 5 + } + public delegate void TakeValueCallback(string s); public interface IJsonStoreModule @@ -49,7 +59,9 @@ namespace OpenSim.Region.Framework.Interfaces bool CreateStore(string value, ref UUID result); bool DestroyStore(UUID storeID); - JsonStoreNodeType GetPathType(UUID storeID, string path); + JsonStoreNodeType GetNodeType(UUID storeID, string path); + JsonStoreValueType GetValueType(UUID storeID, string path); + bool TestStore(UUID storeID); bool SetValue(UUID storeID, string path, string value, bool useJson); diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs index 40adba1..e498c6a 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs @@ -145,7 +145,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore /// /// // ----------------------------------------------------------------- - public JsonStoreNodeType PathType(string expr) + public JsonStoreNodeType GetNodeType(string expr) { Stack path; if (! ParsePathExpression(expr,out path)) @@ -173,6 +173,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore /// /// // ----------------------------------------------------------------- + public JsonStoreValueType GetValueType(string expr) + { + Stack path; + if (! ParsePathExpression(expr,out path)) + return JsonStoreValueType.Undefined; + + OSD result = ProcessPathExpression(ValueStore,path); + + if (result == null) + return JsonStoreValueType.Undefined; + + if (result is OSDMap) + return JsonStoreValueType.Undefined; + + if (result is OSDArray) + return JsonStoreValueType.Undefined; + + if (result is OSDBoolean) + return JsonStoreValueType.Boolean; + + if (result is OSDInteger) + return JsonStoreValueType.Integer; + + if (result is OSDReal) + return JsonStoreValueType.Float; + + if (result is OSDString) + return JsonStoreValueType.String; + + return JsonStoreValueType.Undefined; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- public int ArrayLength(string expr) { Stack path; diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs index e78a2f4..5fbfcc5 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -270,7 +270,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore /// /// // ----------------------------------------------------------------- - public JsonStoreNodeType GetPathType(UUID storeID, string path) + public JsonStoreNodeType GetNodeType(UUID storeID, string path) { if (! m_enabled) return JsonStoreNodeType.Undefined; @@ -287,7 +287,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore try { lock (map) - return map.PathType(path); + return map.GetNodeType(path); } catch (Exception e) { @@ -302,6 +302,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore /// /// // ----------------------------------------------------------------- + public JsonStoreValueType GetValueType(UUID storeID, string path) + { + if (! m_enabled) return JsonStoreValueType.Undefined; + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); + return JsonStoreValueType.Undefined; + } + } + + try + { + lock (map) + return map.GetValueType(path); + } + catch (Exception e) + { + m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e); + } + + return JsonStoreValueType.Undefined; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- public bool SetValue(UUID storeID, string path, string value, bool useJson) { if (! m_enabled) return false; diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs index e13eb56..4a754a9 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -192,16 +192,32 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore #region ScriptConstantsInterface [ScriptConstant] - public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined; + public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined; [ScriptConstant] - public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object; + public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object; [ScriptConstant] - public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array; + public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array; [ScriptConstant] - public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value; + public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value; + + [ScriptConstant] + public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined; + + [ScriptConstant] + public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean; + + [ScriptConstant] + public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer; + + [ScriptConstant] + public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float; + + [ScriptConstant] + public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String; + #endregion @@ -310,9 +326,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore /// // ----------------------------------------------------------------- [ScriptInvocation] - public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path) + public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path) + { + return (int)m_store.GetNodeType(storeID,path); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + [ScriptInvocation] + public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path) { - return (int)m_store.GetPathType(storeID,path); + return (int)m_store.GetValueType(storeID,path); } // ----------------------------------------------------------------- diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs index b64dbd4..bfa9937 100644 --- a/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/Tests/JsonStoreScriptModuleTests.cs @@ -158,8 +158,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests Assert.That(dsrv, Is.EqualTo(1)); - int tprv = (int)InvokeOp("JsonGetPathType", storeId, "Hello"); - Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); } [Test] @@ -277,8 +277,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); Assert.That(returnValue, Is.EqualTo(1)); - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello"); Assert.That(returnValue2, Is.EqualTo("")); @@ -291,8 +291,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello"); Assert.That(returnValue, Is.EqualTo(1)); - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello"); Assert.That(returnValue2, Is.EqualTo("")); @@ -306,11 +306,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]"); Assert.That(returnValue, Is.EqualTo(1)); - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[0]"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); - result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[1]"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]"); Assert.That(stringReturnValue, Is.EqualTo("value2")); @@ -433,7 +433,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests } [Test] - public void TestJsonGetPathType() + public void TestJsonGetNodeType() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -441,41 +441,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }"); { - int result = (int)InvokeOp("JsonGetPathType", storeId, "."); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "."); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); } { - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT)); } { - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY)); } { - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); } { - int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE)); } // Test for non-existant path { - int result = (int)InvokeOp("JsonGetPathType", storeId, "foo"); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo"); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); } // Test for non-existant store { UUID fakeStoreId = TestHelpers.ParseTail(0x500); - int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, "."); - Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF)); + int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, "."); + Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF)); } } -- cgit v1.1 From 8960418e7d51a0f861e7b4cb800f007d76862c9c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 6 Mar 2013 21:37:53 +0000 Subject: Add regression test for presence crossing between regions on the same simulator. Unlike a much earlier commented out version of this test, this is done in synchronous mode. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 37 +++--- .../Scenes/Tests/ScenePresenceAgentTests.cs | 103 --------------- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 140 +++++++++++++++++++++ .../BasicPhysicsPlugin/BasicPhysicsScene.cs | 9 +- OpenSim/Tests/Common/Mock/TestClient.cs | 4 + 5 files changed, 170 insertions(+), 123 deletions(-) create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 39a885c..a7c7539 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1613,32 +1613,28 @@ namespace OpenSim.Region.Framework.Scenes bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); - //m_log.Debug("[CONTROL]: " +flags); // Applies a satisfying roll effect to the avatar when flying. - if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0) && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)) + if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { - - ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0)); - - + ApplyFlyingRoll( + FLY_ROLL_RADIANS_PER_UPDATE, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } - else if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0) && - ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)) + else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 && + (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { - ApplyFlyingRoll(-FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0)); - - + ApplyFlyingRoll( + -FLY_ROLL_RADIANS_PER_UPDATE, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0, + (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0); } else { if (m_AngularVelocity.Z != 0) - m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); - - } - - - + m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); + } if (Flying && IsColliding && controlland) { @@ -2400,7 +2396,8 @@ namespace OpenSim.Region.Framework.Scenes /// The vector in which to move. This is relative to the rotation argument public void AddNewMovement(Vector3 vec) { -// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1} for {2}", vec, Rotation, Name); Vector3 direc = vec * Rotation; direc.Normalize(); @@ -2420,6 +2417,8 @@ namespace OpenSim.Region.Framework.Scenes direc *= 0.03f * 128f * SpeedModifier; +// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); + if (PhysicsActor != null) { if (Flying) @@ -2453,6 +2452,8 @@ namespace OpenSim.Region.Framework.Scenes } } +// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); + // TODO: Add the force instead of only setting it to support multiple forces per frame? m_forceToApply = direc; } diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 5faf131..bbfbbfc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -289,108 +289,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests // // Assert.That(presence, Is.Null, "presence is not null"); // } - - // I'm commenting this test because it does not represent - // crossings. The Thread.Sleep's in here are not meaningful mocks, - // and they sometimes fail in panda. - // We need to talk in order to develop a test - // that really tests region crossings. There are 3 async components, - // but things are synchronous among them. So there should be - // 3 threads in here. - //[Test] -// public void T021_TestCrossToNewRegion() -// { -// TestHelpers.InMethod(); -// -// scene.RegisterRegionWithGrid(); -// scene2.RegisterRegionWithGrid(); -// -// // Adding child agent to region 1001 -// string reason; -// scene2.NewUserConnection(acd1,0, out reason); -// scene2.AddNewClient(testclient, PresenceType.User); -// -// ScenePresence presence = scene.GetScenePresence(agent1); -// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true); -// -// ScenePresence presence2 = scene2.GetScenePresence(agent1); -// -// // Adding neighbour region caps info to presence2 -// -// string cap = presence.ControllingClient.RequestClientInfo().CapsPath; -// presence2.AddNeighbourRegion(region1, cap); -// -// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region."); -// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region."); -// -// // Cross to x+1 -// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100); -// presence.Update(); -// -// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); -// -// // Mimicking communication between client and server, by waiting OK from client -// // sent by TestClient.CrossRegion call. Originally, this is network comm. -// if (!wh.WaitOne(5000,false)) -// { -// presence.Update(); -// if (!wh.WaitOne(8000,false)) -// throw new ArgumentException("1 - Timeout waiting for signal/variable."); -// } -// -// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which -// // would normally be fired after receiving the reply packet from comm. done on the last line. -// testclient.CompleteMovement(); -// -// // Crossings are asynchronous -// int timer = 10; -// -// // Make sure cross hasn't already finished -// if (!presence.IsInTransit && !presence.IsChildAgent) -// { -// // If not and not in transit yet, give it some more time -// Thread.Sleep(5000); -// } -// -// // Enough time, should at least be in transit by now. -// while (presence.IsInTransit && timer > 0) -// { -// Thread.Sleep(1000); -// timer-=1; -// } -// -// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1."); -// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected."); -// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent."); -// -// // Cross Back -// presence2.AbsolutePosition = new Vector3(-10, 3, 100); -// presence2.Update(); -// -// if (!wh.WaitOne(5000,false)) -// { -// presence2.Update(); -// if (!wh.WaitOne(8000,false)) -// throw new ArgumentException("2 - Timeout waiting for signal/variable."); -// } -// testclient.CompleteMovement(); -// -// if (!presence2.IsInTransit && !presence2.IsChildAgent) -// { -// // If not and not in transit yet, give it some more time -// Thread.Sleep(5000); -// } -// -// // Enough time, should at least be in transit by now. -// while (presence2.IsInTransit && timer > 0) -// { -// Thread.Sleep(1000); -// timer-=1; -// } -// -// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2."); -// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected."); -// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again."); -// } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs new file mode 100644 index 0000000..ef9fff5 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -0,0 +1,140 @@ +/* + * 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.Reflection; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceCrossingTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [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 so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + + [Test] + public void TestCrossOnSameSimulator() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. +// entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + originalSp.AbsolutePosition = new Vector3(128, 32, 10); + +// originalSp.Flying = true; + +// Console.WriteLine("First pos {0}", originalSp.AbsolutePosition); + + AgentUpdateArgs moveArgs = new AgentUpdateArgs(); + //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); + moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); + moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; + + originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); + + sceneA.Update(1); + +// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); + + // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. + // But really we want to do this in a more robust way. + for (int i = 0; i < 100; i++) + { + sceneA.Update(1); +// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); + } + + // sceneA should now only have a child agent + ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); + Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True); + + ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); + + // Agent remains a child until the client triggers complete movement + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + + TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); + + bool receivedCompleteMovement = false; + sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => receivedCompleteMovement = true; + + sceneBTc.CompleteMovement(); + + Assert.That(receivedCompleteMovement, Is.True); + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs index c4b9117..0816b7b 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs @@ -102,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin public override float Simulate(float timeStep) { +// Console.WriteLine("Simulating"); + float fps = 0; for (int i = 0; i < _actors.Count; ++i) { @@ -109,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin Vector3 actorPosition = actor.Position; Vector3 actorVelocity = actor.Velocity; - actorPosition.X += actor.Velocity.X*timeStep; - actorPosition.Y += actor.Velocity.Y*timeStep; +// Console.WriteLine( +// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity); + + actorPosition.X += actor.Velocity.X * timeStep; + actorPosition.Y += actor.Velocity.Y * timeStep; if (actor.Position.Y < 0) { diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 182f4d9..a448cc5 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -60,6 +60,8 @@ namespace OpenSim.Tests.Common.Mock public List SentImagePacketPackets { get; private set; } public List SentImageNotInDatabasePackets { get; private set; } + public event Action OnReceivedMoveAgentIntoRegion; + // disable warning: public events, part of the public API #pragma warning disable 67 @@ -566,6 +568,8 @@ namespace OpenSim.Tests.Common.Mock public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) { + if (OnReceivedMoveAgentIntoRegion != null) + OnReceivedMoveAgentIntoRegion(regInfo, pos, look); } public virtual AgentCircuitData RequestClientInfo() -- cgit v1.1 From 5751ecde5250484fe8e4b79ef38bfbf441e3dead Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 6 Mar 2013 23:06:00 +0000 Subject: Add code for testing event queue messages recevied on region cross. This is currently disabled pending an improvement in the test code to properly add avatars when an event queue module is present. --- .../EntityTransfer/EntityTransferModule.cs | 5 + .../Simulation/LocalSimulationConnector.cs | 9 +- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 27 +++- .../Tests/Common/Mock/TestEventQueueGetModule.cs | 178 +++++++++++++++++++++ 4 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 07c3666..01b1668 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1206,6 +1206,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // region doesn't take it m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.", + neighbourRegion.RegionName, agent.Name); + ReInstantiateScripts(agent); agent.AddToPhysicalScene(isFlying); @@ -1225,6 +1229,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer neighbourRegion.RegionHandle); return agent; } + // No turning back agent.IsChildAgent = true; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 3c18074..a413546 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation { // m_log.DebugFormat( // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", -// s.RegionInfo.RegionName, destination.RegionHandle); +// destination.RegionName, destination.RegionID); return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); } -// m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle); +// m_log.DebugFormat( +// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate", +// destination.RegionName, destination.RegionID); + return false; } @@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // note that we really don't need the GridRegion for this call foreach (Scene s in m_scenes.Values) { - //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); +// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); s.IncomingChildAgentDataUpdate(cAgentData); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index ef9fff5..81a2fcc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using Nini.Config; using NUnit.Framework; @@ -65,10 +66,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestCrossOnSameSimulator() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); +// TestEventQueueGetModule eqmA = new TestEventQueueGetModule(); EntityTransferModule etmA = new EntityTransferModule(); EntityTransferModule etmB = new EntityTransferModule(); LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); @@ -77,7 +79,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfig modulesConfig = config.AddConfig("Modules"); modulesConfig.Set("EntityTransferModule", etmA.Name); modulesConfig.Set("SimulationServices", lscm.Name); - IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); +// IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); // In order to run a single threaded regression test we do not want the entity transfer module waiting // for a callback from the destination scene before removing its avatar data. @@ -89,6 +91,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); +// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); @@ -98,6 +101,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Console.WriteLine("First pos {0}", originalSp.AbsolutePosition); +// eqmA.ClearEvents(); + AgentUpdateArgs moveArgs = new AgentUpdateArgs(); //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); @@ -117,6 +122,18 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); } + // Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm + // messages +// Dictionary> eqmEvents = eqmA.Events; +// +// Assert.That(eqmEvents.Count, Is.EqualTo(1)); +// Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True); +// +// List spEqmEvents = eqmEvents[originalSp.UUID]; +// +// Assert.That(spEqmEvents.Count, Is.EqualTo(1)); +// Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion")); + // sceneA should now only have a child agent ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True); @@ -128,12 +145,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); - bool receivedCompleteMovement = false; - sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => receivedCompleteMovement = true; + int agentMovementCompleteReceived = 0; + sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; sceneBTc.CompleteMovement(); - Assert.That(receivedCompleteMovement, Is.True); + Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); } } diff --git a/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs new file mode 100644 index 0000000..6707019 --- /dev/null +++ b/OpenSim/Tests/Common/Mock/TestEventQueueGetModule.cs @@ -0,0 +1,178 @@ +/* + * 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.Generic; +using System.Net; +using System.Reflection; +using System.Threading; +using log4net; +using Nini.Config; +using Mono.Addins; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Tests.Common +{ + public class TestEventQueueGetModule : IEventQueue, INonSharedRegionModule + { + public class Event + { + public string Name { get; set; } + public object[] Args { get; set; } + + public Event(string name, object[] args) + { + name = Name; + args = Args; + } + } + + public Dictionary> Events { get; set; } + + public void Initialise(IConfigSource source) {} + + public void Close() {} + + public void AddRegion(Scene scene) + { + Events = new Dictionary>(); + scene.RegisterModuleInterface(this); + } + + public void RemoveRegion (Scene scene) {} + + public void RegionLoaded (Scene scene) {} + + public string Name { get { return "TestEventQueueGetModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private void AddEvent(UUID avatarID, string name, params object[] args) + { + Console.WriteLine("Adding event {0} for {1}", name, avatarID); + + List avEvents; + + if (!Events.ContainsKey(avatarID)) + { + avEvents = new List(); + Events[avatarID] = avEvents; + } + else + { + avEvents = Events[avatarID]; + } + + avEvents.Add(new Event(name, args)); + } + + public void ClearEvents() + { + if (Events != null) + Events.Clear(); + } + + public bool Enqueue(OSD o, UUID avatarID) + { + AddEvent(avatarID, "Enqueue", o); + return true; + } + + public void DisableSimulator(ulong handle, UUID avatarID) + { + AddEvent(avatarID, "DisableSimulator", handle); + } + + public void EnableSimulator (ulong handle, IPEndPoint endPoint, UUID avatarID) + { + AddEvent(avatarID, "EnableSimulator", handle); + } + + public void EstablishAgentCommunication (UUID avatarID, IPEndPoint endPoint, string capsPath) + { + AddEvent(avatarID, "EstablishAgentCommunication", endPoint, capsPath); + } + + public void TeleportFinishEvent (ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, uint locationID, uint flags, string capsURL, UUID agentID) + { + AddEvent(agentID, "TeleportFinishEvent", regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); + } + + public void CrossRegion (ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID avatarID, UUID sessionID) + { + AddEvent(avatarID, "CrossRegion", handle, pos, lookAt, newRegionExternalEndPoint, capsURL, sessionID); + } + + public void ChatterboxInvitation( + UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName, + byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, + UUID transactionID, bool fromGroup, byte[] binaryBucket) + { + AddEvent( + toAgent, "ChatterboxInvitation", sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog, + timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket); + } + + public void ChatterBoxSessionAgentListUpdates (UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, bool isModerator, bool textMute) + { + AddEvent(toAgent, "ChatterBoxSessionAgentListUpdates", sessionID, fromAgent, canVoiceChat, isModerator, textMute); + } + + public void ParcelProperties (OpenMetaverse.Messages.Linden.ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID) + { + AddEvent(avatarID, "ParcelProperties", parcelPropertiesMessage); + } + + public void GroupMembership (OpenMetaverse.Packets.AgentGroupDataUpdatePacket groupUpdate, UUID avatarID) + { + AddEvent(avatarID, "GroupMembership", groupUpdate); + } + + public OSD ScriptRunningEvent (UUID objectID, UUID itemID, bool running, bool mono) + { + Console.WriteLine("ONE"); + throw new System.NotImplementedException (); + } + + public OSD BuildEvent (string eventName, OSD eventBody) + { + Console.WriteLine("TWO"); + throw new System.NotImplementedException (); + } + + public void partPhysicsProperties (uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID) + { + AddEvent(avatarID, "partPhysicsProperties", localID, physhapetype, density, friction, bounce, gravmod); + } + } +} \ No newline at end of file -- cgit v1.1 From 6706e189d5b1c04e4931c96b1a9c233f3606b71a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 6 Mar 2013 23:11:32 +0000 Subject: minor: remove some completely unused string local vars added recently in commit 984faf2 --- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 3ccf9f4..b6a7481 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -324,7 +324,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Remove any previous attachments List existingAttachments = sp.GetAttachments(attachmentPt); - string existingAttachmentScriptState = null; // At the moment we can only deal with a single attachment if (existingAttachments.Count != 0 && existingAttachments[0].FromItemID != UUID.Zero) @@ -849,7 +848,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Remove any previous attachments List attachments = sp.GetAttachments(attachmentPt); - string previousAttachmentScriptedState = null; // At the moment we can only deal with a single attachment if (attachments.Count != 0) -- cgit v1.1 From 33dab49d22002b9d24b2c286d662dca1755ace30 Mon Sep 17 00:00:00 2001 From: teravus Date: Thu, 7 Mar 2013 19:19:36 -0500 Subject: * Just another one of those new packet blocks causing a null ref. Defaulting to zero length array..... --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6742d99..bae7952 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4581,7 +4581,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock(); rinfopack.AgentData.AgentID = AgentId; rinfopack.AgentData.SessionID = SessionId; - + rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0]; OutPacket(rinfopack, ThrottleOutPacketType.Task); } -- cgit v1.1 From 5097437e1174d19d3dcb68e936581e60e4ef49cc Mon Sep 17 00:00:00 2001 From: teravus Date: Fri, 8 Mar 2013 19:32:47 -0500 Subject: * Apparently, sometimes texture entries come in from the wire with no default texture defined.. so apply better fallback protection against that. The net result is clients will have their selected textures set when they would have previously had an ignored exception. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index cce8b21..3e9a6fa 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4503,8 +4503,25 @@ namespace OpenSim.Region.Framework.Scenes Changed changeFlags = 0; + Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture; + Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture; + + // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all + // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point. + if (fallbackNewFace == null) + { + fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); + newTex.DefaultTexture = fallbackNewFace; + } + if (fallbackOldFace == null) + { + fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); + oldTex.DefaultTexture = fallbackOldFace; + } + for (int i = 0 ; i < GetNumberOfSides(); i++) { + Primitive.TextureEntryFace newFace = newTex.DefaultTexture; Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture; -- cgit v1.1 From 1120bcf123b5aa159e966a80254794f6af66f2a3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 9 Mar 2013 14:15:14 -0800 Subject: BulletSim: remove the ability for avatars to fly off the edge of regions when there are no region neighbors. Add some terrain location processing routines to support above. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 29 +++--- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 5 ++ .../Physics/BulletSPlugin/BSTerrainManager.cs | 100 +++++++++++++++++++-- .../Region/Physics/BulletSPlugin/BSTerrainMesh.cs | 6 +- 4 files changed, 117 insertions(+), 23 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index f442ca2..e208d3a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -205,7 +205,7 @@ public sealed class BSCharacter : BSPhysObject // errors can creap in and the avatar will slowly float off in some direction. // So, the problem is that, when an avatar is standing, we cannot tell creaping error // from real pushing. - // The code below keeps setting the velocity to zero hoping the world will keep pushing. + // The code below uses whether the collider is static or moving to decide whether to zero motion. _velocityMotor.Step(timeStep); @@ -244,6 +244,7 @@ public sealed class BSCharacter : BSPhysObject } else { + // Supposed to be moving. OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; if (Friction != BSParam.AvatarFriction) @@ -276,8 +277,8 @@ public sealed class BSCharacter : BSPhysObject }); } - // Decide of the character is colliding with a low object and compute a force to pop the - // avatar up so it has a chance of walking up and over the low object. + // Decide if the character is colliding with a low object and compute a force to pop the + // avatar up so it can walk up and over the low objects. private OMV.Vector3 WalkUpStairs() { OMV.Vector3 ret = OMV.Vector3.Zero; @@ -476,17 +477,19 @@ public sealed class BSCharacter : BSPhysObject if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) { // The character is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; + // Force the avatar position to be within known. ScenePresence will use the position + // plus the velocity to decide if the avatar is moving out of the region. + RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); + DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); + return true; } // If below the ground, move the avatar up float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); if (Position.Z < terrainHeight) { - DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); - _position.Z = terrainHeight + 2.0f; + DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); + _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; ret = true; } if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) @@ -806,14 +809,7 @@ public sealed class BSCharacter : BSPhysObject private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { if (force.IsFinite()) { - float magnitude = force.Length(); - if (magnitude > BSParam.MaxAddForceMagnitude) - { - // Force has a limit - force = force / magnitude * BSParam.MaxAddForceMagnitude; - } - - OMV.Vector3 addForce = force; + OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() @@ -902,6 +898,7 @@ public sealed class BSCharacter : BSPhysObject // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) { + DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); entprop.Position = _position; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index fa58109..2af8468 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -107,6 +107,7 @@ public static class BSParam public static float AvatarCapsuleDepth { get; private set; } public static float AvatarCapsuleHeight { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } + public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarStepHeight { get; private set; } public static float AvatarStepApproachFactor { get; private set; } public static float AvatarStepForceFactor { get; private set; } @@ -497,6 +498,10 @@ public static class BSParam 0.1f, (s) => { return AvatarContactProcessingThreshold; }, (s,v) => { AvatarContactProcessingThreshold = v; } ), + new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", + 1.0f, + (s) => { return AvatarBelowGroundUpCorrectionMeters; }, + (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", 0.3f, (s) => { return AvatarStepHeight; }, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 2e9db39..e8040d8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -337,6 +337,54 @@ public sealed class BSTerrainManager : IDisposable return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); } + // Return a new position that is over known terrain if the position is outside our terrain. + public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) + { + Vector3 ret = pPos; + + // Can't do this function if we don't know about any terrain. + if (m_terrains.Count == 0) + return ret; + + int loopPrevention = 5; + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) + { + // The passed position is not within a known terrain area. + + // First, base addresses are never negative so correct for that possible problem. + if (ret.X < 0f || ret.Y < 0f) + { + if (ret.X < 0f) + ret.X = 0f; + if (ret.Y < 0f) + ret.Y = 0f; + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", + BSScene.DetailLogZero, pPos, ret); + } + else + { + // Must be off the top of a region. Find an adjacent region to move into. + Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); + + ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X); + ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y); + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", + BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); + } + if (loopPrevention-- < 0f) + { + // The 'while' is a little dangerous so this prevents looping forever if the + // mapping of the terrains ever gets messed up (like nothing at <0,0>) or + // the list of terrains is in transition. + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); + break; + } + } + return ret; + } + // Given an X and Y, find the height of the terrain. // Since we could be handling multiple terrains for a mega-region, // the base of the region is calcuated assuming all regions are @@ -400,18 +448,60 @@ public sealed class BSTerrainManager : IDisposable // the descriptor class and the 'base' fo the addresses therein. private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) { - int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; - int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; - Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); + bool ret = false; + + Vector3 terrainBaseXYZ = Vector3.Zero; + if (pos.X < 0f || pos.Y < 0f) + { + // We don't handle negative addresses so just make up a base that will not be found. + terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); + } + else + { + int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; + int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; + terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); + } BSTerrainPhys physTerrain = null; lock (m_terrains) { - m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); + ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); } outTerrainBase = terrainBaseXYZ; outPhysTerrain = physTerrain; - return (physTerrain != null); + return ret; + } + + // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than + // this one. Usually used to return an out of bounds object to a known place. + private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) + { + Vector3 ret = pTerrainBase; + ret.Z = 0f; + lock (m_terrains) + { + // Once down to the <0,0> region, we have to be done. + while (ret.X > 0f && ret.Y > 0f) + { + if (ret.X > 0f) + { + ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } + if (ret.Y > 0f) + { + ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } + } + } + + return ret; } // Although no one seems to check this, I do support combining. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index d7e800d..57a5ff2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -215,7 +215,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys float magX = (float)sizeX / extentX; float magY = (float)sizeY / extentY; - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", + if (physicsScene != null) + physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); float minHeight = float.MaxValue; // Note that sizeX+1 vertices are created since there is land between this and the next region. @@ -257,7 +258,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys } catch (Exception e) { - physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", + if (physicsScene != null) + physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", LogHeader, physicsScene.RegionName, extentBase, e); } -- cgit v1.1 From e898a5fec5b78fe428ec10e1cd94cc717f5ac5a7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Mar 2013 22:42:27 +0000 Subject: minor: Remove mono compiler warnings in EventQueueTests --- .../ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index ed8ec16..141af8a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -49,8 +49,10 @@ namespace OpenSim.Region.ClientStack.Linden.Tests private TestScene m_scene; [SetUp] - public void SetUp() + public override void SetUp() { + base.SetUp(); + uint port = 9999; uint sslPort = 9998; -- cgit v1.1 From be686f80a354103cd6630cd8f4e5fb40a4093549 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Mar 2013 23:01:07 +0000 Subject: minor: Remove mono compiler warnings from LSL_ApiHttpTests --- OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs index b0baa1c..ab44e38 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiHttpTests.cs @@ -209,7 +209,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests += (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse); // Console.WriteLine("Trying {0}", returnedUri); - HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri); AssertHttpResponse(returnedUri, testResponse); -- cgit v1.1 From 0c6268fe5606c197d99c81a5e84a84e667e28fe8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 11 Mar 2013 23:15:13 +0000 Subject: minor: remove mono compiler warning in SceneObjectUndoRedoTests --- OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs index 96973de..4883ae7 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUndoRedoTests.cs @@ -110,8 +110,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 firstSize = new Vector3(2, 3, 4); Vector3 secondSize = new Vector3(5, 6, 7); - Vector3 thirdSize = new Vector3(8, 9, 10); - Vector3 fourthSize = new Vector3(11, 12, 13); +// Vector3 thirdSize = new Vector3(8, 9, 10); +// Vector3 fourthSize = new Vector3(11, 12, 13); Scene scene = new SceneHelpers().SetupScene(); scene.MaxUndoCount = 20; -- cgit v1.1 From c43d4b557267547d07f6c90dc7e335ce4f7e07be Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Mar 2013 22:16:09 +0000 Subject: Improve teleport cancellation in some circumstances, though cancelling teleports is still not recommended. Previously, hitting the cancel button on a teleport would cancel on the client side but the request was ignored on the server side. Cancel would still work if the teleport failed in the early stages (e.g. because the destination never replied to early CreateAgent and UpdateAgent messages). But if the teleport still completed after a delay here or later on, the viewer would become confused (usual symptom appears to be avatar being unable to move/reteleport). This commit makes OpenSimulator obey cancellations which are received before it sends the TeleportFinish event queue message and does proper cleanup. But cancellations received after this (which can happen even though the cancel button is removed as this messages comes on a different thread) can still result in a frozen avatar. This looks extremely difficult and impossible to fix. I can replicate the same problem on the Linden Lab grid by hitting cancel immediately after a teleport starts (a teleport which would otherwise quickly succeed). --- .../EntityTransfer/EntityTransferModule.cs | 59 ++++++++-- .../EntityTransfer/EntityTransferStateMachine.cs | 124 ++++++++++++++++----- 2 files changed, 149 insertions(+), 34 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 01b1668..34f0924 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -148,6 +148,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual void OnNewClient(IClientAPI client) { + client.OnTeleportCancel += OnClientCancelTeleport; client.OnTeleportHomeRequest += TeleportHome; client.OnTeleportLandmarkRequest += RequestTeleportLandmark; } @@ -168,6 +169,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Agent Teleports + private void OnClientCancelTeleport(IClientAPI client) + { + m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); + } + public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (sp.Scene.Permissions.IsGridGod(sp.UUID)) @@ -567,6 +576,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", + sp.Name, finalDestination.RegionName, sp.Scene.Name); + + return; + } + // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); @@ -631,7 +649,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", + sp.Name, finalDestination.RegionName, sp.Scene.Name); + + CleanupAbortedInterRegionTeleport(sp, finalDestination); + + return; + } m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", @@ -714,14 +741,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // } } - protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) + /// + /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation. + /// + /// + /// All operations here must be idempotent so that we can call this method at any point in the teleport process + /// up until we send the TeleportFinish event quene event to the viewer. + /// + /// + /// + protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) { m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - // Client never contacted destination. Let's restore everything back - sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); - - // Fail. Reset it back sp.IsChildAgent = false; ReInstantiateScripts(sp); @@ -729,7 +761,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Finally, kill the agent we just created at the destination. Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); + } + + /// + /// Signal that the inter-region teleport failed and perform cleanup. + /// + /// + /// + /// + protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) + { + CleanupAbortedInterRegionTeleport(sp, finalDestination); + sp.ControllingClient.SendTeleportFailed( + string.Format("Problems connecting to destination {0}", finalDestination.RegionName)); sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); } @@ -2097,7 +2142,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public bool IsInTransit(UUID id) { - return m_entityTransferStateMachine.IsInTransit(id); + return m_entityTransferStateMachine.GetAgentTransferState(id) != null; } protected void ReInstantiateScripts(ScenePresence sp) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index d0cab49..24d81d9 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs @@ -51,8 +51,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// This is a state machine. /// /// [Entry] => Preparing - /// Preparing => { Transferring || CleaningUp || [Exit] } - /// Transferring => { ReceivedAtDestination || CleaningUp } + /// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] } + /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp } + /// Cancelling => CleaningUp /// ReceivedAtDestination => CleaningUp /// CleaningUp => [Exit] /// @@ -64,7 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Preparing, // The agent is being prepared for transfer Transferring, // The agent is in the process of being transferred to a destination ReceivedAtDestination, // The destination has notified us that the agent has been successfully received - CleaningUp // The agent is being changed to child/removed after a transfer + CleaningUp, // The agent is being changed to child/removed after a transfer + Cancelling // The user has cancelled the teleport but we have yet to act upon this. } /// @@ -115,42 +117,110 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// Illegal transitions will throw an Exception - internal void UpdateInTransit(UUID id, AgentTransferState newState) + internal bool UpdateInTransit(UUID id, AgentTransferState newState) { + bool transitionOkay = false; + + // We don't want to throw an exception on cancel since this can come it at any time. + bool failIfNotOkay = true; + + // Should be a failure message if failure is not okay. + string failureMessage = null; + + AgentTransferState? oldState = null; + lock (m_agentsInTransit) { // Illegal to try and update an agent that's not actually in transit. if (!m_agentsInTransit.ContainsKey(id)) - throw new Exception( - string.Format( - "Agent with ID {0} is not registered as in transit in {1}", - id, m_mod.Scene.RegionInfo.RegionName)); - - AgentTransferState oldState = m_agentsInTransit[id]; + { + if (newState != AgentTransferState.Cancelling) + failureMessage = string.Format( + "Agent with ID {0} is not registered as in transit in {1}", + id, m_mod.Scene.RegionInfo.RegionName); + else + failIfNotOkay = false; + } + else + { + oldState = m_agentsInTransit[id]; - bool transitionOkay = false; + if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) + { + transitionOkay = true; + } + else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) + { + transitionOkay = true; + } + else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) + { + transitionOkay = true; + } + else + { + if (newState == AgentTransferState.Cancelling + && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) + { + transitionOkay = true; + } + else + { + failIfNotOkay = false; + } + } - if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) - transitionOkay = true; - else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) - transitionOkay = true; - else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) - transitionOkay = true; + if (!transitionOkay) + failureMessage + = string.Format( + "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", + id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); + } if (transitionOkay) + { m_agentsInTransit[id] = newState; - else - throw new Exception( - string.Format( - "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", - id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); + +// m_log.DebugFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", +// id, oldState, newState, m_mod.Scene.Name); + } + else if (failIfNotOkay) + { + throw new Exception(failureMessage); + } +// else +// { +// if (oldState != null) +// m_log.DebugFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", +// id, oldState, newState, m_mod.Scene.Name); +// else +// m_log.DebugFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", +// id, newState, m_mod.Scene.Name); +// } } + + return transitionOkay; } - internal bool IsInTransit(UUID id) + /// + /// Gets the current agent transfer state. + /// + /// Null if the agent is not in transit + /// + /// Identifier. + /// + internal AgentTransferState? GetAgentTransferState(UUID id) { lock (m_agentsInTransit) - return m_agentsInTransit.ContainsKey(id); + { + if (!m_agentsInTransit.ContainsKey(id)) + return null; + else + return m_agentsInTransit[id]; + } } /// @@ -203,14 +273,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer lock (m_agentsInTransit) { - if (!IsInTransit(id)) + AgentTransferState? currentState = GetAgentTransferState(id); + + if (currentState == null) throw new Exception( string.Format( "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", id, m_mod.Scene.RegionInfo.RegionName)); - AgentTransferState currentState = m_agentsInTransit[id]; - if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) throw new Exception( string.Format( -- cgit v1.1 From fb1211ad5ef86bf6a1b6170775f1ebb4adcb4cb7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 12 Mar 2013 23:01:27 +0000 Subject: Add DisableInterRegionTeleportCancellation option in [EntityTransfer] section of OpenSim.ini. False by default. This option allows the simulator to specify that the cancel button on inter-region teleports should never appear. This exists because sometimes cancellation will result in a stuck avatar requiring relog. It may be hard to prevent this due to the protocol design (the LL grid has the same issue) In small controlled grids where teleport failure is practically impossible it can be better to disable teleport cancellation entirely. --- .../EntityTransfer/EntityTransferModule.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 34f0924..9b1b69a 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -66,6 +66,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// public bool WaitForAgentArrivedAtDestination { get; set; } + /// + /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. + /// + /// + /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a + /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the + /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport + /// cancellation consistently suceed. + /// + public bool DisableInterRegionTeleportCancellation { get; set; } + protected bool m_Enabled = false; public Scene Scene { get; private set; } @@ -116,6 +127,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { + DisableInterRegionTeleportCancellation + = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); + WaitForAgentArrivedAtDestination = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); @@ -148,9 +162,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual void OnNewClient(IClientAPI client) { - client.OnTeleportCancel += OnClientCancelTeleport; client.OnTeleportHomeRequest += TeleportHome; client.OnTeleportLandmarkRequest += RequestTeleportLandmark; + + if (!DisableInterRegionTeleportCancellation) + client.OnTeleportCancel += OnClientCancelTeleport; } public virtual void Close() {} @@ -528,6 +544,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (sp.ParentID != (uint)0) sp.StandUp(); + if (DisableInterRegionTeleportCancellation) + teleportFlags |= (uint)TeleportFlags.DisableCancel; + // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). sp.ControllingClient.SendTeleportStart(teleportFlags); -- cgit v1.1 From 0d25be3f8162fc4e99cd5abdaceb425a1f7370fe Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 00:19:37 +0000 Subject: Make C# scripts return correct error line and column numbers instead of failing because they have no linemap. Adapted fix from http://opensimulator.org/mantis/view.php?id=6571 Thanks Nickel Briand --- OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 9d20c9e..b71afe3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -662,13 +662,18 @@ namespace SecondLife { string severity = CompErr.IsWarning ? "Warning" : "Error"; - KeyValuePair lslPos; + KeyValuePair errorPos; // Show 5 errors max, but check entire list for errors if (severity == "Error") { - lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); + // C# scripts will not have a linemap since theres no line translation involved. + if (!m_lineMaps.ContainsKey(assembly)) + errorPos = new KeyValuePair(CompErr.Line, CompErr.Column); + else + errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]); + string text = CompErr.ErrorText; // Use LSL type names @@ -678,7 +683,7 @@ namespace SecondLife // The Second Life viewer's script editor begins // countingn lines and columns at 0, so we subtract 1. errtext += String.Format("({0},{1}): {4} {2}: {3}\n", - lslPos.Key - 1, lslPos.Value - 1, + errorPos.Key - 1, errorPos.Value - 1, CompErr.ErrorNumber, text, severity); hadErrors = true; } -- cgit v1.1 From f8a4d95bdd2bff70a428d386edad1ca91e15c6c0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 00:22:07 +0000 Subject: minor: Remove mono compiler warning in LLClientView --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index bae7952..7ea538c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -7069,7 +7069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (handlerUpdatePrimFlags != null) { - byte[] data = Pack.ToBytes(); +// byte[] data = Pack.ToBytes(); // 46,47,48 are special positions within the packet // This may change so perhaps we need a better way // of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?) -- cgit v1.1 From b7216f4daffca6dad4049c84982beca6dca9b094 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 00:46:17 +0000 Subject: minor: save some commented out log lines which will be useful again in future debugging of VectorRenderModule --- .../Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs index f04fabe..4cecd85 100644 --- a/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/VectorRender/VectorRenderModule.cs @@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender foreach (string line in GetLines(data, dataDelim)) { string nextLine = line.Trim(); + +// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine); + //replace with switch, or even better, do some proper parsing if (nextLine.StartsWith("MoveTo")) { @@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); PointF point = new PointF(x, y); points[i / 2] = point; + +// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]); } } } -- cgit v1.1 From 5c53660a7f055be9ed41f30893de673acac8a0f1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 22:59:06 +0000 Subject: Add prototype dynamic objects map for scene object parts This allows region modules to add dynamic objects to SOPs rather than having to continually push and pull OSD dynamic attributes. This is to explore the original MOAP use case for dynamic attributes where it could be very awkward and possibly time-consuming to keep reconstructing MediaEntrys from stored DynamicAttributes. This commit adds a DOExampleModule to demonstrate/evolve this code. Dynamic objects involve no storage or persistence changes - the 'backing store' for any data that does need to be saved will remain the DAMap. DOExampleModule in this commit only attaches a fresh dynamic object. Actually constructing this from stored dynamic attributes and handling persistence is left for later. These changes should affect no existing functionality, though it may or may not reveal necessary changes in DAMap down the road. --- OpenSim/Framework/DAMap.cs | 2 +- OpenSim/Framework/DOMap.cs | 98 +++++++++++++++++ .../Framework/DynamicAttributes/DOExampleModule.cs | 117 +++++++++++++++++++++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 22 ++++ 4 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Framework/DOMap.cs create mode 100644 OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs (limited to 'OpenSim') diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index 64cea77..df4a6bc 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -180,7 +180,7 @@ namespace OpenSim.Framework /// Validate the key used for storing separate data stores. /// /// - private static void ValidateKey(string key) + public static void ValidateKey(string key) { if (key.Length < MIN_STORE_NAME_LENGTH) throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH); diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs new file mode 100644 index 0000000..755e129 --- /dev/null +++ b/OpenSim/Framework/DOMap.cs @@ -0,0 +1,98 @@ +/* + * 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.Generic; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework +{ + /// + /// This class stores and retrieves dynamic objects. + /// + /// + /// Experimental - DO NOT USE. + /// + public class DOMap + { + private IDictionary m_map; + + public void Add(string key, object dynObj) + { + DAMap.ValidateKey(key); + + lock (this) + { + if (m_map == null) + m_map = new Dictionary(); + + m_map.Add(key, dynObj); + } + } + + public bool ContainsKey(string key) + { + return Get(key) != null; + } + + /// + /// Get a dynamic object + /// + /// + /// Not providing an index method so that users can't casually overwrite each other's objects. + /// + /// + public object Get(string key) + { + lock (this) + { + if (m_map == null) + return null; + else + return m_map[key]; + } + } + + public bool Remove(string key) + { + lock (this) + { + if (m_map == null) + return false; + else + return m_map.Remove(key); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs new file mode 100644 index 0000000..71bb3f0 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs @@ -0,0 +1,117 @@ +/* + * 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.Generic; +using System.Reflection; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule +{ + /// + /// Example module for experimenting with and demonstrating dynamic object ideas. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")] + public class DOExampleModule : INonSharedRegionModule + { + public class MyObject + { + public int Moves { get; set; } + } + + // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static readonly bool ENABLED = false; // enable for testing + + private Scene m_scene; + private IDialogModule m_dialogMod; + + public string Name { get { return "DOExample Module"; } } + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) {} + + public void AddRegion(Scene scene) + { + if (ENABLED) + { + m_scene = scene; + m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene; + m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; + m_dialogMod = m_scene.RequestModuleInterface(); + } + } + + public void RemoveRegion(Scene scene) + { + if (ENABLED) + { + m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; + } + } + + public void RegionLoaded(Scene scene) {} + + public void Close() + { + RemoveRegion(m_scene); + } + + private void OnObjectAddedToScene(SceneObjectGroup so) + { + so.RootPart.DynObjs.Add(Name, new MyObject()); + } + + private bool OnSceneGroupMove(UUID groupId, Vector3 delta) + { + SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId); + + if (so == null) + return true; + + object rawObj = so.RootPart.DynObjs.Get(Name); + + if (rawObj != null) + { + MyObject myObj = (MyObject)rawObj; + + m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves)); + } + + return true; + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 3e9a6fa..ee7c4f4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -129,6 +129,27 @@ namespace OpenSim.Region.Framework.Scenes /// Dynamic attributes can be created and deleted as required. /// public DAMap DynAttrs { get; set; } + + private DOMap m_dynObjs; + + /// + /// Dynamic objects that can be created and deleted as required. + /// + public DOMap DynObjs + { + get + { + if (m_dynObjs == null) + m_dynObjs = new DOMap(); + + return m_dynObjs; + } + + set + { + m_dynObjs = value; + } + } /// /// Is this a root part? @@ -348,6 +369,7 @@ namespace OpenSim.Region.Framework.Scenes Rezzed = DateTime.UtcNow; Description = String.Empty; DynAttrs = new DAMap(); + DynObjs = new DOMap(); // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from -- cgit v1.1 From 39a0928052bcaf4b81af326e129cbfd6329f9292 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 23:17:27 +0000 Subject: minor: Remove some mono compiler warnings in OpenSim.Framework.dll --- OpenSim/Framework/PluginManager.cs | 4 ++-- OpenSim/Framework/Util.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs index 00263f5..0117096 100644 --- a/OpenSim/Framework/PluginManager.cs +++ b/OpenSim/Framework/PluginManager.cs @@ -218,7 +218,7 @@ namespace OpenSim.Framework Console.WriteLine ("Looking for updates..."); Repositories.UpdateAllRepositories (ps); Console.WriteLine ("Available add-in updates:"); - bool found = false; + AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates(); foreach (AddinRepositoryEntry entry in entries) @@ -541,7 +541,7 @@ namespace OpenSim.Framework { list.AddRange(PluginRegistry.GetAddins()); } - catch(Exception e) + catch (Exception) { Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[]; return x; diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0fa54b2..94a172c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -303,12 +303,12 @@ namespace OpenSim.Framework // Clamp the maximum magnitude of a vector public static Vector3 ClampV(Vector3 x, float max) { - Vector3 ret = x; float lenSq = x.LengthSquared(); if (lenSq > (max * max)) { x = x / x.Length() * max; } + return x; } -- cgit v1.1 From 48d41ef3076eb4c2a8c4a67d811630ab7b498469 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 23:25:56 +0000 Subject: Remove unnecessary instation of DOMap() in SOP from commit 5c53660 since this is being done lazily --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ee7c4f4..a8b63fe 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -369,7 +369,6 @@ namespace OpenSim.Region.Framework.Scenes Rezzed = DateTime.UtcNow; Description = String.Empty; DynAttrs = new DAMap(); - DynObjs = new DOMap(); // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from -- cgit v1.1 From 43220afda2a69e7849c2ab9f98dcbd61a3da218b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 23:42:14 +0000 Subject: Improve DAExampleModule to show current necessary locking to avoid race conditions with a serialization thread. --- .../Framework/DynamicAttributes/DAExampleModule.cs | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 37131b9..f874495 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -85,19 +85,27 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule { OSDMap attrs = null; SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId); + + if (sop == null) + return true; + if (!sop.DynAttrs.TryGetValue(Name, out attrs)) attrs = new OSDMap(); OSDInteger newValue; - - if (!attrs.ContainsKey("moves")) - newValue = new OSDInteger(1); - else - newValue = new OSDInteger(((OSDInteger)attrs["moves"]).AsInteger() + 1); - - attrs["moves"] = newValue; - sop.DynAttrs[Name] = attrs; + // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code. + lock (sop.DynAttrs) + { + if (!attrs.ContainsKey("moves")) + newValue = new OSDInteger(1); + else + newValue = new OSDInteger(attrs["moves"].AsInteger() + 1); + + attrs["moves"] = newValue; + + sop.DynAttrs[Name] = attrs; + } m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue)); -- cgit v1.1 From e9c394fb4ed56ffb931a0161b8c6fdc929b38058 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 21:23:48 +0000 Subject: Make llGetObjectDetails() return the correct world rotation for a sitting avatar This addresses http://opensimulator.org/mantis/view.php?id=6567 This creates a ScenePresence.GetWorldRotation() with the same semantics as SOP.GetWorldRotation() SP.Rotation can't be used since it's relative to the sat upon prim if the avatar is sitting. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 40 +++++++++++++++++++--- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- 2 files changed, 36 insertions(+), 6 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index a7c7539..82bb759 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -559,16 +559,28 @@ namespace OpenSim.Region.Framework.Scenes private Quaternion m_bodyRot = Quaternion.Identity; + /// + /// The rotation of the avatar. + /// + /// + /// If the avatar is not sitting, this is with respect to the world + /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation). + /// If you always want the world rotation, use GetWorldRotation() + /// public Quaternion Rotation { - get { return m_bodyRot; } + get + { + return m_bodyRot; + } + set { m_bodyRot = value; + if (PhysicsActor != null) - { PhysicsActor.Orientation = m_bodyRot; - } + // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); } } @@ -608,6 +620,26 @@ namespace OpenSim.Region.Framework.Scenes set { m_health = value; } } + /// + /// Gets the world rotation of this presence. + /// + /// + /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not. + /// + /// + public Quaternion GetWorldRotation() + { + if (IsSatOnObject) + { + SceneObjectPart sitPart = ParentPart; + + if (sitPart != null) + return sitPart.GetWorldRotation() * Rotation; + } + + return Rotation; + } + public void AdjustKnownSeeds() { Dictionary seeds; @@ -709,8 +741,6 @@ namespace OpenSim.Region.Framework.Scenes #endregion - - #region Constructor(s) public ScenePresence( diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index dd7ee24..47f8758 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10518,7 +10518,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z)); break; case ScriptBaseClass.OBJECT_ROT: - ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W)); + ret.Add(new LSL_Rotation(av.GetWorldRotation())); break; case ScriptBaseClass.OBJECT_VELOCITY: ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z)); -- cgit v1.1 From ad9bd3fe93e3d48b17ca28b3e036fe39991f2203 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 21:46:29 +0000 Subject: Fix sensors, llGetRootRotation(), llGet*Param() and other functions to use the world rotation if the avatar to which they are attached is sitting --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 9 +++------ .../Shared/Api/Implementation/Plugins/SensorRepeat.cs | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 47f8758..d88e416 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2174,7 +2174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) q = avatar.CameraRotation; // Mouselook else - q = avatar.Rotation; // Currently infrequently updated so may be inaccurate + q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate } else q = part.ParentGroup.GroupRotation; // Likely never get here but just in case @@ -7831,7 +7831,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0) q = avatar.CameraRotation; // Mouselook else - q = avatar.Rotation; // Currently infrequently updated so may be inaccurate + q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate else q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 48c6b50..bd83f02 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2578,18 +2578,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID npcId; if (!UUID.TryParse(npc.m_string, out npcId)) - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return new LSL_Rotation(Quaternion.Identity); if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return new LSL_Rotation(Quaternion.Identity); ScenePresence sp = World.GetScenePresence(npcId); if (sp != null) - { - Quaternion rot = sp.Rotation; - return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W); - } + return new LSL_Rotation(sp.GetWorldRotation()); } return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index dd45406..88ab515 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -353,7 +353,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); - q = avatar.Rotation * q; + q = avatar.GetWorldRotation() * q; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); @@ -480,7 +480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); - q = avatar.Rotation * q; + q = avatar.GetWorldRotation() * q; } LSL_Types.Quaternion r = new LSL_Types.Quaternion(q); -- cgit v1.1 From f84072827384f7ea7c50f77eab23c141cae6cd9e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 21:57:43 +0000 Subject: refactor: use cleaner LSL_Rotation quaternion constructor in LSL_Api.GetPartRot() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d88e416..854169b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2181,10 +2181,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else q = part.ParentGroup.GroupRotation; // just the group rotation - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(q); } - q = part.GetWorldRotation(); - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(part.GetWorldRotation()); } public LSL_Rotation llGetLocalRot() -- cgit v1.1 From c3e081a5ca165b197fcb5c6e407f0174931c8f7c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:00:04 +0000 Subject: Fix minor race condition in llGetLocalRot() where inconsistent results could be returned if the prim was rotating during the call --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 854169b..c9d0d91 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2191,7 +2191,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation llGetLocalRot() { m_host.AddScriptLPS(1); - return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W); + + return new LSL_Rotation(m_host.RotationOffset); } public void llSetForce(LSL_Vector force, int local) -- cgit v1.1 From ffbbe29229c2122502a3c173bd40a870d2a3d631 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:01:24 +0000 Subject: refactor: Use LSL_Vector(Vector3) constructor in llGetTorque() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c9d0d91..e55e215 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2287,8 +2287,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetTorque() { m_host.AddScriptLPS(1); - Vector3 torque = m_host.ParentGroup.GetTorque(); - return new LSL_Vector(torque.X,torque.Y,torque.Z); + + return new LSL_Vector(m_host.ParentGroup.GetTorque()); } public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local) -- cgit v1.1 From 04e806036ff6fe9246f7c1ab91f162cb5168bb07 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:02:43 +0000 Subject: refactor: Use LSL_Vector(Vector3) constructor in llGetVel() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index e55e215..aadfe72 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2314,7 +2314,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api vel = m_host.Velocity; } - return new LSL_Vector(vel.X, vel.Y, vel.Z); + return new LSL_Vector(vel); } public LSL_Vector llGetAccel() -- cgit v1.1 From 1774c631cb441458596f3adde3474518d883a7e6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:04:11 +0000 Subject: Fix minor race condition in llGetOmega() where a call whilst a prim was changing angular velocity could return inconsistent results --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index aadfe72..29bc9c7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2320,7 +2320,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetAccel() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); + + return new LSL_Vector(m_host.Acceleration); } public LSL_Vector llGetOmega() -- cgit v1.1 From 895aa7346f5ba44055225cb4d11351f953ce458e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:07:07 +0000 Subject: Fix minor race condition in llGetOmega() where inconsistent results could be returned (accidentally stated that commit 1774c631 was this fix). Commit 1774c631 was actually a fix for a similar minor race condition in llGetAccel() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 29bc9c7..d25f673 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2327,7 +2327,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetOmega() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z); + + return new LSL_Vector(m_host.AngularVelocity); } public LSL_Float llGetTimeOfDay() -- cgit v1.1 From ff6a16b46e334995bce589fe9c9f3854381ee167 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:09:05 +0000 Subject: Fix a minor race condition in llInstantMessage() where slightly wrong origin co-ordinates could be given for a fast moving prim --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d25f673..267dc96 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3105,13 +3105,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api msg.ParentEstateID = 0; //ParentEstateID; msg.Position = new Vector3(m_host.AbsolutePosition); msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; + + Vector3 pos = m_host.AbsolutePosition; msg.binaryBucket = Util.StringToBytes256( "{0}/{1}/{2}/{3}", World.RegionInfo.RegionName, - (int)Math.Floor(m_host.AbsolutePosition.X), - (int)Math.Floor(m_host.AbsolutePosition.Y), - (int)Math.Floor(m_host.AbsolutePosition.Z)); + (int)Math.Floor(pos.X), + (int)Math.Floor(pos.Y), + (int)Math.Floor(pos.Z)); if (m_TransferModule != null) { -- cgit v1.1 From 7b85279dbaf3e73ed45ecafe6a373565643e9a9e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:14:32 +0000 Subject: refactor: Use LSL_Vector(Vector3) constructor in llGetCenterOfMass() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 267dc96..aca0132 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4877,8 +4877,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetCenterOfMass() { m_host.AddScriptLPS(1); - Vector3 center = m_host.GetCenterOfMass(); - return new LSL_Vector(center.X,center.Y,center.Z); + + return new LSL_Vector(m_host.GetCenterOfMass()); } public LSL_List llListSort(LSL_List src, int stride, int ascending) -- cgit v1.1 From 3c9bea1e3fbe0bb457bcc227d0420125c00ce832 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:22:10 +0000 Subject: Fix minor race conditions in llTeleportAgent(), llTeleportAgentGlobalCoords(), llEjectFromLand() and llOverMyLand() where the wrong parcel could be identified for very fast moving avatars. --- .../Shared/Api/Implementation/LSL_Api.cs | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index aca0132..8415feb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4202,9 +4202,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (destination == String.Empty) destination = World.RegionInfo.RegionName; + Vector3 pos = presence.AbsolutePosition; + // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) { DoLLTeleport(presence, destination, targetPos, targetLookAt); } @@ -4234,9 +4235,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // agent must not be a god if (presence.GodLevel >= 200) return; + Vector3 pos = presence.AbsolutePosition; + // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) { World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); } @@ -5865,8 +5867,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence presence = World.GetScenePresence(agentID); if (presence != null) { + Vector3 pos = presence.AbsolutePosition; + // agent must be over the owners land - ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); if (land == null) return; @@ -5888,19 +5892,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence presence = World.GetScenePresence(key); if (presence != null) // object is an avatar { - if (m_host.OwnerID - == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + Vector3 pos = presence.AbsolutePosition; + + if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) return 1; } else // object is not an avatar { SceneObjectPart obj = World.GetSceneObjectPart(key); + if (obj != null) - if (m_host.OwnerID - == World.LandChannel.GetLandObject( - obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID) + { + Vector3 pos = obj.AbsolutePosition; + + if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) return 1; + } } } @@ -5979,7 +5986,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // or // if the object is owned by a person with estate access. - ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y); + Vector3 pos = av.AbsolutePosition; + + ILandObject parcel = World.LandChannel.GetLandObject(pos.X, pos.Y); if (parcel != null) { if (m_host.OwnerID == parcel.LandData.OwnerID || @@ -5991,9 +6000,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - } - } public LSL_Vector llGroundSlope(LSL_Vector offset) -- cgit v1.1 From f8c24b2a61e9f927620fee8e06457f70ba6e2e82 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:26:37 +0000 Subject: minor: Reuse ground LSL_Vector in llGroundSlope() rather than creating a new one. --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 8415feb..6414f35 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6006,6 +6006,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGroundSlope(LSL_Vector offset) { m_host.AddScriptLPS(1); + //Get the slope normal. This gives us the equation of the plane tangent to the slope. LSL_Vector vsn = llGroundNormal(offset); @@ -6016,7 +6017,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api vsl.Normalize(); //Normalization might be overkill here - return new LSL_Vector(vsl.X, vsl.Y, vsl.Z); + vsn.x = vsl.X; + vsn.y = vsl.Y; + vsn.z = vsl.Z; + + return vsn; } public LSL_Vector llGroundNormal(LSL_Vector offset) -- cgit v1.1 From e6eb9146756a9c49aef018cdfd403c10c2bc82d6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:28:40 +0000 Subject: refactor: use LSL_Vector(Vector3) constructor in llGroundNormal() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 6414f35..6aae784 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6071,7 +6071,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //I believe the crossproduct of two normalized vectors is a normalized vector so //this normalization may be overkill - return new LSL_Vector(vsn.X, vsn.Y, vsn.Z); + return new LSL_Vector(vsn); } public LSL_Vector llGroundContour(LSL_Vector offset) -- cgit v1.1 From e7603f98b7353a2d1603094d206ad6f80b837371 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:31:07 +0000 Subject: Fix minor race conditions in detecting current parcel for llAddToLandPassList(), llSetParcelMusicURL() and llGetParcelMusicURL() for moving prims --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 6aae784..f95ecb4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6571,7 +6571,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + Vector3 pos = m_host.AbsolutePosition; + + ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { int expires = 0; @@ -7800,7 +7802,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + Vector3 pos = m_host.AbsolutePosition; + ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); if (land.LandData.OwnerID != m_host.OwnerID) return; @@ -7814,7 +7817,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + Vector3 pos = m_host.AbsolutePosition; + ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); if (land.LandData.OwnerID != m_host.OwnerID) return String.Empty; -- cgit v1.1 From dd6f1fc637f0efb44e0aadf7424314993f100a32 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:33:44 +0000 Subject: Fix minor race condition in llGetRootPosition() where inconsistent results could be returned for moving prims --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index f95ecb4..559744f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7829,8 +7829,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetRootPosition() { m_host.AddScriptLPS(1); - return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, - m_host.ParentGroup.AbsolutePosition.Z); + + return new LSL_Vector(m_host.ParentGroup.AbsolutePosition); } /// -- cgit v1.1 From a6f8638174dde7c32bef4659164a71b47c1c6c71 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:34:48 +0000 Subject: refactor: use LSL_Rotation(Quaternion) constructor in lLGetRootRotation() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 559744f..19eec71 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7859,7 +7859,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else q = m_host.ParentGroup.GroupRotation; // just the group rotation - return new LSL_Rotation(q.X, q.Y, q.Z, q.W); + + return new LSL_Rotation(q); } public LSL_String llGetObjectDesc() -- cgit v1.1 From b23009e480cee996d2d2808b22ea4dfd76a45e03 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:35:41 +0000 Subject: Fix minor race condition in llGetGeometricCenter() if this was changing whilst the function was called. --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 19eec71..deaaa8a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7967,7 +7967,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetGeometricCenter() { - return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z); + return new LSL_Vector(m_host.GetGeometricCenter()); } public LSL_List llGetPrimitiveParams(LSL_List rules) -- cgit v1.1 From 2a81eb8d45b4c2b1866479eec1bc906d0d6cf1a7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:42:11 +0000 Subject: Fix minor race conditions in LSL_Api.GetPrimParams() for PRIM_POSITION, PRIM_SIZE and PRIM_ROT_LOCAL This function is used by all the various ll*Params() and os*Params() functions --- .../Shared/Api/Implementation/LSL_Api.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index deaaa8a..8d5eea3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -8054,23 +8054,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case (int)ScriptBaseClass.PRIM_POSITION: - LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, - part.AbsolutePosition.Y, - part.AbsolutePosition.Z); + LSL_Vector v = new LSL_Vector(part.AbsolutePosition); + // For some reason, the part.AbsolutePosition.* values do not change if the // linkset is rotated; they always reflect the child prim's world position // as though the linkset is unrotated. This is incompatible behavior with SL's // implementation, so will break scripts imported from there (not to mention it // makes it more difficult to determine a child prim's actual inworld position). - if (part.ParentID != 0) - v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition(); + if (!part.IsRoot) + { + LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition); + v = ((v - rootPos) * llGetRootRotation()) + rootPos; + } + res.Add(v); break; case (int)ScriptBaseClass.PRIM_SIZE: - res.Add(new LSL_Vector(part.Scale.X, - part.Scale.Y, - part.Scale.Z)); + res.Add(new LSL_Vector(part.Scale)); break; case (int)ScriptBaseClass.PRIM_ROTATION: @@ -8384,8 +8385,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_DESC: res.Add(new LSL_String(part.Description)); break; - case (int)ScriptBaseClass.PRIM_ROT_LOCAL: - res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W)); + case (int)ScriptBaseClass.PRIM_ROT_LOCAL: + res.Add(new LSL_Rotation(part.RotationOffset)); break; case (int)ScriptBaseClass.PRIM_POS_LOCAL: res.Add(new LSL_Vector(GetPartLocalPos(part))); -- cgit v1.1 From d4b109b4c4c9bc548bfbfa4b0c6d021cfa38bee3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:45:00 +0000 Subject: Fix minor race condition in llParcelMediaCommandList() where a parcel could be misidentified for a moving prim --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 8d5eea3..1b98bd8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -9595,7 +9595,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // according to the docs, this command only works if script owner and land owner are the same // lets add estate owners and gods, too, and use the generic permission check. - ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + Vector3 pos = m_host.AbsolutePosition; + + ILandObject landObject = World.LandChannel.GetLandObject(pos.X, pos.Y); if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? -- cgit v1.1 From 114fd042ded4b2b5e27866810c7af05a6568fc87 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:46:27 +0000 Subject: Fix minor race condition in llGetCameraPos() where an inconsistent post could be returned for a moving camera --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 1b98bd8..b1134e7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -9916,21 +9916,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_item.PermsGranter == UUID.Zero) - return new LSL_Vector(); + return Vector3.Zero; if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { ShoutError("No permissions to track the camera"); - return new LSL_Vector(); + return Vector3.Zero; } ScenePresence presence = World.GetScenePresence(m_host.OwnerID); if (presence != null) { - LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z); + LSL_Vector pos = new LSL_Vector(presence.CameraPosition); return pos; } - return new LSL_Vector(); + + return Vector3.Zero; } public LSL_Rotation llGetCameraRot() -- cgit v1.1 From c09f4ff4834aa2064489ef5376e51352dcdc6966 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:49:08 +0000 Subject: Fix minor race condition in llGetCameraRot() where inconsistent information could be returned for a rotating camera --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index b1134e7..42f9c8d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -9939,21 +9939,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_item.PermsGranter == UUID.Zero) - return new LSL_Rotation(); + return Quaternion.Identity; if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { ShoutError("No permissions to track the camera"); - return new LSL_Rotation(); + return Quaternion.Identity; } ScenePresence presence = World.GetScenePresence(m_host.OwnerID); if (presence != null) { - return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W); + return new LSL_Rotation(presence.CameraRotation); } - return new LSL_Rotation(); + return Quaternion.Identity; } /// -- cgit v1.1 From c1115e4c2e8a35fee3287add748881f3718deba5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 22:56:26 +0000 Subject: Add ILandChannel.GetLandObject(Vector3 position) as this is a very common input to GetLandObject() This conforms to the existing ILandChannel.ParcelsNearPoint() method --- OpenSim/Framework/ILandChannel.cs | 7 +++++++ OpenSim/Region/CoreModules/World/Land/LandChannel.cs | 5 +++++ .../Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs | 5 +++++ OpenSim/Tests/Common/Mock/TestLandChannel.cs | 5 +++++ 4 files changed, 22 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Framework/ILandChannel.cs b/OpenSim/Framework/ILandChannel.cs index 869d4c8..c46c03c 100644 --- a/OpenSim/Framework/ILandChannel.cs +++ b/OpenSim/Framework/ILandChannel.cs @@ -56,6 +56,13 @@ namespace OpenSim.Region.Framework.Interfaces ILandObject GetLandObject(float x, float y); /// + /// Get the parcel at the specified point + /// + /// Vector where x and y components are between 0 and 256. z component is ignored. + /// Land object at the point supplied + ILandObject GetLandObject(Vector3 position); + + /// /// Get the parcels near the specified point /// /// diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 7fc358d..73c592d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs @@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land return null; } + public ILandObject GetLandObject(Vector3 position) + { + return GetLandObject(position.X, position.Y); + } + public ILandObject GetLandObject(int x, int y) { if (m_landManagementModule != null) diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs index a133e51..b4abc1d 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs @@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel RootRegionLandChannel.Clear(setupDefaultParcel); } + public ILandObject GetLandObject(Vector3 position) + { + return GetLandObject(position.X, position.Y); + } + public ILandObject GetLandObject(int x, int y) { //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); diff --git a/OpenSim/Tests/Common/Mock/TestLandChannel.cs b/OpenSim/Tests/Common/Mock/TestLandChannel.cs index 4b4d52d..3115035 100644 --- a/OpenSim/Tests/Common/Mock/TestLandChannel.cs +++ b/OpenSim/Tests/Common/Mock/TestLandChannel.cs @@ -81,6 +81,11 @@ namespace OpenSim.Tests.Common.Mock return obj; } + public ILandObject GetLandObject(Vector3 position) + { + return GetLandObject(position.X, position.Y); + } + public ILandObject GetLandObject(int x, int y) { return GetNoLand(); -- cgit v1.1 From ca99f418d8c09a9364d802d6cbd144c188c7b5cf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:05:21 +0000 Subject: refactor: Use ILandChannel.GetLandObject(Vector3) in LSL_Api rather than having to continually take intermediate Vector3s to avoid race conditions --- .../Shared/Api/Implementation/LSL_Api.cs | 62 ++++++++-------------- 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 42f9c8d..9ab92c9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4176,13 +4176,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (presence != null) { // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject( - presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { World.TeleportClientHome(agentId, presence.ControllingClient); } } } + ScriptSleep(5000); } @@ -4202,10 +4202,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (destination == String.Empty) destination = World.RegionInfo.RegionName; - Vector3 pos = presence.AbsolutePosition; - // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { DoLLTeleport(presence, destination, targetPos, targetLookAt); } @@ -4235,10 +4233,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // agent must not be a god if (presence.GodLevel >= 200) return; - Vector3 pos = presence.AbsolutePosition; - // agent must be over the owners land - if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) { World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation); } @@ -4442,7 +4438,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (pushrestricted) { - ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); + ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); // We didn't find the parcel but region is push restricted so assume it is NOT ok if (targetlandObj == null) @@ -4457,7 +4453,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y); + ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos); if (targetlandObj == null) { // We didn't find the parcel but region isn't push restricted so assume it's ok @@ -5715,8 +5711,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID id = UUID.Zero; if (parcel || parcelOwned) { - pos = m_host.ParentGroup.RootPart.GetWorldPosition(); - land = World.LandChannel.GetLandObject(pos.X, pos.Y); + land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition()); if (land == null) { id = UUID.Zero; @@ -5742,8 +5737,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { if (!regionWide) { - pos = ssp.AbsolutePosition; - land = World.LandChannel.GetLandObject(pos.X, pos.Y); + land = World.LandChannel.GetLandObject(ssp.AbsolutePosition); if (land != null) { if (parcelOwned && land.LandData.OwnerID == id || @@ -5867,10 +5861,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence presence = World.GetScenePresence(agentID); if (presence != null) { - Vector3 pos = presence.AbsolutePosition; - // agent must be over the owners land - ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); + ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition); if (land == null) return; @@ -5892,9 +5884,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence presence = World.GetScenePresence(key); if (presence != null) // object is an avatar { - Vector3 pos = presence.AbsolutePosition; - - if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID) return 1; } else // object is not an avatar @@ -5903,9 +5893,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (obj != null) { - Vector3 pos = obj.AbsolutePosition; - - if (m_host.OwnerID == World.LandChannel.GetLandObject(pos.X, pos.Y).LandData.OwnerID) + if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID) return 1; } } @@ -5985,10 +5973,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // if the land is group owned and the object is group owned by the same group // or // if the object is owned by a person with estate access. - - Vector3 pos = av.AbsolutePosition; - - ILandObject parcel = World.LandChannel.GetLandObject(pos.X, pos.Y); + ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition); if (parcel != null) { if (m_host.OwnerID == parcel.LandData.OwnerID || @@ -6571,9 +6556,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - Vector3 pos = m_host.AbsolutePosition; + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); - ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { int expires = 0; @@ -7802,8 +7786,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - Vector3 pos = m_host.AbsolutePosition; - ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return; @@ -7817,8 +7800,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - Vector3 pos = m_host.AbsolutePosition; - ILandObject land = World.LandChannel.GetLandObject(pos.X, pos.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return String.Empty; @@ -9595,9 +9577,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // according to the docs, this command only works if script owner and land owner are the same // lets add estate owners and gods, too, and use the generic permission check. - Vector3 pos = m_host.AbsolutePosition; - - ILandObject landObject = World.LandChannel.GetLandObject(pos.X, pos.Y); + ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return; bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)? @@ -10022,7 +10002,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { int expires = 0; @@ -10063,7 +10043,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed)) { if (UUID.TryParse(avatar, out key)) @@ -10090,7 +10070,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); UUID key; - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned)) { if (UUID.TryParse(avatar, out key)) @@ -10352,7 +10332,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llResetLandBanList() { m_host.AddScriptLPS(1); - LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; + LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; if (land.OwnerID == m_host.OwnerID) { foreach (LandAccessEntry entry in land.ParcelAccessList) @@ -10369,7 +10349,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llResetLandPassList() { m_host.AddScriptLPS(1); - LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData; + LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData; if (land.OwnerID == m_host.OwnerID) { foreach (LandAccessEntry entry in land.ParcelAccessList) -- cgit v1.1 From f8dab4f93fda5aa63bb796adfe64187a7799a7af Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:06:54 +0000 Subject: refactor: Use LSL_Vector(Vector3) constructor in llCastRay() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 9ab92c9..3885ba6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -11462,7 +11462,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api list.Add(new LSL_Integer(linkNum)); if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) - list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z)); + list.Add(new LSL_Vector(result.Normal)); values++; if (values >= count) -- cgit v1.1 From 55204ccde6099652652bbfa315abdd321e96a340 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:09:59 +0000 Subject: Fix minor race conditions in OSSL_Api functions where a parcel could be misidentified for moving prims. --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index bd83f02..dc03ee6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -363,7 +363,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //OSSL only may be used if object is in the same group as the parcel if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) { - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) { @@ -374,7 +374,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api //Only Parcelowners may use the function if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER")) { - ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID == ownerID) { @@ -1502,8 +1502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - ILandObject land - = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) return; @@ -1519,8 +1518,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - ILandObject land - = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); + ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition); if (land.LandData.OwnerID != m_host.OwnerID) { -- cgit v1.1 From 56b333f301cc66cf6417c0e4853f1b930e54dbb0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:12:58 +0000 Subject: minor: Use more compact libomv primitive constructors in osNpcGetPos() and osNpcGetRot() --- .../Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index dc03ee6..0ab2733 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2513,13 +2513,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScenePresence sp = World.GetScenePresence(npcId); if (sp != null) - { - Vector3 pos = sp.AbsolutePosition; - return new LSL_Vector(pos.X, pos.Y, pos.Z); - } + return new LSL_Vector(sp.AbsolutePosition); } - return new LSL_Vector(0, 0, 0); + return Vector3.Zero; } public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos) @@ -2587,7 +2584,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Rotation(sp.GetWorldRotation()); } - return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); + return Quaternion.Identity; } public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation) -- cgit v1.1 From 0ea0f8aa83eac5ce826483785ac5398286876e17 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:16:39 +0000 Subject: Fix bug in osCauseHealing() if called with an avatar ID for an avatar that is not in the scene. --- .../Shared/Api/Implementation/OSSL_Api.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 0ab2733..a6dca61 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3014,20 +3014,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID avatarId = new UUID(avatar); ScenePresence presence = World.GetScenePresence(avatarId); - Vector3 pos = m_host.GetWorldPosition(); - bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z)); - if (result) + + if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition())) { - if (presence != null) - { - float health = presence.Health; - health += (float)healing; - if (health >= 100) - { - health = 100; - } - presence.setHealthWithUpdate(health); - } + float health = presence.Health; + health += (float)healing; + + if (health >= 100) + health = 100; + + presence.setHealthWithUpdate(health); } } -- cgit v1.1 From 2fbc08d7dd30b16b3cf5198e175353ea49f08d91 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:19:18 +0000 Subject: refactor: minor cleanup in osGetAvatarList() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index a6dca61..bf1b45b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -3100,8 +3100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (avatar != null && avatar.UUID != m_host.OwnerID) { result.Add(new LSL_String(avatar.UUID.ToString())); - OpenMetaverse.Vector3 ap = avatar.AbsolutePosition; - result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z)); + result.Add(new LSL_Vector(avatar.AbsolutePosition)); result.Add(new LSL_String(avatar.Name)); } }); -- cgit v1.1 From 12900ea84e699f84943009f2d3218fcf5013c6f9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:39:15 +0000 Subject: Log same environment information to Robust log as is already done for simulator logs, for debug purposes --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 12 +----------- OpenSim/Framework/Servers/ServerBase.cs | 20 ++++++++++++++++++++ OpenSim/Region/Application/OpenSim.cs | 1 + OpenSim/Region/Application/OpenSimBase.cs | 4 ---- OpenSim/Server/Base/ServicesServerBase.cs | 5 +---- 5 files changed, 23 insertions(+), 19 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index c0dc907..035b3ad 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -133,17 +133,7 @@ namespace OpenSim.Framework.Servers /// Performs initialisation of the scene, such as loading configuration from disk. /// public virtual void Startup() - { - m_log.Info("[STARTUP]: Beginning startup processing"); - - m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine); - // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and - // the clr version number doesn't match the project version number under Mono. - //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); - m_log.InfoFormat( - "[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n", - Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); - + { StartupSpecific(); TimeSpan timeTaken = DateTime.Now - m_startuptime; diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 47baac8..657444c 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -113,6 +113,26 @@ namespace OpenSim.Framework.Servers } } + /// + /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details, + /// etc.). + /// + public void LogEnvironmentInformation() + { + // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net + // XmlConfigurator calls first accross servers. + m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory); + + m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version); + + // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and + // the clr version number doesn't match the project version number under Mono. + //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine); + m_log.InfoFormat( + "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit", + Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32"); + } + public void RegisterCommonAppenders(IConfig startupConfig) { ILoggerRepository repository = LogManager.GetRepository(); diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 4075edb..11dd052 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -159,6 +159,7 @@ namespace OpenSim MainConsole.Instance = m_console; + LogEnvironmentInformation(); RegisterCommonAppenders(Config.Configs["Startup"]); RegisterConsoleCommands(); diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 137bd81..c555915 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -134,10 +134,6 @@ namespace OpenSim /// public OpenSimBase(IConfigSource configSource) : base() { - // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net - // XmlConfigurator calls first accross servers. - m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory); - LoadConfigSettings(configSource); } diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index 5aff72a..7c8e6b7 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -186,10 +186,7 @@ namespace OpenSim.Server.Base XmlConfigurator.Configure(); } - // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net - // XmlConfigurator calls first accross servers. - m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory); - + LogEnvironmentInformation(); RegisterCommonAppenders(startupConfig); if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty) -- cgit v1.1 From 081271e1d7fbf18c918a676d17b40edc8b0b6bfb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 14 Mar 2013 23:44:16 +0000 Subject: minor: remove mono compiler warnings in LSL_Api.cs --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 3885ba6..cf16571 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -5707,8 +5707,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } ILandObject land; - Vector3 pos; UUID id = UUID.Zero; + if (parcel || parcelOwned) { land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition()); @@ -11028,7 +11028,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World.ForEachScenePresence(delegate(ScenePresence sp) { Vector3 ac = sp.AbsolutePosition - rayStart; - Vector3 bc = sp.AbsolutePosition - rayEnd; +// Vector3 bc = sp.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); @@ -11118,7 +11118,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api radius = Math.Abs(maxZ); radius = radius*1.413f; Vector3 ac = group.AbsolutePosition - rayStart; - Vector3 bc = group.AbsolutePosition - rayEnd; +// Vector3 bc = group.AbsolutePosition - rayEnd; double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd)); -- cgit v1.1 From e25ba116a337fe360145ad0a430ee5326d318859 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 00:06:42 +0000 Subject: refactor: make llGetLinkName() and llGetLinkKey() use a common GetLinkEntity() method --- .../Shared/Api/Implementation/LSL_Api.cs | 164 ++++++++++----------- 1 file changed, 80 insertions(+), 84 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cf16571..8adf4d9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -283,6 +283,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + /// + /// Get a given link entity from a linkset (linked objects and any sitting avatars). + /// + /// + /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then + /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset. + /// The ScenePresences receive linknums in the order in which they sat. + /// + /// + /// The link entity. null if not found. + /// + /// + /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4). + /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned. + /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any + /// positive integer is given in this case then null is returned. + /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number + /// of entities, then the entity which corresponds to that linknum is returned. + /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then + /// null is returned. + /// + public ISceneEntity GetLinkEntity(int linknum) + { + if (linknum < 0) + { + if (linknum == ScriptBaseClass.LINK_THIS) + return m_host; + else + return null; + } + + int actualPrimCount = m_host.ParentGroup.PrimCount; + List sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); + int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; + + // Special case for a single prim. In this case the linknum is zero. However, this will not match a single + // prim that has any avatars sat upon it (in which case the root prim is link 1). + if (linknum == 0) + { + if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) + return m_host; + + return null; + } + // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but + // here we must match 1 (ScriptBaseClass.LINK_ROOT). + else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1) + { + if (sittingAvatarIds.Count > 0) + return m_host.ParentGroup.RootPart; + else + return null; + } + else if (linknum <= adjustedPrimCount) + { + if (linknum <= actualPrimCount) + { + return m_host.ParentGroup.GetLinkNumPart(linknum); + } + else + { + ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]); + if (sp != null) + return sp; + else + return null; + } + } + else + { + return null; + } + } + public List GetLinkParts(int linkType) { return GetLinkParts(m_host, linkType); @@ -3697,47 +3771,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (linknum < 0) - { - if (linknum == ScriptBaseClass.LINK_THIS) - return m_host.UUID.ToString(); - else - return ScriptBaseClass.NULL_KEY; - } - - int actualPrimCount = m_host.ParentGroup.PrimCount; - List sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); - int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; + ISceneEntity entity = GetLinkEntity(linknum); - // Special case for a single prim. In this case the linknum is zero. However, this will not match a single - // prim that has any avatars sat upon it (in which case the root prim is link 1). - if (linknum == 0) - { - if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) - return m_host.UUID.ToString(); - - return ScriptBaseClass.NULL_KEY; - } - // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but - // here we must match 1 (ScriptBaseClass.LINK_ROOT). - else if (linknum == 1 && actualPrimCount == 1) - { - if (sittingAvatarIds.Count > 0) - return m_host.ParentGroup.RootPart.UUID.ToString(); - else - return ScriptBaseClass.NULL_KEY; - } - else if (linknum <= adjustedPrimCount) - { - if (linknum <= actualPrimCount) - return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString(); - else - return sittingAvatarIds[linknum - actualPrimCount - 1].ToString(); - } + if (entity != null) + return entity.UUID.ToString(); else - { return ScriptBaseClass.NULL_KEY; - } } /// @@ -3783,55 +3822,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (linknum < 0) - { - if (linknum == ScriptBaseClass.LINK_THIS) - return m_host.Name; - else - return ScriptBaseClass.NULL_KEY; - } - - int actualPrimCount = m_host.ParentGroup.PrimCount; - List sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars(); - int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count; - - // Special case for a single prim. In this case the linknum is zero. However, this will not match a single - // prim that has any avatars sat upon it (in which case the root prim is link 1). - if (linknum == 0) - { - if (actualPrimCount == 1 && sittingAvatarIds.Count == 0) - return m_host.Name; + ISceneEntity entity = GetLinkEntity(linknum); - return ScriptBaseClass.NULL_KEY; - } - // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but - // here we must match 1 (ScriptBaseClass.LINK_ROOT). - else if (linknum == 1 && actualPrimCount == 1) - { - if (sittingAvatarIds.Count > 0) - return m_host.ParentGroup.RootPart.Name; - else - return ScriptBaseClass.NULL_KEY; - } - else if (linknum <= adjustedPrimCount) - { - if (linknum <= actualPrimCount) - { - return m_host.ParentGroup.GetLinkNumPart(linknum).Name; - } - else - { - ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]); - if (sp != null) - return sp.Name; - else - return ScriptBaseClass.NULL_KEY; - } - } + if (entity != null) + return entity.Name; else - { return ScriptBaseClass.NULL_KEY; - } } public LSL_Integer llGetInventoryNumber(int type) -- cgit v1.1 From cb74186888d987ec353a257d677aa35b0dc63c0a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 00:27:06 +0000 Subject: Add ParentGroup.HasGroupChanged = true setting to DAExampleModule as this is necessary to get attributes to save (though this probably happens anyway due to the prim move) --- .../Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index f874495..854e00d 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -106,6 +106,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule sop.DynAttrs[Name] = attrs; } + + sop.ParentGroup.HasGroupChanged = true; m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue)); -- cgit v1.1 From d3e76730bd8e89b684cb856bcb7192246f201c2a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 00:49:35 +0000 Subject: Add example code to DOExampleModule to pull data from that previously saved by DAExampleModule when instantiating a dynamc object. --- .../Framework/DynamicAttributes/DAExampleModule.cs | 8 ++++--- .../Framework/DynamicAttributes/DOExampleModule.cs | 26 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 854e00d..1f1568f 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -39,7 +39,7 @@ using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule +namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] public class DAExampleModule : INonSharedRegionModule @@ -48,6 +48,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule private static readonly bool ENABLED = false; // enable for testing + public const string DANamespace = "DAExample Module"; + protected Scene m_scene; protected IDialogModule m_dialogMod; @@ -89,7 +91,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule if (sop == null) return true; - if (!sop.DynAttrs.TryGetValue(Name, out attrs)) + if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs)) attrs = new OSDMap(); OSDInteger newValue; @@ -104,7 +106,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule attrs["moves"] = newValue; - sop.DynAttrs[Name] = attrs; + sop.DynAttrs[DANamespace] = attrs; } sop.ParentGroup.HasGroupChanged = true; diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs index 71bb3f0..650aa35 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs @@ -36,6 +36,7 @@ using OpenMetaverse.Packets; using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Region.Framework; +using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -50,9 +51,14 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule public class MyObject { public int Moves { get; set; } + + public MyObject(int moves) + { + Moves = moves; + } } - // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly bool ENABLED = false; // enable for testing @@ -92,7 +98,23 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule private void OnObjectAddedToScene(SceneObjectGroup so) { - so.RootPart.DynObjs.Add(Name, new MyObject()); + SceneObjectPart rootPart = so.RootPart; + + OSDMap attrs; + + int movesSoFar = 0; + +// Console.WriteLine("Here for {0}", so.Name); + + if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs)) + { + movesSoFar = attrs["moves"].AsInteger(); + + m_log.DebugFormat( + "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name); + } + + rootPart.DynObjs.Add(Name, new MyObject(movesSoFar)); } private bool OnSceneGroupMove(UUID groupId, Vector3 delta) -- cgit v1.1 From c10c43d6f6b0a79848b9a655533c27ab58cd2993 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 15 Mar 2013 13:59:34 -0700 Subject: Fix server statistics always reporting zero for total network bytes in/out. Clean up some parameter code in Statistics.Binary. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 51 ++++++++++++++-------- .../Framework/Monitoring/ServerStats.cs | 41 ++++++++++------- 2 files changed, 58 insertions(+), 34 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a7628d2..72516cd 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -278,25 +278,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_shouldCollectStats = false; if (config != null) { - if (config.Contains("enabled") && config.GetBoolean("enabled")) - { - if (config.Contains("collect_packet_headers")) - m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); - if (config.Contains("packet_headers_period_seconds")) - { - binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); - } - if (config.Contains("stats_dir")) - { - binStatsDir = config.GetString("stats_dir"); - } - } - else - { - m_shouldCollectStats = false; - } - } - #endregion BinaryStats + m_shouldCollectStats = config.GetBoolean("Enabled", false); + binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300)); + binStatsDir = config.GetString("stats_dir", "."); + m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false); + } + #endregion BinaryStats m_throttle = new TokenBucket(null, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); @@ -1266,8 +1253,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP static object binStatsLogLock = new object(); static string binStatsDir = ""; + //for Aggregated In/Out BW logging + static bool m_aggregatedBWStats = false; + static long m_aggregatedBytesIn = 0; + static long m_aggregatedByestOut = 0; + static object aggBWStatsLock = new object(); + + public static long AggregatedLLUDPBytesIn + { + get { return m_aggregatedBytesIn; } + } + public static long AggregatedLLUDPBytesOut + { + get {return m_aggregatedByestOut;} + } + public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) { + if (m_aggregatedBWStats) + { + lock (aggBWStatsLock) + { + if (incoming) + m_aggregatedBytesIn += size; + else + m_aggregatedByestOut += size; + } + } + if (!m_shouldCollectStats) return; // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs index a3d2436..6e74ce0 100644 --- a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs +++ b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs @@ -140,9 +140,12 @@ public class ServerStats : ISharedRegionModule } #endregion ISharedRegionModule - private void MakeStat(string pName, string pUnit, string pContainer, Action act) + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) { - Stat stat = new Stat(pName, pName, "", pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); + string desc = pDesc; + if (desc == null) + desc = pName; + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); StatsManager.RegisterStat(stat); RegisteredStats.Add(pName, stat); } @@ -166,16 +169,16 @@ public class ServerStats : ISharedRegionModule StatsManager.RegisterStat(tempStat); RegisteredStats.Add(tempName, tempStat); - MakeStat("TotalProcessorTime", "sec", ContainerProcessor, + MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); - MakeStat("UserProcessorTime", "sec", ContainerProcessor, + MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); - MakeStat("PrivilegedProcessorTime", "sec", ContainerProcessor, + MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); - MakeStat("Threads", "threads", ContainerProcessor, + MakeStat("Threads", null, "threads", ContainerProcessor, (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); } catch (Exception e) @@ -196,8 +199,10 @@ public class ServerStats : ISharedRegionModule string nicInterfaceType = nic.NetworkInterfaceType.ToString(); if (!okInterfaceTypes.Contains(nicInterfaceType)) { - m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'. To include, add to [Monitoring]NetworkInterfaceTypes='Ethernet,Loopback'", + m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", LogHeader, nic.Name, nicInterfaceType); + m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", + LogHeader, NetworkInterfaceTypes); continue; } @@ -206,14 +211,15 @@ public class ServerStats : ISharedRegionModule IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); if (nicStats != null) { - MakeStat("BytesRcvd/" + nic.Name, "KB", ContainerNetwork, + MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); - MakeStat("BytesSent/" + nic.Name, "KB", ContainerNetwork, + MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); - MakeStat("TotalBytes/" + nic.Name, "KB", ContainerNetwork, + MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); } } + // TODO: add IPv6 (it may actually happen someday) } } catch (Exception e) @@ -221,13 +227,13 @@ public class ServerStats : ISharedRegionModule m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); } - MakeStat("ProcessMemory", "MB", ContainerMemory, + MakeStat("ProcessMemory", null, "MB", ContainerMemory, (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); - MakeStat("ObjectMemory", "MB", ContainerMemory, + MakeStat("ObjectMemory", null, "MB", ContainerMemory, (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); - MakeStat("LastMemoryChurn", "MB/sec", ContainerMemory, + MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); - MakeStat("AverageMemoryChurn", "MB/sec", ContainerMemory, + MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); } @@ -263,6 +269,8 @@ public class ServerStats : ISharedRegionModule } } + // Lookup the nic that goes with this stat and set the value by using a fetch action. + // Not sure about closure with delegates inside delegates. private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) { @@ -275,7 +283,10 @@ public class ServerStats : ISharedRegionModule { IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); if (intrStats != null) - stat.Value = Math.Round(getter(intrStats) / factor, 3); + { + double newVal = Math.Round(getter(intrStats) / factor, 3); + stat.Value = newVal; + } break; } } -- cgit v1.1 From 78b25094dce9bbc79848da1208c44f0d9ebe8c76 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Mon, 11 Mar 2013 19:08:38 -0400 Subject: BulletSim: Tweak vertical angular attraction to remove double VehicleOrientation application fixing the problem with the vertical attractor pushing vehicles nose first into ground when tilted on side. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 235cefc..d347159 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1335,7 +1335,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG vertContributionV /= m_verticalAttractionTimescale; - VehicleRotationalVelocity += vertContributionV * VehicleOrientation; + VehicleRotationalVelocity += vertContributionV; VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, -- cgit v1.1 From 924d6e892a7b5a61e900b910a5a35de488963529 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 21:53:39 +0000 Subject: Make it possible to chain another asset service underneath the de-duplicating XAssetService. This makes it possible to use the dedupliicating service without needing to migrate all the existing asset data beforehand. Currently controlled by a ChainedServiceModule setting in [AssetService] (e.g. ChainedServiceModule = "OpenSim.Services.AssetService.dll:AssetService") Not yet ready for use. --- OpenSim/Services/AssetService/XAssetService.cs | 51 +++++++++++++++++----- OpenSim/Services/AssetService/XAssetServiceBase.cs | 47 +++++++++++++++----- 2 files changed, 75 insertions(+), 23 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index a1d10ed..7dd48c9 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -39,8 +39,7 @@ using OpenMetaverse; namespace OpenSim.Services.AssetService { /// - /// This will be developed into a de-duplicating asset service. - /// XXX: Currently it's a just a copy of the existing AssetService. so please don't attempt to use it. + /// A de-duplicating asset service. /// public class XAssetService : XAssetServiceBase, IAssetService { @@ -48,7 +47,9 @@ namespace OpenSim.Services.AssetService protected static XAssetService m_RootInstance; - public XAssetService(IConfigSource config) : base(config) + public XAssetService(IConfigSource config) : this(config, "AssetService") {} + + public XAssetService(IConfigSource config, string configName) : base(config, configName) { if (m_RootInstance == null) { @@ -56,22 +57,21 @@ namespace OpenSim.Services.AssetService if (m_AssetLoader != null) { - IConfig assetConfig = config.Configs["AssetService"]; + IConfig assetConfig = config.Configs[configName]; if (assetConfig == null) throw new Exception("No AssetService configuration"); - string loaderArgs = assetConfig.GetString("AssetLoaderArgs", - String.Empty); + string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty); bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); - if (assetLoaderEnabled) + if (assetLoaderEnabled && !HasChainedAssetService) { m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs); m_AssetLoader.ForEachDefaultXmlAsset( loaderArgs, - delegate(AssetBase a) + a => { AssetBase existingAsset = Get(a.ID); // AssetMetadata existingMetadata = GetMetadata(a.ID); @@ -103,7 +103,14 @@ namespace OpenSim.Services.AssetService try { - return m_Database.GetAsset(assetID); + AssetBase asset = m_Database.GetAsset(assetID); + + if (asset != null) + return asset; + else if (HasChainedAssetService) + return m_ChainedAssetService.Get(id); + else + return null; } catch (Exception e) { @@ -128,9 +135,17 @@ namespace OpenSim.Services.AssetService AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) + { return asset.Metadata; - - return null; + } + else if (HasChainedAssetService) + { + return m_ChainedAssetService.GetMetadata(id); + } + else + { + return null; + } } public virtual byte[] GetData(string id) @@ -143,7 +158,13 @@ namespace OpenSim.Services.AssetService return null; AssetBase asset = m_Database.GetAsset(assetID); - return asset.Data; + + if (asset != null) + return asset.Data; + else if (HasChainedAssetService) + return m_ChainedAssetService.GetData(id); + else + return null; } public virtual bool Get(string id, Object sender, AssetRetrieved handler) @@ -157,6 +178,9 @@ namespace OpenSim.Services.AssetService AssetBase asset = m_Database.GetAsset(assetID); + if (asset == null && HasChainedAssetService) + asset = m_ChainedAssetService.Get(id); + //m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset); handler(id, sender, asset); @@ -194,6 +218,9 @@ namespace OpenSim.Services.AssetService if (!UUID.TryParse(id, out assetID)) return false; + // Don't bother deleting from a chained asset service. This isn't a big deal since deleting happens + // very rarely. + return m_Database.Delete(id); } } diff --git a/OpenSim/Services/AssetService/XAssetServiceBase.cs b/OpenSim/Services/AssetService/XAssetServiceBase.cs index 0c5c2c3..c118c9d 100644 --- a/OpenSim/Services/AssetService/XAssetServiceBase.cs +++ b/OpenSim/Services/AssetService/XAssetServiceBase.cs @@ -27,9 +27,11 @@ using System; using System.Reflection; +using log4net; using Nini.Config; using OpenSim.Framework; using OpenSim.Data; +using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Services.Base; @@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService { public class XAssetServiceBase : ServiceBase { - protected IXAssetDataPlugin m_Database = null; - protected IAssetLoader m_AssetLoader = null; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public XAssetServiceBase(IConfigSource config) : base(config) + protected IXAssetDataPlugin m_Database; + protected IAssetLoader m_AssetLoader; + protected IAssetService m_ChainedAssetService; + + protected bool HasChainedAssetService { get { return m_ChainedAssetService != null; } } + + public XAssetServiceBase(IConfigSource config, string configName) : base(config) { string dllName = String.Empty; string connString = String.Empty; @@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService // // Try reading the [AssetService] section first, if it exists // - IConfig assetConfig = config.Configs["AssetService"]; + IConfig assetConfig = config.Configs[configName]; if (assetConfig != null) { dllName = assetConfig.GetString("StorageProvider", dllName); @@ -77,17 +84,35 @@ namespace OpenSim.Services.AssetService if (m_Database == null) throw new Exception("Could not find a storage interface in the given module"); - m_Database.Initialise(connString); + string chainedAssetServiceDesignator = assetConfig.GetString("ChainedServiceModule", null); + + if (chainedAssetServiceDesignator != null) + { + m_log.InfoFormat( + "[XASSET SERVICE BASE]: Loading chained asset service from {0}", chainedAssetServiceDesignator); - string loaderName = assetConfig.GetString("DefaultAssetLoader", - String.Empty); + Object[] args = new Object[] { config, configName }; + m_ChainedAssetService = ServerUtils.LoadPlugin(chainedAssetServiceDesignator, args); - if (loaderName != String.Empty) + if (!HasChainedAssetService) + throw new Exception( + String.Format("Failed to load ChainedAssetService from {0}", chainedAssetServiceDesignator)); + } + + m_Database.Initialise(connString); + + if (HasChainedAssetService) { - m_AssetLoader = LoadPlugin(loaderName); + string loaderName = assetConfig.GetString("DefaultAssetLoader", + String.Empty); + + if (loaderName != String.Empty) + { + m_AssetLoader = LoadPlugin(loaderName); - if (m_AssetLoader == null) - throw new Exception("Asset loader could not be loaded"); + if (m_AssetLoader == null) + throw new Exception("Asset loader could not be loaded"); + } } } } -- cgit v1.1 From 3a7d9f740e3574bb3091d40fa35c7abf642c1f3c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 22:05:18 +0000 Subject: minor: Make logged message in ServerUtils more consistent. --- OpenSim/Server/Base/ServerUtils.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 2e6d279..210a314 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -138,17 +138,17 @@ namespace OpenSim.Server.Base case ExtensionChange.Add: if (a.AddinFile.Contains(Registry.DefaultAddinsFolder)) { - m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Adding {0} from registry", a.Name); connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); } else { - m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Adding {0} from ./bin", a.Name); connector.PluginPath = a.AddinFile; } LoadPlugin(connector); break; case ExtensionChange.Remove: - m_log.InfoFormat("[SERVER]: Removing {0}", a.Name); + m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name); UnloadPlugin(connector); break; } @@ -166,13 +166,13 @@ namespace OpenSim.Server.Base } else { - m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName); + m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName); } } private void UnloadPlugin(IRobustConnector connector) { - m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName); + m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName); connector.Unload(); } @@ -280,7 +280,7 @@ namespace OpenSim.Server.Base { if (!(e is System.MissingMethodException)) { - m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}", + m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0} from {1}. Exception: {2}, {3}", interfaceName, dllName, e.InnerException == null ? e.Message : e.InnerException.Message, @@ -298,14 +298,14 @@ namespace OpenSim.Server.Base } catch (ReflectionTypeLoadException rtle) { - m_log.Error(string.Format("Error loading plugin from {0}:\n{1}", dllName, + m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName, String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))), rtle); return null; } catch (Exception e) { - m_log.Error(string.Format("Error loading plugin from {0}", dllName), e); + m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e); return null; } } @@ -517,7 +517,7 @@ namespace OpenSim.Server.Base public static IConfigSource LoadInitialConfig(string url) { IConfigSource source = new XmlConfigSource(); - m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url); + m_log.InfoFormat("[SERVER UTILS]: {0} is a http:// URI, fetching ...", url); // The ini file path is a http URI // Try to read it @@ -529,7 +529,7 @@ namespace OpenSim.Server.Base } catch (Exception e) { - m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url); + m_log.FatalFormat("[SERVER UTILS]: Exception reading config from URI {0}\n" + e.ToString(), url); Environment.Exit(1); } -- cgit v1.1 From 7fb458b05517089ae3d072cde167258aa6a129ff Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 22:08:11 +0000 Subject: minor: log an error rather than info if a connector fails to load. --- OpenSim/Server/ServerMain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs index 8be69a9..65e9287 100644 --- a/OpenSim/Server/ServerMain.cs +++ b/OpenSim/Server/ServerMain.cs @@ -145,7 +145,7 @@ namespace OpenSim.Server } else { - m_log.InfoFormat("[SERVER]: Failed to load {0}", conn); + m_log.ErrorFormat("[SERVER]: Failed to load {0}", conn); } } -- cgit v1.1 From d05af4bdad7d4855b05eba909c5b21714e5f438a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 22:14:34 +0000 Subject: Fix bug in AssetService where requesting data only for an asset would throw an exception if the asset did not exist. --- OpenSim/Services/AssetService/AssetService.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'OpenSim') diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index e7eb6fe..422fd0a 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -146,7 +146,11 @@ namespace OpenSim.Services.AssetService return null; AssetBase asset = m_Database.GetAsset(assetID); - return asset.Data; + + if (asset != null) + return asset.Data; + else + return null; } public virtual bool Get(string id, Object sender, AssetRetrieved handler) -- cgit v1.1 From bd0c1d9b6ac23b0fca8228fcf48da842b114773e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 22:33:39 +0000 Subject: Migrate assets from chained asset service to xassetservice as they are requested. This shrinks the asset database over time as duplicate assets are fetched. --- OpenSim/Services/AssetService/XAssetService.cs | 48 +++++++++++--------------- 1 file changed, 20 insertions(+), 28 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index 7dd48c9..8a2ca7c 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -106,11 +106,20 @@ namespace OpenSim.Services.AssetService AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) + { return asset; + } else if (HasChainedAssetService) - return m_ChainedAssetService.Get(id); - else - return null; + { + asset = m_ChainedAssetService.Get(id); + + if (asset != null) + MigrateFromChainedService(asset); + + return asset; + } + + return null; } catch (Exception e) { @@ -127,42 +136,23 @@ namespace OpenSim.Services.AssetService public virtual AssetMetadata GetMetadata(string id) { // m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; + AssetBase asset = Get(id); - AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) - { return asset.Metadata; - } - else if (HasChainedAssetService) - { - return m_ChainedAssetService.GetMetadata(id); - } else - { return null; - } } public virtual byte[] GetData(string id) { // m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id); - UUID assetID; - - if (!UUID.TryParse(id, out assetID)) - return null; - - AssetBase asset = m_Database.GetAsset(assetID); + AssetBase asset = Get(id); if (asset != null) return asset.Data; - else if (HasChainedAssetService) - return m_ChainedAssetService.GetData(id); else return null; } @@ -176,10 +166,7 @@ namespace OpenSim.Services.AssetService if (!UUID.TryParse(id, out assetID)) return false; - AssetBase asset = m_Database.GetAsset(assetID); - - if (asset == null && HasChainedAssetService) - asset = m_ChainedAssetService.Get(id); + AssetBase asset = Get(id); //m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset); @@ -223,5 +210,10 @@ namespace OpenSim.Services.AssetService return m_Database.Delete(id); } + + private void MigrateFromChainedService(AssetBase asset) + { + Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); }); + } } } \ No newline at end of file -- cgit v1.1 From 45dee383db016d1840c468b594db28ea714493a5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 22:42:34 +0000 Subject: refactor: Reuse Get() method in AssetService to eliminate some copy/paste in other Get methods --- OpenSim/Services/AssetService/AssetService.cs | 28 +++++---------------------- 1 file changed, 5 insertions(+), 23 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index 422fd0a..08fd3f8 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -123,29 +123,20 @@ namespace OpenSim.Services.AssetService public virtual AssetMetadata GetMetadata(string id) { // m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; + AssetBase asset = Get(id); - AssetBase asset = m_Database.GetAsset(assetID); if (asset != null) return asset.Metadata; - - return null; + else + return null; } public virtual byte[] GetData(string id) { // m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return null; - - AssetBase asset = m_Database.GetAsset(assetID); + AssetBase asset = Get(id); if (asset != null) return asset.Data; @@ -156,17 +147,8 @@ namespace OpenSim.Services.AssetService public virtual bool Get(string id, Object sender, AssetRetrieved handler) { //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); - - UUID assetID; - if (!UUID.TryParse(id, out assetID)) - return false; - - AssetBase asset = m_Database.GetAsset(assetID); - - //m_log.DebugFormat("[AssetService]: Got asset {0}", asset); - - handler(id, sender, asset); + handler(id, sender, Get(id)); return true; } -- cgit v1.1 From e9f3cd1a60bfc5e936d1029495ada2c2bff99430 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 23:17:54 +0000 Subject: Implement access time updates on assets for XAssetService. This only happens if access time is older than 30 days currently, in order to reduce database updates. The idea is to give some idea of assets which haven't been accessed for a very, very long time. These might conceivably be deleteable, though this will be a risk due to caching at other points in the chain. This is actually currently much less useable on the xasset service since access time is on metadata rather than the data itself. And many metadata entries may point to the same data. Probably need to address this. --- OpenSim/Data/MySQL/MySQLXAssetData.cs | 95 +++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 38 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index c2282c8..273fbca 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -50,6 +50,11 @@ namespace OpenSim.Data.MySQL get { return GetType().Assembly; } } + /// + /// Number of days that must pass before we update the access time on an asset when it has been fetched. + /// + private const int DaysBetweenAccessTimeUpdates = 30; + private bool m_enableCompression = false; private string m_connectionString; private object m_dbLock = new object(); @@ -133,7 +138,7 @@ namespace OpenSim.Data.MySQL dbcon.Open(); using (MySqlCommand cmd = new MySqlCommand( - "SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id", + "SELECT name, description, access_time, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id", dbcon)) { cmd.Parameters.AddWithValue("?id", assetID.ToString()); @@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL // asset.ID, asset.Name, asset.Data.Length, compressedLength); } } + + UpdateAccessTime(asset.Metadata, (int)dbReader["access_time"]); } } } catch (Exception e) { - m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message); + m_log.Error("[MYSQL XASSET DATA]: Failure fetching asset " + assetID + ": " + e.Message); } } } @@ -303,41 +310,49 @@ namespace OpenSim.Data.MySQL } } -// private void UpdateAccessTime(AssetBase asset) -// { -// lock (m_dbLock) -// { -// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) -// { -// dbcon.Open(); -// MySqlCommand cmd = -// new MySqlCommand("update assets set access_time=?access_time where id=?id", -// dbcon); -// -// // need to ensure we dispose -// try -// { -// using (cmd) -// { -// // create unix epoch time -// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); -// cmd.Parameters.AddWithValue("?id", asset.ID); -// cmd.Parameters.AddWithValue("?access_time", now); -// cmd.ExecuteNonQuery(); -// cmd.Dispose(); -// } -// } -// catch (Exception e) -// { -// m_log.ErrorFormat( -// "[ASSETS DB]: " + -// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() -// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); -// } -// } -// } -// -// } + /// + /// Updates the access time of the asset if it was accessed above a given threshhold amount of time. + /// + /// + /// This gives us some insight into assets which haven't ben accessed for a long period. This is only done + /// over the threshold time to avoid excessive database writes as assets are fetched. + /// + /// + /// + private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime) + { + DateTime now = DateTime.UtcNow; + + if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates) + return; + + lock (m_dbLock) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + MySqlCommand cmd = + new MySqlCommand("update assets set access_time=?access_time where id=?id", dbcon); + + try + { + using (cmd) + { + // create unix epoch time + cmd.Parameters.AddWithValue("?id", assetMetadata.ID); + cmd.Parameters.AddWithValue("?access_time", (int)Utils.DateTimeToUnixTime(now)); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}", + assetMetadata.ID, assetMetadata.Name); + } + } + } + } /// /// We assume we already have the m_dbLock. @@ -422,6 +437,8 @@ namespace OpenSim.Data.MySQL return assetExists; } + + /// /// Returns a list of AssetMetadata objects. The list is a subset of /// the entire data set offset by containing @@ -439,7 +456,7 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon); + MySqlCommand cmd = new MySqlCommand("SELECT name,description,access_time,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon); cmd.Parameters.AddWithValue("?start", start); cmd.Parameters.AddWithValue("?count", count); @@ -461,6 +478,8 @@ namespace OpenSim.Data.MySQL // We'll ignore this for now - it appears unused! // metadata.SHA1 = dbReader["hash"]); + UpdateAccessTime(metadata, (int)dbReader["access_time"]); + retList.Add(metadata); } } -- cgit v1.1 From 35843e8ec8c58803664ab33ad52fd8e64a8765c6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 23:42:16 +0000 Subject: Change the table and field names of XAssetService mysql db tables to be capitalized like Avatars, Friends, etc. Also fixes access time being set on assets rather than XAssetsMeta This is to try and be somewhat consistent with other service tables that are mainly in this style. No migration is supplied, since nobody should be using this service yet except on a test basis. --- OpenSim/Data/MySQL/MySQLXAssetData.cs | 92 +++++++++++----------- .../Data/MySQL/Resources/XAssetStore.migrations | 30 +++---- 2 files changed, 60 insertions(+), 62 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index 273fbca..8c93825 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -138,10 +138,10 @@ namespace OpenSim.Data.MySQL dbcon.Open(); using (MySqlCommand cmd = new MySqlCommand( - "SELECT name, description, access_time, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id", + "SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID", dbcon)) { - cmd.Parameters.AddWithValue("?id", assetID.ToString()); + cmd.Parameters.AddWithValue("?ID", assetID.ToString()); try { @@ -149,18 +149,18 @@ namespace OpenSim.Data.MySQL { if (dbReader.Read()) { - asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString()); - asset.Data = (byte[])dbReader["data"]; - asset.Description = (string)dbReader["description"]; + asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString()); + asset.Data = (byte[])dbReader["Data"]; + asset.Description = (string)dbReader["Description"]; - string local = dbReader["local"].ToString(); + string local = dbReader["Local"].ToString(); if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase)) asset.Local = true; else asset.Local = false; - asset.Temporary = Convert.ToBoolean(dbReader["temporary"]); - asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]); + asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); if (m_enableCompression) { @@ -177,13 +177,13 @@ namespace OpenSim.Data.MySQL } } - UpdateAccessTime(asset.Metadata, (int)dbReader["access_time"]); + UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]); } } } catch (Exception e) { - m_log.Error("[MYSQL XASSET DATA]: Failure fetching asset " + assetID + ": " + e.Message); + m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e); } } } @@ -249,23 +249,23 @@ namespace OpenSim.Data.MySQL { using (MySqlCommand cmd = new MySqlCommand( - "replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" + - "VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)", + "replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" + + "VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)", dbcon)) { // create unix epoch time int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?hash", hash); - cmd.Parameters.AddWithValue("?name", assetName); - cmd.Parameters.AddWithValue("?description", assetDescription); - cmd.Parameters.AddWithValue("?asset_type", asset.Type); - cmd.Parameters.AddWithValue("?local", asset.Local); - cmd.Parameters.AddWithValue("?temporary", asset.Temporary); - cmd.Parameters.AddWithValue("?create_time", now); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID); - cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); + cmd.Parameters.AddWithValue("?ID", asset.ID); + cmd.Parameters.AddWithValue("?Hash", hash); + cmd.Parameters.AddWithValue("?Name", assetName); + cmd.Parameters.AddWithValue("?Description", assetDescription); + cmd.Parameters.AddWithValue("?AssetType", asset.Type); + cmd.Parameters.AddWithValue("?Local", asset.Local); + cmd.Parameters.AddWithValue("?Temporary", asset.Temporary); + cmd.Parameters.AddWithValue("?CreateTime", now); + cmd.Parameters.AddWithValue("?AccessTime", now); + cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); + cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags); cmd.ExecuteNonQuery(); } } @@ -285,11 +285,11 @@ namespace OpenSim.Data.MySQL { using (MySqlCommand cmd = new MySqlCommand( - "INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)", + "INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)", dbcon)) { - cmd.Parameters.AddWithValue("?hash", hash); - cmd.Parameters.AddWithValue("?data", asset.Data); + cmd.Parameters.AddWithValue("?Hash", hash); + cmd.Parameters.AddWithValue("?Data", asset.Data); cmd.ExecuteNonQuery(); } } @@ -332,15 +332,15 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); MySqlCommand cmd = - new MySqlCommand("update assets set access_time=?access_time where id=?id", dbcon); + new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon); try { using (cmd) { // create unix epoch time - cmd.Parameters.AddWithValue("?id", assetMetadata.ID); - cmd.Parameters.AddWithValue("?access_time", (int)Utils.DateTimeToUnixTime(now)); + cmd.Parameters.AddWithValue("?ID", assetMetadata.ID); + cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now)); cmd.ExecuteNonQuery(); } } @@ -368,9 +368,9 @@ namespace OpenSim.Data.MySQL bool exists = false; - using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon)) + using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon)) { - cmd.Parameters.AddWithValue("?hash", hash); + cmd.Parameters.AddWithValue("?Hash", hash); try { @@ -410,9 +410,9 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon)) + using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon)) { - cmd.Parameters.AddWithValue("?id", uuid.ToString()); + cmd.Parameters.AddWithValue("?ID", uuid.ToString()); try { @@ -427,8 +427,7 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.ErrorFormat( - "[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); + m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e); } } } @@ -438,7 +437,6 @@ namespace OpenSim.Data.MySQL } - /// /// Returns a list of AssetMetadata objects. The list is a subset of /// the entire data set offset by containing @@ -456,7 +454,7 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT name,description,access_time,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon); + MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon); cmd.Parameters.AddWithValue("?start", start); cmd.Parameters.AddWithValue("?count", count); @@ -467,18 +465,18 @@ namespace OpenSim.Data.MySQL while (dbReader.Read()) { AssetMetadata metadata = new AssetMetadata(); - metadata.Name = (string)dbReader["name"]; - metadata.Description = (string)dbReader["description"]; - metadata.Type = (sbyte)dbReader["asset_type"]; - metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. - metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); - metadata.FullID = DBGuid.FromDB(dbReader["id"]); - metadata.CreatorID = dbReader["creator_id"].ToString(); + metadata.Name = (string)dbReader["Name"]; + metadata.Description = (string)dbReader["Description"]; + metadata.Type = (sbyte)dbReader["AssetType"]; + metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct. + metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]); + metadata.FullID = DBGuid.FromDB(dbReader["ID"]); + metadata.CreatorID = dbReader["CreatorID"].ToString(); // We'll ignore this for now - it appears unused! // metadata.SHA1 = dbReader["hash"]); - UpdateAccessTime(metadata, (int)dbReader["access_time"]); + UpdateAccessTime(metadata, (int)dbReader["AccessTime"]); retList.Add(metadata); } @@ -504,9 +502,9 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon)) + using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon)) { - cmd.Parameters.AddWithValue("?id", id); + cmd.Parameters.AddWithValue("?ID", id); cmd.ExecuteNonQuery(); } diff --git a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations index d3cca5e..0c49d0d 100644 --- a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations +++ b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations @@ -3,24 +3,24 @@ BEGIN; -CREATE TABLE `xassetsmeta` ( - `id` char(36) NOT NULL, - `hash` binary(32) NOT NULL, - `name` varchar(64) NOT NULL, - `description` varchar(64) NOT NULL, - `asset_type` tinyint(4) NOT NULL, - `local` tinyint(1) NOT NULL, - `temporary` tinyint(1) NOT NULL, - `create_time` int(11) NOT NULL, - `access_time` int(11) NOT NULL, - `asset_flags` int(11) NOT NULL, - `creator_id` varchar(128) NOT NULL, +CREATE TABLE `XAssetsMeta` ( + `ID` char(36) NOT NULL, + `Hash` binary(32) NOT NULL, + `Name` varchar(64) NOT NULL, + `Description` varchar(64) NOT NULL, + `AssetType` tinyint(4) NOT NULL, + `Local` tinyint(1) NOT NULL, + `Temporary` tinyint(1) NOT NULL, + `CreateTime` int(11) NOT NULL, + `AccessTime` int(11) NOT NULL, + `AssetFlags` int(11) NOT NULL, + `CreatorID` varchar(128) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; -CREATE TABLE `xassetsdata` ( - `hash` binary(32) NOT NULL, - `data` longblob NOT NULL, +CREATE TABLE `XAssetsData` ( + `Hash` binary(32) NOT NULL, + `Data` longblob NOT NULL, PRIMARY KEY (`hash`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1'; -- cgit v1.1 From 7e5d5537815d5626387d8638da769192ab3c7ca8 Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 15 Mar 2013 23:46:49 +0000 Subject: Make the LSL memory functions virtual so script engines can override them if they have different memory management. --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 8adf4d9..f07b645 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6068,7 +6068,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.ParentGroup.AttachmentPoint; } - public LSL_Integer llGetFreeMemory() + public virtual LSL_Integer llGetFreeMemory() { m_host.AddScriptLPS(1); // Make scripts designed for LSO happy @@ -11560,7 +11560,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 16384; } - public LSL_Integer llGetUsedMemory() + public virtual LSL_Integer llGetUsedMemory() { m_host.AddScriptLPS(1); // The value returned for LSO scripts in SL @@ -11790,4 +11790,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } -} \ No newline at end of file +} -- cgit v1.1 From 03075359b5f1a4470ed5fa54afd76f08bf57a437 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 15 Mar 2013 23:48:40 +0000 Subject: Finally remove the 'REST' ApplicationPlugins code which has been non-functional and largely commented out for many years. --- OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs | 43 - .../Rest/Inventory/IRestHandler.cs | 59 - .../Rest/Inventory/RequestData.cs | 1465 ------------ .../Rest/Inventory/Resources/RestHandler.addin.xml | 11 - OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs | 551 ----- .../Rest/Inventory/RestAppearanceServices.cs | 860 ------- .../Rest/Inventory/RestAssetServices.cs | 383 ---- .../Rest/Inventory/RestFileServices.cs | 448 ---- .../Rest/Inventory/RestHandler.cs | 662 ------ .../Rest/Inventory/RestInventoryServices.cs | 2343 -------------------- .../Rest/Inventory/RestTestServices.cs | 246 -- .../Rest/Inventory/tests/ITest.cs | 46 - .../Rest/Inventory/tests/Remote.cs | 204 -- .../ApplicationPlugins/Rest/Regions/GETHandler.cs | 228 -- .../Rest/Regions/GETRegionInfoHandler.cs | 136 -- .../ApplicationPlugins/Rest/Regions/POSTHandler.cs | 122 - .../Rest/Regions/RegionDetails.cs | 98 - .../Regions/Resources/RestRegionPlugin.addin.xml | 11 - .../Rest/Regions/RestRegionPlugin.cs | 94 - OpenSim/ApplicationPlugins/Rest/RestPlugin.cs | 417 ---- OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs | 72 - OpenSim/ApplicationPlugins/Rest/rest.xsd | 276 --- 22 files changed, 8775 deletions(-) delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml delete mode 100644 OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/RestPlugin.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs delete mode 100644 OpenSim/ApplicationPlugins/Rest/rest.xsd (limited to 'OpenSim') diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs deleted file mode 100644 index 8b43d42..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - /// - /// This interface represents the boundary between the general purpose - /// REST plugin handling, and the functionally specific handlers. The - /// handler knows only to initialize and terminate all such handlers - /// that it finds. Implementing this interface identifies the class as - /// a REST handler implementation. - /// - - internal interface IRest - { - void Initialize(); - void Close(); - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs deleted file mode 100644 index a88fe88..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// The handler delegates are not noteworthy. The allocator allows - /// a given handler to optionally subclass the base RequestData - /// structure to carry any locally required per-request state - /// needed. - /// - - public delegate void RestMethodHandler(RequestData rdata); - public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path); - - /// - /// This interface exports the generic plugin-handling services - /// available to each loaded REST services module (IRest implementation) - /// - - internal interface IRestHandler - { - - string MsgId { get; } - string RequestId { get; } - - void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma); - void AddStreamHandler(string httpMethod, string path, RestMethod method); - - } - -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs deleted file mode 100644 index 10f1a6e..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs +++ /dev/null @@ -1,1465 +0,0 @@ -/* - * 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.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; - -using OpenMetaverse; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// This class represents the current REST request. It - /// encapsulates the request/response state and takes care - /// of response generation without exposing the REST handler - /// to the actual mechanisms involved. - /// - /// This structure is created on entry to the Handler - /// method and is disposed of upon return. It is part of - /// the plug-in infrastructure, rather than the functionally - /// specific REST handler, and fundamental changes to - /// this should be reflected in the Rest HandlerVersion. The - /// object is instantiated, and may be extended by, any - /// given handler. See the inventory handler for an example - /// of this. - /// - /// If possible, the underlying request/response state is not - /// changed until the handler explicitly issues a Respond call. - /// This ensures that the request/response pair can be safely - /// processed by subsequent, unrelated, handlers even id the - /// agent handler had completed much of its processing. Think - /// of it as a transactional req/resp capability. - /// - - public class RequestData - { - - // HTTP Server interface data (Received values) - - internal OSHttpRequest request = null; - internal OSHttpResponse response = null; - internal string qprefix = null; - - // Request lifetime values - // buffer is global because it is referenced by the handler - // in supported of streamed requests. - // If a service provider wants to construct the message - // body explicitly it can use body to do this. The value - // in body is used if the buffer is still null when a response - // is generated. - // Storing information in body will suppress the return of - // statusBody which is only intended to report status on - // requests which do not themselves ordinarily generate - // an informational response. All of this is handled in - // Respond(). - - internal byte[] buffer = null; - internal string body = null; - internal string bodyType = "text/html"; - - // The encoding in effect is set to a server default. It may - // subsequently be overridden by a Content header. This - // value is established during construction and is used - // wherever encoding services are needed. - - internal Encoding encoding = Rest.Encoding; - - // These values are derived from the supplied URL. They - // are initialized during construction. - - internal string path = null; - internal string method = null; - internal Uri uri = null; - internal string query = null; - internal string hostname = "localhost"; - internal int port = 80; - - // The path part of the URI is decomposed. pathNodes - // is an array of every element in the URI. Parameters - // is an array that contains only those nodes that - // are not a part of the authority prefix - - private string[] pathNodes = null; - private string[] parameters = null; - private static readonly string[] EmptyPath = { String.Empty }; - - // The status code gets set during the course of processing - // and is the HTTP completion code. The status body is - // initialized during construction, is appended to during the - // course of execution, and is finalized during Respond - // processing. - // - // Fail processing marks the request as failed and this is - // then used to inhibit processing during Response processing. - - internal int statusCode = 0; - internal string statusBody = String.Empty; - internal bool fail = false; - - // This carries the URL to which the client should be redirected. - // It is set by the service provider using the Redirect call. - - internal string redirectLocation = null; - - // These values influence response processing. They can be set by - // service providers according to need. The defaults are generally - // good. - - internal bool keepAlive = false; - internal bool chunked = false; - - // XML related state - - internal XmlWriter writer = null; - internal XmlReader reader = null; - - // Internal working state - - private StringBuilder sbuilder = new StringBuilder(1024); - private MemoryStream xmldata = null; - - // This is used to make the response mechanism idempotent. - - internal bool handled = false; - - // Authentication related state - // - // Two supported authentication mechanisms are: - // scheme = Rest.AS_BASIC; - // scheme = Rest.AS_DIGEST; - // Presented in that order (as required by spec) - // A service provider can set the scheme variable to - // force selection of a particular authentication model - // (choosing from amongst those supported of course) - // - - internal bool authenticated = false; - internal string scheme = Rest.Scheme; - internal string realm = Rest.Realm; - internal string domain = null; - internal string nonce = null; - internal string cnonce = null; - internal string qop = Rest.Qop_Auth; - internal string opaque = null; - internal string stale = null; - internal string algorithm = Rest.Digest_MD5; - internal string authParms = null; - internal string authPrefix = null; - internal string userName = String.Empty; - internal string userPass = String.Empty; - - // Session related tables. These are only needed if QOP is set to "auth-sess" - // and for now at least, it is not. Session related authentication is of - // questionable merit in the context of REST anyway, but it is, arguably, more - // secure. - - private static Dictionary cntable = new Dictionary(); - private static Dictionary sktable = new Dictionary(); - - // This dictionary is used to keep track fo all of the parameters discovered - // when the authorisation header is anaylsed. - - private Dictionary authparms = new Dictionary(); - - // These regular expressions are used to decipher the various header entries. - - private static Regex schema = new Regex("^\\s*(?\\w+)\\s*.*", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex basicParms = new Regex("^\\s*(?:\\w+)\\s+(?\\S+)\\s*", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex digestParm1 = new Regex("\\s*(?\\w+)\\s*=\\s*\"(?[^\"]+)\"", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex digestParm2 = new Regex("\\s*(?\\w+)\\s*=\\s*(?[^\\p{P}\\s]+)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static Regex reuserPass = new Regex("(?[^:]+):(?[\\S\\s]*)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - // For efficiency, we create static instances of these objects - - private static MD5 md5hash = MD5.Create(); - - private static StringComparer sc = StringComparer.OrdinalIgnoreCase; - -#region properties - - // Just for convenience... - - internal string MsgId - { - get { return Rest.MsgId; } - } - - /// - /// Return a boolean indication of whether or no an authenticated user is - /// associated with this request. This could be wholly integrated, but - /// that would make authentication mandatory. - /// - - internal bool IsAuthenticated - { - get - { - if (Rest.Authenticate) - { - if (!authenticated) - { - authenticate(); - } - - return authenticated; - } - else return true; - } - } - - /// - /// Access to all 'nodes' in the supplied URI as an - /// array of strings. - /// - - internal string[] PathNodes - { - get - { - return pathNodes; - } - } - - /// - /// Access to all non-prefix 'nodes' in the supplied URI as an - /// array of strings. These identify a specific resource that - /// is managed by the authority (the prefix). - /// - - internal string[] Parameters - { - get - { - return parameters; - } - } - -#endregion properties - -#region constructors - - // Constructor - - internal RequestData(OSHttpRequest p_request, OSHttpResponse p_response, string p_qprefix) - { - - request = p_request; - response = p_response; - qprefix = p_qprefix; - - sbuilder.Length = 0; - - encoding = request.ContentEncoding; - - if (encoding == null) - { - encoding = Rest.Encoding; - } - - method = request.HttpMethod.ToLower(); - initUrl(); - - initParameters(p_qprefix.Length); - - } - -#endregion constructors - -#region authentication_common - - /// - /// The REST handler has requested authentication. Authentication - /// is considered to be with respect to the current values for - /// Realm, domain, etc. - /// - /// This method checks to see if the current request is already - /// authenticated for this domain. If it is, then it returns - /// true. If it is not, then it issues a challenge to the client - /// and responds negatively to the request. - /// - /// As soon as authentication failure is detected the method calls - /// DoChallenge() which terminates the request with REST exception - /// for unauthroized access. - /// - - private void authenticate() - { - - string authdata = request.Headers.Get("Authorization"); - string reqscheme = String.Empty; - - // If we don't have an authorization header, then this - // user is certainly not authorized. This is the typical - // pivot for the 1st request by a client. - - if (authdata == null) - { - Rest.Log.DebugFormat("{0} Challenge reason: No authorization data", MsgId); - DoChallenge(); - } - - // So, we have authentication data, now we have to check to - // see what we got and whether or not it is valid for the - // current domain. To do this we need to interpret the data - // provided in the Authorization header. First we need to - // identify the scheme being used and route accordingly. - - MatchCollection matches = schema.Matches(authdata); - - foreach (Match m in matches) - { - Rest.Log.DebugFormat("{0} Scheme matched : {1}", MsgId, m.Groups["scheme"].Value); - reqscheme = m.Groups["scheme"].Value.ToLower(); - } - - // If we want a specific authentication mechanism, make sure - // we get it. null indicates we don't care. non-null indicates - // a specific scheme requirement. - - if (scheme != null && scheme.ToLower() != reqscheme) - { - Rest.Log.DebugFormat("{0} Challenge reason: Requested scheme not acceptable", MsgId); - DoChallenge(); - } - - // In the future, these could be made into plug-ins... - // But for now at least we have no reason to use anything other - // then MD5. TLS/SSL are taken care of elsewhere. - - switch (reqscheme) - { - case "digest" : - Rest.Log.DebugFormat("{0} Digest authentication offered", MsgId); - DoDigest(authdata); - break; - - case "basic" : - Rest.Log.DebugFormat("{0} Basic authentication offered", MsgId); - DoBasic(authdata); - break; - } - - // If the current header is invalid, then a challenge is still needed. - - if (!authenticated) - { - Rest.Log.DebugFormat("{0} Challenge reason: Authentication failed", MsgId); - DoChallenge(); - } - - } - - /// - /// Construct the necessary WWW-Authenticate headers and fail the request - /// with a NOT AUTHORIZED response. The parameters are the union of values - /// required by the supported schemes. - /// - - private void DoChallenge() - { - Flush(); - nonce = Rest.NonceGenerator(); // should be unique per 401 (and it is) - Challenge(scheme, realm, domain, nonce, opaque, stale, algorithm, qop, authParms); - Fail(Rest.HttpStatusCodeNotAuthorized); - } - - /// - /// The Flush() call is here to support a problem encountered with the - /// client where an authentication rejection was lost because the rejection - /// may flow before the clienthas finished sending us the inbound data stream, - /// in which case the client responds to the socket error on out put, and - /// never sees the authentication challenge. The client should be fixed, - /// because this solution leaves the server prone to DOS attacks. A message - /// will be issued whenever flushing occurs. It can be enabled/disabled from - /// the configuration file. - /// - - private void Flush() - { - if (Rest.FlushEnabled) - { - byte[] dbuffer = new byte[8192]; - Rest.Log.WarnFormat("{0} REST server is flushing the inbound data stream", MsgId); - while (request.InputStream.Read(dbuffer,0,dbuffer.Length) != 0); - } - return; - } - - // Indicate that authentication is required - - private void Challenge(string scheme, string realm, string domain, string nonce, - string opaque, string stale, string alg, - string qop, string auth) - { - - sbuilder.Length = 0; - - // The service provider can force a particular scheme by - // assigning a value to scheme. - - // Basic authentication is pretty simple. - // Just specify the realm in question. - - if (scheme == null || scheme == Rest.AS_BASIC) - { - - sbuilder.Append(Rest.AS_BASIC); - - if (realm != null) - { - sbuilder.Append(" realm="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(realm); - sbuilder.Append(Rest.CS_DQUOTE); - } - AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString()); - } - - sbuilder.Length = 0; - - // Digest authentication takes somewhat more - // to express. - - if (scheme == null || scheme == Rest.AS_DIGEST) - { - - sbuilder.Append(Rest.AS_DIGEST); - sbuilder.Append(" "); - - // Specify the effective realm. This should - // never be null if we are uthenticating, as it is required for all - // authentication schemes. It defines, in conjunction with the - // absolute URI information, the domain to which the authentication - // applies. It is an arbitrary string. I *believe* this allows an - // authentication to apply to disjoint resources within the same - // server. - - if (realm != null) - { - sbuilder.Append("realm="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(realm); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // Share our nonce. This is *uniquely* generated each time a 401 is - // returned. We do not generate a very sophisticated nonce at the - // moment (it's simply a base64 encoded UUID). - - if (nonce != null) - { - sbuilder.Append("nonce="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(nonce); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // The opaque string should be returned by the client unchanged in all - // subsequent requests. - - if (opaque != null) - { - sbuilder.Append("opaque="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(opaque); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // This flag indicates that the authentication was rejected because the - // included nonce was stale. The server might use timestamp information - // in the nonce to determine this. We do not. - - if (stale != null) - { - sbuilder.Append("stale="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(stale); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // Identifies the algorithm used to produce the digest and checksum. - // The default is MD5. - - if (alg != null) - { - sbuilder.Append("algorithm="); - sbuilder.Append(alg); - sbuilder.Append(Rest.CS_COMMA); - } - - // Theoretically QOP is optional, but it is required by a compliant - // with current versions of the scheme. In fact IE requires that QOP - // be specified and will refuse to authenticate otherwise. - - if (qop != String.Empty) - { - sbuilder.Append("qop="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(qop); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(Rest.CS_COMMA); - } - - // This parameter allows for arbitrary extensions to the protocol. - // Unrecognized values should be simply ignored. - - if (auth != null) - { - sbuilder.Append(auth); - sbuilder.Append(Rest.CS_COMMA); - } - - // We don't know the userid that will be used - // so we cannot make any authentication domain - // assumptions. So the prefix will determine - // this. - - sbuilder.Append("domain="); - sbuilder.Append(Rest.CS_DQUOTE); - sbuilder.Append(qprefix); - sbuilder.Append(Rest.CS_DQUOTE); - - // Generate the authenticate header and we're basically - // done. - - AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString()); - - } - - } - -#endregion authentication_common - -#region authentication_basic - - /// - /// Interpret a BASIC authorization claim. Some clients can only - /// understand this and also expect it to be the first one - /// offered. So we do. - /// OpenSim also needs this, as it is the only scheme that allows - /// authentication using the hashed passwords stored in the - /// user database. - /// - - private void DoBasic(string authdata) - { - - string response = null; - - MatchCollection matches = basicParms.Matches(authdata); - - // In the case of basic authentication there is - // only expected to be a single argument. - - foreach (Match m in matches) - { - authparms.Add("response",m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} Parameter matched : {1} = {2}", - MsgId, "response", m.Groups["pval"].Value); - } - - // Did we get a valid response? - - if (authparms.TryGetValue("response", out response)) - { - // Decode - response = Rest.Base64ToString(response); - Rest.Log.DebugFormat("{0} Auth response is: <{1}>", MsgId, response); - - // Extract user & password - Match m = reuserPass.Match(response); - userName = m.Groups["user"].Value; - userPass = m.Groups["pass"].Value; - - // Validate against user database - authenticated = Validate(userName,userPass); - } - - } - - /// - /// This method provides validation in support of the BASIC - /// authentication method. This is not normaly expected to be - /// used, but is included for completeness (and because I tried - /// it first). - /// - - private bool Validate(string user, string pass) - { - - Rest.Log.DebugFormat("{0} Simple User Validation", MsgId); - - // Both values are required - - if (user == null || pass == null) - return false; - - // Eliminate any leading or trailing spaces - user = user.Trim(); - - return vetPassword(user, pass); - - } - - /// - /// This is used by the BASIC authentication scheme to calculate - /// the double hash used by OpenSim to encode user's passwords. - /// It returns true, if the supplied password is actually correct. - /// If the specified user-id is not recognized, but the password - /// matches the God password, then this is accepted as an admin - /// session. - /// - - private bool vetPassword(string user, string pass) - { - - int x; - string first; - string last; - - // Distinguish the parts, if necessary - - if ((x=user.IndexOf(Rest.C_SPACE)) != -1) - { - first = user.Substring(0,x); - last = user.Substring(x+1); - } - else - { - first = user; - last = String.Empty; - } - - UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last); - - // If we don't recognize the user id, perhaps it is god? - if (account == null) - return pass == Rest.GodKey; - - return (Rest.AuthServices.Authenticate(account.PrincipalID, pass, 1) != string.Empty); - - } - -#endregion authentication_basic - -#region authentication_digest - - /// - /// This is an RFC2617 compliant HTTP MD5 Digest authentication - /// implementation. It has been tested with Firefox, Java HTTP client, - /// and Microsoft's Internet Explorer V7. - /// - - private void DoDigest(string authdata) - { - - string response = null; - - // Find all of the values of the for x = "y" - - MatchCollection matches = digestParm1.Matches(authdata); - - foreach (Match m in matches) - { - authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} String Parameter matched : {1} = {2}", - MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value); - } - - // Find all of the values of the for x = y - - matches = digestParm2.Matches(authdata); - - foreach (Match m in matches) - { - authparms.Add(m.Groups["parm"].Value,m.Groups["pval"].Value); - Rest.Log.DebugFormat("{0} Tokenized Parameter matched : {1} = {2}", - MsgId, m.Groups["parm"].Value,m.Groups["pval"].Value); - } - - // A response string MUST be returned, otherwise we are - // NOT authenticated. - - Rest.Log.DebugFormat("{0} Validating authorization parameters", MsgId); - - if (authparms.TryGetValue("response", out response)) - { - - string temp = null; - - do - { - - string nck = null; - string ncl = null; - - // The userid is sent in clear text. Needed for the - // verification. - - authparms.TryGetValue("username", out userName); - - // All URI's of which this is a prefix are - // optimistically considered to be authenticated by the - // client. This is also needed to verify the response. - - authparms.TryGetValue("uri", out authPrefix); - - // There MUST be a nonce string present. We're not preserving any server - // side state and we can't validate the MD5 unless the client returns it - // to us, as it should. - - if (!authparms.TryGetValue("nonce", out nonce) || nonce == null) - { - Rest.Log.WarnFormat("{0} Authentication failed: nonce missing", MsgId); - break; - } - - // If there is an opaque string present, it had better - // match what we sent. - - if (authparms.TryGetValue("opaque", out temp)) - { - if (temp != opaque) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad opaque value", MsgId); - break; - } - } - - // If an algorithm string is present, it had better - // match what we sent. - - if (authparms.TryGetValue("algorithm", out temp)) - { - if (temp != algorithm) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad algorithm value", MsgId); - break; - } - } - - // Quality of protection considerations... - - if (authparms.TryGetValue("qop", out temp)) - { - - qop = temp.ToLower(); // replace with actual value used - - // if QOP was specified then - // these MUST be present. - - if (!authparms.ContainsKey("cnonce")) - { - Rest.Log.WarnFormat("{0} Authentication failed: cnonce missing", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - - cnonce = authparms["cnonce"]; - - if (!authparms.TryGetValue("nc", out nck) || nck == null) - { - Rest.Log.WarnFormat("{0} Authentication failed: cnonce counter missing", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - - Rest.Log.DebugFormat("{0} Comparing nonce indices", MsgId); - - if (cntable.TryGetValue(nonce, out ncl)) - { - Rest.Log.DebugFormat("{0} nonce values: Verify that request({1}) > Reference({2})", MsgId, nck, ncl); - - if (Rest.Hex2Int(ncl) >= Rest.Hex2Int(nck)) - { - Rest.Log.WarnFormat("{0} Authentication failed: bad cnonce counter", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - cntable[nonce] = nck; - } - else - { - lock (cntable) cntable.Add(nonce, nck); - } - - } - else - { - - qop = String.Empty; - - // if QOP was not specified then - // these MUST NOT be present. - if (authparms.ContainsKey("cnonce")) - { - Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - if (authparms.ContainsKey("nc")) - { - Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce counter[2]", MsgId); - Fail(Rest.HttpStatusCodeBadRequest); - break; - } - } - - // Validate the supplied userid/password info - - authenticated = ValidateDigest(userName, nonce, cnonce, nck, authPrefix, response); - - } - while (false); - - } - else - Fail(Rest.HttpStatusCodeBadRequest); - - } - - /// - /// This mechanism is used by the digest authentication mechanism - /// to return the user's password. In fact, because the OpenSim - /// user's passwords are already hashed, and the HTTP mechanism - /// does not supply an open password, the hashed passwords cannot - /// be used unless the client has used the same salting mechanism - /// to has the password before using it in the authentication - /// algorithn. This is not inconceivable... - /// - - private string getPassword(string user) - { - - int x; - string first; - string last; - - // Distinguish the parts, if necessary - - if ((x=user.IndexOf(Rest.C_SPACE)) != -1) - { - first = user.Substring(0,x); - last = user.Substring(x+1); - } - else - { - first = user; - last = String.Empty; - } - - UserAccount account = Rest.UserServices.GetUserAccount(UUID.Zero, first, last); - // If we don;t recognize the user id, perhaps it is god? - - if (account == null) - { - Rest.Log.DebugFormat("{0} Administrator", MsgId); - return Rest.GodKey; - } - else - { - Rest.Log.DebugFormat("{0} Normal User {1}", MsgId, user); - - // !!! REFACTORING PROBLEM - // This is what it was. It doesn't work in 0.7 - // Nothing retrieves the password from the authentication service, there's only authentication. - //return udata.PasswordHash; - return string.Empty; - } - - } - - // Validate the request-digest - - private bool ValidateDigest(string user, string nonce, string cnonce, string nck, string uri, string response) - { - - string patt = null; - string payl = String.Empty; - string KDS = null; - string HA1 = null; - string HA2 = null; - string pass = getPassword(user); - - // Generate H(A1) - - if (algorithm == Rest.Digest_MD5Sess) - { - if (!sktable.ContainsKey(cnonce)) - { - patt = String.Format("{0}:{1}:{2}:{3}:{4}", user, realm, pass, nonce, cnonce); - HA1 = HashToString(patt); - sktable.Add(cnonce, HA1); - } - else - { - HA1 = sktable[cnonce]; - } - } - else - { - patt = String.Format("{0}:{1}:{2}", user, realm, pass); - HA1 = HashToString(patt); - } - - // Generate H(A2) - - if (qop == "auth-int") - { - patt = String.Format("{0}:{1}:{2}", request.HttpMethod, uri, HashToString(payl)); - } - else - { - patt = String.Format("{0}:{1}", request.HttpMethod, uri); - } - - HA2 = HashToString(patt); - - // Generate Digest - - if (qop != String.Empty) - { - patt = String.Format("{0}:{1}:{2}:{3}:{4}:{5}", HA1, nonce, nck, cnonce, qop, HA2); - } - else - { - patt = String.Format("{0}:{1}:{2}", HA1, nonce, HA2); - } - - KDS = HashToString(patt); - - // Compare the generated sequence with the original - - return (0 == sc.Compare(KDS, response)); - - } - - private string HashToString(string pattern) - { - - Rest.Log.DebugFormat("{0} Generate <{1}>", MsgId, pattern); - - byte[] hash = md5hash.ComputeHash(encoding.GetBytes(pattern)); - - sbuilder.Length = 0; - - for (int i = 0; i < hash.Length; i++) - { - sbuilder.Append(hash[i].ToString("x2")); - } - - Rest.Log.DebugFormat("{0} Hash = <{1}>", MsgId, sbuilder.ToString()); - - return sbuilder.ToString(); - - } - -#endregion authentication_digest - -#region service_interface - - /// - /// Conditionally set a normal completion code. This allows a normal - /// execution path to default. - /// - - internal void Complete() - { - if (statusCode == 0) - { - statusCode = Rest.HttpStatusCodeOK; - } - } - - /// - /// Indicate a functionally-dependent conclusion to the - /// request. See Rest.cs for a list of possible values. - /// - - internal void Complete(int code) - { - statusCode = code; - } - - /// - /// Indicate that a request should be redirected, using - /// the HTTP completion codes. Permanent and temporary - /// redirections may be indicated. The supplied URL is - /// the new location of the resource. - /// - - internal void Redirect(string Url, bool temp) - { - - redirectLocation = Url; - - if (temp) - { - statusCode = Rest.HttpStatusCodeTemporaryRedirect; - } - else - { - statusCode = Rest.HttpStatusCodePermanentRedirect; - } - - Fail(statusCode, String.Empty, true); - - } - - /// - /// Fail for an arbitrary reason. Just a failure with - /// headers. The supplied message will be returned in the - /// message body. - /// - - internal void Fail(int code) - { - Fail(code, String.Empty, false); - } - - /// - /// For the more adventurous. This failure also includes a - /// specified entity to be appended to the code-related - /// status string. - /// - - internal void Fail(int code, string addendum) - { - Fail(code, addendum, false); - } - - internal void Fail(int code, string addendum, bool reset) - { - - statusCode = code; - appendStatus(String.Format("({0}) : {1}", code, Rest.HttpStatusDesc[code])); - - // Add any final addendum to the status information - - if (addendum != String.Empty) - { - appendStatus(String.Format(addendum)); - } - - // Help us understand why the request is being rejected - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Request Failure State Dump", MsgId); - Rest.Log.DebugFormat("{0} Scheme = {1}", MsgId, scheme); - Rest.Log.DebugFormat("{0} Realm = {1}", MsgId, realm); - Rest.Log.DebugFormat("{0} Domain = {1}", MsgId, domain); - Rest.Log.DebugFormat("{0} Nonce = {1}", MsgId, nonce); - Rest.Log.DebugFormat("{0} CNonce = {1}", MsgId, cnonce); - Rest.Log.DebugFormat("{0} Opaque = {1}", MsgId, opaque); - Rest.Log.DebugFormat("{0} Stale = {1}", MsgId, stale); - Rest.Log.DebugFormat("{0} Algorithm = {1}", MsgId, algorithm); - Rest.Log.DebugFormat("{0} QOP = {1}", MsgId, qop); - Rest.Log.DebugFormat("{0} AuthPrefix = {1}", MsgId, authPrefix); - Rest.Log.DebugFormat("{0} UserName = {1}", MsgId, userName); - Rest.Log.DebugFormat("{0} UserPass = {1}", MsgId, userPass); - } - - fail = true; - - // Respond to the client's request, tag the response (for the - // benefit of trace) to indicate the reason. - - Respond(String.Format("Failure response: ({0}) : {1} ", - code, Rest.HttpStatusDesc[code])); - - // Finally initialize and the throw a RestException. All of the - // handler's infrastructure knows that this is a "normal" - // completion from a code point-of-view. - - RestException re = new RestException(Rest.HttpStatusDesc[code]+" <"+code+">"); - - re.statusCode = code; - re.statusDesc = Rest.HttpStatusDesc[code]; - re.httpmethod = method; - re.httppath = path; - - throw re; - - } - - // Reject this request - - internal void Reject() - { - Fail(Rest.HttpStatusCodeNotImplemented, "request rejected (not implemented)"); - } - - // This MUST be called by an agent handler before it returns - // control to Handle, otherwise the request will be ignored. - // This is called implciitly for the REST stream handlers and - // is harmless if it is called twice. - - internal virtual bool Respond(string reason) - { - - - Rest.Log.DebugFormat("{0} Respond ENTRY, handled = {1}, reason = {2}", MsgId, handled, reason); - - // We do this to try and make multiple Respond requests harmless, - // as it is sometimes convenient to isse a response without - // certain knowledge that it has not previously been done. - - if (!handled) - { - - Rest.Log.DebugFormat("{0} Generating Response", MsgId); - Rest.Log.DebugFormat("{0} Method is {1}", MsgId, method); - - // A Head request can NOT have a body! So don't waste time on - // formatting if we're going to reject it anyway! - - if (method != Rest.HEAD) - { - - Rest.Log.DebugFormat("{0} Response is not abbreviated", MsgId); - - // If the writer is non-null then we know that an XML - // data component exists. Flush and close the writer and - // then convert the result to the expected buffer format - // unless the request has already been failed for some - // reason. - - if (writer != null) - { - Rest.Log.DebugFormat("{0} XML Response handler extension ENTRY", MsgId); - Rest.Log.DebugFormat("{0} XML Response exists", MsgId); - writer.Flush(); - writer.Close(); - if (!fail) - { - buffer = xmldata.ToArray(); - AddHeader("Content-Type","application/xml"); - } - xmldata.Close(); - Rest.Log.DebugFormat("{0} XML Response encoded", MsgId); - Rest.Log.DebugFormat("{0} XML Response handler extension EXIT", MsgId); - } - - if (buffer == null && body != null) - { - buffer = encoding.GetBytes(body); - AddHeader("Content-Type",bodyType); - } - - // OK, if the buffer contains something, regardless of how - // it got there, set various response headers accordingly. - - if (buffer != null) - { - Rest.Log.DebugFormat("{0} Buffer-based entity", MsgId); - } - else - { - if (statusBody != String.Empty) - { - statusBody += Rest.statusTail; - buffer = encoding.GetBytes(statusBody); - AddHeader("Content-Type","text/html"); - } - else - { - statusBody = Rest.statusHead; - appendStatus(String.Format(": ({0}) {1}", - statusCode, Rest.HttpStatusDesc[statusCode])); - statusBody += Rest.statusTail; - buffer = encoding.GetBytes(statusBody); - AddHeader("Content-Type","text/html"); - } - } - - response.ContentLength64 = buffer.Length; - - if (response.ContentEncoding == null) - response.ContentEncoding = encoding; - - response.SendChunked = chunked; - response.KeepAlive = keepAlive; - - } - - // Set the status code & description. If nothing has been stored, - // we consider that a success. - - if (statusCode == 0) - { - Complete(); - } - - // Set the response code in the actual carrier - - response.StatusCode = statusCode; - - // For a redirect we need to set the relocation header accordingly - - if (response.StatusCode == (int) Rest.HttpStatusCodeTemporaryRedirect || - response.StatusCode == (int) Rest.HttpStatusCodePermanentRedirect) - { - Rest.Log.DebugFormat("{0} Re-direct location is {1}", MsgId, redirectLocation); - response.RedirectLocation = redirectLocation; - } - - // And include the status description if provided. - - response.StatusDescription = Rest.HttpStatusDesc[response.StatusCode]; - - // Finally we send back our response. - - // We've left the setting of handled' until the - // last minute because the header settings included - // above are pretty harmless. But everything from - // here on down probably leaves the response - // element unusable by anyone else. - - handled = true; - - // DumpHeaders(); - - // if (request.InputStream != null) - // { - // Rest.Log.DebugFormat("{0} Closing input stream", MsgId); - // request.InputStream.Close(); - // } - - if (buffer != null && buffer.Length != 0) - { - Rest.Log.DebugFormat("{0} Entity buffer, length = {1}", MsgId, buffer.Length); - // Rest.Log.DebugFormat("{0} Entity buffer, length = {1} : <{2}>", - // MsgId, buffer.Length, encoding.GetString(buffer)); - response.OutputStream.Write(buffer, 0, buffer.Length); - } - - // Closing the outputstream should complete the transmission process - - Rest.Log.DebugFormat("{0} Sending response", MsgId); - // response.OutputStream.Close(); - response.Send(); - - } - - Rest.Log.DebugFormat("{0} Respond EXIT, handled = {1}, reason = {2}", MsgId, handled, reason); - - return handled; - - } - - /// - /// These methods allow a service provider to manipulate the - /// request/response headers. The DumpHeaders method is intended - /// for problem diagnosis. - /// - - internal void AddHeader(string hdr, string data) - { - if (Rest.DEBUG) Rest.Log.DebugFormat("{0} Adding header: <{1}: {2}>", MsgId, hdr, data); - response.AddHeader(hdr, data); - } - - // internal void RemoveHeader(string hdr) - // { - // if (Rest.DEBUG) - // { - // Rest.Log.DebugFormat("{0} Removing header: <{1}>", MsgId, hdr); - // if (response.Headers.Get(hdr) == null) - // { - // Rest.Log.DebugFormat("{0} No such header existed", - // MsgId, hdr); - // } - // } - // response.Headers.Remove(hdr); - // } - - // internal void DumpHeaders() - // { - // if (Rest.DEBUG) - // { - // for (int i=0;i - /// Helper methods for deconstructing and reconstructing - /// URI path data. - /// - - private void initUrl() - { - - uri = request.Url; - - if (query == null) - { - query = uri.Query; - } - - // If the path has not been previously initialized, - // do so now. - - if (path == null) - { - path = uri.AbsolutePath; - if (path.EndsWith(Rest.UrlPathSeparator)) - path = path.Substring(0,path.Length-1); - } - - // If we succeeded in getting a path, perform any - // additional pre-processing required. - - if (path != null) - { - if (Rest.ExtendedEscape) - { - // Handle "+". Not a standard substitution, but - // common enough... - path = path.Replace(Rest.C_PLUS,Rest.C_SPACE); - } - pathNodes = path.Split(Rest.CA_PATHSEP); - } - else - { - pathNodes = EmptyPath; - } - - // Elimiate any %-escaped values. This is left until here - // so that escaped "+' are not mistakenly replaced. - - path = Uri.UnescapeDataString(path); - - // Request server context info - - hostname = uri.Host; - port = uri.Port; - - } - - private int initParameters(int prfxlen) - { - - if (prfxlen < path.Length-1) - { - parameters = path.Substring(prfxlen+1).Split(Rest.CA_PATHSEP); - } - else - { - parameters = new string[0]; - } - - // Generate a debug list of the decoded parameters - - if (Rest.DEBUG && prfxlen < path.Length-1) - { - Rest.Log.DebugFormat("{0} URI: Parameters: {1}", MsgId, path.Substring(prfxlen)); - for (int i = 0; i < parameters.Length; i++) - { - Rest.Log.DebugFormat("{0} Parameter[{1}]: {2}", MsgId, i, parameters[i]); - } - } - - return parameters.Length; - - } - -#endregion internal_methods - - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml b/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml deleted file mode 100644 index 777a2dc..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/Resources/RestHandler.addin.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs deleted file mode 100644 index 9755e73..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs +++ /dev/null @@ -1,551 +0,0 @@ -/* - * 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.Generic; -using System.Reflection; -using System.Text; -using log4net; -using Nini.Config; -using OpenSim.Framework; -using OpenSim.Framework.Communications; -using OpenSim.Services.Interfaces; -using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class Rest - { - internal static readonly ILog Log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - internal static bool DEBUG = Log.IsDebugEnabled; - - /// - /// Supported authentication schemes - /// - - public const string AS_BASIC = "Basic"; // simple user/password verification - public const string AS_DIGEST = "Digest"; // password safe authentication - - /// Supported Digest algorithms - - public const string Digest_MD5 = "MD5"; // assumed default if omitted - public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST? - - public const string Qop_Auth = "auth"; // authentication only - public const string Qop_Int = "auth-int"; // TODO - - /// - /// These values have a single value for the whole - /// domain and lifetime of the plugin handler. We - /// make them static for ease of reference within - /// the assembly. These are initialized by the - /// RestHandler class during start-up. - /// - - internal static IRestHandler Plugin = null; - internal static OpenSimBase main = null; - internal static string Prefix = null; - internal static IConfig Config = null; - internal static string GodKey = null; - internal static bool Authenticate = true; - internal static bool Secure = true; - internal static bool ExtendedEscape = true; - internal static bool DumpAsset = false; - internal static bool Fill = true; - internal static bool FlushEnabled = true; - internal static string Realm = "OpenSim REST"; - internal static string Scheme = AS_BASIC; - internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 - - /// - /// These are all dependent upon the Comms manager - /// being initialized. So they have to be properties - /// because the comms manager is now a module and is - /// not guaranteed to be there when the rest handler - /// initializes. - /// - - internal static IInventoryService InventoryServices - { - get { return main.SceneManager.CurrentOrFirstScene.InventoryService; } - } - - internal static IUserAccountService UserServices - { - get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; } - } - - internal static IAuthenticationService AuthServices - { - get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; } - } - - internal static IAvatarService AvatarServices - { - get { return main.SceneManager.CurrentOrFirstScene.AvatarService; } - } - - internal static IAssetService AssetServices - { - get { return main.SceneManager.CurrentOrFirstScene.AssetService; } - } - - /// - /// HTTP requires that status information be generated for PUT - /// and POST opertaions. This is in support of that. The - /// operation verb gets substituted into the first string, - /// and the completion code is inserted into the tail. The - /// strings are put here to encourage consistency. - /// - - internal static string statusHead = "{0} status"; - internal static string statusTail = ""; - - internal static Dictionary HttpStatusDesc; - - static Rest() - { - HttpStatusDesc = new Dictionary(); - if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length) - { - Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match"); - throw new Exception("HTTP Status array discrepancy"); - } - - // Repackage the data into something more tractable. The sparse - // nature of HTTP return codes makes an array a bad choice. - - for (int i=0; i - /// Version control for REST implementation. This - /// refers to the overall infrastructure represented - /// by the following classes - /// RequestData - /// RequestInventoryPlugin - /// Rest - /// It does no describe implementation classes such as - /// RestInventoryServices, which may morph much more - /// often. Such classes ARE dependent upon this however - /// and should check it in their Initialize method. - /// - - public static readonly float Version = 1.0F; - public const string Name = "REST 1.0"; - - /// - /// Currently defined HTTP methods. - /// Only GET and HEAD are required to be - /// supported by all servers. See Respond - /// to see how these are handled. - /// - - // REST AGENT 1.0 interpretations - public const string GET = "get"; // information retrieval - server state unchanged - public const string HEAD = "head"; // same as get except only the headers are returned. - public const string POST = "post"; // Replace the URI designated resource with the entity. - public const string PUT = "put"; // Add the entity to the context represented by the URI - public const string DELETE = "delete"; // Remove the URI designated resource from the server. - - public const string OPTIONS = "options"; // - public const string TRACE = "trace"; // - public const string CONNECT = "connect"; // - - // Define this in one place... - - public const string UrlPathSeparator = "/"; - public const string UrlMethodSeparator = ":"; - - // Redirection qualifications - - public const bool PERMANENT = false; - public const bool TEMPORARY = true; - - // Constant arrays used by String.Split - - public static readonly char C_SPACE = ' '; - public static readonly char C_SLASH = '/'; - public static readonly char C_PATHSEP = '/'; - public static readonly char C_COLON = ':'; - public static readonly char C_PLUS = '+'; - public static readonly char C_PERIOD = '.'; - public static readonly char C_COMMA = ','; - public static readonly char C_DQUOTE = '"'; - - public static readonly string CS_SPACE = " "; - public static readonly string CS_SLASH = "/"; - public static readonly string CS_PATHSEP = "/"; - public static readonly string CS_COLON = ":"; - public static readonly string CS_PLUS = "+"; - public static readonly string CS_PERIOD = "."; - public static readonly string CS_COMMA = ","; - public static readonly string CS_DQUOTE = "\""; - - public static readonly char[] CA_SPACE = { C_SPACE }; - public static readonly char[] CA_SLASH = { C_SLASH }; - public static readonly char[] CA_PATHSEP = { C_PATHSEP }; - public static readonly char[] CA_COLON = { C_COLON }; - public static readonly char[] CA_PERIOD = { C_PERIOD }; - public static readonly char[] CA_PLUS = { C_PLUS }; - public static readonly char[] CA_COMMA = { C_COMMA }; - public static readonly char[] CA_DQUOTE = { C_DQUOTE }; - - // HTTP Code Values (in value order) - - public const int HttpStatusCodeContinue = 100; - public const int HttpStatusCodeSwitchingProtocols = 101; - - public const int HttpStatusCodeOK = 200; - public const int HttpStatusCodeCreated = 201; - public const int HttpStatusCodeAccepted = 202; - public const int HttpStatusCodeNonAuthoritative = 203; - public const int HttpStatusCodeNoContent = 204; - public const int HttpStatusCodeResetContent = 205; - public const int HttpStatusCodePartialContent = 206; - - public const int HttpStatusCodeMultipleChoices = 300; - public const int HttpStatusCodePermanentRedirect = 301; - public const int HttpStatusCodeFound = 302; - public const int HttpStatusCodeSeeOther = 303; - public const int HttpStatusCodeNotModified = 304; - public const int HttpStatusCodeUseProxy = 305; - public const int HttpStatusCodeReserved306 = 306; - public const int HttpStatusCodeTemporaryRedirect = 307; - - public const int HttpStatusCodeBadRequest = 400; - public const int HttpStatusCodeNotAuthorized = 401; - public const int HttpStatusCodePaymentRequired = 402; - public const int HttpStatusCodeForbidden = 403; - public const int HttpStatusCodeNotFound = 404; - public const int HttpStatusCodeMethodNotAllowed = 405; - public const int HttpStatusCodeNotAcceptable = 406; - public const int HttpStatusCodeProxyAuthenticate = 407; - public const int HttpStatusCodeTimeOut = 408; - public const int HttpStatusCodeConflict = 409; - public const int HttpStatusCodeGone = 410; - public const int HttpStatusCodeLengthRequired = 411; - public const int HttpStatusCodePreconditionFailed = 412; - public const int HttpStatusCodeEntityTooLarge = 413; - public const int HttpStatusCodeUriTooLarge = 414; - public const int HttpStatusCodeUnsupportedMedia = 415; - public const int HttpStatusCodeRangeNotSatsified = 416; - public const int HttpStatusCodeExpectationFailed = 417; - - public const int HttpStatusCodeServerError = 500; - public const int HttpStatusCodeNotImplemented = 501; - public const int HttpStatusCodeBadGateway = 502; - public const int HttpStatusCodeServiceUnavailable = 503; - public const int HttpStatusCodeGatewayTimeout = 504; - public const int HttpStatusCodeHttpVersionError = 505; - - public static readonly int[] HttpStatusCodeArray = { - HttpStatusCodeContinue, - HttpStatusCodeSwitchingProtocols, - HttpStatusCodeOK, - HttpStatusCodeCreated, - HttpStatusCodeAccepted, - HttpStatusCodeNonAuthoritative, - HttpStatusCodeNoContent, - HttpStatusCodeResetContent, - HttpStatusCodePartialContent, - HttpStatusCodeMultipleChoices, - HttpStatusCodePermanentRedirect, - HttpStatusCodeFound, - HttpStatusCodeSeeOther, - HttpStatusCodeNotModified, - HttpStatusCodeUseProxy, - HttpStatusCodeReserved306, - HttpStatusCodeTemporaryRedirect, - HttpStatusCodeBadRequest, - HttpStatusCodeNotAuthorized, - HttpStatusCodePaymentRequired, - HttpStatusCodeForbidden, - HttpStatusCodeNotFound, - HttpStatusCodeMethodNotAllowed, - HttpStatusCodeNotAcceptable, - HttpStatusCodeProxyAuthenticate, - HttpStatusCodeTimeOut, - HttpStatusCodeConflict, - HttpStatusCodeGone, - HttpStatusCodeLengthRequired, - HttpStatusCodePreconditionFailed, - HttpStatusCodeEntityTooLarge, - HttpStatusCodeUriTooLarge, - HttpStatusCodeUnsupportedMedia, - HttpStatusCodeRangeNotSatsified, - HttpStatusCodeExpectationFailed, - HttpStatusCodeServerError, - HttpStatusCodeNotImplemented, - HttpStatusCodeBadGateway, - HttpStatusCodeServiceUnavailable, - HttpStatusCodeGatewayTimeout, - HttpStatusCodeHttpVersionError - }; - - // HTTP Status Descriptions (in status code order) - // This array must be kept strictly consistent with respect - // to the status code array above. - - public static readonly string[] HttpStatusDescArray = { - "Continue Request", - "Switching Protocols", - "OK", - "CREATED", - "ACCEPTED", - "NON-AUTHORITATIVE INFORMATION", - "NO CONTENT", - "RESET CONTENT", - "PARTIAL CONTENT", - "MULTIPLE CHOICES", - "PERMANENT REDIRECT", - "FOUND", - "SEE OTHER", - "NOT MODIFIED", - "USE PROXY", - "RESERVED CODE 306", - "TEMPORARY REDIRECT", - "BAD REQUEST", - "NOT AUTHORIZED", - "PAYMENT REQUIRED", - "FORBIDDEN", - "NOT FOUND", - "METHOD NOT ALLOWED", - "NOT ACCEPTABLE", - "PROXY AUTHENTICATION REQUIRED", - "TIMEOUT", - "CONFLICT", - "GONE", - "LENGTH REQUIRED", - "PRECONDITION FAILED", - "ENTITY TOO LARGE", - "URI TOO LARGE", - "UNSUPPORTED MEDIA", - "RANGE NOT SATISFIED", - "EXPECTATION FAILED", - "SERVER ERROR", - "NOT IMPLEMENTED", - "BAD GATEWAY", - "SERVICE UNAVAILABLE", - "GATEWAY TIMEOUT", - "HTTP VERSION NOT SUPPORTED" - }; - - // HTTP Headers - - public const string HttpHeaderAccept = "Accept"; - public const string HttpHeaderAcceptCharset = "Accept-Charset"; - public const string HttpHeaderAcceptEncoding = "Accept-Encoding"; - public const string HttpHeaderAcceptLanguage = "Accept-Language"; - public const string HttpHeaderAcceptRanges = "Accept-Ranges"; - public const string HttpHeaderAge = "Age"; - public const string HttpHeaderAllow = "Allow"; - public const string HttpHeaderAuthorization = "Authorization"; - public const string HttpHeaderCacheControl = "Cache-Control"; - public const string HttpHeaderConnection = "Connection"; - public const string HttpHeaderContentEncoding = "Content-Encoding"; - public const string HttpHeaderContentLanguage = "Content-Language"; - public const string HttpHeaderContentLength = "Content-Length"; - public const string HttpHeaderContentLocation = "Content-Location"; - public const string HttpHeaderContentMD5 = "Content-MD5"; - public const string HttpHeaderContentRange = "Content-Range"; - public const string HttpHeaderContentType = "Content-Type"; - public const string HttpHeaderDate = "Date"; - public const string HttpHeaderETag = "ETag"; - public const string HttpHeaderExpect = "Expect"; - public const string HttpHeaderExpires = "Expires"; - public const string HttpHeaderFrom = "From"; - public const string HttpHeaderHost = "Host"; - public const string HttpHeaderIfMatch = "If-Match"; - public const string HttpHeaderIfModifiedSince = "If-Modified-Since"; - public const string HttpHeaderIfNoneMatch = "If-None-Match"; - public const string HttpHeaderIfRange = "If-Range"; - public const string HttpHeaderIfUnmodifiedSince = "If-Unmodified-Since"; - public const string HttpHeaderLastModified = "Last-Modified"; - public const string HttpHeaderLocation = "Location"; - public const string HttpHeaderMaxForwards = "Max-Forwards"; - public const string HttpHeaderPragma = "Pragma"; - public const string HttpHeaderProxyAuthenticate = "Proxy-Authenticate"; - public const string HttpHeaderProxyAuthorization = "Proxy-Authorization"; - public const string HttpHeaderRange = "Range"; - public const string HttpHeaderReferer = "Referer"; - public const string HttpHeaderRetryAfter = "Retry-After"; - public const string HttpHeaderServer = "Server"; - public const string HttpHeaderTE = "TE"; - public const string HttpHeaderTrailer = "Trailer"; - public const string HttpHeaderTransferEncoding = "Transfer-Encoding"; - public const string HttpHeaderUpgrade = "Upgrade"; - public const string HttpHeaderUserAgent = "User-Agent"; - public const string HttpHeaderVary = "Vary"; - public const string HttpHeaderVia = "Via"; - public const string HttpHeaderWarning = "Warning"; - public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate"; - - /// Utility routines - - public static string StringToBase64(string str) - { - try - { - byte[] encData_byte = new byte[str.Length]; - encData_byte = Util.UTF8.GetBytes(str); - return Convert.ToBase64String(encData_byte); - } - catch - { - return String.Empty; - } - } - - public static string Base64ToString(string str) - { - try - { - return Util.Base64ToString(str); - } - catch - { - return String.Empty; - } - } - - private const string hvals = "0123456789abcdef"; - - public static int Hex2Int(string hex) - { - int val = 0; - int sum = 0; - string tmp = null; - - if (hex != null) - { - tmp = hex.ToLower(); - for (int i = 0; i < tmp.Length; i++) - { - val = hvals.IndexOf(tmp[i]); - if (val == -1) - break; - sum *= 16; - sum += val; - } - } - - return sum; - } - - // Nonce management - - public static string NonceGenerator() - { - return StringToBase64(CreationDate + Guid.NewGuid().ToString()); - } - - // Dump the specified data stream - - public static void Dump(byte[] data) - { - char[] buffer = new char[DumpLineSize]; - int cc = 0; - - for (int i = 0; i < data.Length; i++) - { - if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8")); - - if (i % 4 == 0) Console.Write(" "); - - Console.Write("{0}",data[i].ToString("x2")); - - if (data[i] < 127 && data[i] > 31) - buffer[i % DumpLineSize] = (char) data[i]; - else - buffer[i % DumpLineSize] = '.'; - - cc++; - - if (i != 0 && (i + 1) % DumpLineSize == 0) - { - Console.Write(" |"+(new String(buffer))+"|"); - cc = 0; - } - } - - // Finish off any incomplete line - - if (cc != 0) - { - for (int i = cc ; i < DumpLineSize; i++) - { - if (i % 4 == 0) Console.Write(" "); - Console.Write(" "); - buffer[i % DumpLineSize] = ' '; - } - Console.WriteLine(" |"+(new String(buffer))+"|"); - } - else - { - Console.Write("\n"); - } - } - } - - // Local exception type - - public class RestException : Exception - { - internal int statusCode; - internal string statusDesc; - internal string httpmethod; - internal string httppath; - - public RestException(string msg) : base(msg) - { - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs deleted file mode 100644 index 3cda984..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs +++ /dev/null @@ -1,860 +0,0 @@ -/* - * 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.Generic; -using System.Xml; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - public class RestAppearanceServices : IRest - { -// private static readonly int PARM_USERID = 0; - - // private static readonly int PARM_PATH = 1; - -// private bool enabled = false; - private string qPrefix = "appearance"; - - /// - /// The constructor makes sure that the service prefix is absolute - /// and the registers the service handler and the allocator. - /// - - public RestAppearanceServices() - { - Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified for the handler's domain, - // add the standard prefix to make it absolute, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Register interface using the absolute URI. - - Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate); - - // Activate if everything went OK - -// enabled = true; - - Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId); - } - - /// - /// Post-construction, pre-enabled initialization opportunity - /// Not currently exploited. - /// - - public void Initialize() - { - } - - /// - /// Called by the plug-in to halt service processing. Local processing is - /// disabled. - /// - - public void Close() - { -// enabled = false; - Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId); - } - - /// - /// This property is declared locally because it is used a lot and - /// brevity is nice. - /// - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - /// - /// The plugin (RestHandler) calls this method to allocate the request - /// state carrier for a new request. It is destroyed when the request - /// completes. All request-instance specific state is kept here. This - /// is registered when this service provider is registered. - /// - /// Inbound HTTP request information - /// Outbound HTTP request information - /// REST service domain prefix - /// A RequestData instance suitable for this service - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new AppearanceRequestData(request, response, prefix); - } - - /// - /// This method is registered with the handler when this service provider - /// is initialized. It is called whenever the plug-in identifies this service - /// provider as the best match for a given request. - /// It handles all aspects of inventory REST processing, i.e. /admin/inventory - /// - /// A consolidated HTTP request work area - - private void DoAppearance(RequestData hdata) - { - // !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7 - - //AppearanceRequestData rdata = (AppearanceRequestData) hdata; - - //Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId); - - //// If we're disabled, do nothing. - - //if (!enabled) - //{ - // return; - //} - - //// Now that we know this is a serious attempt to - //// access inventory data, we should find out who - //// is asking, and make sure they are authorized - //// to do so. We need to validate the caller's - //// identity before revealing anything about the - //// status quo. Authenticate throws an exception - //// via Fail if no identity information is present. - //// - //// With the present HTTP server we can't use the - //// builtin authentication mechanisms because they - //// would be enforced for all in-bound requests. - //// Instead we look at the headers ourselves and - //// handle authentication directly. - - //try - //{ - // if (!rdata.IsAuthenticated) - // { - // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - // } - //} - //catch (RestException e) - //{ - // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - // { - // Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // else - // { - // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // throw (e); - //} - - //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); - - //// We can only get here if we are authorized - //// - //// The requestor may have specified an UUID or - //// a conjoined FirstName LastName string. We'll - //// try both. If we fail with the first, UUID, - //// attempt, we try the other. As an example, the - //// URI for a valid inventory request might be: - //// - //// http://:/admin/inventory/Arthur Dent - //// - //// Indicating that this is an inventory request for - //// an avatar named Arthur Dent. This is ALL that is - //// required to designate a GET for an entire - //// inventory. - //// - - //// Do we have at least a user agent name? - - //if (rdata.Parameters.Length < 1) - //{ - // Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified"); - //} - - //// The first parameter MUST be the agent identification, either an UUID - //// or a space-separated First-name Last-Name specification. We check for - //// an UUID first, if anyone names their character using a valid UUID - //// that identifies another existing avatar will cause this a problem... - - //try - //{ - // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]); - // Rest.Log.DebugFormat("{0} UUID supplied", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid); - //} - //catch - //{ - // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE); - // if (names.Length == 2) - // { - // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]); - // } - // else - // { - // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity"); - // } - //} - - //// If the user profile is null then either the server is broken, or the - //// user is not known. We always assume the latter case. - - //if (rdata.userProfile != null) - //{ - // Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - //} - //else - //{ - // Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity"); - //} - - //// If we get to here, then we have effectively validated the user's - - //switch (rdata.method) - //{ - // case Rest.HEAD : // Do the processing, set the status code, suppress entity - // DoGet(rdata); - // rdata.buffer = null; - // break; - - // case Rest.GET : // Do the processing, set the status code, return entity - // DoGet(rdata); - // break; - - // case Rest.PUT : // Update named element - // DoUpdate(rdata); - // break; - - // case Rest.POST : // Add new information to identified context. - // DoExtend(rdata); - // break; - - // case Rest.DELETE : // Delete information - // DoDelete(rdata); - // break; - - // default : - // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}", - // MsgId, rdata.method, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed, - // String.Format("{0} not supported", rdata.method)); - // break; - //} - } - - #endregion Interface - - #region method-specific processing - - /// - /// This method implements GET processing for user's appearance. - /// - /// HTTP service request work area - -// private void DoGet(AppearanceRequestData rdata) -// { -// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); -// -// if (adata == null) -// { -// rdata.Fail(Rest.HttpStatusCodeNoContent, -// String.Format("appearance data not found for user {0} {1}", -// rdata.userProfile.FirstName, rdata.userProfile.SurName)); -// } -// rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID); -// -// rdata.initXmlWriter(); -// -// FormatUserAppearance(rdata); -// -// // Indicate a successful request -// -// rdata.Complete(); -// -// // Send the response to the user. The body will be implicitly -// // constructed from the result of the XML writer. -// -// rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method)); -// } - - /// - /// POST adds NEW information to the user profile database. - /// This effectively resets the appearance before applying those - /// characteristics supplied in the request. - /// - -// private void DoExtend(AppearanceRequestData rdata) -// { -// -// bool created = false; -// bool modified = false; -// string newnode = String.Empty; -// -// Rest.Log.DebugFormat("{0} POST ENTRY", MsgId); -// -// //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); -// -// rdata.userAppearance = new AvatarAppearance(); -// -// // Although the following behavior is admitted by HTTP I am becoming -// // increasingly doubtful that it is appropriate for REST. If I attempt to -// // add a new record, and it already exists, then it seems to me that the -// // attempt should fail, rather than update the existing record. -// AvatarData adata = null; -// if (GetUserAppearance(rdata)) -// { -// modified = rdata.userAppearance != null; -// created = !modified; -// adata = new AvatarData(rdata.userAppearance); -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// } -// else -// { -// created = true; -// adata = new AvatarData(rdata.userAppearance); -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// } -// -// if (created) -// { -// newnode = String.Format("{0} {1}", rdata.userProfile.FirstName, -// rdata.userProfile.SurName); -// // Must include a location header with a URI that identifies the new resource. -// -// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}", -// rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode)); -// rdata.Complete(Rest.HttpStatusCodeCreated); -// -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// -// } - - /// - /// This updates the user's appearance. not all aspects need to be provided, - /// only those supplied will be changed. - /// - -// private void DoUpdate(AppearanceRequestData rdata) -// { -// -// // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7 -// -// //bool created = false; -// //bool modified = false; -// -// -// //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); -// -// //// If the user exists then this is considered a modification regardless -// //// of what may, or may not be, specified in the payload. -// -// //if (rdata.userAppearance != null) -// //{ -// // modified = true; -// // Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance); -// // Rest.UserServices.UpdateUserProfile(rdata.userProfile); -// //} -// -// //if (created) -// //{ -// // rdata.Complete(Rest.HttpStatusCodeCreated); -// //} -// //else -// //{ -// // if (modified) -// // { -// // rdata.Complete(Rest.HttpStatusCodeOK); -// // } -// // else -// // { -// // rdata.Complete(Rest.HttpStatusCodeNoContent); -// // } -// //} -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// -// } - - /// - /// Delete the specified user's appearance. This actually performs a reset - /// to the default avatar appearance, if the info is already there. - /// Existing ownership is preserved. All prior updates are lost and can not - /// be recovered. - /// -// private void DoDelete(AppearanceRequestData rdata) -// { -// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); -// -// if (adata != null) -// { -// AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID); -// rdata.userAppearance = new AvatarAppearance(); -// rdata.userAppearance.Owner = old.Owner; -// adata = new AvatarData(rdata.userAppearance); -// -// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); -// -// rdata.Complete(); -// } -// else -// { -// -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// -// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); -// } - -#endregion method-specific processing - - private bool GetUserAppearance(AppearanceRequestData rdata) - { - - XmlReader xml; - bool indata = false; - - rdata.initXmlReader(); - xml = rdata.reader; - - while (xml.Read()) - { - switch (xml.NodeType) - { - case XmlNodeType.Element : - switch (xml.Name) - { - case "Appearance" : - if (xml.MoveToAttribute("Height")) - { - rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value); - indata = true; - } -// if (xml.MoveToAttribute("Owner")) -// { -// rdata.userAppearance.Owner = (UUID)xml.Value; -// indata = true; -// } - if (xml.MoveToAttribute("Serial")) - { - rdata.userAppearance.Serial = Convert.ToInt32(xml.Value); - indata = true; - } - break; -/* - case "Body" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.BodyItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.BodyAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Skin" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SkinItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SkinAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Hair" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.HairItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.HairAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Eyes" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.EyesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.EyesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Shirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.ShirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.ShirtAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Pants" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.PantsItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.PantsAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Shoes" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.ShoesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.ShoesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Socks" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SocksItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SocksAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Jacket" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.JacketItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.JacketAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Gloves" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.GlovesItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.GlovesAsset = (UUID)xml.Value; - indata = true; - } - break; - case "UnderShirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.UnderShirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value; - indata = true; - } - break; - case "UnderPants" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.UnderPantsItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value; - indata = true; - } - break; - case "Skirt" : - if (xml.MoveToAttribute("Item")) - { - rdata.userAppearance.SkirtItem = (UUID)xml.Value; - indata = true; - } - if (xml.MoveToAttribute("Asset")) - { - rdata.userAppearance.SkirtAsset = (UUID)xml.Value; - indata = true; - } - break; -*/ - case "Attachment" : - { - - int ap; - UUID asset; - UUID item; - - if (xml.MoveToAttribute("AtPoint")) - { - ap = Convert.ToInt32(xml.Value); - if (xml.MoveToAttribute("Asset")) - { - asset = new UUID(xml.Value); - if (xml.MoveToAttribute("Asset")) - { - item = new UUID(xml.Value); - rdata.userAppearance.SetAttachment(ap, item, asset); - indata = true; - } - } - } - } - break; - case "Texture" : - if (xml.MoveToAttribute("Default")) - { - rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value)); - indata = true; - } - break; - case "Face" : - { - uint index; - if (xml.MoveToAttribute("Index")) - { - index = Convert.ToUInt32(xml.Value); - if (xml.MoveToAttribute("Id")) - { - rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value); - indata = true; - } - } - } - break; - case "VisualParameters" : - { - xml.ReadContentAsBase64(rdata.userAppearance.VisualParams, - 0, rdata.userAppearance.VisualParams.Length); - indata = true; - } - break; - } - break; - } - } - - return indata; - - } - - private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset) - { - if (item != UUID.Zero || asset != UUID.Zero) - { - rdata.writer.WriteStartElement(part); - if (item != UUID.Zero) - { - rdata.writer.WriteAttributeString("Item",item.ToString()); - } - - if (asset != UUID.Zero) - { - rdata.writer.WriteAttributeString("Asset",asset.ToString()); - } - rdata.writer.WriteEndElement(); - } - } - - private void FormatUserAppearance(AppearanceRequestData rdata) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId); - - if (rdata.userAppearance != null) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId); - rdata.writer.WriteStartElement("Appearance"); - - rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString()); -// if (rdata.userAppearance.Owner != UUID.Zero) -// rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString()); - rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString()); - -/* - FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset); - FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset); - FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset); - FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset); - - FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset); - FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset); - FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset); - FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset); - FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset); - - FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset); - FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset); - - FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset); - FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset); -*/ - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); - - rdata.writer.WriteStartElement("Attachments"); - List attachments = rdata.userAppearance.GetAttachments(); - foreach (AvatarAttachment attach in attachments) - { - rdata.writer.WriteStartElement("Attachment"); - rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString()); - rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString()); - rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString()); - rdata.writer.WriteEndElement(); - } - rdata.writer.WriteEndElement(); - - Primitive.TextureEntry texture = rdata.userAppearance.Texture; - - if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null)) - { - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId); - - rdata.writer.WriteStartElement("Texture"); - - if (texture.DefaultTexture != null) - { - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId); - rdata.writer.WriteAttributeString("Default", - texture.DefaultTexture.TextureID.ToString()); - } - - if (texture.FaceTextures != null) - { - - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId); - - for (int i=0; i - /// These are the inventory specific request/response state - /// extensions. - /// - - internal UUID uuid = UUID.Zero; - internal UserProfileData userProfile = null; - internal AvatarAppearance userAppearance = null; - - internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - - } - - #endregion Appearance RequestData extension - - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs deleted file mode 100644 index 4ba3d77..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs +++ /dev/null @@ -1,383 +0,0 @@ -/* - * 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.Xml; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestAssetServices : IRest - { - private bool enabled = false; - private string qPrefix = "assets"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestAssetServices() - { - Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If the handler specifies a relative path for its domain - // then we must add the standard absolute prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); - } - - // Register interface using the fully-qualified prefix - - Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate); - - // Activate if all went OK - - enabled = true; - - Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new AssetRequestData(request, response, prefix); - } - - // Asset Handler - - private void DoAsset(RequestData rparm) - { - if (!enabled) return; - - AssetRequestData rdata = (AssetRequestData) rparm; - - Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix); - - // Now that we know this is a serious attempt to - // access inventory data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 0) - { - switch (rdata.method) - { - case "get" : - DoGet(rdata); - break; - case "put" : - DoPut(rdata); - break; - case "post" : - DoPost(rdata); - break; - case "delete" : - default : - Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}", - MsgId, rdata.method); - rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); - break; - } - } - else - { - Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); - } - - Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId); - } - - #endregion Interface - - /// - /// The only parameter we recognize is a UUID.If an asset with this identification is - /// found, it's content, base-64 encoded, is returned to the client. - /// - - private void DoGet(AssetRequestData rdata) - { - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length == 1) - { - UUID uuid = new UUID(rdata.Parameters[0]); - AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); - - if (asset != null) - { - Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]); - - rdata.initXmlWriter(); - - rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty); - - rdata.writer.WriteAttributeString("id", asset.ID); - rdata.writer.WriteAttributeString("name", asset.Name); - rdata.writer.WriteAttributeString("desc", asset.Description); - rdata.writer.WriteAttributeString("type", asset.Type.ToString()); - rdata.writer.WriteAttributeString("local", asset.Local.ToString()); - rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString()); - - rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length); - - rdata.writer.WriteFullEndElement(); - - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - } - - rdata.Complete(); - rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method)); - - } - - /// - /// UPDATE existing item, if it exists. URI identifies the item in question. - /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) - /// is decoded and stored in the database, identified by the supplied UUID. - /// - private void DoPut(AssetRequestData rdata) - { - bool modified = false; - bool created = false; - - AssetBase asset = null; - - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length == 1) - { - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("Asset")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - UUID uuid = new UUID(rdata.Parameters[0]); - asset = Rest.AssetServices.Get(uuid.ToString()); - - modified = (asset != null); - created = !modified; - - asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); - asset.Description = xml.GetAttribute("desc"); - asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; - asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; - asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); - - if (asset.ID != rdata.Parameters[0]) - { - Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}", - MsgId, rdata.Parameters[0], asset.ID); - } - - Rest.AssetServices.Store(asset); - - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoPost(AssetRequestData rdata) - { - - bool modified = false; - bool created = false; - - Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length != 0) - { - Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path); - Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path); - } - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("Asset")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - UUID uuid = new UUID(xml.GetAttribute("id")); - AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); - - modified = (asset != null); - created = !modified; - - asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); - asset.Description = xml.GetAttribute("desc"); - asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; - asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; - asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); - - Rest.AssetServices.Store(asset); - - if (created) - { - rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified asset {0}, UUID {1}

", asset.Name, asset.FullID)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); - - } - - ///

- /// Asset processing has no special data area requirements. - /// - - internal class AssetRequestData : RequestData - { - internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs deleted file mode 100644 index e79d2bd..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs +++ /dev/null @@ -1,448 +0,0 @@ -/* - * 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.Xml; -using System.IO; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestFileServices : IRest - { - private bool enabled = false; - private string qPrefix = "files"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestFileServices() - { - Rest.Log.InfoFormat("{0} File services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If the handler specifies a relative path for its domain - // then we must add the standard absolute prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); - } - - // Register interface using the fully-qualified prefix - - Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate); - - // Activate if all went OK - - enabled = true; - - Rest.Log.InfoFormat("{0} File services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new FileRequestData(request, response, prefix); - } - - // Asset Handler - - private void DoFile(RequestData rparm) - { - if (!enabled) return; - - FileRequestData rdata = (FileRequestData) rparm; - - Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix); - - // Now that we know this is a serious attempt to - // access file data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, - rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 0) - { - switch (rdata.method) - { - case "get" : - DoGet(rdata); - break; - case "put" : - DoPut(rdata); - break; - case "post" : - DoPost(rdata); - break; - case "delete" : - DoDelete(rdata); - break; - default : - Rest.Log.WarnFormat("{0} File: Method not supported: {1}", - MsgId, rdata.method); - rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); - break; - } - } - else - { - Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); - } - - Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId); - - } - - #endregion Interface - - /// - /// The only parameter we recognize is a UUID.If an asset with this identification is - /// found, it's content, base-64 encoded, is returned to the client. - /// - - private void DoGet(FileRequestData rdata) - { - - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - if (File.Exists(path)) - { - Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path); - Byte[] data = File.ReadAllBytes(path); - rdata.initXmlWriter(); - rdata.writer.WriteStartElement(String.Empty,"File",String.Empty); - rdata.writer.WriteAttributeString("name", path); - rdata.writer.WriteBase64(data,0,data.Length); - rdata.writer.WriteFullEndElement(); - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path)); - } - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}", - path, e.Message)); - } - } - - rdata.Complete(); - rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method)); - - } - - /// - /// UPDATE existing item, if it exists. URI identifies the item in question. - /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) - /// is decoded and stored in the database, identified by the supplied UUID. - /// - private void DoPut(FileRequestData rdata) - { - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - bool maymod = File.Exists(path); - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("File")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); - - File.WriteAllBytes(path,data); - modified = maymod; - created = ! maymod; - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoPost(FileRequestData rdata) - { - - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - bool maymod = File.Exists(path); - - rdata.initXmlReader(); - XmlReader xml = rdata.reader; - - if (!xml.ReadToFollowing("File")) - { - Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); - } - - Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", "")); - - File.WriteAllBytes(path,data); - modified = maymod; - created = ! maymod; - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// CREATE new item, replace if it exists. URI identifies the context for the item in question. - /// No parameters are required for POST, just thepayload. - /// - - private void DoDelete(FileRequestData rdata) - { - - bool modified = false; - bool created = false; - string path = String.Empty; - - Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method); - - if (rdata.Parameters.Length > 1) - { - try - { - path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2); - - if (File.Exists(path)) - { - File.Delete(path); - } - } - catch (Exception e) - { - Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId, - e.Message); - rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}", - path, e.Message)); - } - } - else - { - Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); - } - - if (created) - { - rdata.appendStatus(String.Format("

Created file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeCreated); - } - else - { - if (modified) - { - rdata.appendStatus(String.Format("

Modified file {0}

", path)); - rdata.Complete(Rest.HttpStatusCodeOK); - } - else - { - rdata.Complete(Rest.HttpStatusCodeNoContent); - } - } - - rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); - - } - - ///

- /// File processing has no special data area requirements. - /// - - internal class FileRequestData : RequestData - { - internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs deleted file mode 100644 index 072bd6f..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs +++ /dev/null @@ -1,662 +0,0 @@ -/* - * 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.Generic; -using System.Reflection; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - /// - /// The class signature reveals the roles that RestHandler plays. - /// - /// [1] It is a sub-class of RestPlugin. It inherits and extends - /// the functionality of this class, constraining it to the - /// specific needs of this REST implementation. This relates - /// to the plug-in mechanism supported by OpenSim, the specifics - /// of which are mostly hidden by RestPlugin. - /// [2] IRestHandler describes the interface that this class - /// exports to service implementations. This is the services - /// management interface. - /// [3] IHttpAgentHandler describes the interface that is exported - /// to the BaseHttpServer in support of this particular HTTP - /// processing model. This is the request interface of the - /// handler. - /// - - public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler - { - // Handler tables: both stream and REST are supported. The path handlers and their - // respective allocators are stored in separate tables. - - internal Dictionary pathHandlers = new Dictionary(); - internal Dictionary pathAllocators = new Dictionary(); - internal Dictionary streamHandlers = new Dictionary(); - - #region local static state - - private static bool handlersLoaded = false; - private static List classes = new List(); - private static List handlers = new List(); - private static Type[] parms = new Type[0]; - private static Object[] args = new Object[0]; - - /// - /// This static initializer scans the ASSEMBLY for classes that - /// export the IRest interface and builds a list of them. These - /// are later activated by the handler. To add a new handler it - /// is only necessary to create a new services class that implements - /// the IRest interface, and recompile the handler. This gives - /// all of the build-time flexibility of a modular approach - /// while not introducing yet-another module loader. Note that - /// multiple assembles can still be built, each with its own set - /// of handlers. Examples of services classes are RestInventoryServices - /// and RestSkeleton. - /// - - static RestHandler() - { - Module[] mods = Assembly.GetExecutingAssembly().GetModules(); - - foreach (Module m in mods) - { - Type[] types = m.GetTypes(); - foreach (Type t in types) - { - try - { - if (t.GetInterface("IRest") != null) - { - classes.Add(t); - } - } - catch (Exception) - { - Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t); - Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t); - } - } - } - } - - #endregion local static state - - #region local instance state - - /// - /// This routine loads all of the handlers discovered during - /// instance initialization. - /// A table of all loaded and successfully constructed handlers - /// is built, and this table is then used by the constructor to - /// initialize each of the handlers in turn. - /// NOTE: The loading process does not automatically imply that - /// the handler has registered any kind of an interface, that - /// may be (optionally) done by the handler either during - /// construction, or during initialization. - /// - /// I was not able to make this code work within a constructor - /// so it is isolated within this method. - /// - - private void LoadHandlers() - { - lock (handlers) - { - if (!handlersLoaded) - { - ConstructorInfo ci; - Object ht; - - foreach (Type t in classes) - { - try - { - ci = t.GetConstructor(parms); - ht = ci.Invoke(args); - handlers.Add((IRest)ht); - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message); - } - } - handlersLoaded = true; - } - } - } - - #endregion local instance state - - #region overriding properties - - // These properties override definitions - // in the base class. - - // Name is used to differentiate the message header. - - public override string Name - { - get { return "HANDLER"; } - } - - // Used to partition the .ini configuration space. - - public override string ConfigName - { - get { return "RestHandler"; } - } - - // We have to rename these because we want - // to be able to share the values with other - // classes in our assembly and the base - // names are protected. - - public string MsgId - { - get { return base.MsgID; } - } - - public string RequestId - { - get { return base.RequestID; } - } - - #endregion overriding properties - - #region overriding methods - - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - - public override void Initialise(OpenSimBase openSim) - { - try - { - // This plugin will only be enabled if the broader - // REST plugin mechanism is enabled. - - //Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId); - - base.Initialise(openSim); - - // IsEnabled is implemented by the base class and - // reflects an overall RestPlugin status - - if (!IsEnabled) - { - //Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId); - return; - } - - Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name); - Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName); - - // These are stored in static variables to make - // them easy to reach from anywhere in the assembly. - - Rest.main = openSim; - if (Rest.main == null) - throw new Exception("OpenSim base pointer is null"); - - Rest.Plugin = this; - Rest.Config = Config; - Rest.Prefix = Prefix; - Rest.GodKey = GodKey; - Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate); - Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme); - Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure); - Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape); - Rest.Realm = Rest.Config.GetString("realm", Rest.Realm); - Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset); - Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill); - Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize); - Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled); - - // Note: Odd spacing is required in the following strings - - Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId, - (Rest.Authenticate ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId, - (Rest.Secure ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId, - (Rest.ExtendedEscape ? "" : "not ")); - - Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId, - (Rest.DumpAsset ? "" : "not ")); - - // The supplied prefix MUST be absolute - - if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator) - { - Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix); - Rest.Log.InfoFormat("{0} Prefix changed to ", MsgId, Rest.Prefix); - Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix); - } - - // If data dumping is requested, report on the chosen line - // length. - - if (Rest.DumpAsset) - { - Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize); - } - - // Load all of the handlers present in the - // assembly - - // In principle, as we're an application plug-in, - // most of what needs to be done could be done using - // static resources, however the Open Sim plug-in - // model makes this an instance, so that's what we - // need to be. - // There is only one Communications manager per - // server, and by inference, only one each of the - // user, asset, and inventory servers. So we can cache - // those using a static initializer. - // We move all of this processing off to another - // services class to minimize overlap between function - // and infrastructure. - - LoadHandlers(); - - // The intention of a post construction initializer - // is to allow for setup that is dependent upon other - // activities outside of the agency. - - foreach (IRest handler in handlers) - { - try - { - handler.Initialize(); - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message); - } - } - - // Now that everything is setup we can proceed to - // add THIS agent to the HTTP server's handler list - - // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will - // have to be handled through the AddHttpHandler interface. -// if (!AddAgentHandler(Rest.Name,this)) -// { -// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId); -// foreach (IRest handler in handlers) -// { -// handler.Close(); -// } -// } - - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message); - } - } - - /// - /// In the interests of efficiency, and because we cannot determine whether - /// or not this instance will actually be harvested, we clobber the only - /// anchoring reference to the working state for this plug-in. What the - /// call to close does is irrelevant to this class beyond knowing that it - /// can nullify the reference when it returns. - /// To make sure everything is copacetic we make sure the primary interface - /// is disabled by deleting the handler from the HTTP server tables. - /// - - public override void Close() - { - Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId); - - // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will - // have to be handled through the AddHttpHandler interface. -// try -// { -// RemoveAgentHandler(Rest.Name, this); -// } -// catch (KeyNotFoundException){} - - foreach (IRest handler in handlers) - { - handler.Close(); - } - } - - #endregion overriding methods - - #region interface methods - - /// - /// This method is called by the HTTP server to match an incoming - /// request. It scans all of the strings registered by the - /// underlying handlers and looks for the best match. It returns - /// true if a match is found. - /// The matching process could be made arbitrarily complex. - /// Note: The match is case-insensitive. - /// - - public bool Match(OSHttpRequest request, OSHttpResponse response) - { - - string path = request.RawUrl.ToLower(); - - // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId); - - try - { - foreach (string key in pathHandlers.Keys) - { - // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key); - - // Note that Match will not necessarily find the handler that will - // actually be used - it does no test for the "closest" fit. It - // simply reflects that at least one possible handler exists. - - if (path.StartsWith(key)) - { - // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); - - // This apparently odd evaluation is needed to prevent a match - // on anything other than a URI token boundary. Otherwise we - // may match on URL's that were not intended for this handler. - - return (path.Length == key.Length || - path.Substring(key.Length, 1) == Rest.UrlPathSeparator); - } - } - - path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path); - - foreach (string key in streamHandlers.Keys) - { - // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key); - - // Note that Match will not necessarily find the handler that will - // actually be used - it does no test for the "closest" fit. It - // simply reflects that at least one possible handler exists. - - if (path.StartsWith(key)) - { - // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); - - // This apparently odd evaluation is needed to prevent a match - // on anything other than a URI token boundary. Otherwise we - // may match on URL's that were not intended for this handler. - - return (path.Length == key.Length || - path.Substring(key.Length, 1) == Rest.UrlPathSeparator); - } - } - } - catch (Exception e) - { - Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message); - } - - return false; - } - - /// - /// This is called by the HTTP server once the handler has indicated - /// that it is able to handle the request. - /// Preconditions: - /// [1] request != null and is a valid request object - /// [2] response != null and is a valid response object - /// Behavior is undefined if preconditions are not satisfied. - /// - - public bool Handle(OSHttpRequest request, OSHttpResponse response) - { - bool handled; - base.MsgID = base.RequestID; - - // Debug only - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} ENTRY", MsgId); - Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent); - Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod); - - for (int i = 0; i < request.Headers.Count; i++) - { - Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>", - MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i)); - } - Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl); - } - - // If a path handler worked we're done, otherwise try any - // available stream handlers too. - - try - { - handled = (FindPathHandler(request, response) || - FindStreamHandler(request, response)); - } - catch (Exception e) - { - // A raw exception indicates that something we weren't expecting has - // happened. This should always reflect a shortcoming in the plugin, - // or a failure to satisfy the preconditions. It should not reflect - // an error in the request itself. Under such circumstances the state - // of the request cannot be determined and we are obliged to mark it - // as 'handled'. - - Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message); - handled = true; - } - - Rest.Log.DebugFormat("{0} EXIT", MsgId); - - return handled; - } - - #endregion interface methods - - /// - /// If there is a stream handler registered that can handle the - /// request, then fine. If the request is not matched, do - /// nothing. - /// Note: The selection is case-insensitive - /// - - private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response) - { - RequestData rdata = new RequestData(request, response, String.Empty); - - string bestMatch = String.Empty; - string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower(); - - Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path); - - if (!IsEnabled) - { - return false; - } - - foreach (string pattern in streamHandlers.Keys) - { - if (path.StartsWith(pattern)) - { - if (pattern.Length > bestMatch.Length) - { - bestMatch = pattern; - } - } - } - - // Handle using the best match available - - if (bestMatch.Length > 0) - { - Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch); - RestStreamHandler handler = streamHandlers[bestMatch]; - rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response); - rdata.AddHeader(rdata.response.ContentType,handler.ContentType); - rdata.Respond("FindStreamHandler Completion"); - } - - return rdata.handled; - } - - /// - /// Add a stream handler for the designated HTTP method and path prefix. - /// If the handler is not enabled, the request is ignored. If the path - /// does not start with the REST prefix, it is added. If method-qualified - /// path has not already been registered, the method is added to the active - /// handler table. - /// - public void AddStreamHandler(string httpMethod, string path, RestMethod method) - { - if (!IsEnabled) - { - return; - } - - if (!path.StartsWith(Rest.Prefix)) - { - path = String.Format("{0}{1}", Rest.Prefix, path); - } - - path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path); - - // Conditionally add to the list - - if (!streamHandlers.ContainsKey(path)) - { - streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method)); - Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path); - } - else - { - Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path); - } - } - - /// - /// Given the supplied request/response, if the handler is enabled, the inbound - /// information is used to match an entry in the active path handler tables, using - /// the method-qualified path information. If a match is found, then the handler is - /// invoked. The result is the boolean result of the handler, or false if no - /// handler was located. The boolean indicates whether or not the request has been - /// handled, not whether or not the request was successful - that information is in - /// the response. - /// Note: The selection process is case-insensitive - /// - - internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response) - { - RequestData rdata = null; - string bestMatch = null; - - if (!IsEnabled) - { - return false; - } - - // Conditionally add to the list - - Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl); - - foreach (string pattern in pathHandlers.Keys) - { - if (request.RawUrl.ToLower().StartsWith(pattern)) - { - if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) - { - bestMatch = pattern; - } - } - } - - if (!String.IsNullOrEmpty(bestMatch)) - { - rdata = pathAllocators[bestMatch](request, response, bestMatch); - - Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch); - - try - { - pathHandlers[bestMatch](rdata); - } - - // A plugin generated error indicates a request-related error - // that has been handled by the plugin. - - catch (RestException r) - { - Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message); - } - } - - return (rdata == null) ? false : rdata.handled; - } - - /// - /// A method handler and a request allocator are stored using the designated - /// path as a key. If an entry already exists, it is replaced by the new one. - /// - - public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra) - { - if (!IsEnabled) - { - return; - } - - if (pathHandlers.ContainsKey(path)) - { - Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path); - pathHandlers.Remove(path); - } - - if (pathAllocators.ContainsKey(path)) - { - Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path); - pathAllocators.Remove(path); - } - - Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path); - - pathHandlers.Add(path, mh); - pathAllocators.Add(path, ra); - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs deleted file mode 100644 index 536f167..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs +++ /dev/null @@ -1,2343 +0,0 @@ -/* - * 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.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Timers; -using System.Xml; -using OpenMetaverse; -using OpenMetaverse.Imaging; -using OpenSim.Framework; - -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using Timer=System.Timers.Timer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestInventoryServices : IRest - { -// private static readonly int PARM_USERID = 0; -// private static readonly int PARM_PATH = 1; - -// private bool enabled = false; - private string qPrefix = "inventory"; - -// private static readonly string PRIVATE_ROOT_NAME = "My Inventory"; - - /// - /// The constructor makes sure that the service prefix is absolute - /// and the registers the service handler and the allocator. - /// - - public RestInventoryServices() - { - Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified for the handler's domain, - // add the standard prefix to make it absolute, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Register interface using the absolute URI. - - Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate); - - // Activate if everything went OK - -// enabled = true; - - Rest.Log.InfoFormat("{0} Inventory services initialization complete", MsgId); - } - - /// - /// Post-construction, pre-enabled initialization opportunity - /// Not currently exploited. - /// - - public void Initialize() - { - } - - /// - /// Called by the plug-in to halt service processing. Local processing is - /// disabled. - /// - - public void Close() - { -// enabled = false; - Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId); - } - - /// - /// This property is declared locally because it is used a lot and - /// brevity is nice. - /// - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - /// - /// The plugin (RestHandler) calls this method to allocate the request - /// state carrier for a new request. It is destroyed when the request - /// completes. All request-instance specific state is kept here. This - /// is registered when this service provider is registered. - /// - /// Inbound HTTP request information - /// Outbound HTTP request information - /// REST service domain prefix - /// A RequestData instance suitable for this service - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return (RequestData) new InventoryRequestData(request, response, prefix); - } - - /// - /// This method is registered with the handler when this service provider - /// is initialized. It is called whenever the plug-in identifies this service - /// provider as the best match for a given request. - /// It handles all aspects of inventory REST processing, i.e. /admin/inventory - /// - /// A consolidated HTTP request work area - private void DoInventory(RequestData hdata) - { -// InventoryRequestData rdata = (InventoryRequestData) hdata; - - Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId); - - // !!! REFACTORING PROBLEM - - //// If we're disabled, do nothing. - - //if (!enabled) - //{ - // return; - //} - - //// Now that we know this is a serious attempt to - //// access inventory data, we should find out who - //// is asking, and make sure they are authorized - //// to do so. We need to validate the caller's - //// identity before revealing anything about the - //// status quo. Authenticate throws an exception - //// via Fail if no identity information is present. - //// - //// With the present HTTP server we can't use the - //// builtin authentication mechanisms because they - //// would be enforced for all in-bound requests. - //// Instead we look at the headers ourselves and - //// handle authentication directly. - - //try - //{ - // if (!rdata.IsAuthenticated) - // { - // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - // } - //} - //catch (RestException e) - //{ - // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - // { - // Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // else - // { - // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - // } - // throw (e); - //} - - //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName); - - //// We can only get here if we are authorized - //// - //// The requestor may have specified an UUID or - //// a conjoined FirstName LastName string. We'll - //// try both. If we fail with the first, UUID, - //// attempt, we try the other. As an example, the - //// URI for a valid inventory request might be: - //// - //// http://:/admin/inventory/Arthur Dent - //// - //// Indicating that this is an inventory request for - //// an avatar named Arthur Dent. This is ALL that is - //// required to designate a GET for an entire - //// inventory. - //// - - - //// Do we have at least a user agent name? - - //if (rdata.Parameters.Length < 1) - //{ - // Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified"); - //} - - //// The first parameter MUST be the agent identification, either an UUID - //// or a space-separated First-name Last-Name specification. We check for - //// an UUID first, if anyone names their character using a valid UUID - //// that identifies another existing avatar will cause this a problem... - - //try - //{ - // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]); - // Rest.Log.DebugFormat("{0} UUID supplied", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid); - //} - //catch - //{ - // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE); - // if (names.Length == 2) - // { - // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId); - // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]); - // } - // else - // { - // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId); - // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity"); - // } - //} - - //// If the user profile is null then either the server is broken, or the - //// user is not known. We always assume the latter case. - - //if (rdata.userProfile != null) - //{ - // Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - //} - //else - //{ - // Rest.Log.WarnFormat("{0} No profile for {1}", MsgId, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity"); - //} - - //// If we get to here, then we have effectively validated the user's - //// identity. Now we need to get the inventory. If the server does not - //// have the inventory, we reject the request with an appropriate explanation. - //// - //// Note that inventory retrieval is an asynchronous event, we use the rdata - //// class instance as the basis for our synchronization. - //// - - //rdata.uuid = rdata.userProfile.ID; - - //if (Rest.InventoryServices.HasInventoryForUser(rdata.uuid)) - //{ - // rdata.root = Rest.InventoryServices.GetRootFolder(rdata.uuid); - - // Rest.Log.DebugFormat("{0} Inventory Root retrieved for {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - - // Rest.InventoryServices.GetUserInventory(rdata.uuid, rdata.GetUserInventory); - - // Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - - // lock (rdata) - // { - // if (!rdata.HaveInventory) - // { - // rdata.startWD(1000); - // rdata.timeout = false; - // Monitor.Wait(rdata); - // } - // } - - // if (rdata.timeout) - // { - // Rest.Log.WarnFormat("{0} Inventory not available for {1} {2}. No response from service.", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory server not responding"); - // } - - // if (rdata.root == null) - // { - // Rest.Log.WarnFormat("{0} Inventory is not available [1] for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory retrieval failed"); - // } - - //} - //else - //{ - // Rest.Log.WarnFormat("{0} Inventory is not locally available for agent {1} {2}", - // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); - // rdata.Fail(Rest.HttpStatusCodeNotFound, "no local inventory for user"); - //} - - //// If we get here, then we have successfully retrieved the user's information - //// and inventory information is now available locally. - - //switch (rdata.method) - //{ - // case Rest.HEAD : // Do the processing, set the status code, suppress entity - // DoGet(rdata); - // rdata.buffer = null; - // break; - - // case Rest.GET : // Do the processing, set the status code, return entity - // DoGet(rdata); - // break; - - // case Rest.PUT : // Update named element - // DoUpdate(rdata); - // break; - - // case Rest.POST : // Add new information to identified context. - // DoExtend(rdata); - // break; - - // case Rest.DELETE : // Delete information - // DoDelete(rdata); - // break; - - // default : - // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}", - // MsgId, rdata.method, rdata.path); - // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed, - // String.Format("{0} not supported", rdata.method)); - // break; - //} - } - - #endregion Interface - - #region method-specific processing - - /// - /// This method implements GET processing for inventory. - /// Any remaining parameters are used to locate the - /// corresponding subtree based upon node name. - /// - /// HTTP service request work area -// private void DoGet(InventoryRequestData rdata) -// { -// rdata.initXmlWriter(); -// -// rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty); -// -// // If there are additional parameters, then these represent -// // a path relative to the root of the inventory. This path -// // must be traversed before we format the sub-tree thus -// // identified. -// -// traverse(rdata, rdata.root, PARM_PATH); -// -// // Close all open elements -// -// rdata.writer.WriteFullEndElement(); -// -// // Indicate a successful request -// -// rdata.Complete(); -// -// // Send the response to the user. The body will be implicitly -// // constructed from the result of the XML writer. -// -// rdata.Respond(String.Format("Inventory {0} Normal completion", rdata.method)); -// } - - /// - /// In the case of the inventory, and probably in general, - /// the distinction between PUT and POST is not always - /// easy to discern. The standard is badly worded in places, - /// and adding a node to a hierarchy can be viewed as - /// an addition, or as a modification to the inventory as - /// a whole. This is exacerbated by an unjustified lack of - /// consistency across different implementations. - /// - /// For OpenSim PUT is an update and POST is an addition. This - /// is the behavior required by the HTTP specification and - /// therefore as required by REST. - /// - /// The best way to explain the distinction is to - /// consider the relationship between the URI and the - /// enclosed entity. For PUT, the URI identifies the - /// actual entity to be modified or replaced, i.e. the - /// enclosed entity. - /// - /// If the operation is POST,then the URI describes the - /// context into which the new entity will be added. - /// - /// As an example, suppose the URI contains: - /// /admin/inventory/Clothing - /// - /// A PUT request will normally result in some modification of - /// the folder or item named "Clothing". Whereas a POST - /// request will normally add some new information into the - /// content identified by Clothing. It follows from this - /// that for POST, the element identified by the URI MUST - /// be a folder. - /// - - /// - /// POST adds new information to the inventory in the - /// context identified by the URI. - /// - /// HTTP service request work area -// private void DoExtend(InventoryRequestData rdata) -// { -// bool created = false; -// bool modified = false; -// string newnode = String.Empty; -// -// // Resolve the context node specified in the URI. Entity -// // data will be ADDED beneath this node. rdata already contains -// // information about the current content of the user's -// // inventory. -// -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill); -// -// // Processing depends upon the type of inventory node -// // identified in the URI. This is the CONTEXT for the -// // change. We either got a context or we threw an -// // exception. -// -// // It follows that we can only add information if the URI -// // has identified a folder. So only a type of folder is supported -// // in this case. -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// // Cast the context node appropriately. -// -// InventoryFolderBase context = (InventoryFolderBase) InventoryNode; -// -// Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}", -// MsgId, rdata.method, rdata.path); -// -// // Reconstitute the inventory sub-tree from the XML supplied in the entity. -// // The result is a stand-alone inventory subtree, not yet integrated into the -// // existing tree. An inventory collection consists of three components: -// // [1] A (possibly empty) set of folders. -// // [2] A (possibly empty) set of items. -// // [3] A (possibly empty) set of assets. -// // If all of these are empty, then the POST is a harmless no-operation. -// -// XmlInventoryCollection entity = ReconstituteEntity(rdata); -// -// // Inlined assets can be included in entity. These must be incorporated into -// // the asset database before we attempt to update the inventory. If anything -// // fails, return a failure to requestor. -// -// if (entity.Assets.Count > 0) -// { -// Rest.Log.DebugFormat("{0} Adding {1} assets to server", -// MsgId, entity.Assets.Count); -// -// foreach (AssetBase asset in entity.Assets) -// { -// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}", -// MsgId, asset.ID, asset.Type, asset.Name); -// Rest.AssetServices.Store(asset); -// -// created = true; -// rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", -// asset.Name, asset.ID)); -// -// if (Rest.DEBUG && Rest.DumpAsset) -// { -// Rest.Dump(asset.Data); -// } -// } -// } -// -// // Modify the context using the collection of folders and items -// // returned in the XmlInventoryCollection. -// -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// InventoryFolderBase found; -// -// // If the parentID is zero, then this folder is going -// // into the root folder identified by the URI. The requestor -// // may have already set the parent ID explicitly, in which -// // case we don't have to do it here. -// -// if (folder.ParentID == UUID.Zero || folder.ParentID == context.ID) -// { -// if (newnode != String.Empty) -// { -// Rest.Log.DebugFormat("{0} Too many resources", MsgId); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "only one root entity is allowed"); -// } -// folder.ParentID = context.ID; -// newnode = folder.Name; -// } -// -// // Search the existing inventory for an existing entry. If -// // we have one, we need to decide if it has really changed. -// // It could just be present as (unnecessary) context, and we -// // don't want to waste time updating the database in that -// // case, OR, it could be being moved from another location -// // in which case an update is most certainly necessary. -// -// found = null; -// -// foreach (InventoryFolderBase xf in rdata.folders) -// { -// // Compare identifying attribute -// if (xf.ID == folder.ID) -// { -// found = xf; -// break; -// } -// } -// -// if (found != null && FolderHasChanged(folder,found)) -// { -// Rest.Log.DebugFormat("{0} Updating existing folder", MsgId); -// Rest.InventoryServices.MoveFolder(folder); -// -// modified = true; -// rdata.appendStatus(String.Format("

Created folder {0}, UUID {1}

", -// folder.Name, folder.ID)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} Adding new folder", MsgId); -// Rest.InventoryServices.AddFolder(folder); -// -// created = true; -// rdata.appendStatus(String.Format("

Modified folder {0}, UUID {1}

", -// folder.Name, folder.ID)); -// } -// } -// -// // Now we repeat a similar process for the items included -// // in the entity. -// -// foreach (InventoryItemBase item in entity.Items) -// { -// InventoryItemBase found = null; -// -// // If the parentID is zero, then this is going -// // directly into the root identified by the URI. -// -// if (item.Folder == UUID.Zero) -// { -// item.Folder = context.ID; -// } -// -// // Determine whether this is a new item or a -// // replacement definition. -// -// foreach (InventoryItemBase xi in rdata.items) -// { -// // Compare identifying attribute -// if (xi.ID == item.ID) -// { -// found = xi; -// break; -// } -// } -// -// if (found != null && ItemHasChanged(item, found)) -// { -// Rest.Log.DebugFormat("{0} Updating item {1} {2} {3} {4} {5}", -// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name); -// Rest.InventoryServices.UpdateItem(item); -// modified = true; -// rdata.appendStatus(String.Format("

Modified item {0}, UUID {1}

", item.Name, item.ID)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} Adding item {1} {2} {3} {4} {5}", -// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name); -// Rest.InventoryServices.AddItem(item); -// created = true; -// rdata.appendStatus(String.Format("

Created item {0}, UUID {1}

", item.Name, item.ID)); -// } -// } -// -// if (created) -// { -// // Must include a location header with a URI that identifies the new resource. -// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}/{3}", -// rdata.hostname, rdata.port,rdata.path,newnode)); -// rdata.Complete(Rest.HttpStatusCodeCreated); -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } -// else -// { -// Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}", -// MsgId, rdata.method, rdata.path, InventoryNode.GetType()); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid resource context"); -// } -// } - - ///

- /// PUT updates the URI-identified element in the inventory. This - /// is actually far more flexible than it might at first sound. For - /// PUT the URI serves two purposes: - /// [1] It identifies the user whose inventory is to be - /// processed. - /// [2] It optionally specifies a subtree of the inventory - /// that is to be used to resolve any relative subtree - /// specifications in the entity. If nothing is specified - /// then the whole of the private inventory is implied. - /// Please note that the subtree specified by the URI is only relevant - /// to an entity containing a URI relative specification, i.e. one or - /// more elements do not specify parent folder information. These - /// elements will be implicitly referenced within the context identified - /// by the URI. - /// If an element in the entity specifies an explicit parent folder, then - /// that parent is effective, regardless of any value specified in the - /// URI. If the parent does not exist, then the element, and any dependent - /// elements, are ignored. This case is actually detected and handled - /// during the reconstitution process. - /// - /// HTTP service request work area -// private void DoUpdate(InventoryRequestData rdata) -// { -// int count = 0; -// bool created = false; -// bool modified = false; -// -// // Resolve the inventory node that is to be modified. -// // rdata already contains information about the current -// // content of the user's inventory. -// -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill); -// -// // As long as we have a node, then we have something -// // meaningful to do, unlike POST. So we reconstitute the -// // subtree before doing anything else. Note that we -// // etiher got a valid node or we threw an exception. -// -// XmlInventoryCollection entity = ReconstituteEntity(rdata); -// -// // Incorporate any inlined assets first. Any failures -// // will terminate the request. -// -// if (entity.Assets.Count > 0) -// { -// Rest.Log.DebugFormat("{0} Adding {1} assets to server", -// MsgId, entity.Assets.Count); -// -// foreach (AssetBase asset in entity.Assets) -// { -// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}", -// MsgId, asset.ID, asset.Type, asset.Name); -// -// // The asset was validated during the collection process -// -// Rest.AssetServices.Store(asset); -// -// created = true; -// rdata.appendStatus(String.Format("

Created asset {0}, UUID {1}

", asset.Name, asset.ID)); -// -// if (Rest.DEBUG && Rest.DumpAsset) -// { -// Rest.Dump(asset.Data); -// } -// } -// } -// -// // The URI specifies either a folder or an item to be updated. -// // -// // The root node in the entity will replace the node identified -// // by the URI. This means the parent will remain the same, but -// // any or all attributes associated with the named element -// // will change. -// // -// // If the inventory collection contains an element with a zero -// // parent ID, then this is taken to be the replacement for the -// // named node. The collection MAY also specify an explicit -// // parent ID, in this case it MAY identify the same parent as -// // the current node, or it MAY specify a different parent, -// // indicating that the folder is being moved in addition to any -// // other modifications being made. -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// bool rfound = false; -// InventoryFolderBase uri = (InventoryFolderBase) InventoryNode; -// InventoryFolderBase xml = null; -// -// // If the entity to be replaced resolved to be the root -// // directory itself (My Inventory), then make sure that -// // the supplied data include as appropriately typed and -// // named folder. Note that we can;t rule out the possibility -// // of a sub-directory being called "My Inventory", so that -// // is anticipated. -// -// if (uri == rdata.root) -// { -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// if ((rfound = (folder.Name == PRIVATE_ROOT_NAME))) -// { -// if ((rfound = (folder.ParentID == UUID.Zero))) -// break; -// } -// } -// -// if (!rfound) -// { -// Rest.Log.DebugFormat("{0} {1}: Path <{2}> will result in loss of inventory", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid inventory structure"); -// } -// } -// -// // Scan the set of folders in the entity collection for an -// // entry that matches the context folder. It is assumed that -// // the only reliable indicator of this is a zero UUID (using -// // implicit context), or the parent's UUID matches that of the -// // URI designated node (explicit context). We don't allow -// // ambiguity in this case because this is POST and we are -// // supposed to be modifying a specific node. -// // We assign any element IDs required as an economy; we don't -// // want to iterate over the fodler set again if it can be -// // helped. -// -// foreach (InventoryFolderBase folder in entity.Folders) -// { -// if (folder.ParentID == uri.ParentID || -// folder.ParentID == UUID.Zero) -// { -// folder.ParentID = uri.ParentID; -// xml = folder; -// count++; -// } -// } -// -// // More than one entry is ambiguous. Other folders should be -// // added using the POST verb. -// -// if (count > 1) -// { -// Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeConflict, "context is ambiguous"); -// } -// -// // Exactly one entry means we ARE replacing the node -// // identified by the URI. So we delete the old folder -// // by moving it to the trash and then purging it. -// // We then add all of the folders and items we -// // included in the entity. The subtree has been -// // modified. -// -// if (count == 1) -// { -// InventoryFolderBase TrashCan = GetTrashCan(rdata); -// -// // All went well, so we generate a UUID is one is -// // needed. -// -// if (xml.ID == UUID.Zero) -// { -// xml.ID = UUID.Random(); -// } -// -// uri.ParentID = TrashCan.ID; -// Rest.InventoryServices.MoveFolder(uri); -// Rest.InventoryServices.PurgeFolder(TrashCan); -// modified = true; -// } -// -// // Now, regardelss of what they represent, we -// // integrate all of the elements in the entity. -// -// foreach (InventoryFolderBase f in entity.Folders) -// { -// rdata.appendStatus(String.Format("

Moving folder {0} UUID {1}

", f.Name, f.ID)); -// Rest.InventoryServices.MoveFolder(f); -// } -// -// foreach (InventoryItemBase it in entity.Items) -// { -// rdata.appendStatus(String.Format("

Storing item {0} UUID {1}

", it.Name, it.ID)); -// Rest.InventoryServices.AddItem(it); -// } -// } -// -// ///

-// /// URI specifies an item to be updated -// /// -// /// -// /// The entity must contain a single item node to be -// /// updated. ID and Folder ID must be correct. -// /// -// -// else -// { -// InventoryItemBase uri = (InventoryItemBase) InventoryNode; -// InventoryItemBase xml = null; -// -// if (entity.Folders.Count != 0) -// { -// Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "folder is not allowed"); -// } -// -// if (entity.Items.Count > 1) -// { -// Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>", -// MsgId, rdata.method, rdata.path); -// rdata.Fail(Rest.HttpStatusCodeBadRequest, "too may items"); -// } -// -// xml = entity.Items[0]; -// -// if (xml.ID == UUID.Zero) -// { -// xml.ID = UUID.Random(); -// } -// -// // If the folder reference has changed, then this item is -// // being moved. Otherwise we'll just delete the old, and -// // add in the new. -// -// // Delete the old item -// -// List uuids = new List(); -// uuids.Add(uri.ID); -// Rest.InventoryServices.DeleteItems(uri.Owner, uuids); -// -// // Add the new item to the inventory -// -// Rest.InventoryServices.AddItem(xml); -// -// rdata.appendStatus(String.Format("

Storing item {0} UUID {1}

", xml.Name, xml.ID)); -// } -// -// if (created) -// { -// rdata.Complete(Rest.HttpStatusCodeCreated); -// } -// else -// { -// if (modified) -// { -// rdata.Complete(Rest.HttpStatusCodeOK); -// } -// else -// { -// rdata.Complete(Rest.HttpStatusCodeNoContent); -// } -// } -// -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } - - ///

- /// Arguably the most damaging REST interface. It deletes the inventory - /// item or folder identified by the URI. - /// - /// We only process if the URI identified node appears to exist - /// We do not test for success because we either get a context, - /// or an exception is thrown. - /// - /// Folders are deleted by moving them to another folder and then - /// purging that folder. We'll do that by creating a temporary - /// sub-folder in the TrashCan and purging that folder's - /// contents. If we can't can it, we don't delete it... - /// So, if no trashcan is available, the request does nothing. - /// Items are summarily deleted. - /// - /// In the interests of safety, a delete request should normally - /// be performed using UUID, as a name might identify several - /// elements. - /// - /// HTTP service request work area -// private void DoDelete(InventoryRequestData rdata) -// { -// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, false); -// -// if (typeof(InventoryFolderBase) == InventoryNode.GetType() || -// typeof(InventoryFolderImpl) == InventoryNode.GetType()) -// { -// InventoryFolderBase TrashCan = GetTrashCan(rdata); -// -// InventoryFolderBase folder = (InventoryFolderBase) InventoryNode; -// Rest.Log.DebugFormat("{0} {1}: Folder {2} will be deleted", -// MsgId, rdata.method, rdata.path); -// folder.ParentID = TrashCan.ID; -// Rest.InventoryServices.MoveFolder(folder); -// Rest.InventoryServices.PurgeFolder(TrashCan); -// -// rdata.appendStatus(String.Format("

Deleted folder {0} UUID {1}

", folder.Name, folder.ID)); -// } -// -// // Deleting items is much more straight forward. -// -// else -// { -// InventoryItemBase item = (InventoryItemBase) InventoryNode; -// Rest.Log.DebugFormat("{0} {1}: Item {2} will be deleted", -// MsgId, rdata.method, rdata.path); -// List uuids = new List(); -// uuids.Add(item.ID); -// Rest.InventoryServices.DeleteItems(item.Owner, uuids); -// rdata.appendStatus(String.Format("

Deleted item {0} UUID {1}

", item.Name, item.ID)); -// } -// -// rdata.Complete(); -// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method)); -// } - -#endregion method-specific processing - - ///

- /// This method is called to obtain the OpenSim inventory object identified - /// by the supplied URI. This may be either an Item or a Folder, so a suitably - /// ambiguous return type is employed (Object). This method recurses as - /// necessary to process the designated hierarchy. - /// - /// If we reach the end of the URI then we return the contextual folder to - /// our caller. - /// - /// If we are not yet at the end of the URI we attempt to find a child folder - /// and if we succeed we recurse. - /// - /// If this is the last node, then we look to see if this is an item. If it is, - /// we return that item. - /// - /// If we reach the end of an inventory path and the URI si not yet exhausted, - /// then if 'fill' is specified, we create the intermediate nodes. - /// - /// Otherwise we fail the request on the ground of an invalid URI. - /// - /// An ambiguous request causes the request to fail. - /// - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// URI parameter index - /// Should missing path members be created? - - private Object getInventoryNode(InventoryRequestData rdata, - InventoryFolderBase folder, - int pi, bool fill) - { - InventoryFolderBase foundf = null; - int fk = 0; - - Rest.Log.DebugFormat("{0} Searching folder {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - // We have just run off the end of the parameter sequence - - if (pi >= rdata.Parameters.Length) - { - return folder; - } - - // There are more names in the parameter sequence, - // look for the folder named by param[pi] as a - // child of the folder supplied as an argument. - // Note that a UUID may have been supplied as the - // identifier (it is the ONLY guaranteed unambiguous - // option. - - if (rdata.folders != null) - { - foreach (InventoryFolderBase f in rdata.folders) - { - // Look for the present node in the directory list - if (f.ParentID == folder.ID && - (f.Name == rdata.Parameters[pi] || - f.ID.ToString() == rdata.Parameters[pi])) - { - foundf = f; - fk++; - } - } - } - - // If more than one node matched, then the path, as specified - // is ambiguous. - - if (fk > 1) - { - Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous"); - } - - // If we find a match, then the method - // increment the parameter index, and calls itself - // passing the found folder as the new context. - - if (foundf != null) - { - return getInventoryNode(rdata, foundf, pi+1, fill); - } - - // No folders that match. Perhaps this parameter identifies an item? If - // it does, then it MUST also be the last name in the sequence. - - if (pi == rdata.Parameters.Length-1) - { - if (rdata.items != null) - { - int k = 0; - InventoryItemBase li = null; - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID && - (i.Name == rdata.Parameters[pi] || - i.ID.ToString() == rdata.Parameters[pi])) - { - li = i; - k++; - } - } - if (k == 1) - { - return li; - } - else if (k > 1) - { - Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous"); - } - } - } - - // If fill is enabled, then we must create the missing intermediate nodes. - // And of course, even this is not straightforward. All intermediate nodes - // are obviously folders, but the last node may be a folder or an item. - - if (fill) - { - } - - // No fill, so abandon the request - - Rest.Log.DebugFormat("{0} {1}: Resource {2} not found", - MsgId, rdata.method, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound, - String.Format("resource {0}:{1} not found", rdata.method, rdata.path)); - - return null; /* Never reached */ - } - - /// - /// This routine traverse the inventory's structure until the end-point identified - /// in the URI is reached, the remainder of the inventory (if any) is then formatted - /// and returned to the requestor. - /// - /// Note that this method is only interested in those folder that match elements of - /// the URI supplied by the requestor, so once a match is fund, the processing does - /// not need to consider any further elements. - /// - /// Only the last element in the URI should identify an item. - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// URI parameter index - - private void traverse(InventoryRequestData rdata, InventoryFolderBase folder, int pi) - { - Rest.Log.DebugFormat("{0} Traverse[initial] : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - if (rdata.folders != null) - { - // If there was only one parameter (avatar name), then the entire - // inventory is being requested. - - if (rdata.Parameters.Length == 1) - { - formatInventory(rdata, rdata.root, String.Empty); - } - - // Has the client specified the root directory name explicitly? - // if yes, then we just absorb the reference, because the folder - // we start looking in for a match *is* the root directory. If there - // are more parameters remaining we tarverse, otehrwise it's time - // to format. Otherwise,we consider the "My Inventory" to be implied - // and we just traverse normally. - - else if (folder.ID.ToString() == rdata.Parameters[pi] || - folder.Name == rdata.Parameters[pi]) - { - // Length is -1 because the avatar name is a parameter - if (pi<(rdata.Parameters.Length-1)) - { - traverseInventory(rdata, folder, pi+1); - } - else - { - formatInventory(rdata, folder, String.Empty); - } - } - else - { - traverseInventory(rdata, folder, pi); - } - - return; - } - } - - /// - /// This is the recursive method. I've separated them in this way so that - /// we do not have to waste cycles on any first-case-only processing. - /// - - private void traverseInventory(InventoryRequestData rdata, InventoryFolderBase folder, int pi) - { - int fk = 0; - InventoryFolderBase ffound = null; - InventoryItemBase ifound = null; - - Rest.Log.DebugFormat("{0} Traverse Folder : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi); - - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.ParentID == folder.ID && - (f.Name == rdata.Parameters[pi] || - f.ID.ToString() == rdata.Parameters[pi])) - { - fk++; - ffound = f; - } - } - - // If this is the last element in the parameter sequence, then - // it is reasonable to check for an item. All intermediate nodes - // MUST be folders. - - if (pi == rdata.Parameters.Length-1) - { - // Only if there are any items, and there pretty much always are. - - if (rdata.items != null) - { - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID && - (i.Name == rdata.Parameters[pi] || - i.ID.ToString() == rdata.Parameters[pi])) - { - fk++; - ifound = i; - } - } - } - } - - if (fk == 1) - { - if (ffound != null) - { - if (pi < rdata.Parameters.Length-1) - { - traverseInventory(rdata, ffound, pi+1); - } - else - { - formatInventory(rdata, ffound, String.Empty); - } - return; - } - else - { - // Fetching an Item has a special significance. In this - // case we also want to fetch the associated asset. - // To make it interesting, we'll do this via redirection. - string asseturl = String.Format("http://{0}:{1}/{2}{3}{4}", rdata.hostname, rdata.port, - "admin/assets",Rest.UrlPathSeparator,ifound.AssetID.ToString()); - rdata.Redirect(asseturl,Rest.PERMANENT); - Rest.Log.DebugFormat("{0} Never Reached", MsgId); - } - } - else if (fk > 1) - { - rdata.Fail(Rest.HttpStatusCodeConflict, - String.Format("ambiguous element ({0}) in path specified: <{1}>", - pi, rdata.path)); - } - - Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>", - MsgId, rdata.path); - rdata.Fail(Rest.HttpStatusCodeNotFound,String.Format("no such item/folder : {0}", - rdata.Parameters[pi])); - - } - - /// - /// This method generates XML that describes an instance of InventoryFolderBase. - /// It recurses as necessary to reflect a folder hierarchy, and calls formatItem - /// to generate XML for any items encountered along the way. - /// The indentation parameter is solely for the benefit of trace record - /// formatting. - /// - /// HTTP service request work area - /// The folder to be searched (parent) - /// pretty print indentation - private void formatInventory(InventoryRequestData rdata, InventoryFolderBase folder, string indent) - { - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Folder : {1} {2} {3} type = {4}", - MsgId, folder.ID, indent, folder.Name, folder.Type); - indent += "\t"; - } - - // Start folder item - - rdata.writer.WriteStartElement(String.Empty,"Folder",String.Empty); - rdata.writer.WriteAttributeString("name",String.Empty,folder.Name); - rdata.writer.WriteAttributeString("uuid",String.Empty,folder.ID.ToString()); - rdata.writer.WriteAttributeString("parent",String.Empty,folder.ParentID.ToString()); - rdata.writer.WriteAttributeString("owner",String.Empty,folder.Owner.ToString()); - rdata.writer.WriteAttributeString("type",String.Empty,folder.Type.ToString()); - rdata.writer.WriteAttributeString("version",String.Empty,folder.Version.ToString()); - - if (rdata.folders != null) - { - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.ParentID == folder.ID) - { - formatInventory(rdata, f, indent); - } - } - } - - if (rdata.items != null) - { - foreach (InventoryItemBase i in rdata.items) - { - if (i.Folder == folder.ID) - { - formatItem(rdata, i, indent); - } - } - } - - // End folder item - - rdata.writer.WriteEndElement(); - } - - /// - /// This method generates XML that describes an instance of InventoryItemBase. - /// - /// HTTP service request work area - /// The item to be formatted - /// Pretty print indentation - private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent) - { - Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}", - MsgId, i.ID, indent, i.Name, i.InvType, i.AssetType); - - rdata.writer.WriteStartElement(String.Empty, "Item", String.Empty); - - rdata.writer.WriteAttributeString("name", String.Empty, i.Name); - rdata.writer.WriteAttributeString("desc", String.Empty, i.Description); - rdata.writer.WriteAttributeString("uuid", String.Empty, i.ID.ToString()); - rdata.writer.WriteAttributeString("folder", String.Empty, i.Folder.ToString()); - rdata.writer.WriteAttributeString("owner", String.Empty, i.Owner.ToString()); - rdata.writer.WriteAttributeString("creator", String.Empty, i.CreatorId); - rdata.writer.WriteAttributeString("creatordata", String.Empty, i.CreatorData); - rdata.writer.WriteAttributeString("creationdate", String.Empty, i.CreationDate.ToString()); - rdata.writer.WriteAttributeString("invtype", String.Empty, i.InvType.ToString()); - rdata.writer.WriteAttributeString("assettype", String.Empty, i.AssetType.ToString()); - rdata.writer.WriteAttributeString("groupowned", String.Empty, i.GroupOwned.ToString()); - rdata.writer.WriteAttributeString("groupid", String.Empty, i.GroupID.ToString()); - rdata.writer.WriteAttributeString("saletype", String.Empty, i.SaleType.ToString()); - rdata.writer.WriteAttributeString("saleprice", String.Empty, i.SalePrice.ToString()); - rdata.writer.WriteAttributeString("flags", String.Empty, i.Flags.ToString()); - - rdata.writer.WriteStartElement(String.Empty, "Permissions", String.Empty); - rdata.writer.WriteAttributeString("current", String.Empty, i.CurrentPermissions.ToString("X")); - rdata.writer.WriteAttributeString("next", String.Empty, i.NextPermissions.ToString("X")); - rdata.writer.WriteAttributeString("group", String.Empty, i.GroupPermissions.ToString("X")); - rdata.writer.WriteAttributeString("everyone", String.Empty, i.EveryOnePermissions.ToString("X")); - rdata.writer.WriteAttributeString("base", String.Empty, i.BasePermissions.ToString("X")); - rdata.writer.WriteEndElement(); - - rdata.writer.WriteElementString("Asset", i.AssetID.ToString()); - - rdata.writer.WriteEndElement(); - } - - /// - /// This method creates a "trashcan" folder to support folder and item - /// deletions by this interface. The xisting trash folder is found and - /// this folder is created within it. It is called "tmp" to indicate to - /// the client that it is OK to delete this folder. The REST interface - /// will recreate the folder on an as-required basis. - /// If the trash can cannot be created, then by implication the request - /// that required it cannot be completed, and it fails accordingly. - /// - /// HTTP service request work area - private InventoryFolderBase GetTrashCan(InventoryRequestData rdata) - { - InventoryFolderBase TrashCan = null; - - foreach (InventoryFolderBase f in rdata.folders) - { - if (f.Name == "Trash") - { - foreach (InventoryFolderBase t in rdata.folders) - { - if (t.Name == "tmp") - { - TrashCan = t; - } - } - if (TrashCan == null) - { - TrashCan = new InventoryFolderBase(); - TrashCan.Name = "tmp"; - TrashCan.ID = UUID.Random(); - TrashCan.Version = 1; - TrashCan.Type = (short) AssetType.TrashFolder; - TrashCan.ParentID = f.ID; - TrashCan.Owner = f.Owner; - Rest.InventoryServices.AddFolder(TrashCan); - } - } - } - - if (TrashCan == null) - { - Rest.Log.DebugFormat("{0} No Trash Can available", MsgId); - rdata.Fail(Rest.HttpStatusCodeServerError, "unable to create trash can"); - } - - return TrashCan; - } - - /// - /// Make sure that an unchanged folder is not unnecessarily - /// processed. - /// - /// Folder obtained from enclosed entity - /// Folder obtained from the user's inventory - private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf) - { - return (newf.Name != oldf.Name - || newf.ParentID != oldf.ParentID - || newf.Owner != oldf.Owner - || newf.Type != oldf.Type - || newf.Version != oldf.Version - ); - } - - /// - /// Make sure that an unchanged item is not unnecessarily - /// processed. - /// - /// Item obtained from enclosed entity - /// Item obtained from the user's inventory - private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf) - { - return (newf.Name != oldf.Name - || newf.Folder != oldf.Folder - || newf.Description != oldf.Description - || newf.Owner != oldf.Owner - || newf.CreatorId != oldf.CreatorId - || newf.AssetID != oldf.AssetID - || newf.GroupID != oldf.GroupID - || newf.GroupOwned != oldf.GroupOwned - || newf.InvType != oldf.InvType - || newf.AssetType != oldf.AssetType - ); - } - - /// - /// This method is called by PUT and POST to create an XmlInventoryCollection - /// instance that reflects the content of the entity supplied on the request. - /// Any elements in the completed collection whose UUID is zero, are - /// considered to be located relative to the end-point identified int he - /// URI. In this way, an entire sub-tree can be conveyed in a single REST - /// PUT or POST request. - /// - /// A new instance of XmlInventoryCollection is created and, if the request - /// has an entity, it is more completely initialized. thus, if no entity was - /// provided the collection is valid, but empty. - /// - /// The entity is then scanned and each tag is processed to produce the - /// appropriate inventory elements. At the end f the scan, teh XmlInventoryCollection - /// will reflect the subtree described by the entity. - /// - /// This is a very flexible mechanism, the entity may contain arbitrary, - /// discontiguous tree fragments, or may contain single element. The caller is - /// responsible for integrating this collection (and ensuring that any - /// missing parent IDs are resolved). - /// - /// HTTP service request work area - internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata) - { - Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId); - - XmlInventoryCollection ic = new XmlInventoryCollection(); - - if (rdata.request.HasEntityBody) - { - Rest.Log.DebugFormat("{0} Entity present", MsgId); - - ic.init(rdata); - - try - { - while (ic.xml.Read()) - { - switch (ic.xml.NodeType) - { - case XmlNodeType.Element: - Rest.Log.DebugFormat("{0} StartElement: <{1}>", - MsgId, ic.xml.Name); - - switch (ic.xml.Name) - { - case "Folder": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectFolder(ic); - break; - case "Item": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectItem(ic); - break; - case "Asset": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectAsset(ic); - break; - case "Permissions": - Rest.Log.DebugFormat("{0} Processing {1} element", - MsgId, ic.xml.Name); - CollectPermissions(ic); - break; - default: - Rest.Log.DebugFormat("{0} Ignoring {1} element", - MsgId, ic.xml.Name); - break; - } - - // This stinks, but the ReadElement call above not only reads - // the imbedded data, but also consumes the end tag for Asset - // and moves the element pointer on to the containing Item's - // element-end, however, if there was a permissions element - // following, it would get us to the start of that.. - if (ic.xml.NodeType == XmlNodeType.EndElement && - ic.xml.Name == "Item") - { - Validate(ic); - } - break; - - case XmlNodeType.EndElement : - switch (ic.xml.Name) - { - case "Folder": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - ic.Pop(); - break; - case "Item": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - Validate(ic); - break; - case "Asset": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - break; - case "Permissions": - Rest.Log.DebugFormat("{0} Completing {1} element", - MsgId, ic.xml.Name); - break; - default: - Rest.Log.DebugFormat("{0} Ignoring {1} element", - MsgId, ic.xml.Name); - break; - } - break; - - default: - Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>", - MsgId, ic.xml.NodeType, ic.xml.Value); - break; - } - } - } - catch (XmlException e) - { - Rest.Log.WarnFormat("{0} XML parsing error: {1}", MsgId, e.Message); - throw e; - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unexpected XML parsing error: {1}", MsgId, e.Message); - throw e; - } - } - else - { - Rest.Log.DebugFormat("{0} Entity absent", MsgId); - } - - if (Rest.DEBUG) - { - Rest.Log.DebugFormat("{0} Reconstituted entity", MsgId); - Rest.Log.DebugFormat("{0} {1} assets", MsgId, ic.Assets.Count); - Rest.Log.DebugFormat("{0} {1} folder", MsgId, ic.Folders.Count); - Rest.Log.DebugFormat("{0} {1} items", MsgId, ic.Items.Count); - } - - return ic; - } - - /// - /// This method creates an inventory Folder from the - /// information supplied in the request's entity. - /// A folder instance is created and initialized to reflect - /// default values. These values are then overridden - /// by information supplied in the entity. - /// If context was not explicitly provided, then the - /// appropriate ID values are determined. - /// - - private void CollectFolder(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret folder element", MsgId); - - InventoryFolderBase result = new InventoryFolderBase(); - - // Default values - - result.Name = String.Empty; - result.ID = UUID.Zero; - result.Owner = ic.UserID; - result.ParentID = UUID.Zero; // Context - result.Type = (short) AssetType.Folder; - result.Version = 1; - - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "name": - result.Name = ic.xml.Value; - break; - case "uuid": - result.ID = new UUID(ic.xml.Value); - break; - case "parent": - result.ParentID = new UUID(ic.xml.Value); - break; - case "owner": - result.Owner = new UUID(ic.xml.Value); - break; - case "type": - result.Type = Int16.Parse(ic.xml.Value); - break; - case "version": - result.Version = UInt16.Parse(ic.xml.Value); - break; - default: - Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute <{0}>", - ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - // The client is relying upon the reconstitution process - // to determine the parent's UUID based upon context. This - // is necessary where a new folder may have been - // introduced. - - if (result.ParentID == UUID.Zero) - { - result.ParentID = ic.Parent(); - } - else - { - bool found = false; - - foreach (InventoryFolderBase parent in ic.rdata.folders) - { - if (parent.ID == result.ParentID) - { - found = true; - break; - } - } - - if (!found) - { - Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}", - MsgId, ic.Item.Folder, result.ID); - ic.Fail(Rest.HttpStatusCodeBadRequest, "invalid parent"); - } - } - - // This is a new folder, so no existing UUID is available - // or appropriate - - if (result.ID == UUID.Zero) - { - result.ID = UUID.Random(); - } - - // Treat this as a new context. Any other information is - // obsolete as a consequence. - - ic.Push(result); - } - - /// - /// This method is called to handle the construction of an Item - /// instance from the supplied request entity. It is called - /// whenever an Item start tag is detected. - /// An instance of an Item is created and initialized to default - /// values. These values are then overridden from values supplied - /// as attributes to the Item element. - /// This item is then stored in the XmlInventoryCollection and - /// will be verified by Validate. - /// All context is reset whenever the effective folder changes - /// or an item is successfully validated. - /// - private void CollectItem(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret item element", MsgId); - - InventoryItemBase result = new InventoryItemBase(); - - result.Name = String.Empty; - result.Description = String.Empty; - result.ID = UUID.Zero; - result.Folder = UUID.Zero; - result.Owner = ic.UserID; - result.CreatorId = ic.UserID.ToString(); - result.AssetID = UUID.Zero; - result.GroupID = UUID.Zero; - result.GroupOwned = false; - result.InvType = (int) InventoryType.Unknown; - result.AssetType = (int) AssetType.Unknown; - - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - - switch (ic.xml.Name) - { - case "name": - result.Name = ic.xml.Value; - break; - case "desc": - result.Description = ic.xml.Value; - break; - case "uuid": - result.ID = new UUID(ic.xml.Value); - break; - case "folder": - result.Folder = new UUID(ic.xml.Value); - break; - case "owner": - result.Owner = new UUID(ic.xml.Value); - break; - case "invtype": - result.InvType = Int32.Parse(ic.xml.Value); - break; - case "creator": - result.CreatorId = ic.xml.Value; - break; - case "assettype": - result.AssetType = Int32.Parse(ic.xml.Value); - break; - case "groupowned": - result.GroupOwned = Boolean.Parse(ic.xml.Value); - break; - case "groupid": - result.GroupID = new UUID(ic.xml.Value); - break; - case "flags": - result.Flags = UInt32.Parse(ic.xml.Value); - break; - case "creationdate": - result.CreationDate = Int32.Parse(ic.xml.Value); - break; - case "saletype": - result.SaleType = Byte.Parse(ic.xml.Value); - break; - case "saleprice": - result.SalePrice = Int32.Parse(ic.xml.Value); - break; - - default: - Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute", - ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - ic.Push(result); - } - - /// - /// This method assembles an asset instance from the - /// information supplied in the request's entity. It is - /// called as a result of detecting a start tag for a - /// type of Asset. - /// The information is collected locally, and an asset - /// instance is created only if the basic XML parsing - /// completes successfully. - /// Default values for all parts of the asset are - /// established before overriding them from the supplied - /// XML. - /// If an asset has inline=true as an attribute, then - /// the element contains the data representing the - /// asset. This is saved as the data component. - /// inline=false means that the element's payload is - /// simply the UUID of the asset referenced by the - /// item being constructed. - /// An asset, if created is stored in the - /// XmlInventoryCollection - /// - private void CollectAsset(XmlInventoryCollection ic) - { - Rest.Log.DebugFormat("{0} Interpret asset element", MsgId); - - string name = String.Empty; - string desc = String.Empty; - sbyte type = (sbyte) AssetType.Unknown; - bool temp = false; - bool local = false; - - // This is not a persistent attribute - bool inline = false; - - UUID uuid = UUID.Zero; - - // Attribute is optional - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "name" : - name = ic.xml.Value; - break; - - case "type" : - type = SByte.Parse(ic.xml.Value); - break; - - case "description" : - desc = ic.xml.Value; - break; - - case "temporary" : - temp = Boolean.Parse(ic.xml.Value); - break; - - case "uuid" : - uuid = new UUID(ic.xml.Value); - break; - - case "inline" : - inline = Boolean.Parse(ic.xml.Value); - break; - - case "local" : - local = Boolean.Parse(ic.xml.Value); - break; - - default : - Rest.Log.DebugFormat("{0} Asset: Unrecognized attribute: {1}:{2}", - MsgId, ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("unrecognized attribute <{0}>", ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - - // If this is a reference to an existing asset, just store the - // asset ID into the item. - - if (!inline) - { - if (ic.Item != null) - { - ic.Item.AssetID = new UUID(ic.xml.ReadElementContentAsString()); - Rest.Log.DebugFormat("{0} Asset ID supplied: {1}", MsgId, ic.Item.AssetID); - } - else - { - Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "no context for asset"); - } - } - - // Otherwise, generate an asset ID, store that into the item, and - // create an entry in the asset list for the inlined asset. But - // only if the size is non-zero. - - else - { - AssetBase asset = null; - string b64string = null; - - // Generate a UUID if none were given, and generally none should - // be. Ever. - - if (uuid == UUID.Zero) - { - uuid = UUID.Random(); - } - - // Create AssetBase entity to hold the inlined asset - - asset = new AssetBase(uuid, name, type, UUID.Zero.ToString()); - - asset.Description = desc; - asset.Local = local; - asset.Temporary = temp; - - b64string = ic.xml.ReadElementContentAsString(); - - Rest.Log.DebugFormat("{0} Data length is {1}", MsgId, b64string.Length); - Rest.Log.DebugFormat("{0} Data content starts with: \n\t<{1}>", MsgId, - b64string.Substring(0, b64string.Length > 132 ? 132 : b64string.Length)); - - asset.Data = Convert.FromBase64String(b64string); - - // Ensure the asset always has some kind of data component - - if (asset.Data == null) - { - asset.Data = new byte[1]; - } - - // If this is in the context of an item, establish - // a link with the item in context. - - if (ic.Item != null && ic.Item.AssetID == UUID.Zero) - { - ic.Item.AssetID = uuid; - } - - ic.Push(asset); - } - } - - /// - /// Store any permissions information provided by the request. - /// This overrides the default permissions set when the - /// XmlInventoryCollection object was created. - /// - private void CollectPermissions(XmlInventoryCollection ic) - { - if (ic.xml.HasAttributes) - { - for (int i = 0; i < ic.xml.AttributeCount; i++) - { - ic.xml.MoveToAttribute(i); - switch (ic.xml.Name) - { - case "current": - ic.CurrentPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "next": - ic.NextPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "group": - ic.GroupPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "everyone": - ic.EveryOnePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - case "base": - ic.BasePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber); - break; - default: - Rest.Log.DebugFormat("{0} Permissions: invalid attribute {1}:{2}", - MsgId,ic.xml.Name, ic.xml.Value); - ic.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid attribute <{0}>", ic.xml.Name)); - break; - } - } - } - - ic.xml.MoveToElement(); - } - - /// - /// This method is called whenever an Item has been successfully - /// reconstituted from the request's entity. - /// It uses the information curren tin the XmlInventoryCollection - /// to complete the item's specification, including any implied - /// context and asset associations. - /// It fails the request if any necessary item or asset information - /// is missing. - /// - - private void Validate(XmlInventoryCollection ic) - { - // There really should be an item present if we've - // called validate. So fail if there is not. - - if (ic.Item == null) - { - Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "request parse error"); - } - - // Every item is required to have a name (via REST anyway) - - if (ic.Item.Name == String.Empty) - { - Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "item name required"); - } - - // An item MUST have an asset ID. AssetID should never be zero - // here. It should always get set from the information stored - // when the Asset element was processed. - - if (ic.Item.AssetID == UUID.Zero) - { - Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId); - Rest.Log.InfoFormat("{0} Asset information is missing", MsgId); - ic.Fail(Rest.HttpStatusCodeBadRequest, "asset information required"); - } - - // If the item is new, then assign it an ID - - if (ic.Item.ID == UUID.Zero) - { - ic.Item.ID = UUID.Random(); - } - - // If the context is being implied, obtain the current - // folder item's ID. If it was specified explicitly, make - // sure that theparent folder exists. - - if (ic.Item.Folder == UUID.Zero) - { - ic.Item.Folder = ic.Parent(); - } - else - { - bool found = false; - - foreach (InventoryFolderBase parent in ic.rdata.folders) - { - if (parent.ID == ic.Item.Folder) - { - found = true; - break; - } - } - - if (!found) - { - Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}", - MsgId, ic.Item.Folder, ic.Item.ID); - ic.Fail(Rest.HttpStatusCodeBadRequest, "parent information required"); - } - } - - // If this is an inline asset being constructed in the context - // of a new Item, then use the itm's name here too. - - if (ic.Asset != null) - { - if (ic.Asset.Name == String.Empty) - ic.Asset.Name = ic.Item.Name; - if (ic.Asset.Description == String.Empty) - ic.Asset.Description = ic.Item.Description; - } - - // Assign permissions - - ic.Item.CurrentPermissions = ic.CurrentPermissions; - ic.Item.EveryOnePermissions = ic.EveryOnePermissions; - ic.Item.BasePermissions = ic.BasePermissions; - ic.Item.GroupPermissions = ic.GroupPermissions; - ic.Item.NextPermissions = ic.NextPermissions; - - // If no type was specified for this item, we can attempt to - // infer something from the file type maybe. This is NOT as - // good as having type be specified in the XML. - - if (ic.Item.AssetType == (int) AssetType.Unknown || - ic.Item.InvType == (int) InventoryType.Unknown) - { - Rest.Log.DebugFormat("{0} Attempting to infer item type", MsgId); - - string[] parts = ic.Item.Name.Split(Rest.CA_PERIOD); - - if (Rest.DEBUG) - { - for (int i = 0; i < parts.Length; i++) - { - Rest.Log.DebugFormat("{0} Name part {1} : {2}", - MsgId, i, parts[i]); - } - } - - // If the associated item name is multi-part, then maybe - // the last part will indicate the item type - if we're - // lucky. - - if (parts.Length > 1) - { - Rest.Log.DebugFormat("{0} File type is {1}", - MsgId, parts[parts.Length - 1]); - switch (parts[parts.Length - 1]) - { - case "jpeg2000" : - case "jpeg-2000" : - case "jpg2000" : - case "jpg-2000" : - Rest.Log.DebugFormat("{0} Type {1} inferred", - MsgId, parts[parts.Length-1]); - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageJPEG; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - break; - case "jpg" : - case "jpeg" : - Rest.Log.DebugFormat("{0} Type {1} inferred", - MsgId, parts[parts.Length - 1]); - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageJPEG; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - break; - case "tga" : - if (parts[parts.Length - 2].IndexOf("_texture") != -1) - { - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.TextureTGA; - if (ic.Item.InvType == (int) AssetType.Unknown) - ic.Item.InvType = (int) InventoryType.Texture; - } - else - { - if (ic.Item.AssetType == (int) AssetType.Unknown) - ic.Item.AssetType = (int) AssetType.ImageTGA; - if (ic.Item.InvType == (int) InventoryType.Unknown) - ic.Item.InvType = (int) InventoryType.Snapshot; - } - break; - default : - Rest.Log.DebugFormat("{0} Asset/Inventory type could not be inferred for {1}", - MsgId,ic.Item.Name); - break; - } - } - } - - /// If this is a TGA remember the fact - - if (ic.Item.AssetType == (int) AssetType.TextureTGA || - ic.Item.AssetType == (int) AssetType.ImageTGA) - { - Bitmap temp; - Stream tgadata = new MemoryStream(ic.Asset.Data); - - temp = LoadTGAClass.LoadTGA(tgadata); - try - { - ic.Asset.Data = OpenJPEG.EncodeFromImage(temp, true); - } - catch (DllNotFoundException) - { - Rest.Log.ErrorFormat("OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - catch (IndexOutOfRangeException) - { - Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - catch (Exception) - { - Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name); - ic.Asset.Data = new Byte[0]; - } - } - - ic.reset(); - } - - #region Inventory RequestData extension - - internal class InventoryRequestData : RequestData - { - /// - /// These are the inventory specific request/response state - /// extensions. - /// - - internal UUID uuid = UUID.Zero; - internal bool HaveInventory = false; - internal ICollection folders = null; - internal ICollection items = null; - internal UserProfileData userProfile = null; - internal InventoryFolderBase root = null; - internal bool timeout = false; - internal Timer watchDog = new Timer(); - - internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) - : base(request, response, prefix) - { - } - - internal void startWD(double interval) - { - Rest.Log.DebugFormat("{0} Setting watchdog", MsgId); - watchDog.Elapsed += new ElapsedEventHandler(OnTimeOut); - watchDog.Interval = interval; - watchDog.AutoReset = false; - watchDog.Enabled = true; - lock (watchDog) - watchDog.Start(); - - } - - internal void stopWD() - { - Rest.Log.DebugFormat("{0} Reset watchdog", MsgId); - lock (watchDog) - watchDog.Stop(); - } - - /// - /// This is the callback method required by the inventory watchdog. The - /// requestor issues an inventory request and then blocks until the - /// request completes, or this method signals the monitor. - /// - - private void OnTimeOut(object sender, ElapsedEventArgs args) - { - Rest.Log.DebugFormat("{0} Asynchronous inventory update timed-out", MsgId); - // InventoryRequestData rdata = (InventoryRequestData) sender; - lock (this) - { - this.folders = null; - this.items = null; - this.HaveInventory = false; - this.timeout = true; - Monitor.Pulse(this); - } - } - - /// - /// This is the callback method required by inventory services. The - /// requestor issues an inventory request and then blocks until this - /// method signals the monitor. - /// - - internal void GetUserInventory(ICollection folders, ICollection items) - { - Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId); - lock (this) - { - if (watchDog.Enabled) - { - this.stopWD(); - } - this.folders = folders; - this.items = items; - this.HaveInventory = true; - this.timeout = false; - Monitor.Pulse(this); - } - } - } - - #endregion Inventory RequestData extension - - /// - /// This class is used to record and manage the hierarchy - /// constructed from the entity supplied in the request for - /// PUT and POST. - /// - - internal class XmlInventoryCollection : InventoryCollection - { - internal InventoryRequestData rdata; - private Stack stk; - - internal List Assets; - - internal InventoryItemBase Item; - internal AssetBase Asset; - internal XmlReader xml; - - internal /*static*/ const uint DefaultCurrent = 0x7FFFFFFF; - internal /*static*/ const uint DefaultNext = 0x82000; - internal /*static*/ const uint DefaultBase = 0x7FFFFFFF; - internal /*static*/ const uint DefaultEveryOne = 0x0; - internal /*static*/ const uint DefaultGroup = 0x0; - - internal uint CurrentPermissions = 0x00; - internal uint NextPermissions = 0x00; - internal uint BasePermissions = 0x00; - internal uint EveryOnePermissions = 0x00; - internal uint GroupPermissions = 0x00; - - internal XmlInventoryCollection() - { - Folders = new List(); - Items = new List(); - Assets = new List(); - } - - internal void init(InventoryRequestData p_rdata) - { - rdata = p_rdata; - UserID = rdata.uuid; - stk = new Stack(); - rdata.initXmlReader(); - xml = rdata.reader; - initPermissions(); - } - - internal void initPermissions() - { - CurrentPermissions = DefaultCurrent; - NextPermissions = DefaultNext; - BasePermissions = DefaultBase; - GroupPermissions = DefaultGroup; - EveryOnePermissions = DefaultEveryOne; - } - - internal UUID Parent() - { - if (stk.Count != 0) - { - return stk.Peek().ID; - } - else - { - return UUID.Zero; - } - } - - internal void Push(InventoryFolderBase folder) - { - stk.Push(folder); - Folders.Add(folder); - reset(); - } - - internal void Push(InventoryItemBase item) - { - Item = item; - Items.Add(item); - } - - internal void Push(AssetBase asset) - { - Asset = asset; - Assets.Add(asset); - } - - internal void Pop() - { - stk.Pop(); - reset(); - } - - internal void reset() - { - Item = null; - Asset = null; - initPermissions(); - } - - internal void Fail(int code, string addendum) - { - rdata.Fail(code, addendum); - } - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs deleted file mode 100644 index 81596a3..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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.Generic; -using System.Reflection; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - public class RestTestServices : IRest - { - private bool enabled = false; - private string qPrefix = "test"; - - // A simple constructor is used to handle any once-only - // initialization of working classes. - - public RestTestServices() - { - Rest.Log.InfoFormat("{0} Test services initializing", MsgId); - Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); - - // If a relative path was specified, make it absolute by adding - // the standard prefix, e.g. /admin - - if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) - { - Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId); - qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); - Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix); - } - - // Load test cases - - loadTests(); - foreach (ITest test in tests) - { - test.Initialize(); - } - - // Register interface - - Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate); - - // Activate - - enabled = true; - - Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - foreach (ITest test in tests) - { - test.Close(); - } - Rest.Log.InfoFormat("{0} Test services closing down", MsgId); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - #region Interface - - private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) - { - return new RequestData(request, response, prefix); - } - - // Inventory Handler - - private void DoTests(RequestData rdata) - { - if (!enabled) - return; - - // Now that we know this is a serious attempt to - // access inventory data, we should find out who - // is asking, and make sure they are authorized - // to do so. We need to validate the caller's - // identity before revealing anything about the - // status quo. Authenticate throws an exception - // via Fail if no identity information is present. - // - // With the present HTTP server we can't use the - // builtin authentication mechanisms because they - // would be enforced for all in-bound requests. - // Instead we look at the headers ourselves and - // handle authentication directly. - - try - { - if (!rdata.IsAuthenticated) - { - rdata.Fail(Rest.HttpStatusCodeNotAuthorized, - String.Format("user \"{0}\" could not be authenticated", rdata.userName)); - } - } - catch (RestException e) - { - if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) - { - Rest.Log.WarnFormat("{0} User not authenticated", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - } - else - { - Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); - Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization")); - } - throw (e); - } - - // Check that a test was specified - - if (rdata.Parameters.Length < 1) - { - Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters"); - } - - // Select the test - - foreach (ITest test in tests) - { - if (!rdata.handled) - test.Execute(rdata); - } - } - - #endregion Interface - - private static bool testsLoaded = false; - private static List classes = new List(); - private static List tests = new List(); - private static Type[] parms = new Type[0]; - private static Object[] args = new Object[0]; - - static RestTestServices() - { - Module[] mods = Assembly.GetExecutingAssembly().GetModules(); - foreach (Module m in mods) - { - Type[] types = m.GetTypes(); - foreach (Type t in types) - { - try - { - if (t.GetInterface("ITest") != null) - { - classes.Add(t); - } - } - catch (Exception e) - { - Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message); - } - } - } - } - - /// - /// This routine loads all of the handlers discovered during - /// instance initialization. Each handler is responsible for - /// registering itself with this handler. - /// I was not able to make this code work in a constructor. - /// - - private void loadTests() - { - lock (tests) - { - if (!testsLoaded) - { - - ConstructorInfo ci; - Object ht; - - foreach (Type t in classes) - { - try - { - if (t.GetInterface("ITest") != null) - { - ci = t.GetConstructor(parms); - ht = ci.Invoke(args); - tests.Add((ITest)ht); - Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t); - } - } - catch (Exception e) - { - Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message); - } - } - testsLoaded = true; - } - } - } - - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs deleted file mode 100644 index eafc154..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* -* 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. -* -*/ - -namespace OpenSim.ApplicationPlugins.Rest.Inventory -{ - - /// - /// This interface represents the boundary between the general purpose - /// REST plugin handling, and the functionally specific handlers. The - /// handler knows only to initialzie and terminate all such handlers - /// that it finds. - /// - - internal interface ITest - { - void Initialize(); - void Execute(RequestData rdata); - void Close(); - } - -} diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs deleted file mode 100644 index 1c1afd0..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenMetaverse; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests -{ - public class Remote : ITest - { - private static readonly int PARM_TESTID = 0; - private static readonly int PARM_COMMAND = 1; - - private static readonly int PARM_MOVE_AVATAR = 2; - private static readonly int PARM_MOVE_X = 3; - private static readonly int PARM_MOVE_Y = 4; - private static readonly int PARM_MOVE_Z = 5; - - private bool enabled = false; - - // No constructor code is required. - - public Remote() - { - Rest.Log.InfoFormat("{0} Remote services constructor", MsgId); - } - - // Post-construction, pre-enabled initialization opportunity - // Not currently exploited. - - public void Initialize() - { - enabled = true; - Rest.Log.InfoFormat("{0} Remote services initialized", MsgId); - } - - // Called by the plug-in to halt REST processing. Local processing is - // disabled, and control blocks until all current processing has - // completed. No new processing will be started - - public void Close() - { - enabled = false; - Rest.Log.InfoFormat("{0} Remote services closing down", MsgId); - } - - // Properties - - internal string MsgId - { - get { return Rest.MsgId; } - } - - // Remote Handler - // Key information of interest here is the Parameters array, each - // entry represents an element of the URI, with element zero being - // the - - public void Execute(RequestData rdata) - { - if (!enabled) return; - - // If we can't relate to what's there, leave it for others. - - if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote") - return; - - Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId); - - // Remove the prefix and what's left are the parameters. If we don't have - // the parameters we need, fail the request. Parameters do NOT include - // any supplied query values. - - if (rdata.Parameters.Length > 1) - { - switch (rdata.Parameters[PARM_COMMAND].ToLower()) - { - case "move" : - DoMove(rdata); - break; - default : - DoHelp(rdata); - break; - } - } - else - { - DoHelp(rdata); - } - } - - private void DoHelp(RequestData rdata) - { - rdata.body = Help; - rdata.Complete(); - rdata.Respond("Help"); - } - - private void DoMove(RequestData rdata) - { - if (rdata.Parameters.Length < 6) - { - Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId); - rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided"); - } - else - { - string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE); - ScenePresence presence = null; - Scene scene = null; - - if (names.Length != 2) - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR])); - } - - Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}", - MsgId, rdata.Parameters[0], names[0], names[1]); - - // The first parameter should be an avatar name, look for the - // avatar in the known regions first. - - Rest.main.SceneManager.ForEachScene(delegate(Scene s) - { - s.ForEachRootScenePresence(delegate(ScenePresence sp) - { - if (sp.Firstname == names[0] && sp.Lastname == names[1]) - { - scene = s; - presence = sp; - } - }); - }); - - if (presence != null) - { - Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}", - MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName); - - try - { - float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]); - float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); - float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); - Vector3 vector = new Vector3(x, y, z); - presence.MoveToTarget(vector, false, false); - } - catch (Exception e) - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("invalid parameters: {0}", e.Message)); - } - } - else - { - rdata.Fail(Rest.HttpStatusCodeBadRequest, - String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR])); - } - - rdata.Complete(); - rdata.Respond("OK"); - } - } - - private static readonly string Help = - "" - + "Remote Command Usage" - + "" - + "

Supported commands are:

" - + "
" - + "
move/avatar-name/x/y/z
" - + "
moves the specified avatar to another location
" - + "
" - + "" - + "" - ; - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs deleted file mode 100644 index d99ba57..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * 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.IO; -using System.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region GET methods - public string GetHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); - - try - { - // param empty: regions list - if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse); - - // param not empty: specific region - return GetHandlerRegion(httpResponse, param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); - } - } - - public string GetHandlerRegions(IOSHttpResponse httpResponse) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndElement(); - } - rxw.WriteEndElement(); - - return rxw.ToString(); - } - - protected string ShortRegionInfo(string key, string value) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - if (String.IsNullOrEmpty(value) || - String.IsNullOrEmpty(key)) return null; - - rxw.WriteStartElement(String.Empty, "region", String.Empty); - rxw.WriteStartElement(String.Empty, key, String.Empty); - rxw.WriteString(value); - rxw.WriteEndDocument(); - - return rxw.ToString(); - } - - public string GetHandlerRegion(IOSHttpResponse httpResponse, string param) - { - // be resilient and don't get confused by a terminating '/' - param = param.TrimEnd(new char[]{'/'}); - string[] comps = param.Split('/'); - UUID regionID = (UUID)comps[0]; - - m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString()); - - if (UUID.Zero == regionID) throw new Exception("missing region ID"); - - Scene scene = null; - App.SceneManager.TryGetScene(regionID, out scene); - if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "GET", "cannot find region {0}", regionID.ToString()); - - RegionDetails details = new RegionDetails(scene.RegionInfo); - - // m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length); - // for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]); - - if (1 == comps.Length) - { - // complete region details requested - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - XmlSerializer xs = new XmlSerializer(typeof(RegionDetails)); - xs.Serialize(rxw, details, _xmlNs); - return rxw.ToString(); - } - - if (2 == comps.Length) - { - string resp = ShortRegionInfo(comps[1], details[comps[1]]); - if (null != resp) return resp; - - // m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]); - - // check for {terrain,stats,prims} - switch (comps[1].ToLower()) - { - case "terrain": - return RegionTerrain(httpResponse, scene); - - case "stats": - return RegionStats(httpResponse, scene); - - case "prims": - return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero); - } - } - - if (3 == comps.Length) - { - switch (comps[1].ToLower()) - { - case "prims": - string[] subregion = comps[2].Split(','); - if (subregion.Length == 6) - { - Vector3 min, max; - try - { - min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo)); - max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo)); - } - catch (Exception) - { - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "invalid subregion parameter"); - } - return RegionPrims(httpResponse, scene, min, max); - } - else - { - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "invalid subregion parameter"); - } - } - } - - return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, - "GET", "too many parameters {0}", param); - } - #endregion GET methods - - protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene) - { - httpResponse.SendChunked = true; - httpResponse.ContentType = "text/xml"; - - return scene.Heightmap.SaveToXmlString(); - //return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, - // "GET", "terrain not implemented"); - } - - protected string RegionStats(IOSHttpResponse httpResponse, Scene scene) - { - int users = scene.GetRootAgentCount(); - int objects = scene.Entities.Count - users; - - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "region", String.Empty); - rxw.WriteStartElement(String.Empty, "stats", String.Empty); - - rxw.WriteStartElement(String.Empty, "users", String.Empty); - rxw.WriteString(users.ToString()); - rxw.WriteEndElement(); - - rxw.WriteStartElement(String.Empty, "objects", String.Empty); - rxw.WriteString(objects.ToString()); - rxw.WriteEndElement(); - - rxw.WriteEndDocument(); - - return rxw.ToString(); - } - - protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max) - { - httpResponse.SendChunked = true; - httpResponse.ContentType = "text/xml"; - - IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); - if (serialiser != null) - serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max); - - return ""; - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs deleted file mode 100644 index 468faea..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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.IO; -using System.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region GET methods - public string GetRegionInfoHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param); - - try - { - // param empty: regions list - // if (String.IsNullOrEmpty(param)) - return GetRegionInfoHandlerRegions(httpResponse); - - // // param not empty: specific region - // return GetRegionInfoHandlerRegion(httpResponse, param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); - } - } - - public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - // regions info - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - { - // regions info: number of regions - rxw.WriteStartAttribute(String.Empty, "number", String.Empty); - rxw.WriteValue(App.SceneManager.Scenes.Count); - rxw.WriteEndAttribute(); - - // regions info: max number of regions - rxw.WriteStartAttribute(String.Empty, "max", String.Empty); - if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null) - { - rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1)); - } - else - { - rxw.WriteValue(-1); - } - rxw.WriteEndAttribute(); - - // regions info: region - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "region", String.Empty); - - rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "name", String.Empty); - rxw.WriteString(s.RegionInfo.RegionName); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "x", String.Empty); - rxw.WriteValue(s.RegionInfo.RegionLocX); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "y", String.Empty); - rxw.WriteValue(s.RegionInfo.RegionLocY); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty); - rxw.WriteString(s.RegionInfo.ExternalHostName); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "ip", String.Empty); - rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString()); - rxw.WriteEndAttribute(); - - int users = s.GetRootAgentCount(); - rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty); - rxw.WriteValue(users); - rxw.WriteEndAttribute(); - - rxw.WriteStartAttribute(String.Empty, "objects", String.Empty); - rxw.WriteValue(s.Entities.Count - users); - rxw.WriteEndAttribute(); - - rxw.WriteEndElement(); - } - } - return rxw.ToString(); - } - #endregion GET methods - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs deleted file mode 100644 index f666f45..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.IO; -using OpenMetaverse; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - #region POST methods - - public string PostHandler(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - // foreach (string h in httpRequest.Headers.AllKeys) - // foreach (string v in httpRequest.Headers.GetValues(h)) - // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); - - MsgID = RequestID; - m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param); - - try - { - // param empty: new region post - if (!IsGod(httpRequest)) - // XXX: this needs to be turned into a FailureUnauthorized(...) - return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized, - "GET", "you are not god"); - - if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse); - - // Parse region ID and other parameters - param = param.TrimEnd(new char[] {'/'}); - string[] comps = param.Split('/'); - UUID regionID = (UUID) comps[0]; - - m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString()); - if (UUID.Zero == regionID) throw new Exception("missing region ID"); - - Scene scene = null; - App.SceneManager.TryGetScene(regionID, out scene); - if (null == scene) - return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "POST", "cannot find region {0}", regionID.ToString()); - - if (2 == comps.Length) - { - // check for {prims} - switch (comps[1].ToLower()) - { - case "prims": - return LoadPrims(request, httpRequest, httpResponse, scene); - } - } - - return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, - "POST", "url {0} not supported", param); - } - catch (Exception e) - { - return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e); - } - } - - public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response) - { - RestXmlWriter rxw = new RestXmlWriter(new StringWriter()); - - rxw.WriteStartElement(String.Empty, "regions", String.Empty); - foreach (Scene s in App.SceneManager.Scenes) - { - rxw.WriteStartElement(String.Empty, "uuid", String.Empty); - rxw.WriteString(s.RegionInfo.RegionID.ToString()); - rxw.WriteEndElement(); - } - rxw.WriteEndElement(); - - return rxw.ToString(); - } - - public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene) - { - IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); - if (serialiser != null) - serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true); - - return ""; - } - - #endregion POST methods - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs deleted file mode 100644 index 5e76009..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.Xml.Serialization; -using OpenMetaverse; -using OpenSim.Framework; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - [XmlRoot(ElementName="region", IsNullable = false)] - public class RegionDetails - { - public string region_name; - public string region_id; - public uint region_x; - public uint region_y; - public string region_owner; - public string region_owner_id; - public uint region_http_port; - public uint region_port; - public string region_server_uri; - public string region_external_hostname; - - public RegionDetails() - { - } - - public RegionDetails(RegionInfo regInfo) - { - region_name = regInfo.RegionName; - region_id = regInfo.RegionID.ToString(); - region_x = regInfo.RegionLocX; - region_y = regInfo.RegionLocY; - region_owner_id = regInfo.EstateSettings.EstateOwner.ToString(); - region_http_port = regInfo.HttpPort; - region_server_uri = regInfo.ServerURI; - region_external_hostname = regInfo.ExternalHostName; - - Uri uri = new Uri(region_server_uri); - region_port = (uint)uri.Port; - } - - public string this[string idx] - { - get - { - switch (idx.ToLower()) - { - case "name": - return region_name; - case "id": - return region_id; - case "location": - return String.Format("{0}{1}", region_x, region_y); - case "owner": - return region_owner; - case "owner_id": - return region_owner_id; - case "http_port": - return region_http_port.ToString(); - case "server_uri": - return region_server_uri; - case "external_hostname": - case "hostname": - return region_external_hostname; - - default: - return null; - } - } - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml b/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml deleted file mode 100644 index 94eca48..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs deleted file mode 100644 index 02ef588..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.Xml.Serialization; - -namespace OpenSim.ApplicationPlugins.Rest.Regions -{ - public partial class RestRegionPlugin : RestPlugin - { - private static XmlSerializerNamespaces _xmlNs; - - static RestRegionPlugin() - { - _xmlNs = new XmlSerializerNamespaces(); - _xmlNs.Add(String.Empty, String.Empty); - } - - #region overriding properties - public override string Name - { - get { return "REGION"; } - } - - public override string ConfigName - { - get { return "RestRegionPlugin"; } - } - #endregion overriding properties - - #region overriding methods - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - public override void Initialise(OpenSimBase openSim) - { - try - { - base.Initialise(openSim); - if (!IsEnabled) - { - //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); - return; - } - - m_log.InfoFormat("{0} REST region plugin enabled", MsgID); - - // add REST method handlers - AddRestStreamHandler("GET", "/regions/", GetHandler); - AddRestStreamHandler("POST", "/regions/", PostHandler); - AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler); - } - catch (Exception e) - { - m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); - m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); - } - } - - public override void Close() - { - } - #endregion overriding methods - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs deleted file mode 100644 index a2425b5..0000000 --- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs +++ /dev/null @@ -1,417 +0,0 @@ -/* - * 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.Generic; -using System.IO; -using System.Reflection; -using System.Xml; -using log4net; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; - -namespace OpenSim.ApplicationPlugins.Rest -{ - public abstract class RestPlugin : IApplicationPlugin - { - #region properties - - protected static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IConfig _config; // Configuration source: Rest Plugins - private IConfig _pluginConfig; // Configuration source: Plugin specific - private OpenSimBase _app; // The 'server' - private BaseHttpServer _httpd; // The server's RPC interface - private string _prefix; // URL prefix below - // which all REST URLs - // are living - // private StringWriter _sw = null; - // private RestXmlWriter _xw = null; - - private string _godkey; - private int _reqk; - - [ThreadStatic] - private static string _threadRequestID = String.Empty; - - /// - /// Return an ever increasing request ID for logging - /// - protected string RequestID - { - get { return _reqk++.ToString(); } - set { _reqk = Convert.ToInt32(value); } - } - - /// - /// Thread-constant message IDs for logging. - /// - protected string MsgID - { - get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); } - set { _threadRequestID = value; } - } - - /// - /// Returns true if Rest Plugins are enabled. - /// - public bool PluginsAreEnabled - { - get { return null != _config; } - } - - /// - /// Returns true if specific Rest Plugin is enabled. - /// - public bool IsEnabled - { - get - { - return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); - } - } - - /// - /// OpenSimMain application - /// - public OpenSimBase App - { - get { return _app; } - } - - /// - /// RPC server - /// - public BaseHttpServer HttpServer - { - get { return _httpd; } - } - - /// - /// URL prefix to use for all REST handlers - /// - public string Prefix - { - get { return _prefix; } - } - - /// - /// Access to GOD password string - /// - protected string GodKey - { - get { return _godkey; } - } - - /// - /// Configuration of the plugin - /// - public IConfig Config - { - get { return _pluginConfig; } - } - - /// - /// Name of the plugin - /// - public abstract string Name { get; } - - /// - /// Return the config section name - /// - public abstract string ConfigName { get; } - - // public XmlTextWriter XmlWriter - // { - // get - // { - // if (null == _xw) - // { - // _sw = new StringWriter(); - // _xw = new RestXmlWriter(_sw); - // _xw.Formatting = Formatting.Indented; - // } - // return _xw; - // } - // } - - // public string XmlWriterResult - // { - // get - // { - // _xw.Flush(); - // _xw.Close(); - // _xw = null; - - // return _sw.ToString(); - // } - // } - - #endregion properties - - #region methods - - // TODO: required by IPlugin, but likely not at all right - private string m_version = "0.0"; - - public string Version - { - get { return m_version; } - } - - public void Initialise() - { - m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!"); - throw new PluginNotInitialisedException(Name); - } - - /// - /// This method is called by OpenSimMain immediately after loading the - /// plugin and after basic server setup, but before running any server commands. - /// - /// - /// Note that entries MUST be added to the active configuration files before - /// the plugin can be enabled. - /// - public virtual void Initialise(OpenSimBase openSim) - { - RequestID = "0"; - MsgID = RequestID; - - try - { - if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null) - { - m_log.WarnFormat("{0} Rest Plugins not configured", MsgID); - return; - } - - if (!_config.GetBoolean("enabled", false)) - { - //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID); - return; - } - - _app = openSim; - _httpd = openSim.HttpServer; - - // Retrieve GOD key value, if any. - _godkey = _config.GetString("god_key", String.Empty); - - // Retrive prefix if any. - _prefix = _config.GetString("prefix", "/admin"); - - // Get plugin specific config - _pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName]; - - m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID); - } - catch (Exception e) - { - // we can safely ignore this, as it just means that - // the key lookup in Configs failed, which signals to - // us that noone is interested in our services...they - // don't know what they are missing out on... - // NOTE: Under the present OpenSimulator implementation it is - // not possible for the openSimulator pointer to be null. However - // were the implementation to be changed, this could - // result in a silent initialization failure. Harmless - // except for lack of function and lack of any - // diagnostic indication as to why. The same is true if - // the HTTP server reference is bad. - // We should at least issue a message... - m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message); - m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString()); - } - } - - public virtual void PostInitialise() - { - } - - private List _handlers = new List(); - private Dictionary _agents = new Dictionary(); - - /// - /// Add a REST stream handler to the underlying HTTP server. - /// - /// GET/PUT/POST/DELETE or - /// similar - /// URL prefix - /// RestMethod handler doing the actual work - public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method) - { - if (!IsEnabled) return; - - if (!path.StartsWith(_prefix)) - { - path = String.Format("{0}{1}", _prefix, path); - } - - RestStreamHandler h = new RestStreamHandler(httpMethod, path, method); - _httpd.AddStreamHandler(h); - _handlers.Add(h); - - m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path); - } - - /// - /// Add a powerful Agent handler to the underlying HTTP - /// server. - /// - /// name of agent handler - /// agent handler method - /// false when the plugin is disabled or the agent - /// handler could not be added. Any generated exceptions are - /// allowed to drop through to the caller, i.e. ArgumentException. - /// - public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) - { - if (!IsEnabled) return false; - _agents.Add(agentName, handler); -// return _httpd.AddAgentHandler(agentName, handler); - - return false; - } - - /// - /// Remove a powerful Agent handler from the underlying HTTP - /// server. - /// - /// name of agent handler - /// agent handler method - /// false when the plugin is disabled or the agent - /// handler could not be removed. Any generated exceptions are - /// allowed to drop through to the caller, i.e. KeyNotFound. - /// - public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler) - { - if (!IsEnabled) return false; - if (_agents[agentName] == handler) - { - _agents.Remove(agentName); -// return _httpd.RemoveAgentHandler(agentName, handler); - } - return false; - } - - /// - /// Check whether the HTTP request came from god; that is, is - /// the god_key as configured in the config section supplied - /// via X-OpenSim-Godkey? - /// - /// HTTP request header - /// true when the HTTP request came from god. - protected bool IsGod(IOSHttpRequest request) - { - string[] keys = request.Headers.GetValues("X-OpenSim-Godkey"); - if (null == keys) return false; - - // we take the last key supplied - return keys[keys.Length - 1] == _godkey; - } - - /// - /// Checks wether the X-OpenSim-Password value provided in the - /// HTTP header is indeed the password on file for the avatar - /// specified by the UUID - /// - protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid) - { - // XXX under construction - return false; - } - - /// - /// Clean up and remove all handlers that were added earlier. - /// - public virtual void Close() - { - foreach (RestStreamHandler h in _handlers) - { - _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); - } - _handlers = null; -// foreach (KeyValuePair h in _agents) -// { -// _httpd.RemoveAgentHandler(h.Key, h.Value); -// } - _agents = null; - } - - public virtual void Dispose() - { - Close(); - } - - /// - /// Return a failure message. - /// - /// origin of the failure message - /// failure message - /// This should probably set a return code as - /// well. (?) - protected string Failure(IOSHttpResponse response, OSHttpStatusCode status, - string method, string format, params string[] msg) - { - string m = String.Format(format, msg); - - response.StatusCode = (int) status; - response.StatusDescription = m; - - m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m); - return String.Format("{0}", m); - } - - /// - /// Return a failure message. - /// - /// origin of the failure message - /// exception causing the failure message - /// This should probably set a return code as - /// well. (?) - public string Failure(IOSHttpResponse response, OSHttpStatusCode status, - string method, Exception e) - { - string m = String.Format("exception occurred: {0}", e.Message); - - response.StatusCode = (int) status; - response.StatusDescription = m; - - m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); - m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); - - return String.Format("{0}", e.Message); - } - - #endregion methods - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs b/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs deleted file mode 100644 index 283fa2e..0000000 --- a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.IO; -using System.Text; -using System.Xml; - -namespace OpenSim.ApplicationPlugins.Rest -{ - public class RestXmlWriter: XmlTextWriter - { - private StringWriter m_sw = null; - - public RestXmlWriter(StringWriter sw) : base(sw) - { - m_sw = sw; - Formatting = Formatting.Indented; - } - - public RestXmlWriter(TextWriter textWriter) : base(textWriter) - { - } - - public RestXmlWriter(Stream stream) - : this(stream, Encoding.UTF8) - { - } - - public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc) - { - } - - public override void WriteStartDocument() - { - } - - public override void WriteStartDocument(bool standalone) - { - } - - public override string ToString() - { - Flush(); - Close(); - return m_sw.ToString(); - } - } -} diff --git a/OpenSim/ApplicationPlugins/Rest/rest.xsd b/OpenSim/ApplicationPlugins/Rest/rest.xsd deleted file mode 100644 index 4dc0ae4..0000000 --- a/OpenSim/ApplicationPlugins/Rest/rest.xsd +++ /dev/null @@ -1,276 +0,0 @@ - - - - - Open Simulator Export/Import XML schema - August 2008 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.1 From 6e1b3f9951b5ae9fbc0dc65e8404cb878206c68d Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 16 Mar 2013 03:14:11 -0400 Subject: *Yet another HTTPServer update code changes in OpenSim Libs. * This fixes a connection close issue by getting rid of the socket references * This adds a connection timeout checker to shutdown poor or evil connections and combats DOS attempts that just connect and make no complete requests and just wait. It also actually implements KeepAlive... instead of just understanding the connection header in the request... you can test by connecting and requesting a keepalive header and sending another request on the same connection. The new timeout checker closes expired keepalive sessions, just make sure you send the request within 70 seconds of connecting or the timeout checker will timeout the connection. --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 58312ab..dfdd566 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -486,7 +486,9 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - SendHTML500(response); + byte[] buffer500 = SendHTML500(response); + response.Body.Write(buffer500,0,buffer500.Length); + response.Body.Close(); } catch { @@ -719,7 +721,15 @@ namespace OpenSim.Framework.Servers.HttpServer catch (Exception e) { m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); - SendHTML500(response); + try + { + byte[] buffer500 = SendHTML500(response); + response.Body.Write(buffer500, 0, buffer500.Length); + response.Body.Close(); + } + catch + { + } } finally { @@ -1746,7 +1756,8 @@ namespace OpenSim.Framework.Servers.HttpServer response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - + + return buffer; } -- cgit v1.1 From fc84ebb819b590099bbfa5bd357e886ce7460063 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Sat, 16 Mar 2013 17:16:01 -0400 Subject: BulletSim: Working Implementation of Angular Banking for Vehicles (Not SL Grade, Other features when implemented should slow it down for now be Strong with Vertical Angular attraction setting and conservative with Angular Velocity on X axis) Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 33 +++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index d347159..96eaa6b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -143,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { enableAngularVerticalAttraction = true; enableAngularDeflection = false; - enableAngularBanking = false; + enableAngularBanking = true; if (BSParam.VehicleDebuggingEnabled) { enableAngularVerticalAttraction = true; @@ -1280,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement // TODO: This is here because this is where ODE put it but documentation says it // is a linear effect. Where should this check go? - if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) - { - angularMotorContributionV.X = 0f; - angularMotorContributionV.Y = 0f; - } + //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) + // { + // angularMotorContributionV.X = 0f; + // angularMotorContributionV.Y = 0f; + // } VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); @@ -1437,24 +1437,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin // As the vehicle rolls to the right or left, the Y value will increase from // zero (straight up) to 1 or -1 (full tilt right or left) Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; - // Figure out the yaw value for this much roll. // Squared because that seems to give a good value - float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency; - + // float yawAngle = (float)Math.Asin(rollComponents.X * rollComponents.X) * m_bankingEfficiency; + float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; // actual error = static turn error + dynamic turn error - float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed; - - // TODO: the banking effect should not go to infinity but what to limit it to? - mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f); + float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); + // TODO: the banking effect should not go to infinity but what to limit it to? and what should happen when this is + // being added to a user defined yaw that is already PI*4? + mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12); // Build the force vector to change rotation from what it is to what it should be bankingContributionV.Z = -mixedYawAngle; - // Don't do it all at once. - bankingContributionV /= m_bankingTimescale; + // Don't do it all at once. 60 becouse 1 second is too fast with most user defined roll as PI*4 + bankingContributionV /= m_bankingTimescale*60; - VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; + //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; + VehicleRotationalVelocity += bankingContributionV; + VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); -- cgit v1.1 From 464201b41d5f5fdd7c88ab5e95dd7b6fbae6d766 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 16 Mar 2013 15:34:07 -0700 Subject: BulletSim: add INI parameter for angular banking timescale fudge parameter. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 12 ++++++------ OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 7 ++++++- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 96eaa6b..38596fa 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1437,21 +1437,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin // As the vehicle rolls to the right or left, the Y value will increase from // zero (straight up) to 1 or -1 (full tilt right or left) Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; + // Figure out the yaw value for this much roll. - // Squared because that seems to give a good value - // float yawAngle = (float)Math.Asin(rollComponents.X * rollComponents.X) * m_bankingEfficiency; float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; // actual error = static turn error + dynamic turn error float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); - // TODO: the banking effect should not go to infinity but what to limit it to? and what should happen when this is - // being added to a user defined yaw that is already PI*4? + + // TODO: the banking effect should not go to infinity but what to limit it to? + // And what should happen when this is being added to a user defined yaw that is already PI*4? mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12); // Build the force vector to change rotation from what it is to what it should be bankingContributionV.Z = -mixedYawAngle; - // Don't do it all at once. 60 becouse 1 second is too fast with most user defined roll as PI*4 - bankingContributionV /= m_bankingTimescale*60; + // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4. + bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge; //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; VehicleRotationalVelocity += bankingContributionV; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2af8468..77bdacb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -123,6 +123,7 @@ public static class BSParam public static Vector3 VehicleLinearFactor { get; private set; } public static Vector3 VehicleAngularFactor { get; private set; } public static float VehicleGroundGravityFudge { get; private set; } + public static float VehicleAngularBankingTimescaleFudge { get; private set; } public static bool VehicleDebuggingEnabled { get; private set; } // Linkset implementation parameters @@ -543,10 +544,14 @@ public static class BSParam 0.0f, (s) => { return VehicleRestitution; }, (s,v) => { VehicleRestitution = v; } ), - new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiple gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", + new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", 0.2f, (s) => { return VehicleGroundGravityFudge; }, (s,v) => { VehicleGroundGravityFudge = v; } ), + new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", + 60.0f, + (s) => { return VehicleAngularBankingTimescaleFudge; }, + (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging", false, (s) => { return VehicleDebuggingEnabled; }, -- cgit v1.1 From a7a9a8a614549c7492e4954189e9f4df2473ca1e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Mar 2013 20:42:08 +0000 Subject: Fix recent regression where an item worn to an attachment point that was already occupied did not remove the previous attachment (current behaviour) Regression was commit ccd6f4 (Tue Mar 5 23:47:36 2013) Added regression test for this case. --- .../Avatar/Attachments/AttachmentsModule.cs | 178 +++++++++++---------- .../Attachments/Tests/AttachmentsModuleTests.cs | 64 +++++++- 2 files changed, 153 insertions(+), 89 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index b6a7481..2092d6f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -289,16 +289,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (!Enabled) return false; - if (AttachObjectInternal(sp, group, attachmentPt, silent, temp)) - { - m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); - return true; - } - - return false; + return AttachObjectInternal(sp, group, attachmentPt, silent, temp, false); } - - private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp) + + /// + /// Internal method which actually does all the work for attaching an object. + /// + /// The object attached. + /// + /// The object to attach. + /// + /// + /// + /// If true then scripts are resumed on the attached object. + private bool AttachObjectInternal( + IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool resumeScripts) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", @@ -322,44 +327,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return false; } + Vector3 attachPos = group.AbsolutePosition; + + // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should + // be removed when that functionality is implemented in opensim + attachmentPt &= 0x7f; + + // If the attachment point isn't the same as the one previously used + // set it's offset position = 0 so that it appears on the attachment point + // and not in a weird location somewhere unknown. + if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) + { + attachPos = Vector3.Zero; + } + + // AttachmentPt 0 means the client chose to 'wear' the attachment. + if (attachmentPt == 0) + { + // Check object for stored attachment point + attachmentPt = group.AttachmentPoint; + } + + // if we still didn't find a suitable attachment point....... + if (attachmentPt == 0) + { + // Stick it on left hand with Zero Offset from the attachment point. + attachmentPt = (uint)AttachmentPoint.LeftHand; + attachPos = Vector3.Zero; + } + // Remove any previous attachments List existingAttachments = sp.GetAttachments(attachmentPt); // At the moment we can only deal with a single attachment if (existingAttachments.Count != 0 && existingAttachments[0].FromItemID != UUID.Zero) - DetachSingleAttachmentToInv(sp, group); + DetachSingleAttachmentToInv(sp, existingAttachments[0]); lock (sp.AttachmentsSyncLock) { - Vector3 attachPos = group.AbsolutePosition; - - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim - attachmentPt &= 0x7f; - - // If the attachment point isn't the same as the one previously used - // set it's offset position = 0 so that it appears on the attachment point - // and not in a weird location somewhere unknown. - if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) - { - attachPos = Vector3.Zero; - } - - // AttachmentPt 0 means the client chose to 'wear' the attachment. - if (attachmentPt == 0) - { - // Check object for stored attachment point - attachmentPt = group.AttachmentPoint; - } - - // if we still didn't find a suitable attachment point....... - if (attachmentPt == 0) - { - // Stick it on left hand with Zero Offset from the attachment point. - attachmentPt = (uint)AttachmentPoint.LeftHand; - attachPos = Vector3.Zero; - } - group.AttachmentPoint = attachmentPt; group.AbsolutePosition = attachPos; @@ -367,6 +372,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); AttachToAgent(sp, group, attachmentPt, attachPos, silent); + + if (resumeScripts) + { + // Fire after attach, so we don't get messy perms dialogs + // 4 == AttachedRez + group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); + group.ResumeScripts(); + } + + // Do this last so that event listeners have access to all the effects of the attachment + m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID); } return true; @@ -391,8 +407,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return null; // m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", -// (AttachmentPoint)AttachmentPt, itemID, sp.Name); +// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}", +// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name); // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should // be removed when that functionality is implemented in opensim @@ -525,6 +541,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return; } +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}", +// so.Name, so.LocalId, sp.Name, m_scene.Name); + // Scripts MUST be snapshotted before the object is // removed from the scene because doing otherwise will // clobber the run flag @@ -846,60 +866,42 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return null; } - // Remove any previous attachments - List attachments = sp.GetAttachments(attachmentPt); - - // At the moment we can only deal with a single attachment - if (attachments.Count != 0) - DetachSingleAttachmentToInv(sp, attachments[0]); - - lock (sp.AttachmentsSyncLock) - { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", // objatt.Name, sp.Name, attachmentPt, m_scene.Name); - // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. - objatt.HasGroupChanged = false; - bool tainted = false; - if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) - tainted = true; - - // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal - // course of events. If not, then it's probably not worth trying to recover the situation - // since this is more likely to trigger further exceptions and confuse later debugging. If - // exceptions can be thrown in expected error conditions (not NREs) then make this consistent - // since other normal error conditions will simply return false instead. - // This will throw if the attachment fails - try - { - AttachObjectInternal(sp, objatt, attachmentPt, false, false); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", - objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); - - // Make sure the object doesn't stick around and bail - sp.RemoveAttachment(objatt); - m_scene.DeleteSceneObject(objatt, false); - return null; - } - - if (tainted) - objatt.HasGroupChanged = true; + // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. + objatt.HasGroupChanged = false; + bool tainted = false; + if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) + tainted = true; + + // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal + // course of events. If not, then it's probably not worth trying to recover the situation + // since this is more likely to trigger further exceptions and confuse later debugging. If + // exceptions can be thrown in expected error conditions (not NREs) then make this consistent + // since other normal error conditions will simply return false instead. + // This will throw if the attachment fails + try + { + AttachObjectInternal(sp, objatt, attachmentPt, false, false, true); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", + objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); - // Fire after attach, so we don't get messy perms dialogs - // 4 == AttachedRez - objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); - objatt.ResumeScripts(); + // Make sure the object doesn't stick around and bail + sp.RemoveAttachment(objatt); + m_scene.DeleteSceneObject(objatt, false); + return null; + } - // Do this last so that event listeners have access to all the effects of the attachment - m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); + if (tainted) + objatt.HasGroupChanged = true; - return objatt; - } + return objatt; } /// diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 0ee01c7..624adcf 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -293,7 +293,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Check appearance status Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); - Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); // Check events @@ -301,6 +300,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests } /// + /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point + /// + [Test] + public void TestWearAttachmentFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20); + InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21); + + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem1.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test wearing a second attachment at the same position + // Until multiple attachments at one point is implemented, this will remove the first attachment + // This test relies on both attachments having the same default attachment point (in this case LeftHand + // since none other has been set). + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + } + + /// /// Test specific conditions associated with rezzing a scripted attachment from inventory. /// [Test] -- cgit v1.1 From 3611d33b00650ccc71994b331e4c6595f95d3131 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 18 Mar 2013 22:04:27 +0000 Subject: Improve rejection of any attempt to reattach an object that is already attached. This also adds/extends regression tests for wearing attachments directly for the scene and attempting to reattach/rewear already attached objects. --- .../Avatar/Attachments/AttachmentsModule.cs | 24 +-- .../Attachments/Tests/AttachmentsModuleTests.cs | 201 +++++++++++++++++++-- 2 files changed, 194 insertions(+), 31 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2092d6f..1c28f49 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -305,6 +305,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private bool AttachObjectInternal( IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool resumeScripts) { + if (sp.GetAttachments().Contains(group)) + { +// m_log.WarnFormat( +// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", +// group.Name, group.LocalId, sp.Name, AttachmentPt); + + return false; + } + // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", // group.Name, group.LocalId, sp.Name, attachmentPt, silent); @@ -318,15 +327,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return false; } - if (sp.GetAttachments(attachmentPt).Contains(group)) - { -// m_log.WarnFormat( -// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", -// group.Name, group.LocalId, sp.Name, AttachmentPt); - - return false; - } - Vector3 attachPos = group.AbsolutePosition; // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should @@ -336,13 +336,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // If the attachment point isn't the same as the one previously used // set it's offset position = 0 so that it appears on the attachment point // and not in a weird location somewhere unknown. - if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) + if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint) { attachPos = Vector3.Zero; } - // AttachmentPt 0 means the client chose to 'wear' the attachment. - if (attachmentPt == 0) + // AttachmentPt 0 (default) means the client chose to 'wear' the attachment. + if (attachmentPt == (uint)AttachmentPoint.Default) { // Check object for stored attachment point attachmentPt = group.AttachmentPoint; diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 624adcf..719a59c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); } + [Test] + public void TestWearAttachmentFromGround() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID); + + { + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID); + + m_numberOfAttachEventsFired = 0; + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status + Assert.That( + sp.Appearance.GetAttachpoint(attSo.FromItemID), + Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test wearing a different attachment from the ground. + { + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status + Assert.That( + sp.Appearance.GetAttachpoint(attSo.FromItemID), + Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + + // Test rewearing an already worn attachment from ground. Nothing should happen. + { + scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false); + + // Check status on scene presence + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(so2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check item status + Assert.That( + sp.Appearance.GetAttachpoint(attSo.FromItemID), + Is.EqualTo((int)AttachmentPoint.LeftHand)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } + } + /// /// Test that we do not attempt to attach an in-world object that someone else is sitting on. /// @@ -275,28 +389,54 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - m_numberOfAttachEventsFired = 0; - scene.AttachmentsModule.RezSingleAttachmentFromInventory( - sp, attItem.ID, (uint)AttachmentPoint.Chest); + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); - // Check scene presence status - Assert.That(sp.HasAttachments(), Is.True); - List attachments = sp.GetAttachments(); - Assert.That(attachments.Count, Is.EqualTo(1)); - SceneObjectGroup attSo = attachments[0]; - Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); - Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); - Assert.That(attSo.IsAttachment); - Assert.That(attSo.UsesPhysics, Is.False); - Assert.That(attSo.IsTemporary, Is.False); + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); - // Check appearance status - Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); - Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + // Check appearance status + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); - // Check events - Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } + + // Test attaching an already attached attachment + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); + } } /// @@ -316,6 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21); { + m_numberOfAttachEventsFired = 0; scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default); // default attachment point is currently the left hand. @@ -360,6 +501,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Check events Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); } + + // Test wearing an already attached attachment + { + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default); + + // default attachment point is currently the left hand. + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(attItem2.Name)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand)); + Assert.That(attSo.IsAttachment); + + // Check appearance status + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand)); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3)); + } } /// -- cgit v1.1