348 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*****************************************************************************
 | 
						|
* 
 | 
						|
* Monitoring check_game plugin
 | 
						|
* 
 | 
						|
* License: GPL
 | 
						|
* Copyright (c) 2002-2007 Monitoring Plugins Development Team
 | 
						|
* 
 | 
						|
* Description:
 | 
						|
* 
 | 
						|
* This file contains the check_game plugin
 | 
						|
* 
 | 
						|
* This plugin tests game server connections with the specified host.
 | 
						|
* using the qstat program
 | 
						|
* 
 | 
						|
* 
 | 
						|
* This program is free software: you can redistribute it and/or modify
 | 
						|
* it under the terms of the GNU General Public License as published by
 | 
						|
* the Free Software Foundation, either version 3 of the License, or
 | 
						|
* (at your option) any later version.
 | 
						|
* 
 | 
						|
* This program 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 General Public License for more details.
 | 
						|
* 
 | 
						|
* You should have received a copy of the GNU General Public License
 | 
						|
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
* 
 | 
						|
*
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
const char *progname = "check_game";
 | 
						|
const char *copyright = "2002-2007";
 | 
						|
const char *email = "devel@monitoring-plugins.org";
 | 
						|
 | 
						|
#include "common.h"
 | 
						|
#include "utils.h"
 | 
						|
#include "runcmd.h"
 | 
						|
 | 
						|
int process_arguments (int, char **);
 | 
						|
int validate_arguments (void);
 | 
						|
void print_help (void);
 | 
						|
void print_usage (void);
 | 
						|
 | 
						|
#define QSTAT_DATA_DELIMITER  ","
 | 
						|
 | 
						|
#define QSTAT_HOST_ERROR  "ERROR"
 | 
						|
#define QSTAT_HOST_DOWN   "DOWN"
 | 
						|
#define QSTAT_HOST_TIMEOUT  "TIMEOUT"
 | 
						|
#define QSTAT_MAX_RETURN_ARGS 12
 | 
						|
 | 
						|
char *server_ip;
 | 
						|
char *game_type;
 | 
						|
int port = 0;
 | 
						|
 | 
						|
bool verbose = false;
 | 
						|
 | 
						|
int qstat_game_players_max = -1;
 | 
						|
int qstat_game_players = -1;
 | 
						|
int qstat_game_field = -1;
 | 
						|
int qstat_map_field = -1;
 | 
						|
