Holds a simulator reference and an encoded packet, these structs are put in the packet outbox for sending
Beispiel #1
0
        public void SendPacketData(byte[] data, int dataLength, PacketType type, bool doZerocode)
        {
            UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndPoint, Packet.MTU);

            // Zerocode if needed
            if (doZerocode)
            {
                try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); }
                catch (IndexOutOfRangeException)
                {
                    // The packet grew larger than Packet.MTU bytes while zerocoding.
                    // Remove the MSG_ZEROCODED flag and send the unencoded data
                    // instead
                    data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
                    Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
                }
            }
            else
            {
                Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
            }
            buffer.DataLength = dataLength;

            #region Queue or Send

            NetworkManager.OutgoingPacket outgoingPacket = new NetworkManager.OutgoingPacket(this, buffer);

            // Send ACK and logout packets directly, everything else goes through the queue
            if (Client.Settings.THROTTLE_OUTGOING_PACKETS == false ||
                type == PacketType.PacketAck ||
                type == PacketType.LogoutRequest)
            {
                SendPacketFinal(outgoingPacket);
            }
            else
            {
                Network.PacketOutbox.Enqueue(outgoingPacket);
            }

            #endregion Queue or Send

            #region Stats Tracking
            if (Client.Settings.TRACK_UTILIZATION)
            {
                Client.Stats.Update(type.ToString(), OpenMetaverse.Stats.Type.Packet, dataLength, 0);
            }
            #endregion
        }
Beispiel #2
0
        /// <summary>
        /// Resend unacknowledged packets
        /// </summary>
        private void ResendUnacked()
        {
            if (NeedAck.Count > 0)
            {
                NetworkManager.OutgoingPacket[] array;

                lock (NeedAck)
                {
                    // Create a temporary copy of the outgoing packets array to iterate over
                    array = new NetworkManager.OutgoingPacket[NeedAck.Count];
                    NeedAck.Values.CopyTo(array, 0);
                }

                int now = Environment.TickCount;

                // Resend packets
                for (int i = 0; i < array.Length; i++)
                {
                    NetworkManager.OutgoingPacket outgoing = array[i];

                    if (outgoing.TickCount != 0 && now - outgoing.TickCount > Client.Settings.RESEND_TIMEOUT)
                    {
                        if (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT)
                        {
                            if (Client.Settings.LOG_RESENDS)
                            {
                                Logger.DebugLog(String.Format("Resending packet #{0}, {1}ms have passed",
                                    outgoing.SequenceNumber, now - outgoing.TickCount), Client);
                            }

                            // The TickCount will be set to the current time when the packet
                            // is actually sent out again
                            outgoing.TickCount = 0;

                            // Set the resent flag
                            outgoing.Buffer.Data[0] = (byte)(outgoing.Buffer.Data[0] | Helpers.MSG_RESENT);

                            // Stats tracking
                            Interlocked.Increment(ref outgoing.ResendCount);
                            Interlocked.Increment(ref Stats.ResentPackets);

                            SendPacketFinal(outgoing);
                        }
                        else
                        {
                            Logger.DebugLog(String.Format("Dropping packet #{0} after {1} failed attempts",
                                outgoing.SequenceNumber, outgoing.ResendCount));

                            lock (NeedAck) NeedAck.Remove(outgoing.SequenceNumber);
                        }
                    }
                }
            }
        }
Beispiel #3
0
        public void SendPacketData(byte[] data, int dataLength, PacketType type, bool doZerocode)
        {
            UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndPoint, Packet.MTU);

            // Zerocode if needed
            if (doZerocode)
            {
                try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); }
                catch (IndexOutOfRangeException)
                {
                    // The packet grew larger than Packet.MTU bytes while zerocoding.
                    // Remove the MSG_ZEROCODED flag and send the unencoded data
                    // instead
                    data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
                    Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
                }
            }
            else
            {
                Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
            }
            buffer.DataLength = dataLength;

            #region Queue or Send

            NetworkManager.OutgoingPacket outgoingPacket = new NetworkManager.OutgoingPacket(this, buffer);

            // Send ACK and logout packets directly, everything else goes through the queue
            if (Network.ThrottleOutgoingPackets == false ||
                type == PacketType.PacketAck ||
                type == PacketType.LogoutRequest)
            {
                SendPacketFinal(outgoingPacket);
            }
            else
            {
                Network.PacketOutbox.Enqueue(outgoingPacket);
            }

            #endregion Queue or Send
        }
