コード例 #1
0
        internal static IntPtr TraceTree(IntPtr handle, IntPtr baseAddr, int[] offsets, int finalOffset)
        {
#if x64
            const int size = 8;
#elif x86
            const int size = 4;
#endif // Arch
            var buffer = new byte[size];
            foreach (var offset in offsets)
            {
                if (!ReadProcessMemory(handle, IntPtr.Add(baseAddr, offset), buffer, size, out _))
                {
                    IpcClient.SendSignal(Signal.InternalException, new[] { "Unable to calculate address: " + Marshal.GetLastWin32Error(), "MemoryCore", "TraceTree" });
                    throw new Exception("Unable to calculate address: " + Marshal.GetLastWin32Error());
                }
#if x64
                baseAddr = new IntPtr(BitConverter.ToInt64(buffer, 0));
#elif x86
                baseAddr = new IntPtr(BitConverter.ToInt32(buffer, 0));
#endif // Arch
                if (baseAddr == IntPtr.Zero)
                {
                    return(IntPtr.Zero);
                }
            }

            return(IntPtr.Add(baseAddr, finalOffset));
        }
コード例 #2
0
        public void Start()
        {
            this._isStopping = false;

            Task.Run(() =>
            {
                Log.Warning("MessageDispatcher Output Thread Started");

                foreach (var data in this._outputQueue.GetConsumingEnumerable())
                {
                    try
                    {
                        var output = data.Consumer(data.Message, data.HeaderLength);

                        data.Listener(data.Header, output);
                        Interlocked.Increment(ref this._messagesDispatched);
                    }
                    catch (Exception e)
                    {
                        IpcClient.SendSignal(Signal.InternalExternalException, new[] { e.Message, e.StackTrace, "MessageDispatcher", "Start" });
                    }
                }

                Log.Warning("MessageDispatcher Output Thread Exited");
            });
        }
コード例 #3
0
        public TCPPacket(byte[] buffer, int ignoreLength)
        {
            try
            {
                GlobalOffset = ignoreLength;

                SourcePort      = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, ignoreLength + 0));
                DestinationPort = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, ignoreLength + 2));

                var offsetAndFlags = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, ignoreLength + 12));
                DataOffset = (byte)((offsetAndFlags >> 12) * 4);
                Flags      = (TCPFlags)(offsetAndFlags & 511); // 0b111111111 = 511

                Payload = buffer.Skip(ignoreLength + DataOffset).ToArray();

                IsValid = true;
            }
            catch
            {
                SourcePort      = 0;
                DestinationPort = 0;
                DataOffset      = 0;
                Flags           = TCPFlags.NONE;

                Payload = null;

                IsValid = false;
                IpcClient.SendSignal(Signal.ClientPacketParseFail, new[] { "unable to tcplize" }, true);
            }
        }
コード例 #4
0
        /// <summary>
        /// Initialize the GameScanner instance with a MemoryReader
        /// </summary>
        /// <param name="purgeCache">If true, pointer cache will not be used</param>
        public void Initialize(bool purgeCache)
        {
            Log.Debug($"GS Initialize - Start Initialize");

            //foreach (ThreadNr threadNr in Enum.GetValues(typeof(ThreadNr)))
            //{
            //    if (_trdPtr.ContainsKey(threadNr)) continue;

            //    if (threadNr == ThreadNr.NoThread) continue;

            //    _trdPtr.Add(threadNr, _reader.GetThreadStack((int)threadNr));

            //    Log.Verbose($"GS Initialize - Scanned Thread Stack {(int)threadNr}: {_trdPtr[threadNr].ToInt64():X}");
            //}

            if (!purgeCache && ReadBaseOffsetCache())
            {
                return;
            }

            var unscanned = new List <SigRecord>();

            foreach (SignatureType signatureType in Enum.GetValues(typeof(SignatureType)))
            {
                if (_sigPtr.ContainsKey(signatureType))
                {
                    continue;
                }

                if (!Signature.SignatureLib.TryGetValue(signatureType, out var pattern))
                {
                    continue;
                }
                unscanned.Add(pattern);
            }

            var result = Search(ref unscanned);

            Log.Warning($"GS Initialize - Unscanned Signature: {string.Join(", ", unscanned.Select(x => Enum.GetName(typeof(SignatureType), x.SelfType)))}");

            foreach (var kvp in result)
            {
                if (kvp.Value != IntPtr.Zero)
                {
                    _sigPtr.Add(kvp.Key, kvp.Value);
                }
            }

            if (!ValidateSignatures())
            {
                IpcClient.SendSignal(Signal.MilvanethNeedUpdate, new[] { "Memory", "ValidateSignatures" });
                throw new InvalidOperationException("Backbone service self validate failed");
            }

            WriteBaseOffsetCache();

            Log.Debug($"GS Initialize - Finish Initialize");
        }
