Sorry I have not been able to find a better title, please see the attached example which may be more descriptive.

Here is what it does:
 * set up an SSH connection
 * open a TCP forwarding channel through this connection
 * do something through the tunnel that will trigger an errback (in the
   example, try to do an XMLRPC call with no one listening on the
   tunnel's end)

This scenario gives me the following traceback (tested with Twisted 8.1.0 and 8.2.0):

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/python/log.py", line 84, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/python/log.py", line 69, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/python/context.py", line 59, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/python/context.py", line 37, in callWithContext
    return func(*args,**kw)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/internet/selectreactor.py", line 156, in _doReadOrWrite
    self._disconnectSelectable(selectable, why, method=="doRead")
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/internet/posixbase.py", line 193, in _disconnectSelectable
    selectable.connectionLost(f)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/internet/tcp.py", line 520, in connectionLost
    protocol.connectionLost(reason)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/conch/ssh/forwarding.py", line 129, in connectionLost
    self.channel.loseConnection()
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/conch/ssh/channel.py", line 253, in loseConnection
    self.conn.sendClose(self)
File "/usr/lib/python2.5/site-packages/Twisted-8.2.0-py2.5-linux-i686.egg/twisted/conch/ssh/connection.py", line 491, in sendClose
    self.channelsToRemoteChannel[channel]))
exceptions.KeyError: <twisted.conch.ssh.forwarding.SSHListenClientForwardingChannel instance at 0x972048c>
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

It works well in the other cases, i.e.:
 * the errback is triggered but the tunnel is not used (comment line 57,
   uncomment line 59)
 * the errback is not triggered (start the XMLRPC server by uncommenting
   line 100), using the tunnel or not

You get the error only when the tunnel is used AND the errback is triggered.

To run the example execute it with an user name that can login using ssh on your host, e.g. 'python test.py someuser' and enter its password.

Cheers,
Luper
#!/usr/bin/env python

import sys
from getpass import getpass
from twisted.python import log
from twisted.conch.ssh import connection, transport, userauth, keys, \
        forwarding, channel
from twisted.conch.ssh.common import NS
from twisted.internet import defer, protocol, reactor
from twisted.web import server, xmlrpc
from twisted.web.xmlrpc import Proxy


conn = None


def connect(user, host, port=22):
    return reactor.connectTCP(host, port, Factory(user, Transport))


class Factory(protocol.ClientFactory):
    def __init__(self, user, protocol):
        self.user = user
        self.protocol = protocol

    def buildProtocol(self, addr):
        p = self.protocol(self.user)
        p.factory = self
        return p


class Transport(transport.SSHClientTransport):
    def __init__(self, user):
        self.user = user

    def verifyHostKey(self, pubkey, fingerprint):
        return defer.succeed(1)

    def connectionSecure(self):
        self.requestService(UserAuth(self.user, Connection()))


class UserAuth(userauth.SSHUserAuthClient):
    def getPassword(self, prompt=None):
        return defer.succeed(getpass("password: "))


class Connection(connection.SSHConnection):
    def __init__(self, *args, **kwargs):
        connection.SSHConnection.__init__(self, *args, **kwargs)
        self.forwarding_sockets = []

    def serviceStarted(self):
        # Create a tunnel from 12345 to 54321
        self.forward_port(12345, 54321)
        # Do something through the tunnel
        p = Proxy('http://localhost:12345/')    # passing through the tunnel,
                                                # triggers the KeyError
        #p = Proxy('http://localhost:54321/')   # not using the tunnel, works
        print "ping...",
        d = p.callRemote("ping")
        def stop_ok(response):
            print response
            conn.disconnect()
            reactor.stop()
        def stop_error(error):
            print "error", error
            conn.disconnect()
            reactor.stop()
        d.addCallback(stop_ok)
        d.addErrback(stop_error)

    def serviceStopped(self):
        # Stop forwarding sockets
        for socket in self.forwarding_sockets:
            socket.stopListening()

    def forward_port(self, local_port, remote_port):
        print "forwarding %d => %d" % (local_port, remote_port)
        socket = reactor.listenTCP(local_port, 
                forwarding.SSHListenForwardingFactory(self, 
                    ("localhost", remote_port), 
                    forwarding.SSHListenClientForwardingChannel))
        self.forwarding_sockets.append(socket)


class DummyServer(xmlrpc.XMLRPC):
    def xmlrpc_ping(self):
        return "pong"


if __name__ == "__main__":    
    if len(sys.argv) != 2:
        print "usage: test.py user"
        sys.exit(1)
    #log.startLogging(sys.stdout)    

    # If the server is not running, stop_error() errback is triggered and we 
    # have the KeyError when passing through the tunnel
    #reactor.listenTCP(54321, server.Site(DummyServer()))

    conn = connect(sys.argv[1], "localhost")
    reactor.run()
_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to