コード例 #1
0
ファイル: UDPServer.cs プロジェクト: xjc90s/libopenmetaverse
        void IncomingPacketHandler()
        {
            IncomingPacket incomingPacket = new IncomingPacket();
            Packet         packet         = null;
            UDPClient      client         = null;

            while (IsRunning)
            {
                // Reset packet to null for the check below
                packet = null;

                if (packetInbox.Dequeue(100, ref incomingPacket))
                {
                    packet = incomingPacket.Packet;
                    client = incomingPacket.Client;

                    if (packet != null)
                    {
                        #region ACK accounting

                        // Check the archives to see whether we already received this packet
                        lock (client.PacketArchive)
                        {
                            if (client.PacketArchive.Contains(packet.Header.Sequence))
                            {
                                if (packet.Header.Resent)
                                {
                                    Logger.DebugLog("Received resent packet #" + packet.Header.Sequence);
                                }
                                else
                                {
                                    Logger.Log(String.Format("Received a duplicate of packet #{0}, current type: {1}",
                                                             packet.Header.Sequence, packet.Type), Helpers.LogLevel.Warning);
                                }

                                // Avoid firing a callback twice for the same packet
                                continue;
                            }
                            else
                            {
                                // Keep the PacketArchive size within a certain capacity
                                while (client.PacketArchive.Count >= Settings.PACKET_ARCHIVE_SIZE)
                                {
                                    client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue();
                                    client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue();
                                }

                                client.PacketArchive.Enqueue(packet.Header.Sequence);
                            }
                        }

                        #endregion ACK accounting

                        #region ACK handling

                        // Handle appended ACKs
                        if (packet.Header.AppendedAcks)
                        {
                            lock (client.NeedAcks)
                            {
                                for (int i = 0; i < packet.Header.AckList.Length; i++)
                                {
                                    client.NeedAcks.Remove(packet.Header.AckList[i]);
                                }
                            }
                        }

                        // Handle PacketAck packets
                        if (packet.Type == PacketType.PacketAck)
                        {
                            PacketAckPacket ackPacket = (PacketAckPacket)packet;

                            lock (client.NeedAcks)
                            {
                                for (int i = 0; i < ackPacket.Packets.Length; i++)
                                {
                                    client.NeedAcks.Remove(ackPacket.Packets[i].ID);
                                }
                            }
                        }

                        #endregion ACK handling

                        packetEvents.BeginRaiseEvent(packet.Type, packet, client.Agent);
                    }
                }
            }
        }
コード例 #2
0
ファイル: UDPServer.cs プロジェクト: xjc90s/libopenmetaverse
        void SendPacket(UDPClient client, Packet packet, PacketCategory category, bool setSequence)
        {
            byte[] buffer;
            int    bytes;

            // Set sequence implies that this is not a resent packet
            if (setSequence)
            {
                // Reset to zero if we've hit the upper sequence number limit
                Interlocked.CompareExchange(ref client.CurrentSequence, 0, 0xFFFFFF);
                // Increment and fetch the current sequence number
                uint sequence = (uint)Interlocked.Increment(ref client.CurrentSequence);
                packet.Header.Sequence = sequence;

                if (packet.Header.Reliable)
                {
                    OutgoingPacket outgoing;

                    if (packet.Header.Resent && client.NeedAcks.TryGetValue(packet.Header.Sequence, out outgoing))
                    {
                        // This packet has already been sent out once, strip any appended ACKs
                        // off it and reinsert them into the outgoing ACK queue under the
                        // assumption that this packet will continually be rejected from the
                        // client or that the appended ACKs are possibly making the delivery fail
                        if (packet.Header.AckList.Length > 0)
                        {
                            Logger.DebugLog(String.Format("Purging ACKs from packet #{0} ({1}) which will be resent.",
                                                          packet.Header.Sequence, packet.GetType()));

                            lock (client.PendingAcks)
                            {
                                foreach (uint ack in packet.Header.AckList)
                                {
                                    if (!client.PendingAcks.ContainsKey(ack))
                                    {
                                        client.PendingAcks[ack] = ack;
                                    }
                                }
                            }

                            packet.Header.AppendedAcks = false;
                            packet.Header.AckList      = new uint[0];
                        }
                    }
                    else
                    {
                        // Wrap this packet in a struct to track timeouts and resends
                        outgoing = new OutgoingPacket(packet);

                        // Add this packet to the list of ACK responses we are waiting on from this client
                        lock (client.NeedAcks)
                            client.NeedAcks[sequence] = outgoing;

                        // This packet is not a resend, check if the conditions are favorable
                        // to ACK appending
                        if (packet.Type != PacketType.PacketAck)
                        {
                            lock (client.PendingAcks)
                            {
                                int count = client.PendingAcks.Count;

                                if (count > 0 && count < 10)
                                {
                                    // Append all of the queued up outgoing ACKs to this packet
                                    packet.Header.AckList = new uint[count];

                                    for (int i = 0; i < count; i++)
                                    {
                                        packet.Header.AckList[i] = client.PendingAcks.Values[i];
                                    }

                                    client.PendingAcks.Clear();
                                    packet.Header.AppendedAcks = true;
                                }
                            }
                        }
                    }

                    // Update the sent time for this packet
                    outgoing.TickCount = Environment.TickCount;
                }
                else if (packet.Header.AckList.Length > 0)
                {
                    // Sanity check for ACKS appended on an unreliable packet, this is bad form
                    Logger.Log("Sending appended ACKs on an unreliable packet", Helpers.LogLevel.Warning);
                }
            }

            // Serialize the packet
            buffer = packet.ToBytes();
            bytes  = buffer.Length;
            //Stats.SentBytes += (ulong)bytes;
            //++Stats.SentPackets;

            UDPPacketBuffer buf = new UDPPacketBuffer(client.Address);

            // Zerocode if needed
            if (packet.Header.Zerocoded)
            {
                bytes = Helpers.ZeroEncode(buffer, bytes, buf.Data);
            }
            else
            {
                Buffer.BlockCopy(buffer, 0, buf.Data, 0, bytes);
            }

            buf.DataLength = bytes;

            AsyncBeginSend(buf);
        }