コード例 #5
0
        public int GetMessageId(MessageIdRetriveKey rawId)
        {
            if (msgDic.TryGetValue((int)rawId, out var id))
            {
                return(id);
            }

            IpcClient.SendSignal(Signal.MilvanethNeedUpdate, new[] { "Network", "MessageIdRetriver" });
            throw new FileNotFoundException("Could not read update file");
        }
コード例 #6
0
        internal static int Write(IntPtr handle, IntPtr address, byte[] buffer)
        {
            if (WriteProcessMemory(handle, address, buffer, buffer.Length, out _))
            {
                return(buffer.Length);
            }

            IpcClient.SendSignal(Signal.InternalException, new[] { "Could not write process memory: " + Marshal.GetLastWin32Error(), "MemoryCore", "Write" });
            throw new Exception("Could not write process memory: " + Marshal.GetLastWin32Error());
        }
コード例 #7
0
        internal static void CloseProc(IntPtr ptr)
        {
            if (CloseHandle(ptr))
            {
                return;
            }

            IpcClient.SendSignal(Signal.InternalException, new[] { "Could not close handle: " + Marshal.GetLastWin32Error(), "MemoryCore", "CloseProc" });
            throw new Exception("Could not close handle: " + Marshal.GetLastWin32Error());
        }
コード例 #8
0
        private void Receive(SocketAsyncEventArgs e)
        {
            // Start a new receive operation straight away, without waiting
            StartReceiving();

            try
            {
                if (e.SocketError != SocketError.Success)
                {
                    if (!this._isStopping)
                    {
                        IpcClient.SendSignal(Signal.InternalUnmanagedException,
                                             new[] { $"Socket error: \n{(int) e.SocketError}", "Network", "SocketSniffer", "Receive" });
                    }

                    return;
                }

                if (e.BytesTransferred <= 0)
                {
                    return;
                }

                Interlocked.Increment(ref this._packetsObserved);

                // Copy the bytes received into a new buffer
                var buffer = new byte[e.BytesTransferred];
                Buffer.BlockCopy(e.Buffer, e.Offset, buffer, 0, e.BytesTransferred);

                EnqueueOutput(new TimestampedData(DateTime.UtcNow, buffer));
            }
            catch (SocketException ex)
            {
                IpcClient.SendSignal(Signal.InternalUnmanagedException,
                                     new[]
                {
                    $"Socket exception: {ex.Message} / {ex.HResult} / {Marshal.GetLastWin32Error()}", "Network",
                    "SocketSniffer", "Receive"
                });
            }
            catch (Exception ex)
            {
                IpcClient.SendSignal(Signal.InternalException,
                                     new[] { $"Error: {ex.Message}", "Network", "SocketSniffer", "Receive" });
            }
            finally
            {
                // Put the SocketAsyncEventArgs back into the pool
                if (!this._isStopping && this._socket != null && this._socket.IsBound)
                {
                    this._receivePool.Push(e);
                    this._maxReceiveEnforcer.Release();
                }
            }
        }
