diff --git a/synapse/app/_base.py b/synapse/app/_base.py
index 5b97a54d45..5b0ca312e2 100644
--- a/synapse/app/_base.py
+++ b/synapse/app/_base.py
@@ -15,19 +15,36 @@
import gc
import logging
+import signal
import sys
+import traceback
import psutil
from daemonize import Daemonize
from twisted.internet import error, reactor
+from twisted.protocols.tls import TLSMemoryBIOFactory
from synapse.app import check_bind_error
+from synapse.crypto import context_factory
from synapse.util import PreserveLoggingContext
from synapse.util.rlimit import change_resource_limit
logger = logging.getLogger(__name__)
+_sighup_callbacks = []
+
+
+def register_sighup(func):
+ """
+ Register a function to be called when a SIGHUP occurs.
+
+ Args:
+ func (function): Function to be called when sent a SIGHUP signal.
+ Will be called with a single argument, the homeserver.
+ """
+ _sighup_callbacks.append(func)
+
def start_worker_reactor(appname, config):
""" Run the reactor in the main process
@@ -189,3 +206,69 @@ def listen_ssl(
logger.info("Synapse now listening on port %d (TLS)", port)
return r
+
+
+def refresh_certificate(hs):
+ """
+ Refresh the TLS certificates that Synapse is using by re-reading them from
+ disk and updating the TLS context factories to use them.
+ """
+
+ if not hs.config.has_tls_listener():
+ # attempt to reload the certs for the good of the tls_fingerprints
+ hs.config.read_certificate_from_disk(require_cert_and_key=False)
+ return
+
+ hs.config.read_certificate_from_disk(require_cert_and_key=True)
+ hs.tls_server_context_factory = context_factory.ServerContextFactory(hs.config)
+
+ if hs._listening_services:
+ logger.info("Updating context factories...")
+ for i in hs._listening_services:
+ # When you listenSSL, it doesn't make an SSL port but a TCP one with
+ # a TLS wrapping factory around the factory you actually want to get
+ # requests. This factory attribute is public but missing from
+ # Twisted's documentation.
+ if isinstance(i.factory, TLSMemoryBIOFactory):
+ # We want to replace TLS factories with a new one, with the new
+ # TLS configuration. We do this by reaching in and pulling out
+ # the wrappedFactory, and then re-wrapping it.
+ i.factory = TLSMemoryBIOFactory(
+ hs.tls_server_context_factory,
+ False,
+ i.factory.wrappedFactory
+ )
+ logger.info("Context factories updated.")
+
+
+def start(hs, listeners=None):
+ """
+ Start a Synapse server or worker.
+
+ Args:
+ hs (synapse.server.HomeServer)
+ listeners (list[dict]): Listener configuration ('listeners' in homeserver.yaml)
+ """
+ try:
+ # Set up the SIGHUP machinery.
+ if hasattr(signal, "SIGHUP"):
+ def handle_sighup(*args, **kwargs):
+ for i in _sighup_callbacks:
+ i(hs)
+
+ signal.signal(signal.SIGHUP, handle_sighup)
+
+ register_sighup(refresh_certificate)
+
+ # Load the certificate from disk.
+ refresh_certificate(hs)
+
+ # It is now safe to start your Synapse.
+ hs.start_listening(listeners)
+ hs.get_datastore().start_profiling()
+ except Exception:
+ traceback.print_exc(file=sys.stderr)
+ reactor = hs.get_reactor()
+ if reactor.running:
+ reactor.stop()
+ sys.exit(1)
|