123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using libsecondlife;
- using libsecondlife.Packets;
- using System.Net;
- using System.Net.Sockets;
- using System.IO;
- using System.Threading;
- using System.Timers;
- using OpenSim.Framework.Utilities;
- using OpenSim.Framework.Interfaces;
- namespace OpenSim
- {
- public class ClientViewBase
- {
- protected BlockingQueue<QueItem> PacketQueue;
- protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
- protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
- protected System.Timers.Timer AckTimer;
- protected uint Sequence = 0;
- protected object SequenceLock = new object();
- protected const int MAX_APPENDED_ACKS = 10;
- protected const int RESEND_TIMEOUT = 4000;
- protected const int MAX_SEQUENCE = 0xFFFFFF;
- public uint CircuitCode;
- public EndPoint userEP;
- protected PacketServer m_networkServer;
- public ClientViewBase()
- {
- }
- protected virtual void ProcessInPacket(Packet Pack)
- {
- }
- protected virtual void ProcessOutPacket(Packet Pack)
- {
- // Keep track of when this packet was sent out
- Pack.TickCount = Environment.TickCount;
- if (!Pack.Header.Resent)
- {
- // Set the sequence number
- lock (SequenceLock)
- {
- if (Sequence >= MAX_SEQUENCE)
- Sequence = 1;
- else
- Sequence++;
- Pack.Header.Sequence = Sequence;
- }
- if (Pack.Header.Reliable) //DIRTY HACK
- {
- lock (NeedAck)
- {
- if (!NeedAck.ContainsKey(Pack.Header.Sequence))
- {
- try
- {
- NeedAck.Add(Pack.Header.Sequence, Pack);
- }
- catch (Exception e) // HACKY
- {
- e.ToString();
- // Ignore
- // Seems to throw a exception here occasionally
- // of 'duplicate key' despite being locked.
- // !?!?!?
- }
- }
- else
- {
- // Client.Log("Attempted to add a duplicate sequence number (" +
- // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
- // packet.Type.ToString(), Helpers.LogLevel.Warning);
- }
- }
- // Don't append ACKs to resent packets, in case that's what was causing the
- // delivery to fail
- if (!Pack.Header.Resent)
- {
- // Append any ACKs that need to be sent out to this packet
- lock (PendingAcks)
- {
- if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
- Pack.Type != PacketType.PacketAck &&
- Pack.Type != PacketType.LogoutRequest)
- {
- Pack.Header.AckList = new uint[PendingAcks.Count];
- int i = 0;
- foreach (uint ack in PendingAcks.Values)
- {
- Pack.Header.AckList[i] = ack;
- i++;
- }
- PendingAcks.Clear();
- Pack.Header.AppendedAcks = true;
- }
- }
- }
- }
- }
- byte[] ZeroOutBuffer = new byte[4096];
- byte[] sendbuffer;
- sendbuffer = Pack.ToBytes();
- try
- {
- if (Pack.Header.Zerocoded)
- {
- int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
- m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, CircuitCode);//userEP);
- }
- else
- {
- m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, CircuitCode); //userEP);
- }
- }
- catch (Exception)
- {
- OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.MEDIUM, "OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
- this.KillThread();
- }
- }
- public virtual void InPacket(Packet NewPack)
- {
- // Handle appended ACKs
- if (NewPack.Header.AppendedAcks)
- {
- lock (NeedAck)
- {
- foreach (uint ack in NewPack.Header.AckList)
- {
- NeedAck.Remove(ack);
- }
- }
- }
- // Handle PacketAck packets
- if (NewPack.Type == PacketType.PacketAck)
- {
- PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
- lock (NeedAck)
- {
- foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
- {
- NeedAck.Remove(block.ID);
- }
- }
- }
- else if ((NewPack.Type == PacketType.StartPingCheck))
- {
- //reply to pingcheck
- libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
- libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
- endPing.PingID.PingID = startPing.PingID.PingID;
- OutPacket(endPing);
- }
- else
- {
- QueItem item = new QueItem();
- item.Packet = NewPack;
- item.Incoming = true;
- this.PacketQueue.Enqueue(item);
- }
- }
- public virtual void OutPacket(Packet NewPack)
- {
- QueItem item = new QueItem();
- item.Packet = NewPack;
- item.Incoming = false;
- this.PacketQueue.Enqueue(item);
- }
- # region Low Level Packet Methods
- protected void ack_pack(Packet Pack)
- {
- if (Pack.Header.Reliable)
- {
- libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
- ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
- ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
- ack_it.Packets[0].ID = Pack.Header.Sequence;
- ack_it.Header.Reliable = false;
- OutPacket(ack_it);
- }
- /*
- if (Pack.Header.Reliable)
- {
- lock (PendingAcks)
- {
- uint sequence = (uint)Pack.Header.Sequence;
- if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
- }
- }*/
- }
- protected void ResendUnacked()
- {
- int now = Environment.TickCount;
- lock (NeedAck)
- {
- foreach (Packet packet in NeedAck.Values)
- {
- if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
- {
- OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.VERBOSE, "Resending " + packet.Type.ToString() + " packet, " +
- (now - packet.TickCount) + "ms have passed");
- packet.Header.Resent = true;
- OutPacket(packet);
- }
- }
- }
- }
- protected void SendAcks()
- {
- lock (PendingAcks)
- {
- if (PendingAcks.Count > 0)
- {
- if (PendingAcks.Count > 250)
- {
- // FIXME: Handle the odd case where we have too many pending ACKs queued up
- OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.VERBOSE, "Too many ACKs queued up!");
- return;
- }
- //OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Sending PacketAck");
- int i = 0;
- PacketAckPacket acks = new PacketAckPacket();
- acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
- foreach (uint ack in PendingAcks.Values)
- {
- acks.Packets[i] = new PacketAckPacket.PacketsBlock();
- acks.Packets[i].ID = ack;
- i++;
- }
- acks.Header.Reliable = false;
- OutPacket(acks);
- PendingAcks.Clear();
- }
- }
- }
- protected void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
- {
- SendAcks();
- ResendUnacked();
- }
- #endregion
- protected virtual void KillThread()
- {
- }
- #region Nested Classes
- public class QueItem
- {
- public QueItem()
- {
- }
- public Packet Packet;
- public bool Incoming;
- }
- #endregion
- }
- }
|