コード例 #9
0
        internal static byte[] Read(IntPtr handle, IntPtr address, long size)
        {
            var buffer = new byte[size];

            if (ReadProcessMemory(handle, address, buffer, buffer.Length, out _))
            {
                return(buffer);
            }

            IpcClient.SendSignal(Signal.InternalException, new[] { "Could not read process memory: " + Marshal.GetLastWin32Error(), "MemoryCore", "Read" });
            throw new Exception("Could not read process memory: " + Marshal.GetLastWin32Error());
        }
コード例 #10
0
        internal static IntPtr OpenProc(int pid)
        {
            var ptr = OpenProcess(ProcessFlags, false, pid);

            if (ptr != IntPtr.Zero)
            {
                return(ptr);
            }

            IpcClient.SendSignal(Signal.InternalException, new [] { "Could not open handle: " + Marshal.GetLastWin32Error(), "MemoryCore", "OpenProc" });
            throw new Exception("Could not open handle: " + Marshal.GetLastWin32Error());
        }
コード例 #11
0
        public void AssignSegment(SocketAsyncEventArgs e)
        {
            if (this.nextOffset + this.segmentSize > this.buffer.Length)
            {
                IpcClient.SendSignal(Signal.InternalException, new[] { "Buffer exhausted" });
                IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "Network", "Sniffer" });
                throw new InsufficientMemoryException("Buffer exhausted");
            }

            e.SetBuffer(this.buffer, this.nextOffset, this.segmentSize);
            this.nextOffset += this.segmentSize;
        }
コード例 #12
0
        public static IPEndPoint GetLobbyEndPoint(Process process)
        {
            string lobbyHost = null;
            var    lobbyPort = 0;

            try
            {
                using (var searcher =
                           new ManagementObjectSearcher(
                               "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id))
                {
                    foreach (var @object in searcher.Get())
                    {
                        var commandline = @object["CommandLine"].ToString();
                        var argv        = commandline.Split(' ');

                        foreach (var arg in argv)
                        {
                            var parts = arg.Split('=');

                            if (parts.Length != 2)
                            {
                                continue;
                            }

                            if (parts[0].Contains("LobbyHost01"))
                            {
                                lobbyHost = parts[1];
                            }
                            else if (parts[0].Contains("LobbyPort01"))
                            {
                                lobbyPort = int.Parse(parts[1]);
                            }
                        }
                    }
                }

                if (lobbyHost == null || lobbyPort <= 0)
                {
                    return(null);
                }
            }
            catch (Exception e)
            {
                IpcClient.SendSignal(Signal.InternalException, new [] { $"GetLobbyEndPoint Failed in Connection Picker: \n{e.Message}", "Network", "ConnectionPicker", "GetLobbyEndPoint" });
                return(null);
            }

            var address = Dns.GetHostAddresses(lobbyHost)[0];

            return(new IPEndPoint(address, lobbyPort));
        }
コード例 #13
0
        private void HasProcStop(object sender, EventArrivedEventArgs e)
        {
            var exiting = (uint)e.NewEvent.Properties["ProcessID"].Value;

            if (exiting != _gamePid && exiting != _parentPid)
            {
                return;
            }

            Log.Information($"Exiting Process: {exiting}");
            IpcClient.SendSignal(Signal.ClientProcessDown, new[] { GameProcess?.Id.ToString() ?? "-1" });
            Stopping = true;
        }
コード例 #14
0
 private void EnterPromiscuousMode()
 {
     try
     {
         this._socket.IOControl(IOControlCode.ReceiveAll, BitConverter.GetBytes(1), new byte[4]);
     }
     catch (Exception ex)
     {
         IpcClient.SendSignal(Signal.InternalUnmanagedException,
                              new[]
         {
             $"Unable to enter promiscuous mode: {ex.Message} / {ex.HResult} / {Marshal.GetLastWin32Error()}",
             "Network", "SocketSniffer", "EnterPromiscuousMode"
         });
         IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "Network", "Sniffer" });
         throw;
     }
 }