コード例 #3
0
ファイル: UDPServer.cs プロジェクト: xjc90s/libopenmetaverse
        protected override void PacketReceived(UDPPacketBuffer buffer)
        {
            UDPClient  client    = null;
            Packet     packet    = null;
            int        packetEnd = buffer.DataLength - 1;
            IPEndPoint address   = (IPEndPoint)buffer.RemoteEndPoint;

            // Decoding
            try
            {
                packet = Packet.BuildPacket(buffer.Data, ref packetEnd, buffer.ZeroData);
            }
            catch (MalformedDataException)
            {
                Logger.Log(String.Format("Malformed data, cannot parse packet:\n{0}",
                                         Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)), Helpers.LogLevel.Error);
            }

            // Fail-safe check
            if (packet == null)
            {
                Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning);
                return;
            }

            //Stats.RecvBytes += (ulong)buffer.DataLength;
            //++Stats.RecvPackets;

            if (packet.Type == PacketType.UseCircuitCode)
            {
                UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet;

                Agent agent;
                if (CompleteAgentConnection(useCircuitCode.CircuitCode.Code, out agent))
                {
                    AddClient(agent, address);
                    if (clients.TryGetValue(agent.AgentID, out client))
                    {
                        Logger.Log("Activated UDP circuit " + useCircuitCode.CircuitCode.Code, Helpers.LogLevel.Info);
                    }
                    else
                    {
                        Logger.Log("Failed to locate newly created UDPClient", Helpers.LogLevel.Error);
                        return;
                    }
                }
                else
                {
                    Logger.Log("Received a UseCircuitCode packet for an unrecognized circuit: " +
                               useCircuitCode.CircuitCode.Code.ToString(), Helpers.LogLevel.Warning);
                    return;
                }
            }
            else
            {
                // Determine which agent this packet came from
                if (!clients.TryGetValue(address, out client))
                {
                    Logger.Log("Received UDP packet from an unrecognized source: " + address.ToString(),
                               Helpers.LogLevel.Warning);
                    return;
                }
            }

            client.Agent.TickLastPacketReceived = Environment.TickCount;

            // Reliable handling
            if (packet.Header.Reliable)
            {
                // Queue up this sequence number for acknowledgement
                QueueAck(client, (uint)packet.Header.Sequence);
                //if (packet.Header.Resent) ++Stats.ReceivedResends;
            }

            // Inbox insertion
            IncomingPacket incomingPacket;

            incomingPacket.Client = client;
            incomingPacket.Packet = packet;

            // TODO: Prioritize the queue
            packetInbox.Enqueue(incomingPacket);
        }
コード例 #4
0
ファイル: UDPServer.cs プロジェクト: xjc90s/libopenmetaverse
        public void AddClient(Agent agent, IPEndPoint endpoint)
        {
            UDPClient client = new UDPClient(this, agent, endpoint);

            clients.Add(agent.AgentID, endpoint, client);
        }