Skip to content

Conversation

@1st1
Copy link
Member

@1st1 1st1 commented Dec 15, 2017

Copy link
Contributor

Choose a reason for hiding this comment

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

Please describe what SOCK_TYPE_MASK is and hint on proper its usage.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not even sure we should expose it, since socket.type takes care of it with this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

To clarify: socket.type now applies it, so there's no real use case for SOCK_TYPE_MASK anymore.

Copy link
Contributor

@asvetlov asvetlov Dec 15, 2017

Choose a reason for hiding this comment

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

Yes, I see.
Ok with not exposing the mask, but if it is exposed -- doc should be updated.
Honestly I don't see how the mask can be useful -- at Python level socket type is always masked already.

Copy link
Contributor

@asvetlov asvetlov left a comment

Choose a reason for hiding this comment

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

Looks good but documentation for SOCK_TYPE_MASK need a little polishing.

@methane
Copy link
Member

methane commented Dec 15, 2017

+0.5 to not exposing SOCK_TYPE_MASK.
LGTM for code.

And I think we can backport it to Python 3.6.

@asvetlov
Copy link
Contributor

Yes, backport makes sense.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

This PR removes SOCK_CLOEXEC. How I am supposed to get this info? From socket.get_inheritable(sock)?

Same question for SOCK_NONBLOCK: use sock.get_blocking()?

This change is backward incompatible. It cannot go into 3.6.

If sock.sock_type is modified, SOCK_TYPE_MASK is useless.

I am not sure that we want to break the backward compatibility here.

This PR doesn't change the checks made on sock.type. it would be nice to include them to have an idea of how much code is impacted.

I am for example surprised that test_socket aren't updated.

@pitrou: I would like to see know your opinion here.

@bedevere-bot
Copy link

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

@pitrou
Copy link
Member

pitrou commented Dec 15, 2017

I agree with Victor:

  • it can't go into 3.6
  • making the change in 3.7 is contentious

Can there be an other way to solve the issue? Can we for example keep socket.type as it is and add a utility function or a property reporting the "masked" type?

@vstinner
Copy link
Member

Can we for example keep socket.type as it is and add a utility function or a property reporting the "masked" type?

Would it make sense to add a new read-only attribute, maybe sock.masked_type?

I would prefer to get it directly in socket objects, to not have to import an utility.

@1st1
Copy link
Member Author

1st1 commented Dec 15, 2017

Please let's bring this discussion to the issue on b.p.o.

@1st1
Copy link
Member Author

1st1 commented Dec 16, 2017

I've rewritten the PR from scratch. Please read the issue for the summary of updates.

@1st1
Copy link
Member Author

1st1 commented Dec 16, 2017

There's no docs update; let's focus on the implementation first.

@1st1
Copy link
Member Author

1st1 commented Dec 16, 2017

Another full update.

@njsmith
Copy link
Contributor

njsmith commented Dec 16, 2017

I think the fiddling with SOCK_NONBLOCK can also be removed from the accept function in Lib/socket.py (note: not socketmodule.c).

@njsmith
Copy link
Contributor

njsmith commented Dec 16, 2017

Also FYI you have test failures.

@1st1 1st1 force-pushed the fix_sock_type branch 2 times, most recently from 4b11ac4 to c1806d6 Compare December 16, 2017 05:46
@1st1
Copy link
Member Author

1st1 commented Dec 16, 2017

I think the fiddling with SOCK_NONBLOCK can also be removed from the accept function in Lib/socket.py (note: not socketmodule.c).

Yes. That will auto-close https://bugs.python.org/issue32318

Also FYI you have test failures.

Fixed.