コード例 #15
0
        private MessageIdRetriver()
        {
            var path = Helper.GetMilFilePathRaw("network.pack");

            if (!File.Exists(path))
            {
                IpcClient.SendSignal(Signal.MilvanethNeedUpdate, new[] { "Network", "MessageIdRetriver" });
                throw new FileNotFoundException("Could not found update file");
            }

            var ser = new Serializer <Dictionary <int, int> >(path, "");

            try
            {
                msgDic = ser.Load();
            }
            catch (Exception e)
            {
                IpcClient.SendSignal(Signal.MilvanethNeedUpdate, new[] { "Network", "MessageIdRetriver" });
                IpcClient.SendSignal(Signal.InternalException, new [] { e.Message, "Network", "MessageIdRetriver", ".ctor" });
                throw new FileNotFoundException("Could not parse update file");
            }
        }
コード例 #16
0
        private MemoryStream GenerateContent(Stream stream, bool isCompressed, ushort length, int offset = -1)
        {
            if (offset >= 0)
            {
                stream.Seek(offset, SeekOrigin.Begin);
            }

            var content = new MemoryStream();

            if (isCompressed)
            {
                var body = new byte[length - HeaderLength - 2];
                stream.Seek(2, SeekOrigin.Current);
                stream.Read(body, 0, body.Length); // pos = length

                try
                {
                    using (var input = new MemoryStream(body))
                        using (var deflate = new DeflateStream(input, CompressionMode.Decompress))
                        {
                            deflate.CopyTo(content);
                        }
                }
                catch
                {
                    IpcClient.SendSignal(Signal.ClientPacketParseFail, new[] { "unable to deflate" }, true);
                }
            }
            else
            {
                var body = new byte[length - HeaderLength];
                stream.Read(body, 0, body.Length); // pos = bundle.Length
                content = new MemoryStream(body);
            }

            return(content);
        }
コード例 #17
0
        private void StartReceiving()
        {
            try
            {
                // Get SocketAsyncEventArgs from pool
                this._maxReceiveEnforcer.Wait();

                if (!this._receivePool.TryPop(out var socketEventArgs))
                {
                    // Because we are controlling access to pooled SocketAsyncEventArgs, this
                    // *should* never happen...
                    IpcClient.SendSignal(Signal.InternalException, new[] { "Connection pool exhausted" });
                    IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "Network", "Sniffer" });
                    throw new Exception("Connection pool exhausted");
                }

                // Returns true if the operation will complete asynchronously, or false if it completed
                // synchronously
                var willRaiseEvent = this._socket.ReceiveAsync(socketEventArgs);

                if (!willRaiseEvent)
                {
                    Receive(socketEventArgs);
                }
            }
            catch (Exception ex)
            {
                // Exceptions while shutting down are expected
                if (!this._isStopping)
                {
                    Log.Error(ex, "Unhandled Error in Sniffer.StartReceiving");
                }

                this._socket.Close();
                this._socket = null;
            }
        }
コード例 #18
0
        public void WaitForProcess()
        {
            while (_gamePid < 0)
            {
                Thread.Sleep(500);
                if (Stopping)
                {
                    throw new OperationCanceledException("Parent exited while hunting");
                }
            }

            var gp = Process.GetProcessById(_gamePid);

            if (!Helper.IsChineseVersion(gp))
            {
                Log.Error("Game process not Chinese version");
                IpcClient.SendSignal(Signal.ClientProcessDown, new[] { _gamePid.ToString() });
                IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "GameStatusManager", ".ctor" });
                throw new InvalidOperationException("Target process is not a FFXIV DX11 process");
            }

            if (!SystemInformation.IsAdmin())
            {
                Log.Error("Insufficient Privilege");
                IpcClient.SendSignal(Signal.ClientInsuffcientPrivilege, new[] { _gamePid.ToString() });
                IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "GameStatusManager", ".ctor" });
                throw new InvalidOperationException("Insufficient Privilege");
            }

            GameProcess     = gp;
            GameConnection  = new List <Connection>();
            LobbyConnection = new List <Connection>();
            _connEqCp       = new ConnectionEqualityComparer();
            _connSetEqCp    = new MultiSetComparer <Connection>(_connEqCp);
            _lobbyEndPoint  = ConnectionPicker.GetLobbyEndPoint(GameProcess);
        }
