check_csgo.cpp 4.03 KB
#include "check_csgo.h"

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;

    char *info_query = (char*) "\xFF\xFF\xFF\xFF\x54Source Engine Query\x00";

    sendMsg(s,info_query, strlen(info_query)+1,&si);
    SOURCEDS_PACKET *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;
}