Hello asyncio developers, the datagram transports provided by asyncio cover only some of what a datagram socket can do. In particular, I'm missing a way to run `recvmsg` when something is to be read, rather than `recvfrom` which is sufficient to satisfy the datagram transport's interface.
Right now, the only way I see to get information about a message's destination address (RECVPKTINFO) or details of ICMP errors (RECVERR) out of a received package is reaching into asyncio internals in a way I should not[1], which is bound to fail sooner or later, and especially with alternative loop implementations. Before I rush ahead and propose a concrete extension to DatagramProtocol, I'd like to explore the options with you. Possible paths I see out of this are: * Export something like loop._add_reader as part of the public loop interface. Such a function would allow users to implement their own transports on anything that has a file handler than can become readable using the given selector. Adding this would require very little effort for loops that support that concept (eg. gbulb), and might be impossible for others -- where it's probably OK because the underlying platform might not even support other required concepts either. (Case in point: Windows doesn't implement RECVPKTINFO anyway.) * Exporting a third line of protocols / transports Next to having a DatagramTransport / DatagramProtocol, there could be a DatagramRecvmsgTransport / DatagramRecvmsgProtocol with all their construction methods of loops. A DatagramRecvmsgProtocol would have a datagram_received(data, addr, flags, ancdata) callback (with two additional arguments compared to DatagramProtocol's), and an additional error_msg_received(addr, flags, ancdata) callback where requested error information is passed along. The transport would, in addition to .sendto(addr, data), offer a .sendmsg(data, ancdata, flags, address) method. This would mean considerable effort (and probably duplication) on the side of loop implementors, but solves the issue. * Doing something fancy to make recvmsg an optional feature of datagram transports Asyncio could generally run `recvmsg` rather than `recvfrom` on datagram sockets, fetching the error queue if so indicated by the return values of recvmsg. Then it could send the resulting data to a datagram_msg_received(data, addr, flags, ancdata) callback on the DatagramProtocol, which -- unless overridden by the implementation -- could fall back to DatagramProtocol's default handler, which would then throw away the ancdata and call the established callback of DatagramProtocol. I'm not sure whether this is possible within the API guarantees given in asyncio (eg. it would rely on protocols to inherit DatagramProtocol, and if someone already uses their own datagram_msg_received method, they'd accidentally overwrite something now) -- maybe it can be made to work. This would mean a little less effort for third party main loops, but would provide a neater interface IMO. The only alternatives I see to adding any of that are doing as I do now (hooking into the _add_reader of the individual loops) or moving networking into a different thread that runs on a loop where I can do that (which kind of defeats the point of asyncio). Which of the sketched ways do you think are worth pursuing, or should this all be handled differently? Best regards Christian [1]: https://github.com/chrysn/aiocoap/blob/0d09b2eb92a12a01279883f75f1da32099b7559e/aiocoap/util/asyncio/recvmsg.py#L99 -- To use raw power is to make yourself infinitely vulnerable to greater powers. -- Bene Gesserit axiom
signature.asc
Description: PGP signature