aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs58
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs15
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs165
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs286
-rw-r--r--OpenSim/Tools/pCampBot/BotManager.cs18
5 files changed, 488 insertions, 54 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index bfdb24f..c839c05 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -4201,6 +4201,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4201 } 4201 }
4202 } 4202 }
4203 4203
4204// m_log.DebugFormat(
4205// "[LLCLIENTVIEW]: Sent {0} updates in ProcessEntityUpdates() for {1} {2} in {3}",
4206// updatesThisCall, Name, SceneAgent.IsChildAgent ? "child" : "root", Scene.Name);
4207//
4204 #endregion Packet Sending 4208 #endregion Packet Sending
4205 } 4209 }
4206 4210
@@ -12337,6 +12341,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12337 /// provide your own method.</param> 12341 /// provide your own method.</param>
12338 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) 12342 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
12339 { 12343 {
12344 if (m_outPacketsToDrop != null)
12345 if (m_outPacketsToDrop.Contains(packet.Type.ToString()))
12346 return;
12347
12340 if (DebugPacketLevel > 0) 12348 if (DebugPacketLevel > 0)
12341 { 12349 {
12342 bool logPacket = true; 12350 bool logPacket = true;
@@ -12395,6 +12403,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12395 /// <param name="Pack">OpenMetaverse.packet</param> 12403 /// <param name="Pack">OpenMetaverse.packet</param>
12396 public void ProcessInPacket(Packet packet) 12404 public void ProcessInPacket(Packet packet)
12397 { 12405 {
12406 if (m_inPacketsToDrop != null)
12407 if (m_inPacketsToDrop.Contains(packet.Type.ToString()))
12408 return;
12409
12398 if (DebugPacketLevel > 0) 12410 if (DebugPacketLevel > 0)
12399 { 12411 {
12400 bool logPacket = true; 12412 bool logPacket = true;
@@ -13119,5 +13131,51 @@ namespace OpenSim.Region.ClientStack.LindenUDP
13119 eq.Enqueue(BuildEvent("BulkUpdateInventory", 13131 eq.Enqueue(BuildEvent("BulkUpdateInventory",
13120 llsd), AgentId); 13132 llsd), AgentId);
13121 } 13133 }
13134
13135 private HashSet<string> m_outPacketsToDrop;
13136
13137 public bool AddOutPacketToDropSet(string packetName)
13138 {
13139 if (m_outPacketsToDrop == null)
13140 m_outPacketsToDrop = new HashSet<string>();
13141
13142 return m_outPacketsToDrop.Add(packetName);
13143 }
13144
13145 public bool RemoveOutPacketFromDropSet(string packetName)
13146 {
13147 if (m_outPacketsToDrop == null)
13148 return false;
13149
13150 return m_outPacketsToDrop.Remove(packetName);
13151 }
13152
13153 public HashSet<string> GetOutPacketDropSet()
13154 {
13155 return new HashSet<string>(m_outPacketsToDrop);
13156 }
13157
13158 private HashSet<string> m_inPacketsToDrop;
13159
13160 public bool AddInPacketToDropSet(string packetName)
13161 {
13162 if (m_inPacketsToDrop == null)
13163 m_inPacketsToDrop = new HashSet<string>();
13164
13165 return m_inPacketsToDrop.Add(packetName);
13166 }
13167
13168 public bool RemoveInPacketFromDropSet(string packetName)
13169 {
13170 if (m_inPacketsToDrop == null)
13171 return false;
13172
13173 return m_inPacketsToDrop.Remove(packetName);
13174 }
13175
13176 public HashSet<string> GetInPacketDropSet()
13177 {
13178 return new HashSet<string>(m_inPacketsToDrop);
13179 }
13122 } 13180 }
13123} 13181}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 39c9cb1..c34bafa 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -650,8 +650,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
650 650
651 if (HasUpdates(m_categories)) 651 if (HasUpdates(m_categories))
652 { 652 {
653 // Asynchronously run the callback 653 if (!m_udpServer.OqrEngine.IsRunning)
654 Util.FireAndForget(FireQueueEmpty, categories); 654 {
655 // Asynchronously run the callback
656 Util.FireAndForget(FireQueueEmpty, categories);
657 }
658 else
659 {
660 m_udpServer.OqrEngine.QueueRequest(this, categories);
661 }
655 } 662 }
656 else 663 else
657 { 664 {
@@ -670,8 +677,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
670 /// <param name="o">Throttle categories to fire the callback for, 677 /// <param name="o">Throttle categories to fire the callback for,
671 /// stored as an object to match the WaitCallback delegate 678 /// stored as an object to match the WaitCallback delegate
672 /// signature</param> 679 /// signature</param>
673 private void FireQueueEmpty(object o) 680 public void FireQueueEmpty(object o)
674 { 681 {
682// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name);
683
675// int start = Environment.TickCount & Int32.MaxValue; 684// int start = Environment.TickCount & Int32.MaxValue;
676// const int MIN_CALLBACK_MS = 30; 685// const int MIN_CALLBACK_MS = 30;
677 686
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 708a0a1..87aa37d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -250,7 +250,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
250 private AgentCircuitManager m_circuitManager; 250 private AgentCircuitManager m_circuitManager;
251 251
252 /// <summary>Reference to the scene this UDP server is attached to</summary> 252 /// <summary>Reference to the scene this UDP server is attached to</summary>
253 protected Scene m_scene; 253 public Scene Scene { get; private set; }
254 254
255 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 255 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
256 private Location m_location; 256 private Location m_location;
@@ -355,6 +355,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
355 /// </summary> 355 /// </summary>
356 private IClientAPI m_currentIncomingClient; 356 private IClientAPI m_currentIncomingClient;
357 357
358 /// <summary>
359 /// Experimental facility to run queue empty processing within a controlled number of threads rather than
360 /// requiring massive numbers of short-lived threads from the threadpool when there are a high number of
361 /// connections.
362 /// </summary>
363 public OutgoingQueueRefillEngine OqrEngine { get; private set; }
364
358 public LLUDPServer( 365 public LLUDPServer(
359 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, 366 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
360 IConfigSource configSource, AgentCircuitManager circuitManager) 367 IConfigSource configSource, AgentCircuitManager circuitManager)
@@ -432,6 +439,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
432 439
433 if (usePools) 440 if (usePools)
434 EnablePools(); 441 EnablePools();
442
443 OqrEngine = new OutgoingQueueRefillEngine(this);
435 } 444 }
436 445
437 public void Start() 446 public void Start()
@@ -453,7 +462,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
453 // This thread will process the packets received that are placed on the packetInbox 462 // This thread will process the packets received that are placed on the packetInbox
454 Watchdog.StartThread( 463 Watchdog.StartThread(
455 IncomingPacketHandler, 464 IncomingPacketHandler,
456 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 465 string.Format("Incoming Packets ({0})", Scene.Name),
457 ThreadPriority.Normal, 466 ThreadPriority.Normal,
458 false, 467 false,
459 true, 468 true,
@@ -469,7 +478,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
469 478
470 Watchdog.StartThread( 479 Watchdog.StartThread(
471 OutgoingPacketHandler, 480 OutgoingPacketHandler,
472 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), 481 string.Format("Outgoing Packets ({0})", Scene.Name),
473 ThreadPriority.Normal, 482 ThreadPriority.Normal,
474 false, 483 false,
475 true, 484 true,
@@ -479,7 +488,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
479 488
480 public void Stop() 489 public void Stop()
481 { 490 {
482 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 491 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
483 base.StopOutbound(); 492 base.StopOutbound();
484 base.StopInbound(); 493 base.StopInbound();
485 } 494 }
@@ -527,7 +536,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
527 "The number of objects currently stored within the UDPPacketBuffer pool", 536 "The number of objects currently stored within the UDPPacketBuffer pool",
528 "", 537 "",
529 "clientstack", 538 "clientstack",
530 m_scene.Name, 539 Scene.Name,
531 StatType.Pull, 540 StatType.Pull,
532 stat => stat.Value = Pool.Count, 541 stat => stat.Value = Pool.Count,
533 StatVerbosity.Debug); 542 StatVerbosity.Debug);
@@ -541,7 +550,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
541 "The number of objects currently stored within the incoming packet pool", 550 "The number of objects currently stored within the incoming packet pool",
542 "", 551 "",
543 "clientstack", 552 "clientstack",
544 m_scene.Name, 553 Scene.Name,
545 StatType.Pull, 554 StatType.Pull,
546 stat => stat.Value = m_incomingPacketPool.Count, 555 stat => stat.Value = m_incomingPacketPool.Count,
547 StatVerbosity.Debug); 556 StatVerbosity.Debug);
@@ -585,7 +594,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
585 594
586 public void AddScene(IScene scene) 595 public void AddScene(IScene scene)
587 { 596 {
588 if (m_scene != null) 597 if (Scene != null)
589 { 598 {
590 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); 599 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
591 return; 600 return;
@@ -597,8 +606,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
597 return; 606 return;
598 } 607 }
599 608
600 m_scene = (Scene)scene; 609 Scene = (Scene)scene;
601 m_location = new Location(m_scene.RegionInfo.RegionHandle); 610 m_location = new Location(Scene.RegionInfo.RegionHandle);
602 611
603 StatsManager.RegisterStat( 612 StatsManager.RegisterStat(
604 new Stat( 613 new Stat(
@@ -621,7 +630,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
621 "Packets reused", 630 "Packets reused",
622 "Number of packets reused out of all requests to the packet pool", 631 "Number of packets reused out of all requests to the packet pool",
623 "clientstack", 632 "clientstack",
624 m_scene.Name, 633 Scene.Name,
625 StatType.Pull, 634 StatType.Pull,
626 stat => 635 stat =>
627 { PercentageStat pstat = (PercentageStat)stat; 636 { PercentageStat pstat = (PercentageStat)stat;
@@ -635,7 +644,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
635 "Packet data blocks reused", 644 "Packet data blocks reused",
636 "Number of data blocks reused out of all requests to the packet pool", 645 "Number of data blocks reused out of all requests to the packet pool",
637 "clientstack", 646 "clientstack",
638 m_scene.Name, 647 Scene.Name,
639 StatType.Pull, 648 StatType.Pull,
640 stat => 649 stat =>
641 { PercentageStat pstat = (PercentageStat)stat; 650 { PercentageStat pstat = (PercentageStat)stat;
@@ -650,7 +659,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
650 "The number of objects currently stored within the packet pool", 659 "The number of objects currently stored within the packet pool",
651 "", 660 "",
652 "clientstack", 661 "clientstack",
653 m_scene.Name, 662 Scene.Name,
654 StatType.Pull, 663 StatType.Pull,
655 stat => stat.Value = PacketPool.Instance.PacketsPooled, 664 stat => stat.Value = PacketPool.Instance.PacketsPooled,
656 StatVerbosity.Debug)); 665 StatVerbosity.Debug));
@@ -662,7 +671,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
662 "The number of objects currently stored within the packet data block pool", 671 "The number of objects currently stored within the packet data block pool",
663 "", 672 "",
664 "clientstack", 673 "clientstack",
665 m_scene.Name, 674 Scene.Name,
666 StatType.Pull, 675 StatType.Pull,
667 stat => stat.Value = PacketPool.Instance.BlocksPooled, 676 stat => stat.Value = PacketPool.Instance.BlocksPooled,
668 StatVerbosity.Debug)); 677 StatVerbosity.Debug));
@@ -689,6 +698,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
689 HandlePacketCommand); 698 HandlePacketCommand);
690 699
691 MainConsole.Instance.Commands.AddCommand( 700 MainConsole.Instance.Commands.AddCommand(
701 "Debug", false, "debug lludp drop",
702 "debug lludp drop <in|out> <add|remove> <packet-name>",
703 "Drop all in or outbound packets that match the given name",
704 "For test purposes.",
705 HandleDropCommand);
706
707 MainConsole.Instance.Commands.AddCommand(
692 "Debug", 708 "Debug",
693 false, 709 false,
694 "debug lludp start", 710 "debug lludp start",
@@ -739,7 +755,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
739 755
740 private void HandlePacketCommand(string module, string[] args) 756 private void HandlePacketCommand(string module, string[] args)
741 { 757 {
742 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 758 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
743 return; 759 return;
744 760
745 bool setAsDefaultLevel = false; 761 bool setAsDefaultLevel = false;
@@ -775,15 +791,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
775 791
776 MainConsole.Instance.OutputFormat( 792 MainConsole.Instance.OutputFormat(
777 "Packet debug for {0} clients set to {1} in {2}", 793 "Packet debug for {0} clients set to {1} in {2}",
778 (setAll ? "all" : "future"), DefaultClientPacketDebugLevel, m_scene.Name); 794 (setAll ? "all" : "future"), DefaultClientPacketDebugLevel, Scene.Name);
779 795
780 if (setAll) 796 if (setAll)
781 { 797 {
782 m_scene.ForEachScenePresence(sp => 798 Scene.ForEachScenePresence(sp =>
783 { 799 {
784 MainConsole.Instance.OutputFormat( 800 MainConsole.Instance.OutputFormat(
785 "Packet debug for {0} ({1}) set to {2} in {3}", 801 "Packet debug for {0} ({1}) set to {2} in {3}",
786 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); 802 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name);
787 803
788 sp.ControllingClient.DebugPacketLevel = newDebug; 804 sp.ControllingClient.DebugPacketLevel = newDebug;
789 }); 805 });
@@ -791,13 +807,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
791 } 807 }
792 else 808 else
793 { 809 {
794 m_scene.ForEachScenePresence(sp => 810 Scene.ForEachScenePresence(sp =>
795 { 811 {
796 if (name == null || sp.Name == name) 812 if (name == null || sp.Name == name)
797 { 813 {
798 MainConsole.Instance.OutputFormat( 814 MainConsole.Instance.OutputFormat(
799 "Packet debug for {0} ({1}) set to {2} in {3}", 815 "Packet debug for {0} ({1}) set to {2} in {3}",
800 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); 816 sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, Scene.Name);
801 817
802 sp.ControllingClient.DebugPacketLevel = newDebug; 818 sp.ControllingClient.DebugPacketLevel = newDebug;
803 } 819 }
@@ -811,9 +827,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
811 } 827 }
812 } 828 }
813 829
830 private void HandleDropCommand(string module, string[] args)
831 {
832 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
833 return;
834
835 if (args.Length != 6)
836 {
837 MainConsole.Instance.Output("Usage: debug lludp drop <in|out> <add|remove> <packet-name>");
838 return;
839 }
840
841 string direction = args[3];
842 string subCommand = args[4];
843 string packetName = args[5];
844
845 if (subCommand == "add")
846 {
847 MainConsole.Instance.OutputFormat(
848 "Adding packet {0} to {1} drop list for all connections in {2}", direction, packetName, Scene.Name);
849
850 Scene.ForEachScenePresence(
851 sp =>
852 {
853 LLClientView llcv = (LLClientView)sp.ControllingClient;
854
855 if (direction == "in")
856 llcv.AddInPacketToDropSet(packetName);
857 else if (direction == "out")
858 llcv.AddOutPacketToDropSet(packetName);
859 }
860 );
861 }
862 else if (subCommand == "remove")
863 {
864 MainConsole.Instance.OutputFormat(
865 "Removing packet {0} from {1} drop list for all connections in {2}", direction, packetName, Scene.Name);
866
867 Scene.ForEachScenePresence(
868 sp =>
869 {
870 LLClientView llcv = (LLClientView)sp.ControllingClient;
871
872 if (direction == "in")
873 llcv.RemoveInPacketFromDropSet(packetName);
874 else if (direction == "out")
875 llcv.RemoveOutPacketFromDropSet(packetName);
876 }
877 );
878 }
879 }
880
814 private void HandleStartCommand(string module, string[] args) 881 private void HandleStartCommand(string module, string[] args)
815 { 882 {
816 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 883 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
817 return; 884 return;
818 885
819 if (args.Length != 4) 886 if (args.Length != 4)
@@ -833,7 +900,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
833 900
834 private void HandleStopCommand(string module, string[] args) 901 private void HandleStopCommand(string module, string[] args)
835 { 902 {
836 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 903 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
837 return; 904 return;
838 905
839 if (args.Length != 4) 906 if (args.Length != 4)
@@ -853,7 +920,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
853 920
854 private void HandlePoolCommand(string module, string[] args) 921 private void HandlePoolCommand(string module, string[] args)
855 { 922 {
856 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 923 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
857 return; 924 return;
858 925
859 if (args.Length != 4) 926 if (args.Length != 4)
@@ -869,7 +936,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
869 if (EnablePools()) 936 if (EnablePools())
870 { 937 {
871 EnablePoolStats(); 938 EnablePoolStats();
872 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name); 939 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", Scene.Name);
873 } 940 }
874 } 941 }
875 else if (enabled == "off") 942 else if (enabled == "off")
@@ -877,7 +944,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
877 if (DisablePools()) 944 if (DisablePools())
878 { 945 {
879 DisablePoolStats(); 946 DisablePoolStats();
880 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name); 947 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", Scene.Name);
881 } 948 }
882 } 949 }
883 else 950 else
@@ -890,27 +957,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
890 957
891 private void HandleAgentUpdateCommand(string module, string[] args) 958 private void HandleAgentUpdateCommand(string module, string[] args)
892 { 959 {
893 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 960 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
894 return; 961 return;
895 962
896 m_discardAgentUpdates = !m_discardAgentUpdates; 963 m_discardAgentUpdates = !m_discardAgentUpdates;
897 964
898 MainConsole.Instance.OutputFormat( 965 MainConsole.Instance.OutputFormat(
899 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); 966 "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, Scene.Name);
900 } 967 }
901 968
902 private void HandleStatusCommand(string module, string[] args) 969 private void HandleStatusCommand(string module, string[] args)
903 { 970 {
904 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) 971 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != Scene)
905 return; 972 return;
906 973
907 MainConsole.Instance.OutputFormat( 974 MainConsole.Instance.OutputFormat(
908 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); 975 "IN LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningInbound ? "enabled" : "disabled");
909 976
910 MainConsole.Instance.OutputFormat( 977 MainConsole.Instance.OutputFormat(
911 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); 978 "OUT LLUDP packet processing for {0} is {1}", Scene.Name, IsRunningOutbound ? "enabled" : "disabled");
912 979
913 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); 980 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", Scene.Name, UsePools ? "on" : "off");
914 981
915 MainConsole.Instance.OutputFormat( 982 MainConsole.Instance.OutputFormat(
916 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); 983 "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel);
@@ -1420,7 +1487,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1420 1487
1421 // Determine which agent this packet came from 1488 // Determine which agent this packet came from
1422 IClientAPI client; 1489 IClientAPI client;
1423 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) 1490 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1424 { 1491 {
1425 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1492 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1426 1493
@@ -1715,7 +1782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1715 1782
1716 m_log.DebugFormat( 1783 m_log.DebugFormat(
1717 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1784 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1718 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint); 1785 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1719 1786
1720 AuthenticateResponse sessionInfo; 1787 AuthenticateResponse sessionInfo;
1721 if (IsClientAuthorized(uccp, out sessionInfo)) 1788 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1737,7 +1804,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1737 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1804 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1738 if (client != null) 1805 if (client != null)
1739 { 1806 {
1740 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); 1807 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1741 bool tp = (aCircuit.teleportFlags > 0); 1808 bool tp = (aCircuit.teleportFlags > 0);
1742 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from 1809 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1743 if (!tp && !client.SceneAgent.SentInitialDataToClient) 1810 if (!tp && !client.SceneAgent.SentInitialDataToClient)
@@ -1749,7 +1816,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1749 // Don't create clients for unauthorized requesters. 1816 // Don't create clients for unauthorized requesters.
1750 m_log.WarnFormat( 1817 m_log.WarnFormat(
1751 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1818 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1752 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1819 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1753 } 1820 }
1754 1821
1755 // m_log.DebugFormat( 1822 // m_log.DebugFormat(
@@ -1781,7 +1848,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1781 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; 1848 CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
1782 1849
1783 m_log.DebugFormat( 1850 m_log.DebugFormat(
1784 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name); 1851 "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, Scene.Name);
1785 1852
1786 // Determine which agent this packet came from 1853 // Determine which agent this packet came from
1787 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination 1854 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
@@ -1792,7 +1859,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1792 int count = 40; 1859 int count = 40;
1793 while (count-- > 0) 1860 while (count-- > 0)
1794 { 1861 {
1795 if (m_scene.TryGetClient(endPoint, out client)) 1862 if (Scene.TryGetClient(endPoint, out client))
1796 { 1863 {
1797 if (!client.IsActive) 1864 if (!client.IsActive)
1798 { 1865 {
@@ -1801,7 +1868,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1801 // not yet been established). 1868 // not yet been established).
1802 m_log.DebugFormat( 1869 m_log.DebugFormat(
1803 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", 1870 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
1804 endPoint, client.Name, m_scene.Name); 1871 endPoint, client.Name, Scene.Name);
1805 } 1872 }
1806 else if (client.SceneAgent == null) 1873 else if (client.SceneAgent == null)
1807 { 1874 {
@@ -1813,7 +1880,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1813 // the client manager 1880 // the client manager
1814 m_log.DebugFormat( 1881 m_log.DebugFormat(
1815 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", 1882 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
1816 endPoint, client.Name, m_scene.Name); 1883 endPoint, client.Name, Scene.Name);
1817 } 1884 }
1818 else 1885 else
1819 { 1886 {
@@ -1824,7 +1891,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1824 { 1891 {
1825 m_log.DebugFormat( 1892 m_log.DebugFormat(
1826 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", 1893 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1827 endPoint, m_scene.Name); 1894 endPoint, Scene.Name);
1828 } 1895 }
1829 1896
1830 Thread.Sleep(200); 1897 Thread.Sleep(200);
@@ -1834,7 +1901,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1834 { 1901 {
1835 m_log.DebugFormat( 1902 m_log.DebugFormat(
1836 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", 1903 "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
1837 endPoint, m_scene.Name); 1904 endPoint, Scene.Name);
1838 1905
1839 return; 1906 return;
1840 } 1907 }
@@ -1846,7 +1913,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1846 // purposes. 1913 // purposes.
1847 m_log.DebugFormat( 1914 m_log.DebugFormat(
1848 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", 1915 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
1849 endPoint, client.Name, m_scene.Name); 1916 endPoint, client.Name, Scene.Name);
1850 1917
1851 return; 1918 return;
1852 } 1919 }
@@ -1941,11 +2008,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1941 // consistently, this lock could probably be removed. 2008 // consistently, this lock could probably be removed.
1942 lock (this) 2009 lock (this)
1943 { 2010 {
1944 if (!m_scene.TryGetClient(agentID, out client)) 2011 if (!Scene.TryGetClient(agentID, out client))
1945 { 2012 {
1946 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 2013 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1947 2014
1948 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 2015 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1949 client.OnLogout += LogoutHandler; 2016 client.OnLogout += LogoutHandler;
1950 client.DebugPacketLevel = DefaultClientPacketDebugLevel; 2017 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1951 2018
@@ -1975,13 +2042,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1975 2042
1976 m_log.WarnFormat( 2043 m_log.WarnFormat(
1977 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", 2044 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1978 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); 2045 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1979 2046
1980 if (!client.SceneAgent.IsChildAgent) 2047 if (!client.SceneAgent.IsChildAgent)
1981 client.Kick("Simulator logged you out due to connection timeout."); 2048 client.Kick("Simulator logged you out due to connection timeout.");
1982 } 2049 }
1983 2050
1984 m_scene.CloseAgent(client.AgentId, true); 2051 Scene.CloseAgent(client.AgentId, true);
1985 } 2052 }
1986 2053
1987 private void IncomingPacketHandler() 2054 private void IncomingPacketHandler()
@@ -2093,7 +2160,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2093 2160
2094 // Handle outgoing packets, resends, acknowledgements, and pings for each 2161 // Handle outgoing packets, resends, acknowledgements, and pings for each
2095 // client. m_packetSent will be set to true if a packet is sent 2162 // client. m_packetSent will be set to true if a packet is sent
2096 m_scene.ForEachClient(clientPacketHandler); 2163 Scene.ForEachClient(clientPacketHandler);
2097 2164
2098 m_currentOutgoingClient = null; 2165 m_currentOutgoingClient = null;
2099 2166
@@ -2260,7 +2327,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2260 watch1.Reset(); 2327 watch1.Reset();
2261 2328
2262 // reuse this -- it's every ~100ms 2329 // reuse this -- it's every ~100ms
2263 if (m_scene.EmergencyMonitoring && nticks % 100 == 0) 2330 if (Scene.EmergencyMonitoring && nticks % 100 == 0)
2264 { 2331 {
2265 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})", 2332 m_log.InfoFormat("[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})",
2266 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); 2333 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
@@ -2309,7 +2376,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2309 { 2376 {
2310 m_log.DebugFormat( 2377 m_log.DebugFormat(
2311 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 2378 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2312 packet.Type, client.Name, m_scene.RegionInfo.RegionName); 2379 packet.Type, client.Name, Scene.RegionInfo.RegionName);
2313 } 2380 }
2314 2381
2315 IncomingPacketsProcessed++; 2382 IncomingPacketsProcessed++;
@@ -2322,7 +2389,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2322 if (!client.IsLoggingOut) 2389 if (!client.IsLoggingOut)
2323 { 2390 {
2324 client.IsLoggingOut = true; 2391 client.IsLoggingOut = true;
2325 m_scene.CloseAgent(client.AgentId, false); 2392 Scene.CloseAgent(client.AgentId, false);
2326 } 2393 }
2327 } 2394 }
2328 } 2395 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs
new file mode 100644
index 0000000..0659d8e
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OutgoingQueueRefillEngine.cs
@@ -0,0 +1,286 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Concurrent;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Monitoring;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.ClientStack.LindenUDP
38{
39 public struct RefillRequest
40 {
41 public LLUDPClient Client;
42 public ThrottleOutPacketTypeFlags Categories;
43
44 public RefillRequest(LLUDPClient client, ThrottleOutPacketTypeFlags categories)
45 {
46 Client = client;
47 Categories = categories;
48 }
49 }
50
51 public class OutgoingQueueRefillEngine
52 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
55 public bool IsRunning { get; private set; }
56
57 /// <summary>
58 /// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping.
59 /// </summary>
60 public int RequestProcessTimeoutOnStop { get; set; }
61
62 /// <summary>
63 /// Controls whether we need to warn in the log about exceeding the max queue size.
64 /// </summary>
65 /// <remarks>
66 /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in
67 /// order to avoid spamming the log with lots of warnings.
68 /// </remarks>
69 private bool m_warnOverMaxQueue = true;
70
71 private BlockingCollection<RefillRequest> m_requestQueue;
72
73 private CancellationTokenSource m_cancelSource = new CancellationTokenSource();
74
75 private LLUDPServer m_udpServer;
76
77 private Stat m_oqreRequestsWaitingStat;
78
79 /// <summary>
80 /// Used to signal that we are ready to complete stop.
81 /// </summary>
82 private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false);
83
84 public OutgoingQueueRefillEngine(LLUDPServer server)
85 {
86 RequestProcessTimeoutOnStop = 5000;
87 m_udpServer = server;
88
89 MainConsole.Instance.Commands.AddCommand(
90 "Debug",
91 false,
92 "debug lludp oqre",
93 "debug lludp oqre <start|stop|status>",
94 "Start, stop or get status of OutgoingQueueRefillEngine.",
95 "Experimental.",
96 HandleOqreCommand);
97 }
98
99 public void Start()
100 {
101 lock (this)
102 {
103 if (IsRunning)
104 return;
105
106 IsRunning = true;
107
108 m_finishedProcessingAfterStop.Reset();
109
110 m_requestQueue = new BlockingCollection<RefillRequest>(new ConcurrentQueue<RefillRequest>(), 5000);
111
112 m_oqreRequestsWaitingStat =
113 new Stat(
114 "OQRERequestsWaiting",
115 "Number of outgong queue refill requests waiting for processing.",
116 "",
117 "",
118 "clientstack",
119 m_udpServer.Scene.Name,
120 StatType.Pull,
121 MeasuresOfInterest.None,
122 stat => stat.Value = m_requestQueue.Count,
123 StatVerbosity.Debug);
124
125 StatsManager.RegisterStat(m_oqreRequestsWaitingStat);
126
127 Watchdog.StartThread(
128 ProcessRequests,
129 String.Format("OutgoingQueueRefillEngineThread ({0})", m_udpServer.Scene.Name),
130 ThreadPriority.Normal,
131 false,
132 true,
133 null,
134 int.MaxValue);
135 }
136 }
137
138 public void Stop()
139 {
140 lock (this)
141 {
142 try
143 {
144 if (!IsRunning)
145 return;
146
147 IsRunning = false;
148
149 int requestsLeft = m_requestQueue.Count;
150
151 if (requestsLeft <= 0)
152 {
153 m_cancelSource.Cancel();
154 }
155 else
156 {
157 m_log.InfoFormat("[OUTGOING QUEUE REFILL ENGINE]: Waiting to write {0} events after stop.", requestsLeft);
158
159 while (requestsLeft > 0)
160 {
161 if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop))
162 {
163 // After timeout no events have been written
164 if (requestsLeft == m_requestQueue.Count)
165 {
166 m_log.WarnFormat(
167 "[OUTGOING QUEUE REFILL ENGINE]: No requests processed after {0} ms wait. Discarding remaining {1} requests",
168 RequestProcessTimeoutOnStop, requestsLeft);
169
170 break;
171 }
172 }
173
174 requestsLeft = m_requestQueue.Count;
175 }
176 }
177 }
178 finally
179 {
180 m_cancelSource.Dispose();
181 StatsManager.DeregisterStat(m_oqreRequestsWaitingStat);
182 m_oqreRequestsWaitingStat = null;
183 m_requestQueue = null;
184 }
185 }
186 }
187
188 public bool QueueRequest(LLUDPClient client, ThrottleOutPacketTypeFlags categories)
189 {
190 if (m_requestQueue.Count < m_requestQueue.BoundedCapacity)
191 {
192// m_log.DebugFormat(
193// "[OUTGOING QUEUE REFILL ENGINE]: Adding request for categories {0} for {1} in {2}",
194// categories, client.AgentID, m_udpServer.Scene.Name);
195
196 m_requestQueue.Add(new RefillRequest(client, categories));
197
198 if (!m_warnOverMaxQueue)
199 m_warnOverMaxQueue = true;
200
201 return true;
202 }
203 else
204 {
205 if (m_warnOverMaxQueue)
206 {
207 m_log.WarnFormat(
208 "[OUTGOING QUEUE REFILL ENGINE]: Request queue at maximum capacity, not recording request from {0} in {1}",
209 client.AgentID, m_udpServer.Scene.Name);
210
211 m_warnOverMaxQueue = false;
212 }
213
214 return false;
215 }
216 }
217
218 private void ProcessRequests()
219 {
220 try
221 {
222 while (IsRunning || m_requestQueue.Count > 0)
223 {
224 RefillRequest req = m_requestQueue.Take(m_cancelSource.Token);
225
226 // QueueEmpty callback = req.Client.OnQueueEmpty;
227 //
228 // if (callback != null)
229 // {
230 // try
231 // {
232 // callback(req.Categories);
233 // }
234 // catch (Exception e)
235 // {
236 // m_log.Error("[OUTGOING QUEUE REFILL ENGINE]: ProcessRequests(" + req.Categories + ") threw an exception: " + e.Message, e);
237 // }
238 // }
239
240 req.Client.FireQueueEmpty(req.Categories);
241 }
242 }
243 catch (OperationCanceledException)
244 {
245 }
246
247 m_finishedProcessingAfterStop.Set();
248 }
249
250 private void HandleOqreCommand(string module, string[] args)
251 {
252 if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
253 return;
254
255 if (args.Length != 4)
256 {
257 MainConsole.Instance.Output("Usage: debug lludp oqre <stop|start|status>");
258 return;
259 }
260
261 string subCommand = args[3];
262
263 if (subCommand == "stop")
264 {
265 Stop();
266 MainConsole.Instance.OutputFormat("Stopped OQRE for {0}", m_udpServer.Scene.Name);
267 }
268 else if (subCommand == "start")
269 {
270 Start();
271 MainConsole.Instance.OutputFormat("Started OQRE for {0}", m_udpServer.Scene.Name);
272 }
273 else if (subCommand == "status")
274 {
275 MainConsole.Instance.OutputFormat("OQRE in {0}", m_udpServer.Scene.Name);
276 MainConsole.Instance.OutputFormat("Running: {0}", IsRunning);
277 MainConsole.Instance.OutputFormat(
278 "Requests waiting: {0}", IsRunning ? m_requestQueue.Count.ToString() : "n/a");
279 }
280 else
281 {
282 MainConsole.Instance.OutputFormat("Unrecognized OQRE subcommand {0}", subCommand);
283 }
284 }
285 }
286} \ No newline at end of file
diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs
index b10f552..29739dc 100644
--- a/OpenSim/Tools/pCampBot/BotManager.cs
+++ b/OpenSim/Tools/pCampBot/BotManager.cs
@@ -690,7 +690,14 @@ namespace pCampBot
690 { 690 {
691 lock (m_bots) 691 lock (m_bots)
692 { 692 {
693 m_bots.ForEach(b => b.SitOnGround()); 693 foreach (Bot bot in m_bots)
694 {
695 if (bot.ConnectionState == ConnectionState.Connected)
696 {
697 MainConsole.Instance.OutputFormat("Sitting bot {0} on ground.", bot.Name);
698 bot.SitOnGround();
699 }
700 }
694 } 701 }
695 } 702 }
696 703
@@ -698,7 +705,14 @@ namespace pCampBot
698 { 705 {
699 lock (m_bots) 706 lock (m_bots)
700 { 707 {
701 m_bots.ForEach(b => b.Stand()); 708 foreach (Bot bot in m_bots)
709 {
710 if (bot.ConnectionState == ConnectionState.Connected)
711 {
712 MainConsole.Instance.OutputFormat("Standing bot {0} from ground.", bot.Name);
713 bot.Stand();
714 }
715 }
702 } 716 }
703 } 717 }
704 718