-
-
Notifications
You must be signed in to change notification settings - Fork 347
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
On Linux, set up socket object correctly when creating from an fd #251
Comments
The description above is a bit confusing... for example, it links to some complicated code using ctypes, but that's only needed for old python versions we don't support anyway. For us it can be fairly simple. Basically we need something like a function that takes the family/type/proto that the user gave us, and fixes them up as best we can (which might be more or less, depending on the OS). For example (untested): def _fix_attrs_for_fileno(family, type, proto, fileno):
# Wrap the raw fileno into a Python socket object
# This object might have the wrong metadata, but it lets us easily call getsockopt
# and then we'll throw it away and construct a new one with the correct metadata.
sockobj = _stdlib_socket.socket(fileno=fileno)
try:
if hasattr(socket, "SO_DOMAIN"):
family = sockobj.getsockopt(SOL_SOCKET, SO_DOMAIN)
if hasattr(socket, "SO_TYPE"):
type = sockobj.getsockopt(SOL_SOCKET, SO_TYPE)
if hasattr(socket, "SO_PROTOCOL"):
proto = sockobj.getsockopt(SOL_SOCKET, SO_PROTOCOL)
finally:
# Unwrap it again, so that sockobj.__del__ doesn't try to close our socket
sockobj.detach()
return family, type, proto And then in family, type, proto = _fix_attrs_for_fileno(family, type, proto, fileno) (copied from #577 (comment)) |
It looks python 3.7 now handles this automatically: python/cpython#1349 Their approach is slightly different than what I wrote above... it only fills in the family/type/proto when they're unspecified; if the user sets one explicitly, then it trusts them. Not sure what the point of this is (surely the kernel is never wrong about the attributes of a socket?) |
Python has APIs for wrapping a bare socket fd into a socket object:
socket.socket(fileno=...)
to wrap, andsocket.fromfd(fileno, ...)
to dup-and-wrap. We currently inherit these with no changes.There's a fairly nasty bug in Python though: to work with a socket correctly, it's not enough to know the fd; Python also needs to know the address family (most important), the socket type, and the protocol (least important).
On Windows, it correctly pulls this information out of the passed-in socket.[Edit: actually Windows is broken too.] On other platforms, it doesn't (see bpo-28134, bpo-27377).AFAICT on MacOS this is mostly a lost cause. You can use
getsockname
to get the address family, but that only works on connected stream sockets, and there's no way to query for the other attributes. I guess you might be able to distinguish Unix/IPv4/IPv6 families by makinggetsockopt
calls with the appropriate level and see if you get an error or not? MaybeLOCAL_PEERCRED
is a reliable signature of AF_UNIX+SOCK_STREAM, and then there's a bunch of IPv6-specific sockopts... (seeunix(4)
,ip(4)
,ip6(4)
).But on Linux – which is the point of this bug! – this is actually pretty easy. You can just ask for all the key pieces of information like:
(more detailed example: https://github.com/tiran/socketfromfd/blob/master/socketfromfd.py)
And this actually matters, because to support systemd socket activation, we need to be able to take bare fds and wrap them into trio socket objects, on Linux.
So: we should teach
trio.socket.socket
to do these checks on Linux whenfileno=
is given, and we should implementtrio.socket.fromfd
in terms oftrio.socket.socket
. (The standard library's implementation ofsocket.fileno
in terms ofsocket.socket
is ~2 lines of code, we can just copy them into trio.)The text was updated successfully, but these errors were encountered: