bind to IPv6 only?

631 views
Skip to first unread message

young-kyun Kim

unread,
Mar 23, 2016, 4:28:27 AM3/23/16
to cherrypy-users
bind to IPv6 only

Hi!

I try to bind to IPv6 only.
But my server failed with ChannelFailures error.

------------------------------------------
Windows 8.1 Enterprise 64bit
Python 2.7.11 32bit
CherryPy 5.1.0
------------------------------------------
server_config = {
    "engine.autoreload.on": False,
    "server.socket_host": "::",
    "server.socket_port": 7070
}

cherrypy.config.update(server_config)
------------------------------------------

My server works well with "0.0.0.0"(IPv4 Only) or "::"(IPv4 + IPv6).

But My server don't work with "[::]", "0:0:0:0:0:0:0:0", "[0:0:0:0:0:0:0:0]"(IPv6 Only?).
7070 port don't used by any other process. (checked by tcpview)

Below is the error message of cherry.
Before below error message is displayed, my server does response to my request.
-------------------------------------------------------------------------------------------
[23/Mar/2016:14:58:13] ENGINE Error in 'start' listener <bound method Server.start of <cherrypy._cpserver.Server object at 0x02F2CA90>>
Traceback (most recent call last):
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\wspbus.py", line 203, in publish
    output.append(listener(*args, **kwargs))
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\_cpserver.py", line 168, in start
    ServerAdapter.start(self)
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\servers.py", line 177, in start
    self.wait()
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\servers.py", line 232, in wait
    wait_for_occupied_port(host, port)
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\servers.py", line 458, in wait_for_occupied_port
    raise IOError("Port %r not bound on %r" % (port, host))
IOError: Port 7070 not bound on '[::]'

[23/Mar/2016:14:58:13] ENGINE Shutting down due to error in start listener:
Traceback (most recent call last):
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\wspbus.py", line 241, in start
    self.publish('start')
  File "C:\devtool\py27x86\lib\site-packages\cherrypy\process\wspbus.py", line 221, in publish
    raise exc
ChannelFailures: IOError("Port 7070 not bound on '[::]'",)
-------------------------------------------------------------------------------------------

How can I bind to IPv6 only?

young-kyun Kim

unread,
Mar 29, 2016, 3:30:13 AM3/29/16
to cherrypy-users
I do more trace this issue.

When server.socket_host is "::" on Win 8.1, my server listen from IPv4, IPv6
My server can be connected from IPv4, IPv6.
Protocol    Local Address               Remote Address          State
TCP        
0.0.0.0:7070                0.0.0.0:0               LISTENING
TCPV6      
[0:0:0:0:0:0:0:0]:7070      [0:0:0:0:0:0:0:0]:0     LISTENING

When server.socket_host is "0:0:0:0:0:0:0:0" on Win 8.1, my server listen from IPv6
But, IOError occurred after about 50 seconds.
My server can be connected from IPv6 only in about 50 seconds.
Protocol    Local Address               Remote Address          State
TCPV6      
[0:0:0:0:0:0:0:0]:7070      [0:0:0:0:0:0:0:0]:0     LISTENING

When server.socket_host is "::" on CentOS 7, my server listen from IPv6 only.
However my server can be connected from IPv4, IPv6.
[root@localhost cqprefserver]# netstat -apn | grep 7070
tcp6      
0      0 :::7070                 :::*                    LISTEN      5695/python  

When server.socket_host is "0:0:0:0:0:0:0:0" on CentOS 7, my server listen from IPv6 only.
However my server can be connected from IPv4, IPv6 and IOError don't occurred.
[root@localhost cqprefserver]# netstat -apn | grep 7070
tcp6      
0      0 :::7070                 :::*                    LISTEN      29574/python

To works well, check_port() in wait_for_occupied_port() must raise IOError.
To check, I write the small test script refer to check_port() function in \Lib\site-packages\cherrypy\process\servers.py
import socket

#host = "::"
host
= "0:0:0:0:0:0:0:0"
#host = "0.0.0.0"
port
= 7070
timeout
= 1.0

info
= socket.getaddrinfo(host, port, socket.AF_UNSPEC,
                          socket
.SOCK_STREAM)

print info

af
, socktype, proto, canonname, sa = info[0]

s
= socket.socket(af, socktype, proto)
s
.settimeout(timeout)
s
.connect((host, port))
s
.close()

Above script works well on CentOS 7, python 2.7.5.
But error occurred on Win 8.1, python 2.7.11.
D:\test>testport.py
[(23, 1, 0, '', ('::', 7070, 0, 0))]

Traceback (most recent call last):

 
File "D:\test\testport.py", line 18, in <module>
    s
.connect((host, port))
 
File "C:\devtool\py27x86\lib\socket.py", line 228, in meth
   
return getattr(self._sock,name)(*args)
socket
.error: [Errno 10049]

IOError occurred by this error on Win 8.1
I modify the client_host() function in \Lib\site-packages\cherrypy\process\servers.py
def client_host(server_host):
   
"""Return the host on which a client can connect to the given listener."""
   
if server_host == '0.0.0.0':
       
# 0.0.0.0 is INADDR_ANY, which should answer on localhost.
       
return '127.0.0.1'
   
if server_host in ('::', '::0', '::0.0.0.0', '0:0:0:0:0:0:0:0'): # add '0:0:0:0:0:0:0:0'
       
# :: is IN6ADDR_ANY, which should answer on localhost.
       
# ::0 and ::0.0.0.0 are non-canonical but common
       
# ways to write IN6ADDR_ANY.
       
return '::1'
   
return server_host

My server works well on Win 8.1
[29/Mar/2016:15:11:03] ENGINE Bus STARTING
[29/Mar/2016:15:11:03] ENGINE Started monitor thread '_TimeoutMonitor'.
[29/Mar/2016:15:11:03] ENGINE Started monitor thread 'Autoreloader'.
[29/Mar/2016:15:11:03] ENGINE Serving on http://0:0:0:0:0:0:0:0:7070
[29/Mar/2016:15:11:03] ENGINE Bus STARTED

However, it seemed impossible to listen from IPv6 only on CentOS 7.

2016년 3월 23일 수요일 오후 5시 28분 27초 UTC+9, young-kyun Kim 님의 말:

Tim Roberts

unread,
Mar 29, 2016, 12:50:26 PM3/29/16
to cherryp...@googlegroups.com
young-kyun Kim wrote:
I do more trace this issue.

First, allow me to congratulate you on the thoroughness of your analysis, and the detail in your description.  I'm not sure we will come up with the answer, but you have certainly given us good information.



To works well, check_port() in wait_for_occupied_port() must raise IOError.
To check, I write the small test script refer to check_port() function in \Lib\site-packages\cherrypy\process\servers.py
import socket

#host = "::"
host
= "0:0:0:0:0:0:0:0"
#host = "0.0.0.0"
port
= 7070
timeout
= 1.0

info
= socket.getaddrinfo(host, port, socket.AF_UNSPEC,
                          socket
.SOCK_STREAM)

print info

af
, socktype, proto, canonname, sa = info[0]

s
= socket.socket(af, socktype, proto)
s
.settimeout(timeout)
s
.connect((host, port))
s
.close()

Above script works well on CentOS 7, python 2.7.5.

How can it possibly work well?  You can bind a TCP server to INADDR_ANY so it listens on all available interfaces, but when you connect as a client, you have to provide a specific IP address.  You are not providing a valid host address.



But error occurred on Win 8.1, python 2.7.11.
D:\test>testport.py
[(23, 1, 0, '', ('::', 7070, 0, 0))]
Traceback (most recent call last):
 
File "D:\test\testport.py", line 18, in <module>
    s
.connect((host, port))
 
File "C:\devtool\py27x86\lib\socket.py", line 228, in meth
   
return getattr(self._sock,name)(*args)
socket
.error: [Errno 10049]


That's what I would expect.  For what it's worth, 10049 is WSAEADDRNOTAVAIL.  I suspect it would work if you specified ::1 as the address.
-- 
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

young-kyun Kim

unread,
Mar 30, 2016, 3:58:07 AM3/30/16
to cherrypy-users
To works well, check_port() in wait_for_occupied_port() must raise IOError.
To check, I write the small test script refer to check_port() function in \Lib\site-packages\cherrypy\process\servers.py
import socket

#host = "::"
host
= "0:0:0:0:0:0:0:0"
#host = "0.0.0.0"
port
= 7070
timeout
= 1.0

info
= socket.getaddrinfo(host, port, socket.AF_UNSPEC,
                          socket
.SOCK_STREAM)

print info

af
, socktype, proto, canonname, sa = info[0]

s
= socket.socket(af, socktype, proto)
s
.settimeout(timeout)
s
.connect((host, port))
s
.close()

Above script works well on CentOS 7, python 2.7.5.

How can it possibly work well?  You can bind a TCP server to INADDR_ANY so it listens on all available interfaces, but when you connect as a client, you have to provide a specific IP address.  You are not providing a valid host address.
Also, I agree with your opinon .
But, I did test many times and the result is same.
My test script don't raise any exception on my CentOS 7 test machine.

2016년 3월 30일 수요일 오전 1시 50분 26초 UTC+9, Tim Roberts 님의 말:

Tim Roberts

unread,
Mar 30, 2016, 1:35:11 PM3/30/16
to cherryp...@googlegroups.com
young-kyun Kim wrote:

How can it possibly work well?  You can bind a TCP server to INADDR_ANY so it listens on all available interfaces, but when you connect as a client, you have to provide a specific IP address.  You are not providing a valid host address.
Also, I agree with your opinon .
But, I did test many times and the result is same.
My test script don't raise any exception on my CentOS 7 test machine.

I understand, but that does not mean that it is correct.  There are many things that violate the contracts but happen to work.  C and C++ programmers know this very well.

You were asking why it didn't work on Windows.  It doesn't work on Windows because the code is wrong.  The fact that it works on CentOS is an accident.
Reply all
Reply to author
Forward
0 new messages