Source

CherryPy / cherrypy / process / servers.py

Diff from to

File cherrypy/process/servers.py

 
     #!/usr/bin/python
     import cherrypy
-    
+
     class HelloWorld:
         \"""Sample request handler class.\"""
         def index(self):
             return "Hello world!"
         index.exposed = True
-    
+
     cherrypy.tree.mount(HelloWorld())
     # CherryPy autoreload must be disabled for the flup server to work
     cherrypy.config.update({'engine.autoreload_on':False})
     } # end of $HTTP["url"] =~ "^/"
 
 Please see `Lighttpd FastCGI Docs
-<http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModFastCGI>`_ for an explanation 
+<http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModFastCGI>`_ for an explanation
 of the possible configuration options.
 """
 
 import sys
 import time
+import warnings
 
 
 class ServerAdapter(object):
     """Adapter for an HTTP server.
-    
+
     If you need to start more than one HTTP server (to serve on multiple
     ports, or protocols, etc.), you can manually register each one and then
     start them all with bus.start:
-    
+
         s1 = ServerAdapter(bus, MyWSGIServer(host='0.0.0.0', port=80))
         s2 = ServerAdapter(bus, another.HTTPServer(host='127.0.0.1', SSL=True))
         s1.subscribe()
         s2.subscribe()
         bus.start()
     """
-    
+
     def __init__(self, bus, httpserver=None, bind_addr=None):
         self.bus = bus
         self.httpserver = httpserver
         self.bind_addr = bind_addr
         self.interrupt = None
         self.running = False
-    
+
     def subscribe(self):
         self.bus.subscribe('start', self.start)
         self.bus.subscribe('stop', self.stop)
-    
+
     def unsubscribe(self):
         self.bus.unsubscribe('start', self.start)
         self.bus.unsubscribe('stop', self.stop)
-    
+
     def start(self):
         """Start the HTTP server."""
         if self.bind_addr is None:
             on_what = "%s:%s" % (host, port)
         else:
             on_what = "socket file: %s" % self.bind_addr
-        
+
         if self.running:
             self.bus.log("Already serving on %s" % on_what)
             return
-        
+
         self.interrupt = None
         if not self.httpserver:
             raise ValueError("No HTTP server has been created.")
-        
+
         # Start the httpserver in a new thread.
         if isinstance(self.bind_addr, tuple):
             wait_for_free_port(*self.bind_addr)
-        
+
         import threading
         t = threading.Thread(target=self._start_http_thread)
         t.setName("HTTPServer " + t.getName())
         t.start()
-        
+
         self.wait()
         self.running = True
         self.bus.log("Serving on %s" % on_what)
     start.priority = 75
-    
+
     def _start_http_thread(self):
         """HTTP servers MUST be running in new threads, so that the
         main thread persists to receive KeyboardInterrupt's. If an
                          traceback=True, level=40)
             self.bus.exit()
             raise
-    
+
     def wait(self):
         """Wait until the HTTP server is ready to receive requests."""
         while not getattr(self.httpserver, "ready", False):
             if self.interrupt:
                 raise self.interrupt
             time.sleep(.1)
-        
+
         # Wait for port to be occupied
         if isinstance(self.bind_addr, tuple):
             host, port = self.bind_addr
             wait_for_occupied_port(host, port)
-    
+
     def stop(self):
         """Stop the HTTP server."""
         if self.running:
         else:
             self.bus.log("HTTP Server %s already shut down" % self.httpserver)
     stop.priority = 25
-    
+
     def restart(self):
         """Restart the HTTP server."""
         self.stop()
 
 class FlupCGIServer(object):
     """Adapter for a flup.server.cgi.WSGIServer."""
-   
+
     def __init__(self, *args, **kwargs):
         self.args = args
         self.kwargs = kwargs
         self.ready = False
-    
+
     def start(self):
         """Start the CGI server."""
         # We have to instantiate the server class here because its __init__
         # starts a threadpool. If we do it too early, daemonize won't work.
         from flup.server.cgi import WSGIServer
-       
+
         self.cgiserver = WSGIServer(*self.args, **self.kwargs)
         self.ready = True
         self.cgiserver.run()
-    
+
     def stop(self):
         """Stop the HTTP server."""
         self.ready = False
 
 class FlupFCGIServer(object):
     """Adapter for a flup.server.fcgi.WSGIServer."""
-    
+
     def __init__(self, *args, **kwargs):
         if kwargs.get('bindAddress', None) is None:
             import socket
         self.args = args
         self.kwargs = kwargs
         self.ready = False
-    
+
     def start(self):
         """Start the FCGI server."""
         # We have to instantiate the server class here because its __init__
         self.fcgiserver._oldSIGs = []
         self.ready = True
         self.fcgiserver.run()
-    
+
     def stop(self):
         """Stop the HTTP server."""
         # Forcibly stop the fcgi server main event loop.
 
 class FlupSCGIServer(object):
     """Adapter for a flup.server.scgi.WSGIServer."""
-    
+
     def __init__(self, *args, **kwargs):
         self.args = args
         self.kwargs = kwargs
         self.ready = False
-    
+
     def start(self):
         """Start the SCGI server."""
         # We have to instantiate the server class here because its __init__
         self.scgiserver._oldSIGs = []
         self.ready = True
         self.scgiserver.run()
-    
+
     def stop(self):
         """Stop the HTTP server."""
         self.ready = False
         raise ValueError("Host values of '' or None are not allowed.")
     host = client_host(host)
     port = int(port)
-    
+
     import socket
-    
+
     # AF_INET or AF_INET6 socket
     # Get the correct address family for our host (allows IPv6 addresses)
     try:
             info = [(socket.AF_INET6, socket.SOCK_STREAM, 0, "", (host, port, 0, 0))]
         else:
             info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", (host, port))]
-    
+
     for res in info:
         af, socktype, proto, canonname, sa = res
         s = None
         raise ValueError("Host values of '' or None are not allowed.")
     if timeout is None:
         timeout = free_port_timeout
-    
+
     for trial in range(50):
         try:
             # we are expecting a free port, so reduce the timeout
             time.sleep(timeout)
         else:
             return
-    
+
     raise IOError("Port %r not free on %r" % (port, host))
 
 def wait_for_occupied_port(host, port, timeout=None):
         raise ValueError("Host values of '' or None are not allowed.")
     if timeout is None:
         timeout = occupied_port_timeout
-    
+
     for trial in range(50):
         try:
             check_port(host, port, timeout=timeout)
         except IOError:
+            # port is occupied
             return
         else:
             time.sleep(timeout)
-    
-    raise IOError("Port %r not bound on %r" % (port, host))
+
+    if host == client_host(host):
+        raise IOError("Port %r not bound on %r" % (port, host))
+
+    # On systems where a loopback interface is not available and the
+    #  server is bound to all interfaces, it's difficult to determine
+    #  whether the server is in fact occupying the port. In this case,
+    #  just issue a warning and move on. See issue #1100.
+    msg = "Unable to verify that the server is bound on %r" % port
+    warnings.warn(msg)