#include "check_csgo.h" #include using namespace std; char *servicename = (char*)"CS:GO"; void printVersion() { cout << "check_csgo v" << VERSION << endl << endl; } void printHelp(bool longVersion) { if(longVersion) { printVersion(); cout << "Check CS:GO DS instance." << endl << endl; printHelp(false); cout << "Options:" << endl; cout << " -h" << endl; cout << " Print detailed help screen" << endl; cout << " -V" << endl; cout << " Print version information" << endl; cout << " -H HOSTADDRESS" << endl; cout << " Host where the Source DS is running" << endl; cout << " -p" << endl; cout << " Port where the Source DS is listening. Default is 27015." << endl << endl; return; } cout << "Usage: " << endl << "check_csgo [-hV] -H HOSTADDRESS [-p PORT]" << endl << endl; } SOURCEDS_PACKET* getSourceDSResponse(int s, sockaddr_in *server) { char *data = new char[DATAGRAM_LENGTH]; int dataLength = recvMsg(s, data, DATAGRAM_LENGTH, server); if(dataLength == -1) { return NULL; } char *header = (char*) "\xFF\xFF\xFF\xFF"; if(memcmp(data,header,HDR_SIZE)) { //Invalid response, or non-supported multi-packet response format return NULL; } SOURCEDS_PACKET *response = new SOURCEDS_PACKET; response->data = data+HDR_SIZE; response->length = dataLength; return response; } int check_csgo(char *hostname, uint16_t port, SERVERINFO *server_info) { struct sockaddr_in si; struct hostent *host = NULL; int s; int timeout = 10; setupSocket(port,hostname,host,timeout,&si,&s); string discard; std::vector info_query; info_query.resize(25); memcpy(info_query.data(), "\xFF\xFF\xFF\xFF\x54Source Engine Query\x00", 25); sendMsg(s, reinterpret_cast(info_query.data()), info_query.size(), &si); SOURCEDS_PACKET *response = getSourceDSResponse(s,&si); if(response == NULL) { return 2; } if(response->data[0] == 'A') { // Challenge response mechanism uint32_t challenge; size_t current_pkt_size = info_query.size(); info_query.resize(current_pkt_size + 4); memcpy(info_query.data() + current_pkt_size, response->data+1, 4); delete[] (response->data-HDR_SIZE); delete response; sendMsg(s, reinterpret_cast(info_query.data()), info_query.size(), &si); response = getSourceDSResponse(s, &si); if(response == NULL) { return 2; } } ssize_t offset = 2; server_info->name = string(response->data+offset,strlen(response->data+offset)); offset += server_info->name.size()+1; server_info->map = string(response->data+offset,strlen(response->data+offset)); offset += server_info->map.size()+1; discard = string(response->data+offset,strlen(response->data+offset)); offset += discard.size() + 1; server_info->game = string(response->data+offset,strlen(response->data+offset)); offset += server_info->game.size()+1; offset += 2; server_info->players = (uint8_t) *((response->data)+offset); server_info->max_players = (uint8_t) *((response->data)+(++offset)); delete[] (response->data-HDR_SIZE); delete response; if(server_info->players == server_info->max_players) { return 1; } return 0; } int main(int argc, char **argv) { struct itimerval timer; timer.it_value.tv_sec = 10; timer.it_value.tv_usec = 0; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; setitimer (ITIMER_VIRTUAL, &timer, 0); struct sigaction sa; memset (&sa, 0, sizeof (sa)); sa.sa_handler = &timer_handler; sigaction (SIGVTALRM, &sa, 0); uint16_t port = 27015; char *hostname = NULL; int c; while ((c = getopt (argc, argv, "H:p:Vh")) != -1) { switch(c) { case 'H': hostname = optarg; break; case 'p': port = (uint16_t) str2int(optarg); break; case 'V': printVersion(); return 0; case 'h': printHelp(true); return 0; case '?': printHelp(false); return 3; } } if(hostname == NULL) { cout << "No HOSTADDRESS specified. Exiting." << endl; return 3; } SERVERINFO server_info; int returnCode = check_csgo(hostname,port,&server_info); cout << servicename; switch(returnCode) { case 0: cout << " OK"; cout << " - " << hostname << " " << server_info.name << " " << server_info.game << " " << server_info.map << " " << (int)server_info.players << "/" << (int)server_info.max_players << " players" << endl ; break; case 1: cout << " WARNING - Server is full"; break; case 2: cout << " CRITICAL - No response"; break; } return returnCode; }