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)); }
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); }