aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs139
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs227
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs61
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs7
6 files changed, 388 insertions, 128 deletions
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 62f51d9..7427c59 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -347,7 +347,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
347 private int m_moneyBalance; 347 private int m_moneyBalance;
348 private int m_animationSequenceNumber = 1; 348 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 349 private bool m_SendLogoutPacketWhenClosing = true;
350 private AgentUpdateArgs lastarg; 350
351 /// <summary>
352 /// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
353 /// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
354 /// is doing absolutely nothing.
355 /// </summary>
356 /// <remarks>
357 /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
358 /// cannot retain a reference to it outside of that method.
359 /// </remarks>
360 private AgentUpdateArgs m_lastAgentUpdateArgs;
351 361
352 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 362 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
353 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 363 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -3922,7 +3932,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3922 { 3932 {
3923 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3933 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3924 3934
3925 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3935 ImprovedTerseObjectUpdatePacket packet
3936 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3937
3926 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3938 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3927 packet.RegionData.TimeDilation = timeDilation; 3939 packet.RegionData.TimeDilation = timeDilation;
3928 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3940 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -3967,7 +3979,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3967 { 3979 {
3968 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3980 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3969 3981
3970 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3982 ImprovedTerseObjectUpdatePacket packet
3983 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
3984 PacketType.ImprovedTerseObjectUpdate);
3985
3971 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3986 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3972 packet.RegionData.TimeDilation = timeDilation; 3987 packet.RegionData.TimeDilation = timeDilation;
3973 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3988 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4959,7 +4974,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4959 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 4974 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
4960 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2; 4975 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
4961 4976
4962 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); 4977 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
4978 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
4979
4963 block.Data = data; 4980 block.Data = data;
4964 4981
4965 if (textureEntry != null && textureEntry.Length > 0) 4982 if (textureEntry != null && textureEntry.Length > 0)
@@ -5191,7 +5208,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5191 protected virtual void RegisterLocalPacketHandlers() 5208 protected virtual void RegisterLocalPacketHandlers()
5192 { 5209 {
5193 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout); 5210 AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
5211
5212 // If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
5213 // for each AgentUpdate packet.
5194 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false); 5214 AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
5215
5195 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false); 5216 AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
5196 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false); 5217 AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
5197 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false); 5218 AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
@@ -5418,80 +5439,83 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5418 5439
5419 #region Scene/Avatar 5440 #region Scene/Avatar
5420 5441
5421 private bool HandleAgentUpdate(IClientAPI sener, Packet Pack) 5442 private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
5422 { 5443 {
5423 if (OnAgentUpdate != null) 5444 if (OnAgentUpdate != null)
5424 { 5445 {
5425 bool update = false; 5446 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
5426 AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
5427 5447
5428 #region Packet Session and User Check 5448 #region Packet Session and User Check
5429 if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId) 5449 if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
5450 {
5451 PacketPool.Instance.ReturnPacket(packet);
5430 return false; 5452 return false;
5453 }
5431 #endregion 5454 #endregion
5432 5455
5433 AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData; 5456 bool update = false;
5434 5457 AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
5435 // We can only check when we have something to check
5436 // against.
5437 5458
5438 if (lastarg != null) 5459 if (m_lastAgentUpdateArgs != null)
5439 { 5460 {
5461 // These should be ordered from most-likely to
5462 // least likely to change. I've made an initial
5463 // guess at that.
5440 update = 5464 update =
5441 ( 5465 (
5442 (x.BodyRotation != lastarg.BodyRotation) || 5466 (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
5443 (x.CameraAtAxis != lastarg.CameraAtAxis) || 5467 (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
5444 (x.CameraCenter != lastarg.CameraCenter) || 5468 (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
5445 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5469 (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
5446 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5470 (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
5447 (x.ControlFlags != lastarg.ControlFlags) || 5471 (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
5448 (x.Far != lastarg.Far) || 5472 (x.Far != m_lastAgentUpdateArgs.Far) ||
5449 (x.Flags != lastarg.Flags) || 5473 (x.Flags != m_lastAgentUpdateArgs.Flags) ||
5450 (x.State != lastarg.State) || 5474 (x.State != m_lastAgentUpdateArgs.State) ||
5451 (x.HeadRotation != lastarg.HeadRotation) || 5475 (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
5452 (x.SessionID != lastarg.SessionID) || 5476 (x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
5453 (x.AgentID != lastarg.AgentID) 5477 (x.AgentID != m_lastAgentUpdateArgs.AgentID)
5454 ); 5478 );
5455 } 5479 }
5456 else 5480 else
5457 { 5481 {
5482 m_lastAgentUpdateArgs = new AgentUpdateArgs();
5458 update = true; 5483 update = true;
5459 } 5484 }
5460 5485
5461 // These should be ordered from most-likely to
5462 // least likely to change. I've made an initial
5463 // guess at that.
5464
5465 if (update) 5486 if (update)
5466 { 5487 {
5467// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); 5488// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
5468 5489
5469 AgentUpdateArgs arg = new AgentUpdateArgs(); 5490 m_lastAgentUpdateArgs.AgentID = x.AgentID;
5470 arg.AgentID = x.AgentID; 5491 m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
5471 arg.BodyRotation = x.BodyRotation; 5492 m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
5472 arg.CameraAtAxis = x.CameraAtAxis; 5493 m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
5473 arg.CameraCenter = x.CameraCenter; 5494 m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
5474 arg.CameraLeftAxis = x.CameraLeftAxis; 5495 m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
5475 arg.CameraUpAxis = x.CameraUpAxis; 5496 m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
5476 arg.ControlFlags = x.ControlFlags; 5497 m_lastAgentUpdateArgs.Far = x.Far;
5477 arg.Far = x.Far; 5498 m_lastAgentUpdateArgs.Flags = x.Flags;
5478 arg.Flags = x.Flags; 5499 m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
5479 arg.HeadRotation = x.HeadRotation; 5500 m_lastAgentUpdateArgs.SessionID = x.SessionID;
5480 arg.SessionID = x.SessionID; 5501 m_lastAgentUpdateArgs.State = x.State;
5481 arg.State = x.State; 5502
5482 UpdateAgent handlerAgentUpdate = OnAgentUpdate; 5503 UpdateAgent handlerAgentUpdate = OnAgentUpdate;
5483 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; 5504 UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
5484 lastarg = arg; // save this set of arguments for nexttime 5505
5485 if (handlerPreAgentUpdate != null) 5506 if (handlerPreAgentUpdate != null)
5486 OnPreAgentUpdate(this, arg); 5507 OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
5508
5487 if (handlerAgentUpdate != null) 5509 if (handlerAgentUpdate != null)
5488 OnAgentUpdate(this, arg); 5510 OnAgentUpdate(this, m_lastAgentUpdateArgs);
5489 5511
5490 handlerAgentUpdate = null; 5512 handlerAgentUpdate = null;
5491 handlerPreAgentUpdate = null; 5513 handlerPreAgentUpdate = null;
5492 } 5514 }
5493 } 5515 }
5494 5516
5517 PacketPool.Instance.ReturnPacket(packet);
5518
5495 return true; 5519 return true;
5496 } 5520 }
5497 5521
@@ -9056,7 +9080,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9056 } 9080 }
9057 #endregion 9081 #endregion
9058 9082
9059 switch (Utils.BytesToString(messagePacket.MethodData.Method)) 9083 string method = Utils.BytesToString(messagePacket.MethodData.Method);
9084
9085 switch (method)
9060 { 9086 {
9061 case "getinfo": 9087 case "getinfo":
9062 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 9088 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9372,7 +9398,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9372 return true; 9398 return true;
9373 9399
9374 default: 9400 default:
9375 m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); 9401 m_log.WarnFormat(
9402 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
9403 method, Name, Scene.Name);
9404
9405 for (int i = 0; i < messagePacket.ParamList.Length; i++)
9406 {
9407 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
9408 string data = (string)Utils.BytesToString(block.Parameter);
9409 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
9410 }
9411
9376 return true; 9412 return true;
9377 } 9413 }
9378 9414
@@ -11758,7 +11794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11758 logPacket = false; 11794 logPacket = false;
11759 11795
11760 if (DebugPacketLevel <= 50 11796 if (DebugPacketLevel <= 50
11761 & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 11797 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
11762 logPacket = false; 11798 logPacket = false;
11763 11799
11764 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) 11800 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -11832,8 +11868,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11832 11868
11833 if (!ProcessPacketMethod(packet)) 11869 if (!ProcessPacketMethod(packet))
11834 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11870 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
11835
11836 PacketPool.Instance.ReturnPacket(packet);
11837 } 11871 }
11838 11872
11839 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 11873 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
@@ -12286,7 +12320,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12286 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12320 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12287 12321
12288 12322
12289 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 12323 ImprovedTerseObjectUpdatePacket packet
12324 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12325 PacketType.ImprovedTerseObjectUpdate);
12326
12290 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 12327 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12291 packet.RegionData.TimeDilation = timeDilation; 12328 packet.RegionData.TimeDilation = timeDilation;
12292 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 12329 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 d11fcbf..419de66 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;
@@ -111,6 +114,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
111 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 114 //PacketEventDictionary packetEvents = new PacketEventDictionary();
112 /// <summary>Incoming packets that are awaiting handling</summary> 115 /// <summary>Incoming packets that are awaiting handling</summary>
113 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 116 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
117
114 /// <summary></summary> 118 /// <summary></summary>
115 //private UDPClientCollection m_clients = new UDPClientCollection(); 119 //private UDPClientCollection m_clients = new UDPClientCollection();
116 /// <summary>Bandwidth throttle for this UDP server</summary> 120 /// <summary>Bandwidth throttle for this UDP server</summary>
@@ -121,28 +125,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
121 125
122 /// <summary>Manages authentication for agent circuits</summary> 126 /// <summary>Manages authentication for agent circuits</summary>
123 private AgentCircuitManager m_circuitManager; 127 private AgentCircuitManager m_circuitManager;
128
124 /// <summary>Reference to the scene this UDP server is attached to</summary> 129 /// <summary>Reference to the scene this UDP server is attached to</summary>
125 protected Scene m_scene; 130 protected Scene m_scene;
131
126 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 132 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
127 private Location m_location; 133 private Location m_location;
134
128 /// <summary>The size of the receive buffer for the UDP socket. This value 135 /// <summary>The size of the receive buffer for the UDP socket. This value
129 /// is passed up to the operating system and used in the system networking 136 /// is passed up to the operating system and used in the system networking
130 /// stack. Use zero to leave this value as the default</summary> 137 /// stack. Use zero to leave this value as the default</summary>
131 private int m_recvBufferSize; 138 private int m_recvBufferSize;
139
132 /// <summary>Flag to process packets asynchronously or synchronously</summary> 140 /// <summary>Flag to process packets asynchronously or synchronously</summary>
133 private bool m_asyncPacketHandling; 141 private bool m_asyncPacketHandling;
142
134 /// <summary>Tracks whether or not a packet was sent each round so we know 143 /// <summary>Tracks whether or not a packet was sent each round so we know
135 /// whether or not to sleep</summary> 144 /// whether or not to sleep</summary>
136 private bool m_packetSent; 145 private bool m_packetSent;
137 146
138 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 147 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
139 private int m_elapsedMSSinceLastStatReport = 0; 148 private int m_elapsedMSSinceLastStatReport = 0;
149
140 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 150 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
141 private int m_tickLastOutgoingPacketHandler; 151 private int m_tickLastOutgoingPacketHandler;
152
142 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 153 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
143 private int m_elapsedMSOutgoingPacketHandler; 154 private int m_elapsedMSOutgoingPacketHandler;
155
144 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 156 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
145 private int m_elapsed100MSOutgoingPacketHandler; 157 private int m_elapsed100MSOutgoingPacketHandler;
158
146 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 159 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
147 private int m_elapsed500MSOutgoingPacketHandler; 160 private int m_elapsed500MSOutgoingPacketHandler;
148 161
@@ -155,6 +168,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
155 /// <summary>Flag to signal when clients should send pings</summary> 168 /// <summary>Flag to signal when clients should send pings</summary>
156 protected bool m_sendPing; 169 protected bool m_sendPing;
157 170
171 private Pool<IncomingPacket> m_incomingPacketPool;
172
158 private int m_defaultRTO = 0; 173 private int m_defaultRTO = 0;
159 private int m_maxRTO = 0; 174 private int m_maxRTO = 0;
160 private int m_ackTimeout = 0; 175 private int m_ackTimeout = 0;
@@ -175,7 +190,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
175 /// </summary> 190 /// </summary>
176 private IClientAPI m_currentIncomingClient; 191 private IClientAPI m_currentIncomingClient;
177 192
178 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 193 public LLUDPServer(
194 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
195 IConfigSource configSource, AgentCircuitManager circuitManager)
179 : base(listenIP, (int)port) 196 : base(listenIP, (int)port)
180 { 197 {
181 #region Environment.TickCount Measurement 198 #region Environment.TickCount Measurement
@@ -229,6 +246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 { 246 {
230 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true); 247 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
231 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true); 248 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
249 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
232 } 250 }
233 251
234 #region BinaryStats 252 #region BinaryStats
@@ -258,20 +276,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
258 276
259 m_throttle = new TokenBucket(null, sceneThrottleBps); 277 m_throttle = new TokenBucket(null, sceneThrottleBps);
260 ThrottleRates = new ThrottleRates(configSource); 278 ThrottleRates = new ThrottleRates(configSource);
279
280 if (UsePools)
281 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
261 } 282 }
262 283
263 public void Start() 284 public void Start()
264 { 285 {
265 if (m_scene == null) 286 StartInbound();
266 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 287 StartOutbound();
288
289 m_elapsedMSSinceLastStatReport = Environment.TickCount;
290 }
267 291
292 private void StartInbound()
293 {
268 m_log.InfoFormat( 294 m_log.InfoFormat(
269 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", 295 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
270 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 296 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
271 297
272 base.Start(m_recvBufferSize, m_asyncPacketHandling); 298 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
273 299
274 // Start the packet processing threads 300 // This thread will process the packets received that are placed on the packetInbox
275 Watchdog.StartThread( 301 Watchdog.StartThread(
276 IncomingPacketHandler, 302 IncomingPacketHandler,
277 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 303 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -280,6 +306,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
280 true, 306 true,
281 GetWatchdogIncomingAlarmData, 307 GetWatchdogIncomingAlarmData,
282 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 308 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
309 }
310
311 private new void StartOutbound()
312 {
313 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
314
315 base.StartOutbound();
283 316
284 Watchdog.StartThread( 317 Watchdog.StartThread(
285 OutgoingPacketHandler, 318 OutgoingPacketHandler,
@@ -289,8 +322,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
289 true, 322 true,
290 GetWatchdogOutgoingAlarmData, 323 GetWatchdogOutgoingAlarmData,
291 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 324 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
325 }
292 326
293 m_elapsedMSSinceLastStatReport = Environment.TickCount; 327 public void Stop()
328 {
329 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
330 base.StopOutbound();
331 base.StopInbound();
294 } 332 }
295 333
296 /// <summary> 334 /// <summary>
@@ -315,12 +353,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
315 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); 353 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
316 } 354 }
317 355
318 public new void Stop()
319 {
320 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
321 base.Stop();
322 }
323
324 public void AddScene(IScene scene) 356 public void AddScene(IScene scene)
325 { 357 {
326 if (m_scene != null) 358 if (m_scene != null)
@@ -337,6 +369,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 369
338 m_scene = (Scene)scene; 370 m_scene = (Scene)scene;
339 m_location = new Location(m_scene.RegionInfo.RegionHandle); 371 m_location = new Location(m_scene.RegionInfo.RegionHandle);
372
373 MainConsole.Instance.Commands.AddCommand(
374 "Debug",
375 false,
376 "debug lludp start",
377 "debug lludp start <in|out|all>",
378 "Control LLUDP packet processing.",
379 "No effect if packet processing has already started.\n"
380 + "in - start inbound processing.\n"
381 + "out - start outbound processing.\n"
382 + "all - start in and outbound processing.\n",
383 HandleStartCommand);
384
385 MainConsole.Instance.Commands.AddCommand(
386 "Debug",
387 false,
388 "debug lludp stop",
389 "debug lludp stop <in|out|all>",
390 "Stop LLUDP packet processing.",
391 "No effect if packet processing has already stopped.\n"
392 + "in - stop inbound processing.\n"
393 + "out - stop outbound processing.\n"
394 + "all - stop in and outbound processing.\n",
395 HandleStopCommand);
396
397 MainConsole.Instance.Commands.AddCommand(
398 "Debug",
399 false,
400 "debug lludp status",
401 "debug lludp status",
402 "Return status of LLUDP packet processing.",
403 HandleStatusCommand);
404 }
405
406 private void HandleStartCommand(string module, string[] args)
407 {
408 if (args.Length != 4)
409 {
410 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
411 return;
412 }
413
414 string subCommand = args[3];
415
416 if (subCommand == "in" || subCommand == "all")
417 StartInbound();
418
419 if (subCommand == "out" || subCommand == "all")
420 StartOutbound();
421 }
422
423 private void HandleStopCommand(string module, string[] args)
424 {
425 if (args.Length != 4)
426 {
427 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
428 return;
429 }
430
431 string subCommand = args[3];
432
433 if (subCommand == "in" || subCommand == "all")
434 StopInbound();
435
436 if (subCommand == "out" || subCommand == "all")
437 StopOutbound();
438 }
439
440 private void HandleStatusCommand(string module, string[] args)
441 {
442 MainConsole.Instance.OutputFormat(
443 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
444
445 MainConsole.Instance.OutputFormat(
446 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
340 } 447 }
341 448
342 public bool HandlesRegion(Location x) 449 public bool HandlesRegion(Location x)
@@ -420,6 +527,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
420 byte[] data = packet.ToBytes(); 527 byte[] data = packet.ToBytes();
421 SendPacketData(udpClient, data, packet.Type, category, method); 528 SendPacketData(udpClient, data, packet.Type, category, method);
422 } 529 }
530
531 PacketPool.Instance.ReturnPacket(packet);
423 } 532 }
424 533
425 /// <summary> 534 /// <summary>
@@ -704,7 +813,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
704 LLUDPClient udpClient = null; 813 LLUDPClient udpClient = null;
705 Packet packet = null; 814 Packet packet = null;
706 int packetEnd = buffer.DataLength - 1; 815 int packetEnd = buffer.DataLength - 1;
707 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 816 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
708 817
709 #region Decoding 818 #region Decoding
710 819
@@ -714,7 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
714// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 823// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
715// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 824// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
716 825
717 return; // Drop undersizd packet 826 return; // Drop undersized packet
718 } 827 }
719 828
720 int headerLen = 7; 829 int headerLen = 7;
@@ -737,7 +846,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
737 846
738 try 847 try
739 { 848 {
740 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 849// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
850// // Only allocate a buffer for zerodecoding if the packet is zerocoded
851// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
852 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
853 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
854 // bytes are copied out).
855 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
741 // Only allocate a buffer for zerodecoding if the packet is zerocoded 856 // Only allocate a buffer for zerodecoding if the packet is zerocoded
742 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 857 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
743 } 858 }
@@ -752,11 +867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
752 867
753 return; // Drop short packet 868 return; // Drop short packet
754 } 869 }
755 catch(Exception e) 870 catch (Exception e)
756 { 871 {
757 if (m_malformedCount < 100) 872 if (m_malformedCount < 100)
758 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 873 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
874
759 m_malformedCount++; 875 m_malformedCount++;
876
760 if ((m_malformedCount % 100000) == 0) 877 if ((m_malformedCount % 100000) == 0)
761 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); 878 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
762 } 879 }
@@ -777,7 +894,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
777 // UseCircuitCode handling 894 // UseCircuitCode handling
778 if (packet.Type == PacketType.UseCircuitCode) 895 if (packet.Type == PacketType.UseCircuitCode)
779 { 896 {
780 object[] array = new object[] { buffer, packet }; 897 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
898 // buffer.
899 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
781 900
782 Util.FireAndForget(HandleUseCircuitCode, array); 901 Util.FireAndForget(HandleUseCircuitCode, array);
783 902
@@ -786,7 +905,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
786 905
787 // Determine which agent this packet came from 906 // Determine which agent this packet came from
788 IClientAPI client; 907 IClientAPI client;
789 if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) 908 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
790 { 909 {
791 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 910 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
792 return; 911 return;
@@ -810,6 +929,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
810 // Handle appended ACKs 929 // Handle appended ACKs
811 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 930 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
812 { 931 {
932// m_log.DebugFormat(
933// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
934// packet.Header.AckList.Length, client.Name, m_scene.Name);
935
813 for (int i = 0; i < packet.Header.AckList.Length; i++) 936 for (int i = 0; i < packet.Header.AckList.Length; i++)
814 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 937 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
815 } 938 }
@@ -819,6 +942,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
819 { 942 {
820 PacketAckPacket ackPacket = (PacketAckPacket)packet; 943 PacketAckPacket ackPacket = (PacketAckPacket)packet;
821 944
945// m_log.DebugFormat(
946// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
947// ackPacket.Packets.Length, client.Name, m_scene.Name);
948
822 for (int i = 0; i < ackPacket.Packets.Length; i++) 949 for (int i = 0; i < ackPacket.Packets.Length; i++)
823 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 950 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
824 951
@@ -832,6 +959,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
832 959
833 if (packet.Header.Reliable) 960 if (packet.Header.Reliable)
834 { 961 {
962// m_log.DebugFormat(
963// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
964// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
965
835 udpClient.PendingAcks.Enqueue(packet.Header.Sequence); 966 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
836 967
837 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 968 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
@@ -878,6 +1009,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
878 1009
879 if (packet.Type == PacketType.StartPingCheck) 1010 if (packet.Type == PacketType.StartPingCheck)
880 { 1011 {
1012// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1013
881 // We don't need to do anything else with ping checks 1014 // We don't need to do anything else with ping checks
882 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1015 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
883 CompletePing(udpClient, startPing.PingID.PingID); 1016 CompletePing(udpClient, startPing.PingID.PingID);
@@ -897,8 +1030,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
897 1030
898 #endregion Ping Check Handling 1031 #endregion Ping Check Handling
899 1032
1033 IncomingPacket incomingPacket;
1034
900 // Inbox insertion 1035 // Inbox insertion
901 packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); 1036 if (UsePools)
1037 {
1038 incomingPacket = m_incomingPacketPool.GetObject();
1039 incomingPacket.Client = (LLClientView)client;
1040 incomingPacket.Packet = packet;
1041 }
1042 else
1043 {
1044 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1045 }
1046
1047 packetInbox.Enqueue(incomingPacket);
902 } 1048 }
903 1049
904 #region BinaryStats 1050 #region BinaryStats
@@ -984,21 +1130,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
984 1130
985 private void HandleUseCircuitCode(object o) 1131 private void HandleUseCircuitCode(object o)
986 { 1132 {
987 IPEndPoint remoteEndPoint = null; 1133 IPEndPoint endPoint = null;
988 IClientAPI client = null; 1134 IClientAPI client = null;
989 1135
990 try 1136 try
991 { 1137 {
992 // DateTime startTime = DateTime.Now; 1138 // DateTime startTime = DateTime.Now;
993 object[] array = (object[])o; 1139 object[] array = (object[])o;
994 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1140 endPoint = (IPEndPoint)array[0];
995 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1141 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
996 1142
997 m_log.DebugFormat( 1143 m_log.DebugFormat(
998 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1144 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
999 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1145 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1000
1001 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1002 1146
1003 AuthenticateResponse sessionInfo; 1147 AuthenticateResponse sessionInfo;
1004 if (IsClientAuthorized(uccp, out sessionInfo)) 1148 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1009,13 +1153,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1009 uccp.CircuitCode.Code, 1153 uccp.CircuitCode.Code,
1010 uccp.CircuitCode.ID, 1154 uccp.CircuitCode.ID,
1011 uccp.CircuitCode.SessionID, 1155 uccp.CircuitCode.SessionID,
1012 remoteEndPoint, 1156 endPoint,
1013 sessionInfo); 1157 sessionInfo);
1014 1158
1015 // Send ack straight away to let the viewer know that the connection is active. 1159 // Send ack straight away to let the viewer know that the connection is active.
1016 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1160 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1017 // circuit code to the existing child agent. This is not particularly obvious. 1161 // circuit code to the existing child agent. This is not particularly obvious.
1018 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1162 SendAckImmediate(endPoint, uccp.Header.Sequence);
1019 1163
1020 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1164 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1021 if (client != null) 1165 if (client != null)
@@ -1026,7 +1170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1026 // Don't create clients for unauthorized requesters. 1170 // Don't create clients for unauthorized requesters.
1027 m_log.WarnFormat( 1171 m_log.WarnFormat(
1028 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1172 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1029 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1173 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1030 } 1174 }
1031 1175
1032 // m_log.DebugFormat( 1176 // m_log.DebugFormat(
@@ -1038,7 +1182,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1038 { 1182 {
1039 m_log.ErrorFormat( 1183 m_log.ErrorFormat(
1040 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1184 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1041 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1185 endPoint != null ? endPoint.ToString() : "n/a",
1042 client != null ? client.Name : "unknown", 1186 client != null ? client.Name : "unknown",
1043 client != null ? client.AgentId.ToString() : "unknown", 1187 client != null ? client.AgentId.ToString() : "unknown",
1044 e.Message, 1188 e.Message,
@@ -1103,20 +1247,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1103 { 1247 {
1104 IClientAPI client = null; 1248 IClientAPI client = null;
1105 1249
1106 // In priciple there shouldn't be more than one thread here, ever. 1250 // We currently synchronize this code across the whole scene to avoid issues such as
1107 // But in case that happens, we need to synchronize this piece of code 1251 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1108 // because it's too important 1252 // consistently, this lock could probably be removed.
1109 lock (this) 1253 lock (this)
1110 { 1254 {
1111 if (!m_scene.TryGetClient(agentID, out client)) 1255 if (!m_scene.TryGetClient(agentID, out client))
1112 { 1256 {
1113 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1257 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1114 1258
1115 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1259 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1116 client.OnLogout += LogoutHandler; 1260 client.OnLogout += LogoutHandler;
1117 1261
1118 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1262 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1119 1263
1120 client.Start(); 1264 client.Start();
1121 } 1265 }
1122 } 1266 }
@@ -1155,7 +1299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1155 // on to en-US to avoid number parsing issues 1299 // on to en-US to avoid number parsing issues
1156 Culture.SetCurrentCulture(); 1300 Culture.SetCurrentCulture();
1157 1301
1158 while (base.IsRunning) 1302 while (IsRunningInbound)
1159 { 1303 {
1160 try 1304 try
1161 { 1305 {
@@ -1170,7 +1314,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1170 } 1314 }
1171 1315
1172 if (packetInbox.Dequeue(100, ref incomingPacket)) 1316 if (packetInbox.Dequeue(100, ref incomingPacket))
1317 {
1173 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); 1318 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
1319
1320 if (UsePools)
1321 m_incomingPacketPool.ReturnObject(incomingPacket);
1322 }
1174 } 1323 }
1175 catch (Exception ex) 1324 catch (Exception ex)
1176 { 1325 {
@@ -1197,7 +1346,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1197 // Action generic every round 1346 // Action generic every round
1198 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1347 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1199 1348
1200 while (base.IsRunning) 1349 while (base.IsRunningOutbound)
1201 { 1350 {
1202 try 1351 try
1203 { 1352 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 039379d..6e6b3ef 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
@@ -127,8 +145,7 @@ namespace OpenMetaverse
127 145
128 m_udpSocket.Bind(ipep); 146 m_udpSocket.Bind(ipep);
129 147
130 // we're not shutting down, we're starting up 148 IsRunningInbound = true;
131 m_shutdownFlag = false;
132 149
133 // kick off an async receive. The Start() method will return, the 150 // kick off an async receive. The Start() method will return, the
134 // actual receives will occur asynchronously and will be caught in 151 // actual receives will occur asynchronously and will be caught in
@@ -138,28 +155,41 @@ namespace OpenMetaverse
138 } 155 }
139 156
140 /// <summary> 157 /// <summary>
141 /// Stops the UDP server 158 /// Start outbound UDP packet handling.
142 /// </summary> 159 /// </summary>
143 public void Stop() 160 public void StartOutbound()
144 { 161 {
145 if (!m_shutdownFlag) 162 IsRunningOutbound = true;
163 }
164
165 public void StopInbound()
166 {
167 if (IsRunningInbound)
146 { 168 {
147 // wait indefinitely for a writer lock. Once this is called, the .NET runtime 169 // wait indefinitely for a writer lock. Once this is called, the .NET runtime
148 // will deny any more reader locks, in effect blocking all other send/receive 170 // will deny any more reader locks, in effect blocking all other send/receive
149 // threads. Once we have the lock, we set shutdownFlag to inform the other 171 // threads. Once we have the lock, we set IsRunningInbound = false to inform the other
150 // threads that the socket is closed. 172 // threads that the socket is closed.
151 m_shutdownFlag = true; 173 IsRunningInbound = false;
152 m_udpSocket.Close(); 174 m_udpSocket.Close();
153 } 175 }
154 } 176 }
155 177
178 public void StopOutbound()
179 {
180 IsRunningOutbound = false;
181 }
182
156 private void AsyncBeginReceive() 183 private void AsyncBeginReceive()
157 { 184 {
158 // allocate a packet buffer 185 UDPPacketBuffer buf;
159 //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); 186
160 UDPPacketBuffer buf = new UDPPacketBuffer(); 187 if (UsePools)
188 buf = m_pool.GetObject();
189 else
190 buf = new UDPPacketBuffer();
161 191
162 if (!m_shutdownFlag) 192 if (IsRunningInbound)
163 { 193 {
164 try 194 try
165 { 195 {
@@ -212,7 +242,7 @@ namespace OpenMetaverse
212 { 242 {
213 // Asynchronous receive operations will complete here through the call 243 // Asynchronous receive operations will complete here through the call
214 // to AsyncBeginReceive 244 // to AsyncBeginReceive
215 if (!m_shutdownFlag) 245 if (IsRunningInbound)
216 { 246 {
217 // Asynchronous mode will start another receive before the 247 // Asynchronous mode will start another receive before the
218 // callback for this packet is even fired. Very parallel :-) 248 // callback for this packet is even fired. Very parallel :-)
@@ -221,8 +251,6 @@ namespace OpenMetaverse
221 251
222 // get the buffer that was created in AsyncBeginReceive 252 // get the buffer that was created in AsyncBeginReceive
223 // this is the received data 253 // this is the received data
224 //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
225 //UDPPacketBuffer buffer = wrappedBuffer.Instance;
226 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; 254 UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
227 255
228 try 256 try
@@ -239,7 +267,8 @@ namespace OpenMetaverse
239 catch (ObjectDisposedException) { } 267 catch (ObjectDisposedException) { }
240 finally 268 finally
241 { 269 {
242 //wrappedBuffer.Dispose(); 270 if (UsePools)
271 m_pool.ReturnObject(buffer);
243 272
244 // Synchronous mode waits until the packet callback completes 273 // Synchronous mode waits until the packet callback completes
245 // before starting the receive to fetch another packet 274 // before starting the receive to fetch another packet
@@ -252,7 +281,7 @@ namespace OpenMetaverse
252 281
253 public void AsyncBeginSend(UDPPacketBuffer buf) 282 public void AsyncBeginSend(UDPPacketBuffer buf)
254 { 283 {
255 if (!m_shutdownFlag) 284 if (IsRunningOutbound)
256 { 285 {
257 try 286 try
258 { 287 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
index fc9406b..2a3d14f 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenMetaverse.Packets; 32using OpenMetaverse.Packets;
33using log4net; 33using log4net;
34using OpenSim.Framework.Monitoring;
34 35
35namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
36{ 37{
@@ -43,17 +44,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
43 private bool packetPoolEnabled = true; 44 private bool packetPoolEnabled = true;
44 private bool dataBlockPoolEnabled = true; 45 private bool dataBlockPoolEnabled = true;
45 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
46 /// <summary> 63 /// <summary>
47 /// Pool of packets available for reuse. 64 /// Pool of packets available for reuse.
48 /// </summary> 65 /// </summary>
49 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>(); 66 private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
50 67
51 private static Dictionary<Type, Stack<Object>> DataBlocks = 68 private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
52 new Dictionary<Type, Stack<Object>>();
53
54 static PacketPool()
55 {
56 }
57 69
58 public static PacketPool Instance 70 public static PacketPool Instance
59 { 71 {
@@ -72,8 +84,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
72 get { return dataBlockPoolEnabled; } 84 get { return dataBlockPoolEnabled; }
73 } 85 }
74 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>
75 public Packet GetPacket(PacketType type) 98 public Packet GetPacket(PacketType type)
76 { 99 {
100 m_packetsReusedStat.Consequent++;
101
77 Packet packet; 102 Packet packet;
78 103
79 if (!packetPoolEnabled) 104 if (!packetPoolEnabled)
@@ -83,13 +108,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 { 108 {
84 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0) 109 if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
85 { 110 {
111// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
112
86 // Creating a new packet if we cannot reuse an old package 113 // Creating a new packet if we cannot reuse an old package
87 packet = Packet.BuildPacket(type); 114 packet = Packet.BuildPacket(type);
88 } 115 }
89 else 116 else
90 { 117 {
118// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
119
91 // Recycle old packages 120 // Recycle old packages
92 packet = (pool[type]).Pop(); 121 m_packetsReusedStat.Antecedent++;
122
123 packet = pool[type].Pop();
93 } 124 }
94 } 125 }
95 126
@@ -138,7 +169,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
138 { 169 {
139 PacketType type = GetType(bytes); 170 PacketType type = GetType(bytes);
140 171
141 Array.Clear(zeroBuffer, 0, zeroBuffer.Length); 172// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
142 173
143 int i = 0; 174 int i = 0;
144 Packet packet = GetPacket(type); 175 Packet packet = GetPacket(type);
@@ -185,6 +216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
185 switch (packet.Type) 216 switch (packet.Type)
186 { 217 {
187 // List pooling packets here 218 // List pooling packets here
219 case PacketType.AgentUpdate:
188 case PacketType.PacketAck: 220 case PacketType.PacketAck:
189 case PacketType.ObjectUpdate: 221 case PacketType.ObjectUpdate:
190 case PacketType.ImprovedTerseObjectUpdate: 222 case PacketType.ImprovedTerseObjectUpdate:
@@ -199,7 +231,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
199 231
200 if ((pool[type]).Count < 50) 232 if ((pool[type]).Count < 50)
201 { 233 {
202 (pool[type]).Push(packet); 234// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
235
236 pool[type].Push(packet);
203 } 237 }
204 } 238 }
205 break; 239 break;
@@ -211,16 +245,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
211 } 245 }
212 } 246 }
213 247
214 public static T GetDataBlock<T>() where T: new() 248 public T GetDataBlock<T>() where T: new()
215 { 249 {
216 lock (DataBlocks) 250 lock (DataBlocks)
217 { 251 {
252 m_blocksReusedStat.Consequent++;
253
218 Stack<Object> s; 254 Stack<Object> s;
219 255
220 if (DataBlocks.TryGetValue(typeof(T), out s)) 256 if (DataBlocks.TryGetValue(typeof(T), out s))
221 { 257 {
222 if (s.Count > 0) 258 if (s.Count > 0)
259 {
260 m_blocksReusedStat.Antecedent++;
223 return (T)s.Pop(); 261 return (T)s.Pop();
262 }
224 } 263 }
225 else 264 else
226 { 265 {
@@ -231,7 +270,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
231 } 270 }
232 } 271 }
233 272
234 public static void ReturnDataBlock<T>(T block) where T: new() 273 public void ReturnDataBlock<T>(T block) where T: new()
235 { 274 {
236 if (block == null) 275 if (block == null)
237 return; 276 return;
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