twisted: problem with sftp-client

Kristian Domke news at neither-nor.net
Wed Jan 23 09:43:47 EST 2008


Hello Folks,

I don't know, if it is ok to post large portions of code, but I have
really no idea where the problem lies, so I don't have much of a choice.

I am programming a tool, which in the end shall connect to an
sftp-server, take the list of files in a specified directory, searches
for some special names and mailes them to different persons.

I am only at the start at the moment. As orientation I use the cftp.py
programm from twisted.conch with some alterations because of not having
userinteraction.

At its current state the programm should do nothing but getting the
listing of files from a server. It works fine with the cfto.py, so the
server is ok.

But while the cftp.py script gets 'files' as an exceptions.EOFError
exeption in the StdioClient._cbReadFile at the end of the listing, I
just get another list and run into wall (aka Traceback):

> 2008/01/23 16:14 +0200 [SSHChannel session (0) on SSHService
> ssh-connection on SimpleTransport,client] Unhandled Error
> 	Traceback (most recent call last):
> 	  File "/usr/lib/python2.5/site-packages/twisted/python/log.py", >
line 48, in callWithLogger
> 	    return callWithContext({"system": lp}, func, *args, **kw)
> 	  File "/usr/lib/python2.5/site-packages/twisted/python/log.py", >
line 33, in callWithContext
> 	    return context.call({ILogContext: newCtx}, func, *args,
> **kw)
> 	  File
> "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 59,
> in callWithContext
> 	    return self.currentContext().callWithContext(ctx, func,
> *args, **kw)
> 	  File
> "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 37,
> in callWithContext
> 	    return func(*args,**kw)
> 	--- <exception caught here> ---
> 	  File
> "/usr/lib/python2.5/site-packages/twisted/conch/ssh/filetransfer.py",
> line 52, in dataReceived
> 	    f(data)
> 	  File
> "/usr/lib/python2.5/site-packages/twisted/conch/ssh/filetransfer.py",
> line 694, in packet_STATUS
> 	    msg, data = getNS(data)
> 	  File
> "/usr/lib/python2.5/site-packages/twisted/conch/ssh/common.py", line
> 39, in getNS
> 	    l, = struct.unpack('!L',s[c:c+4])
> 	  File "struct.py", line 87, in unpack
> 	    return o.unpack(s)
> 	struct.error: unpack requires a string argument of length 4
	

I have no Idea, and hope here is someone who can help me.

Kristian
----------------------------------------
from twisted.internet import reactor, defer, protocol
from twisted.conch.ssh import connection, filetransfer, keys, userauth
from twisted.conch.ssh import channel, transport, common
from twisted.conch.client import options, default, connect
from twisted.python import log, failure

import sys, time

publicKey = 'some public key'
privateKey ='''some private key'''

USER = 'sftpuser'


def run():
    opts = options.ConchOptions()
    opts['host'] = 'localhost'
    opts['user'] = USER
    opts['port'] = 22

    log.startLogging(sys.stdout)
    log.msg('logging started')
    protocol.ClientCreator(reactor,
SimpleTransport).connectTCP(opts['host'], opts['port'])
    reactor.run() # start the event loop

def doConnect(options):
    host = options['host']
    user = options['user']
    port = options['port']
    conn = SSHConnection
    vhk = default.verifyHostKey
    uao = UserAuthClient(user, conn)
    d = connect.connect(host, port, options, vhk, uao)
    d.addErrback(_ebExit)
    return d

def _ebExit(f):
    if hasattr(f.value, 'value'):
        s =f.value.value
    else:
        s = str(f)
    log.msg( s )
    try:
        reactor.stop()
    except:
        pass

def _cleanExit():
    try:
        reactor.stop()
    except:
        pass

class SimpleTransport(transport.SSHClientTransport):
    def verifyHostKey(self, hostKey, fingerprint):
        log.msg('host key fingerprint: %s' % fingerprint)
        return defer.succeed(1)

    def connectionSecure(self):
        self.requestService(
            UserAuthClient(USER,
                SSHConnection()))

class UserAuthClient(userauth.SSHUserAuthClient):
    """Simple User Authentication Client"""

    def getPassword(self, prompt = None):
        return
        # this says we won't do password authentication

    def getPublicKey(self):
        return keys.getPublicKeyString(data = publicKey)

    def getPrivateKey(self):
        return defer.succeed(keys.getPrivateKeyObject(data = privateKey))

class SSHConnection(connection.SSHConnection):
    def serviceStarted(self):
        log.msg('Service started')
        self.openChannel(SSHSession(conn = self))

class SSHSession(channel.SSHChannel):

    name = 'session'

    def channelOpen(self, irgnoreData):
        log.msg('session %s is open' % self.id)
        request = 'subsystem'
        d = self.conn.sendRequest(self, request, common.NS('sftp'),
wantReply=1)
        d.addCallback(self._cbSubsystem)
        d.addErrback(_ebExit)
        return d

    def _cbSubsystem(self, result):
        log.msg('Establishing Subsystem')
        self.client = SFTPClient()
        self.client.makeConnection(self)
        self.dataReceived = self.client.dataReceived

    def openFailed(self, reason):
        log.err('Opening Session failed: %s' % reason)
        _cleanExit()


class SFTPClient(filetransfer.FileTransferClient):

    def __init__(self):
        filetransfer.FileTransferClient.__init__(self)
        self.currentDirectory = ''


    def connectionMade(self):
        log.msg('Connection with SFTPClient established')

self.realPath('').addCallback(self._cbSetCurDir).addErrback(_cleanExit)

    def _cbSetCurDir(self, path):
        self.currentDirectory = path
        log.msg('currentDirectory set to %s.' % path)
        #self.cmd_MKDIR('test')
        self.cmd_LS(self.currentDirectory)

    def cmd_MKDIR(self, path):
        return self.makeDirectory(path, {}).addCallback(self._ignore)

    def cmd_LS(self, path):
        log.msg('List Stucture of %s' % path)
        d = self.openDirectory(path)
        d.addCallback(self._cbOpenList)

    def _cbOpenList(self, directory):
        files = []
        log.msg('direc.:%s' % str(directory))
        log.msg('direc.:%s' % type(directory))
        log.msg('direc.:%s' % str(directory.parent))
        log.msg('direc.:%s' % type(directory.parent))
        d = directory.read()
        d.addCallback(self._cbReadFile, files, directory)
        d.addErrback(self._ebRaeadFile, files, directory)

    def _ebReadFile(self, files, l, directory):
        log.msg('**errback!**')
        self._cbReadFile(files, l, directory)

    def _cbReadFile(self, files, l, directory):
        log.msg('ReadFile called')
        log.msg('direc.:%s' % type(files))
        if not isinstance(files, failure.Failure):
            log.msg('if not')
            l.extend(files)
            d = directory.read()
            #d.addCallback(self._ignore)
            d.addBoth(self._cbReadFile, l, directory)
            return d
        else:
            log.msg('else')
            reason = files
            reason.trap(EOFError)
            directory.close()
            return l

    def _ignore(self, *args):
        pass

if __name__ == "__main__":
    run()




More information about the Python-list mailing list