fix infinite recursion loop in SendGridInstantMessageViaXMLRPCAsync()

0.8.0.3
Kunta Kinte 2014-04-29 07:26:07 -07:00 committed by Justin Clark-Casey (justincc)
parent 0faba7dc33
commit cecb446e0e
1 changed files with 84 additions and 104 deletions

View File

@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
/// <summary> /// <summary>
/// delegate for sending a grid instant message asynchronously /// delegate for sending a grid instant message asynchronously
/// </summary> /// </summary>
public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
protected virtual void GridInstantMessageCompleted(IAsyncResult iar) protected virtual void GridInstantMessageCompleted(IAsyncResult iar)
{ {
@ -442,138 +442,118 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{ {
GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync;
d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
} }
/// <summary> /// <summary>
/// Recursive SendGridInstantMessage over XMLRPC method. /// Internal SendGridInstantMessage over XMLRPC method.
/// This is called from within a dedicated thread. /// 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.
/// </summary> /// </summary>
/// <param name="prevRegionHandle"> private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result)
/// Pass in 0 the first time this method is called. It will be called recursively with the last
/// regionhandle tried
/// </param>
protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
{ {
UUID toAgentID = new UUID(im.toAgentID); UUID toAgentID = new UUID(im.toAgentID);
UUID regionID;
bool lookupAgent;
PresenceInfo upd = null; /*
* Try to get what region the agent is in from the cache.
bool lookupAgent = false; */
lock (m_UserRegionMap) lock (m_UserRegionMap)
{ {
if (m_UserRegionMap.ContainsKey(toAgentID)) lookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID);
{
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;
}
} }
while (true)
{
// Are we needing to look-up an agent? /*
* 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) if (lookupAgent)
{ {
// Non-cached user agent lookup.
PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
if (presences != null && presences.Length > 0)
regionID = UUID.Zero;
if (presences != null)
{ {
foreach (PresenceInfo p in presences) foreach (PresenceInfo p in presences)
{ {
if (p.RegionID != UUID.Zero) if (p.RegionID != UUID.Zero)
{ {
upd = p; regionID = p.RegionID;
break; break;
} }
} }
} }
if (upd != null) // If not found, message is undeliverable
if (regionID == UUID.Zero)
{ {
// check if we've tried this before.. break;
// This is one way to end the recursive loop
//
if (upd.RegionID == prevRegionID)
{
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
HandleUndeliveredMessage(im, result);
return;
}
}
else
{
// m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
HandleUndeliveredMessage(im, result);
return;
} }
} }
if (upd != null) /*
{ * Try to find out about region.
GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, * If unable, message is undeliverable.
upd.RegionID); */
if (reginfo != null) GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID);
if (reginfo == null)
{ {
m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID);
break;
}
/*
* Try to send message to agent in the region.
*/
Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
// Not actually used anymore, left in for compatibility
// Remove at next interface change
//
msgdata["region_handle"] = 0; msgdata["region_handle"] = 0;
bool imresult = doIMSending(reginfo, msgdata); 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) if (imresult)
{ {
// IM delivery successful, so store the Agent's location in our local cache.
lock (m_UserRegionMap) lock (m_UserRegionMap)
{ {
if (m_UserRegionMap.ContainsKey(toAgentID)) m_UserRegionMap[toAgentID] = regionID;
{
m_UserRegionMap[toAgentID] = upd.RegionID;
}
else
{
m_UserRegionMap.Add(toAgentID, upd.RegionID);
}
} }
result(true); result(true);
return;
} }
else
{
// 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, * Message delivery failed.
upd.RegionID); * If we just looked up what region the agent is in, message is undeliverable.
} */
} if (lookupAgent)
else
{ {
m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); break;
HandleUndeliveredMessage(im, result);
} }
/*
* 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);
} }
/// <summary> /// <summary>