Commit 6d6deda9 authored by m!nus's avatar m!nus

rewrote address handling, removed old example code

parent 8f0d857d
#!/usr/bin/env python2
from teeworlds.teeworlds import Teeworlds
# set up stuff
tw = Teeworlds(timeout=2)
# ask the masters for servers
tw.query_masters()
# query servers, wait for responses
# stops if no packet is received for `timeout` seconds
tw.run_loop()
# filter the serverlist
servers = tw.serverlist.find(name="^C", # Server whose name begins with "C", regex style
gametype="CTF", # gametype contains "CTF"
maxping=0.1) # ping is lower or equal to 100ms
# sort by ping
servers.sort(key=lambda s: s.latency)
# display a nice list
for server in servers:
print("{server: <64} [{gametype: ^16}] on {master}: {clients: >2}/{max_clients: <2} - {latency: >4.0f} ms" \
.format(server=server.name, gametype=server.gametype, master=server.master.name, clients=server.clients, \
max_clients=server.max_clients, latency=server.latency*1000))
# check if m!nus is currently playing
minus_list = tw.playerlist.find(name="^m!nus$")
if minus_list.players:
minus = minus_list.players[0]
print("m!nus is currently playing on {server} ({address}) with {players} other player(s)."
.format(server=minus.server.name, address=minus.server.address, players=(minus.server.players-1)))
else:
print("m!nus isn't playing at the moment.")
#!/usr/bin/env python2
import sys
from teeworlds.teeworlds import Teeworlds
# set up stuff
tw = Teeworlds(timeout=2)
# ask the masters for servers
tw.query_masters()
# query servers, wait for responses
# stops if no packet is received for `timeout` seconds
tw.run_loop()
# filter the serverlist
ip_filter = "^"+sys.argv[1].replace(".", "\\.")
servers = tw.serverlist.find(address=ip_filter)
# sort by ping
servers.sort(key=lambda s: s.address)
# display a nice list
for server in servers:
print("{server: <64} {address: <15} [{gametype: ^16}] on {master}: {clients: >2}/{max_clients: <2} - {latency: >4.0f} ms" \
.format(server=server.name, address=server.address, gametype=server.gametype, master=server.master.name, clients=server.clients, \
max_clients=server.max_clients, latency=server.latency*1000))
# check if m!nus is currently playing
#minus_list = tw.playerlist.find(name="^m!nus$")
#if minus_list.players:
# minus = minus_list.players[0]
# print("m!nus is currently playing on {server} ({address}) with {players} other player(s)."
# .format(server=minus.server.name, address=minus.server.address, players=(minus.server.players-1)))
#else:
# print("m!nus isn't playing at the moment.")
......@@ -13,39 +13,60 @@ L = logging.getLogger(__name__)
def get_address(host, port=8303, family=0):
try:
info = socket.getaddrinfo(host, port, family, socket.SOCK_DGRAM)
return info[0][4]
return Address(info[0][4][0], info[0][4][1], family)
except socket.gaierror as e:
L.warning('getaddrinfo failed: ' + str(e))
return None
def is_ipv6(address):
if isinstance(address, tuple): address = address[0]
# TODO: should be more solid
return True if ':' in address else False
def ip_from_data(data):
def listdata2addresslist(listdata):
"""takes 6 or 18 bytes of data and extracts IPv4/v6 addresses from it
returns a tuple (family, address)
"""
# ::ffff:0:0/96 == IPv4 mapping
if data[0:12] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
data = data[12:18]
if len(data) == 6:
return (socket.inet_ntoa(data[:4]), unpack("!H", data[4:])[0])
elif len(data) == 18:
address = None
port = unpack("!H", data[16:])[0]
if sys.platform == "win32":
segments = []
for (a, b) in (data[:16:2], data[1:16:2]):
segments.append("{:x}".format((ord(a)<<8) + ord(b)))
address = ':'.join(segments)
addresses = []
for i in range(0, len(listdata), 18):
data = listdata[i:i+18]
# ::ffff:0:0/96 == IPv4 mapping
if data[0:12] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
data = data[12:18]
if len(data) == 6:
host = socket.inet_ntoa(data[:4])
port = unpack("!H", data[4:])[0]
addresses.append(Address(host, port, socket.AF_INET))
elif len(data) == 18:
host = None
port = unpack("!H", data[16:])[0]
if sys.platform == "win32":
segments = []
for (a, b) in (data[:16:2], data[1:16:2]):
segments.append("{:x}".format((ord(a)<<8) + ord(b)))
host = ':'.join(segments)
else:
host = socket.inet_ntop(socket.AF_INET6, data[:16])
addresses.append(Address(host, port, socket.AF_INET6))
else:
address = socket.inet_ntop(socket.AF_INET6, data[:16])
return (address, port)
else:
raise Exception("Invalid IP data")
raise Exception("Invalid IP data")
return addresses
class Address(object):
def __init__(self, host=None, port=None, family=None):
self.host = host
self.port = port
self.family = family
def address_tuple(self):
return (self.host, self.port)
def __lt__(self, other):
return self.address_tuple() < other.address_tuple()
def __str__(self):
if self.family == socket.AF_INET6:
return "[{host}]:{port}".format(self.host, self.port)
return "{host}:{port}".format(host=self.host, port=self.port)
class Request(object):
......@@ -62,7 +83,7 @@ class Request(object):
return False
def get_address(self):
"""must return destination address as a tuple (host, port)"""
"""must return destination address, an Address object"""
return self.address
def get_data(self):
......@@ -115,12 +136,13 @@ class EventSocket(object):
def _send(self, request):
"""Actually send request"""
socket_type = socket.AF_INET
if is_ipv6(request.get_address()):
addr = request.get_address()
if addr.family == socket.AF_INET6:
if not self.has_ipv6:
raise socket.error("Cannot send IPv6 packet without IPv6 socket")
socket_type = socket.AF_INET6
self._requests[request.get_address()].add(request)
length = self._sockets[socket_type].sendto(request.get_data(), request.get_address())
self._requests[addr.address_tuple()].add(request)
length = self._sockets[socket_type].sendto(request.get_data(), addr.address_tuple())
L.debug("Sent {}".format(request))
request.sent()
self._packet_rate += 1
......@@ -142,7 +164,6 @@ class EventSocket(object):
try:
length = self._send(request)
if length != len(data):
# TODO: resend?
L.warning('Sent {} of {} bytes of {}'.format(length, len(data)))
except socket.error as e:
if e.errno == 10054: # ICMP port unreachable
......
......@@ -58,15 +58,13 @@ class MasterServer(object):
def __init__(self, socket, address, name=None):
self._socket = socket
self._address = address
self.address = ("[{host}]:{port}" if is_ipv6(address) else "{host}:{port}") \
.format(host=address[0], port=address[1])
self.address = address
self.name = name or "None"
self.latency = None
self.serverlist = []
self.count = None
self._request_count = self.Count(self._address, self._count_response)
self._request_list = self.List(self._address, self.add_from_serverlist)
self._request_count = self.Count(self.address, self._count_response)
self._request_list = self.List(self.address, self.add_from_serverlist)
def request_list(self):
self.on_list_request(self._request_list)
......@@ -82,8 +80,8 @@ class MasterServer(object):
"""
if len(data) % self.List.serveraddr_size != 0:
L.warning("Serverlist data length is not a multiple of {}".format(self.List.serveraddr_size))
for i in range(0, len(data), self.List.serveraddr_size):
server = Server(self._socket, ip_from_data(data[i:i+self.List.serveraddr_size]), master=self)
for address in listdata2addresslist(data):
server = Server(self._socket, address, master=self)
self.serverlist.append(server)
self.on_server_add(server)
......
......@@ -41,20 +41,18 @@ class Server(object):
self.data_cb(pieces)
def __init__(self, socket, address, master=None):
self._address = address
self.address = ("[{host}]:{port}" if is_ipv6(address) else "{host}:{port}") \
.format(host=address[0], port=address[1])
self.address = address
self._socket = socket
self.master = master
self.data = None
self.reset()
def reset(self):
self._request = self.Info(self._address, self.parse)
self._request = self.Info(self.address, self.parse)
self.latency = None
self.playerlist = []
self.version = None
self.name = self.address
self.name = str(self.address)
self.map = None
self.gametype = None
self.password = None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment