aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-07-19 22:32:27 +0100
committerJustin Clark-Casey (justincc)2012-07-19 22:32:27 +0100
commitba80f137b58cfacf46fadb3ec8b63af6896c5b43 (patch)
treef7f4ff7132cac0fb35adf19cf9e35143f3eaf155
parentAdd TestCreateDuplicateRootScenePresence() regression test. (diff)
downloadopensim-SC_OLD-ba80f137b58cfacf46fadb3ec8b63af6896c5b43.zip
opensim-SC_OLD-ba80f137b58cfacf46fadb3ec8b63af6896c5b43.tar.gz
opensim-SC_OLD-ba80f137b58cfacf46fadb3ec8b63af6896c5b43.tar.bz2
opensim-SC_OLD-ba80f137b58cfacf46fadb3ec8b63af6896c5b43.tar.xz
Prevent race conditions between two threads that call LLClientView.Close() simultaneously (e.g. ack timeout and an attempt to reconnect)
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs58
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs29
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs6
3 files changed, 60 insertions, 33 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 73cdec3..ae5207b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -347,8 +347,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
347 private int m_animationSequenceNumber = 1; 347 private int m_animationSequenceNumber = 1;
348 private bool m_SendLogoutPacketWhenClosing = true; 348 private bool m_SendLogoutPacketWhenClosing = true;
349 private AgentUpdateArgs lastarg; 349 private AgentUpdateArgs lastarg;
350 private bool m_IsActive = true;
351 private bool m_IsLoggingOut = false;
352 350
353 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 351 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
354 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 352 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -412,16 +410,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
412 public uint CircuitCode { get { return m_circuitCode; } } 410 public uint CircuitCode { get { return m_circuitCode; } }
413 public int MoneyBalance { get { return m_moneyBalance; } } 411 public int MoneyBalance { get { return m_moneyBalance; } }
414 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } 412 public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } }
415 public bool IsActive 413
416 { 414 /// <summary>
417 get { return m_IsActive; } 415 /// As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to
418 set { m_IsActive = value; } 416 /// prevent race conditions by different threads calling Close().
419 } 417 /// </summary>
420 public bool IsLoggingOut 418 public bool IsActive { get; set; }
421 { 419
422 get { return m_IsLoggingOut; } 420 /// <summary>
423 set { m_IsLoggingOut = value; } 421 /// Used to synchronise threads when client is being closed.
424 } 422 /// </summary>
423 public Object CloseSyncLock { get; private set; }
424
425 public bool IsLoggingOut { get; set; }
425 426
426 public bool DisableFacelights 427 public bool DisableFacelights
427 { 428 {
@@ -446,6 +447,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
446 { 447 {
447// DebugPacketLevel = 1; 448// DebugPacketLevel = 1;
448 449
450 CloseSyncLock = new Object();
451
449 RegisterInterface<IClientIM>(this); 452 RegisterInterface<IClientIM>(this);
450 RegisterInterface<IClientInventory>(this); 453 RegisterInterface<IClientInventory>(this);
451 RegisterInterface<IClientChat>(this); 454 RegisterInterface<IClientChat>(this);
@@ -478,17 +481,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
478 m_prioritizer = new Prioritizer(m_scene); 481 m_prioritizer = new Prioritizer(m_scene);
479 482
480 RegisterLocalPacketHandlers(); 483 RegisterLocalPacketHandlers();
484
485 IsActive = true;
481 } 486 }
482 487
483 #region Client Methods 488 #region Client Methods
484 489
485 /// <summary> 490 /// <summary>
486 /// Shut down the client view 491 /// Close down the client view
487 /// </summary> 492 /// </summary>
488 public void Close() 493 public void Close()
489 { 494 {
490 IsActive = false; 495 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
496 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
497 lock (CloseSyncLock)
498 {
499 if (!IsActive)
500 return;
501
502 IsActive = false;
503 CloseWithoutChecks();
504 }
505 }
491 506
507 /// <summary>
508 /// Closes down the client view without first checking whether it is active.
509 /// </summary>
510 /// <remarks>
511 /// This exists because LLUDPServer has to set IsActive = false in earlier synchronous code before calling
512 /// CloseWithoutIsActiveCheck asynchronously.
513 ///
514 /// Callers must lock ClosingSyncLock before calling.
515 /// </remarks>
516 public void CloseWithoutChecks()
517 {
492 m_log.DebugFormat( 518 m_log.DebugFormat(
493 "[CLIENT]: Close has been called for {0} attached to scene {1}", 519 "[CLIENT]: Close has been called for {0} attached to scene {1}",
494 Name, m_scene.RegionInfo.RegionName); 520 Name, m_scene.RegionInfo.RegionName);
@@ -3567,7 +3593,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3567 3593
3568 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations) 3594 public void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations)
3569 { 3595 {
3570 if (!IsActive) return; // We don't need to update inactive clients. 3596 // We don't need to update inactive clients.
3597 if (!IsActive)
3598 return;
3571 3599
3572 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate); 3600 CoarseLocationUpdatePacket loc = (CoarseLocationUpdatePacket)PacketPool.Instance.GetPacket(PacketType.CoarseLocationUpdate);
3573 loc.Header.Reliable = false; 3601 loc.Header.Reliable = false;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 097f109..746eb90 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -1123,22 +1123,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1123 /// regular client pings. 1123 /// regular client pings.
1124 /// </remarks> 1124 /// </remarks>
1125 /// <param name='client'></param> 1125 /// <param name='client'></param>
1126 private void DeactivateClientDueToTimeout(IClientAPI client) 1126 private void DeactivateClientDueToTimeout(LLClientView client)
1127 { 1127 {
1128 // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even 1128 lock (client.CloseSyncLock)
1129 // though it's set later on by LLClientView.Close() 1129 {
1130 client.IsActive = false; 1130 m_log.WarnFormat(
1131 1131 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
1132 m_log.WarnFormat( 1132 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
1133 "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", 1133
1134 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); 1134 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
1135 1135
1136 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); 1136 if (!client.SceneAgent.IsChildAgent)
1137 1137 client.Kick("Simulator logged you out due to connection timeout");
1138 if (!client.SceneAgent.IsChildAgent) 1138
1139 client.Kick("Simulator logged you out due to connection timeout"); 1139 client.CloseWithoutChecks();
1140 1140 }
1141 client.Close();
1142 } 1141 }
1143 1142
1144 private void IncomingPacketHandler() 1143 private void IncomingPacketHandler()
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 36452de..51a6820 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3517,8 +3517,8 @@ namespace OpenSim.Region.Framework.Scenes
3517 // We have a zombie from a crashed session. 3517 // We have a zombie from a crashed session.
3518 // Or the same user is trying to be root twice here, won't work. 3518 // Or the same user is trying to be root twice here, won't work.
3519 // Kill it. 3519 // Kill it.
3520 m_log.DebugFormat( 3520 m_log.WarnFormat(
3521 "[SCENE]: Zombie scene presence detected for {0} {1} in {2}", 3521 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3522 sp.Name, sp.UUID, RegionInfo.RegionName); 3522 sp.Name, sp.UUID, RegionInfo.RegionName);
3523 3523
3524 sp.ControllingClient.Close(); 3524 sp.ControllingClient.Close();
@@ -4474,7 +4474,7 @@ namespace OpenSim.Region.Framework.Scenes
4474 /// </summary> 4474 /// </summary>
4475 /// <remarks> 4475 /// <remarks>
4476 /// This method will return both root and child scene presences. 4476 /// This method will return both root and child scene presences.
4477 /// 4477 ///
4478 /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not 4478 /// Consider using ForEachScenePresence() or ForEachRootScenePresence() if possible since these will not
4479 /// involving creating a new List object. 4479 /// involving creating a new List object.
4480 /// </remarks> 4480 /// </remarks>