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

bpo-28134: Auto-detect socket values from file descriptor #1349

Merged
merged 1 commit into from
Jan 29, 2018

Conversation

tiran
Copy link
Member

@tiran tiran commented Apr 28, 2017

Fix socket(fileno=fd) by auto-detecting the socket's family, type,
and proto from the file descriptor. The auto-detection can be overruled
by passing in family, type, and proto explicitly.

Without the fix, all socket except for TCP/IP over IPv4 are basically broken:

>>> s = socket.create_connection(('www.python.org', 443))
>>> s
<socket.socket fd=3, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=6, laddr=('2003:58:bc4a:3b00:56ee:75ff:fe47:ca7b', 59730, 0, 0), raddr=('2a04:4e42:1b::223', 443, 0, 0)>
>>> socket.socket(fileno=s.fileno())
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('2003:58:bc4a:3b00::%2550471192', 59730, 0, 2550471192), raddr=('2a04:4e42:1b:0:700c:e70b:ff7f:0%2550471192', 443, 0, 2550471192)>

Signed-off-by: Christian Heimes christian@python.org

https://bugs.python.org/issue28134

# For user code address family and type values are IntEnum members, but
# for the underlying _socket.socket they're just integers. The
# constructor of _socket.socket converts the given argument to an
# integer automatically.
if fileno is None:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block is not necessary but makes the code easier to understand for non-C coders

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you propose to remove it? If not, I suggest None for default values rather than −1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, while -1 falling through to socketmodule.c would trigger its default behavior, writing this here in Python would be nicer using the =None idiom.

@tiran tiran force-pushed the bpo-28134-socket-fd branch 2 times, most recently from 67264b2 to a3650c7 Compare April 28, 2017 19:50
@nascheme
Copy link
Member

I like this better than my fromfd2() patch (https://bugs.python.org/issue27377). A few comments:

  • I think the tests need to be conditional based on platform. I suspect they only pass on Linux as they are.
  • I suggest adding a version change note to socket.socket, e.g.

.. versionchanged:: 3.7
If supported by platform, get socket family, type and protocol from
passed fileno.

I think querying a file descriptor for this information could be a useful operation without tying it to socket.socket(). I'm going to create a separate pull request that adds socket.fdtype(). The unit tests you have added could check for socket.fdtype before enabling them (e.g. hasattr(socket, 'fdtype')). I have created a HAVE_FDTYPE define that should only be enabled on platforms that support the operation.

@tiran tiran force-pushed the bpo-28134-socket-fd branch from a3650c7 to c634ce9 Compare April 28, 2017 22:18
@tiran
Copy link
Member Author

tiran commented Apr 29, 2017

@nascheme my patch has a big catch. On some platforms getsockname() does not work with sockets that are neither bound nor connected. For that reason my tests are currently failing on Windows. IIRC you were running into the same issue with socket.fdtype(). https://msdn.microsoft.com/de-de/library/windows/desktop/ms738543(v=vs.85).aspx

@tiran tiran force-pushed the bpo-28134-socket-fd branch 4 times, most recently from 0be56ed to c375e06 Compare April 29, 2017 20:25
@brettcannon brettcannon added the type-feature A feature request or enhancement label May 1, 2017
@tiran tiran force-pushed the bpo-28134-socket-fd branch from c375e06 to cc4cb87 Compare July 20, 2017 16:03
@tiran tiran force-pushed the bpo-28134-socket-fd branch from cc4cb87 to bf90728 Compare September 5, 2017 17:12
@@ -4083,7 +4083,7 @@ def get_high_socket_fd(self):

def close(self, fd):
if WIN32:
socket.socket(fileno=fd).close()
socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=fd).close()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use keyword arguments for all of these.

# For user code address family and type values are IntEnum members, but
# for the underlying _socket.socket they're just integers. The
# constructor of _socket.socket converts the given argument to an
# integer automatically.
if fileno is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, while -1 falling through to socketmodule.c would trigger its default behavior, writing this here in Python would be nicer using the =None idiom.

#else
PyErr_SetFromErrnoWithFilename(PyExc_OSError, "type");
#endif
return -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any idea if SO_TYPE or SO_PROTOCOL are ever actually undefined on any platforms? If so, it'd be nice if we could make the exception raised as a result of this contain error message text indicating that the type and protocol must be supplied on the given platform.

@gpshead
Copy link
Member

gpshead commented Dec 22, 2017

is this going to go in?

@nascheme
Copy link
Member

I have no cycles to review it again but I will say I'd be happy if 3.7 had this functionality. When you try to write Python code that uses systemd inherited sockets, you need something like it.

@tiran
Copy link
Member Author

tiran commented Dec 24, 2017

The changes may break applications that are handling socket fds wrongly. I'm going to drop a mail on python-dev first.

@tiran tiran force-pushed the bpo-28134-socket-fd branch 2 times, most recently from 533c3e6 to 883e44a Compare December 24, 2017 19:01
@tiran tiran force-pushed the bpo-28134-socket-fd branch from 883e44a to e5ff880 Compare January 14, 2018 15:08
Fix socket(fileno=fd) by auto-detecting the socket's family, type,
and proto from the file descriptor. The auto-detection can be overruled
by passing in family, type, and proto explicitly.

Without the fix, all socket except for TCP/IP over IPv4 are basically broken:

>>> s = socket.create_connection(('www.python.org', 443))
>>> s
<socket.socket fd=3, family=AddressFamily.AF_INET6, type=SocketKind.SOCK_STREAM, proto=6, laddr=('2003:58:bc4a:3b00:56ee:75ff:fe47:ca7b', 59730, 0, 0), raddr=('2a04:4e42:1b::223', 443, 0, 0)>
>>> socket.socket(fileno=s.fileno())
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('2003:58:bc4a:3b00::%2550471192', 59730, 0, 2550471192), raddr=('2a04:4e42:1b:0:700c:e70b:ff7f:0%2550471192', 443, 0, 2550471192)>

Signed-off-by: Christian Heimes <christian@python.org>
@tiran tiran force-pushed the bpo-28134-socket-fd branch from e5ff880 to 28b925f Compare January 14, 2018 15:44
@tiran
Copy link
Member Author

tiran commented Jan 16, 2018

@gpshead @nascheme I like to land #5048 first, so I can remove some hacks for closing the socket fd on Windows.

@gpshead
Copy link
Member

gpshead commented Jan 29, 2018

3.7 deadline is at today... 2018-01-29 ~23:59 Anywhere on Earth (UTC-12:00). merge me maybe?

@tiran
Copy link
Member Author

tiran commented Jan 29, 2018

Yeah, I'm pressing the big green button now...

@tiran tiran merged commit b6e43af into python:master Jan 29, 2018
@bedevere-bot
Copy link

@tiran: Please replace # with GH- in the commit message next time. Thanks!

@1st1
Copy link
Member

1st1 commented Jan 29, 2018

You need to add versionchanged: 3.7 tag.

@1st1
Copy link
Member

1st1 commented Jan 29, 2018

What happens if SO_PROTOCOL isn't defined?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-feature A feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants