From 1a2078739e78ed5ea86c8bd2fccbd3789f27b4f2 Mon Sep 17 00:00:00 2001 From: Goffi Date: Mon, 3 Feb 2020 13:46:24 +0100 Subject: [PATCH] core (xmpp): avoid starting several clients at the same time: a check is done to avoid running startConnection several times at once, which would lead to the creation of several SatXMPPEntity instances at the same time, resulting in many issues. If startConnection is called while a previous one is not finished yet, a CancelError is now raised. --- sat/core/xmpp.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sat/core/xmpp.py b/sat/core/xmpp.py index 58f764b1..0f69b718 100644 --- a/sat/core/xmpp.py +++ b/sat/core/xmpp.py @@ -56,8 +56,10 @@ NS_ROSTER_VER = "urn:xmpp:features:rosterver" ROSTER_VER_KEY = "@version@" -class SatXMPPEntity(object): +class SatXMPPEntity: """Common code for Client and Component""" + # profile is added there when startConnection begins and removed when it is finished + profiles_connecting = set() def __init__(self, host_app, profile, max_retries): factory = self.factory @@ -154,6 +156,9 @@ class SatXMPPEntity(object): # (e.g. adding subprotocols) # but client should not be deleted except if session is finished # (independently of connection/deconnection) + if profile in cls.profiles_connecting: + raise exceptions.CancelError(f"{profile} is already being connected") + cls.profiles_connecting.add(profile) try: port = int( host.memory.getParamA( @@ -169,9 +174,6 @@ class SatXMPPEntity(object): password = yield host.memory.asyncGetParamA( "Password", "Connection", profile_key=profile ) - if profile in host.profiles: - raise exceptions.InternalError( - f"There is already a profile of name {profile} in host") entity_jid_s = yield host.memory.asyncGetParamA( "JabberID", "Connection", profile_key=profile) @@ -195,6 +197,9 @@ class SatXMPPEntity(object): resource=resource)) entity_jid.resource = resource + if profile in host.profiles: + raise exceptions.InternalError( + f"There is already a profile of name {profile} in host") entity = host.profiles[profile] = cls( host, profile, entity_jid, password, host.memory.getParamA(C.FORCE_SERVER_PARAM, "Connection", @@ -249,6 +254,8 @@ class SatXMPPEntity(object): ) # FIXME: we should have a timeout here, and a way to know if a plugin freeze # TODO: mesure launch time of each plugin + cls.profiles_connecting.remove(profile) + def _disconnectionCb(self, __): self._connected_d = None @@ -784,7 +791,11 @@ class SatXMPPClient(SatXMPPEntity, wokkel_client.XMPPClient): @classmethod @defer.inlineCallbacks def startConnection(cls, host, profile, max_retries): - yield super(SatXMPPClient, cls).startConnection(host, profile, max_retries) + try: + yield super(SatXMPPClient, cls).startConnection(host, profile, max_retries) + except exceptions.CancelError as e: + log.warning(f"startConnection cancelled: {e}") + return entity = host.profiles[profile] # we finally send our presence entity.presence.available()