Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with my twisted server that's supposed to take a .exe and send its stdio to anyone who asks. Instead, it doesn't send anything

print 'Preall test works!'
from twisted.internet import reactor, protocol
from twisted.python import log
import sys
print 'Imports done'

class PrgShell(protocol.Protocol):
    data = ''
    class PrgProto(protocol.ProcessProtocol):
        def __init__(self, out):
            print 'Prgproto instance made'
            self.transportout = out.transport
            self.out = out
        def outReceived(self, data):
            """Called when process sends data. We send it on to transport, however if it's 'I want input', we need to activate input."""
            print 'Sub said: '+data
            if data == "input":
                print 'Sub wants input'
                self.transportout.write("input")
                sleep(0.01)
                self.transport(self.out.getWrit())
            else:
                self.transportout.write(data)



    def getWrit(self):
        print 'Proto gave input to prg'
        data = self.data
        self.data = ''
        return data 

    def connectionMade(self):
        global reactor
        print 'Connected'
        proto = self.PrgProto(self)
        addr = "C:\\Documents and Settings\\papa\\My Documents\\Python\\Files\\Maze\\exe\\maze.exe"
        reactor.spawnProcess(proto, addr)
        print 'Procces spawned!'


    def dataReceived(self, data):
        print 'Data recived: '+data
        self.data+=data

print 'About to do stuff'
factory = protocol.ServerFactory()
factory.protocol = PrgShell
#f = open("errors.txt", 'w')
#log.startLogging(f)
#print 'Logging started'
reactor.listenTCP(8000,factory)
print 'Runing'
reactor.run()

The program in question prints stuff first thing. When I connect to it, via raw sockets, it doesn't send anything. Here's the output:

Preall test works!
Imports done
About to do stuff
Runing (connect)
Connected
Prgproto instance made
Procces spawned!

Am I missing anything?

Thanks in advance.

like image 933
technillogue Avatar asked Nov 15 '22 00:11

technillogue


1 Answers

Replace reactor.spawnProcess(proto, addr) with reactor.spawnProcess(proto, addr, ['maze'], {}).

Past experience has show that if you don't pass exe name as the first argument then nothing useful happens. However I have yet to find a reasonable explanation for why this happens.

Also you don't need global reactor. When you import the reactor you add it to the top level script namespace. This means that all functions and class in the same file can use it without declaring a global or importing again.

Also, you should not be using sleep(0.01) because:

  1. Its not a builtin function. You need to import it from the time module.
  2. Twisted is a asynchronous framework where function should avoid blocking at all costs, and time.sleep() (link) by its definition is a blocking call.

You should instead use reactor.callLater() link where you provide it will a callback and a time period. This will let twisted handle other things (like a new connection) while you wait.

Finally, you code at the moment would require the user to enter input before the program asks for any. This is because getWrit just sends stuff already in the buffer rather than asking the user. This means that if the user hasn't sent any data before getWrit is called then it will just return an empty string.

It would be a better idea if you used a deferred. Then what you would do is call getWrit which would immanently return a deferred and clear the data buffer. Then in dataReceived you would append data to the buffer until you got a newline character (\n). At which point you would call the deferred set up in getWrit.

Something like this:

print 'Preall test works!'
from twisted.internet import reactor, protocol, defer
from twisted.python import log
import sys
print 'Imports done'

class PrgShell(protocol.Protocol):
    data = ''
    class PrgProto(protocol.ProcessProtocol):
        def __init__(self, out):
            print 'Prgproto instance made'
            self.transportout = out.transport
            self.out = out
        def outReceived(self, data):
            """Called when process sends data. We send it on to transport, however if it's 'I want input', we need to activate input."""
            print 'Sub said: '+data
            if data == "input":
                print 'Sub wants input'
                self.transportout.write("input")
                d = self.out.getWrit() # getWrit returns a deferred. We store it in d to make the code more readable
                d.addCallback(self.sendInput) # Here we add self.sendInput to the callback chain.
                                              # This way self.sendInput gets called with the user input.
            else:
                self.transportout.write(data)

        def sendInput(self, data):
            self.transport.write(data)


    def getWrit(self):
        print 'Proto gave input to prg'
        self.deferred = defer.deferred()
        self.data = ''
        return self.deferred

    def connectionMade(self):
        print 'Connected'
        proto = self.PrgProto(self)
        addr = "C:\\Documents and Settings\\papa\\My Documents\\Python\\Files\\Maze\\exe\\maze.exe"
        reactor.spawnProcess(proto, addr, ['maze'], {})
        print 'Procces spawned!'


    def dataReceived(self, data):
        print 'Data recived: '+data
        self.data+=data

        if self.data.endswith('\n'):
            if self.deferred:
                # We got a newline character, and there is a deferred to call, so lets call it
                d, self.deferred = self.deferred, None # This will set self.deferred to none to stop mistakes later

                d.callback(self.data) # Call the deferred with data. This will send the data to sendInput above.

                self.data = '' # Clear the buffer

print 'About to do stuff'
factory = protocol.ServerFactory()
factory.protocol = PrgShell
#f = open("errors.txt", 'w')
#log.startLogging(f)
#print 'Logging started'
reactor.listenTCP(8000,factory)
print 'Runing'
reactor.run()
like image 139
thomas Avatar answered Dec 10 '22 18:12

thomas