diff --git a/radicale/__main__.py b/radicale/__main__.py index 209348f13..dcf8cb67c 100644 --- a/radicale/__main__.py +++ b/radicale/__main__.py @@ -198,7 +198,7 @@ def shutdown_signal_handler(signal_number: int, server.serve(configuration, shutdown_socket_out) except Exception as e: logger.critical("An exception occurred during server startup: %s", e, - exc_info=True) + exc_info=False) sys.exit(1) diff --git a/radicale/server.py b/radicale/server.py index 23381315d..30946a2a7 100644 --- a/radicale/server.py +++ b/radicale/server.py @@ -3,6 +3,7 @@ # Copyright © 2008 Pascal Halter # Copyright © 2008-2017 Guillaume Ayoub # Copyright © 2017-2019 Unrud +# Copyright © 2024-2024 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,7 +23,6 @@ """ -import errno import http import select import socket @@ -283,45 +283,22 @@ def serve(configuration: config.Configuration, servers = {} try: hosts: List[Tuple[str, int]] = configuration.get("server", "hosts") - for address in hosts: - # Try to bind sockets for IPv4 and IPv6 - possible_families = (socket.AF_INET, socket.AF_INET6) - bind_ok = False - for i, family in enumerate(possible_families): - is_last = i == len(possible_families) - 1 + for AddressPort in hosts: + # retrieve IPv4/IPv6 address of address + try: + getaddrinfo = socket.getaddrinfo(AddressPort[0], AddressPort[1], 0, socket.SOCK_STREAM, socket.IPPROTO_TCP) + except OSError as e: + logger.warn("cannot retrieve IPv4 or IPv6 address of '%s': %s" % (format_address(AddressPort), e)) + continue + logger.debug("getaddrinfo of '%s': %s" % (format_address(AddressPort), getaddrinfo)) + for (AddressFamily, SocketKind, SocketProto, SocketFlags, SocketAddress) in getaddrinfo: + logger.debug("try to create server socket on '%s'" % (format_address(SocketAddress))) try: - server = server_class(configuration, family, address, - RequestHandler) + server = server_class(configuration, AddressFamily, (SocketAddress[0], SocketAddress[1]), RequestHandler) except OSError as e: - # Ignore unsupported families (only one must work) - if ((bind_ok or not is_last) and ( - isinstance(e, socket.gaierror) and ( - # Hostname does not exist or doesn't have - # address for address family - # Linux: temporary failure in name resolution (-3) - e.errno == socket.EAI_AGAIN or - # macOS: IPv6 address for INET address family - e.errno == socket.EAI_NONAME or - # Address not for address family - e.errno == COMPAT_EAI_ADDRFAMILY or - e.errno == COMPAT_EAI_NODATA) or - # Workaround for PyPy - str(e) == "address family mismatched" or - # Address family not available (e.g. IPv6 disabled) - # macOS: IPv4 address for INET6 address family with - # IPV6_V6ONLY set - e.errno == errno.EADDRNOTAVAIL or - # Device or resource busy (16) - e.errno == errno.EBUSY or - # Address family not supported - e.errno == errno.EAFNOSUPPORT or - # Protocol not supported - e.errno == errno.EPROTONOSUPPORT)): - continue - raise RuntimeError("Failed to start server %r: %s" % ( - format_address(address), e)) from e + logger.warn("cannot create server socket on '%s': %s" % (format_address(SocketAddress), e)) + continue servers[server.socket] = server - bind_ok = True server.set_app(application) logger.info("Listening on %r%s", format_address(server.server_address),