aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs21
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs158
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs255
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs288
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs7
10 files changed, 665 insertions, 159 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
index 650cd50..f6146a9 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs
@@ -241,8 +241,8 @@ namespace OpenSim.Region.ClientStack.Linden
241 m_HostCapsObj.RegisterHandler( 241 m_HostCapsObj.RegisterHandler(
242 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); 242 "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
243 243
244 m_log.DebugFormat( 244// m_log.DebugFormat(
245 "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); 245// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
246 246
247 //m_capsHandlers["MapLayer"] = 247 //m_capsHandlers["MapLayer"] =
248 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST", 248 // new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
@@ -337,11 +337,12 @@ namespace OpenSim.Region.ClientStack.Linden
337 public string SeedCapRequest(string request, string path, string param, 337 public string SeedCapRequest(string request, string path, string param,
338 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 338 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
339 { 339 {
340// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName); 340 m_log.DebugFormat(
341 "[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
341 342
342 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) 343 if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
343 { 344 {
344 m_log.DebugFormat( 345 m_log.WarnFormat(
345 "[CAPS]: Unauthorized CAPS client {0} from {1}", 346 "[CAPS]: Unauthorized CAPS client {0} from {1}",
346 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint); 347 m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
347 348
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index e113c60..5bbdce8 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
94 94
95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); 95 //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
96 96
97 scene.EventManager.OnNewClient += OnNewClient; 97// scene.EventManager.OnNewClient += OnNewClient;
98 98
99 // TODO: Leaving these open, or closing them when we 99 // TODO: Leaving these open, or closing them when we
100 // become a child is incorrect. It messes up TP in a big 100 // become a child is incorrect. It messes up TP in a big
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
102 // circuit is there. 102 // circuit is there.
103 103
104 scene.EventManager.OnClientClosed += ClientClosed; 104 scene.EventManager.OnClientClosed += ClientClosed;
105
105 scene.EventManager.OnMakeChildAgent += MakeChildAgent; 106 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
106 scene.EventManager.OnRegisterCaps += OnRegisterCaps; 107 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
107 108
@@ -110,10 +111,10 @@ namespace OpenSim.Region.ClientStack.Linden
110 false, 111 false,
111 "debug eq", 112 "debug eq",
112 "debug eq [0|1|2]", 113 "debug eq [0|1|2]",
113 "Turn on event queue debugging" 114 "Turn on event queue debugging\n"
114 + "<= 0 - turns off all event queue logging" 115 + " <= 0 - turns off all event queue logging\n"
115 + ">= 1 - turns on outgoing event logging" 116 + " >= 1 - turns on outgoing event logging\n"
116 + ">= 2 - turns on poll notification", 117 + " >= 2 - turns on poll notification",
117 HandleDebugEq); 118 HandleDebugEq);
118 } 119 }
119 else 120 else
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
226 227
227 #endregion 228 #endregion
228 229
229 private void OnNewClient(IClientAPI client)
230 {
231 //client.OnLogout += ClientClosed;
232 }
233
234// private void ClientClosed(IClientAPI client)
235// {
236// ClientClosed(client.AgentId);
237// }
238
239 private void ClientClosed(UUID agentID, Scene scene) 230 private void ClientClosed(UUID agentID, Scene scene)
240 { 231 {
241// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); 232// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
index cd70410..d604cf6 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
94 UUID spId = TestHelpers.ParseTail(0x1); 94 UUID spId = TestHelpers.ParseTail(0x1);
95 95
96 SceneHelpers.AddScenePresence(m_scene, spId); 96 SceneHelpers.AddScenePresence(m_scene, spId);
97 m_scene.IncomingCloseAgent(spId); 97 m_scene.IncomingCloseAgent(spId, false);
98 98
99 // TODO: Add more assertions for the other aspects of event queues 99 // TODO: Add more assertions for the other aspects of event queues
100 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); 100 Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
index 0a5ad0f..fcac182 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs
@@ -109,7 +109,7 @@ namespace OpenSim.Region.ClientStack.Linden
109 109
110 UUID capID = UUID.Random(); 110 UUID capID = UUID.Random();
111 111
112 m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 112// m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
113 caps.RegisterHandler( 113 caps.RegisterHandler(
114 "SimConsoleAsync", 114 "SimConsoleAsync",
115 new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene)); 115 new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
index 1b8535c..e22670b 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs
@@ -45,7 +45,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
45 public Packet Packet; 45 public Packet Packet;
46 46
47 /// <summary> 47 /// <summary>
48 /// Default constructor 48 /// No arg constructor.
49 /// </summary>
50 public IncomingPacket() {}
51
52 /// <summary>
53 /// Constructor
49 /// </summary> 54 /// </summary>
50 /// <param name="client">Reference to the client this packet came from</param> 55 /// <param name="client">Reference to the client this packet came from</param>
51 /// <param name="packet">Packet data</param> 56 /// <param name="packet">Packet data</param>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ee28914..67ce48e 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 47using OpenSim.Services.Interfaces;
48using Timer = System.Timers.Timer; 48using Timer = System.Timers.Timer;
49using AssetLandmark = OpenSim.Framework.AssetLandmark; 49using AssetLandmark = OpenSim.Framework.AssetLandmark;
50using RegionFlags = OpenMetaverse.RegionFlags;
50using Nini.Config; 51using Nini.Config;
51 52
52using System.IO; 53using System.IO;
@@ -354,7 +355,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
354 private bool m_deliverPackets = true; 355 private bool m_deliverPackets = true;
355 private int m_animationSequenceNumber = 1; 356 private int m_animationSequenceNumber = 1;
356 private bool m_SendLogoutPacketWhenClosing = true; 357 private bool m_SendLogoutPacketWhenClosing = true;
357 private AgentUpdateArgs lastarg; 358
359 /// <summary>
360 /// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
361 /// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
362 /// is doing absolutely nothing.
363 /// </summary>
364 /// <remarks>
365 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
366 /// cannot retain a reference to it outside of that method.
367 /// </remarks>
368 private AgentUpdateArgs m_lastAgentUpdateArgs;
358 369
359 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 370 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
360 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 371 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -509,19 +520,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
509 /// </summary> 520 /// </summary>
510 public void Close() 521 public void Close()
511 { 522 {
512 Close(true); 523 Close(true, false);
513 } 524 }
514 525
515 /// <summary> 526 public void Close(bool sendStop, bool force)
516 /// Shut down the client view
517 /// </summary>
518 public void Close(bool sendStop)
519 { 527 {
520 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 528 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g.
521 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. 529 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
522 lock (CloseSyncLock) 530 lock (CloseSyncLock)
523 { 531 {
524 if (!IsActive) 532 // We still perform a force close inside the sync lock since this is intended to attempt close where
533 // there is some unidentified connection problem, not where we have issues due to deadlock
534 if (!IsActive && !force)
525 return; 535 return;
526 536
527 IsActive = false; 537 IsActive = false;
@@ -3984,7 +3994,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3984 { 3994 {
3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3995 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3986 3996
3987 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3997 ImprovedTerseObjectUpdatePacket packet
3998 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3988 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3999 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3989 packet.RegionData.TimeDilation = timeDilation; 4000 packet.RegionData.TimeDilation = timeDilation;
3990 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4001 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4029,7 +4040,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4029 { 4040 {
4030 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 4041 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4031 4042
4032 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 4043 ImprovedTerseObjectUpdatePacket packet
4044 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4045 PacketType.ImprovedTerseObjectUpdate);
4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4046 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4034 packet.RegionData.TimeDilation = timeDilation; 4047 packet.RegionData.TimeDilation = timeDilation;
4035 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4048 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4037,7 +4050,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4037 for (int i = 0; i < blocks.Count; i++) 4050 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i]; 4051 packet.ObjectData[i] = blocks[i];
4039 4052
4040 OutPacket(packet, ThrottleOutPacketType.Task, true); 4053 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4041 } 4054 }
4042 4055
4043 #endregion Packet Sending 4056 #endregion Packet Sending
@@ -4534,7 +4547,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4534 { 4547 {
4535 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock(); 4548 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4536 } 4549 }
4537 j = 0; 4550 j = 0;
4538 4551
4539 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 4552 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4540 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; 4553 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
@@ -5038,7 +5051,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5038 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 5051 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
5039 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; 5052 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5040 5053
5041 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); 5054 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5055 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5056
5042 block.Data = data; 5057 block.Data = data;
5043 5058
5044 if (textureEntry != null && textureEntry.Length > 0) 5059 if (textureEntry != null && textureEntry.Length > 0)
@@ -5288,7 +5303,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5288 protected virtual void RegisterLocalPacketHandlers() 5303 protected virtual void RegisterLocalPacketHandlers()
5289 { 5304 {
5290 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout); 5305 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
5306
5307 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5308 // for each AgentUpdate packet.
5291 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5309 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5310
5292 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5311 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5293 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5312 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5294 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5313 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
@@ -5517,81 +5536,84 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5517 5536
5518 #region Scene/Avatar 5537 #region Scene/Avatar
5519 5538
5520 private bool HandleAgentUpdate(IClientAPI sener, Packet Pack) 5539 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5521 { 5540 {
5522 if (OnAgentUpdate != null) 5541 if (OnAgentUpdate != null)
5523 { 5542 {
5524 bool update = false; 5543 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5525 AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
5526 5544
5527 #region Packet Session and User Check 5545 #region Packet Session and User Check
5528 if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId) 5546 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
5547 {
5548 PacketPool.Instance.ReturnPacket(packet);
5529 return false; 5549 return false;
5550 }
5530 #endregion 5551 #endregion
5531 5552
5532 AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData; 5553 bool update = false;
5533 5554 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5534 // We can only check when we have something to check
5535 // against.
5536 5555
5537 if (lastarg != null) 5556 if (m_lastAgentUpdateArgs != null)
5538 { 5557 {
5558 // These should be ordered from most-likely to
5559 // least likely to change. I've made an initial
5560 // guess at that.
5539 update = 5561 update =
5540 ( 5562 (
5541 (x.BodyRotation != lastarg.BodyRotation) || 5563 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
5542 (x.CameraAtAxis != lastarg.CameraAtAxis) || 5564 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
5543 (x.CameraCenter != lastarg.CameraCenter) || 5565 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5544 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5566 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5545 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5567 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5546 (x.ControlFlags != lastarg.ControlFlags) || 5568 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5547 (x.ControlFlags != 0) || 5569 (x.ControlFlags != 0) ||
5548 (x.Far != lastarg.Far) || 5570 (x.Far != m_lastAgentUpdateArgs.Far) ||
5549 (x.Flags != lastarg.Flags) || 5571 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5550 (x.State != lastarg.State) || 5572 (x.State != m_lastAgentUpdateArgs.State) ||
5551 (x.HeadRotation != lastarg.HeadRotation) || 5573 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5552 (x.SessionID != lastarg.SessionID) || 5574 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5553 (x.AgentID != lastarg.AgentID) 5575 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5554 ); 5576 );
5555 } 5577 }
5556 else 5578 else
5557 { 5579 {
5580 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5558 update = true; 5581 update = true;
5559 } 5582 }
5560 5583
5561 // These should be ordered from most-likely to
5562 // least likely to change. I've made an initial
5563 // guess at that.
5564
5565 if (update) 5584 if (update)
5566 { 5585 {
5567// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5586// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
5568 5587
5569 AgentUpdateArgs arg = new AgentUpdateArgs(); 5588 m_lastAgentUpdateArgs.AgentID = x.AgentID;
5570 arg.AgentID = x.AgentID; 5589 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
5571 arg.BodyRotation = x.BodyRotation; 5590 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5572 arg.CameraAtAxis = x.CameraAtAxis; 5591 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
5573 arg.CameraCenter = x.CameraCenter; 5592 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5574 arg.CameraLeftAxis = x.CameraLeftAxis; 5593 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5575 arg.CameraUpAxis = x.CameraUpAxis; 5594 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
5576 arg.ControlFlags = x.ControlFlags; 5595 m_lastAgentUpdateArgs.Far = x.Far;
5577 arg.Far = x.Far; 5596 m_lastAgentUpdateArgs.Flags = x.Flags;
5578 arg.Flags = x.Flags; 5597 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5579 arg.HeadRotation = x.HeadRotation; 5598 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5580 arg.SessionID = x.SessionID; 5599 m_lastAgentUpdateArgs.State = x.State;
5581 arg.State = x.State; 5600
5582 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5601 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5583 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5602 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5584 lastarg = arg; // save this set of arguments for nexttime 5603
5585 if (handlerPreAgentUpdate != null) 5604 if (handlerPreAgentUpdate != null)
5586 OnPreAgentUpdate(this, arg); 5605 OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
5606
5587 if (handlerAgentUpdate != null) 5607 if (handlerAgentUpdate != null)
5588 OnAgentUpdate(this, arg); 5608 OnAgentUpdate(this, m_lastAgentUpdateArgs);
5589 5609
5590 handlerAgentUpdate = null; 5610 handlerAgentUpdate = null;
5591 handlerPreAgentUpdate = null; 5611 handlerPreAgentUpdate = null;
5592 } 5612 }
5593 } 5613 }
5594 5614
5615 PacketPool.Instance.ReturnPacket(packet);
5616
5595 return true; 5617 return true;
5596 } 5618 }
5597 5619
@@ -5963,7 +5985,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5963 msgpack.MessageBlock.ID, 5985 msgpack.MessageBlock.ID,
5964 msgpack.MessageBlock.Offline != 0 ? true : false, 5986 msgpack.MessageBlock.Offline != 0 ? true : false,
5965 msgpack.MessageBlock.Position, 5987 msgpack.MessageBlock.Position,
5966 msgpack.MessageBlock.BinaryBucket); 5988 msgpack.MessageBlock.BinaryBucket,
5989 true);
5967 5990
5968 handlerInstantMessage(this, im); 5991 handlerInstantMessage(this, im);
5969 } 5992 }
@@ -9245,7 +9268,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9245 } 9268 }
9246 #endregion 9269 #endregion
9247 9270
9248 switch (Utils.BytesToString(messagePacket.MethodData.Method)) 9271 string method = Utils.BytesToString(messagePacket.MethodData.Method);
9272
9273 switch (method)
9249 { 9274 {
9250 case "getinfo": 9275 case "getinfo":
9251 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 9276 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9561,7 +9586,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9561 return true; 9586 return true;
9562 9587
9563 default: 9588 default:
9564 m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); 9589 m_log.WarnFormat(
9590 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
9591 method, Name, Scene.Name);
9592
9593 for (int i = 0; i < messagePacket.ParamList.Length; i++)
9594 {
9595 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
9596 string data = (string)Utils.BytesToString(block.Parameter);
9597 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
9598 }
9599
9565 return true; 9600 return true;
9566 } 9601 }
9567 9602
@@ -11949,7 +11984,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11949 logPacket = false; 11984 logPacket = false;
11950 11985
11951 if (DebugPacketLevel <= 50 11986 if (DebugPacketLevel <= 50
11952 & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 11987 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
11953 logPacket = false; 11988 logPacket = false;
11954 11989
11955 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) 11990 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -12023,8 +12058,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12023 12058
12024 if (!ProcessPacketMethod(packet)) 12059 if (!ProcessPacketMethod(packet))
12025 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 12060 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
12026
12027 PacketPool.Instance.ReturnPacket(packet);
12028 } 12061 }
12029 12062
12030 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 12063 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -12193,7 +12226,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12193 { 12226 {
12194 Kick(reason); 12227 Kick(reason);
12195 Thread.Sleep(1000); 12228 Thread.Sleep(1000);
12196 Close(); 12229 Disconnect();
12197 } 12230 }
12198 12231
12199 public void Disconnect() 12232 public void Disconnect()
@@ -12481,7 +12514,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12481 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12514 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12482 12515
12483 12516
12484 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 12517 ImprovedTerseObjectUpdatePacket packet
12518 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12519 PacketType.ImprovedTerseObjectUpdate);
12520
12485 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 12521 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12486 packet.RegionData.TimeDilation = timeDilation; 12522 packet.RegionData.TimeDilation = timeDilation;
12487 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 12523 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index d6513c5..df4bbb3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -37,6 +37,7 @@ using log4net;
37using Nini.Config; 37using Nini.Config;
38using OpenMetaverse.Packets; 38using OpenMetaverse.Packets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Console;
40using OpenSim.Framework.Monitoring; 41using OpenSim.Framework.Monitoring;
41using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
42using OpenMetaverse; 43using OpenMetaverse;
@@ -100,9 +101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 101
101 /// <summary>The measured resolution of Environment.TickCount</summary> 102 /// <summary>The measured resolution of Environment.TickCount</summary>
102 public readonly float TickCountResolution; 103 public readonly float TickCountResolution;
104
103 /// <summary>Number of prim updates to put on the queue each time the 105 /// <summary>Number of prim updates to put on the queue each time the
104 /// OnQueueEmpty event is triggered for updates</summary> 106 /// OnQueueEmpty event is triggered for updates</summary>
105 public readonly int PrimUpdatesPerCallback; 107 public readonly int PrimUpdatesPerCallback;
108
106 /// <summary>Number of texture packets to put on the queue each time the 109 /// <summary>Number of texture packets to put on the queue each time the
107 /// OnQueueEmpty event is triggered for textures</summary> 110 /// OnQueueEmpty event is triggered for textures</summary>
108 public readonly int TextureSendLimit; 111 public readonly int TextureSendLimit;
@@ -124,28 +127,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
124 127
125 /// <summary>Manages authentication for agent circuits</summary> 128 /// <summary>Manages authentication for agent circuits</summary>
126 private AgentCircuitManager m_circuitManager; 129 private AgentCircuitManager m_circuitManager;
130
127 /// <summary>Reference to the scene this UDP server is attached to</summary> 131 /// <summary>Reference to the scene this UDP server is attached to</summary>
128 protected Scene m_scene; 132 protected Scene m_scene;
133
129 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 134 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
130 private Location m_location; 135 private Location m_location;
136
131 /// <summary>The size of the receive buffer for the UDP socket. This value 137 /// <summary>The size of the receive buffer for the UDP socket. This value
132 /// is passed up to the operating system and used in the system networking 138 /// is passed up to the operating system and used in the system networking
133 /// stack. Use zero to leave this value as the default</summary> 139 /// stack. Use zero to leave this value as the default</summary>
134 private int m_recvBufferSize; 140 private int m_recvBufferSize;
141
135 /// <summary>Flag to process packets asynchronously or synchronously</summary> 142 /// <summary>Flag to process packets asynchronously or synchronously</summary>
136 private bool m_asyncPacketHandling; 143 private bool m_asyncPacketHandling;
144
137 /// <summary>Tracks whether or not a packet was sent each round so we know 145 /// <summary>Tracks whether or not a packet was sent each round so we know
138 /// whether or not to sleep</summary> 146 /// whether or not to sleep</summary>
139 private bool m_packetSent; 147 private bool m_packetSent;
140 148
141 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 149 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
142 private int m_elapsedMSSinceLastStatReport = 0; 150 private int m_elapsedMSSinceLastStatReport = 0;
151
143 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 152 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
144 private int m_tickLastOutgoingPacketHandler; 153 private int m_tickLastOutgoingPacketHandler;
154
145 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 155 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
146 private int m_elapsedMSOutgoingPacketHandler; 156 private int m_elapsedMSOutgoingPacketHandler;
157
147 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 158 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
148 private int m_elapsed100MSOutgoingPacketHandler; 159 private int m_elapsed100MSOutgoingPacketHandler;
160
149 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 161 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
150 private int m_elapsed500MSOutgoingPacketHandler; 162 private int m_elapsed500MSOutgoingPacketHandler;
151 163
@@ -159,6 +171,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
159 protected bool m_sendPing; 171 protected bool m_sendPing;
160 172
161 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 173 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
174 private Pool<IncomingPacket> m_incomingPacketPool;
162 175
163 private int m_defaultRTO = 0; 176 private int m_defaultRTO = 0;
164 private int m_maxRTO = 0; 177 private int m_maxRTO = 0;
@@ -180,7 +193,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
180 /// </summary> 193 /// </summary>
181 private IClientAPI m_currentIncomingClient; 194 private IClientAPI m_currentIncomingClient;
182 195
183 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 196 public LLUDPServer(
197 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
198 IConfigSource configSource, AgentCircuitManager circuitManager)
184 : base(listenIP, (int)port) 199 : base(listenIP, (int)port)
185 { 200 {
186 #region Environment.TickCount Measurement 201 #region Environment.TickCount Measurement
@@ -227,6 +242,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
227 m_pausedAckTimeout = 1000 * 300; // 5 minutes 242 m_pausedAckTimeout = 1000 * 300; // 5 minutes
228 } 243 }
229 244
245 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
246 // However, there is no harm in temporarily doing it multiple times.
247 IConfig packetConfig = configSource.Configs["PacketPool"];
248 if (packetConfig != null)
249 {
250 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
251 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
252 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
253 }
254
230 #region BinaryStats 255 #region BinaryStats
231 config = configSource.Configs["Statistics.Binary"]; 256 config = configSource.Configs["Statistics.Binary"];
232 m_shouldCollectStats = false; 257 m_shouldCollectStats = false;
@@ -254,20 +279,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 279
255 m_throttle = new TokenBucket(null, sceneThrottleBps); 280 m_throttle = new TokenBucket(null, sceneThrottleBps);
256 ThrottleRates = new ThrottleRates(configSource); 281 ThrottleRates = new ThrottleRates(configSource);
282
283 if (UsePools)
284 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
257 } 285 }
258 286
259 public void Start() 287 public void Start()
260 { 288 {
261 if (m_scene == null) 289 StartInbound();
262 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 290 StartOutbound();
263 291
292 m_elapsedMSSinceLastStatReport = Environment.TickCount;
293 }
294
295 private void StartInbound()
296 {
264 m_log.InfoFormat( 297 m_log.InfoFormat(
265 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", 298 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
266 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 299 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
267 300
268 base.Start(m_recvBufferSize, m_asyncPacketHandling); 301 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
269 302
270 // Start the packet processing threads 303 // This thread will process the packets received that are placed on the packetInbox
271 Watchdog.StartThread( 304 Watchdog.StartThread(
272 IncomingPacketHandler, 305 IncomingPacketHandler,
273 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 306 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -276,6 +309,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
276 true, 309 true,
277 GetWatchdogIncomingAlarmData, 310 GetWatchdogIncomingAlarmData,
278 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 311 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
312 }
313
314 private new void StartOutbound()
315 {
316 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
317
318 base.StartOutbound();
279 319
280 Watchdog.StartThread( 320 Watchdog.StartThread(
281 OutgoingPacketHandler, 321 OutgoingPacketHandler,
@@ -285,8 +325,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 true, 325 true,
286 GetWatchdogOutgoingAlarmData, 326 GetWatchdogOutgoingAlarmData,
287 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 327 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
328 }
288 329
289 m_elapsedMSSinceLastStatReport = Environment.TickCount; 330 public void Stop()
331 {
332 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
333 base.StopOutbound();
334 base.StopInbound();
290 } 335 }
291 336
292 /// <summary> 337 /// <summary>
@@ -311,12 +356,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); 356 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
312 } 357 }
313 358
314 public new void Stop()
315 {
316 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
317 base.Stop();
318 }
319
320 public void AddScene(IScene scene) 359 public void AddScene(IScene scene)
321 { 360 {
322 if (m_scene != null) 361 if (m_scene != null)
@@ -333,6 +372,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 372
334 m_scene = (Scene)scene; 373 m_scene = (Scene)scene;
335 m_location = new Location(m_scene.RegionInfo.RegionHandle); 374 m_location = new Location(m_scene.RegionInfo.RegionHandle);
375
376 MainConsole.Instance.Commands.AddCommand(
377 "Debug",
378 false,
379 "debug lludp start",
380 "debug lludp start <in|out|all>",
381 "Control LLUDP packet processing.",
382 "No effect if packet processing has already started.\n"
383 + "in - start inbound processing.\n"
384 + "out - start outbound processing.\n"
385 + "all - start in and outbound processing.\n",
386 HandleStartCommand);
387
388 MainConsole.Instance.Commands.AddCommand(
389 "Debug",
390 false,
391 "debug lludp stop",
392 "debug lludp stop <in|out|all>",
393 "Stop LLUDP packet processing.",
394 "No effect if packet processing has already stopped.\n"
395 + "in - stop inbound processing.\n"
396 + "out - stop outbound processing.\n"
397 + "all - stop in and outbound processing.\n",
398 HandleStopCommand);
399
400 MainConsole.Instance.Commands.AddCommand(
401 "Debug",
402 false,
403 "debug lludp status",
404 "debug lludp status",
405 "Return status of LLUDP packet processing.",
406 HandleStatusCommand);
407 }
408
409 private void HandleStartCommand(string module, string[] args)
410 {
411 if (args.Length != 4)
412 {
413 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
414 return;
415 }
416
417 string subCommand = args[3];
418
419 if (subCommand == "in" || subCommand == "all")
420 StartInbound();
421
422 if (subCommand == "out" || subCommand == "all")
423 StartOutbound();
424 }
425
426 private void HandleStopCommand(string module, string[] args)
427 {
428 if (args.Length != 4)
429 {
430 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
431 return;
432 }
433
434 string subCommand = args[3];
435
436 if (subCommand == "in" || subCommand == "all")
437 StopInbound();
438
439 if (subCommand == "out" || subCommand == "all")
440 StopOutbound();
441 }
442
443 private void HandleStatusCommand(string module, string[] args)
444 {
445 MainConsole.Instance.OutputFormat(
446 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
447
448 MainConsole.Instance.OutputFormat(
449 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
336 } 450 }
337 451
338 public bool HandlesRegion(Location x) 452 public bool HandlesRegion(Location x)
@@ -416,6 +530,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 byte[] data = packet.ToBytes(); 530 byte[] data = packet.ToBytes();
417 SendPacketData(udpClient, data, packet.Type, category, method); 531 SendPacketData(udpClient, data, packet.Type, category, method);
418 } 532 }
533
534 PacketPool.Instance.ReturnPacket(packet);
419 } 535 }
420 536
421 /// <summary> 537 /// <summary>
@@ -700,7 +816,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 LLUDPClient udpClient = null; 816 LLUDPClient udpClient = null;
701 Packet packet = null; 817 Packet packet = null;
702 int packetEnd = buffer.DataLength - 1; 818 int packetEnd = buffer.DataLength - 1;
703 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 819 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
704 820
705 #region Decoding 821 #region Decoding
706 822
@@ -710,7 +826,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 826// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
711// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 827// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
712 828
713 return; // Drop undersizd packet 829 return; // Drop undersized packet
714 } 830 }
715 831
716 int headerLen = 7; 832 int headerLen = 7;
@@ -733,7 +849,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
733 849
734 try 850 try
735 { 851 {
736 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 852// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
853// // Only allocate a buffer for zerodecoding if the packet is zerocoded
854// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
855 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
856 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
857 // bytes are copied out).
858 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
737 // Only allocate a buffer for zerodecoding if the packet is zerocoded 859 // Only allocate a buffer for zerodecoding if the packet is zerocoded
738 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 860 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
739 } 861 }
@@ -748,11 +870,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
748 870
749 return; // Drop short packet 871 return; // Drop short packet
750 } 872 }
751 catch(Exception e) 873 catch (Exception e)
752 { 874 {
753 if (m_malformedCount < 100) 875 if (m_malformedCount < 100)
754 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 876 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
877
755 m_malformedCount++; 878 m_malformedCount++;
879
756 if ((m_malformedCount % 100000) == 0) 880 if ((m_malformedCount % 100000) == 0)
757 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); 881 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
758 } 882 }
@@ -772,7 +896,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
772 896
773 // If there is already a client for this endpoint, don't process UseCircuitCode 897 // If there is already a client for this endpoint, don't process UseCircuitCode
774 IClientAPI client = null; 898 IClientAPI client = null;
775 if (!m_scene.TryGetClient(address, out client)) 899 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
776 { 900 {
777 // UseCircuitCode handling 901 // UseCircuitCode handling
778 if (packet.Type == PacketType.UseCircuitCode) 902 if (packet.Type == PacketType.UseCircuitCode)
@@ -780,13 +904,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
780 // And if there is a UseCircuitCode pending, also drop it 904 // And if there is a UseCircuitCode pending, also drop it
781 lock (m_pendingCache) 905 lock (m_pendingCache)
782 { 906 {
783 if (m_pendingCache.Contains(address)) 907 if (m_pendingCache.Contains(endPoint))
784 return; 908 return;
785 909
786 m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); 910 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
787 } 911 }
788 912
789 object[] array = new object[] { buffer, packet }; 913 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
914 // buffer.
915 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
790 916
791 Util.FireAndForget(HandleUseCircuitCode, array); 917 Util.FireAndForget(HandleUseCircuitCode, array);
792 918
@@ -798,7 +924,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
798 lock (m_pendingCache) 924 lock (m_pendingCache)
799 { 925 {
800 Queue<UDPPacketBuffer> queue; 926 Queue<UDPPacketBuffer> queue;
801 if (m_pendingCache.TryGetValue(address, out queue)) 927 if (m_pendingCache.TryGetValue(endPoint, out queue))
802 { 928 {
803 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); 929 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
804 queue.Enqueue(buffer); 930 queue.Enqueue(buffer);
@@ -834,6 +960,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
834 // Handle appended ACKs 960 // Handle appended ACKs
835 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 961 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
836 { 962 {
963// m_log.DebugFormat(
964// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
965// packet.Header.AckList.Length, client.Name, m_scene.Name);
966
837 for (int i = 0; i < packet.Header.AckList.Length; i++) 967 for (int i = 0; i < packet.Header.AckList.Length; i++)
838 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 968 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
839 } 969 }
@@ -843,6 +973,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
843 { 973 {
844 PacketAckPacket ackPacket = (PacketAckPacket)packet; 974 PacketAckPacket ackPacket = (PacketAckPacket)packet;
845 975
976// m_log.DebugFormat(
977// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
978// ackPacket.Packets.Length, client.Name, m_scene.Name);
979
846 for (int i = 0; i < ackPacket.Packets.Length; i++) 980 for (int i = 0; i < ackPacket.Packets.Length; i++)
847 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 981 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
848 982
@@ -856,6 +990,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
856 990
857 if (packet.Header.Reliable) 991 if (packet.Header.Reliable)
858 { 992 {
993// m_log.DebugFormat(
994// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
995// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
996
859 udpClient.PendingAcks.Enqueue(packet.Header.Sequence); 997 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
860 998
861 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 999 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
@@ -902,6 +1040,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
902 1040
903 if (packet.Type == PacketType.StartPingCheck) 1041 if (packet.Type == PacketType.StartPingCheck)
904 { 1042 {
1043// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1044
905 // We don't need to do anything else with ping checks 1045 // We don't need to do anything else with ping checks
906 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1046 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
907 CompletePing(udpClient, startPing.PingID.PingID); 1047 CompletePing(udpClient, startPing.PingID.PingID);
@@ -921,13 +1061,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
921 1061
922 #endregion Ping Check Handling 1062 #endregion Ping Check Handling
923 1063
1064 IncomingPacket incomingPacket;
1065
924 // Inbox insertion 1066 // Inbox insertion
925 if (packet.Type == PacketType.AgentUpdate || 1067 if (UsePools)
926 packet.Type == PacketType.ChatFromViewer) 1068 {
927 packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); 1069 incomingPacket = m_incomingPacketPool.GetObject();
1070 incomingPacket.Client = (LLClientView)client;
1071 incomingPacket.Packet = packet;
1072 }
1073 else
1074 {
1075 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1076 }
1077
1078 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1079 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1080 packetInbox.EnqueueHigh(incomingPacket);
928 else 1081 else
929 packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); 1082 packetInbox.EnqueueLow(incomingPacket);
930// packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
931 } 1083 }
932 1084
933 #region BinaryStats 1085 #region BinaryStats
@@ -1013,21 +1165,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1013 1165
1014 private void HandleUseCircuitCode(object o) 1166 private void HandleUseCircuitCode(object o)
1015 { 1167 {
1016 IPEndPoint remoteEndPoint = null; 1168 IPEndPoint endPoint = null;
1017 IClientAPI client = null; 1169 IClientAPI client = null;
1018 1170
1019 try 1171 try
1020 { 1172 {
1021 // DateTime startTime = DateTime.Now; 1173 // DateTime startTime = DateTime.Now;
1022 object[] array = (object[])o; 1174 object[] array = (object[])o;
1023 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1175 endPoint = (IPEndPoint)array[0];
1024 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1176 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1025 1177
1026 m_log.DebugFormat( 1178 m_log.DebugFormat(
1027 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1179 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1028 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1180 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1029
1030 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1031 1181
1032 AuthenticateResponse sessionInfo; 1182 AuthenticateResponse sessionInfo;
1033 if (IsClientAuthorized(uccp, out sessionInfo)) 1183 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1038,13 +1188,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1038 uccp.CircuitCode.Code, 1188 uccp.CircuitCode.Code,
1039 uccp.CircuitCode.ID, 1189 uccp.CircuitCode.ID,
1040 uccp.CircuitCode.SessionID, 1190 uccp.CircuitCode.SessionID,
1041 remoteEndPoint, 1191 endPoint,
1042 sessionInfo); 1192 sessionInfo);
1043 1193
1044 // Send ack straight away to let the viewer know that the connection is active. 1194 // Send ack straight away to let the viewer know that the connection is active.
1045 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1195 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1046 // circuit code to the existing child agent. This is not particularly obvious. 1196 // circuit code to the existing child agent. This is not particularly obvious.
1047 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1197 SendAckImmediate(endPoint, uccp.Header.Sequence);
1048 1198
1049 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1199 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1050 if (client != null) 1200 if (client != null)
@@ -1058,12 +1208,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 1208
1059 lock (m_pendingCache) 1209 lock (m_pendingCache)
1060 { 1210 {
1061 if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) 1211 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1062 { 1212 {
1063 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1213 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1064 return; 1214 return;
1065 } 1215 }
1066 m_pendingCache.Remove(remoteEndPoint); 1216 m_pendingCache.Remove(endPoint);
1067 } 1217 }
1068 1218
1069 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1219 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@@ -1081,9 +1231,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 // Don't create clients for unauthorized requesters. 1231 // Don't create clients for unauthorized requesters.
1082 m_log.WarnFormat( 1232 m_log.WarnFormat(
1083 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1233 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1084 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1234 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1085 lock (m_pendingCache) 1235 lock (m_pendingCache)
1086 m_pendingCache.Remove(remoteEndPoint); 1236 m_pendingCache.Remove(endPoint);
1087 } 1237 }
1088 1238
1089 // m_log.DebugFormat( 1239 // m_log.DebugFormat(
@@ -1095,7 +1245,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1095 { 1245 {
1096 m_log.ErrorFormat( 1246 m_log.ErrorFormat(
1097 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1247 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1098 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1248 endPoint != null ? endPoint.ToString() : "n/a",
1099 client != null ? client.Name : "unknown", 1249 client != null ? client.Name : "unknown",
1100 client != null ? client.AgentId.ToString() : "unknown", 1250 client != null ? client.AgentId.ToString() : "unknown",
1101 e.Message, 1251 e.Message,
@@ -1160,20 +1310,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1160 { 1310 {
1161 IClientAPI client = null; 1311 IClientAPI client = null;
1162 1312
1163 // In priciple there shouldn't be more than one thread here, ever. 1313 // We currently synchronize this code across the whole scene to avoid issues such as
1164 // But in case that happens, we need to synchronize this piece of code 1314 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1165 // because it's too important 1315 // consistently, this lock could probably be removed.
1166 lock (this) 1316 lock (this)
1167 { 1317 {
1168 if (!m_scene.TryGetClient(agentID, out client)) 1318 if (!m_scene.TryGetClient(agentID, out client))
1169 { 1319 {
1170 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1320 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1171 1321
1172 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1322 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1173 client.OnLogout += LogoutHandler; 1323 client.OnLogout += LogoutHandler;
1174 1324
1175 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1325 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1176 1326
1177 client.Start(); 1327 client.Start();
1178 } 1328 }
1179 } 1329 }
@@ -1212,7 +1362,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1212 // on to en-US to avoid number parsing issues 1362 // on to en-US to avoid number parsing issues
1213 Culture.SetCurrentCulture(); 1363 Culture.SetCurrentCulture();
1214 1364
1215 while (base.IsRunning) 1365 while (IsRunningInbound)
1216 { 1366 {
1217 m_scene.ThreadAlive(1); 1367 m_scene.ThreadAlive(1);
1218 try 1368 try
@@ -1228,7 +1378,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1228 } 1378 }
1229 1379
1230 if (packetInbox.Dequeue(100, ref incomingPacket)) 1380 if (packetInbox.Dequeue(100, ref incomingPacket))
1381 {
1231 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); 1382 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
1383
1384 if (UsePools)
1385 m_incomingPacketPool.ReturnObject(incomingPacket);
1386 }
1232 } 1387 }
1233 catch (Exception ex) 1388 catch (Exception ex)
1234 { 1389 {
@@ -1255,7 +1410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1255 // Action generic every round 1410 // Action generic every round
1256 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1411 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1257 1412
1258 while (base.IsRunning) 1413 while (base.IsRunningOutbound)
1259 { 1414 {
1260 m_scene.ThreadAlive(2); 1415 m_scene.ThreadAlive(2);
1261 try 1416 try
@@ -1523,7 +1678,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1523 if (!client.IsLoggingOut) 1678 if (!client.IsLoggingOut)
1524 { 1679 {
1525 client.IsLoggingOut = true; 1680 client.IsLoggingOut = true;
1526 client.Close(false); 1681 client.Close(false, false);
1527 } 1682 }
1528 } 1683 }
1529 } 1684 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index cfe7c9d..e7d8a30 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -30,6 +30,7 @@ using System.Net;
30using System.Net.Sockets; 30using System.Net.Sockets;
31using System.Threading; 31using System.Threading;
32using log4net; 32using log4net;
33using OpenSim.Framework;
33 34
34namespace OpenMetaverse 35namespace OpenMetaverse
35{ 36{
@@ -58,17 +59,29 @@ namespace OpenMetaverse
58 /// <summary>Flag to process packets asynchronously or synchronously</summary> 59 /// <summary>Flag to process packets asynchronously or synchronously</summary>
59 private bool m_asyncPacketHandling; 60 private bool m_asyncPacketHandling;
60 61
61 /// <summary>The all important shutdown flag</summary> 62 /// <summary>
62 private volatile bool m_shutdownFlag = true; 63 /// Pool to use for handling data. May be null if UsePools = false;
64 /// </summary>
65 protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
63 66
64 /// <summary>Returns true if the server is currently listening, otherwise false</summary> 67 /// <summary>
65 public bool IsRunning { get { return !m_shutdownFlag; } } 68 /// Are we to use object pool(s) to reduce memory churn when receiving data?
69 /// </summary>
70 public bool UsePools { get; protected set; }
71
72 /// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
73 public bool IsRunningInbound { get; private set; }
74
75 /// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
76 /// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
77 public bool IsRunningOutbound { get; private set; }
66 78
67 /// <summary> 79 /// <summary>
68 /// Default constructor 80 /// Default constructor
69 /// </summary> 81 /// </summary>
70 /// <param name="bindAddress">Local IP address to bind the server to</param> 82 /// <param name="bindAddress">Local IP address to bind the server to</param>
71 /// <param name="port">Port to listening for incoming UDP packets on</param> 83 /// <param name="port">Port to listening for incoming UDP packets on</param>
84 /// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
72 public OpenSimUDPBase(IPAddress bindAddress, int port) 85 public OpenSimUDPBase(IPAddress bindAddress, int port)
73 { 86 {
74 m_localBindAddress = bindAddress; 87 m_localBindAddress = bindAddress;
@@ -76,7 +89,7 @@ namespace OpenMetaverse
76 } 89 }
77 90
78 /// <summary> 91 /// <summary>
79 /// Start the UDP server 92 /// Start inbound UDP packet handling.
80 /// </summary> 93 /// </summary>
81 /// <param name="recvBufferSize">The size of the receive buffer for 94 /// <param name="recvBufferSize">The size of the receive buffer for
82 /// the UDP socket. This value is passed up to the operating system 95 /// the UDP socket. This value is passed up to the operating system
@@ -91,11 +104,16 @@ namespace OpenMetaverse
91 /// manner (not throwing an exception when the remote side resets the 104 /// manner (not throwing an exception when the remote side resets the
92 /// connection). This call is ignored on Mono where the flag is not 105 /// connection). This call is ignored on Mono where the flag is not
93 /// necessary</remarks> 106 /// necessary</remarks>
94 public void Start(int recvBufferSize, bool asyncPacketHandling) 107 public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
95 { 108 {
109 if (UsePools)
110 m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
111 else
112 m_pool = null;
113
96 m_asyncPacketHandling = asyncPacketHandling; 114 m_asyncPacketHandling = asyncPacketHandling;
97 115
98 if (m_shutdownFlag) 116 if (!IsRunningInbound)
99 { 117 {
100 const int SIO_UDP_CONNRESET = -1744830452; 118 const int SIO_UDP_CONNRESET = -1744830452;
101 119
@@ -123,8 +141,7 @@ namespace OpenMetaverse
123 141
124 m_udpSocket.Bind(ipep); 142 m_udpSocket.Bind(ipep);
125 143
126 // we're not shutting down, we're starting up 144 IsRunningInbound = true;
127 m_shutdownFlag = false;
128 145
129 // kick off an async receive. The Start() method will return, the 146 // kick off an async receive. The Start() method will return, the
130 // actual receives will occur asynchronously and will be caught in 147 // actual receives will occur asynchronously and will be caught in
@@ -134,28 +151,41 @@ namespace OpenMetaverse
134 } 151 }
135 152
136 /// <summary> 153 /// <summary>
137 /// Stops the UDP server 154 /// Start outbound UDP packet handling.
138 /// </summary> 155 /// </summary>
139 public void Stop() 156 public void StartOutbound()
140 { 157 {
141 if (!m_shutdownFlag) 158 IsRunningOutbound = true;
159 }
160
161 public void StopInbound()
162 {
163 if (IsRunningInbound)
142 { 164 {
143 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 165 // wait indefinitely for a writer lock. Once this is called, the .NET runtime
144 // will deny any more reader locks, in effect blocking all other send/receive 166 // will deny any more reader locks, in effect blocking all other send/receive
145 // threads. Once we have the lock, we set shutdownFlag to inform the other 167 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
146 // threads that the socket is closed. 168 // threads that the socket is closed.
147 m_shutdownFlag = true; 169 IsRunningInbound = false;
148 m_udpSocket.Close(); 170 m_udpSocket.Close();
149 } 171 }
150 } 172 }
151 173
174 public void StopOutbound()
175 {
176 IsRunningOutbound = false;
177 }
178
152 private void AsyncBeginReceive() 179 private void AsyncBeginReceive()
153 { 180 {
154 // allocate a packet buffer 181 UDPPacketBuffer buf;
155 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 182
156 UDPPacketBuffer buf = new UDPPacketBuffer(); 183 if (UsePools)
184 buf = m_pool.GetObject();
185 else
186 buf = new UDPPacketBuffer();
157 187
158 if (!m_shutdownFlag) 188 if (IsRunningInbound)
159 { 189 {
160 try 190 try
161 { 191 {
@@ -208,7 +238,7 @@ namespace OpenMetaverse
208 { 238 {
209 // Asynchronous receive operations will complete here through the call 239 // Asynchronous receive operations will complete here through the call
210 // to AsyncBeginReceive 240 // to AsyncBeginReceive
211 if (!m_shutdownFlag) 241 if (IsRunningInbound)
212 { 242 {
213 // Asynchronous mode will start another receive before the 243 // Asynchronous mode will start another receive before the
214 // callback for this packet is even fired. Very parallel :-) 244 // callback for this packet is even fired. Very parallel :-)
@@ -217,8 +247,6 @@ namespace OpenMetaverse
217 247
218 // get the buffer that was created in AsyncBeginReceive 248 // get the buffer that was created in AsyncBeginReceive
219 // this is the received data 249 // this is the received data
220 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
221 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
222 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 250 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
223 251
224 try 252 try
@@ -235,7 +263,8 @@ namespace OpenMetaverse
235 catch (ObjectDisposedException) { } 263 catch (ObjectDisposedException) { }
236 finally 264 finally
237 { 265 {
238 //wrappedBuffer.Dispose(); 266 if (UsePools)
267 m_pool.ReturnObject(buffer);
239 268
240 // Synchronous mode waits until the packet callback completes 269 // Synchronous mode waits until the packet callback completes
241 // before starting the receive to fetch another packet 270 // before starting the receive to fetch another packet
@@ -248,7 +277,7 @@ namespace OpenMetaverse
248 277
249 public void AsyncBeginSend(UDPPacketBuffer buf) 278 public void AsyncBeginSend(UDPPacketBuffer buf)
250 { 279 {
251 if (!m_shutdownFlag) 280 if (IsRunningOutbound)
252 { 281 {
253 try 282 try
254 { 283 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..2a3d14f
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,288 @@
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.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework.Monitoring;
35
36namespace OpenSim.Region.ClientStack.LindenUDP
37{
38 public sealed class PacketPool
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private static readonly PacketPool instance = new PacketPool();
43
44 private bool packetPoolEnabled = true;
45 private bool dataBlockPoolEnabled = true;
46
47 private PercentageStat m_packetsReusedStat = new PercentageStat(
48 "PacketsReused",
49 "Packets reused",
50 "clientstack",
51 "packetpool",
52 StatVerbosity.Debug,
53 "Number of packets reused out of all requests to the packet pool");
54
55 private PercentageStat m_blocksReusedStat = new PercentageStat(
56 "BlocksReused",
57 "Blocks reused",
58 "clientstack",
59 "packetpool",
60 StatVerbosity.Debug,
61 "Number of data blocks reused out of all requests to the packet pool");
62
63 /// <summary>
64 /// Pool of packets available for reuse.
65 /// </summary>
66 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
67
68 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
69
70 public static PacketPool Instance
71 {
72 get { return instance; }
73 }
74
75 public bool RecyclePackets
76 {
77 set { packetPoolEnabled = value; }
78 get { return packetPoolEnabled; }
79 }
80
81 public bool RecycleDataBlocks
82 {
83 set { dataBlockPoolEnabled = value; }
84 get { return dataBlockPoolEnabled; }
85 }
86
87 private PacketPool()
88 {
89 StatsManager.RegisterStat(m_packetsReusedStat);
90 StatsManager.RegisterStat(m_blocksReusedStat);
91 }
92
93 /// <summary>
94 /// Gets a packet of the given type.
95 /// </summary>
96 /// <param name='type'></param>
97 /// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
98 public Packet GetPacket(PacketType type)
99 {
100 m_packetsReusedStat.Consequent++;
101
102 Packet packet;
103
104 if (!packetPoolEnabled)
105 return Packet.BuildPacket(type);
106
107 lock (pool)
108 {
109 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
110 {
111// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
112
113 // Creating a new packet if we cannot reuse an old package
114 packet = Packet.BuildPacket(type);
115 }
116 else
117 {
118// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
119
120 // Recycle old packages
121 m_packetsReusedStat.Antecedent++;
122
123 packet = pool[type].Pop();
124 }
125 }
126
127 return packet;
128 }
129
130 // private byte[] decoded_header = new byte[10];
131 private static PacketType GetType(byte[] bytes)
132 {
133 byte[] decoded_header = new byte[10 + 8];
134 ushort id;
135 PacketFrequency freq;
136
137 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
138 {
139 Helpers.ZeroDecode(bytes, 16, decoded_header);
140 }
141 else
142 {
143 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
144 }
145
146 if (decoded_header[6] == 0xFF)
147 {
148 if (decoded_header[7] == 0xFF)
149 {
150 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
151 freq = PacketFrequency.Low;
152 }
153 else
154 {
155 id = decoded_header[7];
156 freq = PacketFrequency.Medium;
157 }
158 }
159 else
160 {
161 id = decoded_header[6];
162 freq = PacketFrequency.High;
163 }
164
165 return Packet.GetType(id, freq);
166 }
167
168 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
169 {
170 PacketType type = GetType(bytes);
171
172// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
173
174 int i = 0;
175 Packet packet = GetPacket(type);
176 if (packet == null)
177 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
178 else
179 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
180
181 return packet;
182 }
183
184 /// <summary>
185 /// Return a packet to the packet pool
186 /// </summary>
187 /// <param name="packet"></param>
188 public void ReturnPacket(Packet packet)
189 {
190 if (dataBlockPoolEnabled)
191 {
192 switch (packet.Type)
193 {
194 case PacketType.ObjectUpdate:
195 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
196
197 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
198 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
199
200 oup.ObjectData = null;
201 break;
202
203 case PacketType.ImprovedTerseObjectUpdate:
204 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
205
206 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
207 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
208
209 itoup.ObjectData = null;
210 break;
211 }
212 }
213
214 if (packetPoolEnabled)
215 {
216 switch (packet.Type)
217 {
218 // List pooling packets here
219 case PacketType.AgentUpdate:
220 case PacketType.PacketAck:
221 case PacketType.ObjectUpdate:
222 case PacketType.ImprovedTerseObjectUpdate:
223 lock (pool)
224 {
225 PacketType type = packet.Type;
226
227 if (!pool.ContainsKey(type))
228 {
229 pool[type] = new Stack<Packet>();
230 }
231
232 if ((pool[type]).Count < 50)
233 {
234// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
235
236 pool[type].Push(packet);
237 }
238 }
239 break;
240
241 // Other packets wont pool
242 default:
243 return;
244 }
245 }
246 }
247
248 public T GetDataBlock<T>() where T: new()
249 {
250 lock (DataBlocks)
251 {
252 m_blocksReusedStat.Consequent++;
253
254 Stack<Object> s;
255
256 if (DataBlocks.TryGetValue(typeof(T), out s))
257 {
258 if (s.Count > 0)
259 {
260 m_blocksReusedStat.Antecedent++;
261 return (T)s.Pop();
262 }
263 }
264 else
265 {
266 DataBlocks[typeof(T)] = new Stack<Object>();
267 }
268
269 return new T();
270 }
271 }
272
273 public void ReturnDataBlock<T>(T block) where T: new()
274 {
275 if (block == null)
276 return;
277
278 lock (DataBlocks)
279 {
280 if (!DataBlocks.ContainsKey(typeof(T)))
281 DataBlocks[typeof(T)] = new Stack<Object>();
282
283 if (DataBlocks[typeof(T)].Count < 50)
284 DataBlocks[typeof(T)].Push(block);
285 }
286 }
287 }
288} \ No newline at end of file
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
index 109a8e1..556df30 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs
@@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
43 /// This will contain basic tests for the LindenUDP client stack 43 /// This will contain basic tests for the LindenUDP client stack
44 /// </summary> 44 /// </summary>
45 [TestFixture] 45 [TestFixture]
46 public class BasicCircuitTests 46 public class BasicCircuitTests : OpenSimTestCase
47 { 47 {
48 private Scene m_scene; 48 private Scene m_scene;
49 private TestLLUDPServer m_udpServer; 49 private TestLLUDPServer m_udpServer;
@@ -65,8 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
65 } 65 }
66 66
67 [SetUp] 67 [SetUp]
68 public void SetUp() 68 public override void SetUp()
69 { 69 {
70 base.SetUp();
70 m_scene = new SceneHelpers().SetupScene(); 71 m_scene = new SceneHelpers().SetupScene();
71 } 72 }
72 73
@@ -143,7 +144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
143 public void TestAddClient() 144 public void TestAddClient()
144 { 145 {
145 TestHelpers.InMethod(); 146 TestHelpers.InMethod();
146// XmlConfigurator.Configure(); 147// TestHelpers.EnableLogging();
147 148
148 AddUdpServer(); 149 AddUdpServer();
149 150