source code checkin

This commit is contained in:
Brett Hewitson 2021-01-07 16:23:23 +10:00
parent 5f8fb2c825
commit 7e57b72e35
675 changed files with 168433 additions and 0 deletions

View file

@ -0,0 +1,69 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace SSQLib
{
internal class Packet
{
internal int RequestId = 0;
internal string Data = "";
internal Packet() { }
//Output the packet data as a byte array
internal byte[] outputAsBytes()
{
byte[] data_byte = null;
if (Data.Length > 0)
{
//Create a new packet based on the length of the request
data_byte = new byte[Data.Length + 5];
//Fill the first 4 bytes with 0xff
data_byte[0] = 0xff;
data_byte[1] = 0xff;
data_byte[2] = 0xff;
data_byte[3] = 0xff;
//Copy the data to the new request
Array.Copy(ASCIIEncoding.UTF8.GetBytes(Data), 0, data_byte, 4, Data.Length);
}
//Empty request to get challenge
else
{
data_byte = new byte[5];
//Fill the first 4 bytes with 0xff
data_byte[0] = 0xff;
data_byte[1] = 0xff;
data_byte[2] = 0xff;
data_byte[3] = 0xff;
data_byte[4] = 0x57;
}
return data_byte;
}
}
}

View file

@ -0,0 +1,170 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SSQLib
{
/// <summary>
/// Stores information about a player in the server
/// </summary>
public class PlayerInfo
{
private string name = "";
private int index = -9999;
private int kills = -9999;
private int deaths = -9999;
private int score = -9999;
private int ping = -9999;
private int rate = -9999;
private float time = 0.0f;
/// <summary>
/// Creates a new PlayerInfo object with default values
/// </summary>
public PlayerInfo() { }
/// <summary>
/// The name of the player
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
/// <summary>
/// The amount of kills the player has (default: -9999)
/// </summary>
public int Kills
{
get {
return this.kills;
}
set {
this.kills = value;
}
}
/// <summary>
/// The amount of deaths the player has (default: -9999)
/// </summary>
public int Deaths
{
get
{
return this.deaths;
}
set
{
this.deaths = value;
}
}
/// <summary>
/// The score of the player (default: -9999)
/// </summary>
public int Score
{
get
{
return this.score;
}
set
{
this.score = value;
}
}
/// <summary>
/// The ping of the player (default: -9999)
/// </summary>
public int Ping
{
get
{
return this.ping;
}
set
{
this.ping = value;
}
}
/// <summary>
/// The rate(?) of the player (default: -9999)
/// </summary>
public int Rate
{
get
{
return this.rate;
}
set
{
this.rate = value;
}
}
/// <summary>
/// The index of the player in the server
/// </summary>
public int Index
{
get
{
return this.index;
}
set
{
this.index = value;
}
}
/// <summary>
/// The time the player has been in the server
/// </summary>
public float Time
{
get
{
return this.time;
}
set
{
this.time = value;
}
}
}
}

307
src/ArkData/SSQLib/SSQL.cs Normal file
View file

@ -0,0 +1,307 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections;
namespace SSQLib
{
/// <summary>
/// Used to retreive information from a Source server
/// </summary>
public class SSQL
{
/// <summary>
/// Generates an SSQL object with default values
/// </summary>
public SSQL()
{
}
/// <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>
/// 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
List<byte> playerName = new List<byte>();
//Loop through and store the player's name
while (buf[i] != 0x00)
{
playerName.Add(buf[i++]);
}
//Move past the end of the string
i++;
// Decode the player name
newPlayer.Name = Encoding.UTF8.GetString(playerName.ToArray());
//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;
}
}
}

View file

@ -0,0 +1,32 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SSQLib
{
class SSQLServerException : System.Exception
{
public SSQLServerException(string message) : base(message)
{
}
}
}

View file

