1#!/usr/local/bin/perl
2#
3# 2007-06-26
4# Written by Ghost
5#
6# 2008-04-16
7# Update: Wildcard version
8#
9# 2008-11-12
10# Update: Perl RCON system
11#
12# Configuration variables
13#
14#   srcdspass       - RCON password
15#   srcdsplayersmax - Maximum number of players (optional, default: 32)
16#
17# Magic markers - optional - used by installation scripts and
18# munin-config:
19#
20#%# family=contrib
21#%# capabilities=autoconf
22
23
24use strict;
25
26# Set library path correctly
27use File::Basename;
28if (-l $0) {
29    push(@INC, dirname(readlink($0)));
30}
31push(@INC, dirname($0));
32
33# Load Rcon module or exit with failure message
34if (!eval "require Rcon") {
35    print "Failed to load Rcon module. ";
36    print "Make sure Rcon.pm is copied to Munin plugins directory.\n";
37    exit 1;
38}
39
40# Parse hostname and port from the plugin filename
41my ($HOST, $PORT) = $0 =~ m/.*_([^:]+)_(\d+)$/;
42if (!defined($HOST) || !defined($PORT)) {
43    print "Could not parse server address from filename.\n";
44    exit 1;
45}
46
47# Load config variables or use default values
48my $PASS    = $ENV{srcdspass}       || "";
49my $MAX     = $ENV{srcdsplayersmax} || 32;
50
51# Print config or do plugin test if asked
52my $arg = shift();
53if ($arg eq 'config') {
54    print_config();
55} elsif ($arg eq 'autoconf') {
56    test_service();
57}
58
59
60#
61# Main program starts here
62#
63
64my $sock = Rcon::sock_connect($HOST, $PORT);
65if (!$sock) {
66    print "Could not open socket to $HOST:$PORT.\n";
67    exit 1;
68}
69if (!Rcon::rcon_auth($sock, $PASS)) {
70    print "Could not authenticate.\n";
71    exit 1;
72}
73
74my $reply = Rcon::rcon_command($sock, "stats");
75if (!defined($reply)) {
76    print "Did not receive reply from server.\n";
77    exit 1;
78}
79my @reply = split(/\n/, $reply);
80
81foreach my $statline (@reply) {
82    next if ($statline !~ m/\s*[\w+\.]+\s+[\w+\.]+\s+[\w+\.]+\s+\d+\s+\d+\s+[\w+\.]+\s+\d+/);
83    my ($cpu, $in, $out, $uptime, $users, $fps, $players) = ($statline =~ m/^\s*([\w+\.]+)\s+([\w+\.]+)\s+([\w+\.]+)\s+(\d+)\s+(\d+)\s+([\w+\.]+)\s+(\d+)/);
84
85    if (defined($players)) {
86	print "players.value $players\n";
87    }
88}
89
90
91sub print_config {
92    print("graph_title Number of players at $HOST:$PORT\n",
93	  "graph_args --base 1000\n",
94	  "graph_vlabel Players\n",
95	  "graph_category games\n",
96	  "graph_info The number of players on Source game server, such as HL2, CS:S and DoD:S.\n");
97
98    print ("players.label Players\n",
99	   "players.min 0\n",
100	   "players.max $MAX\n",
101	   "players.type GAUGE\n");
102}
103
104
105sub test_service {
106    my $sock = Rcon::sock_connect($HOST, $PORT);
107    if (!$sock) {
108	print "no (could not open socket to $HOST:$PORT)\n";
109	exit 0;
110    }
111    if (!Rcon::rcon_auth($sock, $PASS)) {
112	print "no (could not authenticate)\n";
113	exit 0;
114    }
115    if (!defined(Rcon::rcon_command($sock, "stats"))) {
116	print "no (did not receive reply from server)\n";
117	exit 0;
118    }
119
120    print "yes\n";
121    exit 0;
122}
123