コード例 #19
0
ファイル: Program.cs プロジェクト: ShadyWhite/Milvaneth
        static void Main(string[] args)
        {
            int counter = 0;

            try
            {
                SetupEnvironment(args);
                RegisterNotification();

                #region Register

                _gsm = new GameStatusManager(_gamePid, _parentPid);

                Log.Verbose("Waiting Game Process");

                _gsm.WaitForProcess();

                Log.Verbose($"Found Game Process {_gsm.GameProcess.Id}");

                _gnm = new GameNetworkMonitor(_gsm.GameProcess);
                _gmm = new GameMemoryMonitor(_gsm.GameProcess);
                _gdm = new GameDataManager();

                _gnm.Subscribe(NetworkCharacterName.GetMessageId(), _gdm.HandleNetworkCharacterName);
                _gnm.Subscribe(NetworkItemInfo.GetMessageId(), _gdm.HandleNetworkItemInfo);
                _gnm.Subscribe(NetworkItemPriceInfo.GetMessageId(), _gdm.HandleNetworkItemPriceInfo);
                _gnm.Subscribe(NetworkItemInfoEnd.GetMessageId(), _gdm.HandleNetworkItemInfoEnd);
                _gnm.Subscribe(NetworkLogout.GetMessageId(), _gdm.HandleNetworkLogout);
                _gnm.Subscribe(NetworkMarketHistory.GetMessageId(), _gdm.HandleNetworkMarketHistory);
                _gnm.Subscribe(NetworkMarketListingCount.GetMessageId(), _gdm.HandleNetworkMarketListingCount);
                _gnm.Subscribe(NetworkMarketListing.GetMessageId(), _gdm.HandleNetworkMarketListing);
                _gnm.Subscribe(NetworkMarketResult.GetMessageId(), _gdm.HandleNetworkMarketResult);
                _gnm.Subscribe(NetworkRetainerHistory.GetMessageId(), _gdm.HandleNetworkRetainerHistory);
                _gnm.Subscribe(NetworkRetainerSummary.GetMessageId(), _gdm.HandleNetworkRetainerSummary);
                _gnm.Subscribe(NetworkRetainerSumEnd.GetMessageId(), _gdm.HandleNetworkRetainerSumEnd);
                _gnm.Subscribe(NetworkLobbyService.GetMessageId(), _gdm.HandleLobbyService);
                _gnm.Subscribe(NetworkLobbyCharacter.GetMessageId(), _gdm.HandleLobbyCharacter);
                _gnm.Subscribe(NetworkClientTrigger.GetMessageId(), _gdm.HandleClientTrigger);
                _gnm.Subscribe(NetworkRequestRetainer.GetMessageId(), _gdm.HandleRequestRetainer);
                _gnm.Subscribe(NetworkInventoryModify.GetMessageId(), _gdm.HandleInventoryModify);
                _gnm.Subscribe(NetworkPlayerSpawn.GetMessageId(), _gdm.HandleNetworkPlayerSpawn);

                _gsm.OnLobbyUpdate    += LobbyUpdate;
                _gsm.OnWorldStart     += WorldStart;
                _gsm.OnWorldStop      += WorldStop;
                _gsm.OnGlobalStart    += GlobalStart;
                _gsm.OnGlobalStop     += GlobalStop;
                _gmm.OnChatlogUpdated += PackLogData;
                _gdm.OnGameLoggingOut += _gsm.SuspectNetworkStop;
                _gdm.OnDataReady      += IpcClient.SendData;
                _gdm.OnRequestScan    += _gmm.GetInventory;
                _gsm.GetPacketAmount  += () => _gnm.PacketsAnalyzed;

                #endregion

                _gsm.StartMonitoringService();

                Log.Warning("Main thread started");

                while (!_gsm.Stopping)
                {
                    counter++;
                    if (counter > 60)
                    {
                        counter = 0;
                        Log.Debug(
                            $"SysLoad: {_gnm?.PacketsObserved:x}" +
                            $"/{_gnm?.PacketsCaptured}" +
                            $"/{_gnm?.PacketsAnalyzed}" +
                            $"/{_gnm?.MessagesProcessed}" +
                            $"/{_gnm?.MessagesDispatched}" +
                            $"/{_gmm?.ScanCycles}" +
                            $"/{_gmm?.LinesRead}" +
                            $"/{IpcClient.PacketSent}");
                    }

                    _gdm.ScheduledTasks();

                    Thread.Sleep(1000);
                }

                Log.Warning("Main thread expected exiting");
            }
            catch (OperationCanceledException)
            {
                // Well, this IS expected literally.
                Log.Warning("Main thread expected exiting");
            }
            catch (Exception e)
            {
                Log.Error(e, $"Main thread unexpected exiting");
            }
            finally
            {
                try { _gsm.Dispose(); } catch { /* ignored */ }
                try { _gmm.Dispose(); } catch { /* ignored */ }
                try { _gnm.Dispose(); } catch { /* ignored */ }
                try { _gdm.Dispose(); } catch { /* ignored */ }

                IpcClient.SendSignal(Signal.MilvanethSubprocessExit, new[] { "Graceful Exit", "Milvaneth.Cmd", "Main Thread" });
                try { IpcClient.Dispose(); } catch { /* ignored */ }

                Log.Fatal("Main thread exited in Program.Main");
                Environment.Exit(0);
            }
        }
