# Buggy code
def _wrap_connection_future(self, transport, done, conn_f):
    def on_connect_success(result):
        # async connect call returns a 2-tuple
        transport, proto = result

        # if e.g. an SSL handshake fails, we will have
        # successfully connected (i.e. get here) but need to
        # 'listen' for the "connection_lost" from the underlying
        # protocol in case of handshake failure .. so we wrap
        # it. Also, we don't increment transport.success_count
        # here on purpose (because we might not succeed).

        # XXX double-check that asyncio behavior on TLS handshake
        # failures is in fact as described above
        orig = proto.connection_lost

        @wraps(orig)
        def lost(fail):
            rtn = orig(fail)
            if not txaio.is_called(done):
                # asyncio will call connection_lost(None) in case of
                # a transport failure, in which case we create an
                # appropriate exception
                if fail is None:
                    fail = TransportLost("failed to complete connection")
                txaio.reject(done, fail)
            return rtn

        proto.connection_lost = lost

    def on_connect_failure(err):
        transport.connect_failures += 1
        # failed to establish a connection in the first place
        txaio.reject(done, err)

    txaio.add_callbacks(conn_f, on_connect_success, None)
    # the errback is added as a second step so it gets called if
    # there as an error in on_connect_success itself.
    txaio.add_callbacks(conn_f, None, on_connect_failure)
    return conn_f


# Traceback (ConnectionResetError)
2019-03-25 15:29:00.597 13776 DEBUG autobahn.asyncio.component.Component [-] component failed: TransportLost: failed to complete connection _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:00.609 13776 DEBUG autobahn.asyncio.component.Component [-] Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
autobahn.wamp.exception.TransportLost: failed to complete connection
_log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:00.615 13776 ERROR autobahn.asyncio.component.Component [-] Connection failed: TransportLost: failed to complete connection: autobahn.wamp.exception.TransportLost: failed to complete connection
2019-03-25 15:29:00.624 13776 DEBUG autobahn.asyncio.component.Component [-] Entering re-connect loop _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:00.631 13776 DEBUG autobahn.asyncio.component.Component [-] trying transport 0 using connect delay 25.279705208019543 _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:25.946 13776 INFO autobahn.asyncio.component.Component [-] connecting once using transport type "websocket" over endpoint "tcp"
2019-03-25 15:29:29.403 13776 DEBUG autobahn.asyncio.component.Component [-] component failed: ConnectionResetError: [Errno 104] Connection reset by peer _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:29.448 13776 DEBUG autobahn.asyncio.component.Component [-] Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/local/lib/python3.5/dist-packages/txaio/aio.py", line 514, in done
res = f.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "/usr/lib/python3.5/asyncio/tasks.py", line 400, in wait_for
return fut.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
result = coro.throw(exc)
File "/usr/lib/python3.5/asyncio/base_events.py", line 801, in create_connection
sock, protocol_factory, ssl, server_hostname)
File "/usr/lib/python3.5/asyncio/base_events.py", line 827, in _create_connection_transport
yield from waiter
File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
yield self  # This tells Task to wait for completion.
File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/selector_events.py", line 723, in _read_ready
data = self._sock.recv(self.max_size)
ConnectionResetError: [Errno 104] Connection reset by peer
_log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:29.454 13776 INFO autobahn.asyncio.component.Component [-] Connection failed: ConnectionResetError: [Errno 104] Connection reset by peer
2019-03-25 15:29:29.471 13776 DEBUG autobahn.asyncio.component.Component [-] Entering re-connect loop _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:29:29.480 13776 DEBUG autobahn.asyncio.component.Component [-] trying transport 0 using connect delay 34.52392114857189 _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:30:04.060 13776 INFO autobahn.asyncio.component.Component [-] connecting once using transport type "websocket" over endpoint "tcp"
2019-03-25 15:30:08.150 13776 DEBUG autobahn.asyncio.websocket.WebSocketClientProtocol [-]
[('logOctets', False, 'WampWebSocketClientFactory'),
('logFrames', False, 'WampWebSocketClientFactory'),
('trackTimings', False, 'WampWebSocketClientFactory'),
('utf8validateIncoming', True, 'WampWebSocketClientFactory'),
('applyMask', True, 'WampWebSocketClientFactory'),
('maxFramePayloadSize', 0, 'WampWebSocketClientFactory'),
('maxMessagePayloadSize', 0, 'WampWebSocketClientFactory'),
('autoFragmentSize', 0, 'WampWebSocketClientFactory'),
('failByDrop', True, 'WampWebSocketClientFactory'),
('echoCloseCodeReason', False, 'WampWebSocketClientFactory'),
('openHandshakeTimeout', 5, 'WampWebSocketClientFactory'),
('closeHandshakeTimeout', 1, 'WampWebSocketClientFactory'),
('tcpNoDelay', True, 'WampWebSocketClientFactory'),
('autoPingInterval', 0, 'WampWebSocketClientFactory'),
('autoPingTimeout', 0, 'WampWebSocketClientFactory'),
('autoPingSize', 4, 'WampWebSocketClientFactory'),
('version', 18, 'WampWebSocketClientFactory'),
('acceptMaskedServerFrames', False, 'WampWebSocketClientFactory'),
('maskClientFrames', True, 'WampWebSocketClientFactory'),
('serverConnectionDropTimeout', 1, 'WampWebSocketClientFactory'),
('perMessageCompressionOffers', [], 'WampWebSocketClientFactory'),
('perMessageCompressionAccept',
<function WebSocketClientFactory.resetProtocolOptions.<locals>.<lambda> at 0xb3d51300>,
'WampWebSocketClientFactory')] _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:30:08.163 13776 DEBUG autobahn.asyncio.websocket.WebSocketClientProtocol [-] connection to tcp:51.75.29.206:8181 established _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:30:08.180 13776 DEBUG autobahn.asyncio.websocket.WebSocketClientProtocol [-] GET / HTTP/1.1
User-Agent: AutobahnPython/19.3.3
Host: <OUR-CROSSBAR-SERVER-IP>:8181
Upgrade: WebSocket
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: 8eiSBL+/0+X97Hz9R5+JhQ==
Sec-WebSocket-Protocol: wamp.2.json
Sec-WebSocket-Version: 13

