[Twisted-Python] KeyError when an errback is triggered within a conch TCP tunnel

(posting it a second time with the example code inlined as pipermail did not like the attachment) 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 Example code: -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*- #!/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() -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

Running the example in the debugger, neither ssh_CHANNEL_OPEN() nor ssh_CHANNEL_OPEN_CONFIRMATION() method of twisted.conch.ssh.connection.SSHConnection is called, so self.channelsToRemoteChannel dict is empty when sendClose() is called, thus the error. I am not sure if I should file a bug as I'm new to Twisted, does anyone see an obvious mistake in my code ? Cheers, Luper
participants (2)
-
luper rouch
-
Luper Rouch