aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs
diff options
context:
space:
mode:
authorMike Mazur2008-08-08 05:57:14 +0000
committerMike Mazur2008-08-08 05:57:14 +0000
commit1040f3f454a6f469dcd74f19c45ea67d0584ade1 (patch)
tree36076b1a16ae66f3451666856e3f52f875e7d8a8 /OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs
parentCommitting first draft of the universal cache. This is by no means (diff)
downloadopensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.zip
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.gz
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.bz2
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.xz
Remove FunSL client stack as it's under development and often won't compile.
This effectively undoes commits 5771 and 5769 as well as parts of the formatting cleanup commits 5774 and 5775.
Diffstat (limited to 'OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs')
-rw-r--r--OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs702
1 files changed, 0 insertions, 702 deletions
diff --git a/OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs b/OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs
deleted file mode 100644
index 342dd5c..0000000
--- a/OpenSim/Region/ClientStack/FunSLUDP/LLPacketHandler.cs
+++ /dev/null
@@ -1,702 +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 OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
32using System.Net.Sockets;
33using System.Timers;
34using libsecondlife;
35using libsecondlife.Packets;
36using Timer = System.Timers.Timer;
37using OpenSim.Framework;
38
39namespace OpenSim.Region.ClientStack.FunSLUDP
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 AddAcks(ref packet);
238 QueuePacket(packet, throttlePacketType, id);
239
240 // We want to see that packet arrive if it's reliable
241 if (packet.Header.Reliable)
242 {
243 m_UnackedBytes += packet.ToBytes().Length;
244 m_NeedAck[packet.Header.Sequence] = new AckData(packet, id);
245 }
246 }
247 }
248
249 private void AddAcks(ref Packet packet)
250 {
251 // This packet type has shown to have issues with
252 // acks being appended to the payload, just don't send
253 // any with this packet type until libsl is fixed.
254 //
255 if (packet is libsecondlife.Packets.ViewerEffectPacket)
256 return;
257
258 // Add acks to outgoing packets
259 //
260 if (m_PendingAcks.Count > 0)
261 {
262 int count = m_PendingAcks.Count;
263 if (count > 10)
264 count = 10;
265 packet.Header.AckList = new uint[count];
266 packet.Header.AppendedAcks = true;
267
268 int i = 0;
269
270 foreach (uint ack in new List<uint>(m_PendingAcks.Keys))
271 {
272 packet.Header.AckList[i] = ack;
273 i++;
274 m_PendingAcks.Remove(ack);
275 if (i >= count) // That is how much space there is
276 break;
277 }
278 }
279 }
280
281 private void QueuePacket(
282 Packet packet, ThrottleOutPacketType throttlePacketType,
283 Object id)
284 {
285 packet.TickCount = System.Environment.TickCount;
286
287 LLQueItem item = new LLQueItem();
288 item.Packet = packet;
289 item.Incoming = false;
290 item.throttleType = throttlePacketType;
291 item.Identifier = id;
292
293 m_PacketQueue.Enqueue(item);
294 m_PacketsSent++;
295 }
296
297 private void ResendUnacked()
298 {
299 int now = System.Environment.TickCount;
300 int lastAck = m_LastAck;
301
302 // Unless we have received at least one ack, don't bother resending
303 // anything. There may not be a client there, don't clog up the
304 // pipes.
305 //
306 if (lastAck == 0)
307 return;
308
309 lock (m_NeedAck)
310 {
311 // Nothing to do
312 //
313 if (m_NeedAck.Count == 0)
314 return;
315
316 // If we have seen no acks in <SilenceLimit> s but are
317 // waiting for acks, then there may be no one listening.
318 // No need to resend anything. Keep it until it gets stale,
319 // then it will be dropped.
320 //
321 if ((((now - lastAck) > m_SilenceLimit) &&
322 m_NeedAck.Count > 0) || m_NeedAck.Count == 0)
323 {
324 return;
325 }
326
327 foreach (AckData data in new List<AckData>(m_NeedAck.Values))
328 {
329 Packet packet = data.Packet;
330
331 // Packets this old get resent
332 //
333 if ((now - packet.TickCount) > m_ResendTimeout)
334 {
335 // Resend the packet. Set the packet's tick count to
336 // now, and keep it marked as resent.
337 //
338 packet.Header.Resent = true;
339 QueuePacket(packet, ThrottleOutPacketType.Resend,
340 data.Identifier);
341 }
342
343 // The discard logic
344 // If the packet is in the queue for <DiscardTimeout> s
345 // without having been processed, then we have clogged
346 // pipes. Most likely, the client is gone
347 // Drop the packets
348 //
349 if ((now - packet.TickCount) > m_DiscardTimeout)
350 {
351 if (!m_ImportantPackets.Contains(packet.Type))
352 m_NeedAck.Remove(packet.Header.Sequence);
353
354 TriggerOnPacketDrop(packet, data.Identifier);
355
356 continue;
357 }
358 }
359 }
360 }
361
362 // Send the pending packet acks to the client
363 // Will send blocks of acks for up to 250 packets
364 //
365 private void SendAcks()
366 {
367 lock (m_NeedAck)
368 {
369 if (m_PendingAcks.Count == 0)
370 return;
371
372 PacketAckPacket acks = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
373
374 // The case of equality is more common than one might think,
375 // because this function will be called unconditionally when
376 // the counter reaches 250. So there is a good chance another
377 // packet with 250 blocks exists.
378 //
379 if (acks.Packets == null ||
380 acks.Packets.Length != m_PendingAcks.Count)
381 acks.Packets = new PacketAckPacket.PacketsBlock[m_PendingAcks.Count];
382 int i = 0;
383 foreach (uint ack in new List<uint>(m_PendingAcks.Keys))
384 {
385 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
386 acks.Packets[i].ID = ack;
387
388 m_PendingAcks.Remove(ack);
389 i++;
390 }
391
392 acks.Header.Reliable = false;
393 OutPacket(acks, ThrottleOutPacketType.Unknown);
394 }
395 }
396
397 // Queue a packet ack. It will be sent either after 250 acks are
398 // queued, or when the timer fires.
399 //
400 private void AckPacket(Packet packet)
401 {
402 lock (m_NeedAck)
403 {
404 if (m_PendingAcks.Count < 250)
405 {
406 if (!m_PendingAcks.ContainsKey(packet.Header.Sequence))
407 m_PendingAcks.Add(packet.Header.Sequence,
408 packet.Header.Sequence);
409 return;
410 }
411 }
412
413 SendAcks();
414
415 lock (m_NeedAck)
416 {
417 // If this is still full we have a truly exceptional
418 // condition (means, can't happen)
419 //
420 if (m_PendingAcks.Count < 250)
421 {
422 if (!m_PendingAcks.ContainsKey(packet.Header.Sequence))
423 m_PendingAcks.Add(packet.Header.Sequence,
424 packet.Header.Sequence);
425 return;
426 }
427 }
428 }
429
430 // When the timer elapses, send the pending acks, trigger resends
431 // and report all the stats.
432 //
433 private void AckTimerElapsed(object sender, ElapsedEventArgs ea)
434 {
435 SendAcks();
436 ResendUnacked();
437 SendPacketStats();
438 }
439
440 // Push out pachet counts for the sim status reporter
441 //
442 private void SendPacketStats()
443 {
444 PacketStats handlerPacketStats = OnPacketStats;
445 if (handlerPacketStats != null)
446 {
447 handlerPacketStats(
448 m_PacketsReceived - m_PacketsReceivedReported,
449 m_PacketsSent - m_PacketsSentReported,
450 m_UnackedBytes);
451
452 m_PacketsReceivedReported = m_PacketsReceived;
453 m_PacketsSentReported = m_PacketsSent;
454 }
455 }
456
457 // We can't keep an unlimited record of dupes. This will prune the
458 // dictionary by age.
459 //
460// private void PruneDupeTracker()
461// {
462// lock (m_DupeTracker)
463// {
464// Dictionary<uint, int> packs =
465// new Dictionary<uint, int>(m_DupeTracker);
466//
467// foreach (uint pack in packs.Keys)
468// {
469// if (Util.UnixTimeSinceEpoch() - m_DupeTracker[pack] >
470// m_DupeTrackerWindow)
471// m_DupeTracker.Remove(pack);
472// }
473// }
474// }
475
476 public void InPacket(Packet packet)
477 {
478 if (packet == null)
479 return;
480
481 // If this client is on another partial instance, no need
482 // to handle packets
483 //
484 if (!m_Client.IsActive && packet.Type != PacketType.LogoutRequest)
485 {
486 PacketPool.Instance.ReturnPacket(packet);
487 return;
488 }
489
490 // Any packet can have some packet acks in the header.
491 // Process them here
492 //
493 if (packet.Header.AppendedAcks)
494 {
495 foreach (uint id in packet.Header.AckList)
496 {
497 ProcessAck(id);
498 }
499 }
500
501 // When too many acks are needed to be sent, the client sends
502 // a packet consisting of acks only
503 //
504 if (packet.Type == PacketType.PacketAck)
505 {
506 PacketAckPacket ackPacket = (PacketAckPacket)packet;
507
508 foreach (PacketAckPacket.PacketsBlock block in
509 ackPacket.Packets)
510 {
511 ProcessAck(block.ID);
512 }
513
514 PacketPool.Instance.ReturnPacket(packet);
515 return;
516 }
517 else if (packet.Type == PacketType.StartPingCheck)
518 {
519 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
520 CompletePingCheckPacket endPing = (CompletePingCheckPacket)PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
521
522 endPing.PingID.PingID = startPing.PingID.PingID;
523 OutPacket(endPing, ThrottleOutPacketType.Task);
524 }
525 else
526 {
527 LLQueItem item = new LLQueItem();
528 item.Packet = packet;
529 item.Incoming = true;
530 m_PacketQueue.Enqueue(item);
531 }
532 }
533
534 public void ProcessInPacket(Packet packet)
535 {
536 // Always ack the packet!
537 //
538 if (packet.Header.Reliable)
539 AckPacket(packet);
540
541 if (packet.Type != PacketType.AgentUpdate)
542 m_PacketsReceived++;
543
544 // Check for duplicate packets.. packets that the client is
545 // resending because it didn't receive our ack
546 //
547 lock (m_DupeTracker)
548 {
549 if (m_DupeTracker.ContainsKey(packet.Header.Sequence))
550 return;
551
552 m_DupeTracker.Add(packet.Header.Sequence,
553 Util.UnixTimeSinceEpoch());
554 }
555
556 m_Client.ProcessInPacket(packet);
557 }
558
559 public void Flush()
560 {
561 m_PacketQueue.Flush();
562 }
563
564 public void Clear()
565 {
566 m_NeedAck.Clear();
567 m_PendingAcks.Clear();
568 m_Sequence += 1000000;
569 }
570
571 private void ProcessAck(uint id)
572 {
573 AckData data;
574 Packet packet;
575
576 lock (m_NeedAck)
577 {
578 if (!m_NeedAck.TryGetValue(id, out data))
579 return;
580
581 packet = data.Packet;
582
583 m_NeedAck.Remove(id);
584 m_UnackedBytes -= packet.ToBytes().Length;
585
586 m_LastAck = System.Environment.TickCount;
587 }
588 }
589
590 // Allocate packet sequence numbers in a threadsave manner
591 //
592 protected uint NextPacketSequenceNumber()
593 {
594 // Set the sequence number
595 uint seq = 1;
596 lock (m_SequenceLock)
597 {
598 if (m_Sequence >= MAX_SEQUENCE)
599 {
600 m_Sequence = 1;
601 }
602 else
603 {
604 m_Sequence++;
605 }
606 seq = m_Sequence;
607 }
608 return seq;
609 }
610
611 public ClientInfo GetClientInfo()
612 {
613 ClientInfo info = new ClientInfo();
614 info.pendingAcks = m_PendingAcks;
615 info.needAck = new Dictionary<uint, byte[]>();
616
617 lock (m_NeedAck)
618 {
619 foreach (uint key in m_NeedAck.Keys)
620 info.needAck.Add(key, m_NeedAck[key].Packet.ToBytes());
621 }
622
623 LLQueItem[] queitems = m_PacketQueue.GetQueueArray();
624
625 for (int i = 0; i < queitems.Length; i++)
626 {
627 if (queitems[i].Incoming == false)
628 info.out_packets.Add(queitems[i].Packet.ToBytes());
629 }
630
631 info.sequence = m_Sequence;
632
633 return info;
634 }
635
636 public void SetClientInfo(ClientInfo info)
637 {
638 m_PendingAcks = info.pendingAcks;
639 m_NeedAck = new Dictionary<uint, AckData>();
640
641 Packet packet = null;
642 int packetEnd = 0;
643 byte[] zero = new byte[3000];
644
645 foreach (uint key in info.needAck.Keys)
646 {
647 byte[] buff = info.needAck[key];
648 packetEnd = buff.Length - 1;
649
650 try
651 {
652 packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
653 }
654 catch (Exception)
655 {
656 }
657
658 m_NeedAck.Add(key, new AckData(packet, null));
659 }
660
661 m_Sequence = info.sequence;
662 }
663
664 public void AddImportantPacket(PacketType type)
665 {
666 if (m_ImportantPackets.Contains(type))
667 return;
668
669 m_ImportantPackets.Add(type);
670 }
671
672 public void RemoveImportantPacket(PacketType type)
673 {
674 if (!m_ImportantPackets.Contains(type))
675 return;
676
677 m_ImportantPackets.Remove(type);
678 }
679
680 private void DropResend(Object id)
681 {
682 foreach (AckData data in new List<AckData>(m_NeedAck.Values))
683 {
684 if (data.Identifier != null && data.Identifier == id)
685 {
686 m_NeedAck.Remove(data.Packet.Header.Sequence);
687 return;
688 }
689 }
690 }
691
692 private void TriggerOnPacketDrop(Packet packet, Object id)
693 {
694 PacketDrop handlerPacketDrop = OnPacketDrop;
695
696 if (handlerPacketDrop == null)
697 return;
698
699 handlerPacketDrop(packet, id);
700 }
701 }
702}