_log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:30:08.191 13776 DEBUG autobahn.asyncio.websocket.WebSocketClientProtocol [-] _connectionLost: [Errno 104] Connection reset by peer _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201
2019-03-25 15:30:12.311 13776 DEBUG autobahn.asyncio.websocket.WebSocketClientProtocol [-] skipping opening handshake timeout: WebSocket connection is already closed _log /usr/local/lib/python3.5/dist-packages/txaio/aio.py:201

# Fixed code
def _wrap_connection_future(self, transport, done, conn_f):
    def on_connect_success(result):
        # async connect call returns a 2-tuple
        transport, proto = result

        # in the case where we .abort() the transport / connection
        # during setup, we still get on_connect_success but our
        # transport is already closed (this will happen if
        # e.g. there's an "open handshake timeout") -- I don't
        # know if there's a "better" way to detect this? #python
        # doesn't know of one, anyway
        if transport.is_closing():
            if not txaio.is_called(done):
                reason = getattr(proto, "_onclose_reason", "Connection already closed")
                txaio.reject(done, TransportLost(reason))
            return

        # if e.g. an SSL handshake fails, we will have
        # successfully connected (i.e. get here) but need to
        # 'listen' for the "connection_lost" from the underlying
        # protocol in case of handshake failure .. so we wrap
        # it. Also, we don't increment transport.success_count
        # here on purpose (because we might not succeed).

        # XXX double-check that asyncio behavior on TLS handshake
        # failures is in fact as described above
        orig = proto.connection_lost

        @wraps(orig)
        def lost(fail):
            rtn = orig(fail)
            if not txaio.is_called(done):
                # asyncio will call connection_lost(None) in case of
                # a transport failure, in which case we create an
                # appropriate exception
                if fail is None:
                    fail = TransportLost("failed to complete connection")
                txaio.reject(done, fail)
            return rtn

        proto.connection_lost = lost

    def on_connect_failure(err):
        transport.connect_failures += 1
        # failed to establish a connection in the first place
        txaio.reject(done, err)

    txaio.add_callbacks(conn_f, on_connect_success, None)
    # the errback is added as a second step so it gets called if
    # there as an error in on_connect_success itself.
    txaio.add_callbacks(conn_f, None, on_connect_failure)
    return conn_f