diff options
author | Justin Clark-Casey (justincc) | 2014-05-23 20:14:49 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2014-05-23 20:14:49 +0100 |
commit | 72c67c50911e31937826314c825fdf13baa1cc28 (patch) | |
tree | 572766a8576778e64e5bb1d346b0283799041f0b | |
parent | If one is sitting on a child with an unset camera-eye and so using one set in... (diff) | |
download | opensim-SC_OLD-72c67c50911e31937826314c825fdf13baa1cc28.zip opensim-SC_OLD-72c67c50911e31937826314c825fdf13baa1cc28.tar.gz opensim-SC_OLD-72c67c50911e31937826314c825fdf13baa1cc28.tar.bz2 opensim-SC_OLD-72c67c50911e31937826314c825fdf13baa1cc28.tar.xz |
Fix possible infinite recursion in MessageTransferModule.SendGridInstantMessageViaXMLRPCAsync() whilst preserving retry lookup behaviour.
This is based on heavily mikemig's original patch in http://opensimulator.org/mantis/view.php?id=7149
but instead of exiting after the first IM delivery failure to presence information retrieved from the presence service
it will retry the lookup until the result matches the previous lookup.
This is to deal with the case where the agent is sent an IM whilst they are teleporting.
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs | 164 |
1 files changed, 56 insertions, 108 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 7aa7123..2462ff8 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 | |||
428 | /// <summary> | 428 | /// <summary> |
429 | /// delegate for sending a grid instant message asynchronously | 429 | /// delegate for sending a grid instant message asynchronously |
430 | /// </summary> | 430 | /// </summary> |
431 | public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); | 431 | public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); |
432 | 432 | ||
433 | protected virtual void GridInstantMessageCompleted(IAsyncResult iar) | 433 | protected virtual void GridInstantMessageCompleted(IAsyncResult iar) |
434 | { | 434 | { |
@@ -442,138 +442,87 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
442 | { | 442 | { |
443 | GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; | 443 | GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; |
444 | 444 | ||
445 | d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); | 445 | d.BeginInvoke(im, result, GridInstantMessageCompleted, d); |
446 | } | 446 | } |
447 | 447 | ||
448 | /// <summary> | 448 | /// <summary> |
449 | /// Recursive SendGridInstantMessage over XMLRPC method. | 449 | /// Internal SendGridInstantMessage over XMLRPC method. |
450 | /// This is called from within a dedicated thread. | ||
451 | /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from | ||
452 | /// itself, prevRegionHandle will be the last region handle that we tried to send. | ||
453 | /// If the handles are the same, we look up the user's location using the grid. | ||
454 | /// If the handles are still the same, we end. The send failed. | ||
455 | /// </summary> | 450 | /// </summary> |
456 | /// <param name="prevRegionHandle"> | 451 | /// <remarks> |
457 | /// Pass in 0 the first time this method is called. It will be called recursively with the last | 452 | /// This is called from within a dedicated thread. |
458 | /// regionhandle tried | 453 | /// </remarks> |
459 | /// </param> | 454 | private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) |
460 | protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) | ||
461 | { | 455 | { |
462 | UUID toAgentID = new UUID(im.toAgentID); | 456 | UUID toAgentID = new UUID(im.toAgentID); |
463 | 457 | UUID regionID; | |
464 | PresenceInfo upd = null; | 458 | bool needToLookupAgent; |
465 | |||
466 | bool lookupAgent = false; | ||
467 | 459 | ||
468 | lock (m_UserRegionMap) | 460 | lock (m_UserRegionMap) |
461 | needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); | ||
462 | |||
463 | while (true) | ||
469 | { | 464 | { |
470 | if (m_UserRegionMap.ContainsKey(toAgentID)) | 465 | if (needToLookupAgent) |
471 | { | 466 | { |
472 | upd = new PresenceInfo(); | 467 | PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); |
473 | upd.RegionID = m_UserRegionMap[toAgentID]; | ||
474 | 468 | ||
475 | // We need to compare the current regionhandle with the previous region handle | 469 | UUID foundRegionID = UUID.Zero; |
476 | // or the recursive loop will never end because it will never try to lookup the agent again | ||
477 | if (prevRegionID == upd.RegionID) | ||
478 | { | ||
479 | lookupAgent = true; | ||
480 | } | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | lookupAgent = true; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | 470 | ||
489 | // Are we needing to look-up an agent? | 471 | if (presences != null) |
490 | if (lookupAgent) | ||
491 | { | ||
492 | // Non-cached user agent lookup. | ||
493 | PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); | ||
494 | if (presences != null && presences.Length > 0) | ||
495 | { | ||
496 | foreach (PresenceInfo p in presences) | ||
497 | { | 472 | { |
498 | if (p.RegionID != UUID.Zero) | 473 | foreach (PresenceInfo p in presences) |
499 | { | 474 | { |
500 | upd = p; | 475 | if (p.RegionID != UUID.Zero) |
501 | break; | 476 | { |
477 | foundRegionID = p.RegionID; | ||
478 | break; | ||
479 | } | ||
502 | } | 480 | } |
503 | } | 481 | } |
504 | } | ||
505 | 482 | ||
506 | if (upd != null) | 483 | // If not found or the found region is the same as the last lookup, then message is undeliverable |
507 | { | 484 | if (foundRegionID == UUID.Zero || foundRegionID == regionID) |
508 | // check if we've tried this before.. | 485 | break; |
509 | // This is one way to end the recursive loop | 486 | else |
510 | // | 487 | regionID = foundRegionID; |
511 | if (upd.RegionID == prevRegionID) | ||
512 | { | ||
513 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
514 | HandleUndeliverableMessage(im, result); | ||
515 | return; | ||
516 | } | ||
517 | } | 488 | } |
518 | else | 489 | |
490 | GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); | ||
491 | if (reginfo == null) | ||
519 | { | 492 | { |
520 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | 493 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); |
521 | HandleUndeliverableMessage(im, result); | 494 | break; |
522 | return; | ||
523 | } | 495 | } |
524 | } | ||
525 | 496 | ||
526 | if (upd != null) | 497 | // Try to send the message to the agent via the retrieved region. |
527 | { | 498 | Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); |
528 | GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, | 499 | msgdata["region_handle"] = 0; |
529 | upd.RegionID); | 500 | bool imresult = doIMSending(reginfo, msgdata); |
530 | if (reginfo != null) | 501 | |
502 | // If the message delivery was successful, then cache the entry. | ||
503 | if (imresult) | ||
531 | { | 504 | { |
532 | Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); | 505 | lock (m_UserRegionMap) |
533 | // Not actually used anymore, left in for compatibility | ||
534 | // Remove at next interface change | ||
535 | // | ||
536 | msgdata["region_handle"] = 0; | ||
537 | bool imresult = doIMSending(reginfo, msgdata); | ||
538 | if (imresult) | ||
539 | { | ||
540 | // IM delivery successful, so store the Agent's location in our local cache. | ||
541 | lock (m_UserRegionMap) | ||
542 | { | ||
543 | if (m_UserRegionMap.ContainsKey(toAgentID)) | ||
544 | { | ||
545 | m_UserRegionMap[toAgentID] = upd.RegionID; | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | m_UserRegionMap.Add(toAgentID, upd.RegionID); | ||
550 | } | ||
551 | } | ||
552 | result(true); | ||
553 | } | ||
554 | else | ||
555 | { | 506 | { |
556 | // try again, but lookup user this time. | 507 | m_UserRegionMap[toAgentID] = regionID; |
557 | // Warning, this must call the Async version | ||
558 | // of this method or we'll be making thousands of threads | ||
559 | // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync | ||
560 | // The version that spawns the thread is SendGridInstantMessageViaXMLRPC | ||
561 | |||
562 | // This is recursive!!!!! | ||
563 | SendGridInstantMessageViaXMLRPCAsync(im, result, | ||
564 | upd.RegionID); | ||
565 | } | 508 | } |
509 | result(true); | ||
510 | return; | ||
566 | } | 511 | } |
567 | else | 512 | |
568 | { | 513 | // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried |
569 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); | 514 | // to use a locally cached region ID. All subsequent attempts need to lookup agent details from |
570 | HandleUndeliverableMessage(im, result); | 515 | // the presence service. |
571 | } | 516 | needToLookupAgent = true; |
572 | } | ||
573 | else | ||
574 | { | ||
575 | HandleUndeliverableMessage(im, result); | ||
576 | } | 517 | } |
518 | |||
519 | // If we reached this point then the message was not deliverable. Remove the bad cache entry and | ||
520 | // signal the delivery failure. | ||
521 | lock (m_UserRegionMap) | ||
522 | m_UserRegionMap.Remove(toAgentID); | ||
523 | |||
524 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
525 | HandleUndeliverableMessage(im, result); | ||
577 | } | 526 | } |
578 | 527 | ||
579 | /// <summary> | 528 | /// <summary> |
@@ -584,7 +533,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
584 | /// <returns>Bool if the message was successfully delivered at the other side.</returns> | 533 | /// <returns>Bool if the message was successfully delivered at the other side.</returns> |
585 | protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata) | 534 | protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata) |
586 | { | 535 | { |
587 | |||
588 | ArrayList SendParams = new ArrayList(); | 536 | ArrayList SendParams = new ArrayList(); |
589 | SendParams.Add(xmlrpcdata); | 537 | SendParams.Add(xmlrpcdata); |
590 | XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); | 538 | XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); |