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

A value of 0 for socket_port should cause CP to bind to an available unused port #645

Closed
bb-migration opened this Issue Jan 16, 2007 · 6 comments

Comments

Projects
None yet
3 participants
@bb-migration

bb-migration commented Jan 16, 2007

Originally reported by: Anonymous


When socket_port is specified as 0, an exception is thrown as follows:

File
"/localhome/raghu/localwork/cherrypy/svn.cherrypy.org/trunk/cherrypy/_cpserver.py",
line 69, in quickstart
    self.start()
  File
"/localhome/raghu/localwork/cherrypy/svn.cherrypy.org/trunk/cherrypy/_cpserver.py",
line 95, in start
    self._start_http(httpserver)
  File
"/localhome/raghu/localwork/cherrypy/svn.cherrypy.org/trunk/cherrypy/_cpserver.py",
line 118, in _start_http
    self.wait(httpserver)
  File
"/localhome/raghu/localwork/cherrypy/svn.cherrypy.org/trunk/cherrypy/_cpserver.py",
line 159, in wait
    wait_for_occupied_port(*bind_addr)
  File
"/localhome/raghu/localwork/cherrypy/svn.cherrypy.org/trunk/cherrypy/_cpserver.py",
line 247, in wait_for_occupied_port
    raise IOError(msg)
IOError: Port 0 not bound on 'localhost'

I am using the latest code from the trunk. It appears to me that even though wsgiserver is properly passing 0 to socket.bind (and hence binding to an unused port), other parts of the code still use "configured" port which is 0.

Reported by draghuram@gmail.com


@bb-migration

This comment has been minimized.

Show comment
Hide comment
@bb-migration

bb-migration Jan 25, 2007

Original comment by Anonymous:


I am attaching a small patch that seems to work with port 0. My only intention in uploading the patch is to suggest it as a starting point. It will take more time for me to understand all its implications and suggest a more thorough solution.

The web server will update its bind_addr after doing socket.bind() so that correct port can be obtained. This port will obviously be different from the original port if the original port was 0. Unfortunately, the code that started the web server needs to wait for this setting before proceeding further. Right now, I just added time.sleep(5) as I don't know of a better solution.

bb-migration commented Jan 25, 2007

Original comment by Anonymous:


I am attaching a small patch that seems to work with port 0. My only intention in uploading the patch is to suggest it as a starting point. It will take more time for me to understand all its implications and suggest a more thorough solution.

The web server will update its bind_addr after doing socket.bind() so that correct port can be obtained. This port will obviously be different from the original port if the original port was 0. Unfortunately, the code that started the web server needs to wait for this setting before proceeding further. Right now, I just added time.sleep(5) as I don't know of a better solution.

@bb-migration

This comment has been minimized.

Show comment
Hide comment
@bb-migration

bb-migration Jan 26, 2007

Original comment by Robert Brewer (Bitbucket: fumanchu, GitHub: fumanchu):


That's a good start, but there's no API guarantee that a given httpserver will possess a "bind_addr" attribute. So we'd either need to add that to the API (which is fine, just needs to be decided) or use some other method of passing that information back up to the Server object.

If we ''did'' add a "bind_addr" requirement, that would mean we could stop using a dict for httpservers and use a list instead (and consumers could inspect [server.bind_addr for server in httpservers] if they cared). That might be the way to go.

bb-migration commented Jan 26, 2007

Original comment by Robert Brewer (Bitbucket: fumanchu, GitHub: fumanchu):


That's a good start, but there's no API guarantee that a given httpserver will possess a "bind_addr" attribute. So we'd either need to add that to the API (which is fine, just needs to be decided) or use some other method of passing that information back up to the Server object.

If we ''did'' add a "bind_addr" requirement, that would mean we could stop using a dict for httpservers and use a list instead (and consumers could inspect [server.bind_addr for server in httpservers] if they cared). That might be the way to go.

@bb-migration

This comment has been minimized.

Show comment
Hide comment
@bb-migration

bb-migration Jul 17, 2012

Original comment by Anonymous:


The solution proposed above needs some tiny tweaks for current versions of CherryPy

Change wsgiserver3.py HTTPServer.bind() to update self.bind_addr with the port used by calling self.socket.getsockname() and then in servers.py ServerAdapter.start() updating self.bind_addr after starting the thread.

It needs to be tested if socket.getsockname() works on all platforms. I've seen other comments saying it doesn't work on Windows but I can confirm that Windows 7 (64 bit) returns a tuple of host and port.

bb-migration commented Jul 17, 2012

Original comment by Anonymous:


The solution proposed above needs some tiny tweaks for current versions of CherryPy

Change wsgiserver3.py HTTPServer.bind() to update self.bind_addr with the port used by calling self.socket.getsockname() and then in servers.py ServerAdapter.start() updating self.bind_addr after starting the thread.

It needs to be tested if socket.getsockname() works on all platforms. I've seen other comments saying it doesn't work on Windows but I can confirm that Windows 7 (64 bit) returns a tuple of host and port.

@jaraco

This comment has been minimized.

Show comment
Hide comment
@jaraco

jaraco May 1, 2016

Member

I confirmed this issue still exists. Running this code:

import cherrypy

class Server:
    @classmethod
    def run(cls):
        config = {
            'global': {
                'server.socket_port': 0,
            }
        }
        cherrypy.quickstart(cls(), config=config)

if __name__ == '__main__':
    Server.run()

produces this output

