Bind sockets for IPv4 and IPv6
This commit is contained in:
		
							
								
								
									
										2
									
								
								config
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								config
									
									
									
									
									
								
							@@ -15,7 +15,7 @@
 | 
			
		||||
# IPv4 syntax: address:port
 | 
			
		||||
# IPv6 syntax: [address]:port
 | 
			
		||||
# For example: 0.0.0.0:9999, [::]:9999
 | 
			
		||||
#hosts = 127.0.0.1:5232
 | 
			
		||||
#hosts = localhost:5232
 | 
			
		||||
 | 
			
		||||
# Max parallel connections
 | 
			
		||||
#max_connections = 8
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ def _convert_to_bool(value):
 | 
			
		||||
DEFAULT_CONFIG_SCHEMA = OrderedDict([
 | 
			
		||||
    ("server", OrderedDict([
 | 
			
		||||
        ("hosts", {
 | 
			
		||||
            "value": "127.0.0.1:5232",
 | 
			
		||||
            "value": "localhost:5232",
 | 
			
		||||
            "help": "set server hostnames including ports",
 | 
			
		||||
            "aliases": ["-H", "--hosts"],
 | 
			
		||||
            "type": list_of_ip_address}),
 | 
			
		||||
 
 | 
			
		||||
@@ -117,26 +117,15 @@ class ParallelHTTPServer(ParallelizationMixIn,
 | 
			
		||||
            self.setup_environ()
 | 
			
		||||
            return
 | 
			
		||||
        try:
 | 
			
		||||
            if self.address_family == socket.AF_INET6:
 | 
			
		||||
                # Only allow IPv6 connections to the IPv6 socket
 | 
			
		||||
                self.socket.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 1)
 | 
			
		||||
            self.server_bind()
 | 
			
		||||
            self.server_activate()
 | 
			
		||||
        except BaseException:
 | 
			
		||||
            self.server_close()
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
    def server_bind(self):
 | 
			
		||||
        try:
 | 
			
		||||
            super().server_bind()
 | 
			
		||||
        except socket.gaierror as e:
 | 
			
		||||
            if (not HAS_IPV6 or self.address_family != socket.AF_INET or
 | 
			
		||||
                    e.errno not in (EAI_NONAME, EAI_ADDRFAMILY)):
 | 
			
		||||
                raise
 | 
			
		||||
            # Try again with IPv6
 | 
			
		||||
            self.address_family = socket.AF_INET6
 | 
			
		||||
            self.socket = socket.socket(self.address_family, self.socket_type)
 | 
			
		||||
            # Only allow IPv6 connections to the IPv6 socket
 | 
			
		||||
            self.socket.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 1)
 | 
			
		||||
            super().server_bind()
 | 
			
		||||
 | 
			
		||||
    def get_request(self):
 | 
			
		||||
        # Set timeout for client
 | 
			
		||||
        socket_, address = super().get_request()
 | 
			
		||||
@@ -291,18 +280,29 @@ def serve(configuration, shutdown_socket=None):
 | 
			
		||||
    application = Application(configuration)
 | 
			
		||||
    servers = {}
 | 
			
		||||
    for server_address_or_socket, family in server_addresses_or_sockets:
 | 
			
		||||
        try:
 | 
			
		||||
            server = server_class(configuration, family,
 | 
			
		||||
                                  server_address_or_socket, RequestHandler)
 | 
			
		||||
            server.set_app(application)
 | 
			
		||||
        except OSError as e:
 | 
			
		||||
            raise RuntimeError(
 | 
			
		||||
                "Failed to start server %r: %s" % (
 | 
			
		||||
                    server_address_or_socket, e)) from e
 | 
			
		||||
        servers[server.socket] = server
 | 
			
		||||
        logger.info("Listening to %r on port %d%s",
 | 
			
		||||
                    server.server_name, server.server_port, " using SSL"
 | 
			
		||||
                    if configuration.get("server", "ssl") else "")
 | 
			
		||||
        # If familiy is AF_INET, try to bind sockets for AF_INET and AF_INET6
 | 
			
		||||
        bind_successful = False
 | 
			
		||||
        for family in [family, socket.AF_INET6]:
 | 
			
		||||
            try:
 | 
			
		||||
                server = server_class(configuration, family,
 | 
			
		||||
                                      server_address_or_socket, RequestHandler)
 | 
			
		||||
                server.set_app(application)
 | 
			
		||||
            except OSError as e:
 | 
			
		||||
                if ((family == socket.AF_INET and HAS_IPV6 or
 | 
			
		||||
                        bind_successful) and isinstance(e, socket.gaierror) and
 | 
			
		||||
                        e.errno in (EAI_NONAME, EAI_ADDRFAMILY)):
 | 
			
		||||
                    # Allow one of AF_INET and AF_INET6 to fail, when
 | 
			
		||||
                    # the address or host don't support the address family.
 | 
			
		||||
                    continue
 | 
			
		||||
                raise RuntimeError(
 | 
			
		||||
                    "Failed to start server %r: %s" % (
 | 
			
		||||
                        server_address_or_socket, e)) from e
 | 
			
		||||
            bind_successful = True
 | 
			
		||||
            servers[server.socket] = server
 | 
			
		||||
            logger.info("Listening to %r on port %d%s (%s)",
 | 
			
		||||
                        server.server_name, server.server_port, " using SSL"
 | 
			
		||||
                        if configuration.get("server", "ssl") else "",
 | 
			
		||||
                        family.name)
 | 
			
		||||
 | 
			
		||||
    # Main loop: wait for requests on any of the servers or program shutdown
 | 
			
		||||
    sockets = list(servers.keys())
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user