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

service name not available for the specified socket type #692

Open
2 tasks done
mtelka opened this issue Feb 21, 2024 · 19 comments
Open
2 tasks done

service name not available for the specified socket type #692

mtelka opened this issue Feb 21, 2024 · 19 comments
Labels
bug Something isn't working

Comments

@mtelka
Copy link

mtelka commented Feb 21, 2024

Things to check first

  • I have searched the existing issues and didn't find my bug already reported there

  • I have checked that my bug is still present in the latest release

AnyIO version

4.3.0

Python version

3.9.18

What happened?

Several anyio tests fails with this error:

_________________ TestTLSListener.test_handshake_fail[asyncio] _________________
tests/streams/test_tls.py:417: in test_handshake_fail
    listener = await create_tcp_listener(local_host="127.0.0.1")
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_core/_sockets.py:290: in create_tcp_listener
    gai_res = await getaddrinfo(
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_core/_sockets.py:573: in getaddrinfo
    gai_res = await get_async_backend().getaddrinfo(
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_backends/_asyncio.py:2370: in getaddrinfo
    return await get_running_loop().getaddrinfo(
/usr/lib/python3.9/asyncio/base_events.py:861: in getaddrinfo
    return await self.run_in_executor(
/usr/lib/python3.9/concurrent/futures/thread.py:58: in run
    result = self.fn(*self.args, **self.kwargs)
/usr/lib/python3.9/asyncio/base_events.py:844: in _getaddrinfo_debug
    addrinfo = socket.getaddrinfo(host, port, family, type, proto, flags)
/usr/lib/python3.9/socket.py:954: in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
E   socket.gaierror: [Errno 9] service name not available for the specified socket type

Here is the complete list of tests with this failure:

TestTLSListener.test_handshake_fail[asyncio]
TestTLSListener.test_extra_attributes[asyncio]
TestTCPListener.test_extra_attributes[asyncio-ipv4]
TestTCPListener.test_extra_attributes[asyncio-ipv6]
TestTCPListener.test_accept[asyncio-ipv4]
TestTCPListener.test_accept[asyncio-ipv6]
TestTCPListener.test_accept[asyncio-both]
TestTCPListener.test_accept_after_close[asyncio-ipv4]
TestTCPListener.test_accept_after_close[asyncio-ipv6]
TestTCPListener.test_socket_options[asyncio-ipv4]
TestTCPListener.test_socket_options[asyncio-ipv6]
TestTCPListener.test_close_from_other_task[asyncio-ipv4]
TestTCPListener.test_close_from_other_task[asyncio-ipv6]
TestTCPListener.test_send_after_eof[asyncio-ipv4]
TestTCPListener.test_send_after_eof[asyncio-ipv6]
TestTCPListener.test_bind_link_local[asyncio]
test_multi_listener[asyncio]
test_getaddrinfo[asyncio]

The problem seems to be that getaddrinfo is called with port=0. The similar issue was already fixed in eventlet (please read the link for more details about the issue).

How can we reproduce the bug?

Run anyio tests on OpenIndiana.

@mtelka mtelka added the bug Something isn't working label Feb 21, 2024
@agronholm
Copy link
Owner

I'm just wondering why this fails only on this specific distro and not any other.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

I'm just wondering why this fails only on this specific distro and not any other.

Because other distros are usually Linux?

@agronholm
Copy link
Owner

I'm just wondering why this fails only on this specific distro and not any other.

Because other distros are usually Linux?

Ahh...I didn't realize.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

BTW, I tried this:

--- anyio-4.3.0/src/anyio/_core/_sockets.py.orig
+++ anyio-4.3.0/src/anyio/_core/_sockets.py
@@ -264,7 +264,7 @@
 async def create_tcp_listener(
     *,
     local_host: IPAddressType | None = None,
-    local_port: int = 0,
+    local_port: int | None = None,
     family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC,
     backlog: int = 65536,
     reuse_port: bool = False,

This allowed the create_tcp_listener() to succeed, but tests/streams/test_tls.py still failed later with:

_________________ TestTLSListener.test_handshake_fail[asyncio] _________________
tests/streams/test_tls.py:422: in test_handshake_fail
    sock.connect(listener.extra(SocketAttribute.local_address))
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_core/_typedattr.py:79: in extra
    raise TypedAttributeLookupError("Attribute not found") from None
E   anyio.TypedAttributeLookupError: Attribute not found

So this apparently needs more work :-(.

@agronholm
Copy link
Owner

I think it'd be best if you submitted a PR. I don't think I can reasonably verify this, as I'm not familiar with this OS.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

Is what I propose above for _socket.py the right way to go? If so, then you can start with that and IMHO you'll see the same failure at tests/streams/test_tls.py:422 as I do. I believe this is not platform specific.

@agronholm
Copy link
Owner

agronholm commented Feb 21, 2024

If the problem is just with getaddrinfo(), then how about a simpler change?

    gai_res = await getaddrinfo(
        local_host,
        local_port or None,
        family=family,
        type=socket.SocketKind.SOCK_STREAM if sys.platform == "win32" else 0,
        flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
    )

This at least passes my local tests.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

I tried:

--- anyio-4.3.0/src/anyio/_core/_sockets.py.orig
+++ anyio-4.3.0/src/anyio/_core/_sockets.py
@@ -289,7 +289,7 @@
     local_host = str(local_host) if local_host is not None else None
     gai_res = await getaddrinfo(
         local_host,
-        local_port,
+        local_port or None,
         family=family,
         type=socket.SocketKind.SOCK_STREAM if sys.platform == "win32" else 0,
         flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,

And I see the same failure here:

_________________ TestTLSListener.test_handshake_fail[asyncio] _________________
tests/streams/test_tls.py:422: in test_handshake_fail
    sock.connect(listener.extra(SocketAttribute.local_address))
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_core/_typedattr.py:79: in extra
    raise TypedAttributeLookupError("Attribute not found") from None
E   anyio.TypedAttributeLookupError: Attribute not found

So it looks like this failure is not platform agnostic as I hoped :-(.

@agronholm
Copy link
Owner

It's just one failure, or are there more?

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

This is the complete list of failed test with anyio.TypedAttributeLookupError: Attribute not found error I see with the above change:

TestTLSListener.test_handshake_fail[asyncio]
TestTLSListener.test_extra_attributes[asyncio]
TestTCPListener.test_extra_attributes[asyncio-ipv4]
TestTCPListener.test_extra_attributes[asyncio-ipv6]
TestTCPListener.test_send_after_eof[asyncio-ipv4]
TestTCPListener.test_send_after_eof[asyncio-ipv6]

The test_getaddrinfo[asyncio] test is still failing with service name not available for the specified socket type (apparently there are more places where 0 should be replaced by None), two are failing with different error now, namely these:

___________ TestTCPListener.test_close_from_other_task[asyncio-ipv4] ___________
tests/test_sockets.py:650: in test_close_from_other_task
    tg.cancel_scope.cancel()
E   Failed: DID NOT RAISE <class 'exceptiongroup.ExceptionGroup'>
___________ TestTCPListener.test_close_from_other_task[asyncio-ipv6] ___________
tests/test_sockets.py:650: in test_close_from_other_task
    tg.cancel_scope.cancel()
E   Failed: DID NOT RAISE <class 'exceptiongroup.ExceptionGroup'>

and all other tests from the initial list are passing now.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

... and these failures are not related to port=0 vs. port=None. Here is another example:

_____________ TestTCPListener.test_extra_attributes[asyncio-ipv4] ______________
tests/test_sockets.py:521: in test_extra_attributes
    assert multi.extra(SocketAttribute.family) == family
../prototype/i386/usr/lib/python3.9/vendor-packages/anyio/_core/_typedattr.py:79: in extra
    raise TypedAttributeLookupError("Attribute not found") from None
E   anyio.TypedAttributeLookupError: Attribute not found

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

... and these failures are not related to port=0 vs. port=None. Here is another example:

In other words, your proposed change (or mine, they are effectively very similar) is clearly improving things. But it looks like the similar issue is in create_udp_socket(), and maybe at some other places too.

@agronholm
Copy link
Owner

I don't think I can effectively work on these if I can't reproduce them.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

I don't think I can effectively work on these if I can't reproduce them.

Okay, np. Will you accept a PR if I create it based on my local_port: int | None = None proposal?

@agronholm
Copy link
Owner

I'd much prefer a PR that fixes all of the problems you're seeing. I can help you figure out the rest.

@mtelka
Copy link
Author

mtelka commented Feb 21, 2024

Hmmm, I see those as different issues, so I'd prefer to handle them separately...

Anyway, what do you suggest for the assert multi.extra(SocketAttribute.family) == family issue?

@agronholm
Copy link
Owner

Hmmm, I see those as different issues, so I'd prefer to handle them separately...

From my PoV, they all fall under the umbrella of "fails on Illumos, works everywhere else".

Anyway, what do you suggest for the assert multi.extra(SocketAttribute.family) == family issue?

That's something you need to dive into – check why the attribute isn't available. The _SocketProvider class might be a good place to start.

@agronholm
Copy link
Owner

I think that what's happening here is that the attribute is actually found, but its getter raises KeyError, thus leading into this error. This in itself is a subtle bug.

@agronholm
Copy link
Owner

That said, the accessor doesn't do any dict lookups so I don't understand where the KeyError is coming from. Setting a breakpoint after line 77 in _typedattr.py should help figure it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants