Bug report
Bug description:
Problem description
We are using create_datagram_endpoint() to set up an asyncio-managed connection to a native hardware CAN bus interface at can0 under debian linux. We are using the sock named argument to pass in a pre-built raw socket to the FD.
This works in Python 3.5.3 but broke following a migration to 3.11.4. We found that the datagram endpoint would fail to be brought up, and the connection_made(transport) method on the protocol_factory would never be called. When I rejigged our code to await the coroutine I got:
ValueError: A UDP Socket was expected, got <socket.socket fd=7, family=29, type=3, proto=1, laddr=('can0',)
I believe this has gone unnoticed due to hardware CAN bus interfaces being rare.
Relevant history
#4231
#4898
#4922
Discussion of underlying issues: https://bugs.python.org/issue32331
Core issue
A socket connected to a CAN bus has sock.type socket.SOCK_RAW, I.E. 0b11. This fails the comparison to socket.SOCK_DGRAM (0b01) so create_datagram_endpoint() raises an exception because the socket's type fails the "is a datagram" check, even though it is. In 3.5.3 the check was:
(sock.type & socket.SOCK_DGRAM) == socket.SOCK_DGRAM
This worked because it was treating SOCK_DGRAM as a bitwise mask, which it kinda is, but kinda isn't.
x86_64-linux-gnu/bits/socket_type.h:
...
/* Types of sockets. */
enum __socket_type
{
SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
byte streams. */
#define SOCK_STREAM SOCK_STREAM
SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
of fixed maximum length. */
#define SOCK_DGRAM SOCK_DGRAM
SOCK_RAW = 3, /* Raw protocol interface. */
#define SOCK_RAW SOCK_RAW
SOCK_RDM = 4, /* Reliably-delivered messages. */
...
I am torn on the best way to approach a fix here. I have written a PR that replaces
if sock.type != socket.SOCK_DGRAM:
comparisons with
if not sock.type & socket.SOCK_DGRAM:
however this perpetuates the enum-vs-bitmask confusion. A more constrained change might be to change
if sock.type != socket.SOCK_DGRAM:
to
if not (sock.type == socket.SOCK_DGRAM || sock.type == socket.SOCK_RAW):
but that may not catch every instance of the problem. I'd appreciate some guidance on this.
Cheers,
Travis.
CPython versions tested on:
3.11
Operating systems tested on:
Linux
Linked PRs
Bug report
Bug description:
Problem description
We are using
create_datagram_endpoint()to set up an asyncio-managed connection to a native hardware CAN bus interface atcan0under debian linux. We are using thesocknamed argument to pass in a pre-built raw socket to the FD.This works in Python 3.5.3 but broke following a migration to 3.11.4. We found that the datagram endpoint would fail to be brought up, and the
connection_made(transport)method on theprotocol_factorywould never be called. When I rejigged our code to await the coroutine I got:I believe this has gone unnoticed due to hardware CAN bus interfaces being rare.
Relevant history
#4231
#4898
#4922
Discussion of underlying issues: https://bugs.python.org/issue32331
Core issue
A socket connected to a CAN bus has
sock.typesocket.SOCK_RAW, I.E.0b11. This fails the comparison tosocket.SOCK_DGRAM(0b01) socreate_datagram_endpoint()raises an exception because the socket's type fails the "is a datagram" check, even though it is. In 3.5.3 the check was:This worked because it was treating SOCK_DGRAM as a bitwise mask, which it kinda is, but kinda isn't.
x86_64-linux-gnu/bits/socket_type.h:
... /* Types of sockets. */ enum __socket_type { SOCK_STREAM = 1, /* Sequenced, reliable, connection-based byte streams. */ #define SOCK_STREAM SOCK_STREAM SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams of fixed maximum length. */ #define SOCK_DGRAM SOCK_DGRAM SOCK_RAW = 3, /* Raw protocol interface. */ #define SOCK_RAW SOCK_RAW SOCK_RDM = 4, /* Reliably-delivered messages. */ ...I am torn on the best way to approach a fix here. I have written a PR that replaces
comparisons with
however this perpetuates the enum-vs-bitmask confusion. A more constrained change might be to change
to
but that may not catch every instance of the problem. I'd appreciate some guidance on this.
Cheers,
Travis.
CPython versions tested on:
3.11
Operating systems tested on:
Linux
Linked PRs