コード例 #20
0
        public static List <Connection> GetConnections(Process process)
        {
            var connections = new List <Connection>();

            var tcpTable       = IntPtr.Zero;
            var tcpTableLength = 0;

            if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, AddressFamily.InterNetwork,
                                                  NativeMethods.TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_CONNECTIONS) == 0)
            {
                return(connections);
            }

            try
            {
                tcpTable = Marshal.AllocHGlobal(tcpTableLength);
                if (NativeMethods.GetExtendedTcpTable(tcpTable, ref tcpTableLength, false, AddressFamily.InterNetwork,
                                                      NativeMethods.TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_CONNECTIONS) == 0)
                {
                    var table = (NativeMethods.TcpTable)Marshal.PtrToStructure(tcpTable,
                                                                               typeof(NativeMethods.TcpTable));

                    var rowPtr = new IntPtr(tcpTable.ToInt64() + Marshal.SizeOf(typeof(uint)));
                    for (var i = 0; i < table.length; i++)
                    {
                        var row = (NativeMethods.TcpRow)Marshal.PtrToStructure(rowPtr, typeof(NativeMethods.TcpRow));

                        if (row.owningPid == process.Id)
                        {
                            var local = new IPEndPoint(row.localAddr,
                                                       (ushort)IPAddress.NetworkToHostOrder((short)row.localPort));
                            var remote = new IPEndPoint(row.remoteAddr,
                                                        (ushort)IPAddress.NetworkToHostOrder((short)row.remotePort));
                            connections.Add(new Connection(local, remote));
                        }

                        rowPtr = new IntPtr(rowPtr.ToInt64() + Marshal.SizeOf(typeof(NativeMethods.TcpRow)));
                    }
                }
                else
                {
                    IpcClient.SendSignal(Signal.InternalUnmanagedException,
                                         new [] { $"GetExtendedTcpTable Failed in Connection Picker: {Marshal.GetLastWin32Error()}", "Network", "ConnectionPicker", "GetConnections" });
                    if (connections.Count == 0)
                    {
                        IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "Network", "ConnectionPicker" });
                    }
                }
            }
            catch (Exception ex)
            {
                IpcClient.SendSignal(Signal.InternalException, new [] { ex.Message, "Network", "ConnectionPicker", "GetConnections" });
                if (connections.Count == 0)
                {
                    IpcClient.SendSignal(Signal.MilvanethComponentExit, new[] { "Network", "ConnectionPicker" });
                }
            }
            finally
            {
                if (tcpTable != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(tcpTable);
                }
            }

            return(connections);
        }
