aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs247
1 files changed, 178 insertions, 69 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 2462ff8..3c82fd9 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -50,6 +50,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 private bool m_Enabled = false; 52 private bool m_Enabled = false;
53 protected string m_MessageKey = String.Empty;
53 protected List<Scene> m_Scenes = new List<Scene>(); 54 protected List<Scene> m_Scenes = new List<Scene>();
54 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); 55 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>();
55 56
@@ -69,14 +70,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
69 public virtual void Initialise(IConfigSource config) 70 public virtual void Initialise(IConfigSource config)
70 { 71 {
71 IConfig cnf = config.Configs["Messaging"]; 72 IConfig cnf = config.Configs["Messaging"];
72 if (cnf != null && cnf.GetString( 73 if (cnf != null)
73 "MessageTransferModule", "MessageTransferModule") !=
74 "MessageTransferModule")
75 { 74 {
76 m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); 75 if (cnf.GetString("MessageTransferModule",
77 return; 76 "MessageTransferModule") != "MessageTransferModule")
78 } 77 {
78 return;
79 }
79 80
81 m_MessageKey = cnf.GetString("MessageKey", String.Empty);
82 }
83 m_log.Debug("[MESSAGE TRANSFER]: Module enabled");
80 m_Enabled = true; 84 m_Enabled = true;
81 } 85 }
82 86
@@ -135,6 +139,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
135 { 139 {
136 UUID toAgentID = new UUID(im.toAgentID); 140 UUID toAgentID = new UUID(im.toAgentID);
137 141
142 if (toAgentID == UUID.Zero)
143 return;
144
138 // Try root avatar only first 145 // Try root avatar only first
139 foreach (Scene scene in m_Scenes) 146 foreach (Scene scene in m_Scenes)
140 { 147 {
@@ -181,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
181 SendGridInstantMessageViaXMLRPC(im, result); 188 SendGridInstantMessageViaXMLRPC(im, result);
182 } 189 }
183 190
184 public void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result) 191 public virtual void HandleUndeliverableMessage(GridInstantMessage im, MessageResultNotification result)
185 { 192 {
186 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage; 193 UndeliveredMessage handlerUndeliveredMessage = OnUndeliveredMessage;
187 194
@@ -249,6 +256,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
249 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") 256 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
250 && requestData.ContainsKey("binary_bucket")) 257 && requestData.ContainsKey("binary_bucket"))
251 { 258 {
259 if (m_MessageKey != String.Empty)
260 {
261 XmlRpcResponse error_resp = new XmlRpcResponse();
262 Hashtable error_respdata = new Hashtable();
263 error_respdata["success"] = "FALSE";
264 error_resp.Value = error_respdata;
265
266 if (!requestData.Contains("message_key"))
267 return error_resp;
268 if (m_MessageKey != (string)requestData["message_key"])
269 return error_resp;
270 }
271
252 // Do the easy way of validating the UUIDs 272 // Do the easy way of validating the UUIDs
253 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); 273 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
254 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); 274 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
@@ -425,104 +445,192 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
425 return resp; 445 return resp;
426 } 446 }
427 447
448
428 /// <summary> 449 /// <summary>
429 /// delegate for sending a grid instant message asynchronously 450 /// delegate for sending a grid instant message asynchronously
430 /// </summary> 451 /// </summary>
431 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); 452 private delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
453
454 private class GIM {
455 public GridInstantMessage im;
456 public MessageResultNotification result;
457 };
458
459 private Queue<GIM> pendingInstantMessages = new Queue<GIM>();
460 private int numInstantMessageThreads = 0;
432 461
433 protected virtual void GridInstantMessageCompleted(IAsyncResult iar) 462 private void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result)
434 { 463 {
435 GridInstantMessageDelegate icon = 464 lock (pendingInstantMessages) {
436 (GridInstantMessageDelegate)iar.AsyncState; 465 if (numInstantMessageThreads >= 4) {
437 icon.EndInvoke(iar); 466 GIM gim = new GIM();
467 gim.im = im;
468 gim.result = result;
469 pendingInstantMessages.Enqueue(gim);
470 } else {
471 ++ numInstantMessageThreads;
472 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: ++numInstantMessageThreads={0}", numInstantMessageThreads);
473 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsyncMain;
474 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
475 }
476 }
438 } 477 }
439 478
440 479
441 protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) 480 private void GridInstantMessageCompleted(IAsyncResult iar)
442 { 481 {
443 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; 482 GridInstantMessageDelegate d = (GridInstantMessageDelegate)iar.AsyncState;
444 483 d.EndInvoke(iar);
445 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
446 } 484 }
447 485
448 /// <summary> 486 /// <summary>
449 /// Internal SendGridInstantMessage over XMLRPC method. 487 /// Internal SendGridInstantMessage over XMLRPC method.
450 /// </summary> 488 /// </summary>
451 /// <remarks> 489
452 /// This is called from within a dedicated thread. 490 /// <param name="prevRegionHandle">
453 /// </remarks> 491 /// Pass in 0 the first time this method is called. It will be called recursively with the last
454 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) 492 /// regionhandle tried
493 /// </param>
494 private void SendGridInstantMessageViaXMLRPCAsyncMain(GridInstantMessage im, MessageResultNotification result)
455 { 495 {
496 GIM gim;
497 do {
498 try {
499 SendGridInstantMessageViaXMLRPCAsync(im, result, UUID.Zero);
500 } catch (Exception e) {
501 m_log.Error("[SendGridInstantMessageViaXMLRPC]: exception " + e.Message);
502 }
503 lock (pendingInstantMessages) {
504 if (pendingInstantMessages.Count > 0) {
505 gim = pendingInstantMessages.Dequeue();
506 im = gim.im;
507 result = gim.result;
508 } else {
509 gim = null;
510 -- numInstantMessageThreads;
511 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: --numInstantMessageThreads={0}", numInstantMessageThreads);
512 }
513 }
514 } while (gim != null);
515 }
516
517 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
518 {
519
456 UUID toAgentID = new UUID(im.toAgentID); 520 UUID toAgentID = new UUID(im.toAgentID);
521 PresenceInfo upd = null;
457 UUID regionID; 522 UUID regionID;
458 bool needToLookupAgent; 523 bool lookupAgent = false;
459 524
460 lock (m_UserRegionMap) 525 lock (m_UserRegionMap)
461 needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID);
462
463 while (true)
464 { 526 {
465 if (needToLookupAgent) 527 if (m_UserRegionMap.ContainsKey(toAgentID))
466 { 528 {
467 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); 529 upd = new PresenceInfo();
530 upd.RegionID = m_UserRegionMap[toAgentID];
468 531
469 UUID foundRegionID = UUID.Zero; 532 // We need to compare the current regionhandle with the previous region handle
470 533 // or the recursive loop will never end because it will never try to lookup the agent again
471 if (presences != null) 534 if (prevRegionID == upd.RegionID)
472 { 535 {
473 foreach (PresenceInfo p in presences) 536 lookupAgent = true;
474 {
475 if (p.RegionID != UUID.Zero)
476 {
477 foundRegionID = p.RegionID;
478 break;
479 }
480 }
481 } 537 }
482
483 // If not found or the found region is the same as the last lookup, then message is undeliverable
484 if (foundRegionID == UUID.Zero || foundRegionID == regionID)
485 break;
486 else
487 regionID = foundRegionID;
488 } 538 }
489 539 else
490 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID);
491 if (reginfo == null)
492 { 540 {
493 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); 541 lookupAgent = true;
494 break;
495 } 542 }
543 }
496 544
497 // Try to send the message to the agent via the retrieved region.
498 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
499 msgdata["region_handle"] = 0;
500 bool imresult = doIMSending(reginfo, msgdata);
501 545
502 // If the message delivery was successful, then cache the entry. 546 // Are we needing to look-up an agent?
503 if (imresult) 547 if (lookupAgent)
548 {
549 // Non-cached user agent lookup.
550 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() });
551 if (presences != null && presences.Length > 0)
504 { 552 {
505 lock (m_UserRegionMap) 553 foreach (PresenceInfo p in presences)
506 { 554 {
507 m_UserRegionMap[toAgentID] = regionID; 555 if (p.RegionID != UUID.Zero)
556 {
557 upd = p;
558 break;
559 }
508 } 560 }
509 result(true);
510 return;
511 } 561 }
512 562
513 // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried 563 if (upd != null)
514 // to use a locally cached region ID. All subsequent attempts need to lookup agent details from 564 {
515 // the presence service. 565 // check if we've tried this before..
516 needToLookupAgent = true; 566 // This is one way to end the recursive loop
567 //
568 if (upd.RegionID == prevRegionID)
569 {
570 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
571 HandleUndeliverableMessage(im, result);
572 return;
573 }
574 }
575 else
576 {
577 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message");
578 HandleUndeliverableMessage(im, result);
579 return;
580 }
517 } 581 }
518 582
519 // If we reached this point then the message was not deliverable. Remove the bad cache entry and 583 if (upd != null)
520 // signal the delivery failure. 584 {
521 lock (m_UserRegionMap) 585 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero,
522 m_UserRegionMap.Remove(toAgentID); 586 upd.RegionID);
587 if (reginfo != null)
588 {
589 Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im);
590 // Not actually used anymore, left in for compatibility
591 // Remove at next interface change
592 //
593 msgdata["region_handle"] = 0;
594 bool imresult = doIMSending(reginfo, msgdata);
595 if (imresult)
596 {
597 // IM delivery successful, so store the Agent's location in our local cache.
598 lock (m_UserRegionMap)
599 {
600 if (m_UserRegionMap.ContainsKey(toAgentID))
601 {
602 m_UserRegionMap[toAgentID] = upd.RegionID;
603 }
604 else
605 {
606 m_UserRegionMap.Add(toAgentID, upd.RegionID);
607 }
608 }
609 result(true);
610 }
611 else
612 {
613 // try again, but lookup user this time.
614 // Warning, this must call the Async version
615 // of this method or we'll be making thousands of threads
616 // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync
617 // The version that spawns the thread is SendGridInstantMessageViaXMLRPC
523 618
524 // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); 619 // This is recursive!!!!!
525 HandleUndeliverableMessage(im, result); 620 SendGridInstantMessageViaXMLRPCAsync(im, result,
621 upd.RegionID);
622 }
623 }
624 else
625 {
626 m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID);
627 HandleUndeliverableMessage(im, result);
628 }
629 }
630 else
631 {
632 HandleUndeliverableMessage(im, result);
633 }
526 } 634 }
527 635
528 /// <summary> 636 /// <summary>
@@ -622,8 +730,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
622 gim["position_z"] = msg.Position.Z.ToString(); 730 gim["position_z"] = msg.Position.Z.ToString();
623 gim["region_id"] = new UUID(msg.RegionID).ToString(); 731 gim["region_id"] = new UUID(msg.RegionID).ToString();
624 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 732 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
733 if (m_MessageKey != String.Empty)
734 gim["message_key"] = m_MessageKey;
625 return gim; 735 return gim;
626 } 736 }
627
628 } 737 }
629} 738}