# -*- coding: UTF-8 -*-
import socket
import sys
timeout = 1.7
server_host = "localhost"
server_port = 25565
# Minecraft Ping protocol to use:
# 1 = Minecraft Beta 1.8 - Minecraft 1.3
# 2 = Minecraft 1.4 - 1.5
# 3 = Minecraft 1.6
protocol = 1
# Parse the command line arguments
# We can have '[host]', '[host] [port]', '[host:port]',
# '[host] [port] [timeout]' or '[host:port] [timeout]'
if len(sys.argv) == 2:
if ':' in sys.argv[1]:
tmp = str(sys.argv[1]).split(':')
server_host = str(tmp[0])
server_port = int(tmp[1])
else:
server_host = str(sys.argv[1])
elif len(sys.argv) >= 3:
if ':' in sys.argv[1]:
tmp = str(sys.argv[1]).split(':')
server_host = str(tmp[0])
server_port = int(tmp[1])
timeout = float(sys.argv[2])
else:
server_host = str(sys.argv[1])
server_port = int(sys.argv[2])
if len(sys.argv) >= 4:
timeout = float(sys.argv[3])
if len(sys.argv) >= 5:
protocol = int(sys.argv[4])
#print str('host: {} port: {} timeout: {}').format(server_host, server_port, timeout)
#sys.exit()
def ping(host, port, timeout = 1.7, protocol = 1):
"""Ping the server and return the values the server gives us"""
if protocol == 1:
# Send 0xFE: Server list ping (Minecraft Beta 1.8 - 1.3)
msg = "\xFE"
#sock.sendall("\xFE")
elif protocol == 2:
# Send 0xFE 0x01: Server list ping (Minecraft 1.4 - 1.5)
msg = "\xFE\x01"
#sock.sendall("\xFE\x01")
elif protocol == 3:
# Server list ping (Minecraft 1.6)
msg = "\xFE\x01\xFA"
msg += "\x00\x0B" # The length of the following string, in characters, as a short (always 11)
# "MC|PingHost" encoded as a big-endian UCS-2 string:
msg += "\x00\x4D\x00\x43\x00\x7C\x00\x50\x00\x69\x00\x6E\x00\x67\x00\x48\x00\x6F\x00\x73\x00\x74"
# FIXME/TODO:
# Alternatively:
#msg += str('MC|PingHost').encode('UTF-16BE')
#msg += "" # The length of the rest of the data, as a short. Compute as 7 + 2 * strlen(hostname)
#msg += "" # Protocol version, currently 74 (decimal)
#msg += "" # The length of following string, in characters, as a short
#msg += "" # The hostname the client is connecting to, encoded in the same way as "MC|PingHost"
#msg += "" # The port the client is connecting to, as an int
else:
print(str('ping(): Error, invalid protocol: {}').format(protocol))
return None
try:
#sock = socket.create_connection((server_address, server_port), timeout)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
#print('socket(): except:', msg)
sock = None
return None
try:
#sock.setblocking(0)
sock.settimeout(timeout)
sock.connect((host, port))
except socket.error as msg:
#print('connect(): except:', msg)
sock = None
return None
sock.sendall(msg)
try:
val = sock.recv(256)
except socket.error as msg:
sock.close()
#print('recv(): except:', msg)
return None
sock.shutdown(socket.SHUT_RDWR)
sock.close()
# Check for a valid 0xFF disconnect
if val[0] != "\xFF":
return None
if protocol == 1:
# Remove the packet ident (0xFF) and the short containing the length of the string
# Minecraft Beta 1.8 - 1.3
val = val[3:]
elif protocol == 2 or protocol == 3:
# Remove the packet ident (0xFF) and the short containing the length of the string
# and the rest of the crap
# Minecraft 1.4 - 1.5, 1.6
val = val[9:]
# Decode UCS-2 string
#val = val.decode('UTF-16LE')
val = val.decode('UTF-16BE')
if protocol == 1:
# Split into a list (Minecraft Beta 1.8 - 1.3)
val = val.split(u"\xA7")
elif protocol == 2 or protocol == 3:
# Split into a list (Minecraft 1.4 - 1.5, 1.6)
val = val.split("\x00")
# Debug:
#print('Length of val:', len(val))
#print(val)
#return "foo"
#if len(val) < 3:
# return None
if len(val) == 3:
# Return a dictionary of values (Minecraft Beta 1.8 - 1.3)
# values: MOTD, num_player, max_players
return {'motd': val[0],\
'num_players': int(val[1]),\
'max_players': int(val[2])}
elif len(val) == 5:
# Return a dictionary of values (Minecraft 1.4 - 1.5, 1.6)
# values: protocol_version, version, MOTD, num_player, max_players
return {'protocol_version': int(val[0]),\
'version': val[1],\
'motd': val[2],\
'num_players': int(val[3]),\
'max_players': int(val[4])}
else:
return None
def check_server(host, port, timeout = 1.7, protocol = 1):
"""Check if the server is up by ping()ing it checking for the known keys"""
data = ping(host, port, timeout, protocol)
#print('host:', host, 'port:', port, data)
if type(data) is dict:
if 'version' in data:
msg = str('{}:{} ([{}], {}): OK').format(host, port, data['version'], data['motd'])
print msg
elif 'motd' in data:
msg = str('{}:{} ({}): OK').format(host, port, data['motd'])
print msg
#print '%s: up' % data['motd']
else:
msg = str('{}:{}: N/A').format(host, port)
print msg
#print '%s: down' % data['motd']
else:
msg = str('{}:{}: N/A').format(host, port)
print msg
return None
check_server(server_host, server_port, timeout, protocol)
Comments