Add methods for listening on multiple addresses

Add listen_tcp and listen_ssl which implement Twisted's reactor.listenTCP
and reactor.listenSSL for multiple addresses.

Signed-off-by: Silke Hofstra <silke@slxh.eu>
This commit is contained in:
Silke Hofstra 2017-09-06 17:48:49 +02:00 committed by Silke
parent 37d1a90025
commit ed48ecc58c
2 changed files with 90 additions and 51 deletions

View File

@ -25,7 +25,7 @@ except Exception:
from daemonize import Daemonize from daemonize import Daemonize
from synapse.util import PreserveLoggingContext from synapse.util import PreserveLoggingContext
from synapse.util.rlimit import change_resource_limit from synapse.util.rlimit import change_resource_limit
from twisted.internet import reactor from twisted.internet import error, reactor
def start_worker_reactor(appname, config): def start_worker_reactor(appname, config):
@ -120,3 +120,58 @@ def quit_with_error(error_string):
sys.stderr.write(" %s\n" % (line.rstrip(),)) sys.stderr.write(" %s\n" % (line.rstrip(),))
sys.stderr.write("*" * line_length + '\n') sys.stderr.write("*" * line_length + '\n')
sys.exit(1) sys.exit(1)
def listen_tcp(logger, bind_addresses, port, factory, backlog=50):
"""
Create a TCP socket for a port and several addresses
"""
for address in bind_addresses:
try:
reactor.listenTCP(
port,
factory,
backlog,
address
)
except error.CannotListenError as e:
check_bind_error(logger, e, address, bind_addresses)
def listen_ssl(logger, bind_addresses, port, factory, context_factory, backlog=50):
"""
Create an SSL socket for a port and several addresses
"""
for address in bind_addresses:
try:
reactor.listenSSL(
port,
factory,
context_factory,
backlog,
address
)
except error.CannotListenError as e:
check_bind_error(logger, e, address, bind_addresses)
def check_bind_error(logger, e, address, bind_addresses):
"""
This method checks an exception occurred while binding on 0.0.0.0.
If :: is specified in the bind addresses a warning is shown.
The exception is still raised otherwise.
Binding on both 0.0.0.0 and :: causes an exception on Linux and macOS
because :: binds on both IPv4 and IPv6 (as per RFC 3493).
When binding on 0.0.0.0 after :: this can safely be ignored.
Args:
logger (Logger): Logger used to log the warning.
e (Exception): Exception that was caught.
address (str): Address on which binding was attempted.
bind_addresses (list): Addresses on which the service listens.
"""
if address == '0.0.0.0' and '::' in bind_addresses:
logger.warn('Failed to listen on 0.0.0.0, continuing because listening on [::]')
else:
raise e

View File

@ -131,9 +131,9 @@ class SynapseHomeServer(HomeServer):
root_resource = create_resource_tree(resources, root_resource) root_resource = create_resource_tree(resources, root_resource)
if tls: if tls:
for address in bind_addresses: _base.listen_ssl(
try: logger,
reactor.listenSSL( bind_addresses,
port, port,
SynapseSite( SynapseSite(
"synapse.access.https.%s" % (site_tag,), "synapse.access.https.%s" % (site_tag,),
@ -142,26 +142,20 @@ class SynapseHomeServer(HomeServer):
root_resource, root_resource,
), ),
self.tls_server_context_factory, self.tls_server_context_factory,
interface=address
) )
except error.CannotListenError as e:
check_bind_error(e, address, bind_addresses)
else: else:
for address in bind_addresses: _base.listen_tcp(
try: logger,
reactor.listenTCP( bind_addresses,
port, port,
SynapseSite( SynapseSite(
"synapse.access.http.%s" % (site_tag,), "synapse.access.http.%s" % (site_tag,),
site_tag, site_tag,
listener_config, listener_config,
root_resource, root_resource,
),
interface=address
) )
except error.CannotListenError as e: )
check_bind_error(e, address, bind_addresses)
logger.info("Synapse now listening on port %d", port) logger.info("Synapse now listening on port %d", port)
def _configure_named_resource(self, name, compress=False): def _configure_named_resource(self, name, compress=False):
@ -239,19 +233,16 @@ class SynapseHomeServer(HomeServer):
elif listener["type"] == "manhole": elif listener["type"] == "manhole":
bind_addresses = listener["bind_addresses"] bind_addresses = listener["bind_addresses"]
for address in bind_addresses: _base.listen_tcp(
try: logger,
reactor.listenTCP( bind_addresses,
listener["port"], listener["port"],
manhole( manhole(
username="matrix", username="matrix",
password="rabbithole", password="rabbithole",
globals={"hs": self}, globals={"hs": self},
),
interface=address
) )
except error.CannotListenError as e: )
check_bind_error(e, address, bind_addresses)
elif listener["type"] == "replication": elif listener["type"] == "replication":
bind_addresses = listener["bind_addresses"] bind_addresses = listener["bind_addresses"]
for address in bind_addresses: for address in bind_addresses:
@ -264,7 +255,7 @@ class SynapseHomeServer(HomeServer):
"before", "shutdown", server_listener.stopListening, "before", "shutdown", server_listener.stopListening,
) )
except error.CannotListenError as e: except error.CannotListenError as e:
check_bind_error(e, address, bind_addresses) _base.check_bind_error(logger, e, address, bind_addresses)
else: else:
logger.warn("Unrecognized listener type: %s", listener["type"]) logger.warn("Unrecognized listener type: %s", listener["type"])
@ -298,13 +289,6 @@ class SynapseHomeServer(HomeServer):
return db_conn return db_conn
def check_bind_error(e, address, bind_addresses):
if address == '0.0.0.0' and '::' in bind_addresses:
logger.warn('Failed to listen on 0.0.0.0, continuing because listening on [::]')
else:
raise e
def setup(config_options): def setup(config_options):
""" """
Args: Args: