diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index 79d6fc58eb..3ac74fceb2 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -53,7 +53,7 @@ namespace OpenSim.Groups private ForeignImporter m_ForeignImporter; private Dictionary m_ActiveRequests = new Dictionary(); - private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes + private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes // This all important cache cahces objects of different types: // group- or group- => ExtendedGroupRecord diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index b399a58d92..496262970c 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -292,7 +292,7 @@ namespace OpenSim.Framework public Vector3 AtAxis; public Vector3 LeftAxis; public Vector3 UpAxis; - public bool ChangedGrid; + public bool SenderWantsToWaitForRoot; public float Far; public float Aspect; @@ -363,8 +363,9 @@ namespace OpenSim.Framework args["left_axis"] = OSD.FromString(LeftAxis.ToString()); args["up_axis"] = OSD.FromString(UpAxis.ToString()); - - args["changed_grid"] = OSD.FromBoolean(ChangedGrid); + //backwards compatibility + args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot); + args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot); args["far"] = OSD.FromReal(Far); args["aspect"] = OSD.FromReal(Aspect); @@ -537,8 +538,8 @@ namespace OpenSim.Framework if (args["up_axis"] != null) Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); - if (args["changed_grid"] != null) - ChangedGrid = args["changed_grid"].AsBoolean(); + if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null) + SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean(); if (args["far"] != null) Far = (float)(args["far"].AsReal()); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 7a4c6f4eb6..544b54b39e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1302,6 +1302,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP queue.Enqueue(buffer); return; } + else if (packet.Type == PacketType.CompleteAgentMovement) + { + // Send ack straight away to let the viewer know that we got it. + SendAckImmediate(endPoint, packet.Header.Sequence); + + // We need to copy the endpoint so that it doesn't get changed when another thread reuses the + // buffer. + object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; + + Util.FireAndForget(HandleCompleteMovementIntoRegion, array); + + return; + } } // Determine which agent this packet came from @@ -1676,6 +1689,72 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + private void HandleCompleteMovementIntoRegion(object o) + { + IPEndPoint endPoint = null; + IClientAPI client = null; + + try + { + object[] array = (object[])o; + endPoint = (IPEndPoint)array[0]; + CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; + + // Determine which agent this packet came from + int count = 20; + bool ready = false; + while (!ready && count-- > 0) + { + if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) + { + LLClientView llClientView = (LLClientView)client; + LLUDPClient udpClient = llClientView.UDPClient; + if (udpClient != null && udpClient.IsConnected) + ready = true; + else + { + m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + Thread.Sleep(200); + } + } + else + { + m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + Thread.Sleep(200); + } + } + + if (client == null) + return; + + IncomingPacket incomingPacket1; + + // Inbox insertion + if (UsePools) + { + incomingPacket1 = m_incomingPacketPool.GetObject(); + incomingPacket1.Client = (LLClientView)client; + incomingPacket1.Packet = packet; + } + else + { + incomingPacket1 = new IncomingPacket((LLClientView)client, packet); + } + + packetInbox.Enqueue(incomingPacket1); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", + endPoint != null ? endPoint.ToString() : "n/a", + client != null ? client.Name : "unknown", + client != null ? client.AgentId.ToString() : "unknown", + e.Message, + e.StackTrace); + } + } + /// /// Send an ack immediately to the given endpoint. /// diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index a3c539de1d..29b429616f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -689,6 +689,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } + if (version.Equals("SIMULATION/0.2")) + TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); + else + TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); + + } + + private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, + IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) + { + ulong destinationHandle = finalDestination.RegionHandle; + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Using TP V1"); // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; @@ -710,7 +724,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportCancels.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); return; @@ -732,11 +746,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // OK, it got this agent. Let's close some child agents sp.CloseChildAgents(newRegionX, newRegionY); - IClientIPEndpoint ipepClient; + IClientIPEndpoint ipepClient; + string capsPath = String.Empty; if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); @@ -783,10 +798,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); - agent.Position = position; + agent.Position = agentCircuit.startpos; SetCallbackURL(agent, sp.Scene.RegionInfo); - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to // establish th econnection to the destination which makes it return true. @@ -821,7 +835,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); return; } @@ -831,7 +845,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportCancels.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); @@ -848,6 +862,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // closes our existing agent which is still signalled as root. sp.IsChildAgent = true; + // OK, send TPFinish to the client, so that it starts the process of contacting the destination region if (m_eqModule != null) { m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); @@ -877,7 +892,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); return; @@ -906,13 +921,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { - // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before - // they regard the new region as the current region after receiving the AgentMovementComplete - // response. If close is sent before then, it will cause the viewer to quit instead. - // - // This sleep can be increased if necessary. However, whilst it's active, - // an agent cannot teleport back to this region if it has teleported away. - Thread.Sleep(3000); + // RED ALERT!!!! + // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. + // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion + // BEFORE THEY SETTLE IN THE NEW REGION. + // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR + // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. + Thread.Sleep(5000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } @@ -923,6 +938,134 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } + private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, + IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) + { + ulong destinationHandle = finalDestination.RegionHandle; + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + + // Let's create an agent there if one doesn't exist yet. + // NOTE: logout will always be false for a non-HG teleport. + bool logout = false; + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + { + m_interRegionTeleportFailures.Value++; + + sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", + sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); + + 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); + + IClientIPEndpoint ipepClient; + string capsPath = String.Empty; + if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", + finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); + + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); + #region IP Translation for NAT + // Uses ipepClient above + if (sp.ClientView.TryGet(out ipepClient)) + { + endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); + } + #endregion + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + else + { + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + + // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, + // where that neighbour simulator could otherwise request a child agent create on the source which then + // closes our existing agent which is still signalled as root. + //sp.IsChildAgent = true; + + // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid + if (m_eqModule != null) + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + else + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", + capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); + + // Let's send a full update of the agent. + AgentData agent = new AgentData(); + sp.CopyTo(agent); + agent.Position = agentCircuit.startpos; + agent.SenderWantsToWaitForRoot = true; + //SetCallbackURL(agent, sp.Scene.RegionInfo); + + // Send the Update. If this returns true, we know the client has contacted the destination + // via CompleteMovementIntoRegion, so we can let go. + // If it returns false, something went wrong, and we need to abort. + if (!UpdateAgent(reg, finalDestination, agent, sp)) + { + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) + { + m_interRegionTeleportAborts.Value++; + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", + sp.Name, finalDestination.RegionName, sp.Scene.Name); + + return; + } + + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", + sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + return; + } + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + + // May need to logout or other cleanup + AgentHasMovedAway(sp, logout); + + // Well, this is it. The agent is over there. + KillEntity(sp.Scene, sp.LocalId); + + // Now let's make it officially a child agent + sp.MakeChildAgent(); + + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone + + if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + { + // RED ALERT!!!! + // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. + // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion + // BEFORE THEY SETTLE IN THE NEW REGION. + // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR + // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. + Thread.Sleep(5000); + sp.Scene.IncomingCloseAgent(sp.UUID, false); + } + else + // now we have a child agent in this region. + sp.Reset(); + } + /// /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation. /// @@ -936,11 +1079,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - sp.IsChildAgent = false; - ReInstantiateScripts(sp); - - EnableChildAgents(sp); + if (sp.IsChildAgent) // We had set it to child before attempted TP (V1) + { + sp.IsChildAgent = false; + ReInstantiateScripts(sp); + EnableChildAgents(sp); + } // Finally, kill the agent we just created at the destination. // XXX: Possibly this should be done asynchronously. Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index 172bea10e3..516ad40fc7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs @@ -79,7 +79,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void OnConnectionClose(IClientAPI client) { - if (!client.SceneAgent.IsChildAgent) + if (client != null && client.SceneAgent != null && !client.SceneAgent.IsChildAgent) { // m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); m_PresenceService.LogoutAgent(client.SessionId); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 8207fb96cd..39657a370f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// /// Version of this service /// - private const string m_Version = "SIMULATION/0.1"; + private const string m_Version = "SIMULATION/0.2"; /// /// Map region ID to scene. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index c132c5d5e4..96e45edb50 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -230,6 +230,8 @@ namespace OpenSim.Region.Framework.Scenes public bool m_seeIntoBannedRegion = false; public int MaxUndoCount = 5; + public bool SeeIntoRegion { get; set; } + // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; public bool LoginLock = false; @@ -861,9 +863,11 @@ namespace OpenSim.Region.Framework.Scenes //Animation states m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); + + MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); + PhysicalPrims = startupConfig.GetBoolean("physical_prim", true); CollidablePrims = startupConfig.GetBoolean("collidable_prim", true); - m_minNonphys = startupConfig.GetFloat("NonPhysicalPrimMin", m_minNonphys); if (RegionInfo.NonphysPrimMin > 0) { @@ -3910,15 +3914,10 @@ namespace OpenSim.Region.Framework.Scenes try { - // Always check estate if this is a login. Always - // check if banned regions are to be blacked out. - if (vialogin || (!m_seeIntoBannedRegion)) + if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) { - if (!AuthorizeUser(agent, out reason)) - { - m_authenticateHandler.RemoveCircuit(agent.circuitcode); - return false; - } + m_authenticateHandler.RemoveCircuit(agent.circuitcode); + return false; } } catch (Exception e) @@ -4158,7 +4157,7 @@ namespace OpenSim.Region.Framework.Scenes /// outputs the reason to this string /// True if the region accepts this agent. False if it does not. False will /// also return a reason. - protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason) + protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason) { reason = String.Empty; @@ -4193,52 +4192,59 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); } - List agentGroups = new List(); - - if (m_groupsModule != null) + // We only test the things below when we want to cut off + // child agents from being present in the scene for which their root + // agent isn't allowed. Otherwise, we allow child agents. The test for + // the root is done elsewhere (QueryAccess) + if (!bypassAccessControl) { - GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + List agentGroups = new List(); - if (GroupMembership != null) + if (m_groupsModule != null) { - for (int i = 0; i < GroupMembership.Length; i++) - agentGroups.Add(GroupMembership[i].GroupID); + GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + + if (GroupMembership != null) + { + for (int i = 0; i < GroupMembership.Length; i++) + agentGroups.Add(GroupMembership[i].GroupID); + } + else + { + m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); + } + } + + bool groupAccess = false; + UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; + + if (estateGroups != null) + { + foreach (UUID group in estateGroups) + { + if (agentGroups.Contains(group)) + { + groupAccess = true; + break; + } + } } else { - m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); + m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); } - } - bool groupAccess = false; - UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; - - if (estateGroups != null) - { - foreach (UUID group in estateGroups) + if (!RegionInfo.EstateSettings.PublicAccess && + !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && + !groupAccess) { - if (agentGroups.Contains(group)) - { - groupAccess = true; - break; - } + m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", + agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); + reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", + RegionInfo.RegionName); + return false; } } - else - { - m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); - } - - if (!RegionInfo.EstateSettings.PublicAccess && - !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && - !groupAccess) - { - m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", - agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", - RegionInfo.RegionName); - return false; - } // TODO: estate/region settings are not properly hooked up // to ILandObject.isRestrictedFromLand() @@ -4402,6 +4408,20 @@ namespace OpenSim.Region.Framework.Scenes } childAgentUpdate.ChildAgentDataUpdate(cAgentData); + + int ntimes = 20; + if (cAgentData.SenderWantsToWaitForRoot) + { + while (childAgentUpdate.IsChildAgent && ntimes-- > 0) + Thread.Sleep(1000); + + m_log.DebugFormat( + "[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits", + childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes); + + if (childAgentUpdate.IsChildAgent) + return false; + } return true; } return false; @@ -4459,10 +4479,6 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout", agentID, RegionInfo.RegionName); -// else -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits", -// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes); return sp; } @@ -5873,7 +5889,7 @@ Environment.Exit(1); try { - if (!AuthorizeUser(aCircuit, out reason)) + if (!AuthorizeUser(aCircuit, false, out reason)) { // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); return false; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 1225c2e1df..c78fe628c1 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -29,7 +29,9 @@ using System; using System.Xml; using System.Collections.Generic; using System.Reflection; +using System.Threading; using System.Timers; +using Timer = System.Timers.Timer; using OpenMetaverse; using log4net; using Nini.Config; @@ -1154,9 +1156,8 @@ namespace OpenSim.Region.Framework.Scenes MovementFlag = 0; - // DIVA NOTE: I moved TriggerOnMakeRootAgent out of here and into the end of - // CompleteMovement. We don't want modules doing heavy computation before CompleteMovement - // is over. + m_scene.EventManager.TriggerOnMakeRootAgent(this); + } public int GetStateSource() @@ -1502,6 +1503,26 @@ namespace OpenSim.Region.Framework.Scenes } + private bool WaitForUpdateAgent(IClientAPI client) + { + // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero + int count = 20; + while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) + { + m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.RegionInfo.RegionName); + Thread.Sleep(200); + } + + if (m_originRegionID.Equals(UUID.Zero)) + { + // Movement into region will fail + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived", client.Name); + return false; + } + + return true; + } + /// /// Complete Avatar's movement into the region. /// @@ -1519,6 +1540,13 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); + // Make sure it's not a login agent. We don't want to wait for updates during login + if ((m_teleportFlags & TeleportFlags.ViaLogin) == 0) + // Let's wait until UpdateAgent (called by departing region) is done + if (!WaitForUpdateAgent(client)) + // The sending region never sent the UpdateAgent data, we have to refuse + return; + Vector3 look = Velocity; // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) @@ -1540,10 +1568,11 @@ namespace OpenSim.Region.Framework.Scenes bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); MakeRootAgent(AbsolutePosition, flying); + + // Tell the client that we're totally ready ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + // Remember in HandleUseCircuitCode, we delayed this to here - // This will also send the initial data to clients when TP to a neighboring region. - // Not ideal, but until we know we're TP-ing from a neighboring region, there's not much we can do if (m_teleportFlags > 0) SendInitialDataToMe(); @@ -1600,10 +1629,6 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); - // DIVA NOTE: moved this here from MakeRoot. We don't want modules making heavy - // computations before CompleteMovement is over - m_scene.EventManager.TriggerOnMakeRootAgent(this); - } /// diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 8055886ba5..57bc79ec54 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -86,6 +86,13 @@ ;; from the selected region_info_source. allow_regionless = false + ;; Allow child agents to see into the region even if their root counterpart isn't allowed in here + see_into_region = true + + ; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos + ; Increasing this number will increase memory usage. + MaxPrimUndos = 20 + ; Maximum size of non physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonPhysicalPrimMax!). NonPhysicalPrimMax = 256