diff options
author | Melanie Thielker | 2008-07-22 17:58:42 +0000 |
---|---|---|
committer | Melanie Thielker | 2008-07-22 17:58:42 +0000 |
commit | f112cebde2c1bc06108839acac82bc8addd7c506 (patch) | |
tree | 7f1e7fabf2fec74171d5982f09d847b47e20d7ca /OpenSim/Region/ClientStack/LindenUDP | |
parent | * refactor: move new inventory service call by user server to OGS1 with all t... (diff) | |
download | opensim-SC_OLD-f112cebde2c1bc06108839acac82bc8addd7c506.zip opensim-SC_OLD-f112cebde2c1bc06108839acac82bc8addd7c506.tar.gz opensim-SC_OLD-f112cebde2c1bc06108839acac82bc8addd7c506.tar.bz2 opensim-SC_OLD-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/LindenUDP')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 567 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs | 692 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | 68 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketTracker.cs | 263 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLQueItem.cs | 4 |
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Net.Sockets; | ||
33 | using System.Timers; | ||
34 | using libsecondlife; | ||
35 | using libsecondlife.Packets; | ||
36 | using Timer = System.Timers.Timer; | ||
37 | using OpenSim.Framework; | ||
38 | |||
39 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | using System.Threading; | ||
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | using OpenSim.Framework; | ||
8 | |||
9 | namespace 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 | ||
28 | using System; | ||
28 | using libsecondlife.Packets; | 29 | using libsecondlife.Packets; |
29 | using OpenSim.Framework; | 30 | using 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 | } |