From 026b5188407e7907b2c07d1c94fa7b77d303ff92 Mon Sep 17 00:00:00 2001 From: Hipstercat Date: Tue, 18 Jun 2019 12:20:49 +0200 Subject: [PATCH] More documentation --- masterserver.py | 76 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/masterserver.py b/masterserver.py index b69b301..d305933 100644 --- a/masterserver.py +++ b/masterserver.py @@ -1,34 +1,62 @@ +import logging import socket import threading import datetime import time import traceback -SERVERS = [{"ip": "136.143.97.184", "port": 19711, "last":datetime.datetime.now()}, - {"ip": "73.181.147.35", "port": 19711, "last": datetime.datetime.now()}, - {"ip": "artolsheim.hipstercat.fr", "port": 19711, "last": datetime.datetime.now()}] +# List of servers always up +DEDICATED_SERVERS = [{"ip": "136.143.97.184", "port": 19711, "last": datetime.datetime.now()}, + {"ip": "73.181.147.35", "port": 19711, "last": datetime.datetime.now()}, + {"ip": "artolsheim.hipstercat.fr", "port": 19711, "last": datetime.datetime.now()}] + +SERVERS = DEDICATED_SERVERS.copy() + + +def setup_logger(name): + # setup logger + _ch = logging.StreamHandler() + _ch.setLevel("DEBUG") + _formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + _ch.setFormatter(_formatter) + logger = logging.getLogger(name) + logger.addHandler(_ch) + logger.setLevel("DEBUG") + logger.debug("Logger initialized") + return logger + + +logger = setup_logger(__name__) + def main(): listen_ip = "0.0.0.0" + # register socket. dedicated servers send packets to this socket to register. registersock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) registersock.bind((listen_ip, 27900)) - print("Listening on", listen_ip, 27900) + logger.info("Register server listening on %s UDP %s", listen_ip, 27900) + # query socket. clients use this socket to query available servers. querysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) querysock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) querysock.bind((listen_ip, 28900)) - print("Listening on", listen_ip, 28900) + print("Query server listening on %s TCP %s", listen_ip, 28900) querysock.listen(5) + # everything is threaded. registerthread = threading.Thread(target=registerloop, args=(registersock,)) querythread = threading.Thread(target=queryloop, args=(querysock,)) + + # clean thread is used to clean older server that haven't updated in a while cleanthread = threading.Thread(target=cleanloop) + # start everything querythread.start() registerthread.start() cleanthread.start() + # wait until everything is finished (which will never happen because they are all running in a loop) querythread.join() registerthread.join() cleanthread.join() @@ -36,8 +64,11 @@ def main(): def queryloop(querysock): while True: + # new query incoming from a client (clientsocket, (_, _)) = querysock.accept() - print("A new client has come") + logger.info("Query from %s:%s", clientsocket[0], clientsocket[1]) + + # forge the response b = b'' for i in range(len(SERVERS)): ip = SERVERS[i]["ip"] @@ -47,42 +78,57 @@ def queryloop(querysock): b += b'\xac' b += str(SERVERS[i]["port"]).encode("ascii") b += b'\x00' - print("Sending back", b) + logger.info("Sending back %s", b.decode('utf8')) + + # send it clientsocket.send(b) + # close the socket + clientsocket.close() + + def registerloop(registersock): while True: + # new register incoming from a server data, (ip, port) = registersock.recvfrom(1024) try: + # first byte is some kind of opcode, so we leave it. the rest is the game port gameport = data[1:].decode("ascii") if int(gameport): + # game port sent. now we try to reach the server to avoid registering of servers unreachable. tempsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) tempsocket.settimeout(5) + + # we try to send a "status" packet to the server. tempsocket.sendto("\\status\\".encode("ascii"), (ip, port)) tempsocket.recvfrom(1024) + + # server will be None if it has not been seen before, or something else if it has been seen server = next((x for x in SERVERS if x["ip"] == ip and x["port"] == gameport), None) if not server: SERVERS.append({"ip": ip, "port": gameport, "last": datetime.datetime.now()}) - print("New server: %s:%s" % (ip, gameport)) + logger.info("New server: %s:%s" % (ip, gameport)) else: server["last"] = datetime.datetime.now() - print("Keepalive from: %s:%s" % (ip, gameport)) + logger.info("Keepalive from: %s:%s" % (ip, gameport)) tempsocket.close() else: + # server sent shit, discard it print("Fuck it, wasn't int: ", data) except Exception as e: + # something wrong happened but we don't know what print("Exception") traceback.print_exc() + def cleanloop(): + # clean loop removes servers that haven't registered or sent a packet in the last 2 minutes + # but don't remove known dedicated servers while True: now = datetime.datetime.now() for server in SERVERS: - if now > server["last"] + datetime.timedelta(minutes=2): - if server["ip"] == "136.143.97.184" or server["ip"] == "73.181.147.35" or server["ip"] == "artolsheim.hipstercat.fr": - # do not remove usual dedicated servers - continue - print("Deleting %s:%s" % (server["ip"], server["port"])) + if now > server["last"] + datetime.timedelta(minutes=2) and server not in DEDICATED_SERVERS: + logger.info("Deleting %s:%s" % (server["ip"], server["port"])) try: SERVERS.remove(server) except ValueError: @@ -91,4 +137,4 @@ def cleanloop(): if __name__ == '__main__': - main() \ No newline at end of file + main()