int qstat_ping_field = -1;
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
main (int argc, char **argv)
 | 
						|
{
 | 
						|
  char *command_line;
 | 
						|
  int result = STATE_UNKNOWN;
 | 
						|
  char *p, *ret[QSTAT_MAX_RETURN_ARGS];
 | 
						|
  size_t i = 0;
 | 
						|
  output chld_out;
 | 
						|
 | 
						|
  setlocale (LC_ALL, "");
 | 
						|
  bindtextdomain (PACKAGE, LOCALEDIR);
 | 
						|
  textdomain (PACKAGE);
 | 
						|
 | 
						|
  /* Parse extra opts if any */
 | 
						|
  argv=np_extra_opts (&argc, argv, progname);
 | 
						|
 | 
						|
  if (process_arguments (argc, argv) == ERROR)
 | 
						|
    usage_va(_("Could not parse arguments"));
 | 
						|
 | 
						|
  result = STATE_OK;
 | 
						|
 | 
						|
  /* create the command line to execute */
 | 
						|
  xasprintf (&command_line, "%s -raw %s -%s %s",
 | 
						|
            PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
 | 
						|
 | 
						|
  if (port)
 | 
						|
    xasprintf (&command_line, "%s:%-d", command_line, port);
 | 
						|
 | 
						|
  if (verbose)
 | 
						|
    printf ("%s\n", command_line);
 | 
						|
 | 
						|
  /* run the command. historically, this plugin ignores output on stderr,
 | 
						|
   * as well as return status of the qstat program */
 | 
						|
  (void)np_runcmd(command_line, &chld_out, NULL, 0);
 | 
						|
 | 
						|
  /* sanity check */
 | 
						|
  /* was thinking about running qstat without any options, capturing the
 | 
						|
     -default line, parsing it & making an array of all know server types
 | 
						|
     but thought this would be too much hassle considering this is a tool
 | 
						|
     for intelligent sysadmins (ha). Could put a static array of known
 | 
						|
     server types in a header file but then we'd be limiting ourselves
 | 
						|
 | 
						|
     In the end, I figured I'd simply let an error occur & then trap it
 | 
						|
   */
 | 
						|
 | 
						|
  if (!strncmp (chld_out.line[0], "unknown option", 14)) {
 | 
						|
    printf (_("CRITICAL - Host type parameter incorrect!\n"));
 | 
						|
    result = STATE_CRITICAL;
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
 | 
						|
  while (p != NULL) {
 | 
						|
    ret[i] = p;
 | 
						|
    p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
 | 
						|
    i++;
 | 
						|
    if (i >= QSTAT_MAX_RETURN_ARGS)
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (strstr (ret[2], QSTAT_HOST_ERROR)) {
 | 
						|
    printf (_("CRITICAL - Host not found\n"));
 | 
						|
    result = STATE_CRITICAL;
 | 
						|
  }
 | 
						|
  else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
 | 
						|
    printf (_("CRITICAL - Game server down or unavailable\n"));
 | 
						|
    result = STATE_CRITICAL;
 | 
						|
  }
 | 
						|
  else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
 | 
						|
    printf (_("CRITICAL - Game server timeout\n"));
 | 
						|
    result = STATE_CRITICAL;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n",
 | 
						|
            ret[qstat_game_players],
 | 
						|
            ret[qstat_game_players_max],
 | 
						|
            ret[qstat_game_field],
 | 
						|
            ret[qstat_map_field],
 | 
						|
            ret[qstat_ping_field],
 | 
						|
            perfdata ("players", atol(ret[qstat_game_players]), "",
 | 
						|
                      false, 0, false, 0,
 | 
						|
                      true, 0, true, atol(ret[qstat_game_players_max])),
 | 
						|
            fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
 | 
						|
                      false, 0, false, 0,
 | 
						|
                      true, 0, false, 0));
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
process_arguments (int argc, char **argv)
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  int opt_index = 0;
 | 
						|
  static struct option long_opts[] = {
 | 
						|
    {"help", no_argument, 0, 'h'},
 | 
						|
    {"version", no_argument, 0, 'V'},
 | 
						|
    {"verbose", no_argument, 0, 'v'},
 | 
						|
    {"timeout", required_argument, 0, 't'},
 | 
						|
    {"hostname", required_argument, 0, 'H'},
 | 
						|
    {"port", required_argument, 0, 'P'},
 | 
						|
    {"game-type", required_argument, 0, 'G'},
 | 
						|
    {"map-field", required_argument, 0, 'm'},
 | 
						|
    {"ping-field", required_argument, 0, 'p'},
 | 
						|
    {"game-field", required_argument, 0, 'g'},
 | 
						|
    {"players-field", required_argument, 0, 129},
 | 
						|
    {"max-players-field", required_argument, 0, 130},
 | 
						|
    {0, 0, 0, 0}
 | 
						|
  };
 | 
						|
 | 
						|
  if (argc < 2)
 | 
						|
    return ERROR;
 | 
						|
 | 
						|
  for (c = 1; c < argc; c++) {
 | 
						|
    if (strcmp ("-mf", argv[c]) == 0)
 | 
						|
      strcpy (argv[c], "-m");
 | 
						|
    else if (strcmp ("-pf", argv[c]) == 0)
 | 
						|
      strcpy (argv[c], "-p");
 | 
						|
    else if (strcmp ("-gf", argv[c]) == 0)
 | 
						|
      strcpy (argv[c], "-g");
 | 
						|
  }
 | 
						|
 | 
						|
  while (1) {
 | 
						|
    c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
 | 
						|
 | 
						|
    if (c == -1 || c == EOF)
 | 
						|
      break;
 | 
						|
 | 
						|
    switch (c) {
 | 
						|
    case 'h': /* help */
 | 
						|
      print_help ();
 | 
						|
      exit (STATE_UNKNOWN);
 | 
						|
    case 'V': /* version */
 | 
						|
      print_revision (progname, NP_VERSION);
 | 
						|
      exit (STATE_UNKNOWN);
 | 
						|
    case 'v': /* version */
 | 
						|
      verbose = true;
 | 
						|
      break;
 | 
						|
    case 't': /* timeout period */
 | 
						|
      timeout_interval = atoi (optarg);
 | 
						|
      break;
 | 
						|
    case 'H': /* hostname */
 | 
						|
      if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH)
 | 
						|
        die (STATE_UNKNOWN, _("Input buffer overflow\n"));
 | 
						|
      server_ip = optarg;
 | 
						|
      break;
 | 
						|
    case 'P': /* port */
 | 
						|
      port = atoi (optarg);
 | 
						|
      break;
 | 
						|
    case 'G': /* hostname */
 | 
						|
      if (strlen (optarg) >= MAX_INPUT_BUFFER)
 | 
						|
        die (STATE_UNKNOWN, _("Input buffer overflow\n"));
 | 
						|
      game_type = optarg;
 | 
						|
      break;
 | 
						|
    case 'p': /* index of ping field */
 | 
						|
      qstat_ping_field = atoi (optarg);
 | 
						|
      if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
 | 
						|
        return ERROR;
 | 
						|
      break;
 | 
						|
    case 'm': /* index on map field */
 | 
						|
      qstat_map_field = atoi (optarg);
 | 
						|
      if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
 | 
						|
        return ERROR;
 | 
						|
      break;
 | 
						|
    case 'g': /* index of game field */
 | 
						|
      qstat_game_field = atoi (optarg);
 | 
						|
      if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
 | 
						|
        return ERROR;
 | 
						|
      break;
 | 
						|
    case 129: /* index of player count field */
 | 
						|
      qstat_game_players = atoi (optarg);
 | 
						|
      if (qstat_game_players_max == 0)
 | 
						|
        qstat_game_players_max = qstat_game_players - 1;
 | 
						|
      if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
 | 
						|
        return ERROR;
 | 
						|
      break;
 | 
						|
    case 130: /* index of max players field */
 | 
						|
      qstat_game_players_max = atoi (optarg);
 | 
						|
      if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
 | 
						|
        return ERROR;
 | 
						|
      break;
 | 
						|
    default: /* args not parsable */
 | 
						|
      usage5();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  c = optind;
 | 
						|
  /* first option is the game type */
 | 
						|
  if (!game_type && c<argc)
 | 
						|
    game_type = strdup (argv[c++]);
 | 
						|
 | 
						|
  /* Second option is the server name */
 | 
						|
  if (!server_ip && c<argc)
 | 
						|
    server_ip = strdup (argv[c++]);
 | 
						|
 | 
						|
  return validate_arguments ();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int
 | 
						|
validate_arguments (void)
 | 
						|
{
 | 
						|
  if (qstat_game_players_max < 0)
 | 
						|
    qstat_game_players_max = 4;
 | 
						|
 | 
						|
  if (qstat_game_players < 0)
 | 
						|
    qstat_game_players = 5;
 | 
						|
 | 
						|
  if (qstat_game_field < 0)
 | 
						|
    qstat_game_field = 2;
 | 
						|
 | 
						|
  if (qstat_map_field < 0)
 | 
						|
    qstat_map_field = 3;
 | 
						|
 | 
						|
  if (qstat_ping_field < 0)
 | 
						|
    qstat_ping_field = 5;
 | 
						|
 | 
						|
  return OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
print_help (void)
 | 
						|
{
 | 
						|
  print_revision (progname, NP_VERSION);
 | 
						|
 | 
						|
  printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
 | 
						|
  printf (COPYRIGHT, copyright, email);
 | 
						|
 | 
						|
  printf (_("This plugin tests game server connections with the specified host."));
 | 
						|
 | 
						|
  printf ("\n\n");
 | 
						|
 | 
						|
  print_usage ();
 | 
						|
 | 
						|
  printf (UT_HELP_VRSN);
 | 
						|
  printf (UT_EXTRA_OPTS);
 | 
						|
 | 
						|
  printf (" %s\n", "-p");
 | 
						|
  printf ("    %s\n", _("Optional port of which to connect"));
 | 
						|
  printf (" %s\n", "gf");
 | 
						|
  printf ("    %s\n", _("Field number in raw qstat output that contains game name"));
 | 
						|
  printf (" %s\n", "-mf");
 | 
						|
  printf ("    %s\n", _("Field number in raw qstat output that contains map name"));
 | 
						|
  printf (" %s\n", "-pf");
 | 
						|
  printf ("    %s\n", _("Field number in raw qstat output that contains ping time"));
 | 
						|
 | 
						|
  printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
 | 
						|
 | 
						|
  printf ("\n");
 | 
						|
  printf ("%s\n", _("Notes:"));
 | 
						|
  printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
 | 
						|
  printf (" %s\n", _("If you don't have the package installed, you will need to download it from"));
 | 
						|
  printf (" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
 | 
						|
 | 
						|
  printf (UT_SUPPORT);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void
 | 
						|
print_usage (void)
 | 
						|
{
 | 
						|
  printf ("%s\n", _("Usage:"));
 | 
						|
  printf (" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> <ip_address>\n", progname);
 | 
						|
}
 | 
						|
 | 
						|
/******************************************************************************
 | 
						|
 *
 | 
						|
 * Test Cases:
 | 
						|
 *
 | 
						|
 * ./check_game --players 7 -p 8 --map 5 qs 67.20.190.61 26000
 | 
						|
 *
 | 
						|
 * qstat -raw , -qs 67.20.190.61
 | 
						|
 *  ==> QS,67.20.190.61,Nightmare.fintek.ca,67.20.190.61:26000,3,e2m1,6,0,83,0
 | 
						|
 *
 | 
						|
 * qstat -qs 67.20.190.61
 | 
						|
 *  ==> ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
 | 
						|
 *  ==> 67.20.190.61            0/ 6     e2m1     79 / 0   Nightmare.fintek.ca
 | 
						|
 *
 | 
						|
 ******************************************************************************/
 |