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; int recvdBytes = -1; try { //Receive the data from the server recvdBytes = srvSocket.ReceiveFrom(rcvPacketInfo, ref Remote); } catch (SocketException se) { throw new SSQLServerException("Could not receive packet from server {" + se.Message + "}"); } if (recvdBytes < sizeof(uint)) return null; uint headerInt = BitConverter.ToUInt32(rcvPacketInfo, 0); if (headerInt != 0xFFFFFFFF) //we only support simple non-split packets for this query return null; int realDataSize = recvdBytes - sizeof(uint); //Send the packet data back byte[] retnData = new byte[realDataSize]; Array.Copy(rcvPacketInfo, sizeof(uint), retnData, 0, realDataSize); return retnData; }
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; }
/// <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; }