Make master server work with Python 3.

As part of this, perform the `from __future__` imports so that as much
as possible resembles Python 3 even if we are running with Python 2.
This commit is contained in:
Simon Howard 2019-02-09 21:24:40 -05:00
parent c0975c8f53
commit 4c7861b2e0
4 changed files with 56 additions and 52 deletions

View file

@ -21,9 +21,11 @@
# Chocolate Doom master server. # Chocolate Doom master server.
# #
from __future__ import division, generators, unicode_literals, print_function
import socket import socket
import struct import struct
import simplejson import json
from select import select from select import select
from time import time, strftime from time import time, strftime
from master_config import * from master_config import *
@ -213,18 +215,16 @@ class MasterServer:
""" Convert a list of strings into a list of payload strings """ Convert a list of strings into a list of payload strings
for responding to queries. """ for responding to queries. """
packets = [struct.pack("")] packets = [b""]
for string in strings: for string in strings:
# Encode string along with terminating NUL. # Encode string along with terminating NUL.
encoded_str = string.encode("utf8") + b"\x00"
encoded_str = struct.pack("%is" % (len(string) + 1), string)
# Start a new packet? # Start a new packet?
if len(packets[-1]) + len(encoded_str) > MAX_RESPONSE_LEN: if len(packets[-1]) + len(encoded_str) > MAX_RESPONSE_LEN:
packets.append(struct.pack("")) packets.append(b"")
packets[-1] += encoded_str packets[-1] += encoded_str
@ -298,7 +298,7 @@ class MasterServer:
def metadata_string(server): def metadata_string(server):
metadata = server.metadata.copy() metadata = server.metadata.copy()
metadata["age"] = server.age() metadata["age"] = server.age()
return simplejson.dumps(metadata).encode('utf8') return json.dumps(metadata).encode('utf8')
# Generate a list of strings containing JSON-encoded metadata # Generate a list of strings containing JSON-encoded metadata
# about servers. Only include verified servers. # about servers. Only include verified servers.
@ -383,8 +383,8 @@ class MasterServer:
try: try:
self.process_packet(data, addr) self.process_packet(data, addr)
except Exception, e: except Exception as e:
print e print("error on packet from %s: %s" % (addr, e))
def rx_packet_query_sock(self): def rx_packet_query_sock(self):
""" Invoked when a packet is received on the query socket. """ """ Invoked when a packet is received on the query socket. """
@ -393,13 +393,13 @@ class MasterServer:
try: try:
self.process_query_response(data, addr) self.process_query_response(data, addr)
except Exception, e: except Exception as e:
print e print("error on query socket packet from %s: %s" % (addr, e))
def age_servers(self): def age_servers(self):
""" Check server timestamps and flush out stale servers. """ """ Check server timestamps and flush out stale servers. """
servers = list(self.servers.values())
for server in self.servers.values(): for server in servers:
if server.timed_out(): if server.timed_out():
self.log_output(server.addr, self.log_output(server.addr,
"Timed out: no heartbeat in %i secs" % "Timed out: no heartbeat in %i secs" %

View file

@ -21,10 +21,12 @@
# Test script for querying the master server. # Test script for querying the master server.
# #
from __future__ import division, generators, unicode_literals, print_function
import socket import socket
import sys import sys
import struct import struct
import simplejson import json
NET_MASTER_PACKET_TYPE_ADD = 0 NET_MASTER_PACKET_TYPE_ADD = 0
NET_MASTER_PACKET_TYPE_ADD_RESPONSE = 1 NET_MASTER_PACKET_TYPE_ADD_RESPONSE = 1
@ -37,7 +39,7 @@ NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE = 7
NET_MASTER_PACKET_TYPE_SIGN_END = 8 NET_MASTER_PACKET_TYPE_SIGN_END = 8
NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE = 9 NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE = 9
UDP_PORT = 2342 UDP_PORT = 5000 # DO NOT SUBMIT
def send_message(sock, addr, message_type, payload=None): def send_message(sock, addr, message_type, payload=None):
header = struct.pack(">h", message_type) header = struct.pack(">h", message_type)
@ -63,7 +65,7 @@ def get_response(sock, addr, message_type):
return packet[2:] return packet[2:]
print "Rxed from %s, expected %s" % (remote_addr, addr) print("Rxed from %s, expected %s" % (remote_addr, addr))
def read_string(packet): def read_string(packet):
terminator = struct.pack("b", 0) terminator = struct.pack("b", 0)
@ -81,13 +83,13 @@ def add_to_master(addr_str):
# Send request # Send request
print "Sending request to master at %s" % str(addr) print("Sending request to master at %s" % str(addr))
send_message(sock, addr, NET_MASTER_PACKET_TYPE_ADD) send_message(sock, addr, NET_MASTER_PACKET_TYPE_ADD)
# Wait for response. # Wait for response.
print "Waiting for response..." print("Waiting for response...")
response = get_response(sock, addr, NET_MASTER_PACKET_TYPE_ADD_RESPONSE) response = get_response(sock, addr, NET_MASTER_PACKET_TYPE_ADD_RESPONSE)
@ -96,7 +98,7 @@ def add_to_master(addr_str):
if not success: if not success:
raise Exception("Address not successfully added to master.") raise Exception("Address not successfully added to master.")
print "Address added to master." print("Address added to master.")
def decode_string_list(packet): def decode_string_list(packet):
""" Decode binary data containing NUL-terminated strings. """ """ Decode binary data containing NUL-terminated strings. """
@ -118,22 +120,22 @@ def query_master(addr_str):
# Send request # Send request
print "Sending query to master at %s" % str(addr) print("Sending query to master at %s" % str(addr))
send_message(sock, addr, NET_MASTER_PACKET_TYPE_QUERY) send_message(sock, addr, NET_MASTER_PACKET_TYPE_QUERY)
# Receive response # Receive response
print "Waiting for response..." print("Waiting for response...")
response = get_response(sock, addr, NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) response = get_response(sock, addr, NET_MASTER_PACKET_TYPE_QUERY_RESPONSE)
servers = decode_string_list(response) servers = decode_string_list(response)
print "%i servers" % len(servers) print("%i servers" % len(servers))
for s in servers: for s in servers:
print "\t%s" % s print("\t%s" % s)
def get_metadata(addr_str): def get_metadata(addr_str):
""" Query a master server for metadata about its servers. """ """ Query a master server for metadata about its servers. """
@ -143,28 +145,28 @@ def get_metadata(addr_str):
# Send request # Send request
print "Sending metadata query to master at %s" % str(addr) print("Sending metadata query to master at %s" % str(addr))
send_message(sock, addr, NET_MASTER_PACKET_TYPE_GET_METADATA) send_message(sock, addr, NET_MASTER_PACKET_TYPE_GET_METADATA)
# Receive response # Receive response
print "Waiting for response..." print("Waiting for response...")
response = get_response(sock, addr, response = get_response(sock, addr,
NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE) NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE)
servers = decode_string_list(response) servers = decode_string_list(response)
print "%i servers" % len(servers) print("%i servers" % len(servers))
for json in servers: for server in servers:
metadata = simplejson.loads(json) metadata = json.loads(server)
print "\tServer: %s:%i" % (metadata["address"], metadata["port"]) print("\tServer: %s:%i" % (metadata["address"], metadata["port"]))
print "\t\tAge: %i seconds" % metadata["age"] print("\t\tAge: %i seconds" % metadata["age"])
print "\t\tName: %s" % metadata["name"] print("\t\tName: %s" % metadata["name"])
print "\t\tVersion: %s" % metadata["version"] print("\t\tVersion: %s" % metadata["version"])
print "\t\tMax. players: %i" % metadata["max_players"] print("\t\tMax. players: %i" % metadata["max_players"])
def sign_start(addr_str): def sign_start(addr_str):
""" Request a signed start message from the master. """ """ Request a signed start message from the master. """
@ -174,20 +176,20 @@ def sign_start(addr_str):
# Send request # Send request
print "Sending signed start request to master at %s" % str(addr_str) print("Sending signed start request to master at %s" % str(addr_str))
send_message(sock, addr, NET_MASTER_PACKET_TYPE_SIGN_START) send_message(sock, addr, NET_MASTER_PACKET_TYPE_SIGN_START)
# Receive response # Receive response
print "Waiting for response..." print("Waiting for response...")
response = get_response(sock, addr, response = get_response(sock, addr,
NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE) NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE)
nonce = response[0:16] nonce = response[0:16]
signature = response[16:] signature = response[16:]
print "Binary nonce: %s" % ("".join(map(lambda x: "%02x" % ord(x), nonce))) print("Binary nonce: %s" % ("".join("%02x" % x for x in nonce)))
print signature print(signature)
def sign_end(addr_str): def sign_end(addr_str):
""" Request a signed end message from the server. """ """ Request a signed end message from the server. """
@ -195,21 +197,21 @@ def sign_end(addr_str):
addr = (socket.gethostbyname(addr_str), UDP_PORT) addr = (socket.gethostbyname(addr_str), UDP_PORT)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print "Paste the start message, then type ^D" print("Paste the start message, then type ^D")
start_message = sys.stdin.read() start_message = sys.stdin.read()
fake_sha1 = "3ijAI83u8A(*j98jf3jf" fake_sha1 = "3ijAI83u8A(*j98jf3jf"
print "Sending signed end request to master at %s" % str(addr_str) print("Sending signed end request to master at %s" % str(addr_str))
send_message(sock, addr, NET_MASTER_PACKET_TYPE_SIGN_END, send_message(sock, addr, NET_MASTER_PACKET_TYPE_SIGN_END,
payload=(fake_sha1 + start_message)) payload=(fake_sha1 + start_message))
print "Waiting for response..." print("Waiting for response...")
response = get_response(sock, addr, response = get_response(sock, addr,
NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE) NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE)
print response print(response)
commands = [ commands = [
("query", query_master), ("query", query_master),
@ -224,10 +226,10 @@ for name, callback in commands:
callback(sys.argv[2]) callback(sys.argv[2])
break break
else: else:
print "Usage:" print("Usage:")
print "chocolate-master-test.py query <address>" print("chocolate-master-test.py query <address>")
print "chocolate-master-test.py add <address>" print("chocolate-master-test.py add <address>")
print "chocolate-master-test.py get-metadata <address>" print("chocolate-master-test.py get-metadata <address>")
print "chocolate-master-test.py sign-start <address>" print("chocolate-master-test.py sign-start <address>")
print "chocolate-master-test.py sign-end <address>" print("chocolate-master-test.py sign-end <address>")

View file

@ -35,7 +35,7 @@ METADATA_REFRESH_TIME = 6 * 60 * 60 # 6 hours
# Address and port to listen on. # Address and port to listen on.
SERVER_ADDRESS = (None, 2342) SERVER_ADDRESS = (None, 5000)
# Address and port to bind query socket. # Address and port to bind query socket.

View file

@ -23,6 +23,8 @@
# back to the clients. # back to the clients.
# #
from __future__ import division, generators, unicode_literals, print_function
from io import BytesIO from io import BytesIO
import os import os
import sys import sys
@ -142,16 +144,16 @@ class SecureSigner(object):
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) < 3: if len(sys.argv) < 3:
print "Usage: %s <start|end> <key>" % sys.argv[0] print("Usage: %s <start|end> <key>" % sys.argv[0])
sys.exit(1) sys.exit(1)
signer = SecureSigner(sys.argv[2]) signer = SecureSigner(sys.argv[2])
if sys.argv[1] == "start": if sys.argv[1] == "start":
nonce, start_message = signer.sign_start_message() nonce, start_message = signer.sign_start_message()
print "Nonce: %s" % bin_to_hex(nonce) print("Nonce: %s" % bin_to_hex(nonce))
print start_message print(start_message)
elif sys.argv[1] == "end": elif sys.argv[1] == "end":
start_message = sys.stdin.read() start_message = sys.stdin.read()
fake_checksum = "3vism1idm4ibmaJ3nF1f" fake_checksum = "3vism1idm4ibmaJ3nF1f"
print signer.sign_end_message(start_message, fake_checksum) print(signer.sign_end_message(start_message, fake_checksum))