Bind sockets for IPv4 and IPv6
This commit is contained in:
		
							
								
								
									
										2
									
								
								config
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								config
									
									
									
									
									
								
							@@ -15,7 +15,7 @@
 | 
				
			|||||||
# IPv4 syntax: address:port
 | 
					# IPv4 syntax: address:port
 | 
				
			||||||
# IPv6 syntax: [address]:port
 | 
					# IPv6 syntax: [address]:port
 | 
				
			||||||
# For example: 0.0.0.0:9999, [::]:9999
 | 
					# For example: 0.0.0.0:9999, [::]:9999
 | 
				
			||||||
#hosts = 127.0.0.1:5232
 | 
					#hosts = localhost:5232
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Max parallel connections
 | 
					# Max parallel connections
 | 
				
			||||||
#max_connections = 8
 | 
					#max_connections = 8
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,7 @@ def _convert_to_bool(value):
 | 
				
			|||||||
DEFAULT_CONFIG_SCHEMA = OrderedDict([
 | 
					DEFAULT_CONFIG_SCHEMA = OrderedDict([
 | 
				
			||||||
    ("server", OrderedDict([
 | 
					    ("server", OrderedDict([
 | 
				
			||||||
        ("hosts", {
 | 
					        ("hosts", {
 | 
				
			||||||
            "value": "127.0.0.1:5232",
 | 
					            "value": "localhost:5232",
 | 
				
			||||||
            "help": "set server hostnames including ports",
 | 
					            "help": "set server hostnames including ports",
 | 
				
			||||||
            "aliases": ["-H", "--hosts"],
 | 
					            "aliases": ["-H", "--hosts"],
 | 
				
			||||||
            "type": list_of_ip_address}),
 | 
					            "type": list_of_ip_address}),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,26 +117,15 @@ class ParallelHTTPServer(ParallelizationMixIn,
 | 
				
			|||||||
            self.setup_environ()
 | 
					            self.setup_environ()
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        try:
 | 
					        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_bind()
 | 
				
			||||||
            self.server_activate()
 | 
					            self.server_activate()
 | 
				
			||||||
        except BaseException:
 | 
					        except BaseException:
 | 
				
			||||||
            self.server_close()
 | 
					            self.server_close()
 | 
				
			||||||
            raise
 | 
					            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):
 | 
					    def get_request(self):
 | 
				
			||||||
        # Set timeout for client
 | 
					        # Set timeout for client
 | 
				
			||||||
        socket_, address = super().get_request()
 | 
					        socket_, address = super().get_request()
 | 
				
			||||||
@@ -291,18 +280,29 @@ def serve(configuration, shutdown_socket=None):
 | 
				
			|||||||
    application = Application(configuration)
 | 
					    application = Application(configuration)
 | 
				
			||||||
    servers = {}
 | 
					    servers = {}
 | 
				
			||||||
    for server_address_or_socket, family in server_addresses_or_sockets:
 | 
					    for server_address_or_socket, family in server_addresses_or_sockets:
 | 
				
			||||||
 | 
					        # 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:
 | 
					            try:
 | 
				
			||||||
                server = server_class(configuration, family,
 | 
					                server = server_class(configuration, family,
 | 
				
			||||||
                                      server_address_or_socket, RequestHandler)
 | 
					                                      server_address_or_socket, RequestHandler)
 | 
				
			||||||
                server.set_app(application)
 | 
					                server.set_app(application)
 | 
				
			||||||
            except OSError as e:
 | 
					            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(
 | 
					                raise RuntimeError(
 | 
				
			||||||
                    "Failed to start server %r: %s" % (
 | 
					                    "Failed to start server %r: %s" % (
 | 
				
			||||||
                        server_address_or_socket, e)) from e
 | 
					                        server_address_or_socket, e)) from e
 | 
				
			||||||
 | 
					            bind_successful = True
 | 
				
			||||||
            servers[server.socket] = server
 | 
					            servers[server.socket] = server
 | 
				
			||||||
        logger.info("Listening to %r on port %d%s",
 | 
					            logger.info("Listening to %r on port %d%s (%s)",
 | 
				
			||||||
                        server.server_name, server.server_port, " using SSL"
 | 
					                        server.server_name, server.server_port, " using SSL"
 | 
				
			||||||
                    if configuration.get("server", "ssl") else "")
 | 
					                        if configuration.get("server", "ssl") else "",
 | 
				
			||||||
 | 
					                        family.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Main loop: wait for requests on any of the servers or program shutdown
 | 
					    # Main loop: wait for requests on any of the servers or program shutdown
 | 
				
			||||||
    sockets = list(servers.keys())
 | 
					    sockets = list(servers.keys())
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user