From cecb446e0e91ede0b05ea9cf40c1313782241f3d Mon Sep 17 00:00:00 2001 From: Kunta Kinte Date: Tue, 29 Apr 2014 07:26:07 -0700 Subject: fix infinite recursion loop in SendGridInstantMessageViaXMLRPCAsync() --- .../Avatar/InstantMessage/MessageTransferModule.cs | 178 +++++++++------------ 1 file changed, 79 insertions(+), 99 deletions(-) (limited to 'OpenSim/Region/CoreModules/Avatar') diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 40a400f..4f8e2cd 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// /// delegate for sending a grid instant message asynchronously /// - public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); + public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); protected virtual void GridInstantMessageCompleted(IAsyncResult iar) { @@ -442,138 +442,118 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; - d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); + d.BeginInvoke(im, result, GridInstantMessageCompleted, d); } /// - /// Recursive SendGridInstantMessage over XMLRPC method. + /// Internal SendGridInstantMessage over XMLRPC method. /// This is called from within a dedicated thread. - /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from - /// itself, prevRegionHandle will be the last region handle that we tried to send. - /// If the handles are the same, we look up the user's location using the grid. - /// If the handles are still the same, we end. The send failed. /// - /// - /// Pass in 0 the first time this method is called. It will be called recursively with the last - /// regionhandle tried - /// - protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) + private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) { UUID toAgentID = new UUID(im.toAgentID); + UUID regionID; + bool lookupAgent; - PresenceInfo upd = null; - - bool lookupAgent = false; - + /* + * Try to get what region the agent is in from the cache. + */ lock (m_UserRegionMap) { - if (m_UserRegionMap.ContainsKey(toAgentID)) - { - upd = new PresenceInfo(); - upd.RegionID = m_UserRegionMap[toAgentID]; - - // We need to compare the current regionhandle with the previous region handle - // or the recursive loop will never end because it will never try to lookup the agent again - if (prevRegionID == upd.RegionID) - { - lookupAgent = true; - } - } - else - { - lookupAgent = true; - } + lookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); } - - // Are we needing to look-up an agent? - if (lookupAgent) + while (true) { - // Non-cached user agent lookup. - PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); - if (presences != null && presences.Length > 0) + + /* + * If not in cache, try to find out what region the agent is in. + * Also do this if we know the existing cache entry is bad. + */ + if (lookupAgent) { - foreach (PresenceInfo p in presences) + PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); + + regionID = UUID.Zero; + if (presences != null) { - if (p.RegionID != UUID.Zero) + foreach (PresenceInfo p in presences) { - upd = p; - break; + if (p.RegionID != UUID.Zero) + { + regionID = p.RegionID; + break; + } } } - } - if (upd != null) - { - // check if we've tried this before.. - // This is one way to end the recursive loop - // - if (upd.RegionID == prevRegionID) + // If not found, message is undeliverable + if (regionID == UUID.Zero) { - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliveredMessage(im, result); - return; + break; } } - else + + /* + * Try to find out about region. + * If unable, message is undeliverable. + */ + GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); + if (reginfo == null) { - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliveredMessage(im, result); - return; + m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); + break; } - } - if (upd != null) - { - GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, - upd.RegionID); - if (reginfo != null) + /* + * Try to send message to agent in the region. + */ + Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); + msgdata["region_handle"] = 0; + bool imresult = doIMSending(reginfo, msgdata); + + /* + * If message delivery successful, save cache entry because we know it is good. + * Then tell caller message has been delivered and we are done. + */ + if (imresult) { - Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); - // Not actually used anymore, left in for compatibility - // Remove at next interface change - // - msgdata["region_handle"] = 0; - bool imresult = doIMSending(reginfo, msgdata); - if (imresult) - { - // IM delivery successful, so store the Agent's location in our local cache. - lock (m_UserRegionMap) - { - if (m_UserRegionMap.ContainsKey(toAgentID)) - { - m_UserRegionMap[toAgentID] = upd.RegionID; - } - else - { - m_UserRegionMap.Add(toAgentID, upd.RegionID); - } - } - result(true); - } - else + lock (m_UserRegionMap) { - // try again, but lookup user this time. - // Warning, this must call the Async version - // of this method or we'll be making thousands of threads - // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync - // The version that spawns the thread is SendGridInstantMessageViaXMLRPC - - // This is recursive!!!!! - SendGridInstantMessageViaXMLRPCAsync(im, result, - upd.RegionID); + m_UserRegionMap[toAgentID] = regionID; } + result(true); + return; } - else + + /* + * Message delivery failed. + * If we just looked up what region the agent is in, message is undeliverable. + */ + if (lookupAgent) { - m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); - HandleUndeliveredMessage(im, result); + break; } + + /* + * We used a cached entry that we now know is bad. + * Try again by searching the grid for the user. + */ + lookupAgent = true; } - else + + /* + * Message is undeliverable for one reason or another. + * Remove possible bad entry from cache. + * Then inform caller that the message is undeliverable. + */ + lock (m_UserRegionMap) { - HandleUndeliveredMessage(im, result); + m_UserRegionMap.Remove(toAgentID); } + + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliveredMessage(im, result); } /// -- cgit v1.1