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 }
/// <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); } } } } }
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 }
/// <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); }
/// <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); } } } } }