コード例 #21
0
ファイル: Program.cs プロジェクト: ShadyWhite/Milvaneth
 private static void GlobalStart()
 {
     Log.Fatal("Logic Start");
     IpcClient.SendSignal(Signal.MilvanethSubprocessReady, new[] { _gsm.GameProcess.Id.ToString() });
 }
コード例 #22
0
        public unsafe void Output(TimestampedData timestampedData)
        {
            if (timestampedData.Protocol != 6)
            {
                return;                                // TCP
            }
            var mark      = timestampedData.RouteMark;
            var tcpPacket = new TCPPacket(timestampedData.Data, timestampedData.HeaderLength);

            if (!tcpPacket.IsValid || (tcpPacket.Flags & TCPFlags.ACK) != TCPFlags.ACK)
            {
                if ((tcpPacket.Flags & FlagFinRst) != 0)
                {
                    IpcClient.SendSignal(Signal.InternalConnectionFin, null, true);
                }

                return;
            }

            if (tcpPacket.Payload == null || tcpPacket.Payload.Length == 0)
            {
                return;
            }

            Interlocked.Increment(ref this._packetsAnalyzed);

            _buffer.Seek(0, SeekOrigin.End);                               // pos = end
            _buffer.Write(tcpPacket.Payload, 0, tcpPacket.Payload.Length); // pos = end

            var needPurge     = false;
            var currentHeader = new byte[HeaderLength];

            for (;;)
            {
                if (!needPurge)
                {
                    _buffer.Seek(processedLength, SeekOrigin.Begin);                                 // pos = 0

                    if (_buffer.Length - processedLength <= HeaderLength || processedLength > 65536) // not enough data
                    {
                        var remaining = _buffer.Length - processedLength;
                        if (remaining < 0)
                        {
                            throw new AggregateException("Invalid processedLength");
                        }

                        var tmp = new byte[remaining];
                        _buffer.Read(tmp, 0, tmp.Length);
                        _buffer.SetLength(0);
                        _buffer.Write(tmp, 0, tmp.Length);
                        processedLength = 0;
                        return;
                    }

                    _buffer.Read(currentHeader, 0, HeaderLength); // pos = 40


                    if (!IsValidHeader(currentHeader))
                    {
                        needPurge = true;
                        continue;
                    }

                    NetworkPacketHeader header;
                    fixed(byte *p = &currentHeader[0])
                    {
                        header = *(NetworkPacketHeader *)p;
                    }

                    if (header.Malformed)
                    {
                        needPurge = true;
                        continue;
                    }

                    var timeDelta = Math.Abs(Helper.DateTimeToUnixTimeStamp(DateTime.Now) * 1000 - header.Timestamp);

                    if (header.Length < HeaderLength || (header.Timestamp != 0 && timeDelta > 60000)) // > 1 min
                    {
                        needPurge = true;
                        continue;
                    }

                    if (header.Length > _buffer.Length - processedLength)
                    {
                        return; // wait for more content
                    }
                    var content = GenerateContent(_buffer, header.IsCompressed, header.Length);

                    if (content.Length == 0)
                    {
                        content.Dispose();

                        needPurge = true;
                        continue;
                    }

                    ConsumeContent(content, header, mark);

                    processedLength += header.Length; // pos = 0
                }
                else
                {
                    needPurge = false;

                    var bytes    = _buffer.ToArray();
                    var newStart = processedLength + 1;
                    var pos      = FindMagic(new ArraySegment <byte>(bytes, newStart, bytes.Length - newStart));

                    if (pos == -1)
                    {
                        _buffer.SetLength(0); // no available data, drop all content
                        processedLength = 0;
                        return;
                    }

                    processedLength += pos + 1;
                }
            }
        }
