aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs875
1 files changed, 0 insertions, 875 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs
deleted file mode 100644
index f30df4d..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs
+++ /dev/null
@@ -1,875 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Net.Sockets;
32using System.Threading;
33using System.Timers;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using log4net;
37using OpenSim.Framework;
38using Timer=System.Timers.Timer;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
43 public delegate void PacketDrop(Packet pack, Object id);
44 public delegate void QueueEmpty(ThrottleOutPacketType queue);
45 public delegate bool SynchronizeClientHandler(IScene scene, Packet packet, UUID agentID, ThrottleOutPacketType throttlePacketType);
46
47 public class LLPacketHandler
48 {
49 private static readonly ILog m_log
50 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 //private int m_resentCount;
53
54 // Packet queues
55 //
56 LLPacketQueue m_PacketQueue;
57
58 public LLPacketQueue PacketQueue
59 {
60 get { return m_PacketQueue; }
61 }
62
63 // Timer to run stats and acks on
64 //
65 private Timer m_AckTimer = new Timer(250);
66
67 // A list of the packets we haven't acked yet
68 //
69 private List<uint> m_PendingAcks = new List<uint>();
70 private Dictionary<uint, uint> m_PendingAcksMap = new Dictionary<uint, uint>();
71
72 private Dictionary<uint, LLQueItem> m_NeedAck =
73 new Dictionary<uint, LLQueItem>();
74
75 /// <summary>
76 /// The number of milliseconds that can pass before a packet that needs an ack is resent.
77 /// </param>
78 private uint m_ResendTimeout = 4000;
79
80 public uint ResendTimeout
81 {
82 get { return m_ResendTimeout; }
83 set { m_ResendTimeout = value; }
84 }
85
86 private int m_MaxReliableResends = 3;
87
88 public int MaxReliableResends
89 {
90 get { return m_MaxReliableResends; }
91 set { m_MaxReliableResends = value; }
92 }
93
94 // Track duplicated packets. This uses a Dictionary. Both insertion
95 // and lookup are common operations and need to take advantage of
96 // the hashing. Expiration is less common and can be allowed the
97 // time for a linear scan.
98 //
99 private List<uint> m_alreadySeenList = new List<uint>();
100 private Dictionary<uint, int>m_alreadySeenTracker = new Dictionary<uint, int>();
101 private int m_alreadySeenWindow = 30000;
102 private int m_lastAlreadySeenCheck = Environment.TickCount & Int32.MaxValue;
103
104 // private Dictionary<uint, int> m_DupeTracker =
105 // new Dictionary<uint, int>();
106 // private uint m_DupeTrackerWindow = 30;
107 // private int m_DupeTrackerLastCheck = Environment.TickCount;
108
109 // Values for the SimStatsReporter
110 //
111 private int m_PacketsReceived = 0;
112 private int m_PacketsReceivedReported = 0;
113 private int m_PacketsSent = 0;
114 private int m_PacketsSentReported = 0;
115 private int m_UnackedBytes = 0;
116
117 private int m_LastResend = 0;
118
119 public int PacketsReceived
120 {
121 get { return m_PacketsReceived; }
122 }
123
124 public int PacketsReceivedReported
125 {
126 get { return m_PacketsReceivedReported; }
127 }
128
129 // The client we are working for
130 //
131 private IClientAPI m_Client;
132
133 // Some events
134 //
135 public event PacketStats OnPacketStats;
136 public event PacketDrop OnPacketDrop;
137 public event QueueEmpty OnQueueEmpty;
138
139
140 //private SynchronizeClientHandler m_SynchronizeClient = null;
141
142 public SynchronizeClientHandler SynchronizeClient
143 {
144 set { /* m_SynchronizeClient = value; */ }
145 }
146
147 // Packet sequencing
148 //
149 private uint m_Sequence = 0;
150 private object m_SequenceLock = new object();
151 private const int MAX_SEQUENCE = 0xFFFFFF;
152
153 // Packet dropping
154 //
155 List<PacketType> m_ImportantPackets = new List<PacketType>();
156 private bool m_ReliableIsImportant = false;
157
158 public bool ReliableIsImportant
159 {
160 get { return m_ReliableIsImportant; }
161 set { m_ReliableIsImportant = value; }
162 }
163
164 private int m_DropSafeTimeout;
165
166 LLPacketServer m_PacketServer;
167 private byte[] m_ZeroOutBuffer = new byte[4096];
168
169 ////////////////////////////////////////////////////////////////////
170
171 // Constructors
172 //
173 public LLPacketHandler(IClientAPI client, LLPacketServer server, ClientStackUserSettings userSettings)
174 {
175 m_Client = client;
176 m_PacketServer = server;
177 m_DropSafeTimeout = Environment.TickCount + 15000;
178
179 m_PacketQueue = new LLPacketQueue(client.AgentId, userSettings);
180
181 m_PacketQueue.OnQueueEmpty += TriggerOnQueueEmpty;
182
183 m_AckTimer.Elapsed += AckTimerElapsed;
184 m_AckTimer.Start();
185 }
186
187 public void Dispose()
188 {
189 m_AckTimer.Stop();
190 m_AckTimer.Close();
191
192 m_PacketQueue.Enqueue(null);
193 m_PacketQueue.Close();
194 m_Client = null;
195 }
196
197 // Send one packet. This actually doesn't send anything, it queues
198 // it. Designed to be fire-and-forget, but there is an optional
199 // notifier.
200 //
201 public void OutPacket(
202 Packet packet, ThrottleOutPacketType throttlePacketType)
203 {
204 OutPacket(packet, throttlePacketType, null);
205 }
206
207 public void OutPacket(
208 Packet packet, ThrottleOutPacketType throttlePacketType,
209 Object id)
210 {
211 // Call the load balancer's hook. If this is not active here
212 // we defer to the sim server this client is actually connected
213 // to. Packet drop notifies will not be triggered in this
214 // configuration!
215 //
216
217 packet.Header.Sequence = 0;
218
219 lock (m_NeedAck)
220 {
221 DropResend(id);
222
223 AddAcks(ref packet);
224 QueuePacket(packet, throttlePacketType, id);
225 }
226 }
227
228 private void AddAcks(ref Packet packet)
229 {
230 // These packet types have shown to have issues with
231 // acks being appended to the payload, just don't send
232 // any with them until libsl is fixed.
233 //
234 if (packet is ViewerEffectPacket)
235 return;
236 if (packet is SimStatsPacket)
237 return;
238
239 // Add acks to outgoing packets
240 //
241 if (m_PendingAcks.Count > 0)
242 {
243 int count = m_PendingAcks.Count;
244 if (count > 10)
245 count = 10;
246 packet.Header.AckList = new uint[count];
247 packet.Header.AppendedAcks = true;
248
249 for (int i = 0; i < count; i++)
250 {
251 packet.Header.AckList[i] = m_PendingAcks[i];
252 m_PendingAcksMap.Remove(m_PendingAcks[i]);
253 }
254 m_PendingAcks.RemoveRange(0, count);
255 }
256 }
257
258 private void QueuePacket(
259 Packet packet, ThrottleOutPacketType throttlePacketType,
260 Object id)
261 {
262 LLQueItem item = new LLQueItem();
263 item.Packet = packet;
264 item.Incoming = false;
265 item.throttleType = throttlePacketType;
266 item.TickCount = Environment.TickCount;
267 item.Identifier = id;
268 item.Resends = 0;
269 item.Length = packet.Length;
270 item.Sequence = packet.Header.Sequence;
271
272 m_PacketQueue.Enqueue(item);
273 m_PacketsSent++;
274 }
275
276 private void ResendUnacked()
277 {
278 int now = Environment.TickCount;
279
280 int intervalMs = 250;
281
282 if (m_LastResend != 0)
283 intervalMs = now - m_LastResend;
284
285 lock (m_NeedAck)
286 {
287 if (m_DropSafeTimeout > now ||
288 intervalMs > 500) // We were frozen!
289 {
290 foreach (LLQueItem data in m_NeedAck.Values)
291 {
292 if (m_DropSafeTimeout > now)
293 {
294 m_NeedAck[data.Packet.Header.Sequence].TickCount = now;
295 }
296 else
297 {
298 m_NeedAck[data.Packet.Header.Sequence].TickCount += intervalMs;
299 }
300 }
301 }
302
303 m_LastResend = now;
304
305 // Unless we have received at least one ack, don't bother resending
306 // anything. There may not be a client there, don't clog up the
307 // pipes.
308
309
310 // Nothing to do
311 //
312 if (m_NeedAck.Count == 0)
313 return;
314
315 int resent = 0;
316 long dueDate = now - m_ResendTimeout;
317
318 List<LLQueItem> dropped = new List<LLQueItem>();
319 foreach (LLQueItem data in m_NeedAck.Values)
320 {
321 Packet packet = data.Packet;
322
323 // Packets this old get resent
324 //
325 if (data.TickCount < dueDate && data.Sequence != 0 && !m_PacketQueue.Contains(data.Sequence))
326 {
327 if (resent < 20) // Was 20 (= Max 117kbit/sec resends)
328 {
329 m_NeedAck[packet.Header.Sequence].Resends++;
330
331 // The client needs to be told that a packet is being resent, otherwise it appears to believe
332 // that it should reset its sequence to that packet number.
333 packet.Header.Resent = true;
334
335 if ((m_NeedAck[packet.Header.Sequence].Resends >= m_MaxReliableResends) &&
336 (!m_ReliableIsImportant))
337 {
338 dropped.Add(data);
339 continue;
340 }
341
342 m_NeedAck[packet.Header.Sequence].TickCount = Environment.TickCount;
343 QueuePacket(packet, ThrottleOutPacketType.Resend, data.Identifier);
344 resent++;
345 }
346 else
347 {
348 m_NeedAck[packet.Header.Sequence].TickCount += intervalMs;
349 }
350 }
351 }
352
353 foreach (LLQueItem data in dropped)
354 {
355 m_NeedAck.Remove(data.Packet.Header.Sequence);
356 TriggerOnPacketDrop(data.Packet, data.Identifier);
357 m_PacketQueue.Cancel(data.Packet.Header.Sequence);
358 PacketPool.Instance.ReturnPacket(data.Packet);
359 }
360 }
361 }
362
363 // Send the pending packet acks to the client
364 // Will send blocks of acks for up to 250 packets
365 //
366 private void SendAcks()
367 {
368 lock (m_NeedAck)
369 {
370 if (m_PendingAcks.Count == 0)
371 return;
372
373 PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
374
375 // The case of equality is more common than one might think,
376 // because this function will be called unconditionally when
377 // the counter reaches 250. So there is a good chance another
378 // packet with 250 blocks exists.
379 //
380 if (acks.Packets == null ||
381 acks.Packets.Length != m_PendingAcks.Count)
382 acks.Packets = new PacketAckPacket.PacketsBlock[m_PendingAcks.Count];
383
384 for (int i = 0; i < m_PendingAcks.Count; i++)
385 {
386 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
387 acks.Packets[i].ID = m_PendingAcks[i];
388
389 }
390 m_PendingAcks.Clear();
391 m_PendingAcksMap.Clear();
392
393 acks.Header.Reliable = false;
394 OutPacket(acks, ThrottleOutPacketType.Unknown);
395 }
396 }
397
398 // Queue a packet ack. It will be sent either after 250 acks are
399 // queued, or when the timer fires.
400 //
401 private void AckPacket(Packet packet)
402 {
403 lock (m_NeedAck)
404 {
405 if (m_PendingAcks.Count < 250)
406 {
407 if (!m_PendingAcksMap.ContainsKey(packet.Header.Sequence))
408 {
409 m_PendingAcks.Add(packet.Header.Sequence);
410 m_PendingAcksMap.Add(packet.Header.Sequence,
411 packet.Header.Sequence);
412 }
413 return;
414 }
415 }
416
417 SendAcks();
418
419 lock (m_NeedAck)
420 {
421 // If this is still full we have a truly exceptional
422 // condition (means, can't happen)
423 //
424 if (m_PendingAcks.Count < 250)
425 {
426 if (!m_PendingAcksMap.ContainsKey(packet.Header.Sequence))
427 {
428 m_PendingAcks.Add(packet.Header.Sequence);
429 m_PendingAcksMap.Add(packet.Header.Sequence,
430 packet.Header.Sequence);
431 }
432 return;
433 }
434 }
435 }
436
437 // When the timer elapses, send the pending acks, trigger resends
438 // and report all the stats.
439 //
440 private void AckTimerElapsed(object sender, ElapsedEventArgs ea)
441 {
442 SendAcks();
443 ResendUnacked();
444 SendPacketStats();
445 }
446
447 // Push out pachet counts for the sim status reporter
448 //
449 private void SendPacketStats()
450 {
451 PacketStats handlerPacketStats = OnPacketStats;
452 if (handlerPacketStats != null)
453 {
454 handlerPacketStats(
455 m_PacketsReceived - m_PacketsReceivedReported,
456 m_PacketsSent - m_PacketsSentReported,
457 m_UnackedBytes);
458
459 m_PacketsReceivedReported = m_PacketsReceived;
460 m_PacketsSentReported = m_PacketsSent;
461 }
462 }
463
464 // We can't keep an unlimited record of dupes. This will prune the
465 // dictionary by age.
466 //
467 // NOTE: this needs to be called from within lock
468 // (m_alreadySeenTracker) context!
469 private void ExpireSeenPackets()
470 {
471 if (m_alreadySeenList.Count < 1024)
472 return;
473
474 int ticks = 0;
475 int tc = Environment.TickCount & Int32.MaxValue;
476 if (tc >= m_lastAlreadySeenCheck)
477 ticks = tc - m_lastAlreadySeenCheck;
478 else
479 ticks = Int32.MaxValue - m_lastAlreadySeenCheck + tc;
480
481 if (ticks < 2000) return;
482 m_lastAlreadySeenCheck = tc;
483
484 // we calculate the drop dead tick count here instead of
485 // in the loop: any packet with a timestamp before
486 // dropDeadTC can be expired
487 int dropDeadTC = tc - m_alreadySeenWindow;
488 int i = 0;
489 while (i < m_alreadySeenList.Count && m_alreadySeenTracker[m_alreadySeenList[i]] < dropDeadTC)
490 {
491 m_alreadySeenTracker.Remove(m_alreadySeenList[i]);
492 i++;
493 }
494 // if we dropped packet from m_alreadySeenTracker we need
495 // to drop them from m_alreadySeenList as well, let's do
496 // that in one go: the list is ordered after all.
497 if (i > 0)
498 {
499 m_alreadySeenList.RemoveRange(0, i);
500 // m_log.DebugFormat("[CLIENT]: expired {0} packets, {1}:{2} left", i, m_alreadySeenList.Count, m_alreadySeenTracker.Count);
501 }
502 }
503
504 public void InPacket(Packet packet)
505 {
506 if (packet == null)
507 return;
508
509 // When too many acks are needed to be sent, the client sends
510 // a packet consisting of acks only
511 //
512 if (packet.Type == PacketType.PacketAck)
513 {
514 PacketAckPacket ackPacket = (PacketAckPacket)packet;
515
516 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
517 {
518 ProcessAck(block.ID);
519 }
520
521 PacketPool.Instance.ReturnPacket(packet);
522 return;
523 }
524
525 // Any packet can have some packet acks in the header.
526 // Process them here
527 //
528 if (packet.Header.AppendedAcks)
529 {
530 foreach (uint id in packet.Header.AckList)
531 {
532 ProcessAck(id);
533 }
534 }
535
536 // If this client is on another partial instance, no need
537 // to handle packets
538 //
539 if (!m_Client.IsActive && packet.Type != PacketType.LogoutRequest)
540 {
541 PacketPool.Instance.ReturnPacket(packet);
542 return;
543 }
544
545 if (packet.Type == PacketType.StartPingCheck)
546 {
547 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
548 CompletePingCheckPacket endPing
549 = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
550
551 endPing.PingID.PingID = startPing.PingID.PingID;
552 OutPacket(endPing, ThrottleOutPacketType.Task);
553 }
554 else
555 {
556 LLQueItem item = new LLQueItem();
557 item.Packet = packet;
558 item.Incoming = true;
559 m_PacketQueue.Enqueue(item);
560 }
561 }
562
563 public void ProcessInPacket(LLQueItem item)
564 {
565 Packet packet = item.Packet;
566
567 // Always ack the packet!
568 //
569 if (packet.Header.Reliable)
570 AckPacket(packet);
571
572 if (packet.Type != PacketType.AgentUpdate)
573 m_PacketsReceived++;
574
575 // Check for duplicate packets.. packets that the client is
576 // resending because it didn't receive our ack
577 //
578 lock (m_alreadySeenTracker)
579 {
580 ExpireSeenPackets();
581
582 if (m_alreadySeenTracker.ContainsKey(packet.Header.Sequence))
583 return;
584
585 m_alreadySeenTracker.Add(packet.Header.Sequence, Environment.TickCount & Int32.MaxValue);
586 m_alreadySeenList.Add(packet.Header.Sequence);
587 }
588
589 m_Client.ProcessInPacket(packet);
590 }
591
592 public void Flush()
593 {
594 m_PacketQueue.Flush();
595 m_UnackedBytes = (-1 * m_UnackedBytes);
596 SendPacketStats();
597 }
598
599 public void Clear()
600 {
601 m_UnackedBytes = (-1 * m_UnackedBytes);
602 SendPacketStats();
603 lock (m_NeedAck)
604 {
605 m_NeedAck.Clear();
606 m_PendingAcks.Clear();
607 m_PendingAcksMap.Clear();
608 }
609 m_Sequence += 1000000;
610 }
611
612 private void ProcessAck(uint id)
613 {
614 LLQueItem data;
615
616 lock (m_NeedAck)
617 {
618 //m_log.DebugFormat("[CLIENT]: In {0} received ack for packet {1}", m_Client.Scene.RegionInfo.ExternalEndPoint.Port, id);
619
620 if (!m_NeedAck.TryGetValue(id, out data))
621 return;
622
623 m_NeedAck.Remove(id);
624 m_PacketQueue.Cancel(data.Sequence);
625 PacketPool.Instance.ReturnPacket(data.Packet);
626 m_UnackedBytes -= data.Length;
627 }
628 }
629
630 // Allocate packet sequence numbers in a threadsave manner
631 //
632 protected uint NextPacketSequenceNumber()
633 {
634 // Set the sequence number
635 uint seq = 1;
636 lock (m_SequenceLock)
637 {
638 if (m_Sequence >= MAX_SEQUENCE)
639 {
640 m_Sequence = 1;
641 }
642 else
643 {
644 m_Sequence++;
645 }
646 seq = m_Sequence;
647 }
648 return seq;
649 }
650
651 public ClientInfo GetClientInfo()
652 {
653 ClientInfo info = new ClientInfo();
654
655 info.pendingAcks = m_PendingAcksMap;
656 info.needAck = new Dictionary<uint, byte[]>();
657
658 lock (m_NeedAck)
659 {
660 foreach (uint key in m_NeedAck.Keys)
661 info.needAck.Add(key, m_NeedAck[key].Packet.ToBytes());
662 }
663
664 LLQueItem[] queitems = m_PacketQueue.GetQueueArray();
665
666 for (int i = 0; i < queitems.Length; i++)
667 {
668 if (queitems[i].Incoming == false)
669 info.out_packets.Add(queitems[i].Packet.ToBytes());
670 }
671
672 info.sequence = m_Sequence;
673
674 float multiplier = m_PacketQueue.ThrottleMultiplier;
675 info.resendThrottle = (int) (m_PacketQueue.ResendThrottle.Throttle / multiplier);
676 info.landThrottle = (int) (m_PacketQueue.LandThrottle.Throttle / multiplier);
677 info.windThrottle = (int) (m_PacketQueue.WindThrottle.Throttle / multiplier);
678 info.cloudThrottle = (int) (m_PacketQueue.CloudThrottle.Throttle / multiplier);
679 info.taskThrottle = (int) (m_PacketQueue.TaskThrottle.Throttle / multiplier);
680 info.assetThrottle = (int) (m_PacketQueue.AssetThrottle.Throttle / multiplier);
681 info.textureThrottle = (int) (m_PacketQueue.TextureThrottle.Throttle / multiplier);
682 info.totalThrottle = (int) (m_PacketQueue.TotalThrottle.Throttle / multiplier);
683
684 return info;
685 }
686
687 public void SetClientInfo(ClientInfo info)
688 {
689 m_PendingAcksMap = info.pendingAcks;
690 m_PendingAcks = new List<uint>(m_PendingAcksMap.Keys);
691 m_NeedAck = new Dictionary<uint, LLQueItem>();
692
693 Packet packet = null;
694 int packetEnd = 0;
695 byte[] zero = new byte[3000];
696
697 foreach (uint key in info.needAck.Keys)
698 {
699 byte[] buff = info.needAck[key];
700 packetEnd = buff.Length - 1;
701
702 try
703 {
704 packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
705 }
706 catch (Exception)
707 {
708 }
709
710 LLQueItem item = new LLQueItem();
711 item.Packet = packet;
712 item.Incoming = false;
713 item.throttleType = 0;
714 item.TickCount = Environment.TickCount;
715 item.Identifier = 0;
716 item.Resends = 0;
717 item.Length = packet.Length;
718 item.Sequence = packet.Header.Sequence;
719 m_NeedAck.Add(key, item);
720 }
721
722 m_Sequence = info.sequence;
723
724 m_PacketQueue.ResendThrottle.Throttle = info.resendThrottle;
725 m_PacketQueue.LandThrottle.Throttle = info.landThrottle;
726 m_PacketQueue.WindThrottle.Throttle = info.windThrottle;
727 m_PacketQueue.CloudThrottle.Throttle = info.cloudThrottle;
728 m_PacketQueue.TaskThrottle.Throttle = info.taskThrottle;
729 m_PacketQueue.AssetThrottle.Throttle = info.assetThrottle;
730 m_PacketQueue.TextureThrottle.Throttle = info.textureThrottle;
731 m_PacketQueue.TotalThrottle.Throttle = info.totalThrottle;
732 }
733
734 public void AddImportantPacket(PacketType type)
735 {
736 if (m_ImportantPackets.Contains(type))
737 return;
738
739 m_ImportantPackets.Add(type);
740 }
741
742 public void RemoveImportantPacket(PacketType type)
743 {
744 if (!m_ImportantPackets.Contains(type))
745 return;
746
747 m_ImportantPackets.Remove(type);
748 }
749
750 private void DropResend(Object id)
751 {
752 LLQueItem d = null;
753
754 foreach (LLQueItem data in m_NeedAck.Values)
755 {
756 if (data.Identifier != null && data.Identifier == id)
757 {
758 d = data;
759 break;
760 }
761 }
762
763 if (null == d) return;
764
765 m_NeedAck.Remove(d.Packet.Header.Sequence);
766 m_PacketQueue.Cancel(d.Sequence);
767 PacketPool.Instance.ReturnPacket(d.Packet);
768 }
769
770 private void TriggerOnPacketDrop(Packet packet, Object id)
771 {
772 PacketDrop handlerPacketDrop = OnPacketDrop;
773
774 if (handlerPacketDrop == null)
775 return;
776
777 handlerPacketDrop(packet, id);
778 }
779
780 private void TriggerOnQueueEmpty(ThrottleOutPacketType queue)
781 {
782 QueueEmpty handlerQueueEmpty = OnQueueEmpty;
783
784 if (handlerQueueEmpty != null)
785 handlerQueueEmpty(queue);
786 }
787
788 // Convert the packet to bytes and stuff it onto the send queue
789 //
790 public void ProcessOutPacket(LLQueItem item)
791 {
792 Packet packet = item.Packet;
793
794 // Assign sequence number here to prevent out of order packets
795 if (packet.Header.Sequence == 0)
796 {
797 lock (m_NeedAck)
798 {
799 packet.Header.Sequence = NextPacketSequenceNumber();
800 item.Sequence = packet.Header.Sequence;
801 item.TickCount = Environment.TickCount;
802
803 // We want to see that packet arrive if it's reliable
804 if (packet.Header.Reliable)
805 {
806 m_UnackedBytes += item.Length;
807
808 // Keep track of when this packet was sent out
809 item.TickCount = Environment.TickCount;
810
811 m_NeedAck[packet.Header.Sequence] = item;
812 }
813 }
814 }
815
816 // If we sent a killpacket
817 if (packet is KillPacket)
818 Abort();
819
820 try
821 {
822 // If this packet has been reused/returned, the ToBytes
823 // will blow up in our face.
824 // Fail gracefully.
825 //
826
827 // Actually make the byte array and send it
828 byte[] sendbuffer = item.Packet.ToBytes();
829
830 if (packet.Header.Zerocoded)
831 {
832 int packetsize = Helpers.ZeroEncode(sendbuffer,
833 sendbuffer.Length, m_ZeroOutBuffer);
834 m_PacketServer.SendPacketTo(m_ZeroOutBuffer, packetsize,
835 SocketFlags.None, m_Client.CircuitCode);
836 }
837 else
838 {
839 // Need some extra space in case we need to add proxy
840 // information to the message later
841 Buffer.BlockCopy(sendbuffer, 0, m_ZeroOutBuffer, 0,
842 sendbuffer.Length);
843 m_PacketServer.SendPacketTo(m_ZeroOutBuffer,
844 sendbuffer.Length, SocketFlags.None, m_Client.CircuitCode);
845 }
846 }
847 catch (NullReferenceException)
848 {
849 m_log.Error("[PACKET]: Detected reuse of a returned packet");
850 m_PacketQueue.Cancel(item.Sequence);
851 return;
852 }
853
854 // If this is a reliable packet, we are still holding a ref
855 // Dont't return in that case
856 //
857 if (!packet.Header.Reliable)
858 {
859 m_PacketQueue.Cancel(item.Sequence);
860 PacketPool.Instance.ReturnPacket(packet);
861 }
862 }
863
864 private void Abort()
865 {
866 m_PacketQueue.Close();
867 Thread.CurrentThread.Abort();
868 }
869
870 public int GetQueueCount(ThrottleOutPacketType queue)
871 {
872 return m_PacketQueue.GetQueueCount(queue);
873 }
874 }
875}