diff options
author | Justin Clark-Casey (justincc) | 2012-07-19 22:32:27 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-07-19 22:32:27 +0100 |
commit | ba80f137b58cfacf46fadb3ec8b63af6896c5b43 (patch) | |
tree | f7f4ff7132cac0fb35adf19cf9e35143f3eaf155 | |
parent | Add TestCreateDuplicateRootScenePresence() regression test. (diff) | |
download | opensim-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.cs | 58 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 29 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 6 |
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> |