public async Task <ServerStatus> GetServerStatus(IDedicatedServer dedicatedServer, CancellationToken cancellationToken)
        {
            var ipEndPoint = new IPEndPoint(IPAddress.Loopback, dedicatedServer.SteamQueryPort);
            var serverInfo = await A2SInfo.GetServerInfoAsync(ipEndPoint, cancellationToken, _logger);

            return(new ServerStatus(
                       GetServerStatusEnum(dedicatedServer, serverInfo),
                       serverInfo?.Name,
                       dedicatedServer?.Modset.Name,
                       serverInfo?.Map,
                       serverInfo?.Players,
                       serverInfo?.MaxPlayers,
                       dedicatedServer?.Port,
                       dedicatedServer?.StartTime,
                       dedicatedServer?.HeadlessClientsConnected));
        }
Ejemplo n.º 2
0
        private static async Task <A2SInfo> ReadServerInfo(
            UdpClient udpClient,
            IPEndPoint ipEndPoint,
            CancellationToken cancellationToken,
            ILogger?logger)
        {
            var serverInfo = new A2SInfo();

            udpClient.Connect(ipEndPoint);

            logger?.LogTrace("Sending UDP request to {IpAddress}", ipEndPoint);

            await udpClient.SendAsync(
                Request,
                Request.Length);

            logger?.LogTrace("UDP request sent tp {IpAddress}", ipEndPoint);

            var receiveTask = udpClient.ReceiveAsync();

            while (!receiveTask.IsCompleted)
            {
                var delayTask = Task.Delay(1000, cancellationToken);
                await Task.WhenAny(receiveTask, delayTask);

                if (cancellationToken.IsCancellationRequested)
                {
                    logger?.LogDebug("UDP connection to {IpAddress} timed out", ipEndPoint);
                    throw new TaskCanceledException($"Connection to {ipEndPoint} timed out");
                }
            }

            var udpReceiveResult = await receiveTask;

            logger?.LogDebug("UDP request received from {IpAddress}. Reading started", ipEndPoint);

            await using var memoryStream = new MemoryStream(udpReceiveResult.Buffer);     // Saves the received data in a memory buffer
            using var binaryReader       = new BinaryReader(memoryStream, Encoding.UTF8); // A binary reader that treats characters as Unicode 8-bit
            memoryStream.Seek(4, SeekOrigin.Begin);                                       // skip the 4 0xFFs

            serverInfo.Header        = binaryReader.ReadByte();
            serverInfo.Protocol      = binaryReader.ReadByte();
            serverInfo.Name          = ReadNullTerminatedString(binaryReader);
            serverInfo.Map           = ReadNullTerminatedString(binaryReader);
            serverInfo.Folder        = ReadNullTerminatedString(binaryReader);
            serverInfo.Game          = ReadNullTerminatedString(binaryReader);
            serverInfo.Id            = binaryReader.ReadInt16();
            serverInfo.Players       = binaryReader.ReadByte();
            serverInfo.MaxPlayers    = binaryReader.ReadByte();
            serverInfo.Bots          = binaryReader.ReadByte();
            serverInfo.ServerType    = (ServerTypeFlags)binaryReader.ReadByte();
            serverInfo.Environment   = (EnvironmentFlags)binaryReader.ReadByte();
            serverInfo.Visibility    = (VisibilityFlags)binaryReader.ReadByte();
            serverInfo.VAC           = (VACFlags)binaryReader.ReadByte();
            serverInfo.Version       = ReadNullTerminatedString(binaryReader);
            serverInfo.ExtraDataFlag = (ExtraDataFlags)binaryReader.ReadByte();

            #region These EDF readers have to be in this order because that's the way they are reported

            if (serverInfo.ExtraDataFlag.HasFlag(ExtraDataFlags.Port))
            {
                serverInfo.Port = binaryReader.ReadInt16();
            }
            if (serverInfo.ExtraDataFlag.HasFlag(ExtraDataFlags.SteamId))
            {
                serverInfo.SteamId = binaryReader.ReadUInt64();
            }
            if (serverInfo.ExtraDataFlag.HasFlag(ExtraDataFlags.Spectator))
            {
                serverInfo.SpectatorPort = binaryReader.ReadInt16();
                serverInfo.Spectator     = ReadNullTerminatedString(binaryReader);
            }

            if (serverInfo.ExtraDataFlag.HasFlag(ExtraDataFlags.Keywords))
            {
                serverInfo.Keywords = ReadNullTerminatedString(binaryReader);
            }
            if (serverInfo.ExtraDataFlag.HasFlag(ExtraDataFlags.GameId))
            {
                serverInfo.GameId = binaryReader.ReadUInt64();
            }

            #endregion

            logger.LogTrace("Successfully read message from {IpAddress}", ipEndPoint);

            return(serverInfo);
        }