aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs457
1 files changed, 256 insertions, 201 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index ed88571..fb2decc 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -80,6 +80,11 @@ namespace OpenSim.Region.Framework.Scenes
80 public SynchronizeSceneHandler SynchronizeScene; 80 public SynchronizeSceneHandler SynchronizeScene;
81 81
82 /// <summary> 82 /// <summary>
83 /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other.
84 /// </summary>
85 private object m_removeClientLock = new object();
86
87 /// <summary>
83 /// Statistical information for this scene. 88 /// Statistical information for this scene.
84 /// </summary> 89 /// </summary>
85 public SimStatsReporter StatsReporter { get; private set; } 90 public SimStatsReporter StatsReporter { get; private set; }
@@ -2709,69 +2714,89 @@ namespace OpenSim.Region.Framework.Scenes
2709 2714
2710 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) 2715 public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
2711 { 2716 {
2717 ScenePresence sp;
2718 bool vialogin;
2719
2712 // Validation occurs in LLUDPServer 2720 // Validation occurs in LLUDPServer
2721 //
2722 // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with
2723 // each other. In practice, this does not currently occur in the code.
2713 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); 2724 AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode);
2714 2725
2715 bool vialogin 2726 // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection
2716 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 2727 // and a simultaneous one that removes it (as can happen if the client is closed at a particular point
2717 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2728 // whilst connecting).
2718 2729 //
2719// CheckHeartbeat(); 2730 // It would be easier to lock across all NewUserConnection(), AddNewClient() and
2720 2731 // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service
2721 ScenePresence sp = GetScenePresence(client.AgentId); 2732 // response in some module listening to AddNewClient()) from holding up unrelated agent calls.
2722 2733 //
2723 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this 2734 // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all
2724 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause 2735 // AddNewClient() operations (though not other ops).
2725 // other problems, and possible the code calling AddNewClient() should ensure that no client is already 2736 // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved.
2726 // connected. 2737 lock (aCircuit)
2727 if (sp == null) 2738 {
2728 { 2739 vialogin
2729 m_log.DebugFormat( 2740 = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0
2730 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", 2741 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2731 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); 2742
2732 2743 // CheckHeartbeat();
2733 m_clientManager.Add(client); 2744
2734 SubscribeToClientEvents(client); 2745 sp = GetScenePresence(client.AgentId);
2735
2736 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2737 m_eventManager.TriggerOnNewPresence(sp);
2738
2739 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2740 2746
2741 // The first agent upon login is a root agent by design. 2747 // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this
2742 // For this agent we will have to rez the attachments. 2748 // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause
2743 // All other AddNewClient calls find aCircuit.child to be true. 2749 // other problems, and possible the code calling AddNewClient() should ensure that no client is already
2744 if (aCircuit.child == false) 2750 // connected.
2751 if (sp == null)
2745 { 2752 {
2746 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to 2753 m_log.DebugFormat(
2747 // start the scripts again (since this is done in RezAttachments()). 2754 "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}",
2748 // XXX: This is convoluted. 2755 client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos);
2749 sp.IsChildAgent = false; 2756
2750 2757 m_clientManager.Add(client);
2751 if (AttachmentsModule != null) 2758 SubscribeToClientEvents(client);
2752 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); 2759
2760 sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
2761 m_eventManager.TriggerOnNewPresence(sp);
2762
2763 sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
2764
2765 // The first agent upon login is a root agent by design.
2766 // For this agent we will have to rez the attachments.
2767 // All other AddNewClient calls find aCircuit.child to be true.
2768 if (aCircuit.child == false)
2769 {
2770 // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to
2771 // start the scripts again (since this is done in RezAttachments()).
2772 // XXX: This is convoluted.
2773 sp.IsChildAgent = false;
2774
2775 if (AttachmentsModule != null)
2776 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
2777 }
2753 } 2778 }
2754 } 2779 else
2755 else 2780 {
2756 { 2781 m_log.WarnFormat(
2757 m_log.WarnFormat( 2782 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence",
2758 "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", 2783 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
2759 sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); 2784 }
2760 } 2785
2786 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
2787 // client is for a root or child agent.
2788 client.SceneAgent = sp;
2761 2789
2762 // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the 2790 // Cache the user's name
2763 // client is for a root or child agent. 2791 CacheUserName(sp, aCircuit);
2764 client.SceneAgent = sp; 2792
2793 EventManager.TriggerOnNewClient(client);
2794 if (vialogin)
2795 EventManager.TriggerOnClientLogin(client);
2796 }
2765 2797
2766 m_LastLogin = Util.EnvironmentTickCount(); 2798 m_LastLogin = Util.EnvironmentTickCount();
2767 2799
2768 // Cache the user's name
2769 CacheUserName(sp, aCircuit);
2770
2771 EventManager.TriggerOnNewClient(client);
2772 if (vialogin)
2773 EventManager.TriggerOnClientLogin(client);
2774
2775 return sp; 2800 return sp;
2776 } 2801 }
2777 2802
@@ -3300,109 +3325,129 @@ namespace OpenSim.Region.Framework.Scenes
3300 { 3325 {
3301// CheckHeartbeat(); 3326// CheckHeartbeat();
3302 bool isChildAgent = false; 3327 bool isChildAgent = false;
3303 ScenePresence avatar = GetScenePresence(agentID); 3328 AgentCircuitData acd;
3304
3305 if (avatar == null)
3306 {
3307 m_log.WarnFormat(
3308 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3309
3310 return;
3311 }
3312 3329
3313 try 3330 lock (m_removeClientLock)
3314 { 3331 {
3315 isChildAgent = avatar.IsChildAgent; 3332 acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3316
3317 m_log.DebugFormat(
3318 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3319 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3320 3333
3321 // Don't do this to root agents, it's not nice for the viewer 3334 if (acd == null)
3322 if (closeChildAgents && isChildAgent)
3323 { 3335 {
3324 // Tell a single agent to disconnect from the region. 3336 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID);
3325 IEventQueue eq = RequestModuleInterface<IEventQueue>(); 3337 return;
3326 if (eq != null)
3327 {
3328 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3329 }
3330 else
3331 {
3332 avatar.ControllingClient.SendShutdownConnectionNotice();
3333 }
3334 } 3338 }
3335 3339 else
3336 // Only applies to root agents.
3337 if (avatar.ParentID != 0)
3338 { 3340 {
3339 avatar.StandUp(); 3341 // We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred
3342 // simultaneously.
3343 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3340 } 3344 }
3345 }
3341 3346
3342 m_sceneGraph.removeUserCount(!isChildAgent); 3347 lock (acd)
3343 3348 {
3344 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop 3349 ScenePresence avatar = GetScenePresence(agentID);
3345 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI 3350
3346 if (closeChildAgents && CapsModule != null) 3351 if (avatar == null)
3347 CapsModule.RemoveCaps(agentID);
3348
3349 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3350 // this method is doing is HORRIBLE!!!
3351 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3352
3353 if (closeChildAgents && !isChildAgent)
3354 { 3352 {
3355 List<ulong> regions = avatar.KnownRegionHandles; 3353 m_log.WarnFormat(
3356 regions.Remove(RegionInfo.RegionHandle); 3354 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3357 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3355
3356 return;
3358 } 3357 }
3359 3358
3360 m_eventManager.TriggerClientClosed(agentID, this); 3359 try
3361 m_eventManager.TriggerOnRemovePresence(agentID);
3362
3363 if (!isChildAgent)
3364 { 3360 {
3365 if (AttachmentsModule != null) 3361 isChildAgent = avatar.IsChildAgent;
3362
3363 m_log.DebugFormat(
3364 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3365 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName);
3366
3367 // Don't do this to root agents, it's not nice for the viewer
3368 if (closeChildAgents && isChildAgent)
3366 { 3369 {
3367 AttachmentsModule.DeRezAttachments(avatar); 3370 // Tell a single agent to disconnect from the region.
3371 IEventQueue eq = RequestModuleInterface<IEventQueue>();
3372 if (eq != null)
3373 {
3374 eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID);
3375 }
3376 else
3377 {
3378 avatar.ControllingClient.SendShutdownConnectionNotice();
3379 }
3368 } 3380 }
3369 3381
3370 ForEachClient( 3382 // Only applies to root agents.
3371 delegate(IClientAPI client) 3383 if (avatar.ParentID != 0)
3384 {
3385 avatar.StandUp();
3386 }
3387
3388 m_sceneGraph.removeUserCount(!isChildAgent);
3389
3390 // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
3391 // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
3392 if (closeChildAgents && CapsModule != null)
3393 CapsModule.RemoveCaps(agentID);
3394
3395 // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever
3396 // this method is doing is HORRIBLE!!!
3397 avatar.Scene.NeedSceneCacheClear(avatar.UUID);
3398
3399 if (closeChildAgents && !isChildAgent)
3400 {
3401 List<ulong> regions = avatar.KnownRegionHandles;
3402 regions.Remove(RegionInfo.RegionHandle);
3403 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3404 }
3405
3406 m_eventManager.TriggerClientClosed(agentID, this);
3407 m_eventManager.TriggerOnRemovePresence(agentID);
3408
3409 if (!isChildAgent)
3410 {
3411 if (AttachmentsModule != null)
3372 { 3412 {
3373 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3413 AttachmentsModule.DeRezAttachments(avatar);
3374 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } 3414 }
3375 catch (NullReferenceException) { }
3376 });
3377 }
3378
3379 // It's possible for child agents to have transactions if changes are being made cross-border.
3380 if (AgentTransactionsModule != null)
3381 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3382 3415
3383 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3416 ForEachClient(
3384 } 3417 delegate(IClientAPI client)
3385 catch (Exception e) 3418 {
3386 { 3419 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3387 m_log.Error( 3420 try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); }
3388 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e); 3421 catch (NullReferenceException) { }
3389 } 3422 });
3390 finally 3423 }
3391 {
3392 try
3393 {
3394 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3395 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3396 // the same cleanup exception continually.
3397 m_sceneGraph.RemoveScenePresence(agentID);
3398 m_clientManager.Remove(agentID);
3399 3424
3400 avatar.Close(); 3425 // It's possible for child agents to have transactions if changes are being made cross-border.
3426 if (AgentTransactionsModule != null)
3427 AgentTransactionsModule.RemoveAgentAssetTransactions(agentID);
3401 } 3428 }
3402 catch (Exception e) 3429 catch (Exception e)
3403 { 3430 {
3404 m_log.Error( 3431 m_log.Error(
3405 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); 3432 string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e);
3433 }
3434 finally
3435 {
3436 try
3437 {
3438 // Always clean these structures up so that any failure above doesn't cause them to remain in the
3439 // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering
3440 // the same cleanup exception continually.
3441 m_sceneGraph.RemoveScenePresence(agentID);
3442 m_clientManager.Remove(agentID);
3443
3444 avatar.Close();
3445 }
3446 catch (Exception e)
3447 {
3448 m_log.Error(
3449 string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e);
3450 }
3406 } 3451 }
3407 } 3452 }
3408 3453
@@ -3572,87 +3617,97 @@ namespace OpenSim.Region.Framework.Scenes
3572 agent.firstname, agent.lastname, agent.Viewer); 3617 agent.firstname, agent.lastname, agent.Viewer);
3573 reason = "Access denied, your viewer is banned by the region owner"; 3618 reason = "Access denied, your viewer is banned by the region owner";
3574 return false; 3619 return false;
3575 }
3576
3577 ScenePresence sp = GetScenePresence(agent.AgentID);
3578
3579 if (sp != null && !sp.IsChildAgent)
3580 {
3581 // We have a zombie from a crashed session.
3582 // Or the same user is trying to be root twice here, won't work.
3583 // Kill it.
3584 m_log.WarnFormat(
3585 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3586 sp.Name, sp.UUID, RegionInfo.RegionName);
3587
3588 sp.ControllingClient.Close(true);
3589 sp = null;
3590 } 3620 }
3591 3621
3592 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); 3622 ILandObject land;
3593 3623
3594 //On login test land permisions 3624 lock (agent)
3595 if (vialogin)
3596 { 3625 {
3597 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3626 ScenePresence sp = GetScenePresence(agent.AgentID);
3627
3628 if (sp != null && !sp.IsChildAgent)
3598 { 3629 {
3599 return false; 3630 // We have a zombie from a crashed session.
3631 // Or the same user is trying to be root twice here, won't work.
3632 // Kill it.
3633 m_log.WarnFormat(
3634 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3635 sp.Name, sp.UUID, RegionInfo.RegionName);
3636
3637 sp.ControllingClient.Close(true);
3638 sp = null;
3600 } 3639 }
3601 } 3640
3602 3641 land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3603 if (sp == null) // We don't have an [child] agent here already 3642
3604 { 3643 //On login test land permisions
3605 if (requirePresenceLookup) 3644 if (vialogin)
3606 { 3645 {
3607 try 3646 if (land != null && !TestLandRestrictions(agent, land, out reason))
3608 {
3609 if (!VerifyUserPresence(agent, out reason))
3610 return false;
3611 } catch (Exception e)
3612 { 3647 {
3613 m_log.ErrorFormat(
3614 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3615 return false; 3648 return false;
3616 } 3649 }
3617 } 3650 }
3618 3651
3619 try 3652 if (sp == null) // We don't have an [child] agent here already
3620 {
3621 if (!AuthorizeUser(agent, out reason))
3622 return false;
3623 } catch (Exception e)
3624 {
3625 m_log.ErrorFormat(
3626 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3627 return false;
3628 }
3629
3630 m_log.InfoFormat(
3631 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3632 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3633 agent.AgentID, agent.circuitcode);
3634
3635 if (CapsModule != null)
3636 { 3653 {
3637 CapsModule.SetAgentCapsSeeds(agent); 3654 if (requirePresenceLookup)
3638 CapsModule.CreateCaps(agent.AgentID); 3655 {
3639 } 3656 try
3640 } else 3657 {
3641 { 3658 if (!VerifyUserPresence(agent, out reason))
3642 // Let the SP know how we got here. This has a lot of interesting 3659 return false;
3643 // uses down the line. 3660 }
3644 sp.TeleportFlags = (TPFlags)teleportFlags; 3661 catch (Exception e)
3662 {
3663 m_log.ErrorFormat(
3664 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3645 3665
3646 if (sp.IsChildAgent) 3666 return false;
3647 { 3667 }
3648 m_log.DebugFormat( 3668 }
3649 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", 3669
3650 agent.AgentID, RegionInfo.RegionName); 3670 try
3671 {
3672 if (!AuthorizeUser(agent, out reason))
3673 return false;
3674 }
3675 catch (Exception e)
3676 {
3677 m_log.ErrorFormat(
3678 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3651 3679
3652 sp.AdjustKnownSeeds(); 3680 return false;
3653 3681 }
3682
3683 m_log.InfoFormat(
3684 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3685 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname,
3686 agent.AgentID, agent.circuitcode);
3687
3654 if (CapsModule != null) 3688 if (CapsModule != null)
3689 {
3655 CapsModule.SetAgentCapsSeeds(agent); 3690 CapsModule.SetAgentCapsSeeds(agent);
3691 CapsModule.CreateCaps(agent.AgentID);
3692 }
3693 }
3694 else
3695 {
3696 // Let the SP know how we got here. This has a lot of interesting
3697 // uses down the line.
3698 sp.TeleportFlags = (TPFlags)teleportFlags;
3699
3700 if (sp.IsChildAgent)
3701 {
3702 m_log.DebugFormat(
3703 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3704 agent.AgentID, RegionInfo.RegionName);
3705
3706 sp.AdjustKnownSeeds();
3707
3708 if (CapsModule != null)
3709 CapsModule.SetAgentCapsSeeds(agent);
3710 }
3656 } 3711 }
3657 } 3712 }
3658 3713