msg185348 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-27 16:48 |
Here's a function similar to socket.create_connection() which addresses all the repetitive tasks needed to order to create an IPv4/IPv6 agnostic server socket.
|
msg185362 - (view) |
Author: Charles-François Natali (neologix) *  |
Date: 2013-03-27 18:39 |
I think that's a good idea.
However, there's a problem with the implementation: if one passes "" or None as address on a dual-stack node, the resulting socket will be either IPv4 bound to INADDR_ANY, or IPv6 bound to IN6ADDR_ANY, whereas one would expect to be bound both in IPv4 and IPv6. In the later case, some platforms (like Linux) use IPv4-mapped addresses by default, some others (e.g. some versions of FreeBSD) don't. So, depending on IPV6_V6ONLY setting, binding to IPV6 any won't accept IPv4 connections. Also, some platforms don't support mapped addresses at all, so the only portable solution is to bind both to 0.0.0.0 and ::, whith two different sockets, and use select() to accept both.
So it would maybe make sense to expose a ServerSocket class, with an accept method which would do the right thing (as an added bonus, it could expose set_reuse_addr(bool), since SO_REUSEADDR have subtle semantic differences between Unix and Windows).
|
msg185369 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-27 19:50 |
What you say is right but whether the kernel supports an hybrid IPv4/6 stack or not there's not much we can do about it anyway.
Exactly what are you suggesting with the ServerSocket class you mentioned? What do you expect it to do?
Note that platforms supporting the dual-stack are already supported. This:
>>> socket.create_server_socket(("::", 0))
...on Linux will create a socket which is reachable both as "::1" and "127.0.0.1".
So if I'm not mistaken the alias for specifying "listen on all interfaces for both IPv4 and IPv6 addresses" would be "::" instead of "" / None.
We can document that.
|
msg185370 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-27 20:01 |
Side note: this is how in pyftpdlib I determine whether a platform supports the dual stack:
def support_hybrid_ip_v4_v6():
# Note: IPPROTO_IPV6 constant is broken on Windows, see:
# http://bugs.python.org/issue6926
sock = None
try:
if not socket.has_ipv6:
return False
sock = socket.socket(socket.AF_INET6)
return not sock.getsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY)
except (socket.error, AttributeError):
return False
finally:
if sock is not None:
sock.close()
|
msg185372 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2013-03-27 20:06 |
Tulip has something similar. Someone should compare the two and make sure they are equivalent or similar.
|
msg185374 - (view) |
Author: Charles-François Natali (neologix) *  |
Date: 2013-03-27 20:32 |
> What you say is right but whether the kernel supports an hybrid IPv4/6 stack
> or not there's not much we can do about it anyway.
> Exactly what are you suggesting with the ServerSocket class you mentioned?
> What do you expect it to do?
There's a confusion.
Dual-stack merely means that the host supports both IPv4 and IPv6 natively.
The IPV6_V6ONLY tunable is just a way to enable or not IPv4-mapped
addresses (i.e. ::ffff::<IPv4 address>) so that an IPv4 client can
connect to this socket. It can be set system-wide, or on a socket
basis.
> Note that platforms supporting the dual-stack are already supported. This:
>
>>>> socket.create_server_socket(("::", 0))
>
> ...on Linux will create a socket which is reachable both as "::1" and
> "127.0.0.1".
Try the same thing after:
# echo 1 > /proc/sys/net/ipv6/bindv6only
It won't accept IPv4 connections anymore.
And that's the default on many (most) platforms, e.g. FreeBSD and
OpenBSD (I think it's also true for Windows).
So the bottom line is that with the current code, on some - most -
platforms, we'll only accept IPv6 connections (and since you iterate
over getaddrinfo() in an unspecified order you may very well bind to
IPv4 only first, in which case you'll only accept IPv4 clients).
The proper way to procedd, on platforms which don't support unsetting
IPV6_V6ONLY, is to use two sockets, one in IPv4, and one IPv6, and use
select() to accept connections.
This would propably belong to an overriden accept() method in a
ServerSocket class, since it's far from trivial.
|
msg185443 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-28 12:53 |
Thanks for clarifying, I have a better understanding of the problem now.
Providing a custom class instantiating two sockets looks like a dead end to me though. To say one, what is getsockname() supposed to return? Same for detach(), fileno(), 'family' and probably others I can't think of right now.
|
msg185447 - (view) |
Author: Charles-François Natali (neologix) *  |
Date: 2013-03-28 13:32 |
> Providing a custom class instantiating two sockets looks like a dead end to me though. To say one, what is getsockname() supposed to return? Same for detach(), fileno(), 'family' and probably others I can't think of right now.
Indeed.
So we might opt for a best-effort approach: try disabling IPV6_V6ONLY
on the socket if it's set: that way it should work on most platforms.
And add a note to the documentation. IIRC that's what Java does.
|
msg185456 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-28 16:34 |
Agreed. Then it probably makes sense to expose also a socket.has_dual_stack() function so that the user can pre-emptively decide whether using a custom class.
Updated draft patch is in attachment.
|
msg185483 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-29 02:14 |
I managed to write a container class which listens on multiples addresses and uses select/poll on accept() as suggested by Charles.
FWICT it seems to work pretty well and supports non-blocking sockets and timeouts (tested on Linux, Windows and OSX).
It is available as a recipe here:
http://code.activestate.com/recipes/578504
IMO has_dual_stack() and create_server_sock() functions can already be included as-is (will adapt the recipe in order to get rid of Python 2.X support and submit another patch).
As for including also MultipleSocketsListener that's debatable.
It can either be added or linked/mentioned it in the doc.
|
msg185486 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2013-03-29 02:23 |
Perhaps you can contribute something like this to Tulip? We've got code to run a server that can handle IPv4 and IPv6, but we currently don't have something that just creates a separate socket for each address family. Our UDP and TCP paths are also quite different.
|
msg185487 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-29 02:51 |
Yep, no prob. It would also be a good chance to test it in a real-world app. Where should I look?
|
msg185489 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2013-03-29 03:51 |
Tulip is at code.google.com/p/tulip
On Thu, Mar 28, 2013 at 7:51 PM, Giampaolo Rodola'
<report@bugs.python.org>wrote:
>
> Giampaolo Rodola' added the comment:
>
> Yep, no prob. It would also be a good chance to test it in a real-world
> app. Where should I look?
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue17561>
> _______________________________________
>
|
msg185497 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-03-29 11:58 |
>> Where should I look?
> Tulip is at code.google.com/p/tulip
I meant in the code (and what needs to be done/refactored exactly).
|
msg185499 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2013-03-29 15:37 |
start_serving() in base_events.py.
On Fri, Mar 29, 2013 at 4:58 AM, Giampaolo Rodola'
<report@bugs.python.org>wrote:
>
> Giampaolo Rodola' added the comment:
>
> >> Where should I look?
> > Tulip is at code.google.com/p/tulip
>
> I meant in the code (and what needs to be done/refactored exactly).
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue17561>
> _______________________________________
>
|
msg185765 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-04-01 20:13 |
Being Tulip asynchronous I think that what it needs is an utility function which returns *multiple* sockets as are the addresses returned by getaddrinfo() and also possibly even disable the IPv4/6 dual stack in order to be consistent across all platforms.
After the sockets are returned they can be "registered" against the event loop as two separate entities such as, say, ("0.0.0.0", 8000) *and* ("::", 8000).
If you think this makes sense I can contribute something like this into Tulip, or I can bring it up on Tulip's ml and ask for other people's opinions.
My current recipe is different in that it provides a function which bind()s on one socket only and tries to enable the dual stack whenever possible in order to support IPv4 and IPv6 with a single socket.
In this it is similar to socket.create_connection() and clearly favors blocking socket usages (although it can also be used in non-blocking apps) which kind of represents the default for the stdlib.
|
msg185849 - (view) |
Author: Guido van Rossum (gvanrossum) *  |
Date: 2013-04-02 17:02 |
Nikolay, you may want to check out this Python tracker issue.
Giampaolo: I didn't even know it was possible for a single socket to be
dual-stack. (It would seem problematic for UDP recvfrom() for example.) In
Tulip it does indeed make more sense to create separate sockets and just
listen on all of them (using the same protocol factory). This can be
completely transparent to the code calling start_serving() and to the
protocol implementation. So if you're brave you can just send a code review
using codereview.appspot.com to the python-tulip list!
On Mon, Apr 1, 2013 at 1:13 PM, Giampaolo Rodola' <report@bugs.python.org>wrote:
>
> Giampaolo Rodola' added the comment:
>
> Being Tulip asynchronous I think that what it needs is an utility function
> which returns *multiple* sockets as are the addresses returned by
> getaddrinfo() and also possibly even disable the IPv4/6 dual stack in order
> to be consistent across all platforms.
>
> After the sockets are returned they can be "registered" against the event
> loop as two separate entities such as, say, ("0.0.0.0", 8000) *and* ("::",
> 8000).
> If you think this makes sense I can contribute something like this into
> Tulip, or I can bring it up on Tulip's ml and ask for other people's
> opinions.
>
> My current recipe is different in that it provides a function which
> bind()s on one socket only and tries to enable the dual stack whenever
> possible in order to support IPv4 and IPv6 with a single socket.
> In this it is similar to socket.create_connection() and clearly favors
> blocking socket usages (although it can also be used in non-blocking apps)
> which kind of represents the default for the stdlib.
>
> ----------
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <http://bugs.python.org/issue17561>
> _______________________________________
>
|
msg185919 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2013-04-03 12:46 |
Here's a patch for Tulip:
https://codereview.appspot.com/8307045
Will ping Tulip's ml as well.
|
msg327719 - (view) |
Author: Cheryl Sabella (cheryl.sabella) *  |
Date: 2018-10-14 18:49 |
Since Tulip/asyncio has gone through a lot of development since this issue was added, I wasn't sure if this has been included already or if there was still interest in it. In either case, I think it might be able to be closed, but I wanted to make sure first. Thanks!
|
msg331943 - (view) |
Author: Jason R. Coombs (jaraco) *  |
Date: 2018-12-17 01:42 |
I do believe this issue is still important and relevant. See issue25667 for a duplicate ticket (and references to implementations) and issue24209 for another issue where this could have been applied.
|
msg331944 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2018-12-17 02:47 |
Interesting. Yes, I agree this proposal is still desirable. We can reuse socket.create_server_sock() in smtpd, ftplib, socketserver (issue20215) and http.server (issue24209) modules which will inherit dual-stack IPv4/6 capabilities for free. I should be able to provide a PR sometime during this month.
|
msg335021 - (view) |
Author: Jason R. Coombs (jaraco) *  |
Date: 2019-02-07 13:32 |
In issue24209, I ended up settling on this implementation (https://github.com/python/cpython/blob/f289084c83190cc72db4a70c58f007ec62e75247/Lib/http/server.py#L1227-L1234), which seems to work well.
|
msg335036 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2019-02-07 19:24 |
After careful thinking I realize I'm not completely sure about how to expose the IPv4/6 functionality yet. I prefer to defer it for later and start landing a bind_socket() utility function which serves as a base for this functionality. See: issue17561.
|
msg335285 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2019-02-12 04:42 |
After iterating over this over the last few days I realized it makes more sense to implement and discuss the whole thing in here and as a single PR, so sorry about previously splitting this in a separate ticket/PR. Relevant PR is now this one and is ready for review:
https://github.com/python/cpython/pull/11784
Relevant changes which probably require attention/discussion are:
1) since it was sort of ambiguous I renamed "has_dual_stack()" to "supports_hybrid_ipv46()". There could be space for some bikeshed as we already have "socket.has_ipv6" so this may be "has_hybrid_ipv46()" called instead
2) if family is unspecified and determined from *host* (e.g. "localhost" or "") the function sorts getaddrinfo() results preferring AF_INET over AF_INET6
3) doc includes link to my http://code.activestate.com/recipes/578504 recipe for platforms not supporting hybrid_ipv46 natively
4) it may be worthwhile (or maybe not?) to have another complementary bind_sockets() (plural) function returning all items from getaddrinfo(). That would be useful for non-blocking apps/frameworks and could be reused by asyncio.
Also, I'm CC-ing people from issue20215 as it contains relevant comments.
|
msg339678 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2019-04-08 22:39 |
Patch committed as of:
https://github.com/python/cpython/commit/eb7e29f2a9d075accc1ab3faf3612ac44f5e2183
For posterity, since the API evolved since the original proposal (as per PR review/suggestions), this is the final incarnation:
# IPv4 only
>>> socket.create_server(addr)
# IPv6 only
>>> socket.create_server(addr, family=socket.AF_INET6)
# IPv4 + IPv6
>>> socket.create_server(addr, family=socket.AF_INET6, dualstack_ipv6=True)
# IPv4/6 if possible and don't care about IPv4 mapped addresses, else IPv4
>>> if socket.has_dualstack_ipv6():
... s = socket.create_server(addr, family=socket.AF_INET6, dualstack_ipv6=True)
... else:
... s = socket.create_server(addr)
|
msg339687 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2019-04-09 00:19 |
The change broke multiple buildbots. Example:
https://buildbot.python.org/all/#builders/16/builds/2625
Traceback (most recent call last):
File "/home/dje/cpython-buildarea/3.x.edelsohn-sles-z/build/Lib/test/_test_multiprocessing.py", line 4377, in test_wait_socket
self.assertEqual(b''.join(v), expected)
AssertionError: b'1\n2\n3\n4\n5\n6\n7\n8\n9\n' != b'0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n'
More logs:
https://github.com/python/cpython/pull/11784#issuecomment-481036369
|
msg339694 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2019-04-09 02:42 |
New changeset 8702b67dad62a9084f6c1823dce10653743667c8 by Giampaolo Rodola in branch 'master':
BPO-17561: set create_server backlog default to None (GH-12735)
https://github.com/python/cpython/commit/8702b67dad62a9084f6c1823dce10653743667c8
|
msg339723 - (view) |
Author: Giampaolo Rodola' (giampaolo.rodola) *  |
Date: 2019-04-09 10:34 |
Fixed. There's a remaining failing BB:
https://buildbot.python.org/all/#/builders/176/builds/185/steps/4/logs/stdio
...but the failure appears unrelated and it has been red for a while.
|
msg339794 - (view) |
Author: STINNER Victor (vstinner) *  |
Date: 2019-04-09 17:53 |
"""
Fixed. There's a remaining failing BB:
https://buildbot.python.org/all/#/builders/176/builds/185/steps/4/logs/stdio
...but the failure appears unrelated and it has been red for a while.
"""
That's known and unrelated issue: https://bugs.python.org/issue31453
|
|
Date |
User |
Action |
Args |
2022-04-11 14:57:43 | admin | set | github: 61761 |
2019-04-09 17:53:09 | vstinner | set | messages:
+ msg339794 |
2019-04-09 10:34:52 | giampaolo.rodola | set | status: open -> closed resolution: fixed messages:
+ msg339723
stage: patch review -> resolved |
2019-04-09 02:42:17 | giampaolo.rodola | set | messages:
+ msg339694 |
2019-04-09 01:38:02 | giampaolo.rodola | set | stage: resolved -> patch review pull_requests:
+ pull_request12658 |
2019-04-09 00:19:24 | vstinner | set | status: closed -> open
nosy:
+ vstinner messages:
+ msg339687
resolution: fixed -> (no value) |
2019-04-08 22:39:30 | giampaolo.rodola | set | messages:
+ msg339678 |
2019-04-08 22:35:18 | giampaolo.rodola | set | status: open -> closed resolution: fixed stage: commit review -> resolved |
2019-02-19 10:44:58 | giampaolo.rodola | link | issue29515 dependencies |
2019-02-17 19:02:34 | giampaolo.rodola | set | stage: patch review -> commit review |
2019-02-12 04:42:06 | giampaolo.rodola | set | nosy:
+ gregory.p.smith, nirs, r.david.murray, berker.peksag, martin.panter, jpokorny, jleedev, dazhaoyu, andreasr, Carlos.Ralli, Paul Marks title: Add socket.create_server_sock() convenience function -> Add socket.bind_socket() convenience function messages:
+ msg335285 pull_requests:
+ pull_request11856
keywords:
- easy |
2019-02-07 19:24:06 | giampaolo.rodola | set | messages:
+ msg335036 |
2019-02-07 13:32:51 | jaraco | set | messages:
+ msg335021 |
2018-12-18 20:43:22 | vstinner | set | nosy:
- vstinner
|
2018-12-18 19:53:53 | gvanrossum | set | nosy:
- gvanrossum
|
2018-12-18 19:35:20 | giampaolo.rodola | set | stage: patch review pull_requests:
+ pull_request10452 |
2018-12-17 02:47:20 | giampaolo.rodola | set | assignee: giampaolo.rodola messages:
+ msg331944 |
2018-12-17 01:42:28 | jaraco | set | nosy:
+ jaraco
messages:
+ msg331943 versions:
+ Python 3.8, - Python 3.4 |
2018-12-17 01:39:39 | jaraco | link | issue25667 superseder |
2018-10-14 18:49:27 | cheryl.sabella | set | nosy:
+ cheryl.sabella, asvetlov messages:
+ msg327719
|
2013-04-03 12:46:24 | giampaolo.rodola | set | messages:
+ msg185919 |
2013-04-03 01:55:14 | vstinner | set | nosy:
+ vstinner
|
2013-04-02 17:02:57 | gvanrossum | set | messages:
+ msg185849 |
2013-04-01 20:13:26 | giampaolo.rodola | set | messages:
+ msg185765 |
2013-03-29 15:37:17 | gvanrossum | set | messages:
+ msg185499 |
2013-03-29 11:58:56 | giampaolo.rodola | set | messages:
+ msg185497 |
2013-03-29 03:51:10 | gvanrossum | set | messages:
+ msg185489 |
2013-03-29 03:35:20 | giampaolo.rodola | set | nosy:
+ loewis, josiah.carlson
|
2013-03-29 02:51:52 | giampaolo.rodola | set | messages:
+ msg185487 |
2013-03-29 02:23:20 | gvanrossum | set | messages:
+ msg185486 |
2013-03-29 02:14:25 | giampaolo.rodola | set | messages:
+ msg185483 |
2013-03-28 16:34:40 | giampaolo.rodola | set | files:
+ socket2.patch
messages:
+ msg185456 |
2013-03-28 13:32:52 | neologix | set | messages:
+ msg185447 |
2013-03-28 12:53:18 | giampaolo.rodola | set | messages:
+ msg185443 |
2013-03-27 20:32:17 | neologix | set | messages:
+ msg185374 |
2013-03-27 20:06:06 | gvanrossum | set | messages:
+ msg185372 |
2013-03-27 20:01:09 | giampaolo.rodola | set | messages:
+ msg185370 |
2013-03-27 19:50:10 | giampaolo.rodola | set | messages:
+ msg185369 |
2013-03-27 18:39:41 | neologix | set | nosy:
+ neologix messages:
+ msg185362
|
2013-03-27 17:07:14 | pitrou | set | nosy:
+ gvanrossum
|
2013-03-27 16:48:29 | giampaolo.rodola | create | |