aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack
diff options
context:
space:
mode:
authorMelanie Thielker2008-07-22 17:58:42 +0000
committerMelanie Thielker2008-07-22 17:58:42 +0000
commitf112cebde2c1bc06108839acac82bc8addd7c506 (patch)
tree7f1e7fabf2fec74171d5982f09d847b47e20d7ca /OpenSim/Region/ClientStack
parent* refactor: move new inventory service call by user server to OGS1 with all t... (diff)
downloadopensim-SC-f112cebde2c1bc06108839acac82bc8addd7c506.zip
opensim-SC-f112cebde2c1bc06108839acac82bc8addd7c506.tar.gz
opensim-SC-f112cebde2c1bc06108839acac82bc8addd7c506.tar.bz2
opensim-SC-f112cebde2c1bc06108839acac82bc8addd7c506.tar.xz
Refactor the packet scheduling out of ClientView. Add intelligent
resending, timeouts, packet discarding. Add notification event for packet discarding. Add priority scheduling for packet queues. Add outgoing duplicate detection facility. Correct packet sequencing. Make provisions for automatic server side throttle adjustments (comes in next installment)
Diffstat (limited to 'OpenSim/Region/ClientStack')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs567
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs692
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs68
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs263
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs4
5 files changed, 782 insertions, 812 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index c9fc83a..41ac657 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -50,20 +50,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
50 50
51 51
52 /// <summary> 52 /// <summary>
53 /// Class that keeps track of past packets so that they don't get
54 /// duplicated when the client doesn't get back an ack
55 /// </summary>
56 public class PacketDupeLimiter
57 {
58 public PacketType pktype;
59 public int timeIn;
60 public uint packetId;
61 public PacketDupeLimiter()
62 {
63 }
64 }
65
66 /// <summary>
67 /// Handles new client connections 53 /// Handles new client connections
68 /// Constructor takes a single Packet and authenticates everything 54 /// Constructor takes a single Packet and authenticates everything
69 /// </summary> 55 /// </summary>
@@ -79,7 +65,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
79 /* static variables */ 65 /* static variables */
80 public static TerrainManager TerrainManager = new TerrainManager(new SecondLife()); 66 public static TerrainManager TerrainManager = new TerrainManager(new SecondLife());
81 67
82 public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType);
83 public static SynchronizeClientHandler SynchronizeClient = null; 68 public static SynchronizeClientHandler SynchronizeClient = null;
84 /* private variables */ 69 /* private variables */
85 private readonly LLUUID m_sessionId; 70 private readonly LLUUID m_sessionId;
@@ -93,15 +78,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
93 78
94 private bool m_clientBlocked = false; 79 private bool m_clientBlocked = false;
95 80
96 // for sim stats
97 private int m_packetsReceived = 0;
98 private int m_lastPacketsReceivedSentToScene = 0;
99 private int m_unAckedBytes = 0;
100
101 private int m_packetsSent = 0;
102 private int m_lastPacketsSentSentToScene = 0;
103 private int m_clearDuplicatePacketTrackingOlderThenXSeconds = 30;
104
105 private int m_probesWithNoIngressPackets = 0; 81 private int m_probesWithNoIngressPackets = 0;
106 private int m_lastPacketsReceived = 0; 82 private int m_lastPacketsReceived = 0;
107 private byte[] ZeroOutBuffer = new byte[4096]; 83 private byte[] ZeroOutBuffer = new byte[4096];
@@ -109,8 +85,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
109 private readonly LLUUID m_agentId; 85 private readonly LLUUID m_agentId;
110 private readonly uint m_circuitCode; 86 private readonly uint m_circuitCode;
111 private int m_moneyBalance; 87 private int m_moneyBalance;
112 88 private IPacketHandler m_PacketHandler;
113 private Dictionary<uint, PacketDupeLimiter> m_dupeLimiter = new Dictionary<uint, PacketDupeLimiter>();
114 89
115 private int m_animationSequenceNumber = 1; 90 private int m_animationSequenceNumber = 1;
116 91
@@ -118,8 +93,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 93
119 private Dictionary<string, LLUUID> m_defaultAnimations = new Dictionary<string, LLUUID>(); 94 private Dictionary<string, LLUUID> m_defaultAnimations = new Dictionary<string, LLUUID>();
120 95
121 private LLPacketTracker m_packetTracker;
122
123 /* protected variables */ 96 /* protected variables */
124 97
125 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = 98 protected static Dictionary<PacketType, PacketMethod> PacketHandlers =
@@ -130,17 +103,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
130 protected IScene m_scene; 103 protected IScene m_scene;
131 protected AgentCircuitManager m_authenticateSessionsHandler; 104 protected AgentCircuitManager m_authenticateSessionsHandler;
132 105
133 protected LLPacketQueue m_packetQueue;
134
135 protected Dictionary<uint, uint> m_pendingAcks = new Dictionary<uint, uint>();
136 protected Dictionary<uint, Packet> m_needAck = new Dictionary<uint, Packet>();
137
138 protected Timer m_ackTimer;
139 protected uint m_sequence = 0;
140 protected object m_sequenceLock = new object();
141 protected const int MAX_APPENDED_ACKS = 10;
142 protected const int RESEND_TIMEOUT = 4000;
143 protected const int MAX_SEQUENCE = 0xFFFFFF;
144 protected LLPacketServer m_networkServer; 106 protected LLPacketServer m_networkServer;
145 107
146 /* public variables */ 108 /* public variables */
@@ -263,7 +225,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
263 private UpdateVector handlerUpdateVector = null; //OnUpdatePrimGroupPosition; 225 private UpdateVector handlerUpdateVector = null; //OnUpdatePrimGroupPosition;
264 private UpdatePrimRotation handlerUpdatePrimRotation = null; //OnUpdatePrimGroupRotation; 226 private UpdatePrimRotation handlerUpdatePrimRotation = null; //OnUpdatePrimGroupRotation;
265 // private UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = null; //OnUpdatePrimGroupMouseRotation; 227 // private UpdatePrimGroupRotation handlerUpdatePrimGroupRotation = null; //OnUpdatePrimGroupMouseRotation;
266 private PacketStats handlerPacketStats = null; // OnPacketStats;#
267 // private RequestAsset handlerRequestAsset = null; // OnRequestAsset; 228 // private RequestAsset handlerRequestAsset = null; // OnRequestAsset;
268 private UUIDNameRequest handlerTeleportHomeRequest = null; 229 private UUIDNameRequest handlerTeleportHomeRequest = null;
269 230
@@ -378,13 +339,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
378 get { return m_animationSequenceNumber++; } 339 get { return m_animationSequenceNumber++; }
379 } 340 }
380 341
342 public IPacketHandler PacketHandler
343 {
344 get { return m_PacketHandler; }
345 }
346
347 bool m_IsActive = true;
348
349 public bool IsActive
350 {
351 get { return m_IsActive; }
352 set { m_IsActive = value; }
353 }
354
381 /* METHODS */ 355 /* METHODS */
382 356
383 public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer, 357 public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer,
384 AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP) 358 AgentCircuitManager authenSessions, LLUUID agentId, LLUUID sessionId, uint circuitCode, EndPoint proxyEP)
385 { 359 {
386 m_packetTracker = new LLPacketTracker(this);
387
388 m_moneyBalance = 1000; 360 m_moneyBalance = 1000;
389 361
390 m_channelVersion = Helpers.StringToField(scene.GetSimulatorVersion()); 362 m_channelVersion = Helpers.StringToField(scene.GetSimulatorVersion());
@@ -414,7 +386,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
414 // in it to process. It's an on-purpose threadlock though because 386 // in it to process. It's an on-purpose threadlock though because
415 // without it, the clientloop will suck up all sim resources. 387 // without it, the clientloop will suck up all sim resources.
416 388
417 m_packetQueue = new LLPacketQueue(agentId); 389 m_PacketHandler = new LLPacketHandler(this);
390 m_PacketHandler.SynchronizeClient = SynchronizeClient;
418 391
419 RegisterLocalPacketHandlers(); 392 RegisterLocalPacketHandlers();
420 393
@@ -423,7 +396,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
423 m_clientThread.Name = "ClientThread"; 396 m_clientThread.Name = "ClientThread";
424 m_clientThread.IsBackground = true; 397 m_clientThread.IsBackground = true;
425 m_clientThread.Start(); 398 m_clientThread.Start();
426 ThreadTracker.Add(m_clientThread);
427 } 399 }
428 400
429 public void SetDebug(int newDebug) 401 public void SetDebug(int newDebug)
@@ -444,12 +416,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
444 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 416 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
445 OutPacket(disable, ThrottleOutPacketType.Unknown); 417 OutPacket(disable, ThrottleOutPacketType.Unknown);
446 418
447 m_packetQueue.Close();
448
449 Thread.Sleep(2000); 419 Thread.Sleep(2000);
450 420
451 // Shut down timers 421 // Shut down timers
452 m_ackTimer.Stop();
453 m_clientPingTimer.Stop(); 422 m_clientPingTimer.Stop();
454 423
455 // This is just to give the client a reasonable chance of 424 // This is just to give the client a reasonable chance of
@@ -479,7 +448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
479 { 448 {
480 // Pull Client out of Region 449 // Pull Client out of Region
481 m_log.Info("[CLIENT]: Close has been called"); 450 m_log.Info("[CLIENT]: Close has been called");
482 m_packetQueue.Flush(); 451 m_PacketHandler.Flush();
483 452
484 //raiseevent on the packet server to Shutdown the circuit 453 //raiseevent on the packet server to Shutdown the circuit
485 if (shutdownCircuit) 454 if (shutdownCircuit)
@@ -509,20 +478,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
509 public void Stop() 478 public void Stop()
510 { 479 {
511 // Shut down timers 480 // Shut down timers
512 m_ackTimer.Stop();
513 m_clientPingTimer.Stop(); 481 m_clientPingTimer.Stop();
514 } 482 }
515 483
516 public void Restart() 484 public void Restart()
517 { 485 {
518 // re-construct 486 // re-construct
519 m_pendingAcks = new Dictionary<uint, uint>(); 487 m_PacketHandler.Clear();
520 m_needAck = new Dictionary<uint, Packet>();
521 m_sequence += 1000000;
522
523 m_ackTimer = new Timer(750);
524 m_ackTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
525 m_ackTimer.Start();
526 488
527 m_clientPingTimer = new Timer(5000); 489 m_clientPingTimer = new Timer(5000);
528 m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity); 490 m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity);
@@ -531,8 +493,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
531 493
532 public void Terminate() 494 public void Terminate()
533 { 495 {
534 // disable blocking queue 496 m_PacketHandler.Stop();
535 m_packetQueue.Enqueue(null);
536 497
537 // wait for thread stoped 498 // wait for thread stoped
538 m_clientThread.Join(); 499 m_clientThread.Join();
@@ -638,7 +599,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
638 m_log.Info("[CLIENT]: Entered loop"); 599 m_log.Info("[CLIENT]: Entered loop");
639 while (true) 600 while (true)
640 { 601 {
641 LLQueItem nextPacket = m_packetQueue.Dequeue(); 602 LLQueItem nextPacket = m_PacketHandler.PacketQueue.Dequeue();
642 if (nextPacket == null) 603 if (nextPacket == null)
643 { 604 {
644 m_log.Error("Got a NULL packet in Client Loop, bailing out of our client loop"); 605 m_log.Error("Got a NULL packet in Client Loop, bailing out of our client loop");
@@ -646,12 +607,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
646 } 607 }
647 if (nextPacket.Incoming) 608 if (nextPacket.Incoming)
648 { 609 {
649 if (nextPacket.Packet.Type != PacketType.AgentUpdate)
650 {
651 m_packetsReceived++;
652 }
653 DebugPacket("IN", nextPacket.Packet); 610 DebugPacket("IN", nextPacket.Packet);
654 ProcessInPacket(nextPacket.Packet); 611 m_PacketHandler.ProcessInPacket(nextPacket.Packet);
655 } 612 }
656 else 613 else
657 { 614 {
@@ -672,7 +629,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
672 /// <param name="e"></param> 629 /// <param name="e"></param>
673 protected void CheckClientConnectivity(object sender, ElapsedEventArgs e) 630 protected void CheckClientConnectivity(object sender, ElapsedEventArgs e)
674 { 631 {
675 if (m_packetsReceived == m_lastPacketsReceived) 632 if (m_PacketHandler.PacketsReceived == m_PacketHandler.PacketsReceivedReported)
676 { 633 {
677 m_probesWithNoIngressPackets++; 634 m_probesWithNoIngressPackets++;
678 if ((m_probesWithNoIngressPackets > 30 && !m_clientBlocked) || (m_probesWithNoIngressPackets > 90 && m_clientBlocked)) 635 if ((m_probesWithNoIngressPackets > 30 && !m_clientBlocked) || (m_probesWithNoIngressPackets > 90 && m_clientBlocked))
@@ -693,19 +650,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
693 { 650 {
694 // Something received in the meantime - we can reset the counters 651 // Something received in the meantime - we can reset the counters
695 m_probesWithNoIngressPackets = 0; 652 m_probesWithNoIngressPackets = 0;
696 m_lastPacketsReceived = m_packetsReceived;
697 } 653 }
698 654
699 //SendPacketStats();
700 m_packetTracker.Process();
701
702 if (m_terrainCheckerCount >= 4)
703 {
704 m_packetTracker.TerrainPacketCheck();
705 // m_packetTracker.PrimPacketCheck();
706 m_terrainCheckerCount = -1;
707 }
708 m_terrainCheckerCount++;
709 } 655 }
710 656
711 # region Setup 657 # region Setup
@@ -719,9 +665,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
719 //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); 665 //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
720 666
721 // Establish our two timers. We could probably get this down to one 667 // Establish our two timers. We could probably get this down to one
722 m_ackTimer = new Timer(750);
723 m_ackTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
724 m_ackTimer.Start();
725 668
726 m_clientPingTimer = new Timer(5000); 669 m_clientPingTimer = new Timer(5000);
727 m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity); 670 m_clientPingTimer.Elapsed += new ElapsedEventHandler(CheckClientConnectivity);
@@ -754,7 +697,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
754 "[CLIENT]: New user request denied to avatar {0} connecting with circuit code {1} from {2}", 697 "[CLIENT]: New user request denied to avatar {0} connecting with circuit code {1} from {2}",
755 m_agentId, m_circuitCode, m_userEndPoint); 698 m_agentId, m_circuitCode, m_userEndPoint);
756 699
757 m_packetQueue.Close(); 700 m_PacketHandler.Stop();
758 m_clientThread.Abort(); 701 m_clientThread.Abort();
759 } 702 }
760 else 703 else
@@ -920,7 +863,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
920 public event FriendActionDelegate OnApproveFriendRequest; 863 public event FriendActionDelegate OnApproveFriendRequest;
921 public event FriendActionDelegate OnDenyFriendRequest; 864 public event FriendActionDelegate OnDenyFriendRequest;
922 public event FriendshipTermination OnTerminateFriendship; 865 public event FriendshipTermination OnTerminateFriendship;
923 public event PacketStats OnPacketStats;
924 public event MoneyTransferRequest OnMoneyTransferRequest; 866 public event MoneyTransferRequest OnMoneyTransferRequest;
925 public event EconomyDataRequest OnEconomyDataRequest; 867 public event EconomyDataRequest OnEconomyDataRequest;
926 public event MoneyBalanceRequest OnMoneyBalanceRequest; 868 public event MoneyBalanceRequest OnMoneyBalanceRequest;
@@ -1105,7 +1047,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1105 public virtual void SendLayerData(float[] map) 1047 public virtual void SendLayerData(float[] map)
1106 { 1048 {
1107 ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendLayerData), (object)map); 1049 ThreadPool.QueueUserWorkItem(new WaitCallback(DoSendLayerData), (object)map);
1108
1109 } 1050 }
1110 1051
1111 /// <summary> 1052 /// <summary>
@@ -1166,11 +1107,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1166 /// <param name="map">heightmap</param> 1107 /// <param name="map">heightmap</param>
1167 public void SendLayerData(int px, int py, float[] map) 1108 public void SendLayerData(int px, int py, float[] map)
1168 { 1109 {
1169 SendLayerData(px, py, map, true);
1170 }
1171
1172 public void SendLayerData(int px, int py, float[] map, bool track)
1173 {
1174 try 1110 try
1175 { 1111 {
1176 int[] patches = new int[1]; 1112 int[] patches = new int[1];
@@ -1183,12 +1119,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1183 LayerDataPacket layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1119 LayerDataPacket layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches);
1184 layerpack.Header.Zerocoded = true; 1120 layerpack.Header.Zerocoded = true;
1185 1121
1186 if (track)
1187 {
1188 layerpack.Header.Sequence = NextSeqNum();
1189 m_packetTracker.TrackTerrainPacket(layerpack.Header.Sequence, px, py);
1190 }
1191
1192 OutPacket(layerpack, ThrottleOutPacketType.Land); 1122 OutPacket(layerpack, ThrottleOutPacketType.Land);
1193 } 1123 }
1194 catch (Exception e) 1124 catch (Exception e)
@@ -2309,14 +2239,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2309 ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape, 2239 ulong regionHandle, ushort timeDilation, uint localID, PrimitiveBaseShape primShape,
2310 LLVector3 pos, LLVector3 vel, LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, 2240 LLVector3 pos, LLVector3 vel, LLVector3 acc, LLQuaternion rotation, LLVector3 rvel,
2311 uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color, 2241 uint flags, LLUUID objectID, LLUUID ownerID, string text, byte[] color,
2312 uint parentID, byte[] particleSystem, byte clickAction, bool track) 2242 uint parentID, byte[] particleSystem, byte clickAction)
2313 { 2243 {
2314 byte[] textureanim = new byte[0]; 2244 byte[] textureanim = new byte[0];
2315 2245
2316 SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel, 2246 SendPrimitiveToClient(regionHandle, timeDilation, localID, primShape, pos, vel,
2317 acc, rotation, rvel, flags, 2247 acc, rotation, rvel, flags,
2318 objectID, ownerID, text, color, parentID, particleSystem, 2248 objectID, ownerID, text, color, parentID, particleSystem,
2319 clickAction, textureanim, false, (uint)0, LLUUID.Zero, LLUUID.Zero, 0, 0, 0, track); 2249 clickAction, textureanim, false, (uint)0, LLUUID.Zero, LLUUID.Zero, 0, 0, 0);
2320 } 2250 }
2321 2251
2322 public void SendPrimitiveToClient( 2252 public void SendPrimitiveToClient(
@@ -2324,7 +2254,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2324 LLVector3 pos, LLVector3 velocity, LLVector3 acceleration, LLQuaternion rotation, LLVector3 rotational_velocity, 2254 LLVector3 pos, LLVector3 velocity, LLVector3 acceleration, LLQuaternion rotation, LLVector3 rotational_velocity,
2325 uint flags, 2255 uint flags,
2326 LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem, 2256 LLUUID objectID, LLUUID ownerID, string text, byte[] color, uint parentID, byte[] particleSystem,
2327 byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius, bool track) 2257 byte clickAction, byte[] textureanim, bool attachment, uint AttachPoint, LLUUID AssetId, LLUUID SoundId, double SoundGain, byte SoundFlags, double SoundRadius)
2328 { 2258 {
2329 2259
2330 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0) 2260 if (rotation.X == rotation.Y && rotation.Y == rotation.Z && rotation.Z == rotation.W && rotation.W == 0)
@@ -2410,13 +2340,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2410 } 2340 }
2411 outPacket.Header.Zerocoded = true; 2341 outPacket.Header.Zerocoded = true;
2412 2342
2413 if (track) 2343 OutPacket(outPacket, ThrottleOutPacketType.LowpriorityTask);
2414 {
2415 outPacket.Header.Sequence = NextSeqNum();
2416 m_packetTracker.TrackPrimPacket(outPacket.Header.Sequence, objectID);
2417 }
2418
2419 OutPacket(outPacket, ThrottleOutPacketType.Task);
2420 } 2344 }
2421 2345
2422 /// <summary> 2346 /// <summary>
@@ -2440,7 +2364,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2440 terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity, state); // AssetID should fall into here probably somehow... 2364 terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity, state); // AssetID should fall into here probably somehow...
2441 terse.Header.Reliable = false; 2365 terse.Header.Reliable = false;
2442 terse.Header.Zerocoded = true; 2366 terse.Header.Zerocoded = true;
2443 OutPacket(terse, ThrottleOutPacketType.Task); 2367 OutPacket(terse, ThrottleOutPacketType.LowpriorityTask);
2444 } 2368 }
2445 2369
2446 public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position, 2370 public void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position,
@@ -2456,7 +2380,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2456 terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity, 0); 2380 terse.ObjectData[0] = CreatePrimImprovedBlock(localID, position, rotation, velocity, rotationalvelocity, 0);
2457 terse.Header.Reliable = false; 2381 terse.Header.Reliable = false;
2458 terse.Header.Zerocoded = true; 2382 terse.Header.Zerocoded = true;
2459 OutPacket(terse, ThrottleOutPacketType.Task); 2383 OutPacket(terse, ThrottleOutPacketType.LowpriorityTask);
2460 } 2384 }
2461 2385
2462 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, LLUUID AssetFullID) 2386 public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, LLUUID AssetFullID)
@@ -3736,7 +3660,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3736 /// <returns></returns> 3660 /// <returns></returns>
3737 public byte[] GetThrottlesPacked(float multiplier) 3661 public byte[] GetThrottlesPacked(float multiplier)
3738 { 3662 {
3739 return m_packetQueue.GetThrottlesPacked(multiplier); 3663 return m_PacketHandler.PacketQueue.GetThrottlesPacked(multiplier);
3740 } 3664 }
3741 /// <summary> 3665 /// <summary>
3742 /// sets the throttles from values supplied by the client 3666 /// sets the throttles from values supplied by the client
@@ -3744,86 +3668,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3744 /// <param name="throttles"></param> 3668 /// <param name="throttles"></param>
3745 public void SetChildAgentThrottle(byte[] throttles) 3669 public void SetChildAgentThrottle(byte[] throttles)
3746 { 3670 {
3747 m_packetQueue.SetThrottleFromClient(throttles); 3671 m_PacketHandler.PacketQueue.SetThrottleFromClient(throttles);
3748 } 3672 }
3749 3673
3750 // Previously ClientView.m_packetQueue 3674 // Previously ClientView.m_packetQueue
3751 3675
3752 // A thread safe sequence number allocator.
3753 protected uint NextSeqNum()
3754 {
3755 // Set the sequence number
3756 uint seq = 1;
3757 lock (m_sequenceLock)
3758 {
3759 if (m_sequence >= MAX_SEQUENCE)
3760 {
3761 m_sequence = 1;
3762 }
3763 else
3764 {
3765 m_sequence++;
3766 }
3767 seq = m_sequence;
3768 }
3769 return seq;
3770 }
3771
3772 protected void AddAck(Packet Pack)
3773 {
3774 lock (m_needAck)
3775 {
3776 if (!m_needAck.ContainsKey(Pack.Header.Sequence))
3777 {
3778 try
3779 {
3780 m_needAck.Add(Pack.Header.Sequence, Pack);
3781 m_unAckedBytes += Pack.ToBytes().Length;
3782 }
3783 //BUG: severity=major - This looks like a framework bug!?
3784 catch (Exception) // HACKY
3785 {
3786 // Ignore
3787 // Seems to throw a exception here occasionally
3788 // of 'duplicate key' despite being locked.
3789 // !?!?!?
3790 }
3791 }
3792 else
3793 {
3794 // Client.Log("Attempted to add a duplicate sequence number (" +
3795 // packet.Header.m_sequence + ") to the m_needAck dictionary for packet type " +
3796 // packet.Type.ToString(), Helpers.LogLevel.Warning);
3797 }
3798 }
3799 }
3800 /// <summary>
3801 /// Append any ACKs that need to be sent out to this packet
3802 /// </summary>
3803 /// <param name="Pack"></param>
3804 protected virtual void SetPendingAcks(ref Packet Pack)
3805 {
3806
3807 lock (m_pendingAcks)
3808 {
3809 // TODO: If we are over MAX_APPENDED_ACKS we should drain off some of these
3810 if (m_pendingAcks.Count > 0 && m_pendingAcks.Count < MAX_APPENDED_ACKS)
3811 {
3812 Pack.Header.AckList = new uint[m_pendingAcks.Count];
3813 int i = 0;
3814
3815 foreach (uint ack in m_pendingAcks.Values)
3816 {
3817 Pack.Header.AckList[i] = ack;
3818 i++;
3819 }
3820
3821 m_pendingAcks.Clear();
3822 Pack.Header.AppendedAcks = true;
3823 }
3824 }
3825 }
3826
3827 /// <summary> 3676 /// <summary>
3828 /// Helper routine to prepare the packet for sending to UDP client 3677 /// Helper routine to prepare the packet for sending to UDP client
3829 /// This converts it to bytes and puts it on the outgoing buffer 3678 /// This converts it to bytes and puts it on the outgoing buffer
@@ -3834,24 +3683,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3834 // Keep track of when this packet was sent out 3683 // Keep track of when this packet was sent out
3835 Pack.TickCount = System.Environment.TickCount; 3684 Pack.TickCount = System.Environment.TickCount;
3836 3685
3837 if (!Pack.Header.Resent)
3838 {
3839 if (Pack.Header.Sequence == 0)
3840 {
3841 Pack.Header.Sequence = NextSeqNum();
3842 }
3843
3844 if (Pack.Header.Reliable) //DIRTY HACK
3845 {
3846 AddAck(Pack); // this adds the need to ack this packet later
3847
3848 if (Pack.Type != PacketType.PacketAck && Pack.Type != PacketType.LogoutRequest)
3849 {
3850 SetPendingAcks(ref Pack);
3851 }
3852 }
3853 }
3854
3855 // Actually make the byte array and send it 3686 // Actually make the byte array and send it
3856 try 3687 try
3857 { 3688 {
@@ -3886,249 +3717,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3886 /// <param name="NewPack"></param> 3717 /// <param name="NewPack"></param>
3887 public virtual void InPacket(Packet NewPack) 3718 public virtual void InPacket(Packet NewPack)
3888 { 3719 {
3889 if (!m_packetProcessingEnabled && NewPack.Type != PacketType.LogoutRequest) 3720 m_PacketHandler.InPacket(NewPack);
3890 {
3891 PacketPool.Instance.ReturnPacket(NewPack);
3892 return;
3893 }
3894
3895 // Handle appended ACKs
3896 if (NewPack != null)
3897 {
3898 if (NewPack.Header.AppendedAcks)
3899 {
3900 lock (m_needAck)
3901 {
3902 foreach (uint ackedPacketId in NewPack.Header.AckList)
3903 {
3904 RemovePacketFromNeedAckList(ackedPacketId);
3905 }
3906 }
3907 }
3908
3909 // Handle PacketAck packets
3910 if (NewPack.Type == PacketType.PacketAck)
3911 {
3912 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
3913
3914 lock (m_needAck)
3915 {
3916 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
3917 {
3918 uint ackedPackId = block.ID;
3919 RemovePacketFromNeedAckList(ackedPackId);
3920 }
3921 }
3922 }
3923 else if ((NewPack.Type == PacketType.StartPingCheck))
3924 {
3925 //reply to pingcheck
3926 StartPingCheckPacket startPing = (StartPingCheckPacket)NewPack;
3927 CompletePingCheckPacket endPing = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
3928 endPing.PingID.PingID = startPing.PingID.PingID;
3929 OutPacket(endPing, ThrottleOutPacketType.Task);
3930 }
3931 else
3932 {
3933 LLQueItem item = new LLQueItem();
3934 item.Packet = NewPack;
3935 item.Incoming = true;
3936 m_packetQueue.Enqueue(item);
3937 }
3938 }
3939 }
3940
3941 private void RemovePacketFromNeedAckList(uint ackedPackId)
3942 {
3943 Packet ackedPacket;
3944 if (m_needAck.TryGetValue(ackedPackId, out ackedPacket))
3945 {
3946 m_unAckedBytes -= ackedPacket.ToBytes().Length;
3947 m_needAck.Remove(ackedPackId);
3948
3949 m_packetTracker.PacketAck(ackedPackId);
3950 }
3951 } 3721 }
3952 3722
3953 /// <summary> 3723 /// <summary>
3954 /// The dreaded OutPacket. This should only be called from withink the ClientStack itself right now 3724 /// The dreaded OutPacket. This should only be called from within
3955 /// This is the entry point for simulator packets to go out to the client. 3725 /// the ClientStack itself right now
3726 /// This is the entry point for simulator packets to go out to
3727 /// the client.
3956 /// </summary> 3728 /// </summary>
3957 /// <param name="NewPack"></param> 3729 /// <param name="NewPack"></param>
3958 /// <param name="throttlePacketType">Corresponds to the type of data that is going out. Enum</param> 3730 /// <param name="throttlePacketType">Corresponds to the type of data that is going out. Enum</param>
3959 public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) 3731 public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType)
3960 { 3732 {
3961 if ((SynchronizeClient != null) && (!IsActive)) 3733 m_PacketHandler.OutPacket(NewPack, throttlePacketType);
3962 {
3963 // Sending packet to active client's server.
3964 if (SynchronizeClient(m_scene, NewPack, m_agentId, throttlePacketType))
3965 {
3966 return;
3967 }
3968 }
3969
3970 LLQueItem item = new LLQueItem();
3971 item.Packet = NewPack;
3972 item.Incoming = false;
3973 item.throttleType = throttlePacketType; // Packet throttle type
3974 m_packetQueue.Enqueue(item);
3975 m_packetsSent++;
3976 }
3977
3978 # region Low Level Packet Methods
3979
3980 protected void ack_pack(Packet Pack)
3981 {
3982 if (Pack.Header.Reliable)
3983 {
3984 PacketAckPacket ack_it = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
3985 // TODO: don't create new blocks if recycling an old packet
3986 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
3987 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
3988 ack_it.Packets[0].ID = Pack.Header.Sequence;
3989 ack_it.Header.Reliable = false;
3990
3991 OutPacket(ack_it, ThrottleOutPacketType.Unknown);
3992 }
3993 /*
3994 if (Pack.Header.Reliable)
3995 {
3996 lock (m_pendingAcks)
3997 {
3998 uint sequence = (uint)Pack.Header.m_sequence;
3999 if (!m_pendingAcks.ContainsKey(sequence)) { m_pendingAcks[sequence] = sequence; }
4000 }
4001 }*/
4002 }
4003
4004 protected void ResendUnacked()
4005 {
4006 int now = System.Environment.TickCount;
4007
4008 lock (m_needAck)
4009 {
4010 foreach (Packet packet in m_needAck.Values)
4011 {
4012 if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
4013 {
4014 //m_log.Debug("[NETWORK]: Resending " + packet.Type.ToString() + " packet, " +
4015 //(now - packet.TickCount) + "ms have passed");
4016
4017 packet.Header.Resent = true;
4018 OutPacket(packet, ThrottleOutPacketType.Resend);
4019 }
4020 }
4021 }
4022 } 3734 }
4023 3735
4024 protected void SendAcks()
4025 {
4026 lock (m_pendingAcks)
4027 {
4028 if (m_pendingAcks.Count > 0)
4029 {
4030 if (m_pendingAcks.Count > 250)
4031 {
4032 // FIXME: Handle the odd case where we have too many pending ACKs queued up
4033 m_log.Info("[NETWORK]: Too many ACKs queued up!");
4034 return;
4035 }
4036
4037 //m_log.Info("[NETWORK]: Sending PacketAck");
4038
4039 int i = 0;
4040 PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
4041 // TODO: don't create new blocks if recycling an old packet
4042 acks.Packets = new PacketAckPacket.PacketsBlock[m_pendingAcks.Count];
4043
4044 foreach (uint ack in m_pendingAcks.Values)
4045 {
4046 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
4047 acks.Packets[i].ID = ack;
4048 i++;
4049 }
4050
4051 acks.Header.Reliable = false;
4052 OutPacket(acks, ThrottleOutPacketType.Unknown);
4053
4054 m_pendingAcks.Clear();
4055 }
4056 }
4057 }
4058
4059 protected void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
4060 {
4061 SendAcks();
4062 ResendUnacked();
4063 SendPacketStats();
4064 // TerrainPacketTrack();
4065 }
4066
4067 /// <summary>
4068 /// Keeps track of the packet stats for the simulator stats reporter
4069 /// </summary>
4070 protected void SendPacketStats()
4071 {
4072 handlerPacketStats = OnPacketStats;
4073 if (handlerPacketStats != null)
4074 {
4075 handlerPacketStats(m_packetsReceived - m_lastPacketsReceivedSentToScene, m_packetsSent - m_lastPacketsSentSentToScene, m_unAckedBytes);
4076 m_lastPacketsReceivedSentToScene = m_packetsReceived;
4077 m_lastPacketsSentSentToScene = m_packetsSent;
4078 }
4079 }
4080
4081
4082 /// <summary>
4083 /// Emties out the old packets in the packet duplication tracking table.
4084 /// </summary>
4085 protected void ClearOldPacketDupeTracking()
4086 {
4087 lock (m_dupeLimiter)
4088 {
4089 List<uint> toEliminate = new List<uint>();
4090 try
4091 {
4092 foreach (uint seq in m_dupeLimiter.Keys)
4093 {
4094 PacketDupeLimiter pkdata = null;
4095 m_dupeLimiter.TryGetValue(seq, out pkdata);
4096 if (pkdata != null)
4097 {
4098 // doing a foreach loop, so we don't want to modify the dictionary while we're searching it
4099 if (Util.UnixTimeSinceEpoch() - pkdata.timeIn > m_clearDuplicatePacketTrackingOlderThenXSeconds)
4100 toEliminate.Add(seq);
4101 }
4102 }
4103 }
4104 catch (InvalidOperationException)
4105 {
4106 m_log.Info("[PACKET]: Unable to clear dupe check packet data");
4107 }
4108
4109 // remove the dupe packets that we detected in the loop above.
4110 uint[] seqsToRemove = toEliminate.ToArray();
4111 for (int i = 0; i < seqsToRemove.Length; i++)
4112 {
4113 if (m_dupeLimiter.ContainsKey(seqsToRemove[i]))
4114 m_dupeLimiter.Remove(seqsToRemove[i]);
4115 }
4116 }
4117 }
4118
4119 #endregion
4120
4121 public void TriggerTerrainUnackedEvent(int patchX, int patchY)
4122 {
4123 handlerUnackedTerrain = OnUnackedTerrain;
4124 if (handlerUnackedTerrain != null)
4125 {
4126 handlerUnackedTerrain(this, patchX, patchY);
4127 }
4128 }
4129
4130 // Previously ClientView.ProcessPackets
4131
4132 public bool AddMoney(int debit) 3736 public bool AddMoney(int debit)
4133 { 3737 {
4134 if (m_moneyBalance + debit >= 0) 3738 if (m_moneyBalance + debit >= 0)
@@ -4143,14 +3747,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4143 } 3747 }
4144 } 3748 }
4145 3749
4146 private bool m_packetProcessingEnabled = true;
4147
4148 public bool IsActive
4149 {
4150 get { return m_packetProcessingEnabled; }
4151 set { m_packetProcessingEnabled = value; }
4152 }
4153
4154 /// <summary> 3750 /// <summary>
4155 /// Breaks down the genericMessagePacket into specific events 3751 /// Breaks down the genericMessagePacket into specific events
4156 /// </summary> 3752 /// </summary>
@@ -4206,31 +3802,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4206 /// all UDP packets from the client will end up here 3802 /// all UDP packets from the client will end up here
4207 /// </summary> 3803 /// </summary>
4208 /// <param name="Pack">libsecondlife.packet</param> 3804 /// <param name="Pack">libsecondlife.packet</param>
4209 protected void ProcessInPacket(Packet Pack) 3805 public void ProcessInPacket(Packet Pack)
4210 { 3806 {
4211 // always ack the packet!
4212 ack_pack(Pack);
4213
4214 // check for duplicate packets.. packets that the client is
4215 // resending because it didn't receive our ack
4216
4217 lock (m_dupeLimiter)
4218 {
4219 if (m_dupeLimiter.ContainsKey(Pack.Header.Sequence))
4220 {
4221 //m_log.Info("[CLIENT]: Warning Duplicate packet detected" + Pack.Type.ToString() + " Dropping.");
4222 return;
4223 }
4224 else
4225 {
4226 PacketDupeLimiter pkdedupe = new PacketDupeLimiter();
4227 pkdedupe.packetId = Pack.Header.ID;
4228 pkdedupe.pktype = Pack.Type;
4229 pkdedupe.timeIn = Util.UnixTimeSinceEpoch();
4230 m_dupeLimiter.Add(Pack.Header.Sequence, pkdedupe);
4231 }
4232 }
4233
4234 // check if we've got a local packet handler for this packet.type. See RegisterLocalPacketHandlers() 3807 // check if we've got a local packet handler for this packet.type. See RegisterLocalPacketHandlers()
4235 if (ProcessPacketMethod(Pack)) 3808 if (ProcessPacketMethod(Pack))
4236 { 3809 {
@@ -4702,7 +4275,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4702 4275
4703 case PacketType.AgentThrottle: 4276 case PacketType.AgentThrottle:
4704 AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; 4277 AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
4705 m_packetQueue.SetThrottleFromClient(atpack.Throttle.Throttles); 4278 m_PacketHandler.PacketQueue.SetThrottleFromClient(atpack.Throttle.Throttles);
4706 break; 4279 break;
4707 4280
4708 case PacketType.AgentPause: 4281 case PacketType.AgentPause:
@@ -6648,76 +6221,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6648 6221
6649 public ClientInfo GetClientInfo() 6222 public ClientInfo GetClientInfo()
6650 { 6223 {
6651 //MainLog.Instance.Verbose("CLIENT", "GetClientInfo BGN"); 6224 ClientInfo info = m_PacketHandler.GetClientInfo();
6652 6225
6653 ClientInfo info = new ClientInfo();
6654 info.userEP = this.m_userEndPoint; 6226 info.userEP = this.m_userEndPoint;
6655 info.proxyEP = this.m_proxyEndPoint; 6227 info.proxyEP = this.m_proxyEndPoint;
6656 info.agentcircuit = new sAgentCircuitData(RequestClientInfo()); 6228 info.agentcircuit = new sAgentCircuitData(RequestClientInfo());
6657 6229
6658 info.pendingAcks = m_pendingAcks;
6659
6660 info.needAck = new Dictionary<uint, byte[]>();
6661
6662 lock (m_needAck)
6663 {
6664 foreach (uint key in m_needAck.Keys)
6665 {
6666 info.needAck.Add(key, m_needAck[key].ToBytes());
6667 }
6668 }
6669
6670 /* pending
6671 QueItem[] queitems = m_packetQueue.GetQueueArray();
6672
6673 MainLog.Instance.Verbose("CLIENT", "Queue Count : [{0}]", queitems.Length);
6674
6675 for (int i = 0; i < queitems.Length; i++)
6676 {
6677 if (queitems[i].Incoming == false)
6678 {
6679 info.out_packets.Add(queitems[i].Packet.ToBytes());
6680 MainLog.Instance.Verbose("CLIENT", "Add OutPacket [{0}]", queitems[i].Packet.Type.ToString());
6681 }
6682 }
6683 */
6684
6685 info.sequence = m_sequence;
6686
6687 //MainLog.Instance.Verbose("CLIENT", "GetClientInfo END");
6688
6689 return info; 6230 return info;
6690 } 6231 }
6691 6232
6692 public void SetClientInfo(ClientInfo info) 6233 public void SetClientInfo(ClientInfo info)
6693 { 6234 {
6694 m_pendingAcks = info.pendingAcks; 6235 m_PacketHandler.SetClientInfo(info);
6695
6696 m_needAck = new Dictionary<uint, Packet>();
6697
6698 Packet packet = null;
6699 int packetEnd = 0;
6700 byte[] zero = new byte[3000];
6701
6702 foreach (uint key in info.needAck.Keys)
6703 {
6704 byte[] buff = info.needAck[key];
6705
6706 packetEnd = buff.Length - 1;
6707
6708 try
6709 {
6710 packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
6711 }
6712 catch (Exception)
6713 {
6714
6715 }
6716
6717 m_needAck.Add(key, packet);
6718 }
6719
6720 m_sequence = info.sequence;
6721 } 6236 }
6722 6237
6723 #region Media Parcel Members 6238 #region Media Parcel Members
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs
new file mode 100644
index 0000000..1ec375f
--- /dev/null
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs
@@ -0,0 +1,692 @@
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 OpenSim 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;
30using System.Collections.Generic;
31using System.Net;
32using System.Net.Sockets;
33using System.Timers;
34using libsecondlife;
35using libsecondlife.Packets;
36using Timer = System.Timers.Timer;
37using OpenSim.Framework;
38
39namespace OpenSim.Region.ClientStack.LindenUDP
40{
41 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
42 public delegate void PacketDrop(Packet pack, Object id);
43 public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType);
44
45 public interface IPacketHandler
46 {
47 event PacketStats OnPacketStats;
48 event PacketDrop OnPacketDrop;
49 SynchronizeClientHandler SynchronizeClient { set; }
50
51 int PacketsReceived { get; }
52 int PacketsReceivedReported { get; }
53 uint SilenceLimit { get; set; }
54 uint DiscardTimeout { get; set; }
55 uint ResendTimeout { get; set; }
56
57 void InPacket(Packet packet);
58 void ProcessInPacket(Packet packet);
59 void OutPacket(Packet NewPack,
60 ThrottleOutPacketType throttlePacketType);
61 void OutPacket(Packet NewPack,
62 ThrottleOutPacketType throttlePacketType, Object id);
63 LLPacketQueue PacketQueue { get; }
64 void Stop();
65 void Flush();
66 void Clear();
67 ClientInfo GetClientInfo();
68 void SetClientInfo(ClientInfo info);
69 void AddImportantPacket(PacketType type);
70 void RemoveImportantPacket(PacketType type);
71 }
72
73 public class LLPacketHandler : IPacketHandler
74 {
75 // Packet queues
76 //
77 LLPacketQueue m_PacketQueue;
78
79 public LLPacketQueue PacketQueue
80 {
81 get { return m_PacketQueue; }
82 }
83
84 // Timer to run stats and acks on
85 //
86 private Timer m_AckTimer = new Timer(250);
87
88 // A list of the packets we haven't acked yet
89 //
90 private Dictionary<uint,uint> m_PendingAcks = new Dictionary<uint,uint>();
91 // Dictionary of the packets that need acks from the client.
92 //
93 private class AckData
94 {
95 public AckData(Packet packet, Object identifier)
96 {
97 Packet = packet;
98 Identifier = identifier;
99 }
100
101 public Packet Packet;
102 public Object Identifier;
103 }
104 private Dictionary<uint, AckData> m_NeedAck =
105 new Dictionary<uint, AckData>();
106
107 private uint m_ResendTimeout = 1000;
108
109 public uint ResendTimeout
110 {
111 get { return m_ResendTimeout; }
112 set { m_ResendTimeout = value; }
113 }
114
115 private uint m_DiscardTimeout = 8000;
116
117 public uint DiscardTimeout
118 {
119 get { return m_DiscardTimeout; }
120 set { m_DiscardTimeout = value; }
121 }
122
123 private uint m_SilenceLimit = 250;
124
125 public uint SilenceLimit
126 {
127 get { return m_SilenceLimit; }
128 set { m_SilenceLimit = value; }
129 }
130
131 private int m_LastAck = 0;
132
133 // Track duplicated packets. This uses a Dictionary. Both insertion
134 // and lookup are common operations and need to take advantage of
135 // the hashing. Expiration is less common and can be allowed the
136 // time for a linear scan.
137 //
138 private Dictionary<uint, int> m_DupeTracker =
139 new Dictionary<uint, int>();
140 private uint m_DupeTrackerWindow = 30;
141
142 // Values for the SimStatsReporter
143 //
144 private int m_PacketsReceived = 0;
145 private int m_PacketsReceivedReported = 0;
146 private int m_PacketsSent = 0;
147 private int m_PacketsSentReported = 0;
148 private int m_UnackedBytes = 0;
149
150 public int PacketsReceived
151 {
152 get { return m_PacketsReceived; }
153 }
154
155 public int PacketsReceivedReported
156 {
157 get { return m_PacketsReceivedReported; }
158 }
159
160 // The client we are working for
161 //
162 private IClientAPI m_Client;
163
164 // Some events
165 //
166 public event PacketStats OnPacketStats;
167 public event PacketDrop OnPacketDrop;
168
169 private SynchronizeClientHandler m_SynchronizeClient = null;
170
171 public SynchronizeClientHandler SynchronizeClient
172 {
173 set { m_SynchronizeClient = value; }
174 }
175
176 // Packet sequencing
177 //
178 private uint m_Sequence = 0;
179 private object m_SequenceLock = new object();
180 private const int MAX_SEQUENCE = 0xFFFFFF;
181
182 List<PacketType> m_ImportantPackets = new List<PacketType>();
183
184 ////////////////////////////////////////////////////////////////////
185
186 // Constructors
187 //
188 public LLPacketHandler(IClientAPI client)
189 {
190 m_Client = client;
191
192 m_PacketQueue = new LLPacketQueue(client.AgentId);
193
194 m_AckTimer.Elapsed += AckTimerElapsed;
195 m_AckTimer.Start();
196 }
197
198 public void Stop()
199 {
200 m_AckTimer.Stop();
201
202 m_PacketQueue.Enqueue(null);
203 }
204
205 // Send one packet. This actually doesn't send anything, it queues
206 // it. Designed to be fire-and-forget, but there is an optional
207 // notifier.
208 //
209 public void OutPacket(
210 Packet packet, ThrottleOutPacketType throttlePacketType)
211 {
212 OutPacket(packet, throttlePacketType, null);
213 }
214
215 public void OutPacket(
216 Packet packet, ThrottleOutPacketType throttlePacketType,
217 Object id)
218 {
219 // Call the load balancer's hook. If this is not active here
220 // we defer to the sim server this client is actually connected
221 // to. Packet drop notifies will not be triggered in this
222 // configuration!
223 //
224 if ((m_SynchronizeClient != null) && (!m_Client.IsActive))
225 {
226 if (m_SynchronizeClient(m_Client.Scene, packet,
227 m_Client.AgentId, throttlePacketType))
228 return;
229 }
230
231 packet.Header.Sequence = NextPacketSequenceNumber();
232
233 lock(m_NeedAck)
234 {
235 DropResend(id);
236
237 QueuePacket(packet, throttlePacketType, id);
238
239 // We want to see that packet arrive if it's reliable
240 if(packet.Header.Reliable)
241 {
242 m_UnackedBytes += packet.ToBytes().Length;
243 m_NeedAck[packet.Header.Sequence] = new AckData(packet, id);
244 }
245 }
246 }
247
248 private void QueuePacket(
249 Packet packet, ThrottleOutPacketType throttlePacketType,
250 Object id)
251 {
252 // Add acks to outgoing packets
253 //
254 lock(m_PendingAcks)
255 {
256 if(m_PendingAcks.Count > 0)
257 {
258 int count = m_PendingAcks.Count;
259 if(count > 10)
260 count = 10;
261 packet.Header.AckList = new uint[count];
262
263 int i = 0;
264
265 foreach (uint ack in new List<uint>(m_PendingAcks.Keys))
266 {
267 packet.Header.AckList[i] = ack;
268 i++;
269 m_PendingAcks.Remove(ack);
270 if (i >= 10) // That is how much space there is
271 break;
272 }
273 }
274 }
275
276 packet.TickCount = System.Environment.TickCount;
277
278 LLQueItem item = new LLQueItem();
279 item.Packet = packet;
280 item.Incoming = false;
281 item.throttleType = throttlePacketType;
282 item.Identifier = id;
283
284 m_PacketQueue.Enqueue(item);
285 m_PacketsSent++;
286 }
287
288 private void ResendUnacked()
289 {
290 int now = System.Environment.TickCount;
291 int lastAck = m_LastAck;
292
293 // Unless we have received at least one ack, don't bother resending
294 // anything. There may not be a client there, don't clog up the
295 // pipes.
296 //
297 if(lastAck == 0)
298 return;
299
300 lock (m_NeedAck)
301 {
302 // Nothing to do
303 //
304 if(m_NeedAck.Count == 0)
305 return;
306
307 // If we have seen no acks in <SilenceLimit> s but are
308 // waiting for acks, then there may be no one listening.
309 // No need to resend anything. Keep it until it gets stale,
310 // then it will be dropped.
311 //
312 if (((now - lastAck) > m_SilenceLimit) &&
313 m_NeedAck.Count > 0)
314 {
315 return;
316 }
317
318 foreach (AckData data in new List<AckData>(m_NeedAck.Values))
319 {
320 Packet packet = data.Packet;
321
322 // Packets this old get resent
323 //
324 if ((now - packet.TickCount) > m_ResendTimeout)
325 {
326 // Resend the packet. Set the packet's tick count to
327 // now, and keep it marked as resent.
328 //
329 packet.Header.Resent = true;
330 QueuePacket(packet, ThrottleOutPacketType.Resend,
331 data.Identifier);
332 }
333
334 // The discard logic
335 // If the packet is in the queue for <DiscardTimeout> s
336 // without having been processed, then we have clogged
337 // pipes. Most likely, the client is gone
338 // Drop the packets
339 //
340 if ((now - packet.TickCount) > m_DiscardTimeout)
341 {
342 if(!m_ImportantPackets.Contains(packet.Type))
343 m_NeedAck.Remove(packet.Header.Sequence);
344
345 TriggerOnPacketDrop(packet, data.Identifier);
346
347 continue;
348 }
349 }
350 }
351 }
352
353 // Send the pending packet acks to the client
354 // Will send blocks of acks for up to 250 packets
355 //
356 private void SendAcks()
357 {
358 lock (m_PendingAcks)
359 {
360 if (m_PendingAcks.Count == 0)
361 return;
362
363 PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
364
365 // The case of equality is more common than one might think,
366 // because this function will be called unconditionally when
367 // the counter reaches 250. So there is a good chance another
368 // packet with 250 blocks exists.
369 //
370 if(acks.Packets == null ||
371 acks.Packets.Length != m_PendingAcks.Count)
372 acks.Packets = new PacketAckPacket.PacketsBlock[m_PendingAcks.Count];
373 int i = 0;
374 foreach (uint ack in new List<uint>(m_PendingAcks.Keys))
375 {
376 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
377 acks.Packets[i].ID = ack;
378
379 m_PendingAcks.Remove(ack);
380 i++;
381 }
382
383 acks.Header.Reliable = false;
384 OutPacket(acks, ThrottleOutPacketType.Unknown);
385 }
386 }
387
388 // Queue a packet ack. It will be sent either after 250 acks are
389 // queued, or when the timer fires.
390 //
391 private void AckPacket(Packet packet)
392 {
393 lock (m_PendingAcks)
394 {
395 if(m_PendingAcks.Count < 250)
396 {
397 if(!m_PendingAcks.ContainsKey(packet.Header.Sequence))
398 m_PendingAcks.Add(packet.Header.Sequence,
399 packet.Header.Sequence);
400 return;
401 }
402 }
403
404 SendAcks();
405
406 lock (m_PendingAcks)
407 {
408 // If this is still full we have a truly exceptional
409 // condition (means, can't happen)
410 //
411 if(m_PendingAcks.Count < 250)
412 {
413 if(!m_PendingAcks.ContainsKey(packet.Header.Sequence))
414 m_PendingAcks.Add(packet.Header.Sequence,
415 packet.Header.Sequence);
416 return;
417 }
418 }
419 }
420
421 // When the timer elapses, send the pending acks, trigger resends
422 // and report all the stats.
423 //
424 private void AckTimerElapsed(object sender, ElapsedEventArgs ea)
425 {
426 SendAcks();
427 ResendUnacked();
428 SendPacketStats();
429 }
430
431 // Push out pachet counts for the sim status reporter
432 //
433 private void SendPacketStats()
434 {
435 PacketStats handlerPacketStats = OnPacketStats;
436 if (handlerPacketStats != null)
437 {
438 handlerPacketStats(
439 m_PacketsReceived - m_PacketsReceivedReported,
440 m_PacketsSent - m_PacketsSentReported,
441 m_UnackedBytes);
442
443 m_PacketsReceivedReported = m_PacketsReceived;
444 m_PacketsSentReported = m_PacketsSent;
445 }
446 }
447
448 // We can't keep an unlimited record of dupes. This will prune the
449 // dictionary by age.
450 //
451 private void PruneDupeTracker()
452 {
453 lock (m_DupeTracker)
454 {
455 Dictionary<uint, int> packs =
456 new Dictionary<uint, int>(m_DupeTracker);
457
458 foreach (uint pack in packs.Keys)
459 {
460 if(Util.UnixTimeSinceEpoch() - m_DupeTracker[pack] >
461 m_DupeTrackerWindow)
462 m_DupeTracker.Remove(pack);
463 }
464 }
465 }
466
467 public void InPacket(Packet packet)
468 {
469 if(packet == null)
470 return;
471
472 // If this client is on another partial instance, no need
473 // to handle packets
474 //
475 if(!m_Client.IsActive && packet.Type != PacketType.LogoutRequest)
476 {
477 PacketPool.Instance.ReturnPacket(packet);
478 return;
479 }
480
481 // Any packet can have some packet acks in the header.
482 // Process them here
483 //
484 if(packet.Header.AppendedAcks)
485 {
486 foreach(uint id in packet.Header.AckList)
487 {
488 ProcessAck(id);
489 }
490 }
491
492 // When too many acks are needed to be sent, the client sends
493 // a packet consisting of acks only
494 //
495 if(packet.Type == PacketType.PacketAck)
496 {
497 PacketAckPacket ackPacket = (PacketAckPacket)packet;
498
499 foreach (PacketAckPacket.PacketsBlock block in
500 ackPacket.Packets)
501 {
502 ProcessAck(block.ID);
503 }
504
505 PacketPool.Instance.ReturnPacket(packet);
506 return;
507 }
508 else if(packet.Type == PacketType.StartPingCheck)
509 {
510 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
511 CompletePingCheckPacket endPing = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
512
513 endPing.PingID.PingID = startPing.PingID.PingID;
514 OutPacket(endPing, ThrottleOutPacketType.Task);
515 }
516 else
517 {
518 LLQueItem item = new LLQueItem();
519 item.Packet = packet;
520 item.Incoming = true;
521 m_PacketQueue.Enqueue(item);
522 }
523 }
524
525 public void ProcessInPacket(Packet packet)
526 {
527 // Always ack the packet!
528 //
529 AckPacket(packet);
530
531 if (packet.Type != PacketType.AgentUpdate)
532 m_PacketsReceived++;
533
534 // Check for duplicate packets.. packets that the client is
535 // resending because it didn't receive our ack
536 //
537 lock (m_DupeTracker)
538 {
539 if (m_DupeTracker.ContainsKey(packet.Header.Sequence))
540 return;
541
542 m_DupeTracker.Add(packet.Header.Sequence,
543 Util.UnixTimeSinceEpoch());
544 }
545
546 m_Client.ProcessInPacket(packet);
547 }
548
549 public void Flush()
550 {
551 m_PacketQueue.Flush();
552 }
553
554 public void Clear()
555 {
556 m_NeedAck.Clear();
557 m_PendingAcks.Clear();
558 m_Sequence += 1000000;
559 }
560
561 private void ProcessAck(uint id)
562 {
563 AckData data;
564 Packet packet;
565
566 lock(m_NeedAck)
567 {
568 if(!m_NeedAck.TryGetValue(id, out data))
569 return;
570
571 packet = data.Packet;
572
573 m_NeedAck.Remove(id);
574 m_UnackedBytes -= packet.ToBytes().Length;
575
576 m_LastAck = System.Environment.TickCount;
577 }
578 }
579
580 // Allocate packet sequence numbers in a threadsave manner
581 //
582 protected uint NextPacketSequenceNumber()
583 {
584 // Set the sequence number
585 uint seq = 1;
586 lock (m_SequenceLock)
587 {
588 if (m_Sequence >= MAX_SEQUENCE)
589 {
590 m_Sequence = 1;
591 }
592 else
593 {
594 m_Sequence++;
595 }
596 seq = m_Sequence;
597 }
598 return seq;
599 }
600
601 public ClientInfo GetClientInfo()
602 {
603 ClientInfo info = new ClientInfo();
604 info.pendingAcks = m_PendingAcks;
605 info.needAck = new Dictionary<uint, byte[]>();
606
607 lock (m_NeedAck)
608 {
609 foreach (uint key in m_NeedAck.Keys)
610 info.needAck.Add(key, m_NeedAck[key].Packet.ToBytes());
611 }
612
613 LLQueItem[] queitems = m_PacketQueue.GetQueueArray();
614
615 for (int i = 0; i < queitems.Length; i++)
616 {
617 if (queitems[i].Incoming == false)
618 info.out_packets.Add(queitems[i].Packet.ToBytes());
619 }
620
621 info.sequence = m_Sequence;
622
623 return info;
624 }
625
626 public void SetClientInfo(ClientInfo info)
627 {
628 m_PendingAcks = info.pendingAcks;
629 m_NeedAck = new Dictionary<uint, AckData>();
630
631 Packet packet = null;
632 int packetEnd = 0;
633 byte[] zero = new byte[3000];
634
635 foreach (uint key in info.needAck.Keys)
636 {
637 byte[] buff = info.needAck[key];
638 packetEnd = buff.Length - 1;
639
640 try
641 {
642 packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
643 }
644 catch (Exception)
645 {
646 }
647
648 m_NeedAck.Add(key, new AckData(packet, null));
649 }
650
651 m_Sequence = info.sequence;
652 }
653
654 public void AddImportantPacket(PacketType type)
655 {
656 if(m_ImportantPackets.Contains(type))
657 return;
658
659 m_ImportantPackets.Add(type);
660 }
661
662 public void RemoveImportantPacket(PacketType type)
663 {
664 if(!m_ImportantPackets.Contains(type))
665 return;
666
667 m_ImportantPackets.Remove(type);
668 }
669
670 private void DropResend(Object id)
671 {
672 foreach (AckData data in new List<AckData>(m_NeedAck.Values))
673 {
674 if(data.Identifier != null && data.Identifier == id)
675 {
676 m_NeedAck.Remove(data.Packet.Header.Sequence);
677 return;
678 }
679 }
680 }
681
682 private void TriggerOnPacketDrop(Packet packet, Object id)
683 {
684 PacketDrop handlerPacketDrop = OnPacketDrop;
685
686 if(handlerPacketDrop == null)
687 return;
688
689 handlerPacketDrop(packet, id);
690 }
691 }
692}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs
index 51dcde7..96f8ac6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs
@@ -54,6 +54,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
54 private Queue<LLQueItem> WindOutgoingPacketQueue; 54 private Queue<LLQueItem> WindOutgoingPacketQueue;
55 private Queue<LLQueItem> CloudOutgoingPacketQueue; 55 private Queue<LLQueItem> CloudOutgoingPacketQueue;
56 private Queue<LLQueItem> TaskOutgoingPacketQueue; 56 private Queue<LLQueItem> TaskOutgoingPacketQueue;
57 private Queue<LLQueItem> TaskLowpriorityPacketQueue;
57 private Queue<LLQueItem> TextureOutgoingPacketQueue; 58 private Queue<LLQueItem> TextureOutgoingPacketQueue;
58 private Queue<LLQueItem> AssetOutgoingPacketQueue; 59 private Queue<LLQueItem> AssetOutgoingPacketQueue;
59 60
@@ -99,6 +100,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
99 WindOutgoingPacketQueue = new Queue<LLQueItem>(); 100 WindOutgoingPacketQueue = new Queue<LLQueItem>();
100 CloudOutgoingPacketQueue = new Queue<LLQueItem>(); 101 CloudOutgoingPacketQueue = new Queue<LLQueItem>();
101 TaskOutgoingPacketQueue = new Queue<LLQueItem>(); 102 TaskOutgoingPacketQueue = new Queue<LLQueItem>();
103 TaskLowpriorityPacketQueue = new Queue<LLQueItem>();
102 TextureOutgoingPacketQueue = new Queue<LLQueItem>(); 104 TextureOutgoingPacketQueue = new Queue<LLQueItem>();
103 AssetOutgoingPacketQueue = new Queue<LLQueItem>(); 105 AssetOutgoingPacketQueue = new Queue<LLQueItem>();
104 106
@@ -106,8 +108,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
106 // Set up the throttle classes (min, max, current) in bytes 108 // Set up the throttle classes (min, max, current) in bytes
107 ResendThrottle = new LLPacketThrottle(5000, 100000, 16000); 109 ResendThrottle = new LLPacketThrottle(5000, 100000, 16000);
108 LandThrottle = new LLPacketThrottle(1000, 100000, 2000); 110 LandThrottle = new LLPacketThrottle(1000, 100000, 2000);
109 WindThrottle = new LLPacketThrottle(1000, 100000, 1000); 111 WindThrottle = new LLPacketThrottle(0, 100000, 0);
110 CloudThrottle = new LLPacketThrottle(1000, 100000, 1000); 112 CloudThrottle = new LLPacketThrottle(0, 100000, 0);
111 TaskThrottle = new LLPacketThrottle(1000, 800000, 3000); 113 TaskThrottle = new LLPacketThrottle(1000, 800000, 3000);
112 AssetThrottle = new LLPacketThrottle(1000, 800000, 1000); 114 AssetThrottle = new LLPacketThrottle(1000, 800000, 1000);
113 TextureThrottle = new LLPacketThrottle(1000, 800000, 4000); 115 TextureThrottle = new LLPacketThrottle(1000, 800000, 4000);
@@ -149,6 +151,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 return; 151 return;
150 } 152 }
151 153
154 if (item.Incoming)
155 {
156 SendQueue.PriorityEnqueue(item);
157 return;
158 }
159
152 lock (this) 160 lock (this)
153 { 161 {
154 switch (item.throttleType) 162 switch (item.throttleType)
@@ -162,6 +170,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
162 case ThrottleOutPacketType.Task: 170 case ThrottleOutPacketType.Task:
163 ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); 171 ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
164 break; 172 break;
173 case ThrottleOutPacketType.LowpriorityTask:
174 ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item);
175 break;
165 case ThrottleOutPacketType.Land: 176 case ThrottleOutPacketType.Land:
166 ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); 177 ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
167 break; 178 break;
@@ -178,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
178 default: 189 default:
179 // Acknowledgements and other such stuff should go directly to the blocking Queue 190 // Acknowledgements and other such stuff should go directly to the blocking Queue
180 // Throttling them may and likely 'will' be problematic 191 // Throttling them may and likely 'will' be problematic
181 SendQueue.Enqueue(item); 192 SendQueue.PriorityEnqueue(item);
182 break; 193 break;
183 } 194 }
184 } 195 }
@@ -214,7 +225,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
214 } 225 }
215 if (TaskOutgoingPacketQueue.Count > 0) 226 if (TaskOutgoingPacketQueue.Count > 0)
216 { 227 {
217 SendQueue.Enqueue(TaskOutgoingPacketQueue.Dequeue()); 228 SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue());
229 }
230 if (TaskLowpriorityPacketQueue.Count > 0)
231 {
232 SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue());
218 } 233 }
219 if (TextureOutgoingPacketQueue.Count > 0) 234 if (TextureOutgoingPacketQueue.Count > 0)
220 { 235 {
@@ -261,6 +276,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
261 WindOutgoingPacketQueue.Count > 0 || 276 WindOutgoingPacketQueue.Count > 0 ||
262 CloudOutgoingPacketQueue.Count > 0 || 277 CloudOutgoingPacketQueue.Count > 0 ||
263 TaskOutgoingPacketQueue.Count > 0 || 278 TaskOutgoingPacketQueue.Count > 0 ||
279 TaskLowpriorityPacketQueue.Count > 0 ||
264 AssetOutgoingPacketQueue.Count > 0 || 280 AssetOutgoingPacketQueue.Count > 0 ||
265 TextureOutgoingPacketQueue.Count > 0); 281 TextureOutgoingPacketQueue.Count > 0);
266 } 282 }
@@ -319,11 +335,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
319 TotalThrottle.Add(qpack.Packet.ToBytes().Length); 335 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
320 CloudThrottle.Add(qpack.Packet.ToBytes().Length); 336 CloudThrottle.Add(qpack.Packet.ToBytes().Length);
321 } 337 }
322 if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0) 338 if (TaskThrottle.UnderLimit() && (TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0))
323 { 339 {
324 LLQueItem qpack = TaskOutgoingPacketQueue.Dequeue(); 340 LLQueItem qpack;
325 341 if(TaskOutgoingPacketQueue.Count > 0)
326 SendQueue.Enqueue(qpack); 342 {
343 qpack = TaskOutgoingPacketQueue.Dequeue();
344 SendQueue.PriorityEnqueue(qpack);
345 }
346 else
347 {
348 qpack = TaskLowpriorityPacketQueue.Dequeue();
349 SendQueue.Enqueue(qpack);
350 }
327 TotalThrottle.Add(qpack.Packet.ToBytes().Length); 351 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
328 TaskThrottle.Add(qpack.Packet.ToBytes().Length); 352 TaskThrottle.Add(qpack.Packet.ToBytes().Length);
329 } 353 }
@@ -490,18 +514,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
490 AssetThrottle.Throttle = tAsset; 514 AssetThrottle.Throttle = tAsset;
491 TotalThrottle.Throttle = tall; 515 TotalThrottle.Throttle = tall;
492 } 516 }
493 else if (tall < 1) 517// else if (tall < 1)
494 { 518// {
495 // client is stupid, penalize him by minning everything 519// // client is stupid, penalize him by minning everything
496 ResendThrottle.Throttle = ResendThrottle.Min; 520// ResendThrottle.Throttle = ResendThrottle.Min;
497 LandThrottle.Throttle = LandThrottle.Min; 521// LandThrottle.Throttle = LandThrottle.Min;
498 WindThrottle.Throttle = WindThrottle.Min; 522// WindThrottle.Throttle = WindThrottle.Min;
499 CloudThrottle.Throttle = CloudThrottle.Min; 523// CloudThrottle.Throttle = CloudThrottle.Min;
500 TaskThrottle.Throttle = TaskThrottle.Min; 524// TaskThrottle.Throttle = TaskThrottle.Min;
501 TextureThrottle.Throttle = TextureThrottle.Min; 525// TextureThrottle.Throttle = TextureThrottle.Min;
502 AssetThrottle.Throttle = AssetThrottle.Min; 526// AssetThrottle.Throttle = AssetThrottle.Min;
503 TotalThrottle.Throttle = TotalThrottle.Min; 527// TotalThrottle.Throttle = TotalThrottle.Min;
504 } 528// }
505 else 529 else
506 { 530 {
507 // we're over so figure out percentages and use those 531 // we're over so figure out percentages and use those
@@ -516,7 +540,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
516 TotalThrottle.Throttle = TotalThrottle.Max; 540 TotalThrottle.Throttle = TotalThrottle.Max;
517 } 541 }
518 // effectively wiggling the slider causes things reset 542 // effectively wiggling the slider causes things reset
519 ResetCounters(); 543// ResetCounters(); // DO NOT reset, better to send less for one period than more
520 } 544 }
521 545
522 // See IPullStatsProvider 546 // See IPullStatsProvider
@@ -540,4 +564,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
540 return SendQueue.GetQueueArray(); 564 return SendQueue.GetQueueArray();
541 } 565 }
542 } 566 }
543} \ No newline at end of file 567}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs
deleted file mode 100644
index 690fadb..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs
+++ /dev/null
@@ -1,263 +0,0 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading;
5using libsecondlife;
6using libsecondlife.Packets;
7using OpenSim.Framework;
8
9namespace OpenSim.Region.ClientStack.LindenUDP
10{
11
12 public class LLPacketTracker
13 {
14 public delegate void PacketAcked(uint sequenceNumber);
15 public event PacketAcked OnPacketAcked;
16
17 protected List<uint> m_beenAcked = new List<uint>();
18
19 protected TerrainPacketTracker[,] m_sentTerrainPackets = new TerrainPacketTracker[16, 16];
20 protected Dictionary<LLUUID, PrimPacketTracker> m_sendPrimPackets = new Dictionary<LLUUID, PrimPacketTracker>();
21
22 protected LLClientView m_parentClient;
23
24 public LLPacketTracker(LLClientView parent)
25 {
26 m_parentClient = parent;
27 OnPacketAcked += TerrainPacketAcked;
28 //OnPacketAcked += PrimPacketAcked;
29 }
30
31 public void PacketAck(uint sequenceNumber)
32 {
33 lock (m_beenAcked)
34 {
35 m_beenAcked.Add(sequenceNumber);
36 }
37 }
38
39 public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY)
40 {
41 TrackTerrainPacket(sequenceNumber, patchX, patchY, false, null);
42 }
43
44 public void TrackTerrainPacket(uint sequenceNumber, int patchX, int patchY, bool keepResending, LayerDataPacket packet)
45 {
46 TerrainPacketTracker tracker = new TerrainPacketTracker();
47 tracker.X = patchX;
48 tracker.Y = patchY;
49 tracker.SeqNumber = sequenceNumber;
50 tracker.TimeSent = DateTime.Now;
51 tracker.KeepResending = keepResending;
52 tracker.Packet = packet;
53 lock (m_sentTerrainPackets)
54 {
55 m_sentTerrainPackets[patchX, patchY] = tracker;
56 }
57 }
58
59 public void TrackPrimPacket(uint sequenceNumber, LLUUID primID)
60 {
61 PrimPacketTracker tracker = new PrimPacketTracker();
62 tracker.PrimID = primID;
63 tracker.TimeSent = DateTime.Now;
64 tracker.SeqNumber = sequenceNumber;
65 lock (m_sendPrimPackets)
66 {
67 m_sendPrimPackets[primID] = tracker;
68 }
69 }
70
71 public void TerrainPacketCheck()
72 {
73 DateTime now = DateTime.Now;
74 List<TerrainPacketTracker> resendList = new List<TerrainPacketTracker>();
75 lock (m_sentTerrainPackets)
76 {
77 for (int y = 0; y < 16; y++)
78 {
79 for (int x = 0; x < 16; x++)
80 {
81 if (m_sentTerrainPackets[x, y] != null)
82 {
83 TerrainPacketTracker tracker = m_sentTerrainPackets[x, y];
84 if ((now - tracker.TimeSent) > TimeSpan.FromMinutes(1))
85 {
86 tracker.TimeSent = now;
87 m_sentTerrainPackets[x, y] = null;
88 resendList.Add(tracker);
89 }
90 }
91 }
92 }
93 }
94
95 foreach (TerrainPacketTracker tracker in resendList)
96 {
97 if (!tracker.KeepResending)
98 {
99 m_parentClient.TriggerTerrainUnackedEvent(tracker.X, tracker.Y);
100 }
101 else
102 {
103 if (tracker.Packet != null)
104 {
105 tracker.Packet.Header.Resent = true;
106 m_parentClient.OutPacket(tracker.Packet, ThrottleOutPacketType.Resend);
107 tracker.TimeSent = DateTime.Now;
108 lock (m_sentTerrainPackets)
109 {
110 if (m_sentTerrainPackets[tracker.X, tracker.Y] == null)
111 {
112 m_sentTerrainPackets[tracker.X, tracker.Y] = tracker;
113 }
114 }
115 }
116 }
117 }
118 }
119
120 public void PrimPacketCheck()
121 {
122 DateTime now = DateTime.Now;
123 List<PrimPacketTracker> resendList = new List<PrimPacketTracker>();
124 List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>();
125
126 lock (m_sendPrimPackets)
127 {
128 foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
129 {
130 if (tracker.Acked)
131 {
132 ackedList.Add(tracker);
133 }
134 else if (((now - tracker.TimeSent) > TimeSpan.FromMinutes(1)) && (!tracker.Acked))
135 {
136 resendList.Add(tracker);
137 }
138 }
139 }
140
141 foreach (PrimPacketTracker tracker in resendList)
142 {
143 lock (m_sendPrimPackets)
144 {
145 m_sendPrimPackets.Remove(tracker.PrimID);
146 }
147 //call event
148 Console.WriteLine("Prim packet not acked, " + tracker.PrimID.ToString());
149 }
150
151
152 RemovePrimTrackers(ackedList);
153 }
154
155 public void PrimTrackerCleanup()
156 {
157 List<PrimPacketTracker> ackedList = new List<PrimPacketTracker>();
158
159 lock (m_sendPrimPackets)
160 {
161 foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
162 {
163 if (tracker.Acked)
164 {
165 ackedList.Add(tracker);
166 }
167 }
168 }
169 Thread.Sleep(15); //give a little bit of time for other code to access list before we lock it again
170
171 RemovePrimTrackers(ackedList);
172 }
173
174 protected void RemovePrimTrackers(List<PrimPacketTracker> ackedList)
175 {
176 lock (m_sendPrimPackets)
177 {
178 foreach (PrimPacketTracker tracker in ackedList)
179 {
180 m_sendPrimPackets.Remove(tracker.PrimID);
181 }
182 }
183 }
184
185 protected void TerrainPacketAcked(uint sequence)
186 {
187 lock (m_sentTerrainPackets)
188 {
189 for (int y = 0; y < 16; y++)
190 {
191 for (int x = 0; x < 16; x++)
192 {
193 if (m_sentTerrainPackets[x, y] != null)
194 {
195 if (m_sentTerrainPackets[x, y].SeqNumber == sequence)
196 {
197 m_sentTerrainPackets[x, y] = null;
198 return;
199 }
200 }
201 }
202 }
203 }
204 }
205
206 protected void PrimPacketAcked(uint sequence)
207 {
208 lock (m_sendPrimPackets)
209 {
210 foreach (PrimPacketTracker tracker in m_sendPrimPackets.Values)
211 {
212 if (tracker.SeqNumber == sequence)
213 {
214 tracker.Acked = true;
215 break;
216 }
217 }
218 }
219 }
220
221 public void Process()
222 {
223 List<uint> ackedPackets = null;
224 lock (m_beenAcked)
225 {
226 ackedPackets = new List<uint>(m_beenAcked);
227 m_beenAcked.Clear();
228 }
229
230 if (ackedPackets != null)
231 {
232 foreach (uint packetId in ackedPackets)
233 {
234 if (OnPacketAcked != null)
235 {
236 OnPacketAcked(packetId);
237 }
238 }
239 }
240
241 // ackedPackets.Clear();
242 ackedPackets = null;
243 }
244
245 public class TerrainPacketTracker
246 {
247 public uint SeqNumber = 0;
248 public int X;
249 public int Y;
250 public DateTime TimeSent;
251 public LayerDataPacket Packet;
252 public bool KeepResending;
253 }
254
255 public class PrimPacketTracker
256 {
257 public uint SeqNumber = 0;
258 public DateTime TimeSent;
259 public LLUUID PrimID;
260 public bool Acked = false;
261 }
262 }
263}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs b/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs
index 2b6e781..e836dd7 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using libsecondlife.Packets; 29using libsecondlife.Packets;
29using OpenSim.Framework; 30using OpenSim.Framework;
30 31
@@ -39,5 +40,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
39 public Packet Packet; 40 public Packet Packet;
40 public bool Incoming; 41 public bool Incoming;
41 public ThrottleOutPacketType throttleType; 42 public ThrottleOutPacketType throttleType;
43 public Object Identifier;
42 } 44 }
43} \ No newline at end of file 45}