From 6d6deda946457edbcad8bfc1e2c1c4301d629e37 Mon Sep 17 00:00:00 2001 From: m!nus Date: Sun, 27 Oct 2013 14:02:41 +0100 Subject: [PATCH] rewrote address handling, removed old example code --- example.py | 37 --------------------- find_by_ip.py | 39 ---------------------- teeworlds/base.py | 81 ++++++++++++++++++++++++++++----------------- teeworlds/master.py | 12 +++---- teeworlds/server.py | 8 ++--- 5 files changed, 59 insertions(+), 118 deletions(-) delete mode 100644 example.py delete mode 100644 find_by_ip.py diff --git a/example.py b/example.py deleted file mode 100644 index b8807c9..0000000 --- a/example.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/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.") diff --git a/find_by_ip.py b/find_by_ip.py deleted file mode 100644 index a31324c..0000000 --- a/find_by_ip.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/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.") diff --git a/teeworlds/base.py b/teeworlds/base.py index 5c260af..11cd117 100644 --- a/teeworlds/base.py +++ b/teeworlds/base.py @@ -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 diff --git a/teeworlds/master.py b/teeworlds/master.py index 28f3023..b599118 100644 --- a/teeworlds/master.py +++ b/teeworlds/master.py @@ -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) diff --git a/teeworlds/server.py b/teeworlds/server.py index 2736635..e964bda 100644 --- a/teeworlds/server.py +++ b/teeworlds/server.py @@ -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 -- GitLab