[Twisted-web] Deferred fun

James R. Saker Jr. cso at netcenturion.biz
Mon Jan 16 18:56:14 MST 2006


Per new years resolution 'I will learn how to use deferreds in twisted', I've 
got a little puzzle in an xmlrpc remote nmap tool that I put together to try 
to learn deferreds (as well as automate scans on my firewall from outside my 
net), figuring the speed of nmap returning the results of a scan can be 
excessively long and should make for a good deferred experiment. Except I 
keep hitting an AssertionError and think it may have to do with what happens 
to my deferred when it completes:

#!/usr/bin/python
"""
pyrscand.py
Python remote scanner: Nmap XML-RPC module for processing scan requests from a 
remote host
"""
import os
from twisted.internet import defer
from twisted.web import xmlrpc, server

NMAP_PATH = '/usr/bin/nmap' # location of nmap binary on host

class ScanServer(xmlrpc.XMLRPC):
    """
    XMLRPC server for remote scan processing
    """

    def handleScan(self, type, ip, detectOS, timing):
	"""
	Simplistic scans only for now!
	"""
        result = ''
        print "running scanner..."
        scandata = os.popen('%s -%s -A -T%s %s -oX -' % \
            (NMAP_PATH, type, timing, ip), 'r')
        for line in scandata:
            result += line  # return xml in a string - not a list object
        print "got result: \n%s" % result
        return result

    def handleFailure(self, f):
        print "errback"
        print "we got an exception: %s" % (f.getTraceback(),)
        f.trap(RuntimeError)
        return 'Error'
        
    def xmlrpc_scan(self, type, ip, detectOS, timing):
        """
        Inputs: type (sS, sT, sP), ip, detectOS flag, timing performance (0-5)
        Outputs: XML formatted report value compliant with nmap schema
        """
        print "scanner"
        d = defer.Deferred()
        d.addCallback(self.handleScan(type, ip, detectOS, timing))
        d.addErrback(self.handleFailure)
    
if __name__ == '__main__':
    from twisted.internet import reactor
    r = ScanServer()
    reactor.listenTCP(7080, server.Site(r))
    reactor.run()


Running it actually shows the nmap xml output is returned to handleScan but 
from there we hit an AssertionError:

Traceback (most recent call last):
  File "/usr/lib/python2.4/site-packages/twisted/web/http.py", line 557, in 
requestReceived
    self.process()
  File "/usr/lib/python2.4/site-packages/twisted/web/server.py", line 153, in 
process
    self.render(resrc)
  File "/usr/lib/python2.4/site-packages/twisted/web/server.py", line 160, in 
render
    body = resrc.render(self)
  File "/usr/lib/python2.4/site-packages/twisted/web/xmlrpc.py", line 118, in 
render
    defer.maybeDeferred(function, *args).addErrback(
--- <exception caught here> ---
  File "/usr/lib/python2.4/site-packages/twisted/internet/defer.py", line 107, 
in maybeDeferred
    result = f(*args, **kw)
  File "pyrscand.py", line 39, in xmlrpc_scan
    d.addCallback(self.handleScan(type, ip, detectOS, timing))
  File "/usr/lib/python2.4/site-packages/twisted/internet/defer.py", line 191, 
in addCallback
    callbackKeywords=kw)
  File "/usr/lib/python2.4/site-packages/twisted/internet/defer.py", line 175, 
in addCallbacks
    assert callable(callback)
exceptions.AssertionError:

My xmlrpc client is pretty short and taken directly from online howto:

from twisted.web.xmlrpc import Proxy
from twisted.internet import reactor

def printValue(value):
    print repr(value)
    reactor.stop()

def printError(error):
    print 'error', error
    reactor.stop()

proxy = Proxy('http://localhost:7080/XMLRPC')
proxy.callRemote('scan', 'sP', '69.63.110.1',\ 		
				1, 5).addCallbacks(printValue,printError)
reactor.run()


Any thoughts would be greatly appreciated -


Jamie



More information about the Twisted-web mailing list