gamespy_player_search_server.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. """DWC Network Server Emulator
  2. Copyright (C) 2014 polaris-
  3. Copyright (C) 2014 msoucy
  4. Copyright (C) 2015 Sepalani
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Affero General Public License as
  7. published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Affero General Public License for more details.
  13. You should have received a copy of the GNU Affero General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. """
  16. import logging
  17. import traceback
  18. from twisted.internet.protocol import Factory
  19. from twisted.internet.endpoints import serverFromString
  20. from twisted.protocols.basic import LineReceiver
  21. from twisted.internet import reactor
  22. from twisted.internet.error import ReactorAlreadyRunning
  23. import gamespy.gs_database as gs_database
  24. import gamespy.gs_query as gs_query
  25. import other.utils as utils
  26. import dwc_config
  27. logger = dwc_config.get_logger('GameSpyPlayerSearchServer')
  28. address = dwc_config.get_ip_port('GameSpyPlayerSearchServer')
  29. class GameSpyPlayerSearchServer(object):
  30. def __init__(self):
  31. pass
  32. def start(self):
  33. endpoint_search = serverFromString(
  34. reactor,
  35. "tcp:%d:interface=%s" % (address[1], address[0])
  36. )
  37. conn_search = endpoint_search.listen(PlayerSearchFactory())
  38. try:
  39. if not reactor.running:
  40. reactor.run(installSignalHandlers=0)
  41. except ReactorAlreadyRunning:
  42. pass
  43. class PlayerSearchFactory(Factory):
  44. def __init__(self):
  45. logger.log(logging.INFO,
  46. "Now listening for player search connections on %s:%d...",
  47. address[0], address[1])
  48. def buildProtocol(self, address):
  49. return PlayerSearch(address)
  50. class PlayerSearch(LineReceiver):
  51. def __init__(self, address):
  52. self.setRawMode()
  53. self.db = gs_database.GamespyDatabase()
  54. self.address = address
  55. self.leftover = ""
  56. def connectionMade(self):
  57. pass
  58. def connectionLost(self, reason):
  59. pass
  60. def rawDataReceived(self, data):
  61. try:
  62. logger.log(logging.DEBUG, "SEARCH RESPONSE: %s", data)
  63. data = self.leftover + data
  64. commands, self.leftover = gs_query.parse_gamespy_message(data)
  65. for data_parsed in commands:
  66. print(data_parsed)
  67. if data_parsed['__cmd__'] == "otherslist":
  68. self.perform_otherslist(data_parsed)
  69. else:
  70. logger.log(logging.DEBUG,
  71. "Found unknown search command, don't know"
  72. " how to handle '%s'.",
  73. data_parsed['__cmd__'])
  74. except:
  75. logger.log(logging.ERROR,
  76. "Unknown exception: %s",
  77. traceback.format_exc())
  78. def perform_otherslist(self, data_parsed):
  79. """Reference: http://wiki.tockdom.com/wiki/MKWii_Network_Protocol/Server/gpsp.gs.nintendowifi.net
  80. """
  81. msg_d = [
  82. ('__cmd__', "otherslist"),
  83. ('__cmd_val__', ""),
  84. ]
  85. if "numopids" in data_parsed and "opids" in data_parsed:
  86. numopids = int(data_parsed['numopids'])
  87. opids = data_parsed['opids'].split('|')
  88. if len(opids) != numopids and int(opids[0]):
  89. logger.log(logging.ERROR,
  90. "Unexpected number of opids, got %d, expected %d.",
  91. len(opids), numopids)
  92. # Return all uniquenicks despite any unexpected/missing opids
  93. # We can do better than that, I think...
  94. for opid in opids:
  95. profile = self.db.get_profile_from_profileid(opid)
  96. msg_d.append(('o', opid))
  97. if profile is not None:
  98. msg_d.append(('uniquenick', profile['uniquenick']))
  99. else:
  100. msg_d.append(('uniquenick', ''))
  101. msg_d.append(('oldone', ""))
  102. msg = gs_query.create_gamespy_message(msg_d)
  103. logger.log(logging.DEBUG, "SENDING: %s", msg)
  104. self.transport.write(bytes(msg))
  105. if __name__ == "__main__":
  106. gsps = GameSpyPlayerSearchServer()
  107. gsps.start()