@ -0,0 +1,317 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SSQLib
{
/// <summary>
/// Stores information about the Source server
/// </summary>
public class ServerInfo
{
private string name = "";
private string ip = "";
private string port = "";
private string game = "";
private string gameVersion = "";
private string appID = "";
private string map = "";
private string playerCount = "";
private string botCount = "";
private string maxPlayers = "";
private bool passworded = false;
private bool vac = false;
private ServerInfo.DedicatedType dedicated = ServerInfo.DedicatedType.NONE;
private ServerInfo.OSType os = ServerInfo.OSType.NONE;
/// <summary>
/// Creates a new object with default values
/// </summary>
public ServerInfo() { }
/// <summary>
/// The name of the server
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
}
}
/// <summary>
/// The IP address of the server
/// </summary>
public string IP
{
get
{
return this.ip;
}
set
{
this.ip = value;
}
}
/// <summary>
/// The port the server uses
/// </summary>
public string Port
{
get
{
return this.port;
}
set
{
this.port = value;
}
}
/// <summary>
/// The game being played on the server (i.e. Team Fortress (tf))
/// </summary>
public string Game
{
get
{
return this.game;
}
set
{
this.game = value;
}
}
/// <summary>
/// The game version running on the server
/// </summary>
public string Version
{
get
{
return this.gameVersion;
}
set
{
this.gameVersion = value;
}
}
/// <summary>
/// The map currently being played on the server
/// </summary>
public string Map
{
get
{
return this.map;
}
set
{
this.map = value;
}
}
/// <summary>
/// The current player count on the server
/// </summary>
public string PlayerCount
{
get
{
return this.playerCount;
}
set
{
this.playerCount = value;
}
}
/// <summary>
/// The current bot count on the server
/// </summary>
public string BotCount
{
get
{
return this.botCount;
}
set
{
this.botCount = value;
}
}
/// <summary>
/// The max amount of players allowed on the server
/// </summary>
public string MaxPlayers
{
get
{
return this.maxPlayers;
}
set
{
this.maxPlayers = value;
}
}
/// <summary>
/// Stores whether the server is passworded or not
/// </summary>
public bool Password
{
get
{
return this.passworded;
}
set
{
this.passworded = value;
}
}
/// <summary>
/// Stores whether the server is VAC protected or not
/// </summary>
public bool VAC
{
get
{
return this.vac;
}
set
{
this.vac = value;
}
}
/// <summary>
/// Stores the app ID of the game used by the server
/// </summary>
public string AppID
{
get
{
return this.appID;
}
set
{
this.appID = value;
}
}
/// <summary>
/// Stores the type of server running (Listen, Dedicated, SourceTV)
/// </summary>
public ServerInfo.DedicatedType Dedicated
{
get
{
return this.dedicated;
}
set
{
this.dedicated = value;
}
}
/// <summary>
/// Stores the operating system of the server (Windows, Linux)
/// </summary>
public ServerInfo.OSType OS
{
get
{
return this.os;
}
set
{
this.os = value;
}
}
/// <summary>
/// Used to describe the type of server running
/// </summary>
public enum DedicatedType
{
/// <summary>
/// Default value
/// </summary>
NONE,
/// <summary>
/// Listen server (locally hosted)
/// </summary>
LISTEN,
/// <summary>
/// Dedicated server
/// </summary>
DEDICATED,
/// <summary>
/// SourceTV server
/// </summary>
SOURCETV
};
/// <summary>
/// Used to describe the operating system running on the server
/// </summary>
public enum OSType
{
/// <summary>
/// Default value
/// </summary>
NONE,
/// <summary>
/// Windows server
/// </summary>
WINDOWS,
/// <summary>
/// Linux server
/// </summary>
LINUX
};
}
}

View file

@ -0,0 +1,111 @@
/*
* This file is part of SSQLib.
*
* SSQLib is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SSQLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SSQLib. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SSQLib
{
internal class SocketUtils
{
private SocketUtils() { }
internal static byte[] getInfo(IPEndPoint ipe, Packet packet)
{
//Create the socket
Socket srvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Save the max packet size
int packetSize = 12288;
//Send/Receive timeouts
srvSocket.SendTimeout = 3000;
srvSocket.ReceiveTimeout = 3000;
try
{
//Send the request to the server
srvSocket.SendTo(packet.outputAsBytes(), ipe);
}
catch (SocketException se)
{
throw new SSQLServerException("Could not send packet to server {" + se.Message + "}");
}
//Create a new receive buffer
byte[] rcvPacketInfo = new byte[packetSize];
EndPoint Remote = (EndPoint)ipe;
try
{
//Receive the data from the server
srvSocket.ReceiveFrom(rcvPacketInfo, ref Remote);
}
catch (SocketException se)
{
throw new SSQLServerException("Could not receive packet from server {" + se.Message + "}");
}
//Send the information back
return rcvPacketInfo;
}
internal static byte[] getInfo(IPEndPoint ipe, byte[] request)
{
//Create the socket
Socket srvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Save the max packet size
int packetSize = 12288;
//Send/Receive timeouts
srvSocket.SendTimeout = 3000;
srvSocket.ReceiveTimeout = 3000;
try
{
//Send the request to the server
srvSocket.SendTo(request, ipe);
}
catch (SocketException se)
{
throw new SSQLServerException("Could not send packet to server {" + se.Message + "}");
}
//Create a new receive buffer
byte[] rcvPacketInfo = new byte[packetSize];
EndPoint Remote = (EndPoint)ipe;
try
{
//Receive the data from the server
srvSocket.ReceiveFrom(rcvPacketInfo, ref Remote);
}
catch (SocketException se)
{
throw new SSQLServerException("Could not receive packet from server {" + se.Message + "}");
}
//Send the information back
return rcvPacketInfo;
}
}
}