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/LLClientView.cs55
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs211
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs75
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs282
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs7
5 files changed, 542 insertions, 88 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ee28914..7686b94 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;
@@ -509,19 +510,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
509 /// </summary> 510 /// </summary>
510 public void Close() 511 public void Close()
511 { 512 {
512 Close(true); 513 Close(true, false);
513 } 514 }
514 515
515 /// <summary> 516 public void Close(bool sendStop, bool force)
516 /// Shut down the client view
517 /// </summary>
518 public void Close(bool sendStop)
519 { 517 {
520 // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. 518 // 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. 519 // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
522 lock (CloseSyncLock) 520 lock (CloseSyncLock)
523 { 521 {
524 if (!IsActive) 522 // We still perform a force close inside the sync lock since this is intended to attempt close where
523 // there is some unidentified connection problem, not where we have issues due to deadlock
524 if (!IsActive && !force)
525 return; 525 return;
526 526
527 IsActive = false; 527 IsActive = false;
@@ -3984,7 +3984,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3984 { 3984 {
3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3985 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3986 3986
3987 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3987 ImprovedTerseObjectUpdatePacket packet
3988 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
3988 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3989 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3989 packet.RegionData.TimeDilation = timeDilation; 3990 packet.RegionData.TimeDilation = timeDilation;
3990 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3991 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4029,7 +4030,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4029 { 4030 {
4030 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 4031 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
4031 4032
4032 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 4033 ImprovedTerseObjectUpdatePacket packet
4034 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
4035 PacketType.ImprovedTerseObjectUpdate);
4033 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 4036 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
4034 packet.RegionData.TimeDilation = timeDilation; 4037 packet.RegionData.TimeDilation = timeDilation;
4035 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 4038 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
@@ -4037,7 +4040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4037 for (int i = 0; i < blocks.Count; i++) 4040 for (int i = 0; i < blocks.Count; i++)
4038 packet.ObjectData[i] = blocks[i]; 4041 packet.ObjectData[i] = blocks[i];
4039 4042
4040 OutPacket(packet, ThrottleOutPacketType.Task, true); 4043 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
4041 } 4044 }
4042 4045
4043 #endregion Packet Sending 4046 #endregion Packet Sending
@@ -4534,7 +4537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4534 { 4537 {
4535 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock(); 4538 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4536 } 4539 }
4537 j = 0; 4540 j = 0;
4538 4541
4539 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 4542 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4540 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; 4543 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
@@ -5038,7 +5041,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5038 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2; 5041 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; 5042 Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
5040 5043
5041 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock(); 5044 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
5045 = PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
5046
5042 block.Data = data; 5047 block.Data = data;
5043 5048
5044 if (textureEntry != null && textureEntry.Length > 0) 5049 if (textureEntry != null && textureEntry.Length > 0)
@@ -5963,7 +5968,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5963 msgpack.MessageBlock.ID, 5968 msgpack.MessageBlock.ID,
5964 msgpack.MessageBlock.Offline != 0 ? true : false, 5969 msgpack.MessageBlock.Offline != 0 ? true : false,
5965 msgpack.MessageBlock.Position, 5970 msgpack.MessageBlock.Position,
5966 msgpack.MessageBlock.BinaryBucket); 5971 msgpack.MessageBlock.BinaryBucket,
5972 true);
5967 5973
5968 handlerInstantMessage(this, im); 5974 handlerInstantMessage(this, im);
5969 } 5975 }
@@ -9245,7 +9251,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9245 } 9251 }
9246 #endregion 9252 #endregion
9247 9253
9248 switch (Utils.BytesToString(messagePacket.MethodData.Method)) 9254 string method = Utils.BytesToString(messagePacket.MethodData.Method);
9255
9256 switch (method)
9249 { 9257 {
9250 case "getinfo": 9258 case "getinfo":
9251 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false)) 9259 if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
@@ -9561,7 +9569,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9561 return true; 9569 return true;
9562 9570
9563 default: 9571 default:
9564 m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket); 9572 m_log.WarnFormat(
9573 "[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
9574 method, Name, Scene.Name);
9575
9576 for (int i = 0; i < messagePacket.ParamList.Length; i++)
9577 {
9578 EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
9579 string data = (string)Utils.BytesToString(block.Parameter);
9580 m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
9581 }
9582
9565 return true; 9583 return true;
9566 } 9584 }
9567 9585
@@ -11949,7 +11967,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11949 logPacket = false; 11967 logPacket = false;
11950 11968
11951 if (DebugPacketLevel <= 50 11969 if (DebugPacketLevel <= 50
11952 & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) 11970 && (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
11953 logPacket = false; 11971 logPacket = false;
11954 11972
11955 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) 11973 if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
@@ -12193,7 +12211,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12193 { 12211 {
12194 Kick(reason); 12212 Kick(reason);
12195 Thread.Sleep(1000); 12213 Thread.Sleep(1000);
12196 Close(); 12214 Disconnect();
12197 } 12215 }
12198 12216
12199 public void Disconnect() 12217 public void Disconnect()
@@ -12481,7 +12499,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
12481 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); 12499 ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
12482 12500
12483 12501
12484 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 12502 ImprovedTerseObjectUpdatePacket packet
12503 = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
12504 PacketType.ImprovedTerseObjectUpdate);
12505
12485 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 12506 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
12486 packet.RegionData.TimeDilation = timeDilation; 12507 packet.RegionData.TimeDilation = timeDilation;
12487 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; 12508 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..7820caf 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
@@ -180,7 +192,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
180 /// </summary> 192 /// </summary>
181 private IClientAPI m_currentIncomingClient; 193 private IClientAPI m_currentIncomingClient;
182 194
183 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 195 public LLUDPServer(
196 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
197 IConfigSource configSource, AgentCircuitManager circuitManager)
184 : base(listenIP, (int)port) 198 : base(listenIP, (int)port)
185 { 199 {
186 #region Environment.TickCount Measurement 200 #region Environment.TickCount Measurement
@@ -227,6 +241,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
227 m_pausedAckTimeout = 1000 * 300; // 5 minutes 241 m_pausedAckTimeout = 1000 * 300; // 5 minutes
228 } 242 }
229 243
244 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
245 // However, there is no harm in temporarily doing it multiple times.
246 IConfig packetConfig = configSource.Configs["PacketPool"];
247 if (packetConfig != null)
248 {
249 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
250 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
251 UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
252 }
253
230 #region BinaryStats 254 #region BinaryStats
231 config = configSource.Configs["Statistics.Binary"]; 255 config = configSource.Configs["Statistics.Binary"];
232 m_shouldCollectStats = false; 256 m_shouldCollectStats = false;
@@ -258,16 +282,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
258 282
259 public void Start() 283 public void Start()
260 { 284 {
261 if (m_scene == null) 285 StartInbound();
262 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 286 StartOutbound();
287
288 m_elapsedMSSinceLastStatReport = Environment.TickCount;
289 }
263 290
291 private void StartInbound()
292 {
264 m_log.InfoFormat( 293 m_log.InfoFormat(
265 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", 294 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
266 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 295 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
267 296
268 base.Start(m_recvBufferSize, m_asyncPacketHandling); 297 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
269 298
270 // Start the packet processing threads 299 // This thread will process the packets received that are placed on the packetInbox
271 Watchdog.StartThread( 300 Watchdog.StartThread(
272 IncomingPacketHandler, 301 IncomingPacketHandler,
273 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 302 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -276,7 +305,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
276 true, 305 true,
277 GetWatchdogIncomingAlarmData, 306 GetWatchdogIncomingAlarmData,
278 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 307 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
308 }
309
310 private new void StartOutbound()
311 {
312 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
313
314 base.StartOutbound();
279 315
316 // This thread will process the packets received that are placed on the packetInbox
280 Watchdog.StartThread( 317 Watchdog.StartThread(
281 OutgoingPacketHandler, 318 OutgoingPacketHandler,
282 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), 319 string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -285,8 +322,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 true, 322 true,
286 GetWatchdogOutgoingAlarmData, 323 GetWatchdogOutgoingAlarmData,
287 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 324 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
325 }
288 326
289 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();
290 } 332 }
291 333
292 /// <summary> 334 /// <summary>
@@ -311,12 +353,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); 353 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
312 } 354 }
313 355
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) 356 public void AddScene(IScene scene)
321 { 357 {
322 if (m_scene != null) 358 if (m_scene != null)
@@ -333,6 +369,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 369
334 m_scene = (Scene)scene; 370 m_scene = (Scene)scene;
335 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");
336 } 447 }
337 448
338 public bool HandlesRegion(Location x) 449 public bool HandlesRegion(Location x)
@@ -416,6 +527,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 byte[] data = packet.ToBytes(); 527 byte[] data = packet.ToBytes();
417 SendPacketData(udpClient, data, packet.Type, category, method); 528 SendPacketData(udpClient, data, packet.Type, category, method);
418 } 529 }
530
531 PacketPool.Instance.ReturnPacket(packet);
419 } 532 }
420 533
421 /// <summary> 534 /// <summary>
@@ -700,7 +813,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 LLUDPClient udpClient = null; 813 LLUDPClient udpClient = null;
701 Packet packet = null; 814 Packet packet = null;
702 int packetEnd = buffer.DataLength - 1; 815 int packetEnd = buffer.DataLength - 1;
703 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 816 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
704 817
705 #region Decoding 818 #region Decoding
706 819
@@ -710,7 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710// "[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}",
711// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 824// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
712 825
713 return; // Drop undersizd packet 826 return; // Drop undersized packet
714 } 827 }
715 828
716 int headerLen = 7; 829 int headerLen = 7;
@@ -733,7 +846,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
733 846
734 try 847 try
735 { 848 {
736 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,
737 // Only allocate a buffer for zerodecoding if the packet is zerocoded 856 // Only allocate a buffer for zerodecoding if the packet is zerocoded
738 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 857 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
739 } 858 }
@@ -748,11 +867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
748 867
749 return; // Drop short packet 868 return; // Drop short packet
750 } 869 }
751 catch(Exception e) 870 catch (Exception e)
752 { 871 {
753 if (m_malformedCount < 100) 872 if (m_malformedCount < 100)
754 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 873 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
874
755 m_malformedCount++; 875 m_malformedCount++;
876
756 if ((m_malformedCount % 100000) == 0) 877 if ((m_malformedCount % 100000) == 0)
757 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);
758 } 879 }
@@ -772,7 +893,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
772 893
773 // If there is already a client for this endpoint, don't process UseCircuitCode 894 // If there is already a client for this endpoint, don't process UseCircuitCode
774 IClientAPI client = null; 895 IClientAPI client = null;
775 if (!m_scene.TryGetClient(address, out client)) 896 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
776 { 897 {
777 // UseCircuitCode handling 898 // UseCircuitCode handling
778 if (packet.Type == PacketType.UseCircuitCode) 899 if (packet.Type == PacketType.UseCircuitCode)
@@ -780,13 +901,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
780 // And if there is a UseCircuitCode pending, also drop it 901 // And if there is a UseCircuitCode pending, also drop it
781 lock (m_pendingCache) 902 lock (m_pendingCache)
782 { 903 {
783 if (m_pendingCache.Contains(address)) 904 if (m_pendingCache.Contains(endPoint))
784 return; 905 return;
785 906
786 m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); 907 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
787 } 908 }
788 909
789 object[] array = new object[] { buffer, packet }; 910 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
911 // buffer.
912 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
790 913
791 Util.FireAndForget(HandleUseCircuitCode, array); 914 Util.FireAndForget(HandleUseCircuitCode, array);
792 915
@@ -798,7 +921,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
798 lock (m_pendingCache) 921 lock (m_pendingCache)
799 { 922 {
800 Queue<UDPPacketBuffer> queue; 923 Queue<UDPPacketBuffer> queue;
801 if (m_pendingCache.TryGetValue(address, out queue)) 924 if (m_pendingCache.TryGetValue(endPoint, out queue))
802 { 925 {
803 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); 926 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
804 queue.Enqueue(buffer); 927 queue.Enqueue(buffer);
@@ -1013,21 +1136,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1013 1136
1014 private void HandleUseCircuitCode(object o) 1137 private void HandleUseCircuitCode(object o)
1015 { 1138 {
1016 IPEndPoint remoteEndPoint = null; 1139 IPEndPoint endPoint = null;
1017 IClientAPI client = null; 1140 IClientAPI client = null;
1018 1141
1019 try 1142 try
1020 { 1143 {
1021 // DateTime startTime = DateTime.Now; 1144 // DateTime startTime = DateTime.Now;
1022 object[] array = (object[])o; 1145 object[] array = (object[])o;
1023 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1146 endPoint = (IPEndPoint)array[0];
1024 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1147 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1025 1148
1026 m_log.DebugFormat( 1149 m_log.DebugFormat(
1027 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1150 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1028 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1151 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1029
1030 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1031 1152
1032 AuthenticateResponse sessionInfo; 1153 AuthenticateResponse sessionInfo;
1033 if (IsClientAuthorized(uccp, out sessionInfo)) 1154 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1038,13 +1159,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1038 uccp.CircuitCode.Code, 1159 uccp.CircuitCode.Code,
1039 uccp.CircuitCode.ID, 1160 uccp.CircuitCode.ID,
1040 uccp.CircuitCode.SessionID, 1161 uccp.CircuitCode.SessionID,
1041 remoteEndPoint, 1162 endPoint,
1042 sessionInfo); 1163 sessionInfo);
1043 1164
1044 // Send ack straight away to let the viewer know that the connection is active. 1165 // 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 1166 // 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. 1167 // circuit code to the existing child agent. This is not particularly obvious.
1047 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1168 SendAckImmediate(endPoint, uccp.Header.Sequence);
1048 1169
1049 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1170 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1050 if (client != null) 1171 if (client != null)
@@ -1058,12 +1179,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 1179
1059 lock (m_pendingCache) 1180 lock (m_pendingCache)
1060 { 1181 {
1061 if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) 1182 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1062 { 1183 {
1063 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1184 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1064 return; 1185 return;
1065 } 1186 }
1066 m_pendingCache.Remove(remoteEndPoint); 1187 m_pendingCache.Remove(endPoint);
1067 } 1188 }
1068 1189
1069 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1190 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@@ -1081,9 +1202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 // Don't create clients for unauthorized requesters. 1202 // Don't create clients for unauthorized requesters.
1082 m_log.WarnFormat( 1203 m_log.WarnFormat(
1083 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1204 "[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); 1205 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1085 lock (m_pendingCache) 1206 lock (m_pendingCache)
1086 m_pendingCache.Remove(remoteEndPoint); 1207 m_pendingCache.Remove(endPoint);
1087 } 1208 }
1088 1209
1089 // m_log.DebugFormat( 1210 // m_log.DebugFormat(
@@ -1095,7 +1216,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1095 { 1216 {
1096 m_log.ErrorFormat( 1217 m_log.ErrorFormat(
1097 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1218 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1098 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1219 endPoint != null ? endPoint.ToString() : "n/a",
1099 client != null ? client.Name : "unknown", 1220 client != null ? client.Name : "unknown",
1100 client != null ? client.AgentId.ToString() : "unknown", 1221 client != null ? client.AgentId.ToString() : "unknown",
1101 e.Message, 1222 e.Message,
@@ -1160,20 +1281,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1160 { 1281 {
1161 IClientAPI client = null; 1282 IClientAPI client = null;
1162 1283
1163 // In priciple there shouldn't be more than one thread here, ever. 1284 // 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 1285 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1165 // because it's too important 1286 // consistently, this lock could probably be removed.
1166 lock (this) 1287 lock (this)
1167 { 1288 {
1168 if (!m_scene.TryGetClient(agentID, out client)) 1289 if (!m_scene.TryGetClient(agentID, out client))
1169 { 1290 {
1170 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1291 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1171 1292
1172 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1293 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1173 client.OnLogout += LogoutHandler; 1294 client.OnLogout += LogoutHandler;
1174 1295
1175 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1296 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1176 1297
1177 client.Start(); 1298 client.Start();
1178 } 1299 }
1179 } 1300 }
@@ -1212,7 +1333,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1212 // on to en-US to avoid number parsing issues 1333 // on to en-US to avoid number parsing issues
1213 Culture.SetCurrentCulture(); 1334 Culture.SetCurrentCulture();
1214 1335
1215 while (base.IsRunning) 1336 while (base.IsRunningInbound)
1216 { 1337 {
1217 m_scene.ThreadAlive(1); 1338 m_scene.ThreadAlive(1);
1218 try 1339 try
@@ -1255,7 +1376,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1255 // Action generic every round 1376 // Action generic every round
1256 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1377 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1257 1378
1258 while (base.IsRunning) 1379 while (base.IsRunningOutbound)
1259 { 1380 {
1260 m_scene.ThreadAlive(2); 1381 m_scene.ThreadAlive(2);
1261 try 1382 try
@@ -1523,7 +1644,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1523 if (!client.IsLoggingOut) 1644 if (!client.IsLoggingOut)
1524 { 1645 {
1525 client.IsLoggingOut = true; 1646 client.IsLoggingOut = true;
1526 client.Close(false); 1647 client.Close(false, false);
1527 } 1648 }
1528 } 1649 }
1529 } 1650 }
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..71f6fe1
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,282 @@
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 // Creating a new packet if we cannot reuse an old package
112 packet = Packet.BuildPacket(type);
113 }
114 else
115 {
116 // Recycle old packages
117 m_packetsReusedStat.Antecedent++;
118
119 packet = (pool[type]).Pop();
120 }
121 }
122
123 return packet;
124 }
125
126 // private byte[] decoded_header = new byte[10];
127 private static PacketType GetType(byte[] bytes)
128 {
129 byte[] decoded_header = new byte[10 + 8];
130 ushort id;
131 PacketFrequency freq;
132
133 if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
134 {
135 Helpers.ZeroDecode(bytes, 16, decoded_header);
136 }
137 else
138 {
139 Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
140 }
141
142 if (decoded_header[6] == 0xFF)
143 {
144 if (decoded_header[7] == 0xFF)
145 {
146 id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
147 freq = PacketFrequency.Low;
148 }
149 else
150 {
151 id = decoded_header[7];
152 freq = PacketFrequency.Medium;
153 }
154 }
155 else
156 {
157 id = decoded_header[6];
158 freq = PacketFrequency.High;
159 }
160
161 return Packet.GetType(id, freq);
162 }
163
164 public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
165 {
166 PacketType type = GetType(bytes);
167
168// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
169
170 int i = 0;
171 Packet packet = GetPacket(type);
172 if (packet == null)
173 m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
174 else
175 packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
176
177 return packet;
178 }
179
180 /// <summary>
181 /// Return a packet to the packet pool
182 /// </summary>
183 /// <param name="packet"></param>
184 public void ReturnPacket(Packet packet)
185 {
186 if (dataBlockPoolEnabled)
187 {
188 switch (packet.Type)
189 {
190 case PacketType.ObjectUpdate:
191 ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
192
193 foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
194 ReturnDataBlock<ObjectUpdatePacket.ObjectDataBlock>(oupod);
195
196 oup.ObjectData = null;
197 break;
198
199 case PacketType.ImprovedTerseObjectUpdate:
200 ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
201
202 foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
203 ReturnDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>(itoupod);
204
205 itoup.ObjectData = null;
206 break;
207 }
208 }
209
210 if (packetPoolEnabled)
211 {
212 switch (packet.Type)
213 {
214 // List pooling packets here
215 case PacketType.AgentUpdate:
216 case PacketType.PacketAck:
217 case PacketType.ObjectUpdate:
218 case PacketType.ImprovedTerseObjectUpdate:
219 lock (pool)
220 {
221 PacketType type = packet.Type;
222
223 if (!pool.ContainsKey(type))
224 {
225 pool[type] = new Stack<Packet>();
226 }
227
228 if ((pool[type]).Count < 50)
229 {
230 (pool[type]).Push(packet);
231 }
232 }
233 break;
234
235 // Other packets wont pool
236 default:
237 return;
238 }
239 }
240 }
241
242 public T GetDataBlock<T>() where T: new()
243 {
244 lock (DataBlocks)
245 {
246 m_blocksReusedStat.Consequent++;
247
248 Stack<Object> s;
249
250 if (DataBlocks.TryGetValue(typeof(T), out s))
251 {
252 if (s.Count > 0)
253 {
254 m_blocksReusedStat.Antecedent++;
255 return (T)s.Pop();
256 }
257 }
258 else
259 {
260 DataBlocks[typeof(T)] = new Stack<Object>();
261 }
262
263 return new T();
264 }
265 }
266
267 public void ReturnDataBlock<T>(T block) where T: new()
268 {
269 if (block == null)
270 return;
271
272 lock (DataBlocks)
273 {
274 if (!DataBlocks.ContainsKey(typeof(T)))
275 DataBlocks[typeof(T)] = new Stack<Object>();
276
277 if (DataBlocks[typeof(T)].Count < 50)
278 DataBlocks[typeof(T)].Push(block);
279 }
280 }
281 }
282} \ 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