Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using "recvmsg" with anyio #201

Closed
smurfix opened this issue Feb 20, 2021 · 10 comments · Fixed by #224
Closed

Using "recvmsg" with anyio #201

smurfix opened this issue Feb 20, 2021 · 10 comments · Fixed by #224
Labels
enhancement New feature or request
Milestone

Comments

@smurfix
Copy link
Collaborator

smurfix commented Feb 20, 2021

Using wait_socket_readable fails when using asyncio.

Seems that asyncio decides to add a socket reader as soon as the socket is opened – which causes BaseSelectorEventLoop._ensure_fd_no_transport to go splat when I try to check for readability.

This test program succeeds with trio, but not with asyncio:

#!/usr/bin/python3

# boring stuff
import anyio
PORT=59493
async def main():
    async def handler(sock):
        await sock.send(b'123')
        await anyio.sleep(9999)
    async def server(evt):
        listener = await anyio.create_tcp_listener(local_port=PORT)
        await evt.set()
        await listener.serve(handler)

    async with anyio.create_task_group() as tg:
        evt = anyio.create_event()
        await tg.spawn(server, evt)
        await evt.wait()
# boring stuff ends

        async with await anyio.connect_tcp('localhost', PORT) as client:
            sock = client.extra(anyio.abc.SocketAttribute.raw_socket)
            await anyio.wait_socket_readable(sock.fileno())
            data, aux, *_ = sock.recvmsg(4096,1024)
            assert data == b'123', data

            await tg.cancel_scope.cancel()
anyio.run(main, backend="asyncio")

I'm doing this because depending on the options it's called with, the library I'm anyio-izing may need to pass file descriptors along.

@agronholm
Copy link
Owner

Yeah, wait_socket_readable() and wait_socket_writable() are not kosher when used on already-wrapped sockets and cannot be expected to work. Perhaps this should be mentioned in the documentation.

You mention passing file descriptors, but that's only possible with UNIX sockets, not TCP. What gives?

@smurfix
Copy link
Collaborator Author

smurfix commented Feb 21, 2021

Nothing gives, I was lazy and used a TCP example to illustrate the problem because I had that lying around.

WRT asyncio one might expect that calling pause_reading on the thing would be sufficient for something else to be granted access to the socket, but that would probably be too easy … there's also no way to cleanly un-wrap a socket; I can dup() it, but attempting to close the original calls shutdown, so I'd have to keep that around too. Bah.

@agronholm
Copy link
Owner

Supporting recvmsg() has been on my private to-do list for a while but up until now nobody has asked for it.

@agronholm
Copy link
Owner

Would it be enough for it to be part of the 3.0 release? I don't really want to add any more features to the 2.x branch.

@smurfix
Copy link
Collaborator Author

smurfix commented Feb 21, 2021

Sure, no problem. The code I'm adapting is going to rely on 3.0's sync-calling features anyway.

@agronholm agronholm added the enhancement New feature or request label Feb 21, 2021
@agronholm agronholm added this to the 3.0.0 milestone Feb 21, 2021
smurfix added a commit to M-o-a-T/asyncdbus that referenced this issue Feb 22, 2021
Need to use raw sockets, because the readiness checks fail, because
asyncio is stupid.

agronholm/anyio#201
@agronholm
Copy link
Owner

I can probably support the narrow use case of sending and receiving a bunch of file descriptors over UNIX sockets, but general recvmsg support in SocketStream is a no-go.

@agronholm
Copy link
Owner

Oh boy. Turns out I have to completely abandon the existing asyncio SocketStream class for UNIX sockets if I want to support this. If a Transport is holding on to a socket, it cannot used for anything else, period. And since asyncio does not support sendmsg() in any way...

@agronholm
Copy link
Owner

Whew, that was a load of work. A new proof-of-concept UNIX socket stream and listener have been successfully tested.

@agronholm
Copy link
Owner

The test suite now passes with the new UNIXSocketStream and UNIXSocketListener implementations. I'll make a PR once I've added new tests for the receive_fds() and send_fds() methods.

@smurfix
Copy link
Collaborator Author

smurfix commented Mar 2, 2021

A heap of thanks for doing that work.

agronholm added a commit that referenced this issue Mar 2, 2021
…cket stream

Closes #201.

Problem: only "pseudo" sockets come out of uvloop, can't use sendmsg()!
agronholm added a commit that referenced this issue Mar 2, 2021
agronholm added a commit that referenced this issue Mar 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants