Repository navigation
start_tls() does not call connection_lost() when the handshake is aborted #160513
Copy link
Copy link
Open
Open
Copy link
Labels
Description
Bug report
Bug description:
When the connection is lost while a TLS handshake started by loop.start_tls() or StreamWriter.start_tls() is in progress, the protocol's connection_lost() is never called. start_tls() raises, but SSLProtocol.connection_lost() skips the application protocol whenever its own state is DO_HANDSHAKE, although with start_tls() that protocol has already had connection_made(). With streams, StreamWriter.wait_closed() then never returns.
import asyncio, socket, ssl, struct, threading
def serve(lsock):
for _ in range(2):
conn, _ = lsock.accept()
conn.recv(65536) # ClientHello
# Reset the connection in the middle of the handshake.
conn.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
conn.close()
class Proto(asyncio.Protocol):
lost = False
def connection_lost(self, exc):
self.lost = True
async def main():
loop = asyncio.get_running_loop()
ctx = ssl.create_default_context()
lsock = socket.create_server(('127.0.0.1', 0))
threading.Thread(target=serve, args=(lsock,), daemon=True).start()
addr = lsock.getsockname()
tr, proto = await loop.create_connection(Proto, *addr)
try:
await loop.start_tls(tr, proto, ctx, server_hostname='localhost')
except OSError as exc:
print('loop.start_tls():', repr(exc))
await asyncio.sleep(1)
print('connection_lost() called:', proto.lost)
reader, writer = await asyncio.open_connection(*addr)
try:
await writer.start_tls(ctx, server_hostname='localhost')
except OSError as exc:
print('writer.start_tls():', repr(exc))
writer.close()
try:
await asyncio.wait_for(writer.wait_closed(), 5)
except TimeoutError:
print('wait_closed() still pending after 5 seconds')
except OSError as exc:
print('wait_closed():', repr(exc))
lsock.close()
asyncio.run(main())Output on main:
loop.start_tls(): ConnectionResetError(104, 'Connection reset by peer')
connection_lost() called: False
writer.start_tls(): ConnectionResetError(104, 'Connection reset by peer')
wait_closed() still pending after 5 seconds
Expected: connection_lost() is called and wait_closed() completes, raising the same error. wait_closed() hangs in the same way when the handshake fails because ssl_handshake_timeout expired. The check dates back to the addition of loop.start_tls() in 3.7.
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsTodo
Activity