// This is called from ConnectionListener.OnDataReceieve()->Session.ProcessPacket()->This /// <summary> /// Processes and incoming packet from a client. /// </summary> /// <param name="packet">The ClientPacket to process.</param> public void ProcessPacket(ClientPacket packet) { packetLog.DebugFormat("[{0}] Processing packet {1}", session.LoggingIdentifier, packet.Header.Sequence); NetworkStatistics.C2S_Packets_Aggregate_Increment(); // If the client is requesting a retransmission, pull those packets from the queue and resend them. if (packet.Header.HasFlag(PacketHeaderFlags.RequestRetransmit)) { if (VerifyCRC(packet)) { foreach (uint sequence in packet.HeaderOptional.RetransmitData) { Retransmit(sequence); } NetworkStatistics.C2S_RequestsForRetransmit_Aggregate_Increment(); } return; } // Check if this packet's sequence is a sequence which we have already processed. // There are some exceptions: // Sequence 0 as we have several Seq 0 packets during connect. This also cathes a case where it seems CICMDCommand arrives at any point with 0 sequence value too. // If the only header on the packet is AckSequence. It seems AckSequence can come in with the same sequence value sometimes. if (packet.Header.Sequence <= lastReceivedPacketSequence && packet.Header.Sequence != 0 && !(packet.Header.Flags == PacketHeaderFlags.AckSequence && packet.Header.Sequence == lastReceivedPacketSequence)) { packetLog.WarnFormat("[{0}] Packet {1} received again", session.LoggingIdentifier, packet.Header.Sequence); return; } // Check if this packet's sequence is greater then the next one we should be getting. // If true we must store it to replay once we have caught up. var desiredSeq = lastReceivedPacketSequence + 1; if (packet.Header.Sequence > desiredSeq) { packetLog.DebugFormat("[{0}] Packet {1} received out of order", session.LoggingIdentifier, packet.Header.Sequence); if (!outOfOrderPackets.ContainsKey(packet.Header.Sequence)) { outOfOrderPackets.TryAdd(packet.Header.Sequence, packet); } if (desiredSeq + 2 <= packet.Header.Sequence && DateTime.Now - LastRequestForRetransmitTime > new TimeSpan(0, 0, 1)) { DoRequestForRetransmission(packet.Header.Sequence); } return; } // If we reach here, this is a packet we should proceed with processing. HandlePacket(packet); // Finally check if we have any out of order packets or fragments we need to process; CheckOutOfOrderPackets(); CheckOutOfOrderFragments(); }
// This is called from ConnectionListener.OnDataReceieve()->Session.ProcessPacket()->This /// <summary> /// Processes and incoming packet from a client. /// </summary> /// <param name="packet">The ClientPacket to process.</param> public void ProcessPacket(ClientPacket packet) { if (isReleased) // Session has been removed { return; } packetLog.DebugFormat("[{0}] Processing packet {1}", session.LoggingIdentifier, packet.Header.Sequence); NetworkStatistics.C2S_Packets_Aggregate_Increment(); if (!packet.VerifyCRC(ConnectionData.CryptoClient, true)) { return; } #region order-insensitive "half-processing" if (packet.Header.HasFlag(PacketHeaderFlags.Disconnect)) { session.Terminate(SessionTerminationReason.PacketHeaderDisconnect); return; } if (packet.Header.HasFlag(PacketHeaderFlags.NetErrorDisconnect)) { session.Terminate(SessionTerminationReason.ClientSentNetworkErrorDisconnect); return; } // If the client is requesting a retransmission process it immediately if (packet.Header.HasFlag(PacketHeaderFlags.RequestRetransmit)) { foreach (uint sequence in packet.HeaderOptional.RetransmitData) { Retransmit(sequence); } NetworkStatistics.C2S_RequestsForRetransmit_Aggregate_Increment(); } // depending on the current session state: // Set the next timeout tick value, to compare against in the WorldManager // Sessions that have gone past the AuthLoginRequest step will stay active for a longer period of time (exposed via configuration) // Sessions that in the AuthLoginRequest will have a short timeout, as set in the AuthenticationHandler.DefaultAuthTimeout. // Example: Applications that check uptime will stay in the AuthLoginRequest state. session.Network.TimeoutTick = (session.State == SessionState.AuthLoginRequest) ? DateTime.UtcNow.AddSeconds(AuthenticationHandler.DefaultAuthTimeout).Ticks : // Default is 15s DateTime.UtcNow.AddSeconds(NetworkManager.DefaultSessionTimeout).Ticks; // Default is 60s #endregion #region Reordering stage // Reordering stage // Check if this packet's sequence is a sequence which we have already processed. // There are some exceptions: // Sequence 0 as we have several Seq 0 packets during connect. This also cathes a case where it seems CICMDCommand arrives at any point with 0 sequence value too. // If the only header on the packet is AckSequence. It seems AckSequence can come in with the same sequence value sometimes. if (packet.Header.Sequence <= lastReceivedPacketSequence && packet.Header.Sequence != 0 && !(packet.Header.Flags == PacketHeaderFlags.AckSequence && packet.Header.Sequence == lastReceivedPacketSequence)) { packetLog.WarnFormat("[{0}] Packet {1} received again", session.LoggingIdentifier, packet.Header.Sequence); return; } // Check if this packet's sequence is greater then the next one we should be getting. // If true we must store it to replay once we have caught up. var desiredSeq = lastReceivedPacketSequence + 1; if (packet.Header.Sequence > desiredSeq) { packetLog.DebugFormat("[{0}] Packet {1} received out of order", session.LoggingIdentifier, packet.Header.Sequence); if (!outOfOrderPackets.ContainsKey(packet.Header.Sequence)) { outOfOrderPackets.TryAdd(packet.Header.Sequence, packet); } if (desiredSeq + 2 <= packet.Header.Sequence && DateTime.Now - LastRequestForRetransmitTime > new TimeSpan(0, 0, 1)) { DoRequestForRetransmission(packet.Header.Sequence); } return; } #endregion #region Final processing stage // Processing stage // If we reach here, this is a packet we should proceed with processing. HandleOrderedPacket(packet); // Process data now in sequence // Finally check if we have any out of order packets or fragments we need to process; CheckOutOfOrderPackets(); CheckOutOfOrderFragments(); #endregion }