Ticket #5485 defect closed duplicate
Canceling a pending TCP4ClientEndpoint connection leads to an AlreadyCalledError
| Reported by: | jssebastian | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | core | Keywords: | endpoints cancel |
| Cc: | Branch: | ||
| Author: | Launchpad Bug: |
Description
It seems that if a tcp connection is hanging (e.g. because the destiantion host sends no reply), attempting to cancel it will lead to a spurious AlreadyCalledError.
Here is a small test case that triggers this bug:
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet import defer
class Greeter(Protocol):
pass
class GreeterFactory(Factory):
def buildProtocol(self, addr):
return Greeter()
def gotProtocol(p):
print "Got protocol"
def connectionFailed(f):
print "Connection failed"
def timeout(d):
print "Got timeout"
if not d.called:
d.cancel()
#defer.setDebugging(True)
point = TCP4ClientEndpoint(reactor, "www.google.com", 666)
d = point.connect(GreeterFactory())
d.addCallback(gotProtocol)
d.addErrback(connectionFailed)
reactor.callLater(10, timeout, d)
reactor.run()
Notice I even test d.called before calling d.cancel(). www.google.com does not respond on port 666, and after 10 seconds I get:
$python alreadycalled.py
Got timeout
Connection failed
Unhandled Error
Traceback (most recent call last):
File "alreadycalled.py", line 28, in <module>
reactor.run()
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1169, in run
self.mainLoop()
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1178, in mainLoop
self.runUntilCurrent()
--- <exception caught here> ---
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 800, in runUntilCurrent
call.func(*call.args, **call.kw)
File "alreadycalled.py", line 21, in timeout
d.cancel()
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/defer.py", line 427, in cancel
canceller(self)
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/endpoints.py", line 261, in _canceller
error.ConnectingCancelledError(connector.getDestination()))
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/defer.py", line 391, in errback
self._startRunCallbacks(fail)
File "/usr/local/lib/python2.6/dist-packages/Twisted-11.1.0-py2.6-linux-x86_64.egg/twisted/internet/defer.py", line 451, in _startRunCallbacks
raise AlreadyCalledError
twisted.internet.defer.AlreadyCalledError:
Notice that the connection failed message is printed *after* the cancel() call.
Tested on:
twisted 11.1.0, python 2.6 on ubuntu 10.04 64 bit
twisted 11.1.0, python 2.7 on ubuntu 11.10 64 bit
Change History
Note: See
TracTickets for help on using
tickets.
