private byte[] PerformBigRequest(byte opcode) { //Create a request packet byte[] rqstBytes = new byte[9]; rqstBytes[0] = (byte)0xff; rqstBytes[1] = (byte)0xff; rqstBytes[2] = (byte)0xff; rqstBytes[3] = (byte)0xff; rqstBytes[4] = (byte)opcode; rqstBytes[5] = (byte)((_challenge >> 0) & 0xFF); rqstBytes[6] = (byte)((_challenge >> 8) & 0xFF); rqstBytes[7] = (byte)((_challenge >> 16) & 0xFF); rqstBytes[8] = (byte)((_challenge >> 24) & 0xFF); byte[] buf = null; try { //Attempt to get the response buf = SocketUtils.getInfo(_ipEnd, rqstBytes); } catch (SSQLServerException e) { throw e; } uint i = 0; if (buf[i] == 'A') //if we need to resend the request with new challenge { i++; //move over the A _challenge = ReadUint32(buf, ref i); //read the challenge we got //put the challenge into the request rqstBytes[5] = (byte)((_challenge >> 0) & 0xFF); rqstBytes[6] = (byte)((_challenge >> 8) & 0xFF); rqstBytes[7] = (byte)((_challenge >> 16) & 0xFF); rqstBytes[8] = (byte)((_challenge >> 24) & 0xFF); try { //Get the actual response buf = SocketUtils.getInfo(_ipEnd, rqstBytes); } catch (SSQLServerException e) { throw e; } } return(buf); }
/// <summary> /// Pings the specified Source server to retreive information about it such as the server name, max players, current number of players, etc. /// </summary> /// <param name="ip_end">The IPEndPoint object containing the IP address and port of the server</param> /// <returns>Information about the server or throws an SSQLServerException if it could not be retreived</returns> public ServerInfo Server(IPEndPoint ip_end) { //Create a new empty server info object ServerInfo info = new ServerInfo(); //Create an empty buffer byte[] buf = null; //Create a new packet and request Packet requestPacket = new Packet(); requestPacket.Data = "TSource Engine Query"; try { //Attempt to get the server info buf = SocketUtils.getInfo(ip_end, requestPacket); } catch (SSQLServerException e) { throw e; } //Start past the first four bytes which are all 0xff int i = 4; //Make sure the first character is an I if (buf[i++] != 'I') { return(null); } //Make sure the returned version is above 0x07 if (buf[i++] < 0x07) { return(null); } StringBuilder srvName = new StringBuilder(); //Retrieve the server name while (buf[i] != 0x00) { srvName.Append((char)buf[i]); i++; } //Move to the next byte i++; //Set the name of the server info.Name = srvName.ToString(); StringBuilder mapName = new StringBuilder(); //Retrieve the map name while (buf[i] != 0x00) { mapName.Append((char)buf[i]); i++; } //Move to the next byte i++; info.Map = mapName.ToString(); StringBuilder gameName = new StringBuilder(); //Get the short name for the game while (buf[i] != 0x00) { gameName.Append((char)buf[i]); i++; } //Move to the next byte i++; StringBuilder gameFriendly = new StringBuilder(); //Get the friendly game description while (buf[i] != 0x00) { gameFriendly.Append((char)buf[i]); i++; } //Move to the next byte i++; info.Game = gameFriendly.ToString() + " (" + gameName.ToString() + ")"; short appID = (short)System.BitConverter.ToInt16(buf, i); //Skip the next 2 bytes i += 2; //Store the app id info.AppID = appID.ToString(); //Get the number of players info.PlayerCount = buf[i++].ToString(); //Get the number of max players info.MaxPlayers = buf[i++].ToString(); //Get the number of bots info.BotCount = buf[i++].ToString(); //Get the dedicated server type if ((char)buf[i] == 'l') { info.Dedicated = ServerInfo.DedicatedType.LISTEN; } else if ((char)buf[i] == 'd') { info.Dedicated = ServerInfo.DedicatedType.DEDICATED; } else if ((char)buf[i] == 'p') { info.Dedicated = ServerInfo.DedicatedType.SOURCETV; } //Move to the next byte i++; //Get the OS type if ((char)buf[i] == 'l') { info.OS = ServerInfo.OSType.LINUX; } else if ((char)buf[i] == 'w') { info.OS = ServerInfo.OSType.WINDOWS; } //Move to the next byte i++; //Check for password protection if (buf[i++] == 0x01) { info.Password = true; } //Check for VAC if (buf[i++] == 0x01) { info.VAC = true; } StringBuilder versionInfo = new StringBuilder(); //Get the game version while (buf[i] != 0x00) { versionInfo.Append((char)buf[i]); i++; } //Move to the next byte i++; //Set the version info.Version = versionInfo.ToString(); return(info); }
/// <summary> /// Pings the specified Source server to retreive information about it such as the server name, max players, current number of players, etc. /// </summary> /// <returns>Information about the server or throws an SSQLServerException if it could not be retreived</returns> public ServerInfo Server() { //Create a new empty server info object ServerInfo info = new ServerInfo(); //Create an empty buffer byte[] buf = null; //Create a new packet and request Packet requestPacket = new Packet(); requestPacket.Data = "TSource Engine Query"; try { //Attempt to get the server info buf = SocketUtils.getInfo(_ipEnd, requestPacket); } catch (SSQLServerException e) { throw e; } //Record the IP the packet came from info.IP = _ipEnd.Address.ToString(); uint i = 0; //Make sure the first character is an I if (buf[i++] != 'I') { return(null); } //Make sure the returned version is above 0x07 if (buf[i++] < 0x07) { return(null); } //Set the name of the server info.Name = ReadString(buf, ref i); //Set the name of the map info.Map = ReadString(buf, ref i); //Get the short name for the game info.Folder = ReadString(buf, ref i); //Get the friendly game description info.Game = ReadString(buf, ref i); //read the appId of the game var appID = ReadUint16(buf, ref i); //Store the app id info.AppID = appID.ToString(); //Get the number of players info.PlayerCount = buf[i++].ToString(); //Get the number of max players info.MaxPlayers = buf[i++].ToString(); //Get the number of bots info.BotCount = buf[i++].ToString(); //Get the dedicated server type if (buf[i] == 'l') { info.Dedicated = ServerInfo.DedicatedType.LISTEN; } else if (buf[i] == 'd') { info.Dedicated = ServerInfo.DedicatedType.DEDICATED; } else if (buf[i] == 'p') { info.Dedicated = ServerInfo.DedicatedType.SOURCETV; } //Move to the next byte i++; //Get the OS type if (buf[i] == 'l') { info.OS = ServerInfo.OSType.LINUX; } else if (buf[i] == 'w') { info.OS = ServerInfo.OSType.WINDOWS; } //Move to the next byte i++; //Check for Password protection if (buf[i++] == 0x01) { info.Password = true; } //Check for VAC if (buf[i++] == 0x01) { info.VAC = true; } //Get the game version info.Version = ReadString(buf, ref i); //get EDF uint edf = buf[i++]; if ((edf & 0x80) != 0) //has port number { ushort portNumber = ReadUint16(buf, ref i); info.Port = portNumber.ToString(); } if ((edf & 0x10) != 0) //has server SteamId { ulong serverSteamId = ReadUint64(buf, ref i); info.SteamID = serverSteamId.ToString(); } if ((edf & 0x40) != 0) //has spectator port number and name { //we currently arent storing these anywhere as they aren't needed ushort sourceTvPort = ReadUint16(buf, ref i); string sourceTvName = ReadString(buf, ref i); } if ((edf & 0x20) != 0) //has keywords { info.Keywords = ReadString(buf, ref i); } if ((edf & 0x01) != 0) //has higher precision GameID { ulong gameId = ReadUint64(buf, ref i); ulong preciseAppId = gameId & 0xFFFFFF; //lower 24-bits contain the appId info.AppID = preciseAppId.ToString(); } //should be at the end of the packet now return(info); }
/// <summary> /// Retreives information about the players on a Source server /// </summary> /// <param name="ip_end">The IPEndPoint object storing the IP address and port of the server</param> /// <returns>An ArrayList of PlayerInfo or throws an SSQLServerException if the server could not be reached</returns> public ArrayList Players(IPEndPoint ip_end) { //Create a new array list to store the player array ArrayList players = new ArrayList(); //Create a new buffer to receive packets byte[] buf = null; //Create a challenge packet byte[] challenge = new byte[9]; challenge[0] = (byte)0xff; challenge[1] = (byte)0xff; challenge[2] = (byte)0xff; challenge[3] = (byte)0xff; challenge[4] = (byte)0x55; challenge[5] = (byte)0x00; challenge[6] = (byte)0x00; challenge[7] = (byte)0x00; challenge[8] = (byte)0x00; try { //Attempt to get the challenge response buf = SocketUtils.getInfo(ip_end, challenge); } catch (SSQLServerException e) { throw e; } int i = 4; //Make sure the response starts with A if (buf[i++] != 'A') { return(null); } //Create the new request with the challenge number byte[] requestPlayer = new byte[9]; requestPlayer[0] = (byte)0xff; requestPlayer[1] = (byte)0xff; requestPlayer[2] = (byte)0xff; requestPlayer[3] = (byte)0xff; requestPlayer[4] = (byte)0x55; requestPlayer[5] = buf[i++]; requestPlayer[6] = buf[i++]; requestPlayer[7] = buf[i++]; requestPlayer[8] = buf[i++]; try { //Attempt to get the players response buf = SocketUtils.getInfo(ip_end, requestPlayer); } catch (SSQLServerException) { return(null); } //Start past 0xffffffff i = 4; //Make sure the response starts with D if (buf[i++] != 'D') { return(null); } //Get the amount of players byte numPlayers = buf[i++]; //Loop through each player and extract their stats for (int ii = 0; ii < numPlayers; ii++) { //Create a new player PlayerInfo newPlayer = new PlayerInfo(); //Set the index of the player (Does not work in L4D2, always returns 0) newPlayer.Index = buf[i++]; //Create a new player name StringBuilder playerName = new StringBuilder(); //Loop through and store the player's name while (buf[i] != 0x00) { playerName.Append((char)buf[i++]); } //Move past the end of the string i++; newPlayer.Name = playerName.ToString(); //Get the kills and store them in the player info newPlayer.Kills = (int)(buf[i] & 255) | ((buf[i + 1] & 255) << 8) | ((buf[i + 2] & 255) << 16) | ((buf[i + 3] & 255) << 24); //Move to the next item i += 5; //Get the time connected as a float and store it in the player info newPlayer.Time = (float)((int)(buf[i] & 255) | ((buf[i + 1] & 255) << 8)); //Move past the float i += 3; //Add the player to the list players.Add(newPlayer); } //Return the list of players return(players); }