Beispiel #4
0
        /// <summary>
        /// Sends a packet directly to the simulator without queuing
        /// </summary>
        /// <param name="packet">Packet to be sent</param>
        /// <param name="setSequence">True to set the sequence number, false to
        /// leave it as is</param>
        public void SendPacketUnqueued(Packet packet, 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 Sequence, 0, Settings.MAX_SEQUENCE);
                // Increment and fetch the current sequence number
                packet.Header.Sequence = (uint)Interlocked.Increment(ref Sequence);

                if (packet.Header.Reliable)
                {
                    // Wrap this packet in a struct to track timeouts and resends
                    NetworkManager.OutgoingPacket outgoing = new NetworkManager.OutgoingPacket(this, packet, true);
                    // Keep track of when this packet was first sent out (right now)
                    outgoing.TickCount = Environment.TickCount;

                    // Add this packet to the list of ACK responses we are waiting on from the server
                    lock (NeedAck)
                    {
                        NeedAck[packet.Header.Sequence] = outgoing;
                    }

                    if (packet.Header.Resent)
                    {
                        // 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
                        // server 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 (PendingAcks)
                            {
                                foreach (uint sequence in packet.Header.AckList)
                                {
                                    if (!PendingAcks.ContainsKey(sequence))
                                        PendingAcks[sequence] = sequence;
                                }
                            }

                            packet.Header.AppendedAcks = false;
                            packet.Header.AckList = new uint[0];
                        }

                        // Update the sent time for this packet
                        SetResentTime(packet.Header.Sequence);
                    }
                    else
                    {
                        // This packet is not a resend, check if the conditions are favorable
                        // to ACK appending
                        if (packet.Type != PacketType.PacketAck &&
                            packet.Type != PacketType.LogoutRequest)
                        {
                            lock (PendingAcks)
                            {
                                if (PendingAcks.Count > 0 &&
                                    PendingAcks.Count < Client.Settings.MAX_APPENDED_ACKS)
                                {
                                    // Append all of the queued up outgoing ACKs to this packet
                                    packet.Header.AckList = new uint[PendingAcks.Count];

                                    for (int i = 0; i < PendingAcks.Count; i++)
                                        packet.Header.AckList[i] = PendingAcks.Values[i];

                                    PendingAcks.Clear();
                                    packet.Header.AppendedAcks = true;
                                }
                            }
                        }
                    }
                }
                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(ipEndPoint);

            // 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);
        }
Beispiel #5
0
        /// <summary>
        /// Resend unacknowledged packets
        /// </summary>
        private void ResendUnacked()
        {
            if (NeedAck.Count > 0)
            {
                NetworkManager.OutgoingPacket[] array;

                lock (NeedAck)
                {
                    // Create a temporary copy of the outgoing packets array to iterate over
                    array = new NetworkManager.OutgoingPacket[NeedAck.Count];
                    NeedAck.Values.CopyTo(array, 0);
                }

                int now = Environment.TickCount;

                // Resend packets
                for (int i = 0; i < array.Length; i++)
                {
                    NetworkManager.OutgoingPacket outgoing = array[i];

                    if (outgoing.TickCount != 0 && now - outgoing.TickCount > Client.Settings.RESEND_TIMEOUT)
                    {
                        if (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT)
                        {
                            if (Client.Settings.LOG_RESENDS)
                            {
                                Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed",
                                    outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(),
                                    now - outgoing.TickCount), Client);
                            }

                            // The TickCount will be set to the current time when the packet
                            // is actually sent out again
                            outgoing.TickCount = 0;
                            outgoing.SetSequence = false;
                            outgoing.Packet.Header.Resent = true;
                            ++outgoing.ResendCount;

                            ++Stats.ResentPackets;

                            SendPacket(outgoing);
                        }
                        else
                        {
                            Logger.DebugLog(String.Format("Dropping packet #{0} ({1}) after {2} failed attempts",
                                outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), outgoing.ResendCount));

                            lock (NeedAck) NeedAck.Remove(outgoing.Packet.Header.Sequence);
                        }
                    }
                }
            }
        }