Using transport's socket with low level add_reader/add_writer #372
Description
Turns out people use transports' sockets with add_reader
/ add_writer
low level APIs. I've discovered this while debugging a crash of a webapp deployed with uvloop. The reason of that crash is how aiohttp implements sendfile: they use transport.get_extra_info('socket')
to get the underlying socket, and then they use loop.add_writer
and loop.remove_writer
on that socket.
The crash in uvloop is caused by how file descriptors are stored internally by libuv. I'll make a workaround for that by using os.dup()
to return a duplicate socket from transport.get_extra_info('socket')
.
However, I think we should do this in asyncio too. The thing is that when you use add_writer
and remove_writer
on the transport's socket, you're messing with the internal state of the transport. For instance, a transport might be in the middle of writing data, and calling remove_writer
will cause the whole program to hang.
I see two options:
- We always return duplicate sockets from
transport.get_extra_info()
, hiding the actual socket that transport is attached to. - We find a way to raise an exception if
add|remove_witer|reader
is used on a transport's socket.
I'm more inclined to do the 1.
/cc @asvetlov