Fixes to matchmaking

This commit is contained in:
polaris
2014-05-14 07:31:58 -04:00
committed by Admiral H. Curtiss
parent 43076f35af
commit 359f4eb3e8
3 changed files with 106 additions and 10 deletions

View File

@@ -50,6 +50,7 @@ class GameSpyBackendServer(object):
GameSpyServerDatabase.register("get_server_list", callable=lambda:self.server_list)
GameSpyServerDatabase.register("find_servers", callable=self.find_servers)
GameSpyServerDatabase.register("find_server_by_address", callable=self.find_server_by_address)
GameSpyServerDatabase.register("find_server_by_local_address", callable=self.find_server_by_local_address)
GameSpyServerDatabase.register("update_server_list", callable=self.update_server_list)
GameSpyServerDatabase.register("delete_server", callable=self.delete_server)
@@ -390,6 +391,29 @@ class GameSpyBackendServer(object):
return None
def find_server_by_local_address(self, publicip, localip, localport, gameid = None):
if gameid == None:
# Search all servers
for gameid in self.server_list:
for server in self.server_list[gameid]:
logger.log(logging.DEBUG, "publicip: %s == %s ? %d" % (server['publicip'], publicip, server['publicip'] == publicip))
if server['publicip'] == publicip and server['localport'] == str(localport):
for x in range(0, 10):
s = 'localip%d' % x
if s in server:
if server[s] == localip:
return server
else:
for server in self.server_list[gameid]:
logger.log(logging.DEBUG, "publicip: %s == %s ? %d" % (server['publicip'], publicip, server['publicip'] == publicip))
if server['publicip'] == publicip and server['localport'] == str(localport):
for x in range(0, 10):
s = 'localip%d' % x
if s in server:
if server[s] == localip:
return server
return None
if __name__ == '__main__':
freeze_support()

View File

