summary refs log tree commit diff
path: root/synapse/app/_base.py
diff options
context:
space:
mode:
authorSilke Hofstra <silke@slxh.eu>2017-09-06 17:48:49 +0200
committerSilke <silke@slxh.eu>2017-12-17 13:15:48 +0100
commited48ecc58cc1e26cacc5bf5a4b7d83c27ba27732 (patch)
treec9ad547a3bd213d8dd9d034ce9b3f2ca8b397cb4 /synapse/app/_base.py
parentAllow binds to both :: and 0.0.0.0 (diff)
downloadsynapse-ed48ecc58cc1e26cacc5bf5a4b7d83c27ba27732.tar.xz
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>
Diffstat (limited to 'synapse/app/_base.py')
-rw-r--r--synapse/app/_base.py57
1 files changed, 56 insertions, 1 deletions
diff --git a/synapse/app/_base.py b/synapse/app/_base.py
index 9477737759..0f9a57bd4c 100644
--- a/synapse/app/_base.py
+++ b/synapse/app/_base.py
@@ -25,7 +25,7 @@ except Exception:
 from daemonize import Daemonize
 from synapse.util import PreserveLoggingContext
 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):
@@ -120,3 +120,58 @@ def quit_with_error(error_string):
         sys.stderr.write(" %s\n" % (line.rstrip(),))
     sys.stderr.write("*" * line_length + '\n')
     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