diff --git a/OpenMetaverse/NetworkManager.cs b/OpenMetaverse/NetworkManager.cs index 35ef7115..04ab1688 100644 --- a/OpenMetaverse/NetworkManager.cs +++ b/OpenMetaverse/NetworkManager.cs @@ -101,12 +101,33 @@ namespace OpenMetaverse public Packet Packet; /// True if the sequence number needs to be set, otherwise false public bool SetSequence; + /// Number of times this packet has been resent + public int ResendCount; + /// Environment.TickCount when this packet was last sent over the wire + public int TickCount; public OutgoingPacket(Simulator simulator, Packet packet, bool setSequence) { Simulator = simulator; Packet = packet; SetSequence = setSequence; + ResendCount = 0; + TickCount = 0; + } + + public void IncrementResendCount() + { + ++ResendCount; + } + + public void SetTickCount() + { + TickCount = Environment.TickCount; + } + + public void ZeroTickCount() + { + TickCount = 0; } } diff --git a/OpenMetaverse/ParcelManager.cs b/OpenMetaverse/ParcelManager.cs index 8d6a86f2..c5e4cfcd 100644 --- a/OpenMetaverse/ParcelManager.cs +++ b/OpenMetaverse/ParcelManager.cs @@ -918,13 +918,11 @@ namespace OpenMetaverse (y + 1) * 4.0f, (x + 1) * 4.0f, y * 4.0f, x * 4.0f, int.MaxValue, false); - // Wait a reasonable amount of time for a reply before sending the next request + // Wait the given amount of time for a reply before sending the next request if (!WaitForSimParcel.WaitOne(msDelay, false)) - { - Logger.Log("Timeout Waiting for ParcelProperties Response, try increasing the delay between requests", Helpers.LogLevel.Debug, Client); - timeouts++; - } - count++; + ++timeouts; + + ++count; } } } diff --git a/OpenMetaverse/Simulator.cs b/OpenMetaverse/Simulator.cs index f5750f90..8638f32d 100644 --- a/OpenMetaverse/Simulator.cs +++ b/OpenMetaverse/Simulator.cs @@ -391,7 +391,7 @@ namespace OpenMetaverse /// (for duplicate checking) internal Queue PacketArchive; /// Packets we sent out that need ACKs from the simulator - internal Dictionary NeedAck = new Dictionary(); + internal Dictionary NeedAck = new Dictionary(); private NetworkManager Network; private Queue InBytes, OutBytes; @@ -608,9 +608,7 @@ namespace OpenMetaverse byte[] buffer; int bytes; - // Keep track of when this packet was sent out - packet.TickCount = Environment.TickCount; - + // Set sequence implies that this is not a resent packet if (setSequence) { // Reset to zero if we've hit the upper sequence number limit @@ -620,10 +618,15 @@ namespace OpenMetaverse 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] = packet; + NeedAck[packet.Header.Sequence] = outgoing; } if (packet.Header.Resent) @@ -649,6 +652,9 @@ namespace OpenMetaverse packet.Header.AppendedAcks = false; packet.Header.AckList = new uint[0]; } + + // Update the sent time for this packet + SetResentTime(packet.Header.Sequence); } else { @@ -890,6 +896,13 @@ namespace OpenMetaverse { } + private void SetResentTime(uint sequence) + { + NetworkManager.OutgoingPacket outgoing; + if (NeedAck.TryGetValue(sequence, out outgoing)) + outgoing.SetTickCount(); + } + /// /// Sends out pending acknowledgements /// @@ -933,26 +946,26 @@ namespace OpenMetaverse int now = Environment.TickCount; // Resend packets - foreach (Packet packet in NeedAck.Values) + foreach (NetworkManager.OutgoingPacket outgoing in NeedAck.Values) { - if (packet.TickCount != 0 && now - packet.TickCount > Client.Settings.RESEND_TIMEOUT) + if (outgoing.TickCount != 0 && now - outgoing.TickCount > Client.Settings.RESEND_TIMEOUT) { - if (packet.ResendCount < Client.Settings.MAX_RESEND_COUNT) + if (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT) { try { if (Client.Settings.LOG_RESENDS) { Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed", - packet.Header.Sequence, packet.GetType(), now - packet.TickCount), Client); + outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), now - outgoing.TickCount), Client); } - packet.TickCount = 0; - packet.Header.Resent = true; + outgoing.ZeroTickCount(); + outgoing.Packet.Header.Resent = true; ++Stats.ResentPackets; - ++packet.ResendCount; + outgoing.IncrementResendCount(); - SendPacket(packet, false); + SendPacket(outgoing.Packet, false); } catch (Exception ex) { @@ -964,10 +977,10 @@ namespace OpenMetaverse if (Client.Settings.LOG_RESENDS) { Logger.DebugLog(String.Format("Dropping packet #{0} ({1}) after {2} failed attempts", - packet.Header.Sequence, packet.GetType(), packet.ResendCount)); + outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), outgoing.ResendCount)); } - dropAck.Add(packet.Header.Sequence); + dropAck.Add(outgoing.Packet.Header.Sequence); } } } diff --git a/OpenMetaverse/_Packets_.cs b/OpenMetaverse/_Packets_.cs index 6852f9e8..ed6ac4d2 100644 --- a/OpenMetaverse/_Packets_.cs +++ b/OpenMetaverse/_Packets_.cs @@ -781,9 +781,6 @@ namespace OpenMetaverse.Packets public abstract PacketType Type { get; } public abstract void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer); public abstract void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer); - public int ResendCount; - public int TickCount; - public abstract byte[] ToBytes(); public static PacketType GetType(ushort id, PacketFrequency frequency) { diff --git a/Programs/Simian/Extensions/UDPServer.cs b/Programs/Simian/Extensions/UDPServer.cs index eeac1961..f9ac4e5b 100644 --- a/Programs/Simian/Extensions/UDPServer.cs +++ b/Programs/Simian/Extensions/UDPServer.cs @@ -8,6 +8,45 @@ using OpenMetaverse.Packets; namespace Simian { + public struct IncomingPacket + { + public UDPClient Client; + public Packet Packet; + } + + public struct OutgoingPacket + { + public UDPClient Client; + public Packet Packet; + /// Number of times this packet has been resent + public int ResendCount; + /// Environment.TickCount when this packet was last sent over the wire + public int TickCount; + + public OutgoingPacket(UDPClient client, Packet packet) + { + Client = client; + Packet = packet; + ResendCount = 0; + TickCount = 0; + } + + public void IncrementResendCount() + { + ++ResendCount; + } + + public void SetTickCount() + { + TickCount = Environment.TickCount; + } + + public void ZeroTickCount() + { + TickCount = 0; + } + } + public class UDPClient { /// @@ -17,7 +56,7 @@ namespace Simian /// Sequence numbers of packets we've received (for duplicate checking) public Queue PacketArchive = new Queue(); /// Packets we have sent that need to be ACKed by the client - public Dictionary NeedAcks = new Dictionary(); + public Dictionary NeedAcks = new Dictionary(); /// ACKs that are queued up, waiting to be sent to the client public SortedList PendingAcks = new SortedList(); /// Current packet sequence number @@ -47,12 +86,6 @@ namespace Simian } } - public struct IncomingPacket - { - public UDPClient Client; - public Packet Packet; - } - public class UDPManager : ISimianExtension, IUDPProvider { Simian Server; @@ -184,9 +217,7 @@ namespace Simian byte[] buffer; int bytes; - // Keep track of when this packet was sent out - packet.TickCount = Environment.TickCount; - + // Set sequence implies that this is not a resent packet if (setSequence) { // Reset to zero if we've hit the upper sequence number limit @@ -197,9 +228,14 @@ namespace Simian if (packet.Header.Reliable) { + // Wrap this packet in a struct to track timeouts and resends + OutgoingPacket outgoing = new OutgoingPacket(null, packet); + // Keep track of when this packet was sent out (right now) + outgoing.TickCount = Environment.TickCount; + // Add this packet to the list of ACK responses we are waiting on from this client lock (client.NeedAcks) - client.NeedAcks[sequence] = packet; + client.NeedAcks[sequence] = outgoing; if (packet.Header.Resent) { @@ -224,6 +260,9 @@ namespace Simian packet.Header.AppendedAcks = false; packet.Header.AckList = new uint[0]; } + + // Update the sent time for this packet + SetResentTime(client, packet.Header.Sequence); } else { @@ -340,6 +379,13 @@ namespace Simian SendPacket(client, acks, PacketCategory.Overhead, true); } + void SetResentTime(UDPClient client, uint sequence) + { + OutgoingPacket outgoing; + if (client.NeedAcks.TryGetValue(sequence, out outgoing)) + outgoing.SetTickCount(); + } + public void ResendUnacked(UDPClient client) { lock (client.NeedAcks) @@ -348,28 +394,28 @@ namespace Simian int now = Environment.TickCount; // Resend packets - foreach (Packet packet in client.NeedAcks.Values) + foreach (OutgoingPacket outgoing in client.NeedAcks.Values) { - if (packet.TickCount != 0 && now - packet.TickCount > 4000) + if (outgoing.TickCount != 0 && now - outgoing.TickCount > 4000) { - if (packet.ResendCount < 3) + if (outgoing.ResendCount < 3) { Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed", - packet.Header.Sequence, packet.GetType(), now - packet.TickCount)); + outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), now - outgoing.TickCount)); - packet.TickCount = 0; - packet.Header.Resent = true; + outgoing.ZeroTickCount(); + outgoing.Packet.Header.Resent = true; //++Stats.ResentPackets; - ++packet.ResendCount; + outgoing.IncrementResendCount(); - SendPacket(client, packet, PacketCategory.Overhead, false); + SendPacket(client, outgoing.Packet, PacketCategory.Overhead, false); } else { Logger.Log(String.Format("Dropping packet #{0} ({1}) after {2} failed attempts", - packet.Header.Sequence, packet.GetType(), packet.ResendCount), Helpers.LogLevel.Warning); + outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), outgoing.ResendCount), Helpers.LogLevel.Warning); - dropAck.Add(packet.Header.Sequence); + dropAck.Add(outgoing.Packet.Header.Sequence); //Disconnect an agent if no packets are received for some time //TODO: Send logout packet? Also, 10000 should be a setting somewhere. diff --git a/Programs/mapgenerator/mapgenerator.cs b/Programs/mapgenerator/mapgenerator.cs index f53bb565..685c7909 100644 --- a/Programs/mapgenerator/mapgenerator.cs +++ b/Programs/mapgenerator/mapgenerator.cs @@ -813,20 +813,6 @@ namespace mapgenerator writer.WriteLine(" " + packet.Name + " = " + (0x30000 | packet.ID) + ","); writer.WriteLine(" }" + Environment.NewLine); - - // Write all of the XmlInclude statements for the Packet class to allow packet serialization - //writer.WriteLine("#if PACKETSERIALIZE"); - //foreach (MapPacket packet in protocol.LowMaps) - // if (packet != null) - // writer.WriteLine(" [XmlInclude(typeof(" + packet.Name + "Packet))]"); - //foreach (MapPacket packet in protocol.MediumMaps) - // if (packet != null) - // writer.WriteLine(" [XmlInclude(typeof(" + packet.Name + "Packet))]"); - //foreach (MapPacket packet in protocol.HighMaps) - // if (packet != null) - // writer.WriteLine(" [XmlInclude(typeof(" + packet.Name + "Packet))]"); - //writer.WriteLine("#endif"); - // Write the base Packet class writer.WriteLine( " public abstract partial class Packet" + Environment.NewLine + " {" + Environment.NewLine + @@ -834,14 +820,7 @@ namespace mapgenerator " public abstract PacketType Type { get; }" + Environment.NewLine + " public abstract void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer);" + Environment.NewLine + " public abstract void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer);" + Environment.NewLine + - " public int ResendCount;" + Environment.NewLine + - " public int TickCount;" + Environment.NewLine + Environment.NewLine + - " public abstract byte[] ToBytes();" //+ Environment.NewLine + Environment.NewLine + - //" public void ToXml(XmlWriter xmlWriter)" + Environment.NewLine + - //" {" + Environment.NewLine + - //" XmlSerializer serializer = new XmlSerializer(typeof(Packet));" + Environment.NewLine + - //" serializer.Serialize(xmlWriter, this);" + Environment.NewLine + - //" }"); + " public abstract byte[] ToBytes();" ); @@ -875,31 +854,6 @@ namespace mapgenerator " break;" + Environment.NewLine + " }" + Environment.NewLine + Environment.NewLine + " return PacketType.Default;" + Environment.NewLine + " }" + Environment.NewLine); - // TODO: Not sure if this function is useful to anyone, but if it is it needs to be - // rewritten to not overwrite passed in pointers and decode the entire packet just - // to read the header - - // Write the Packet.GetType() function - //writer.WriteLine( - // " public static PacketType GetType(byte[] bytes, int packetEnd, byte[] zeroBuffer)" + Environment.NewLine + - // " {" + Environment.NewLine + " ushort id; PacketFrequency freq;" + Environment.NewLine + - // " int i = 0, end = packetEnd;" + Environment.NewLine + - // " Header header = Header.BuildHeader(bytes, ref i, ref end);" + Environment.NewLine + - // " if (header.Zerocoded)" + Environment.NewLine + " {" + Environment.NewLine + - // " end = Helpers.ZeroDecode(bytes, end + 1, zeroBuffer) - 1;" + Environment.NewLine + - // " bytes = zeroBuffer;" + Environment.NewLine + " }" + Environment.NewLine + Environment.NewLine + - // " if (bytes[6] == 0xFF)" + Environment.NewLine + " {" + Environment.NewLine + - // " if (bytes[7] == 0xFF)" + Environment.NewLine + " {" + Environment.NewLine + - // " id = (ushort)((bytes[8] << 8) + bytes[9]); freq = PacketFrequency.Low;" + Environment.NewLine + - // " }" + Environment.NewLine + - // " else" + Environment.NewLine + - // " {" + Environment.NewLine + " id = (ushort)bytes[7]; freq = PacketFrequency.Medium;" + - // Environment.NewLine + " }" + Environment.NewLine + " }" + Environment.NewLine + - // " else" + Environment.NewLine + " {" + Environment.NewLine + - // " id = (ushort)bytes[6]; freq = PacketFrequency.High;" + Environment.NewLine + - // " }" + Environment.NewLine + - // " return GetType(id, freq);" + Environment.NewLine + - // " }" + Environment.NewLine); // Write the Packet.BuildPacket(PacketType) function writer.WriteLine(" public static Packet BuildPacket(PacketType type)");