コード例 #23
0
        private void NetworkStateMachine()
        {
            const int gameConnectionCount = 2;

            switch (_networkState)
            {
            case NetworkState.Lobby:
                _packetCycle     = 0;
                _noPackCycle     = 0;
                _requireSoftStop = false;
                Interlocked.Exchange(ref _softStopCycle, 0);

                var l_conn = ConnectionPicker.GetConnections(GameProcess);
                if (!l_conn.Any())
                {
                    _networkState = NetworkState.Unconnected;
                    LobbyConnection.Clear();
                    Log.Information($"Network State: NoConnection");
                    break;
                }

                LobbyConnection = ExtractConnections(l_conn, null);
                OnLobbyUpdate?.Invoke();

                var l_game = ExtractConnections(l_conn, LobbyConnection);
                if (l_game.Count == gameConnectionCount)
                {
                    GameConnection = l_game;
                    _networkState  = NetworkState.GameUninitialized;
                    Log.Information($"Network State: GameConnDetected");
                }

                break;

            case NetworkState.Unconnected:
                _networkState = NetworkState.Fail;

                if (!NetworkInterface.GetIsNetworkAvailable())
                {
                    break;
                }
                if (!PingHost(ConnectionPicker.GetLobbyEndPoint(GameProcess)))
                {
                    break;
                }

                _networkState = NetworkState.Pending;
                Log.Information($"Network State: WaitingLogin");

                break;

            case NetworkState.Fail:
                Log.Information($"Network State: FailNetworkCheck");
                IpcClient.SendSignal(Signal.ClientNetworkFail, new[] { GameProcess.Id.ToString() });
                Stopping = true;

                break;

            case NetworkState.Pending:
                if (ConnectionPicker.GetConnections(GameProcess).Any())
                {
                    _networkState = NetworkState.Lobby;
                    Log.Information($"Network State: ConnectedToLobby");
                }

                break;

            case NetworkState.GameUninitialized:
                OnWorldStart?.Invoke();
                _networkState = NetworkState.GameInitialized;
                Log.Information($"Network State: InitializeInvoked");

                break;

            case NetworkState.GameInitialized:
                if (_requireSoftStop)
                {
                    Interlocked.Increment(ref _softStopCycle);
                    _networkState = NetworkState.GameNoPacket;
                    Log.Information($"Network State: ConnectivityCheck");
                    break;
                }

                if (GetPacketAmount != null && _previousGamePacketCount != GetPacketAmount?.Invoke())
                {
                    _noPackCycle             = 0;
                    _previousGamePacketCount = GetPacketAmount.Invoke();
                    break;
                }

                _packetCycle++;
                _noPackCycle++;

                if (_packetCycle > 240)     // 2min, Quality assurance
                {
                    _networkState = NetworkState.GameNoPacket;
                    Log.Information($"Network State: ScheduledQA");
                }

                if (_noPackCycle > 10)    // 5s, Suspected disconnected
                {
                    _networkState = NetworkState.GameNoPacket;
                    Log.Information($"Network State: NoPackNetworkCheck");
                }

                break;

            case NetworkState.GameNoPacket:
                var gnp_conn = ConnectionPicker.GetConnections(GameProcess);

                if (!_connSetEqCp.Equals(gnp_conn, GameConnection))
                {
                    OnWorldStop?.Invoke();
                    _networkState = NetworkState.Lobby;
                    Log.Information($"Network State: ConnectionLost");
                    break;
                }

                if (_softStopCycle > 20)     // 10s, Kept monitoring
                {
                    _requireSoftStop = false;
                    Interlocked.Exchange(ref _softStopCycle, 0);
                }

                _packetCycle  = 0;
                _noPackCycle  = 0;
                _networkState = NetworkState.GameInitialized;
                Log.Information($"Network State: Normal");

                break;

            default:
                _networkState = NetworkState.Lobby;
                Log.Information($"Network State: UnrecognizedToLobby");

                break;
            }
        }