public void ResendUnacked(LLAgent agent) { //FIXME: Make this an .ini setting const int AGENT_TIMEOUT_MS = 1000 * 60; // Disconnect an agent if no packets are received for some time if (Util.TickCount() - agent.TickLastPacketReceived > AGENT_TIMEOUT_MS) { m_log.Warn("Ack timeout, disconnecting " + agent.ID); ShutdownClient(agent); return; } // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO List <OutgoingPacket> expiredPackets = agent.NeedAcks.GetExpiredPackets(agent.RTO); if (expiredPackets != null) { //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); // Exponential backoff of the retransmission timeout agent.BackoffRTO(); // Resend packets for (int i = 0; i < expiredPackets.Count; i++) { OutgoingPacket outgoingPacket = expiredPackets[i]; //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); // Set the resent flag outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); outgoingPacket.Category = ThrottleCategory.Resend; // Bump up the resend count on this packet Interlocked.Increment(ref outgoingPacket.ResendCount); Interlocked.Increment(ref m_packetsResent); // Requeue or resend the packet if (!agent.EnqueueOutgoing(outgoingPacket)) { SendPacketFinal(outgoingPacket); } } } }
public void SendPacketData(LLAgent agent, byte[] data, PacketType type, ThrottleCategory category) { int dataLength = data.Length; bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; bool doCopy = true; // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here // to accomodate for both common scenarios and provide ample room for ACK appending in both int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; UDPPacketBuffer buffer = new UDPPacketBuffer(agent.RemoteEndPoint, bufferSize); // Zerocode if needed if (doZerocode) { try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); doCopy = false; } catch (IndexOutOfRangeException) { // The packet grew larger than the bufferSize while zerocoding. // Remove the MSG_ZEROCODED flag and send the unencoded data // instead m_log.Debug("Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); } } // If the packet data wasn't already copied during zerocoding, copy it now if (doCopy) { if (dataLength > buffer.Data.Length) { m_log.Error("Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length); buffer.Data = new byte[dataLength]; } Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } buffer.DataLength = dataLength; #region Queue or Send OutgoingPacket outgoingPacket = new OutgoingPacket(agent, buffer, category, type); if (!agent.EnqueueOutgoing(outgoingPacket)) SendPacketFinal(outgoingPacket); #endregion Queue or Send }
public void ResendUnacked(LLAgent agent) { //FIXME: Make this an .ini setting const int AGENT_TIMEOUT_MS = 1000 * 60; // Disconnect an agent if no packets are received for some time if (Util.TickCount() - agent.TickLastPacketReceived > AGENT_TIMEOUT_MS) { m_log.Warn("Ack timeout, disconnecting " + agent.ID); ShutdownClient(agent); return; } // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO List<OutgoingPacket> expiredPackets = agent.NeedAcks.GetExpiredPackets(agent.RTO); if (expiredPackets != null) { //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); // Exponential backoff of the retransmission timeout agent.BackoffRTO(); // Resend packets for (int i = 0; i < expiredPackets.Count; i++) { OutgoingPacket outgoingPacket = expiredPackets[i]; //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); // Set the resent flag outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); outgoingPacket.Category = ThrottleCategory.Resend; // Bump up the resend count on this packet Interlocked.Increment(ref outgoingPacket.ResendCount); Interlocked.Increment(ref m_packetsResent); // Requeue or resend the packet if (!agent.EnqueueOutgoing(outgoingPacket)) SendPacketFinal(outgoingPacket); } } }
public void SendPacketData(LLAgent agent, byte[] data, PacketType type, ThrottleCategory category) { int dataLength = data.Length; bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; bool doCopy = true; // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here // to accomodate for both common scenarios and provide ample room for ACK appending in both int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; UDPPacketBuffer buffer = new UDPPacketBuffer(agent.RemoteEndPoint, bufferSize); // Zerocode if needed if (doZerocode) { try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); doCopy = false; } catch (IndexOutOfRangeException) { // The packet grew larger than the bufferSize while zerocoding. // Remove the MSG_ZEROCODED flag and send the unencoded data // instead m_log.Debug("Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); } } // If the packet data wasn't already copied during zerocoding, copy it now if (doCopy) { if (dataLength > buffer.Data.Length) { m_log.Error("Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length); buffer.Data = new byte[dataLength]; } Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); } buffer.DataLength = dataLength; #region Queue or Send OutgoingPacket outgoingPacket = new OutgoingPacket(agent, buffer, category, type); if (!agent.EnqueueOutgoing(outgoingPacket)) { SendPacketFinal(outgoingPacket); } #endregion Queue or Send }