Skip to content

Commit

Permalink
Decoding list. Fetching data from other master server.
Browse files Browse the repository at this point in the history
  • Loading branch information
garncarz committed Jan 4, 2018
1 parent c826b1f commit 9d084e6
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 16 deletions.
29 changes: 27 additions & 2 deletions aluigi/aluigiModule.c
Expand Up @@ -4,8 +4,9 @@
#include <Python.h>

int enctype2_encoder(unsigned char *key, unsigned char *data, int size);
unsigned char *enctype2_decoder(unsigned char *key, unsigned char *data, int *size);

static PyObject* encodeList(PyObject* self, PyObject* args) {
static PyObject* encode_list(PyObject* self, PyObject* args) {
unsigned char *key, *data_arg, *data;
int size, ret_size;
PyObject *ret;
Expand All @@ -25,8 +26,32 @@ static PyObject* encodeList(PyObject* self, PyObject* args) {
return ret;
}

static PyObject* decode_list(PyObject* self, PyObject* args) {
unsigned char *key, *data_arg, *data, *data_ret;
int size_arg, size;
PyObject *ret;

if (!PyArg_ParseTuple(args, "sy#", &key, &data_arg, &size_arg)) {
return NULL;
}

size = size_arg;

data = (unsigned char*)malloc(2 * size * sizeof(unsigned char));
memcpy(data, data_arg, size * sizeof(unsigned char));

data_ret = enctype2_decoder(key, data, &size);

ret = Py_BuildValue("y#", data_ret, size);
free(data);
// free(data_ret); leads to "invalid pointer"

return ret;
}

static PyMethodDef aluigiMethods[] = {
{"encodeList", encodeList, METH_VARARGS},
{"encode_list", encode_list, METH_VARARGS},
{"decode_list", decode_list, METH_VARARGS},
{NULL, NULL}
};

Expand Down
5 changes: 3 additions & 2 deletions app.py
Expand Up @@ -7,7 +7,8 @@


arg_parser = argparse.ArgumentParser('Vietcong 1 master server crawler/replicator')
arg_parser.add_argument('--new', action='store_true', help='Pull new servers.')
arg_parser.add_argument('--new', nargs='?', const='Qtracker', default=False,
help='Pull new servers from Qtracker / IP of another master server.')
arg_parser.add_argument('--refresh', action='store_true', help='Refresh all saved servers.')
arg_parser.add_argument('--master', action='store_true', help='Run master server.')

Expand All @@ -20,7 +21,7 @@ def main():
args = arg_parser.parse_args()

if args.new:
tasks.pull_master()
tasks.pull_master(args.new if args.new.lower() != 'qtracker' else None)
if args.refresh:
tasks.refresh_all_servers()
if args.master:
Expand Down
27 changes: 20 additions & 7 deletions nogamespy/protocol.py
Expand Up @@ -10,8 +10,20 @@
logger = logging.getLogger(__name__)


def _encode_list(servers):
return aluigi.encodeList('bq98mE', memoryview(servers).tobytes())
def encode_list(decrypted):
return aluigi.encode_list(settings.GAMESPY_KEY, memoryview(decrypted).tobytes())


def decode_list(encrypted):
decrypted = aluigi.decode_list(settings.GAMESPY_KEY, encrypted)

for i in range(0, len(decrypted) - 1, 6):
if decrypted[i:].startswith(b'\\final'):
break

ip = socket.inet_ntoa(decrypted[i:i+4])
port = struct.unpack('>h', decrypted[i+4:i+6])[0]
yield ip, port


class MasterService(socketserver.TCPServer):
Expand All @@ -30,12 +42,13 @@ def handle(self):
self.request.sendall('\\basic\\\\secure\\'.encode('latin1'))

# TODO cache for some small amount of time
servers = bytearray()
byte_string = bytearray()

for server in models.Server.query.filter_by(online=True).all():
servers.extend(socket.inet_aton(server.ip))
servers.extend(struct.pack('>h', server.info_port))
# TODO move byte schema to encode_list
byte_string.extend(socket.inet_aton(server.ip))
byte_string.extend(struct.pack('>h', server.info_port))

servers.extend(b'\\final\\')
byte_string.extend(b'\\final\\')

self.request.send(_encode_list(servers))
self.request.send(encode_list(byte_string))
2 changes: 2 additions & 0 deletions nogamespy/settings.py
@@ -1,5 +1,7 @@
DATABASE = 'postgresql://localhost/vietcong'

GAMESPY_KEY = 'bq98mE'

UDP_TIMEOUT = 4

MASTER_PORT = 28900
Expand Down
27 changes: 25 additions & 2 deletions nogamespy/tasks.py
Expand Up @@ -14,21 +14,44 @@


def _get_qtracker_list():
logger.debug('Fetching new servers from Qtracker...')

resp = requests.get('http://www.qtracker.com/server_list_details.php?game=vietcong')
for line in resp.text.splitlines():
ip, port = line.split(':')
yield ip, port


def pull_master():
for ip, port in _get_qtracker_list():
def _fetch_from_master(ip):
logger.debug(f'Fetching new servers from {ip}...')

client = socket.create_connection((ip, settings.MASTER_PORT))

client.recv(4096)

client.send(b'\\gamename\\vietcong\\gamever\\2\\location\\0\\validate\\JOzySo8c\\enctype\\2\\final\\'
b'\\queryid\\1.1\\\\list\\cmp\\gamename\\vietcong\\final\\')

resp = client.recv(4096)
servers = protocol.decode_list(resp)

client.close()

return servers


def pull_master(source=None):
servers = _get_qtracker_list() if not source else _fetch_from_master(source)

for ip, port in servers:
server, created = models.get_or_create(models.Server, ip=ip, info_port=port)

if created:
logger.info(f'New server: {server}')
pull_server_info(server)


# TODO move to protocol.py
def _get_server_info(server):
logger.debug(f'Trying to get info from {server.ip}:{server.info_port}...')

Expand Down
14 changes: 12 additions & 2 deletions tests/test_protocol.py
@@ -1,4 +1,5 @@
import socket
import time
import threading

from nogamespy import protocol, settings
Expand All @@ -21,12 +22,21 @@ def test_master_server():
client = socket.create_connection(('127.0.0.1', settings.MASTER_PORT))

client.send(b'pls')
time.sleep(0.1)

resp = client.recv(4096).decode('latin1')
assert resp # TODO be more precise
resp = client.recv(4096)
assert resp == b"\\basic\\\\secure\\\xe4bq98mE\x00\x00\xac~\xcd#]k\xc3'\xdeI[\xa4t\xc40\r\xf0v\xda\x86\x06^0\xdc"

client.close()

master_server.shutdown()
master_server.server_close()
master_thread.join()


def test_decode_list():
encrypted = b"\xe4bq98mE\x00\x00\xac~\xcd#]k\xc3'\xdeI[\xa4t\xc40\r\xf0v\xda\x86\x06^0\xdc"
assert list(protocol.decode_list(encrypted)) == [
('1.2.3.4', 15425),
('5.6.7.10', 15426),
]
6 changes: 5 additions & 1 deletion tests/test_tasks.py
@@ -1,9 +1,13 @@
from nogamespy import tasks


def test_pull_master():
def test_pull_qtracker_txt_list():
tasks.pull_master()


def test_pull_qtracker_master():
tasks.pull_master('65.112.87.186')


def test_refresh_all_servers():
tasks.refresh_all_servers()

0 comments on commit 9d084e6

Please sign in to comment.