.. versionchanged:: 3.7
On Linux: when :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC` bit
flags are applied to *type* they are cleared, and :attr:`socket.type`
will not reflect them.
Copy link
Member

Choose a reason for hiding this comment

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

This belongs with the socket.type attribute, not the constructors. It sounds like Python will prevent the caller from passing these flags to Linux, and makes you wonder if socketpair and fromfd are affected.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually they will be passed to Linux socket(), but won't be applied to Python sock.type attribute. I'll rephrase this.

0xF is SOCK_TYPE_MASK in include/linux/net.h which on Linux
is used to mask off SOCK_NONBLOCK and SOCK_CLOEXEC.
*/
s->sock_type = type & 0xF;
Copy link
Member

Choose a reason for hiding this comment

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

It's not possible to use SOCK_TYPE_MASK?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, Linux doesn't export it. It's a private macro in 'include/linux/net.h' that doesn't get exported in 'socket.h'.

Copy link
Member

Choose a reason for hiding this comment

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

If it's not exported, maybe it's not a good idea to use it. Can we mask SOCK_NONBLOCK and SOCK_CLOEXEC instead? type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)

Copy link
Member

Choose a reason for hiding this comment

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

Or maybe use getsockopt(SOL_SOCKET, SO_TYPE)? But this option would add a syscall.

Copy link
Member Author

Choose a reason for hiding this comment

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

So SOCK_TYPE_MASK isn't exported. I described why I think it's safe to just use 0xF in the code in the issue, quoting:

Since Linux doesn't export SOCK_TYPE_MASK I decided to hardcode it in socketmodule.c. My reasoning:

a/ It's highly unlikely that Linux will implement 5 more new socket types anytime soon, so 0xF should last for a very long time.

b/ It's more likely than "a/" that they add a new flag like SOCK_CLOEXEC, in which case the "type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)" approach will fail.

So given a/ and b/ I think it's safe to just use 0xF mask on Linux.

Copy link
Member Author

Choose a reason for hiding this comment

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

If it's not exported, maybe it's not a good idea to use it. Can we mask SOCK_NONBLOCK and SOCK_CLOEXEC instead? type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)

Alright, let's play it safe. All in all, if Linux adds another 'SOCK_SOMETHING' bit flag, we'll add it to our socket module, and then we can add it to the list of excluded flags.

Copy link
Member

Choose a reason for hiding this comment

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

At least, please don't hardcode a constant. Use something like "#define SOCK_TYPE_MASK 0xf". Maybe add a reference to bpo-32331.

In the module init, we may add the following assertion coming from the Linux kernel to make sure that SOCK_TYPE_MASK removes SOCK_CLOEXEC and SOCK_NONBLOCK flags:

    assert(!(SOCK_CLOEXEC & SOCK_TYPE_MASK));
    assert(!(SOCK_NONBLOCK & SOCK_TYPE_MASK));

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

@1st1
Copy link
Member Author

1st1 commented Dec 18, 2017

@vstinner I've pushed an update addressing your comments.

s->sock_fd = fd;
s->sock_family = family;

#ifdef __linux__
Copy link
Member

Choose a reason for hiding this comment

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

See the bpo. The bug is not specific to Linux, FreeBSD is also affected. Maybe also other OSes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

@vstinner
Copy link
Member

I don't know if the following change is the best option...

+#ifdef SOCK_NONBLOCK
+    s->sock_type = s->sock_type & ~SOCK_NONBLOCK;
+#endif
+#ifdef SOCK_CLOEXEC
+    s->sock_type = s->sock_type & ~SOCK_CLOEXEC;
+#endif

... but at least it works on FreeBSD to clear SOCK_NONBLOCK and SOCK_CLOEXEC in socket.socket constructor:

[haypo@freebsd ~/prog/python/master]$ ./python
Python 3.7.0a3+ (heads/master-dirty:6efcb6d3d5, Dec 18 2017, 23:44:31) 
[Clang 3.8.0 (tags/RELEASE_380/final 262564)] on freebsd11
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.socket(type=socket.SOCK_STREAM | socket.SOCK_NONBLOCK | socket.SOCK_CLOEXEC).type
<SocketKind.SOCK_STREAM: 1>

@1st1
Copy link
Member Author

1st1 commented Dec 18, 2017

I don't know if the following change is the best option...

It's better than hardcoding 0xF for sure. We now clear the flags explicitly and only flags that we know we can clear.

The CAN_ISOTP protocol was added.

.. versionchanged:: 3.7
Linux-specific: when :const:`SOCK_NONBLOCK` or :const:`SOCK_CLOEXEC`
Copy link
Member

Choose a reason for hiding this comment

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

Linux and FreeBSD and maybe other OSes specific? :-)


.. versionchanged:: 3.7
The method no longer applies :const:`SOCK_NONBLOCK` flag on
:attr:`socket.type` on Linux.
Copy link
Member

Choose a reason for hiding this comment

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

you may drop "on Linux".


.. versionchanged:: 3.7
The method no longer toggles :const:`SOCK_NONBLOCK` flag on
:attr:`socket.type` on Linux.
Copy link
Member

Choose a reason for hiding this comment

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

ditto (on linux)

* On Linux, the :attr:`socket.type <socket.socket.type>` attribute no
longer has :const:`socket.SOCK_NONBLOCK` or :const:`socket.SOCK_CLOEXEC`
flags applied, so checks like ``if sock.type == socket.SOCK_STREAM``
work as expected on all platforms.
Copy link
Member

Choose a reason for hiding this comment

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

You may suggest to use getblocking() to check if the socket is non-blocking.

"On Linux" doesn't include FreeBSD. Maybe just remove "On Linux".

@@ -0,0 +1,3 @@
Fix socket.settimeout() and socket.setblocking() to not change socket.type
on Linux. Fix socket.socket() constructor to reset any bit flags applied to
socket's type. This change only affects Linux.
Copy link
Member

Choose a reason for hiding this comment

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

and FreeBSD? (or remove the last sentence)

not portable.
0xF is SOCK_TYPE_MASK in include/linux/net.h which on Linux
is used to mask off SOCK_NONBLOCK and SOCK_CLOEXEC.
Copy link
Member

Choose a reason for hiding this comment

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

Outdated comment?

@1st1
Copy link
Member Author

1st1 commented Dec 19, 2017

@vstinner I've fixed docs/comments.

Lib/socket.py Outdated
C.startswith('SOCK_') and
# SOCK_NONBLOCK and SOCK_CLOEXEC are not socket types,
# they are Linux-specific bit flags.
C not in {'SOCK_NONBLOCK', 'SOCK_CLOEXEC'}))
Copy link
Member

Choose a reason for hiding this comment

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

With this change, we loose the nice repr:

socket.SOCK_CLOEXEC
<SocketKind.SOCK_CLOEXEC: 524288>
socket.SOCK_NONBLOCK
<SocketKind.SOCK_NONBLOCK: 2048>

Which problem are you solving with this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

They are not types of sockets. They are OS specific special flags.

If someone prints members of the SocketKind to lear what kinds of sockets exist, they will see SOCK_NONBLOCK on Linux and will likely be surprised.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe put them in a different enum in this case (SocketFlags?), but I would prefer to keep the nice repr, it eases debugging.

Copy link
Member Author

Choose a reason for hiding this comment

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

SocketFlags makes sense. I'll remove this change from this PR, we'll need a new one for it.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants