diff --git a/gamespy_backend_server.py b/gamespy_backend_server.py index 1d7565e..85559b2 100644 --- a/gamespy_backend_server.py +++ b/gamespy_backend_server.py @@ -55,6 +55,9 @@ class GameSpyBackendServer(object): address = ("127.0.0.1", 27500) password = "" + #self.server_list['mariokartwii'] = [] + #self.server_list['mariokartwii'].append({'__session__': 1113766873, 'eb': '5000', 'ev': '5000', 'publicport': '61784', 'localip1': '190.190.190.190', 'gamename': 'mariokartwii', 'maxplayers': '11', 'dwc_mtype': '0', 'publicip': '167772642', 'dwc_mver': '90', 'rk': 'vs_123', 'natneg': '1', 'dwc_groupid': '0', 'localip0': '10.0.1.226', 'dwc_pid': '1', 'localport': '61784', 'statechanged': '1', 'dwc_suspend': '1', 'dwc_eval': '1', 'numplayers': '0', 'dwc_hoststate': '0', 'p': '0'}) + logger.log(logging.INFO, "Started server on %s:%d..." % (address[0], address[1])) manager = GameSpyServerDatabase(address = address, authkey = password) @@ -293,13 +296,13 @@ class GameSpyBackendServer(object): values.append({ 'value': int(lval & rval), 'type': TokenType.NUMBER}) if match == True: - #print "Matched: %s %s %s" % (l['value'], op, r['value']) + print "Matched: %s %s %s" % (l['value'], op, r['value']) matched_filters += 1 elif op != "&": # & doesn't need to be matched, so don't display a message for it - #print "Not matched: %s %s %s" % (l['value'], op, r['value']) + print "Not matched: %s %s %s" % (l['value'], op, r['value']) pass - #print "Matched %d/%d" % (matched_filters, filter_count) + print "Matched %d/%d" % (matched_filters, filter_count) # Add the server if everything was matched if matched_filters == filter_count: @@ -344,7 +347,7 @@ class GameSpyBackendServer(object): return servers - def update_server_list(self, gameid, session, value): + def update_server_list(self, gameid, session, value, console): # Make sure the user isn't hosting multiple servers or there isn't some left over server information that # never got handled properly (game crashed, etc). self.delete_server(gameid, session) @@ -355,6 +358,7 @@ class GameSpyBackendServer(object): # Add new server value['__session__'] = session + value['__console__'] = console logger.log(logging.DEBUG, "Added %s to the server list for %s" % (value, gameid)) self.server_list[gameid].append(value) diff --git a/gamespy_natneg_server.py b/gamespy_natneg_server.py index c4cb996..fb2856e 100644 --- a/gamespy_natneg_server.py +++ b/gamespy_natneg_server.py @@ -20,7 +20,7 @@ class GameSpyNatNegServer(object): self.secret_key_list = gs_utils.generate_secret_keys("gslist.cfg") def start(self): - # Start QR server + # Start natneg server address = ('0.0.0.0', 27901) # accessible to outside connections (use this if you don't know what you're doing) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) @@ -32,6 +32,7 @@ class GameSpyNatNegServer(object): recv_data, addr = s.recvfrom(2048) logger.log(logging.DEBUG, "Connection from %s:%d..." % (addr[0], addr[1])) + logger.log(logging.DEBUG, utils.pretty_print_hex(recv_data)) # Make sure it's a legal packet if recv_data[0:6] != bytearray([0xfd, 0xfc, 0x1e, 0x66, 0x6a, 0xb2]): @@ -44,6 +45,12 @@ class GameSpyNatNegServer(object): if recv_data[7] == '\x00': logger.log(logging.DEBUG, "Received initialization from %s:%s..." % (addr[0], addr[1])) + output = bytearray(recv_data[0:14]) + output += bytearray([0xff, 0xff, 0x6d, 0x16, 0xb5, 0x7d, 0xea ]) # Checked with Tetris DS, Mario Kart DS, and Metroid Prime Hunters, and this seems to be the standard response to 0x00 + output[7] = 0x01 # Initialization response + s.sendto(output, addr) + + # Try to connect to the server gameid = utils.get_string(recv_data, 0x16) client_id = "%02x" % ord(recv_data[13]) @@ -56,8 +63,6 @@ class GameSpyNatNegServer(object): self.session_list[gameid][session_id][client_id]['addr'] = addr clients = len(self.session_list[gameid][session_id]) - #if client_id in session_list[gameid][session_id]: - # clients -= 1 if clients > 0: # Someone else is waiting to connect, send message @@ -81,11 +86,6 @@ class GameSpyNatNegServer(object): logger.log(logging.DEBUG, "") #session_list[gameid][session_id][client_id]['connected'] = True - output = bytearray(recv_data[0:14]) - output += bytearray([0xff, 0xff, 0x6d, 0x16, 0xb5, 0x7d, 0xea ]) # Checked with Tetris DS, Mario Kart DS, and Metroid Prime Hunters, and this seems to be the standard response to 0x00 - output[7] = 0x01 # Initialization response - s.sendto(output, addr) - elif recv_data[7] == '\x06': # Was able to connect client_id = "%02x" % ord(recv_data[13]) logger.log(logging.DEBUG, "Received connected command from %s:%s..." % (addr[0], addr[1])) @@ -97,15 +97,15 @@ class GameSpyNatNegServer(object): if client_id not in self.session_list[gameid][session_id]: pass - #session_list[gameid][session_id][client_id]['connected'] = True + #self.session_list[gameid][session_id][client_id]['connected'] = True elif recv_data[7] == '\x0d': client_id = "%02x" % ord(recv_data[13]) logger.log(logging.DEBUG, "Received report command from %s:%s..." % (addr[0], addr[1])) logger.log(logging.DEBUG, utils.pretty_print_hex(recv_data)) - output[7] = 0x0e # Report response - s.sendto(output, addr) + recv_data[7] = 0x0e # Report response + s.sendto(recv_data, addr) else: # Was able to connect logger.log(logging.DEBUG, "Received unknown command %02x from %s:%s..." % (ord(recv_data[7]), addr[0], addr[1])) diff --git a/gamespy_qr_server.py b/gamespy_qr_server.py index 12ae1f8..4dc5cf1 100644 --- a/gamespy_qr_server.py +++ b/gamespy_qr_server.py @@ -5,6 +5,7 @@ import logging import socket import struct import gamespy.gs_utility as gs_utils +import gamespy.gs_database as gs_database import other.utils as utils from multiprocessing.managers import BaseManager @@ -27,6 +28,8 @@ class GameSpyQRServer(object): self.secretkey = "" # Parse gslist.cfg later self.sent_challenge = False self.address = address + self.console = 0 + self.playerid= 0 def __init__(self): self.sessions = {} @@ -36,6 +39,8 @@ class GameSpyQRServer(object): self.secret_key_list = gs_utils.generate_secret_keys("gslist.cfg") #self.log(logging.DEBUG, address, "Generated list of secret game keys...") + self.db = gs_database.GamespyDatabase() + GameSpyServerDatabase.register("update_server_list") GameSpyServerDatabase.register("delete_server") @@ -193,6 +198,17 @@ class GameSpyQRServer(object): self.sessions[session_id].secretkey = self.secret_key_list[k['gamename']] #print "Got secret key %s for %s" % (self.sessions[session_id].secretkey, k['gamename']) + if self.sessions[session_id].playerid == 0 and "dwc_pid" in k: + # Get the player's id and then query the profile to figure out what console they are on. + # The endianness of some server data depends on the endianness of the console, so we must be able + # to account for that. + self.sessions[session_id].playerid = int(k['dwc_pid']) + profile = self.db.get_profile_from_profileid(self.sessions[session_id].playerid) + + if "console" in profile: + self.sessions[session_id].console = profile['console'] + + if self.sessions[session_id].sent_challenge == False: addr_hex = ''.join(["%02X" % int(x) for x in address[0].split('.')]) port_hex = "%04X" % int(address[1]) @@ -218,7 +234,7 @@ class GameSpyQRServer(object): # dwc_mtype = 3 is used when looking for a friends only game (possibly other uses too). # Some memory could be saved by clearing out any unwanted fields from k before sending. - self.server_manager.update_server_list(k['gamename'] , session_id, k) + self.server_manager.update_server_list(k['gamename'] , session_id, k, self.sessions[session_id].console) elif k['statechanged'] == "2": # Close server self.server_manager.delete_server(k['gamename'] , session_id) #self.sessions.pop(session_id) diff --git a/gamespy_server_browser_server.py b/gamespy_server_browser_server.py index b46d649..f647918 100644 --- a/gamespy_server_browser_server.py +++ b/gamespy_server_browser_server.py @@ -74,6 +74,7 @@ class Session(LineReceiver): self.forward_to_client = False self.forward_client = () self.secret_key_list = secret_key_list # Don't waste time parsing every session, so just accept it from the parent + self.console = 0 manager_address = ("127.0.0.1", 27500) manager_password = "" @@ -101,18 +102,22 @@ class Session(LineReceiver): # Find session id of server # Iterate through the list of servers sent to the client and match by IP and port. # Is there a better way to determine this information? - ip = str(ctypes.c_int32(utils.get_int(bytearray([int(x) for x in self.forward_client[0].split('.')]), 0)).value) + if self.console != 0: + ip = str(ctypes.c_int32(utils.get_int_be(bytearray([int(x) for x in self.forward_client[0].split('.')]), 0)).value) # Wii + else: + ip = str(ctypes.c_int32(utils.get_int(bytearray([int(x) for x in self.forward_client[0].split('.')]), 0)).value) # DS + logger.log(logging.DEBUG, "Trying to send message to %s:%d..." % (self.forward_client[0], self.forward_client[1])) logger.log(logging.DEBUG, utils.pretty_print_hex(bytearray(data))) # Get server based on ip/port server = self.server_manager.find_server_by_address(ip, self.forward_client[1])._getvalue() - logger.log(logging.DEBUG, server) + logger.log(logging.DEBUG, "find_server_by_address returned: %s" % server) if server == None: pass - #print "%s %s" % (ip, server['publicip']) + logger.log(logging.DEBUG, "%s %s" % (ip, server['publicip'])) if server['publicip'] == ip and server['publicport'] == str(self.forward_client[1]): # Send command to server to get it to connect to natneg natneg_session = int(utils.generate_random_hex_str(8), 16) # Quick and lazy way to get a random 32bit integer. Replace with something else late.r @@ -254,7 +259,10 @@ class Session(LineReceiver): if "natneg" in server_info: flags |= ServerListFlags.CONNECT_NEGOTIATE_FLAG - flags_buffer += utils.get_bytes_from_int(int(server_info['publicip'])) + if self.console != 0: + flags_buffer += utils.get_bytes_from_int_be(int(server_info['publicip'])) # Wii + else: + flags_buffer += utils.get_bytes_from_int(int(server_info['publicip'])) # DS flags |= ServerListFlags.NONSTANDARD_PORT_FLAG flags_buffer += utils.get_bytes_from_short_be(int(server_info['publicport'])) @@ -303,6 +311,9 @@ class Session(LineReceiver): #print "Requested was empty" server = {} + if "__console__" in server: + self.console = int(server['__console__']) + # Generate binary server list data data = self.generate_server_list_data(self.address, fields, server) logger.log(logging.DEBUG, utils.pretty_print_hex(data))