@@ -3,10 +3,13 @@
import logging
import socket
import ctypes
import struct
import gamespy.gs_utility as gs_utils
import other.utils as utils
from multiprocessing.managers import BaseManager
# Logger settings
logger_output_to_console = True
logger_output_to_file = True
@@ -14,11 +17,25 @@ logger_name = "GameSpyNatNegServer"
logger_filename = "gamespy_natneg_server.log"
logger = utils.create_logger(logger_name, logger_filename, -1, logger_output_to_console, logger_output_to_file)
class GameSpyServerDatabase(BaseManager):
pass
GameSpyServerDatabase.register("get_server_list")
GameSpyServerDatabase.register("modify_server_list")
GameSpyServerDatabase.register("find_servers")
GameSpyServerDatabase.register("find_server_by_address")
GameSpyServerDatabase.register("find_server_by_local_address")
class GameSpyNatNegServer(object):
def __init__(self):
self.session_list = {}
self.secret_key_list = gs_utils.generate_secret_keys("gslist.cfg")
manager_address = ("127.0.0.1", 27500)
manager_password = ""
self.server_manager = GameSpyServerDatabase(address = manager_address, authkey= manager_password)
self.server_manager.connect()
def start(self):
# Start natneg server
address = ('0.0.0.0', 27901) # accessible to outside connections (use this if you don't know what you're doing)
@@ -54,46 +71,72 @@ class GameSpyNatNegServer(object):
gameid = utils.get_string(recv_data, 0x16)
client_id = "%02x" % ord(recv_data[13])
localip_raw = recv_data[15:19]
localip = '.'.join(["%d" % ord(x) for x in localip_raw])
localport_raw = recv_data[19:21]
localport = utils.get_short_be(localport_raw, 0)
localaddr = (localip, localport)
if gameid not in self.session_list:
self.session_list[gameid] = {}
if session_id not in self.session_list[gameid]:
self.session_list[gameid][session_id] = {}
if client_id not in self.session_list[gameid][session_id]:
self.session_list[gameid][session_id][client_id] = { 'connected': False, 'addr': '' }
self.session_list[gameid][session_id][client_id] = { 'connected': False, 'addr': '', 'localaddr': None, 'serveraddr': None, 'gameid': None }
self.session_list[gameid][session_id][client_id]['gameid'] = utils.get_string(recv_data[21:], 0)
self.session_list[gameid][session_id][client_id]['addr'] = addr
self.session_list[gameid][session_id][client_id]['localaddr'] = localaddr
clients = len(self.session_list[gameid][session_id])
for client in self.session_list[gameid][session_id]:
if self.session_list[gameid][session_id][client]['connected'] == False:
if self.session_list[gameid][session_id][client]['connected'] == False and self.session_list[gameid][session_id][client]['localaddr'][1] != 0:
if client == client_id:
continue
if self.session_list[gameid][session_id][client]['serveraddr'] == None:
serveraddr = self.get_server_info(gameid, session_id, client)
self.session_list[gameid][session_id][client]['serveraddr'] = serveraddr
logger.log(logging.DEBUG, "Found server from local ip/port: %s" % serveraddr)
publicport = 0
if self.session_list[gameid][session_id][client]['serveraddr'] != None:
publicport = int(self.session_list[gameid][session_id][client]['serveraddr']['publicport'])
# Send to requesting client
output = bytearray(recv_data[0:12])
output += bytearray([int(x) for x in self.session_list[gameid][session_id][client]['addr'][0].split('.')])
output += utils.get_bytes_from_short_be(self.session_list[gameid][session_id][client]['addr'][1])
output += utils.get_bytes_from_short_be(publicport)
output += bytearray([0x42, 0x00]) # Unknown, always seems to be \x42\x00
output[7] = 0x05
s.sendto(output, (self.session_list[gameid][session_id][client_id]['addr']))
#s.sendto(output, (self.session_list[gameid][session_id][client_id]['addr']))
s.sendto(output, (self.session_list[gameid][session_id][client_id]['addr'][0], self.session_list[gameid][session_id][client_id]['addr'][1]))
logger.log(logging.DEBUG, "Sent connection request to %s:%d..." % (self.session_list[gameid][session_id][client_id]['addr'][0], self.session_list[gameid][session_id][client_id]['addr'][1]))
logger.log(logging.DEBUG, utils.pretty_print_hex(output))
logger.log(logging.DEBUG, "")
# Send to other client
if self.session_list[gameid][session_id][client_id]['serveraddr'] == None:
serveraddr = self.get_server_info(gameid, session_id, client_id)
self.session_list[gameid][session_id][client_id]['serveraddr'] = serveraddr
logger.log(logging.DEBUG, "Found server 2 from local ip/port: %s" % serveraddr)
publicport = 0
if self.session_list[gameid][session_id][client_id]['serveraddr'] != None:
publicport = int(self.session_list[gameid][session_id][client_id]['serveraddr']['publicport'])
output = bytearray(recv_data[0:12])
output += bytearray([int(x) for x in self.session_list[gameid][session_id][client_id]['addr'][0].split('.')])
output += utils.get_bytes_from_short_be(self.session_list[gameid][session_id][client_id]['addr'][1])
output += utils.get_bytes_from_short_be(publicport)
output += bytearray([0x42, 0x00]) # Unknown, always seems to be \x42\x00
output[7] = 0x05
s.sendto(output, (self.session_list[gameid][session_id][client]['addr']))
#s.sendto(output, (self.session_list[gameid][session_id][client]['addr']))
s.sendto(output, (self.session_list[gameid][session_id][client]['addr'][0], self.session_list[gameid][session_id][client]['addr'][1]))
logger.log(logging.DEBUG, "Sent connection request to %s:%d..." % (self.session_list[gameid][session_id][client]['addr'][0], self.session_list[gameid][session_id][client]['addr'][1]))
logger.log(logging.DEBUG, utils.pretty_print_hex(output))
logger.log(logging.DEBUG, "")
elif recv_data[7] == '\x06': # Was able to connect
client_id = "%02x" % ord(recv_data[13])
@@ -106,7 +149,7 @@ class GameSpyNatNegServer(object):
if client_id not in self.session_list[gameid][session_id]:
pass
#self.session_list[gameid][session_id][client_id]['connected'] = True
self.session_list[gameid][session_id][client_id]['connected'] = True
elif recv_data[7] == '\x0a': # Address check. Note: UNTESTED!
client_id = "%02x" % ord(recv_data[13])
@@ -135,6 +178,31 @@ class GameSpyNatNegServer(object):
else: # Was able to connect
logger.log(logging.DEBUG, "Received unknown command %02x from %s:%s..." % (ord(recv_data[7]), addr[0], addr[1]))
def get_server_info(self, gameid, session_id, client_id):
console = 0
ipstr = self.session_list[gameid][session_id][client_id]['addr'][0]
if console != 0:
ip = str(ctypes.c_int32(utils.get_int_be(bytearray([int(x) for x in ipstr.split('.')]), 0)).value) # Wii
console = 0
else:
ip = str(ctypes.c_int32(utils.get_int(bytearray([int(x) for x in ipstr.split('.')]), 0)).value) # DS
console = 1
serveraddr = self.server_manager.find_server_by_local_address(ip, self.session_list[gameid][session_id][client_id]['localaddr'][0], self.session_list[gameid][session_id][client_id]['localaddr'][1], self.session_list[gameid][session_id][client_id]['gameid'])._getvalue()
if serveraddr == None:
if console != 0:
ip = str(ctypes.c_int32(utils.get_int_be(bytearray([int(x) for x in ipstr.split('.')]), 0)).value) # Wii
console = 0
else:
ip = str(ctypes.c_int32(utils.get_int(bytearray([int(x) for x in ipstr.split('.')]), 0)).value) # DS
console = 1
serveraddr = self.server_manager.find_server_by_local_address(ip, self.session_list[gameid][session_id][client_id]['localaddr'][0], self.session_list[gameid][session_id][client_id]['localaddr'][1], self.session_list[gameid][session_id][client_id]['gameid'])._getvalue()
return serveraddr
if __name__ == "__main__":
natneg_server = GameSpyNatNegServer()
natneg_server.start()

View File

@@ -364,6 +364,7 @@ class Session(LineReceiver):
# #self.server_cache.pop((publicip + str(self.forward_client[1])))
server = self.server_manager.find_server_by_address(ip, self.forward_client[1])._getvalue()
self.log(logging.DEBUG, "find_server_in_cache is returning: %s %s" % (server, ip))
return server, ip
@@ -371,6 +372,9 @@ 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?
if self.forward_client == None or len(self.forward_client) != 2:
return
server, ip = self.find_server_in_cache(self.forward_client[0], self.forward_client[1], self.console)
if server == None:
@@ -389,7 +393,7 @@ class Session(LineReceiver):
self.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
natneg_session = int(utils.generate_random_hex_str(8), 16) # Quick and lazy way to get a random 32bit integer. Replace with something else later
output = bytearray([0xfe, 0xfd, 0x06])
output += utils.get_bytes_from_int(server['__session__'])