python / asyncio

asyncio historical repository
https://docs.python.org/3/library/asyncio.html
1.03k stars 178 forks source link

SSL hangs if connection is closed before handshake completed #472

Closed tvoinarovskyi closed 7 years ago

tvoinarovskyi commented 7 years ago

Here's the snippet, that replicates the issue. I stomped upon this in normal TCP sockets, so sockpair is not the issue.

import asyncio
import socket
import ssl
import sys
import threading

context = ssl.create_default_context()
rsock, wsock = socket.socketpair()

def reader(sock):
    data = sock.recv(4)
    print("RCV", data)
    sock.close()

t = threading.Thread(target=reader, args=(rsock, ))
t.start()
try:
    if sys.argv[1] == 'sync':
        # The blocking example works OK. Exits right away
        sock = context.wrap_socket(
            wsock,
            server_hostname="localhost",
        )
        print("Connected")

    elif sys.argv[1] == "async":
        # Non blocking call example
        async def connect(loop):
            reader, writer = await asyncio.open_connection(
                sock=wsock, ssl=context, loop=loop,
                server_hostname="localhost")
            print("Connected Async")

        loop = asyncio.get_event_loop()
        loop.run_until_complete(loop.create_task(connect(loop)))

finally:
    wsock.close()
    t.join()

The idea is, that the other end is not an SSL socket, but rather some plain protocol, that reads size (lets say 4 bytes) and closes the socket, as size is inappropriate. Blocking (test.py sync) socket works as expected raising ConnectionResetError Async (test.py async) example blocks forever

Version: Python 3.5.2 (default, Jul 17 2016, 00:00:00) [GCC 4.8.4] on linux

tvoinarovskyi commented 7 years ago

Tried with uvloop, it does not support sockpair, as it's not AF_INET, so the example does not work there. Tried it on a normal TCP, and it also hangs. uvloop==0.6.5

1st1 commented 7 years ago

Thanks for reporting this. I'll take a look.

Tried with uvloop, it does not support sockpair, as it's not AF_INET, so the example does not work

It's because create_connection didn't support AF_UNIX sockets. It's fixed in the master branch now.

Tried it on a normal TCP, and it also hangs.

uvloop uses asyncio/sslproto.py and the bug is probably there.

HoHo-Ho commented 7 years ago

Bug is in function connection_lost (member function of class SSLProtocol in asyncio/sslproto.py). This function should call _wakeup_waiter otherwise function _create_connection_transport (in asyncio/base_events.py) will hang on yield from waiter.

1st1 commented 7 years ago

@HoHo-Ho Would you be able to write a patch+test for this and submit to http://github.com/python/asyncio asap? Python 3.6 is scheduled to be released tomorrow, we might still have time to fix this.

1st1 commented 7 years ago

Closing this issue now.