Browse Source

game_servers: let socket.timeout bubble up

Related to #140
0.9
Rossen Georgiev 7 years ago
parent
commit
e38e87e593
  1. 66
      steam/game_servers.py

66
steam/game_servers.py

@ -120,7 +120,7 @@ from bz2 import decompress as _bz2_decompress
from re import match as _re_match
from struct import pack as _pack, unpack_from as _unpack_from
from time import time as _time
from enum import IntEnum, Enum
from enum import IntEnum
from steam.util.binary import StructReader
@ -161,7 +161,7 @@ def query_master(filter_text=r'\napp\500', region=MSRegion.World, master=MSServe
:type region: :class:`.MSRegion`
:param master: (optional) master server to query
:type master: (:class:`str`, :class:`int`)
:raises: This function will raise in various situations
:raises: :class:`RuntimeError`, :class:`socket.timeout`
:returns: a generator yielding (ip, port) pairs
:rtype: :class:`generator`
"""
@ -292,8 +292,9 @@ def a2s_info(server_addr, timeout=2, force_goldsrc=False):
:type force_goldsrc: :class:`bool`
:param timeout: (optional) timeout in seconds
:type timeout: float
:raises: :class:`RuntimeError`, :class:`socket.timeout`
:returns: a dict with information or `None` on timeout
:rtype: :class:`dict`, :class:`None`
:rtype: :class:`dict`
"""
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss.connect(server_addr)
@ -306,36 +307,32 @@ def a2s_info(server_addr, timeout=2, force_goldsrc=False):
# handle response(s)
try:
data = _handle_a2s_response(ss)
except socket.timeout:
except:
ss.close()
return None
raise
ping = max(0.0, _time() - start) * 1000
if force_goldsrc:
if data[4:5] != b'm':
ss.close()
return None
raise socket.timeout('time out')
else:
# we got a valid GoldSrc response, check if it is followed by Source response
if data[4:5] == b'm':
ss.settimeout(0.3)
try:
data2 = _handle_a2s_response(ss)
data = _handle_a2s_response(ss)
except socket.timeout:
pass
if data2[4:5] == b'I':
data = data2
ss.close()
data = StructReader(data)
data.skip(4) # packet header
header, = data.unpack('<c')
header, = data.unpack('<4xc')
# invalid header
if header not in b'mI':
return None
raise RuntimeError("Invalid reponse header - %s" % repr(header))
# GoldSrc response
elif header == b'm':
info = {
@ -402,8 +399,9 @@ def a2s_players(server_addr, timeout=2, challenge=0):
:type timeout: float
:param challenge: (optional) challenge number
:type challenge: int
:raises: :class:`RuntimeError`, :class:`socket.timeout`
:returns: a list of players
:rtype: :class:`list`, :class:`None`
:rtype: :class:`list`
"""
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss.connect(server_addr)
@ -411,11 +409,12 @@ def a2s_players(server_addr, timeout=2, challenge=0):
# request challenge number
if challenge in (-1, 0):
ss.send(_pack('<lci', -1, b'U', challenge))
try:
ss.send(_pack('<lci', -1, b'U', challenge))
except socket.timeout:
return None
_, header, challange = _unpack_from('<lcl', ss.recv(512))
_, header, challange = _unpack_from('<lcl', ss.recv(512))
except:
ss.close()
raise
if header != b'A':
raise RuntimeError("Unexpected challange response - %s" % repr(header))
@ -425,13 +424,10 @@ def a2s_players(server_addr, timeout=2, challenge=0):
try:
data = StructReader(_handle_a2s_response(ss))
except socket.timeout:
return None
finally:
ss.close()
data.skip(4) # skip packet header
header, num_players = data.unpack('<cB')
header, num_players = data.unpack('<4xcB')
if header != b'D':
return None
@ -461,8 +457,9 @@ def a2s_rules(server_addr, timeout=2, challenge=0):
:type timeout: float
:param challenge: (optional) challenge number
:type challenge: int
:raises: :class:`RuntimeError`, :class:`socket.timeout`
:returns: a list of players
:rtype: :class:`list`, :class:`None`
:rtype: :class:`list`
"""
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss.connect(server_addr)
@ -470,11 +467,12 @@ def a2s_rules(server_addr, timeout=2, challenge=0):
# request challenge number
if challenge in (-1, 0):
ss.send(_pack('<lci', -1, b'V', challenge))
try:
ss.send(_pack('<lci', -1, b'V', challenge))
except socket.timeout:
return None
_, header, challange = _unpack_from('<lcl', ss.recv(512))
_, header, challange = _unpack_from('<lcl', ss.recv(512))
except:
ss.close()
raise
if header != b'A':
raise RuntimeError("Unexpected challange response")
@ -484,13 +482,10 @@ def a2s_rules(server_addr, timeout=2, challenge=0):
try:
data = StructReader(_handle_a2s_response(ss))
except socket.timeout:
return None
finally:
ss.close()
data.skip(4) # skip packet header
header, num_rules = data.unpack('<cH')
header, num_rules = data.unpack('<4xcH')
if header != b'E':
return None
@ -503,6 +498,8 @@ def a2s_rules(server_addr, timeout=2, challenge=0):
if _re_match(r'^\-?[0-9]+$', value):
value = int(value)
elif _re_match(r'^\-?[0-9]+\.[0-9]+$', value):
value = float(value)
rules[name] = value
@ -513,15 +510,16 @@ def a2s_ping(server_addr, timeout=2):
"""Ping a server
.. warning::
This method for pinging is considered deprecated and will not work on newer sources games.
This method for pinging is considered deprecated and may not work on certian servers.
Use :func:`.a2s_info` instead.
:param server_addr: (ip, port) for the server
:type server_addr: tuple
:param timeout: (optional) timeout in seconds
:type timeout: float
:raises: :class:`RuntimeError`, :class:`socket.timeout`
:returns: ping response in milliseconds or `None` for timeout
:rtype: :class:`float`, :class:`None`
:rtype: :class:`float`
"""
ss = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss.connect(server_addr)
@ -532,8 +530,6 @@ def a2s_ping(server_addr, timeout=2):
try:
data = _handle_a2s_response(ss)
except socket.timeout:
return None
finally:
ss.close()

Loading…
Cancel
Save