void IncomingPacketHandler() { IncomingPacket incomingPacket = new IncomingPacket(); Packet packet = null; UDPClient client = null; while (IsRunning) { // Reset packet to null for the check below packet = null; if (packetInbox.Dequeue(100, ref incomingPacket)) { packet = incomingPacket.Packet; client = incomingPacket.Client; if (packet != null) { #region ACK accounting // Check the archives to see whether we already received this packet lock (client.PacketArchive) { if (client.PacketArchive.Contains(packet.Header.Sequence)) { if (packet.Header.Resent) { Logger.DebugLog("Received resent packet #" + packet.Header.Sequence); } else { Logger.Log(String.Format("Received a duplicate of packet #{0}, current type: {1}", packet.Header.Sequence, packet.Type), Helpers.LogLevel.Warning); } // Avoid firing a callback twice for the same packet continue; } else { // Keep the PacketArchive size within a certain capacity while (client.PacketArchive.Count >= Settings.PACKET_ARCHIVE_SIZE) { client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue(); client.PacketArchive.Dequeue(); } client.PacketArchive.Enqueue(packet.Header.Sequence); } } #endregion ACK accounting #region ACK handling // Handle appended ACKs if (packet.Header.AppendedAcks) { lock (client.NeedAcks) { for (int i = 0; i < packet.Header.AckList.Length; i++) { client.NeedAcks.Remove(packet.Header.AckList[i]); } } } // Handle PacketAck packets if (packet.Type == PacketType.PacketAck) { PacketAckPacket ackPacket = (PacketAckPacket)packet; lock (client.NeedAcks) { for (int i = 0; i < ackPacket.Packets.Length; i++) { client.NeedAcks.Remove(ackPacket.Packets[i].ID); } } } #endregion ACK handling packetEvents.BeginRaiseEvent(packet.Type, packet, client.Agent); } } } }
void SendPacket(UDPClient client, Packet packet, PacketCategory category, 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 client.CurrentSequence, 0, 0xFFFFFF); // Increment and fetch the current sequence number uint sequence = (uint)Interlocked.Increment(ref client.CurrentSequence); packet.Header.Sequence = sequence; if (packet.Header.Reliable) { OutgoingPacket outgoing; if (packet.Header.Resent && client.NeedAcks.TryGetValue(packet.Header.Sequence, out outgoing)) { // 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) { 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]; } } else { // Wrap this packet in a struct to track timeouts and resends outgoing = new OutgoingPacket(packet); // 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; } } } } // Update the sent time for this packet outgoing.TickCount = Environment.TickCount; } 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(client.Address); // 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); }
protected override void PacketReceived(UDPPacketBuffer buffer) { UDPClient client = null; Packet packet = null; int packetEnd = buffer.DataLength - 1; IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; // Decoding try { packet = Packet.BuildPacket(buffer.Data, ref packetEnd, buffer.ZeroData); } catch (MalformedDataException) { Logger.Log(String.Format("Malformed data, cannot parse packet:\n{0}", Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)), Helpers.LogLevel.Error); } // Fail-safe check if (packet == null) { Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning); return; } //Stats.RecvBytes += (ulong)buffer.DataLength; //++Stats.RecvPackets; if (packet.Type == PacketType.UseCircuitCode) { UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; Agent agent; if (CompleteAgentConnection(useCircuitCode.CircuitCode.Code, out agent)) { AddClient(agent, address); if (clients.TryGetValue(agent.AgentID, out client)) { Logger.Log("Activated UDP circuit " + useCircuitCode.CircuitCode.Code, Helpers.LogLevel.Info); } else { Logger.Log("Failed to locate newly created UDPClient", Helpers.LogLevel.Error); return; } } else { Logger.Log("Received a UseCircuitCode packet for an unrecognized circuit: " + useCircuitCode.CircuitCode.Code.ToString(), Helpers.LogLevel.Warning); return; } } else { // Determine which agent this packet came from if (!clients.TryGetValue(address, out client)) { Logger.Log("Received UDP packet from an unrecognized source: " + address.ToString(), Helpers.LogLevel.Warning); return; } } client.Agent.TickLastPacketReceived = Environment.TickCount; // Reliable handling if (packet.Header.Reliable) { // Queue up this sequence number for acknowledgement QueueAck(client, (uint)packet.Header.Sequence); //if (packet.Header.Resent) ++Stats.ReceivedResends; } // Inbox insertion IncomingPacket incomingPacket; incomingPacket.Client = client; incomingPacket.Packet = packet; // TODO: Prioritize the queue packetInbox.Enqueue(incomingPacket); }
public void AddClient(Agent agent, IPEndPoint endpoint) { UDPClient client = new UDPClient(this, agent, endpoint); clients.Add(agent.AgentID, endpoint, client); }