diff --git a/OpenMetaverse/Simulator.cs b/OpenMetaverse/Simulator.cs index a0757fbb..0aea3894 100644 --- a/OpenMetaverse/Simulator.cs +++ b/OpenMetaverse/Simulator.cs @@ -360,7 +360,7 @@ namespace OpenMetaverse #region Properties /// The IP address and port of the server - public IPEndPoint IPEndPoint { get { return ipEndPoint; } } + public IPEndPoint IPEndPoint { get { return remoteEndPoint; } } /// Whether there is a working connection to the simulator or /// not public bool Connected { get { return connected; } } @@ -400,7 +400,6 @@ namespace OpenMetaverse private Queue InBytes, OutBytes; // ACKs that are queued up to be sent to the simulator private SortedList PendingAcks = new SortedList(); - private IPEndPoint ipEndPoint; private Timer AckTimer; private Timer PingTimer; private Timer StatsTimer; @@ -421,7 +420,6 @@ namespace OpenMetaverse { Client = client; - ipEndPoint = address; Handle = handle; Estate = new EstateTools(Client); Network = Client.Network; @@ -563,7 +561,7 @@ namespace OpenMetaverse { // Try to send the CloseCircuit notice CloseCircuitPacket close = new CloseCircuitPacket(); - UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint); + UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint); byte[] data = close.ToBytes(); Buffer.BlockCopy(data, 0, buf.Data, 0, data.Length); buf.DataLength = data.Length; @@ -659,31 +657,7 @@ namespace OpenMetaverse // Add this packet to the list of ACK responses we are waiting on from the server lock (NeedAck) NeedAck[packet.Header.Sequence] = outgoingPacket; - 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]; - } - } - else + if (!packet.Header.Resent) { // This packet is not a resend, check if the conditions are favorable // to ACK appending @@ -715,13 +689,38 @@ namespace OpenMetaverse } } + 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]; + } + } + // Serialize the packet buffer = packet.ToBytes(); bytes = buffer.Length; Stats.SentBytes += (ulong)bytes; ++Stats.SentPackets; - UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint); + UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint); // Zerocode if needed if (packet.Header.Zerocoded) @@ -756,7 +755,7 @@ namespace OpenMetaverse Stats.SentBytes += (ulong)payload.Length; ++Stats.SentPackets; - UDPPacketBuffer buf = new UDPPacketBuffer(ipEndPoint); + UDPPacketBuffer buf = new UDPPacketBuffer(remoteEndPoint); Buffer.BlockCopy(payload, 0, buf.Data, 0, payload.Length); buf.DataLength = payload.Length; @@ -813,9 +812,9 @@ namespace OpenMetaverse public override string ToString() { if (!String.IsNullOrEmpty(Name)) - return String.Format("{0} ({1})", Name, ipEndPoint); + return String.Format("{0} ({1})", Name, remoteEndPoint); else - return String.Format("({0})", ipEndPoint); + return String.Format("({0})", remoteEndPoint); } /// @@ -837,7 +836,7 @@ namespace OpenMetaverse Simulator sim = obj as Simulator; if (sim == null) return false; - return (ipEndPoint.Equals(sim.ipEndPoint)); + return (remoteEndPoint.Equals(sim.remoteEndPoint)); } public static bool operator ==(Simulator lhs, Simulator rhs) @@ -854,7 +853,7 @@ namespace OpenMetaverse return false; } - return lhs.ipEndPoint.Equals(rhs.ipEndPoint); + return lhs.remoteEndPoint.Equals(rhs.remoteEndPoint); } public static bool operator !=(Simulator lhs, Simulator rhs) @@ -867,7 +866,7 @@ namespace OpenMetaverse Packet packet = null; // Check if this packet came from the server we expected it to come from - if (!ipEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address)) + if (!remoteEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address)) { Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " + ((IPEndPoint)buffer.RemoteEndPoint).ToString(), Helpers.LogLevel.Warning, Client); @@ -976,59 +975,52 @@ namespace OpenMetaverse /// private void ResendUnacked() { - lock (NeedAck) + if (NeedAck.Count > 0) { - if (NeedAck.Count > 0) + NetworkManager.OutgoingPacket[] array; + + lock (NeedAck) { // Create a temporary copy of the outgoing packets array to iterate over - NetworkManager.OutgoingPacket[] array = new NetworkManager.OutgoingPacket[NeedAck.Count]; + array = new NetworkManager.OutgoingPacket[NeedAck.Count]; NeedAck.Values.CopyTo(array, 0); + } - int now = Environment.TickCount; + int now = Environment.TickCount; - // Resend packets - for (int i = 0; i < array.Length; i++) + // 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) { - 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 (outgoing.ResendCount < Client.Settings.MAX_RESEND_COUNT) + if (Client.Settings.LOG_RESENDS) { - try - { - 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. Set it to zero while it sits in the - // queue to avoid requeueing the same packet - - outgoing.TickCount = 0; - outgoing.SetSequence = false; - outgoing.Packet.Header.Resent = true; - ++outgoing.ResendCount; - - ++Stats.ResentPackets; - - SendPacket(outgoing); - } - catch (Exception ex) - { - Logger.DebugLog("Exception trying to resend packet: " + ex.ToString(), Client); - } + Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed", + outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), + now - outgoing.TickCount), Client); } - else - { - Logger.DebugLog(String.Format("Dropping packet #{0} ({1}) after {2} failed attempts", - outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), outgoing.ResendCount)); - NeedAck.Remove(outgoing.Packet.Header.Sequence); - } + // 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); } } } diff --git a/OpenMetaverse/UDPBase.cs b/OpenMetaverse/UDPBase.cs index fce90627..26022f26 100644 --- a/OpenMetaverse/UDPBase.cs +++ b/OpenMetaverse/UDPBase.cs @@ -56,11 +56,7 @@ namespace OpenMetaverse // wait until all outstanding operations are completed before shutting down. // this avoids the problem of closing the socket with outstanding operations // and trying to catch the inevitable ObjectDisposedException. -#if PocketPC - private OpenMetaverse.ReaderWriterLock rwLock = new OpenMetaverse.ReaderWriterLock(); -#else private ReaderWriterLock rwLock = new ReaderWriterLock(); -#endif // number of outstanding operations. This is a reference count // which we use to ensure that the threads exit cleanly. Note that @@ -71,8 +67,8 @@ namespace OpenMetaverse // the all important shutdownFlag. This is synchronized through the ReaderWriterLock. private volatile bool shutdownFlag = true; - // - private IPEndPoint remoteEndPoint = null; + // the remote endpoint to communicate with + protected IPEndPoint remoteEndPoint = null; /// diff --git a/Programs/Simian/Extensions/ConnectionManagement.cs b/Programs/Simian/Extensions/ConnectionManagement.cs index 4a732558..8f4f5b40 100644 --- a/Programs/Simian/Extensions/ConnectionManagement.cs +++ b/Programs/Simian/Extensions/ConnectionManagement.cs @@ -17,9 +17,9 @@ namespace Simian.Extensions { this.server = server; - server.UDP.RegisterPacketCallback(PacketType.UseCircuitCode, new PacketCallback(UseCircuitCodeHandler)); - server.UDP.RegisterPacketCallback(PacketType.StartPingCheck, new PacketCallback(StartPingCheckHandler)); - server.UDP.RegisterPacketCallback(PacketType.LogoutRequest, new PacketCallback(LogoutRequestHandler)); + server.UDP.RegisterPacketCallback(PacketType.UseCircuitCode, UseCircuitCodeHandler); + server.UDP.RegisterPacketCallback(PacketType.StartPingCheck, StartPingCheckHandler); + server.UDP.RegisterPacketCallback(PacketType.LogoutRequest, LogoutRequestHandler); } public void Stop() diff --git a/Programs/Simian/Extensions/FriendManager.cs b/Programs/Simian/Extensions/FriendManager.cs index bb01cfb6..64598009 100644 --- a/Programs/Simian/Extensions/FriendManager.cs +++ b/Programs/Simian/Extensions/FriendManager.cs @@ -35,77 +35,73 @@ namespace Simian.Extensions { lock (server.Agents) { - foreach (Agent recipient in server.Agents.Values) + // HACK: Only works for agents currently online + Agent recipient; + if (server.Agents.TryGetValue(im.MessageBlock.ToAgentID, out recipient)) { - if (recipient.AgentID == im.MessageBlock.ToAgentID) + ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket(); + sendIM.MessageBlock.RegionID = UUID.Random(); //FIXME + sendIM.MessageBlock.ParentEstateID = 1; + sendIM.MessageBlock.FromGroup = false; + sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.Avatar.Name); + sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID; + sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog; + sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online; + sendIM.MessageBlock.ID = agent.AgentID; + sendIM.MessageBlock.Message = im.MessageBlock.Message; + sendIM.MessageBlock.BinaryBucket = new byte[0]; + sendIM.MessageBlock.Timestamp = 0; + sendIM.MessageBlock.Position = agent.Avatar.Position; + + sendIM.AgentData.AgentID = agent.AgentID; + + server.UDP.SendPacket(recipient.AgentID, sendIM, PacketCategory.Transaction); + + if (dialog == InstantMessageDialog.FriendshipAccepted) { - ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket(); - sendIM.MessageBlock.RegionID = UUID.Random(); //FIXME - sendIM.MessageBlock.ParentEstateID = 1; - sendIM.MessageBlock.FromGroup = false; - sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.Avatar.Name); - sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID; - sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog; - sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online; - sendIM.MessageBlock.ID = agent.AgentID; - sendIM.MessageBlock.Message = im.MessageBlock.Message; - sendIM.MessageBlock.BinaryBucket = new byte[0]; - sendIM.MessageBlock.Timestamp = 0; - sendIM.MessageBlock.Position = agent.Avatar.Position; + bool receiverOnline = server.Agents.ContainsKey(agent.AgentID); + bool senderOnline = server.Agents.ContainsKey(recipient.AgentID); - sendIM.AgentData.AgentID = agent.AgentID; - - server.UDP.SendPacket(recipient.AgentID, sendIM, PacketCategory.Transaction); - - if (dialog == InstantMessageDialog.FriendshipAccepted) + if (receiverOnline) { - bool receiverOnline = server.Agents.ContainsKey(agent.AgentID); - bool senderOnline = server.Agents.ContainsKey(recipient.AgentID); - - if (receiverOnline) - { - if (senderOnline) - { - OnlineNotificationPacket notify = new OnlineNotificationPacket(); - notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0]; - notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock(); - notify.AgentBlock[0].AgentID = agent.AgentID; - server.UDP.SendPacket(recipient.AgentID, notify, PacketCategory.State); - } - else - { - OfflineNotificationPacket notify = new OfflineNotificationPacket(); - notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0]; - notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock(); - notify.AgentBlock[0].AgentID = agent.AgentID; - server.UDP.SendPacket(recipient.AgentID, notify, PacketCategory.State); - } - } - if (senderOnline) { - if (receiverOnline) - { - OnlineNotificationPacket notify = new OnlineNotificationPacket(); - notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0]; - notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock(); - notify.AgentBlock[0].AgentID = recipient.AgentID; - server.UDP.SendPacket(agent.AgentID, notify, PacketCategory.State); - } - else - { - OfflineNotificationPacket notify = new OfflineNotificationPacket(); - notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0]; - notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock(); - notify.AgentBlock[0].AgentID = recipient.AgentID; - server.UDP.SendPacket(agent.AgentID, notify, PacketCategory.State); - } + OnlineNotificationPacket notify = new OnlineNotificationPacket(); + notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0]; + notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock(); + notify.AgentBlock[0].AgentID = agent.AgentID; + server.UDP.SendPacket(recipient.AgentID, notify, PacketCategory.State); } + else + { + OfflineNotificationPacket notify = new OfflineNotificationPacket(); + notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0]; + notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock(); + notify.AgentBlock[0].AgentID = agent.AgentID; + server.UDP.SendPacket(recipient.AgentID, notify, PacketCategory.State); + } + } - } - - break; - } + if (senderOnline) + { + if (receiverOnline) + { + OnlineNotificationPacket notify = new OnlineNotificationPacket(); + notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0]; + notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock(); + notify.AgentBlock[0].AgentID = recipient.AgentID; + server.UDP.SendPacket(agent.AgentID, notify, PacketCategory.State); + } + else + { + OfflineNotificationPacket notify = new OfflineNotificationPacket(); + notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0]; + notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock(); + notify.AgentBlock[0].AgentID = recipient.AgentID; + server.UDP.SendPacket(agent.AgentID, notify, PacketCategory.State); + } + } + } } } } diff --git a/Programs/Simian/Extensions/Messaging.cs b/Programs/Simian/Extensions/Messaging.cs index d9d715aa..c0de013a 100644 --- a/Programs/Simian/Extensions/Messaging.cs +++ b/Programs/Simian/Extensions/Messaging.cs @@ -58,30 +58,27 @@ namespace Simian.Extensions { lock (server.Agents) { - foreach (Agent recipient in server.Agents.Values) + // HACK: Only works for agents currently online + Agent recipient; + if (server.Agents.TryGetValue(im.MessageBlock.ToAgentID, out recipient)) { - if (recipient.AgentID == im.MessageBlock.ToAgentID) - { - ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket(); - sendIM.MessageBlock.RegionID = UUID.Random(); //FIXME - sendIM.MessageBlock.ParentEstateID = 1; - sendIM.MessageBlock.FromGroup = false; - sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.Avatar.Name); - sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID; - sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog; - sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online; - sendIM.MessageBlock.ID = agent.AgentID; - sendIM.MessageBlock.Message = im.MessageBlock.Message; - sendIM.MessageBlock.BinaryBucket = new byte[0]; - sendIM.MessageBlock.Timestamp = 0; - sendIM.MessageBlock.Position = agent.Avatar.Position; + ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket(); + sendIM.MessageBlock.RegionID = UUID.Random(); //FIXME + sendIM.MessageBlock.ParentEstateID = 1; + sendIM.MessageBlock.FromGroup = false; + sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.Avatar.Name); + sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID; + sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog; + sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online; + sendIM.MessageBlock.ID = agent.AgentID; + sendIM.MessageBlock.Message = im.MessageBlock.Message; + sendIM.MessageBlock.BinaryBucket = new byte[0]; + sendIM.MessageBlock.Timestamp = 0; + sendIM.MessageBlock.Position = agent.Avatar.Position; - sendIM.AgentData.AgentID = agent.AgentID; + sendIM.AgentData.AgentID = agent.AgentID; - server.UDP.SendPacket(recipient.AgentID, sendIM, PacketCategory.Transaction); - - break; - } + server.UDP.SendPacket(recipient.AgentID, sendIM, PacketCategory.Transaction); } } } diff --git a/Programs/Simian/Extensions/Money.cs b/Programs/Simian/Extensions/Money.cs index 6c5b9bd0..8364360e 100644 --- a/Programs/Simian/Extensions/Money.cs +++ b/Programs/Simian/Extensions/Money.cs @@ -54,18 +54,15 @@ namespace Simian.Extensions lock (server.Agents) { - foreach (Agent recipient in server.Agents.Values) + // HACK: Only works for sending money to someone who is online + Agent recipient; + if (server.Agents.TryGetValue(request.MoneyData.DestID, out recipient)) { - if (recipient.AgentID == request.MoneyData.DestID) - { - agent.Balance -= request.MoneyData.Amount; - recipient.Balance += request.MoneyData.Amount; + agent.Balance -= request.MoneyData.Amount; + recipient.Balance += request.MoneyData.Amount; - SendBalance(agent, UUID.Zero, String.Format("You paid L${0} to {1}.", request.MoneyData.Amount, recipient.Avatar.Name)); - SendBalance(agent, UUID.Zero, String.Format("{1} paid you L${0}.", request.MoneyData.Amount, agent.Avatar.Name)); - - break; - } + SendBalance(agent, UUID.Zero, String.Format("You paid L${0} to {1}.", request.MoneyData.Amount, recipient.Avatar.Name)); + SendBalance(agent, UUID.Zero, String.Format("{1} paid you L${0}.", request.MoneyData.Amount, agent.Avatar.Name)); } } } diff --git a/Programs/Simian/Extensions/UDPManager.cs b/Programs/Simian/Extensions/UDPManager.cs index 6da03c9e..7709deaa 100644 --- a/Programs/Simian/Extensions/UDPManager.cs +++ b/Programs/Simian/Extensions/UDPManager.cs @@ -22,10 +22,13 @@ namespace Simian public int ResendCount; /// Environment.TickCount when this packet was last sent over the wire public int TickCount; + /// Category this packet belongs to + public PacketCategory Category; - public OutgoingPacket(Packet packet) + public OutgoingPacket(Packet packet, PacketCategory category) { Packet = packet; + Category = category; } } @@ -98,11 +101,6 @@ namespace Simian return udpServer.RemoveClient(agent); } - public bool RemoveClient(Agent agent, IPEndPoint endpoint) - { - return udpServer.RemoveClient(agent, endpoint); - } - public uint CreateCircuit(Agent agent) { return udpServer.CreateCircuit(agent); @@ -176,11 +174,6 @@ namespace Simian return false; } - public bool RemoveClient(Agent agent, IPEndPoint endpoint) - { - return clients.Remove(agent.AgentID, endpoint); - } - public uint CreateCircuit(Agent agent) { uint circuitCode = (uint)Interlocked.Increment(ref currentCircuitCode); @@ -197,7 +190,7 @@ namespace Simian public void BroadcastPacket(Packet packet, PacketCategory category) { clients.ForEach( - delegate(UDPClient client) { SendPacket(client, packet, category, true); }); + delegate(UDPClient client) { SendPacket(client, new OutgoingPacket(packet, category)); }); } public void SendPacket(UUID agentID, Packet packet, PacketCategory category) @@ -211,16 +204,19 @@ namespace Simian return; } - SendPacket(client, packet, category, true); + SendPacket(client, new OutgoingPacket(packet, category)); } - void SendPacket(UDPClient client, Packet packet, PacketCategory category, bool setSequence) + void SendPacket(UDPClient client, OutgoingPacket outgoingPacket) { + Packet packet = outgoingPacket.Packet; byte[] buffer; int bytes; - // Set sequence implies that this is not a resent packet - if (setSequence) + // Update the sent time for this packet + outgoingPacket.TickCount = Environment.TickCount; + + if (!packet.Header.Resent) { // Reset to zero if we've hit the upper sequence number limit Interlocked.CompareExchange(ref client.CurrentSequence, 0, 0xFFFFFF); @@ -230,71 +226,55 @@ namespace Simian if (packet.Header.Reliable) { - OutgoingPacket outgoing; + // Add this packet to the list of ACK responses we are waiting on from this client + lock (client.NeedAcks) + client.NeedAcks[sequence] = outgoingPacket; - if (packet.Header.Resent && client.NeedAcks.TryGetValue(packet.Header.Sequence, out outgoing)) + // This packet is reliable and not a resend, check if the conditions are favorable + // to ACK appending + if (packet.Type != PacketType.PacketAck) { - // 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) + lock (client.PendingAcks) { - Logger.DebugLog(String.Format("Purging ACKs from packet #{0} ({1}) which will be resent.", - packet.Header.Sequence, packet.GetType())); + int count = client.PendingAcks.Count; - lock (client.PendingAcks) + if (count > 0 && count < 10) { - foreach (uint ack in packet.Header.AckList) - { - if (!client.PendingAcks.ContainsKey(ack)) - client.PendingAcks[ack] = ack; - } - } + // Append all of the queued up outgoing ACKs to this packet + packet.Header.AckList = new uint[count]; - 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); + for (int i = 0; i < count; i++) + packet.Header.AckList[i] = client.PendingAcks.Values[i]; - // 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; - } + 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) + } + else + { + // 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) { - // 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); + 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]; } } @@ -345,7 +325,7 @@ namespace Simian acks.Packets[0] = new PacketAckPacket.PacketsBlock(); acks.Packets[0].ID = ack; - SendPacket(client, acks, PacketCategory.Overhead, true); + SendPacket(client, new OutgoingPacket(acks, PacketCategory.Overhead)); } public void SendAcks(UDPClient client) @@ -378,19 +358,29 @@ namespace Simian } if (acks != null) - SendPacket(client, acks, PacketCategory.Overhead, true); + SendPacket(client, new OutgoingPacket(acks, PacketCategory.Overhead)); } public void ResendUnacked(UDPClient client) { - lock (client.NeedAcks) + if (client.NeedAcks.Count > 0) { - List dropAck = new List(); + OutgoingPacket[] array; int now = Environment.TickCount; - // Resend packets - foreach (OutgoingPacket outgoing in client.NeedAcks.Values) + lock (client.NeedAcks) { + // Create a temporary copy of the outgoing packets array to iterate over + array = new OutgoingPacket[client.NeedAcks.Count]; + client.NeedAcks.Values.CopyTo(array, 0); + } + + // Resend packets + for (int i = 0; i < array.Length; i++) + { + OutgoingPacket outgoing = array[i]; + + // FIXME: Make 4000 and 3 .ini settings if (outgoing.TickCount != 0 && now - outgoing.TickCount > 4000) { if (outgoing.ResendCount < 3) @@ -398,12 +388,15 @@ namespace Simian Logger.DebugLog(String.Format("Resending packet #{0} ({1}), {2}ms have passed", outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), now - outgoing.TickCount)); - outgoing.TickCount = Environment.TickCount; + // The TickCount will be set to the current time when the packet + // is actually sent out again + outgoing.TickCount = 0; outgoing.Packet.Header.Resent = true; ++outgoing.ResendCount; + //++Stats.ResentPackets; - SendPacket(client, outgoing.Packet, PacketCategory.Overhead, false); + SendPacket(client, outgoing); } else { @@ -411,10 +404,10 @@ namespace Simian outgoing.Packet.Header.Sequence, outgoing.Packet.GetType(), outgoing.ResendCount), Helpers.LogLevel.Warning); - dropAck.Add(outgoing.Packet.Header.Sequence); + lock (client.NeedAcks) client.NeedAcks.Remove(outgoing.Packet.Header.Sequence); //Disconnect an agent if no packets are received for some time - //TODO: 60000 should be a setting somewhere. + //FIXME: Make 60000 an .ini setting if (Environment.TickCount - client.Agent.TickLastPacketReceived > 60000) { Logger.Log(String.Format("Ack timeout for {0}, disconnecting", client.Agent.Avatar.Name), @@ -426,12 +419,6 @@ namespace Simian } } } - - if (dropAck.Count != 0) - { - for (int i = 0; i < dropAck.Count; i++) - client.NeedAcks.Remove(dropAck[i]); - } } } @@ -470,6 +457,7 @@ namespace Simian Agent agent; if (CompleteAgentConnection(useCircuitCode.CircuitCode.Code, out agent)) { + // FIXME: Sanity check that the agent isn't already logged in here AddClient(agent, address); if (clients.TryGetValue(agent.AgentID, out client)) { @@ -607,35 +595,20 @@ namespace Simian } } - bool TryGetUnassociatedAgent(uint circuitCode, out Agent agent) - { - if (unassociatedAgents.TryGetValue(circuitCode, out agent)) - { - lock (unassociatedAgents) - unassociatedAgents.Remove(circuitCode); - - return true; - } - else - { - return false; - } - } - bool CompleteAgentConnection(uint circuitCode, out Agent agent) { - if (unassociatedAgents.TryGetValue(circuitCode, out agent)) + lock (unassociatedAgents) { - lock (server.Agents) - server.Agents[agent.AgentID] = agent; - lock (unassociatedAgents) + if (unassociatedAgents.TryGetValue(circuitCode, out agent)) + { unassociatedAgents.Remove(circuitCode); - - return true; - } - else - { - return false; + lock (server.Agents) server.Agents[agent.AgentID] = agent; + return true; + } + else + { + return false; + } } } } diff --git a/Programs/Simian/Interfaces/IUDPProvider.cs b/Programs/Simian/Interfaces/IUDPProvider.cs index ced107f6..f7351c4e 100644 --- a/Programs/Simian/Interfaces/IUDPProvider.cs +++ b/Programs/Simian/Interfaces/IUDPProvider.cs @@ -36,7 +36,6 @@ namespace Simian { void AddClient(Agent agent, IPEndPoint endpoint); bool RemoveClient(Agent agent); - bool RemoveClient(Agent agent, IPEndPoint endpoint); uint CreateCircuit(Agent agent); void SendPacket(UUID agentID, Packet packet, PacketCategory category); diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs index aac882b6..f06f6469 100644 --- a/Programs/Simian/Simian.cs +++ b/Programs/Simian/Simian.cs @@ -316,7 +316,8 @@ namespace Simian // Get this machine's IP address IPHostEntry addresses = Dns.GetHostByName(Dns.GetHostName()); - IPAddress simIP = addresses.AddressList.Length > 0 ? addresses.AddressList[0] : IPAddress.Loopback; + IPAddress simIP = addresses.AddressList.Length > 0 ? + addresses.AddressList[addresses.AddressList.Length - 1] :IPAddress.Loopback; response.AgentID = agent.AgentID; response.SecureSessionID = agent.SecureSessionID; diff --git a/bin/Simian.ini b/bin/Simian.ini index ec879e7f..42954ce0 100644 --- a/bin/Simian.ini +++ b/bin/Simian.ini @@ -5,7 +5,7 @@ UDPManager ; LLUDP connection management. Allows agents to connect and disconnect from a ; simulator, as well as keeping the UDP connection alive. -ConnectionManager +ConnectionManagement ; Creates an account for anyone who logs in. The account will be registered ; with the account provider so persistence between sessions is possible, but