#!/usr/bin/env python3 import sys import re from twisted.internet import defer from twisted.internet import protocol from twisted.internet import reactor from twisted.python import log from twisted.enterprise import adbapi from twisted.protocols.basic import LineReceiver # Connect to: HOST = "127.0.0.1" PORT = 2002 # Listen on: LISTEN_PORT = 9999 LISTEN_ON = "127.0.0.1" class LineRecv(LineReceiver): def __init__(self, notify): self.delimiter = b"\n" # \r" self.notify = notify def lineReceived(self, line): log.msg("LR:", line) self.notify.gotLine(line) class PlayerProtocol(protocol.Protocol): def __init__(self): self.user = None self.dbinit = False self.db = None self.buffer = "" self.linereader = LineRecv(self) self.linereader.connectionMade() def connectionMade(self): log.msg("Client: connected to peer") self.queue_twgs = self.factory.queue_twgs self.queue_twgs.get().addCallback(self.serverDataReceived) def gotLine(self, line): log.msg(">>> [{0}]".format(line.decode("utf-8", "ignore"))) def serverDataReceived(self, chunk): # rlogin looks like this: \x00 password \x00 username \x00 terminal/speed \x00 # b'\x00up2lat3\x00bugz\x00ansi-bbs/115200\x00' # We're looking for 4 \x00! # TODO: Line processing, and line cleaning (remove ANSI color codes) if chunk is False: self.queue_twgs = None log.msg("Client: disconnecting from peer") self.factory.continueTrying = False self.transport.loseConnection() else: self.buffer += chunk.decode("utf-8") if self.user is None: # Ok, process this # self.buffer += chunk.decode('utf-8') # We don't have the username yet parts = self.buffer.split("\x00") if len(parts) >= 5: # Got it! self.user = parts[1] log.msg("User: {0}".format(self.user)) # Reset buffer -- remove everything before last \x00 zpos = self.buffer.rindex("\x00") self.buffer = self.buffer[zpos + 1 :] self.buffer = "" # init sqlite db using the username else: # process the buffer # Handle backspaces by deleting previous character. # Send the received data into the linereader for "automatic" line processing. self.linereader.dataReceived(chunk) # # # Strip out ANSI color codes # self.buffer = re.sub(r'\x1b[\d;?\d+m', '', self.buffer) # Process lines ... self.transport.write(chunk) self.queue_twgs.get().addCallback(self.serverDataReceived) # elif b"$" == chunk: # self.factory.svr_queue.put(b"HELLO.\r\n") # self.cli_queue.get().addCallback(self.serverDataReceived) # elif self.cli_queue: # log.msg("Client: writing %d bytes to peer" % len(chunk)) # log.msg(">>", repr(chunk)) # self.transport.write(chunk) # self.cli_queue.get().addCallback(self.serverDataReceived) # else: # self.factory.cli_queue.put(chunk) def dataReceived(self, chunk): # log.msg("Client: %d bytes received from peer" % len(chunk)) # clean, strip ANSI, etc. # log.msg("<<", chunk.decode("utf-8", "ignore")) log.msg("<<", repr(chunk)) self.factory.queue_client.put(chunk) def connectionLost(self, why): log.msg("connectionLost because: %s" % why) # if self.cli_queue: # self.cli_queue = None # log.msg("Client: peer disconnect unexpectedly") self.factory.queue_client.put(False) self.queue_twgs = None self.transport.loseConnection() class GlueFactory(protocol.ClientFactory): maxDelay = 10 protocol = PlayerProtocol def __init__(self, queue_client, queue_twgs): self.queue_client = queue_client self.queue_twgs = queue_twgs def closeIt(self): log.msg("closeIt") self.queue_client.put(False) def clientConnectionFailed(self, connector, why): log.msg("connectionFailed: %s" % why) self.queue_client.put(b"Sorry! I'm Unable to connect to the game server.\r\n") # syncterm gets cranky/locks up if we close this here. # (Because it is still sending rlogin information?) reactor.callLater(2, self.closeIt) # ProxyServer is created for each connection class TWGSServer(protocol.Protocol): def connectionMade(self): self.queue_twgs = defer.DeferredQueue() self.queue_client = defer.DeferredQueue() self.queue_client.get().addCallback(self.clientDataReceived) factory = GlueFactory(self.queue_client, self.queue_twgs) reactor.connectTCP(HOST, PORT, factory, 5) def clientDataReceived(self, chunk): if chunk is False: self.transport.loseConnection() else: # log.msg("Server: writing %d bytes to original client" % len(chunk)) self.transport.write(chunk) self.queue_client.get().addCallback(self.clientDataReceived) def dataReceived(self, chunk): # log.msg("Server: %d bytes received" % len(chunk)) self.queue_twgs.put(chunk) def connectionLost(self, why): log.msg("lost connection %s" % why) self.queue_twgs.put(False) def connectionFailed(self, why): log.msg("connectionFailed: %s" % why) if __name__ == "__main__": log.startLogging(sys.stdout) factory = protocol.Factory() factory.protocol = TWGSServer reactor.listenTCP(LISTEN_PORT, factory, interface=LISTEN_ON) reactor.run()