Esempio n. 1
0
        /// <summary>
        /// request retransmission of lost sequences
        /// </summary>
        /// <param name="rcvdSeq">the sequence of the packet that was just received.</param>
        private void DoRequestForRetransmission(uint rcvdSeq)
        {
            var         desiredSeq = lastReceivedPacketSequence + 1;
            List <uint> needSeq    = new List <uint>();

            needSeq.Add(desiredSeq);
            uint bottom = desiredSeq + 1;

            for (uint a = bottom; a < rcvdSeq; a++)
            {
                if (!outOfOrderPackets.ContainsKey(a))
                {
                    needSeq.Add(a);
                }
            }

            ServerPacket reqPacket = new ServerPacket();

            byte[]       reqData   = new byte[4 + (needSeq.Count * 4)];
            MemoryStream msReqData = new MemoryStream(reqData);

            msReqData.Write(BitConverter.GetBytes((uint)needSeq.Count), 0, 4);
            needSeq.ForEach(k => msReqData.Write(BitConverter.GetBytes(k), 0, 4));
            reqPacket.Data         = msReqData;
            reqPacket.Header.Flags = PacketHeaderFlags.RequestRetransmit;

            EnqueueSend(reqPacket);

            LastRequestForRetransmitTime = DateTime.Now;
            packetLog.DebugFormat("[{0}] Requested retransmit of {1}", session.LoggingIdentifier, needSeq.Select(k => k.ToString()).Aggregate((a, b) => a + ", " + b));
            NetworkStatistics.S2C_RequestsForRetransmit_Aggregate_Increment();
        }
Esempio n. 2
0
        public bool VerifyCRC(CryptoSystem fq)
        {
            if (Header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
            {
                var key = ((Header.Checksum - headerChecksum) ^ payloadChecksum);
                if (fq.Search(key))
                {
                    fq.ConsumeKey(key);
                    return(true);
                }
            }
            else
            {
                if (headerChecksum + payloadChecksum == Header.Checksum)
                {
                    packetLog.DebugFormat("{0}", this);
                    return(true);
                }

                packetLog.DebugFormat("{0}, Checksum Failed", this);
            }

            NetworkStatistics.C2S_CRCErrors_Aggregate_Increment();

            return(false);
        }
Esempio n. 3
0
        // 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();
        }
