Jelajahi Sumber

Bind sockets for IPv4 and IPv6

Unrud 6 tahun lalu
induk
melakukan
cc22927353
3 mengubah file dengan 28 tambahan dan 28 penghapusan
  1. 1 1
      config
  2. 1 1
      radicale/config.py
  3. 26 26
      radicale/server.py

+ 1 - 1
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

+ 1 - 1
radicale/config.py

@@ -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}),

+ 26 - 26
radicale/server.py

@@ -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:
-        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
     # Main loop: wait for requests on any of the servers or program shutdown
     sockets = list(servers.keys())
     sockets = list(servers.keys())