diff options
Diffstat (limited to '')
10 files changed, 811 insertions, 823 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 | } |
diff --git a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs index 574bc63..72520c4 100644 --- a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs | |||
@@ -51,6 +51,11 @@ namespace OpenSim.Region.Environment.Modules.World.NPC | |||
51 | m_scene = scene; | 51 | m_scene = scene; |
52 | } | 52 | } |
53 | 53 | ||
54 | public IScene Scene | ||
55 | { | ||
56 | get { return m_scene; } | ||
57 | } | ||
58 | |||
54 | public void Say(string message) | 59 | public void Say(string message) |
55 | { | 60 | { |
56 | SendOnChatFromViewer(message, ChatTypeEnum.Say); | 61 | SendOnChatFromViewer(message, ChatTypeEnum.Say); |
@@ -259,7 +264,6 @@ namespace OpenSim.Region.Environment.Modules.World.NPC | |||
259 | public event FriendActionDelegate OnApproveFriendRequest; | 264 | public event FriendActionDelegate OnApproveFriendRequest; |
260 | public event FriendActionDelegate OnDenyFriendRequest; | 265 | public event FriendActionDelegate OnDenyFriendRequest; |
261 | public event FriendshipTermination OnTerminateFriendship; | 266 | public event FriendshipTermination OnTerminateFriendship; |
262 | public event PacketStats OnPacketStats; | ||
263 | 267 | ||
264 | public event EconomyDataRequest OnEconomyDataRequest; | 268 | public event EconomyDataRequest OnEconomyDataRequest; |
265 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | 269 | public event MoneyBalanceRequest OnMoneyBalanceRequest; |
@@ -518,7 +522,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC | |||
518 | LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags, | 522 | LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags, |
519 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, | 523 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, |
520 | uint parentID, | 524 | uint parentID, |
521 | byte[] particleSystem, byte clickAction, bool track) | 525 | byte[] particleSystem, byte clickAction) |
522 | { | 526 | { |
523 | } | 527 | } |
524 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 528 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, |
@@ -527,7 +531,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC | |||
527 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, | 531 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, |
528 | uint parentID, | 532 | uint parentID, |
529 | byte[] particleSystem, byte clickAction, byte[] textureanimation, | 533 | byte[] particleSystem, byte clickAction, byte[] textureanimation, |
530 | bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius, bool track) | 534 | bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) |
531 | { | 535 | { |
532 | } | 536 | } |
533 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | 537 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, |
@@ -711,6 +715,10 @@ namespace OpenSim.Region.Environment.Modules.World.NPC | |||
711 | { | 715 | { |
712 | } | 716 | } |
713 | 717 | ||
718 | public void ProcessInPacket(Packet NewPack) | ||
719 | { | ||
720 | } | ||
721 | |||
714 | public void Close(bool ShutdownCircuit) | 722 | public void Close(bool ShutdownCircuit) |
715 | { | 723 | { |
716 | } | 724 | } |
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 626aaaa..6bf552c 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -2088,7 +2088,6 @@ namespace OpenSim.Region.Environment.Scenes | |||
2088 | client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; | 2088 | client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; |
2089 | client.OnParcelBuy += ProcessParcelBuy; | 2089 | client.OnParcelBuy += ProcessParcelBuy; |
2090 | client.OnAvatarPickerRequest += ProcessAvatarPickerRequest; | 2090 | client.OnAvatarPickerRequest += ProcessAvatarPickerRequest; |
2091 | client.OnPacketStats += AddPacketStats; | ||
2092 | client.OnObjectIncludeInSearch += m_innerScene.MakeObjectSearchable; | 2091 | client.OnObjectIncludeInSearch += m_innerScene.MakeObjectSearchable; |
2093 | client.OnTeleportHomeRequest += TeleportClientHome; | 2092 | client.OnTeleportHomeRequest += TeleportClientHome; |
2094 | client.OnSetStartLocationRequest += SetHomeRezPoint; | 2093 | client.OnSetStartLocationRequest += SetHomeRezPoint; |
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 253a83e..156310b 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs | |||
@@ -2085,7 +2085,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
2085 | remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, | 2085 | remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, |
2086 | lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, | 2086 | lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, |
2087 | m_text, color, _parentID, m_particleSystem, m_clickAction, m_TextureAnimation, m_IsAttachment, | 2087 | m_text, color, _parentID, m_particleSystem, m_clickAction, m_TextureAnimation, m_IsAttachment, |
2088 | m_attachmentPoint,fromAssetID, Sound, SoundGain, SoundFlags, SoundRadius, false); | 2088 | m_attachmentPoint,fromAssetID, Sound, SoundGain, SoundFlags, SoundRadius); |
2089 | } | 2089 | } |
2090 | 2090 | ||
2091 | /// <summary> | 2091 | /// <summary> |
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index c975df5..bc675ff 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs | |||
@@ -42,6 +42,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
42 | private LLQuaternion bodyDirection = LLQuaternion.Identity; | 42 | private LLQuaternion bodyDirection = LLQuaternion.Identity; |
43 | private short count = 0; | 43 | private short count = 0; |
44 | private short frame = 0; | 44 | private short frame = 0; |
45 | private Scene m_scene; | ||
45 | 46 | ||
46 | // disable warning: public events, part of the public API | 47 | // disable warning: public events, part of the public API |
47 | #pragma warning disable 67 | 48 | #pragma warning disable 67 |
@@ -165,7 +166,6 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
165 | public event FriendActionDelegate OnApproveFriendRequest; | 166 | public event FriendActionDelegate OnApproveFriendRequest; |
166 | public event FriendActionDelegate OnDenyFriendRequest; | 167 | public event FriendActionDelegate OnDenyFriendRequest; |
167 | public event FriendshipTermination OnTerminateFriendship; | 168 | public event FriendshipTermination OnTerminateFriendship; |
168 | public event PacketStats OnPacketStats; | ||
169 | 169 | ||
170 | public event EconomyDataRequest OnEconomyDataRequest; | 170 | public event EconomyDataRequest OnEconomyDataRequest; |
171 | public event MoneyBalanceRequest OnMoneyBalanceRequest; | 171 | public event MoneyBalanceRequest OnMoneyBalanceRequest; |
@@ -208,10 +208,12 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
208 | 208 | ||
209 | private LLUUID myID = LLUUID.Random(); | 209 | private LLUUID myID = LLUUID.Random(); |
210 | 210 | ||
211 | public MyNpcCharacter(EventManager eventManager) | 211 | public MyNpcCharacter(Scene scene) |
212 | { | 212 | { |
213 | |||
213 | // startPos = new LLVector3(128, (float)(Util.RandomClass.NextDouble()*100), 2); | 214 | // startPos = new LLVector3(128, (float)(Util.RandomClass.NextDouble()*100), 2); |
214 | eventManager.OnFrame += Update; | 215 | m_scene = scene; |
216 | m_scene.EventManager.OnFrame += Update; | ||
215 | } | 217 | } |
216 | 218 | ||
217 | private LLVector3 startPos = new LLVector3(128, 128, 2); | 219 | private LLVector3 startPos = new LLVector3(128, 128, 2); |
@@ -280,6 +282,11 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
280 | get { return 1; } | 282 | get { return 1; } |
281 | } | 283 | } |
282 | 284 | ||
285 | public IScene Scene | ||
286 | { | ||
287 | get { return m_scene; } | ||
288 | } | ||
289 | |||
283 | public virtual void OutPacket(Packet newPack, ThrottleOutPacketType packType) | 290 | public virtual void OutPacket(Packet newPack, ThrottleOutPacketType packType) |
284 | { | 291 | { |
285 | } | 292 | } |
@@ -432,7 +439,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
432 | LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags, | 439 | LLVector3 acc, LLQuaternion rotation, LLVector3 rvel, uint flags, |
433 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, | 440 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, |
434 | uint parentID, | 441 | uint parentID, |
435 | byte[] particleSystem, byte clickAction, bool track) | 442 | byte[] particleSystem, byte clickAction) |
436 | { | 443 | { |
437 | } | 444 | } |
438 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, | 445 | public virtual void SendPrimitiveToClient(ulong regionHandle, ushort timeDilation, uint localID, |
@@ -441,7 +448,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
441 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, | 448 | LLUUID objectID, LLUUID ownerID, string text, byte[] color, |
442 | uint parentID, | 449 | uint parentID, |
443 | byte[] particleSystem, byte clickAction, byte[] textureanimation, | 450 | byte[] particleSystem, byte clickAction, byte[] textureanimation, |
444 | bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius, bool track) | 451 | bool attachment, uint AttachmentPoint, LLUUID AssetId, LLUUID SoundId, double SoundVolume, byte SoundFlags, double SoundRadius) |
445 | { | 452 | { |
446 | } | 453 | } |
447 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, | 454 | public virtual void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, |
@@ -700,6 +707,10 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
700 | { | 707 | { |
701 | } | 708 | } |
702 | 709 | ||
710 | public void ProcessInPacket(Packet NewPack) | ||
711 | { | ||
712 | } | ||
713 | |||
703 | public void Close(bool ShutdownCircuit) | 714 | public void Close(bool ShutdownCircuit) |
704 | { | 715 | { |
705 | } | 716 | } |
diff --git a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs b/OpenSim/Region/Examples/SimpleModule/RegionModule.cs index 46b7efd..441c696 100644 --- a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs +++ b/OpenSim/Region/Examples/SimpleModule/RegionModule.cs | |||
@@ -84,7 +84,7 @@ namespace OpenSim.Region.Examples.SimpleModule | |||
84 | { | 84 | { |
85 | for (int i = 0; i < 1; i++) | 85 | for (int i = 0; i < 1; i++) |
86 | { | 86 | { |
87 | MyNpcCharacter m_character = new MyNpcCharacter(m_scene.EventManager); | 87 | MyNpcCharacter m_character = new MyNpcCharacter(m_scene); |
88 | m_scene.AddNewClient(m_character, false); | 88 | m_scene.AddNewClient(m_character, false); |
89 | } | 89 | } |
90 | 90 | ||