Esempio n. 4
0
        private void SendPacket(ServerPacket packet)
        {
            packetLog.DebugFormat("[{0}] Sending packet {1}", session.LoggingIdentifier, packet.GetHashCode());
            NetworkStatistics.S2C_Packets_Aggregate_Increment();

            if (packet.Header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
            {
                uint issacXor = ConnectionData.IssacServer.GetOffset();
                packetLog.DebugFormat("[{0}] Setting Issac for packet {1} to {2}", session.LoggingIdentifier, packet.GetHashCode(), issacXor);
                packet.IssacXor = issacXor;
            }

            SendPacketRaw(packet);
        }
Esempio n. 5
0
        const uint MaxNumNakSeqIds = 115; //464 + header = 484;  (464 - 4) / 4

        /// <summary>
        /// request retransmission of lost sequences
        /// </summary>
        /// <param name="rcvdSeq">the sequence of the packet that was just received.</param>
        private void DoRequestForRetransmission(uint rcvdSeq)
        {
            var         desiredSeq = lastReceivedPacketSequence + 1;
            List <uint> needSeq    = new List <uint>();

            needSeq.Add(desiredSeq);
            uint bottom = desiredSeq + 1;

            if (rcvdSeq < bottom || rcvdSeq - bottom > CryptoSystem.MaximumEffortLevel)
            {
                session.Terminate(SessionTerminationReason.AbnormalSequenceReceived);
                return;
            }
            uint seqIdCount = 1;

            for (uint a = bottom; a < rcvdSeq; a++)
            {
                if (!outOfOrderPackets.ContainsKey(a))
                {
                    needSeq.Add(a);
                    seqIdCount++;
                    if (seqIdCount >= MaxNumNakSeqIds)
                    {
                        break;
                    }
                }
            }

            ServerPacket reqPacket = new ServerPacket();

            byte[]       reqData   = new byte[4 + (needSeq.Count * 4)];
            MemoryStream msReqData = new MemoryStream(reqData, 0, reqData.Length, true, true);

            msReqData.Write(BitConverter.GetBytes((uint)needSeq.Count), 0, 4);
            needSeq.ForEach(k => msReqData.Write(BitConverter.GetBytes(k), 0, 4));
            reqPacket.Data         = msReqData;
            reqPacket.Header.Flags = PacketHeaderFlags.RequestRetransmit;

            EnqueueSend(reqPacket);

            LastRequestForRetransmitTime = DateTime.UtcNow;
            packetLog.DebugFormat("[{0}] Requested retransmit of {1}", session.LoggingIdentifier, needSeq.Select(k => k.ToString()).Aggregate((a, b) => a + ", " + b));
            NetworkStatistics.S2C_RequestsForRetransmit_Aggregate_Increment();
        }
Esempio n. 6
0
        private bool VerifyCRC(ClientPacket packet)
        {
            bool encryptedChecksum =
                !packet.Header.HasFlag(PacketHeaderFlags.RequestRetransmit) &&
                packet.Header.HasFlag(PacketHeaderFlags.EncryptedChecksum);

            if (encryptedChecksum)
            {
#if NETDIAG
                int?gen = GetGeneration(ConnectionData.IssacClient, packet);
                if (gen != null)
                {
                    // gen should always be 1 notch forward, but some programming errors have revealed gen to be 2 or more and since fixed
                    // generational ISSAC helps immensely when troubleshooting certain kinds of protocol problems
                    ConnectionData.IssacClient = GetGeneration(ConnectionData.IssacClient, gen.Value);
                    if (gen.Value != 1)
                    {
                        packetLog.Warn($"Packet CRC encryption generation out of sequence for packet {packet.Header.Sequence} gen {gen} {UnfoldFlags(packet.Header.Flags)}");
                    }
                    packetLog.Debug($"Verified encrypted CRC for packet {packet.Header.Sequence} gen {gen} {UnfoldFlags(packet.Header.Flags)}");
                    return(true);
                }
#else
                if (packet.VerifyChecksum(ConnectionData.IssacClient.GetOffset()))
                {
                    return(true);
                }
#endif
            }
            else
            {
                if (packet.VerifyChecksum(0))
                {
                    packetLog.Debug($"Verified CRC for packet {packet.Header.Sequence} {UnfoldFlags(packet.Header.Flags)}");
                    return(true);
                }
            }
            NetworkStatistics.C2S_CRCErrors_Aggregate_Increment();
            return(false);
        }
Esempio n. 7
0
 public bool VerifyCRC(CryptoSystem fq, bool rangeAdvance)
 {
     if (Header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
     {
         if (VerifyEncryptedCRCAndLogResult(fq, rangeAdvance))
         {
             CRCVerified = true;
             return(true);
         }
     }
     else
     {
         if (Header.HasFlag(PacketHeaderFlags.RequestRetransmit))
         {
             // discard retransmission request with cleartext CRC
             // client sends one encrypted version and one non encrypted version of each retransmission request
             // honoring these causes client to drop because it's only expecting one of the two retransmission requests to be honored
             // and it's more secure to only accept the trusted version
             return(false);
         }
         else
         {
             if (VerifyChecksum(0))
             {
                 packetLog.Debug($"{this}");
                 return(true);
             }
             else
             {
                 packetLog.Debug($"{this}, Checksum Failed");
             }
         }
     }
     NetworkStatistics.C2S_CRCErrors_Aggregate_Increment();
     return(false);
 }
Esempio n. 8
0
        public bool VerifyCRC(CryptoSystem fq)
        {
            if (Header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
            {
                if (VerifyEncryptedCRCAndLogResult(fq))
                {
                    return(true);
                }
            }
            else
            {
                if (VerifyChecksum())
                {
                    packetLog.DebugFormat("{0}", this);
                    return(true);
                }

                packetLog.DebugFormat("{0}, Checksum Failed", this);
            }

            NetworkStatistics.C2S_CRCErrors_Aggregate_Increment();

            return(false);
        }
Esempio n. 9
0
        // 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
        }