[01/May/2016:15:31:00] ENGINE Listening for SIGHUP.
[01/May/2016:15:31:00] ENGINE Listening for SIGTERM.
[01/May/2016:15:31:00] ENGINE Listening for SIGUSR1.
[01/May/2016:15:31:00] ENGINE Bus STARTING
[01/May/2016:15:31:01] ENGINE Started monitor thread '_TimeoutMonitor'.
[01/May/2016:15:31:01] ENGINE Started monitor thread 'Autoreloader'.
[01/May/2016:15:31:51] ENGINE Error in 'start' listener <bound method Server.start of <cherrypy._cpserver.Server object at 0x101fd0828>>
Traceback (most recent call last):
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 203, in publish
    output.append(listener(*args, **kwargs))
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/_cpserver.py", line 168, in start
    ServerAdapter.start(self)
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 177, in start
    self.wait()
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 232, in wait
    wait_for_occupied_port(host, port)
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 458, in wait_for_occupied_port
    raise IOError("Port %r not bound on %r" % (port, host))
OSError: Port 0 not bound on '127.0.0.1'

[01/May/2016:15:31:51] ENGINE Shutting down due to error in start listener:
Traceback (most recent call last):
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 241, in start
    self.publish('start')
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 221, in publish
    raise exc
cherrypy.process.wspbus.ChannelFailures: OSError("Port 0 not bound on '127.0.0.1'",)

[01/May/2016:15:31:51] ENGINE Bus STOPPING
[01/May/2016:15:31:51] ENGINE HTTP Server cherrypy._cpwsgi_server.CPWSGIServer(('127.0.0.1', 0)) already shut down
[01/May/2016:15:31:51] ENGINE Stopped thread 'Autoreloader'.
[01/May/2016:15:31:51] ENGINE Stopped thread '_TimeoutMonitor'.
[01/May/2016:15:31:51] ENGINE Bus STOPPED
[01/May/2016:15:31:51] ENGINE Bus EXITING
[01/May/2016:15:31:51] ENGINE Bus EXITED

Note the 50 second timeout.

Member

jaraco commented May 1, 2016

I confirmed this issue still exists. Running this code:

import cherrypy

class Server:
    @classmethod
    def run(cls):
        config = {
            'global': {
                'server.socket_port': 0,
            }
        }
        cherrypy.quickstart(cls(), config=config)

if __name__ == '__main__':
    Server.run()

produces this output

[01/May/2016:15:31:00] ENGINE Listening for SIGHUP.
[01/May/2016:15:31:00] ENGINE Listening for SIGTERM.
[01/May/2016:15:31:00] ENGINE Listening for SIGUSR1.
[01/May/2016:15:31:00] ENGINE Bus STARTING
[01/May/2016:15:31:01] ENGINE Started monitor thread '_TimeoutMonitor'.
[01/May/2016:15:31:01] ENGINE Started monitor thread 'Autoreloader'.
[01/May/2016:15:31:51] ENGINE Error in 'start' listener <bound method Server.start of <cherrypy._cpserver.Server object at 0x101fd0828>>
Traceback (most recent call last):
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 203, in publish
    output.append(listener(*args, **kwargs))
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/_cpserver.py", line 168, in start
    ServerAdapter.start(self)
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 177, in start
    self.wait()
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 232, in wait
    wait_for_occupied_port(host, port)
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/servers.py", line 458, in wait_for_occupied_port
    raise IOError("Port %r not bound on %r" % (port, host))
OSError: Port 0 not bound on '127.0.0.1'

[01/May/2016:15:31:51] ENGINE Shutting down due to error in start listener:
Traceback (most recent call last):
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 241, in start
    self.publish('start')
  File "/Users/jaraco/Dropbox/code/public/cherrypy/cherrypy/process/wspbus.py", line 221, in publish
    raise exc
cherrypy.process.wspbus.ChannelFailures: OSError("Port 0 not bound on '127.0.0.1'",)

[01/May/2016:15:31:51] ENGINE Bus STOPPING
[01/May/2016:15:31:51] ENGINE HTTP Server cherrypy._cpwsgi_server.CPWSGIServer(('127.0.0.1', 0)) already shut down
[01/May/2016:15:31:51] ENGINE Stopped thread 'Autoreloader'.
[01/May/2016:15:31:51] ENGINE Stopped thread '_TimeoutMonitor'.
[01/May/2016:15:31:51] ENGINE Bus STOPPED
[01/May/2016:15:31:51] ENGINE Bus EXITING
[01/May/2016:15:31:51] ENGINE Bus EXITED

Note the 50 second timeout.

@webknjaz webknjaz self-assigned this Sep 26, 2016

@webknjaz

This comment has been minimized.

Show comment
Hide comment
@webknjaz

webknjaz Sep 26, 2016

Member

I think, I'll take a look at this issue.

Member

webknjaz commented Sep 26, 2016

I think, I'll take a look at this issue.

@jaraco jaraco changed the title from A value of 0 for socket_port should cause CP to bind to an avaibale unused port to A value of 0 for socket_port should cause CP to bind to an available unused port Dec 29, 2016

@jaraco jaraco closed this in c52bb19 Dec 29, 2016

@jaraco jaraco reopened this Dec 29, 2016

@jaraco

This comment has been minimized.

Show comment
Hide comment
@jaraco

jaraco Dec 29, 2016

Member

I hadn't meant to push that commit to master. I've moved it to the feature/bind-ephemeral branch.

Member

jaraco commented Dec 29, 2016

I hadn't meant to push that commit to master. I've moved it to the feature/bind-ephemeral branch.

jaraco added a commit that referenced this issue Dec 31, 2016

@jaraco jaraco closed this in e012843 Dec 31, 2016

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