From 079e8d3e2239f92c34152f84c85635a718dba061 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 16 Jan 2020 12:14:35 +0000 Subject: [PATCH 1/6] Refactor reconnect plugin. Now we have a registration state listener per provider in the wrapper. If there is some locking or slowness it will not affect all providers. Minimizes the synchronized blocks and make them per provider. --- .../jabber/LoginByPasswordStrategy.java | 3 +- .../ProtocolProviderServiceJabberImpl.java | 4 +- .../reconnectplugin/PPReconnectWrapper.java | 361 ++++++++++++ .../ReconnectPluginActivator.java | 544 +++++------------- .../event/RegistrationStateChangeEvent.java | 3 +- 5 files changed, 508 insertions(+), 407 deletions(-) create mode 100644 src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java index c4687ca988..643babae96 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/LoginByPasswordStrategy.java @@ -1,7 +1,7 @@ /* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * - * Copyright @ 2015 Atlassian Pty Ltd + * Copyright @ 2018 - present 8x8, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,6 @@ import net.java.sip.communicator.service.protocol.event.*; import org.jivesoftware.smack.*; import org.jxmpp.jid.*; -import org.jxmpp.jid.parts.Resourcepart; import javax.net.ssl.*; import java.io.*; diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index ab67616835..f9f3be515a 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -1302,10 +1302,10 @@ else if (loginStrategy.isTlsRequired()) ProtocolProviderFactory.KEEP_ALIVE_INTERVAL, -1); if (this.isKeepAliveEnabled && keepAliveInterval > 0) { - PingManager.getInstanceFor(connection).setPingInterval(keepAliveInterval); + PingManager.getInstanceFor(connection) + .setPingInterval(keepAliveInterval); } - connection.setReplyTimeout(30000); connection.connect(); setTrafficClass(); diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java new file mode 100644 index 0000000000..415d01c27d --- /dev/null +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java @@ -0,0 +1,361 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package net.java.sip.communicator.plugin.reconnectplugin; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +import static net.java.sip.communicator.plugin.reconnectplugin.ReconnectPluginActivator.*; + +/** + * Wraps a provider to listen for registration state changes and act + * appropriately to make sure we try reconnect it. + * Keeps a local state to make sure we do not try to process same event twice + * and schedule undesired reconnects. + */ +public class PPReconnectWrapper + implements RegistrationStateChangeListener +{ + /** + * Logger of this class + */ + private static final Logger logger + = Logger.getLogger(PPReconnectWrapper.class); + + /** + * The provider instance. + */ + private final ProtocolProviderService provider; + + /** + * The local state of the wrapper, we sync this and update it to avoid + * double processing of multiple events in multithreaded environment. + */ + private RegistrationState localState = null; + + /** + * The local state mutex. + */ + private final Object localStateMutex = new Object(); + + /** + * Whether we had scheduled unregister for this provider. + */ + private boolean currentlyUnregistering = false; + + /** + * Non null value indicates that on next UNREGISTERED or CONNECTION_FAILED + * event we need to schedule a reconnect with delay using the value. + */ + private Long reconnectOnNextUnregisteredDelay = null; + + /** + * The current reconnect task. + */ + private ReconnectPluginActivator.ReconnectTask currentReconnect = null; + + /** + * Protects currentReconnect field. + */ + private final Object reconnectTaskMutex = new Object(); + + /** + * Creates new wrapper. + * + * @param provider the provider that will be handled by this wrapper. + */ + public PPReconnectWrapper(ProtocolProviderService provider) + { + this.provider = provider; + + provider.addRegistrationStateChangeListener(this); + } + + /** + * Returns the provider instance. + * @return the provider instance. + */ + public ProtocolProviderService getProvider() + { + return provider; + } + + /** + * Clears any listener or resource used. + */ + public void clear() + { + this.provider.removeRegistrationStateChangeListener(this); + + // if currently reconnecting cancel + cancelReconnect(); + } + + /** + * The method is called by a ProtocolProviderService + * implementation whenever a change in the registration state of the + * corresponding provider had occurred. + * + * @param evt the event describing the status change. + */ + @Override + public void registrationStateChanged(RegistrationStateChangeEvent evt) + { + RegistrationState state = evt.getNewState(); + // we don't care about protocol providers that don't support + // reconnection and we are interested only in few state changes + if (!(evt.getSource() instanceof ProtocolProviderService) + || !(state.equals(RegistrationState.REGISTERED) + || state.equals(RegistrationState.UNREGISTERED) + || state.equals(RegistrationState.CONNECTION_FAILED))) + return; + + ProtocolProviderService pp = (ProtocolProviderService) evt.getSource(); + + synchronized(localStateMutex) + { + // state is already handled, nothing to do + if (state.equals(localState)) + { + return; + } + + this.localState = state; + + // if we are in a process of scheduling a reconnect with unregister + // before that process + if (this.reconnectOnNextUnregisteredDelay != null) + { + long delay = this.reconnectOnNextUnregisteredDelay; + this.reconnectOnNextUnregisteredDelay = null; + + if ((state.equals(RegistrationState.UNREGISTERED) + || state.equals(RegistrationState.CONNECTION_FAILED)) + && !evt.isUserRequest() + && this.currentlyUnregistering) + { + // this is us who triggered the unregister + this.currentlyUnregistering = false; + + createReconnect(delay); + return; + } + } + + boolean isServerReturnedErroneousInputEvent = + state.equals(RegistrationState.CONNECTION_FAILED) + && evt.getReasonCode() == RegistrationStateChangeEvent + .REASON_SERVER_RETURNED_ERRONEOUS_INPUT; + + try + { + if (state.equals(RegistrationState.REGISTERED)) + { + ReconnectPluginActivator.addReconnectEnabledProvider(this); + + // if currently reconnecting cancel + cancelReconnect(); + + if (logger.isTraceEnabled()) + { + logger.trace("Got Registered for " + pp); + } + } + else if (state.equals(RegistrationState.CONNECTION_FAILED) + && !isServerReturnedErroneousInputEvent) + { + if (!ReconnectPluginActivator + .hasAtLeastOneSuccessfulConnection(pp)) + { + // ignore providers which haven't registered successfully + // till now, they maybe miss-configured + ReconnectPluginActivator.notifyConnectionFailed(evt); + + return; + } + + // if currentlyUnregistering it means + // we got conn failed cause the pp has tried to unregister + // with sending network packet + // but this unregister is scheduled from us so skip + if (this.currentlyUnregistering) + { + this.currentlyUnregistering = false; + return; + } + + if (!ReconnectPluginActivator.noConnectedInterfaces()) + { + // network is up but something happen and cannot reconnect + // strange lets try again after some time + reconnect(currentReconnect != null ? + currentReconnect.delay : -1); + } + } + else if (state.equals(RegistrationState.UNREGISTERED) + || isServerReturnedErroneousInputEvent) + { + this.currentlyUnregistering = false; + + // Removes from list of auto-reconnect only if the unregister + // event is by user request + if (evt.isUserRequest() || isServerReturnedErroneousInputEvent) + { + ReconnectPluginActivator + .removeReconnectEnabledProviders(this); + } + + // if currently reconnecting cancel + cancelReconnect(); + } + } + catch(Throwable ex) + { + logger.error("Error dispatching protocol registration change", ex); + } + } + } + + /** + * Cancels currently scheduled reconnect task. + */ + private void cancelReconnect() + { + synchronized(reconnectTaskMutex) + { + if (this.currentReconnect != null) + { + this.currentReconnect.cancel(); + this.currentReconnect = null; + } + } + } + + /** + * Creates and schedules new reconnect task if such is not already created. + * @param delay the delay to use. + */ + private void createReconnect(long delay) + { + synchronized(reconnectTaskMutex) + { + if (this.currentReconnect == null) + { + this.currentReconnect = ReconnectPluginActivator + .scheduleReconnectIfNeeded(delay, this.provider); + } + else + { + logger.warn("Reconnect with delay:" + + this.currentReconnect.delay + " already scheduled for " + + this.provider + " attempted schedule with delay:" + + delay); + } + } + } + + /** + * Schedules a reconnect. + */ + void reconnect() + { + // if currently reconnecting cancel and try again + cancelReconnect(); + + this.reconnect(-1); + } + + /** + * Schedules a reconnect. + * @param previousDelay the delay used in the previous reconnect or -1; + */ + private void reconnect(long previousDelay) + { + long delay; + + if (previousDelay != -1) + { + delay = Math.min(previousDelay * 2, MAX_RECONNECT_DELAY*1000); + } + else + { + delay = (long)(RECONNECT_DELAY_MIN + + Math.random() * RECONNECT_DELAY_MAX)*1000; + } + + if (this.provider.getRegistrationState().equals( + RegistrationState.UNREGISTERING) + || this.provider.getRegistrationState().equals( + RegistrationState.UNREGISTERED) + || this.provider.getRegistrationState().equals( + RegistrationState.CONNECTION_FAILED)) + { + createReconnect(delay); + } + else + { + synchronized(localStateMutex) + { + // start registering after the pp has unregistered + this.reconnectOnNextUnregisteredDelay = delay; + + // as we will reconnect, lets unregister + unregister(); + } + } + } + + /** + * Unregisters the ProtocolProvider. + */ + void unregister() + { + this.currentlyUnregistering = true; + + // if currently reconnecting cancel + cancelReconnect(); + + try + { + this.provider.unregister(); + } + catch(Throwable t) + { + logger.error("Error unregistering pp:" + this.provider, t); + } + } + + /** + * Prints current wrapper state. + * @return string representing current wrapper state. + */ + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append(super.toString()) + .append("[provider=").append(provider) + .append(", currentlyUnregistering=").append(currentlyUnregistering) + .append(", currentReconnect=").append(currentReconnect) + .append(", reconnectOnNextUnregisteredDelay=") + .append(reconnectOnNextUnregisteredDelay) + .append("]"); + + return builder.toString(); + } +} diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java index 7a2a96fe9f..f6d850d451 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java @@ -1,7 +1,7 @@ /* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * - * Copyright @ 2015 Atlassian Pty Ltd + * Copyright @ 2018 - present 8x8, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package net.java.sip.communicator.plugin.reconnectplugin; import java.util.*; +import java.util.stream.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.netaddr.*; @@ -39,8 +40,7 @@ public class ReconnectPluginActivator implements BundleActivator, ServiceListener, - NetworkConfigurationChangeListener, - RegistrationStateChangeListener + NetworkConfigurationChangeListener { /** * Logger of this class @@ -81,96 +81,46 @@ public class ReconnectPluginActivator private NetworkAddressManagerService networkAddressManagerService = null; /** - * Holds every protocol provider which is can be reconnected and + * Holds every protocol provider wrapper which can be reconnected and * a list of the available and up interfaces when the provider was - * registered. When a provider is unregistered it is removed - * from this collection. + * registered. When a provider is unregistered by user request it is removed + * from this collection. Or when the provider service is removed from OSGi. + * Or if provider failed registering and there were yet no successful + * connections of this provider. * Providers REMOVED: * - When provider is removed from osgi - * - When a provider is UNREGISTERED + * - When a provider is UNREGISTERED by user request * Providers ADDED: * - When a provider is REGISTERED */ - private final Map> - autoReconnEnabledProviders = new HashMap>(); - - /** - * Holds the currently reconnecting providers and their reconnect tasks. - * When they get connected they are removed from this collection. - * Providers REMOVED: - * - When provider removed from osgi. - * - When interface is UP, we remove providers and schedule reconnect - * for them - * - When interface is DOWN, we remove all providers and schedule reconnect - * - When last interface is DOWN, we remove all providers and - * unregister them - * - On connection failed with no interface connected - * - Provider is Registered - * - Provider is Unregistered and is missing in unregistered providers list - * - After provider is unregistered just before reconnecting, and there - * are no connected interfaces - * Providers ADDED: - * - Before unregister (in new thread) when scheduling a reconnect task - * - After provider is unregistered just before reconnecting - */ - private final Map - currentlyReconnecting - = new HashMap(); - - /** - * If network is down we save here the providers which need - * to be reconnected. - * Providers REMOVED: - * - When provider removed from osgi. - * - Remove all providers when interface is up and we will reconnect them - * Providers ADDED: - * - Interface is down, and there are still active interfaces, add all - * auto reconnect enabled and all currently reconnecting - * - Provider in connection failed and there are no connected interfaces - * - Provider is unregistered or connection failed and there are no - * connected interfaces. - */ - private Set needsReconnection = - new HashSet(); - - /** - * A list of providers on which we have called unregister. This is a - * way to differ our unregister calls from calls coming from user, wanting - * to stop all reconnects. - * Providers REMOVED: - * - Provider is Connection failed. - * - Provider is registered/unregistered - * Providers ADDED: - * - Provider is about to be unregistered - */ - private Set unregisteringProviders - = new HashSet(); + private static final Map> + reconnectEnabledProviders = new HashMap<>(); /** * A list of currently connected interfaces. If empty network is down. */ - private Set connectedInterfaces = new HashSet(); + private static final Set connectedInterfaces = new HashSet<>(); /** * Timer for scheduling all reconnect operations. */ - private Timer timer = null; + private static Timer timer = null; /** * Start of the delay interval when starting a reconnect. */ - private static final int RECONNECT_DELAY_MIN = 2; // sec + static final int RECONNECT_DELAY_MIN = 2; // sec /** * The end of the interval for the initial reconnect. */ - private static final int RECONNECT_DELAY_MAX = 4; // sec + static final int RECONNECT_DELAY_MAX = 4; // sec /** * Max value for growing the reconnect delay, all subsequent reconnects * use this maximum delay. */ - private static final int MAX_RECONNECT_DELAY = 300; // sec + static final int MAX_RECONNECT_DELAY = 300; // sec /** * Network notifications event type. @@ -178,7 +128,9 @@ public class ReconnectPluginActivator public static final String NETWORK_NOTIFICATIONS = "NetworkNotifications"; /** - * + * Whether the provider connected at least once, which means settings are + * correct, otherwise it maybe server address wrong or username/password + * and there is no point of reconnecting. */ public static final String ATLEAST_ONE_CONNECTION_PROP = "net.java.sip.communicator.plugin.reconnectplugin." + @@ -430,7 +382,10 @@ private void handleProviderAdded(ProtocolProviderService provider) if (logger.isTraceEnabled()) logger.trace("New protocol provider is coming " + provider); - provider.addRegistrationStateChangeListener(this); + // we just create the instance, if the instance successfully registers + // will use addReconnectEnabledProvider to add itself to those we will + // handle + new PPReconnectWrapper(provider); } /** @@ -452,17 +407,52 @@ private void handleProviderRemoved(ProtocolProviderService provider) setAtLeastOneSuccessfulConnection(provider, false); } - provider.removeRegistrationStateChangeListener(this); - - synchronized(this) + synchronized(reconnectEnabledProviders) { - autoReconnEnabledProviders.remove(provider); - needsReconnection.remove(provider); + Iterator iter + = reconnectEnabledProviders.keySet().iterator(); + while(iter.hasNext()) + { + PPReconnectWrapper wrapper = iter.next(); + if (wrapper.getProvider().equals(provider)) + { + iter.remove(); + wrapper.clear(); + } + } + } + } - if(currentlyReconnecting.containsKey(provider)) + /** + * Adds a wrapper to the list of the wrappers we will handle reconnecting. + * Marks one successful connection if needed. + * @param wrapper the provider wrapper. + */ + static void addReconnectEnabledProvider(PPReconnectWrapper wrapper) + { + ProtocolProviderService pp = wrapper.getProvider(); + + synchronized(reconnectEnabledProviders) + { + if (!hasAtLeastOneSuccessfulConnection(pp)) { - currentlyReconnecting.remove(provider).cancel(); + setAtLeastOneSuccessfulConnection(pp, true); } + + reconnectEnabledProviders.put( + wrapper, new ArrayList<>(connectedInterfaces)); + } + } + + /** + * Removes the wrapper from the list, will not reconnect it. + * @param wrapper the wrapper to remove. + */ + static void removeReconnectEnabledProviders(PPReconnectWrapper wrapper) + { + synchronized(reconnectEnabledProviders) + { + reconnectEnabledProviders.remove(wrapper); } } @@ -476,26 +466,18 @@ public synchronized void configurationChanged(ChangeEvent event) if(event.getType() == ChangeEvent.IFACE_UP) { // no connection so one is up, lets connect - if(connectedInterfaces.isEmpty()) + if (noConnectedInterfaces()) { onNetworkUp(); - Iterator iter = - needsReconnection.iterator(); - while (iter.hasNext()) + List wrappers; + synchronized (reconnectEnabledProviders) { - ProtocolProviderService pp = iter.next(); - if(currentlyReconnecting.containsKey(pp)) - { - // now lets cancel it and schedule it again - // so it will use this iface - currentlyReconnecting.remove(pp).cancel(); - } - - reconnect(pp); + wrappers = new LinkedList<>( + reconnectEnabledProviders.keySet()); } - needsReconnection.clear(); + wrappers.stream().forEach(PPReconnectWrapper::reconnect); } connectedInterfaces.add((String)event.getSource()); @@ -507,57 +489,33 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN) connectedInterfaces.remove(ifaceName); // one is down and at least one more is connected - if(connectedInterfaces.size() > 0) + if (!noConnectedInterfaces()) { - // lets reconnect all that was connected when this one was + // lets reconnect all that were connected when this one was // available, cause they maybe using it - Iterator>> iter = - autoReconnEnabledProviders.entrySet().iterator(); - while (iter.hasNext()) + List wrappers; + synchronized (reconnectEnabledProviders) { - Map.Entry> entry - = iter.next(); - - if(entry.getValue().contains(ifaceName)) - { - ProtocolProviderService pp = entry.getKey(); - // hum someone is reconnecting, lets cancel and - // schedule it again - if(currentlyReconnecting.containsKey(pp)) - { - currentlyReconnecting.remove(pp).cancel(); - } - - reconnect(pp); - } + wrappers = reconnectEnabledProviders.entrySet().stream() + .filter(entry -> entry.getValue().contains(ifaceName)) + .map(entry -> entry.getKey()) + .collect(Collectors.toList()); } + + wrappers.stream().forEach(PPReconnectWrapper::reconnect); } else { - // we must disconnect every pp and put all to be need of reconnecting - needsReconnection.addAll(autoReconnEnabledProviders.keySet()); - // there can by and some that are currently going to reconnect - // must take care of them too, cause there is no net and they won't succeed - needsReconnection.addAll(currentlyReconnecting.keySet()); - - Iterator iter = - needsReconnection.iterator(); - while (iter.hasNext()) + // we must disconnect every pp that is trying to reconnect + // and they will reconnect when network is back + List wrappers; + synchronized (reconnectEnabledProviders) { - ProtocolProviderService pp = iter.next(); - - // if provider is scheduled for reconnect, - // cancel it there is no network - if(currentlyReconnecting.containsKey(pp)) - { - currentlyReconnecting.remove(pp).cancel(); - } - - // don't reconnect just unregister if needed. - unregister(pp); + wrappers = new LinkedList<>( + reconnectEnabledProviders.keySet()); } - connectedInterfaces.clear(); + wrappers.stream().forEach(PPReconnectWrapper::unregister); onNetworkDown(); } @@ -572,22 +530,12 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN) } /** - * Unregisters the ProtocolProvider. Make sure to do it in separate thread - * so we don't block other processing. - * @param pp the protocol provider to unregister. + * Whether we have any connected interface. + * @return true when there is no connected interface at the moment. */ - private void unregister(final ProtocolProviderService pp) + static boolean noConnectedInterfaces() { - unregisteringProviders.add(pp); - - try - { - pp.unregister(); - } - catch(Throwable t) - { - logger.error("Error unregistering pp:" + pp, t); - } + return connectedInterfaces.isEmpty(); } /** @@ -597,12 +545,8 @@ private void unregister(final ProtocolProviderService pp) private void traceCurrentPPState() { logger.trace("connectedInterfaces: " + connectedInterfaces); - logger.trace("autoReconnEnabledProviders: " - + autoReconnEnabledProviders.keySet()); - logger.trace("currentlyReconnecting: " - + currentlyReconnecting.keySet()); - logger.trace("needsReconnection: " + needsReconnection); - logger.trace("unregisteringProviders: " + unregisteringProviders); + logger.trace("reconnectEnabledProviders: " + + reconnectEnabledProviders.keySet()); logger.trace("----"); } @@ -613,7 +557,7 @@ private void traceCurrentPPState() * @param params and parameters in any. * @param tag extra notification tag object */ - private void notify(String title, String i18nKey, String[] params, + private static void notify(String title, String i18nKey, String[] params, Object tag) { Map extras = new HashMap(); @@ -631,233 +575,36 @@ private void notify(String title, String i18nKey, String[] params, } /** - * The method is called by a ProtocolProviderService - * implementation whenever a change in the registration state of the - * corresponding provider had occurred. - * - * @param evt the event describing the status change. + * Notifies for connection failed or failed to non existing user. + * @param evt the event to notify for. */ - public void registrationStateChanged(RegistrationStateChangeEvent evt) + static void notifyConnectionFailed(RegistrationStateChangeEvent evt) { - // we don't care about protocol providers that don't support - // reconnection and we are interested only in few state changes - if(!(evt.getSource() instanceof ProtocolProviderService) - || - !(evt.getNewState().equals(RegistrationState.REGISTERED) - || evt.getNewState().equals(RegistrationState.UNREGISTERED) - || evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))) - return; - - synchronized(this) { - try + if (!evt.getNewState().equals(RegistrationState.CONNECTION_FAILED)) { - ProtocolProviderService pp = (ProtocolProviderService)evt.getSource(); - - boolean isServerReturnedErroneousInputEvent = - evt.getNewState().equals(RegistrationState.CONNECTION_FAILED) - && evt.getReasonCode() == RegistrationStateChangeEvent - .REASON_SERVER_RETURNED_ERRONEOUS_INPUT; - - if(evt.getNewState().equals(RegistrationState.CONNECTION_FAILED) - && !isServerReturnedErroneousInputEvent) - { - if(!hasAtLeastOneSuccessfulConnection(pp)) - { - // ignore providers which haven't registered successfully - // till now, they maybe misconfigured - //String notifyMsg; - - if(evt.getReasonCode() == - RegistrationStateChangeEvent.REASON_NON_EXISTING_USER_ID) - { - notify( - getResources().getI18NString("service.gui.ERROR"), - "service.gui.NON_EXISTING_USER_ID", - new String[]{pp.getAccountID().getService()}, - pp.getAccountID()); - } - else - { - notify( - getResources().getI18NString("service.gui.ERROR"), - "plugin.reconnectplugin.CONNECTION_FAILED_MSG", - new String[] - { pp.getAccountID().getUserID(), - pp.getAccountID().getService() }, - pp.getAccountID()); - } - - return; - } - - // if this pp is already in needsReconnection, it means - // we got conn failed cause the pp has tried to unregister - // with sending network packet - // but this unregister is scheduled from us so skip - if(needsReconnection.contains(pp)) - return; - - if(connectedInterfaces.isEmpty()) - { - needsReconnection.add(pp); - - if(currentlyReconnecting.containsKey(pp)) - currentlyReconnecting.remove(pp).cancel(); - } - else - { - // network is up but something happen and cannot reconnect - // strange lets try again after some time - reconnect(pp); - } - - // unregister can finish and with connection failed, - // the protocol is unable to unregister - unregisteringProviders.remove(pp); - - if(logger.isTraceEnabled()) - { - logger.trace("Got Connection Failed for " + pp, - new Exception("tracing exception")); - traceCurrentPPState(); - } - } - else if(evt.getNewState().equals(RegistrationState.REGISTERED)) - { - if(!hasAtLeastOneSuccessfulConnection(pp)) - { - setAtLeastOneSuccessfulConnection(pp, true); - } - - autoReconnEnabledProviders.put( - pp, - new ArrayList(connectedInterfaces)); - - if(currentlyReconnecting.containsKey(pp)) - currentlyReconnecting.remove(pp).cancel(); - - unregisteringProviders.remove(pp); - - if(logger.isTraceEnabled()) - { - logger.trace("Got Registered for " + pp); - traceCurrentPPState(); - } - } - else if(evt.getNewState().equals(RegistrationState.UNREGISTERED) - || isServerReturnedErroneousInputEvent) - { - // Removes from list of autoreconnect only if the unregister - // event is by user request - if(evt.isUserRequest() - || isServerReturnedErroneousInputEvent) - autoReconnEnabledProviders.remove(pp); - - if(!unregisteringProviders.contains(pp) - && currentlyReconnecting.containsKey(pp)) - { - currentlyReconnecting.remove(pp).cancel(); - } - unregisteringProviders.remove(pp); - - if(logger.isTraceEnabled()) - { - logger.trace("Got Unregistered for " + pp); - - if(!currentlyReconnecting.containsKey(pp) - && !needsReconnection.contains(pp) - && logger.isTraceEnabled()) - { - // provider is not present in any collection - // it will be no longer reconnected, maybe user request - // to unregister lets trace check - logger.trace( - "Provider is unregistered and will not " + - "be reconnected (maybe on user request): " + pp - + " / reason:" + evt.getReason() - + " / reasonCode:" + evt.getReasonCode() - + " / oldState:" + evt.getOldState(), - new Exception("Trace exception.")); - } - traceCurrentPPState(); - } - } - } - catch(Throwable ex) - { - logger.error("Error dispatching protocol registration change", ex); - } + return; } - } - /** - * Method to schedule a reconnect for a protocol provider. - * @param pp the provider. - */ - private void reconnect(final ProtocolProviderService pp) - { - long delay; + ProtocolProviderService pp = (ProtocolProviderService)evt.getSource(); - if(currentlyReconnecting.containsKey(pp)) + if (evt.getReasonCode() == + RegistrationStateChangeEvent.REASON_NON_EXISTING_USER_ID) { - delay = currentlyReconnecting.get(pp).delay; - - // we never stop trying - //if(delay == MAX_RECONNECT_DELAY*1000) - // return; - - delay = Math.min(delay * 2, MAX_RECONNECT_DELAY*1000); + notify( + getResources().getI18NString("service.gui.ERROR"), + "service.gui.NON_EXISTING_USER_ID", + new String[]{pp.getAccountID().getService()}, + pp.getAccountID()); } else { - delay = (long)(RECONNECT_DELAY_MIN - + Math.random() * RECONNECT_DELAY_MAX)*1000; - } - - if(pp.getRegistrationState().equals(RegistrationState.UNREGISTERING) - || pp.getRegistrationState().equals(RegistrationState.UNREGISTERED) - || pp.getRegistrationState() - .equals(RegistrationState.CONNECTION_FAILED)) - { - scheduleReconnectIfNeeded(delay, pp, false); - } - else - { - // start registering after the pp has unregistered - final long delayFinal = delay; - RegistrationStateChangeListener listener = - new RegistrationStateChangeListener() - { - public void registrationStateChanged(RegistrationStateChangeEvent evt) - { - if(evt.getSource() instanceof ProtocolProviderService) - { - if(evt.getNewState().equals( - RegistrationState.UNREGISTERED) - || evt.getNewState().equals( - RegistrationState.CONNECTION_FAILED)) - { - pp.removeRegistrationStateChangeListener(this); - - scheduleReconnectIfNeeded( - delayFinal, pp, evt.isUserRequest()); - } - /* - this unregister one way or another, and will end - with unregister or connection failed - if we remove listener when unregister come - we will end up with unregistered provider without reconnect - else if(evt.getNewState().equals( - RegistrationState.REGISTERED)) - { - pp.removeRegistrationStateChangeListener(this); - }*/ - } - }}; - pp.addRegistrationStateChangeListener(listener); - - // as we will reconnect, lets unregister - unregister(pp); + notify( + getResources().getI18NString("service.gui.ERROR"), + "plugin.reconnectplugin.CONNECTION_FAILED_MSG", + new String[] + { pp.getAccountID().getUserID(), + pp.getAccountID().getService() }, + pp.getAccountID()); } } @@ -866,58 +613,44 @@ else if(evt.getNewState().equals( * interfaces and user request is not null). * @param delay The delay to use when creating the reconnect task. * @param pp the protocol provider that will be reconnected. - * @param userRequest whether this reconnect is coming from user request - * event that was fired. */ - private synchronized void scheduleReconnectIfNeeded( - long delay, ProtocolProviderService pp, boolean userRequest) + static ReconnectTask scheduleReconnectIfNeeded( + long delay, ProtocolProviderService pp) { final ReconnectTask task = new ReconnectTask(pp); task.delay = delay; - if(timer == null) - return; + if (timer == null) + { + return null; + } - if(connectedInterfaces.size() == 0) + if (noConnectedInterfaces()) { - // well there is no network we just need - // this provider in needs reconnection when - // there is one - // means we started unregistering while + // There is no network, nothing to do, when + // network is back it will be scheduled to reconnect. + // This means we started unregistering while // network was going down and meanwhile there // were no connected interface, this happens // when we have more than one connected // interface and we got 2 events for down iface - needsReconnection.add(pp); - if(currentlyReconnecting.containsKey(pp)) - currentlyReconnecting.remove(pp).cancel(); - - return; + return null; } - // cancel any existing task before overriding it - if(currentlyReconnecting.containsKey(pp)) - currentlyReconnecting.remove(pp).cancel(); + if(logger.isInfoEnabled()) + logger.info("Reconnect " + + pp + " after " + task.delay + " ms."); - // schedule the reconnect only if is not user - // requested unregister - if (!userRequest) - { - currentlyReconnecting.put(pp, task); - - if(logger.isInfoEnabled()) - logger.info("Reconnect " - + pp + " after " + task.delay + " ms."); + timer.schedule(task, task.delay); - timer.schedule(task, task.delay); - } + return task; } /** * The task executed by the timer when time for reconnect comes. */ - private class ReconnectTask + static class ReconnectTask extends TimerTask { /** @@ -928,7 +661,7 @@ private class ReconnectTask /** * The delay with which was this task scheduled. */ - private long delay; + long delay; /** * The thread to execute this task. @@ -972,6 +705,12 @@ public void run() } } } + + @Override + public String toString() + { + return super.toString() + "[delay=" + delay + "]"; + } } /** @@ -980,7 +719,8 @@ public void run() * @param pp the protocol provider * @return true if property exists. */ - private boolean hasAtLeastOneSuccessfulConnection(ProtocolProviderService pp) + static boolean hasAtLeastOneSuccessfulConnection( + ProtocolProviderService pp) { String value = (String)getConfigurationService().getProperty( ATLEAST_ONE_CONNECTION_PROP + "." @@ -997,7 +737,7 @@ private boolean hasAtLeastOneSuccessfulConnection(ProtocolProviderService pp) * @param pp the protocol provider * @param value the new value true or false. */ - private void setAtLeastOneSuccessfulConnection( + private static void setAtLeastOneSuccessfulConnection( ProtocolProviderService pp, boolean value) { getConfigurationService().setProperty( diff --git a/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeEvent.java index 93791c070b..f9648ef5a4 100644 --- a/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/RegistrationStateChangeEvent.java @@ -1,7 +1,7 @@ /* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * - * Copyright @ 2015 Atlassian Pty Ltd + * Copyright @ 2018 - present 8x8, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -199,6 +199,7 @@ public String toString() return "RegistrationStateChangeEvent[ oldState=" + getOldState().getStateName() + "; newState="+ getNewState() + + "; userRequest="+ isUserRequest() + "; reasonCode=" + getReasonCode() + "; reason=" + getReason() + "]"; } From c916ad527fab564edd0f91d9643f3a27952bbe97 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 17 Jan 2020 09:37:19 +0000 Subject: [PATCH 2/6] Renames a method. --- .../plugin/reconnectplugin/PPReconnectWrapper.java | 2 +- .../reconnectplugin/ReconnectPluginActivator.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java index 415d01c27d..e3678c5bc0 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java @@ -199,7 +199,7 @@ else if (state.equals(RegistrationState.CONNECTION_FAILED) return; } - if (!ReconnectPluginActivator.noConnectedInterfaces()) + if (ReconnectPluginActivator.anyConnectedInterfaces()) { // network is up but something happen and cannot reconnect // strange lets try again after some time diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java index f6d850d451..11c1479dc3 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java @@ -466,7 +466,7 @@ public synchronized void configurationChanged(ChangeEvent event) if(event.getType() == ChangeEvent.IFACE_UP) { // no connection so one is up, lets connect - if (noConnectedInterfaces()) + if (!anyConnectedInterfaces()) { onNetworkUp(); @@ -489,7 +489,7 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN) connectedInterfaces.remove(ifaceName); // one is down and at least one more is connected - if (!noConnectedInterfaces()) + if (anyConnectedInterfaces()) { // lets reconnect all that were connected when this one was // available, cause they maybe using it @@ -531,11 +531,12 @@ else if(event.getType() == ChangeEvent.IFACE_DOWN) /** * Whether we have any connected interface. - * @return true when there is no connected interface at the moment. + * @return true when there is at least one connected interface at + * the moment. */ - static boolean noConnectedInterfaces() + static boolean anyConnectedInterfaces() { - return connectedInterfaces.isEmpty(); + return !connectedInterfaces.isEmpty(); } /** @@ -625,7 +626,7 @@ static ReconnectTask scheduleReconnectIfNeeded( return null; } - if (noConnectedInterfaces()) + if (!anyConnectedInterfaces()) { // There is no network, nothing to do, when // network is back it will be scheduled to reconnect. From 956564318c8b8efcabe178dd09a83b7760db5de2 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 17 Jan 2020 10:09:49 +0000 Subject: [PATCH 3/6] Moves timer and ReconnectTask in the wrapper. This way we will have more rapid reconnects as there will be a thread for every reconnect task, and not a single one for all tasks. --- .../reconnectplugin/PPReconnectWrapper.java | 124 ++++++++++++++++-- .../ReconnectPluginActivator.java | 118 ----------------- 2 files changed, 114 insertions(+), 128 deletions(-) diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java index e3678c5bc0..ef50b68069 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java @@ -20,6 +20,8 @@ import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; +import java.util.*; + import static net.java.sip.communicator.plugin.reconnectplugin.ReconnectPluginActivator.*; /** @@ -53,6 +55,11 @@ public class PPReconnectWrapper */ private final Object localStateMutex = new Object(); + /** + * Timer for scheduling the reconnect operation. + */ + private Timer timer = null; + /** * Whether we had scheduled unregister for this provider. */ @@ -67,7 +74,7 @@ public class PPReconnectWrapper /** * The current reconnect task. */ - private ReconnectPluginActivator.ReconnectTask currentReconnect = null; + private ReconnectTask currentReconnect = null; /** * Protects currentReconnect field. @@ -82,6 +89,8 @@ public class PPReconnectWrapper public PPReconnectWrapper(ProtocolProviderService provider) { this.provider = provider; + this.timer = new Timer("Reconnect timer p:" + + provider.getAccountID().getAccountUniqueID(), true); provider.addRegistrationStateChangeListener(this); } @@ -100,6 +109,12 @@ public ProtocolProviderService getProvider() */ public void clear() { + if(timer != null) + { + timer.cancel(); + timer = null; + } + this.provider.removeRegistrationStateChangeListener(this); // if currently reconnecting cancel @@ -166,7 +181,7 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) { if (state.equals(RegistrationState.REGISTERED)) { - ReconnectPluginActivator.addReconnectEnabledProvider(this); + addReconnectEnabledProvider(this); // if currently reconnecting cancel cancelReconnect(); @@ -179,12 +194,11 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) else if (state.equals(RegistrationState.CONNECTION_FAILED) && !isServerReturnedErroneousInputEvent) { - if (!ReconnectPluginActivator - .hasAtLeastOneSuccessfulConnection(pp)) + if (!hasAtLeastOneSuccessfulConnection(pp)) { // ignore providers which haven't registered successfully // till now, they maybe miss-configured - ReconnectPluginActivator.notifyConnectionFailed(evt); + notifyConnectionFailed(evt); return; } @@ -199,7 +213,7 @@ else if (state.equals(RegistrationState.CONNECTION_FAILED) return; } - if (ReconnectPluginActivator.anyConnectedInterfaces()) + if (anyConnectedInterfaces()) { // network is up but something happen and cannot reconnect // strange lets try again after some time @@ -216,8 +230,9 @@ else if (state.equals(RegistrationState.UNREGISTERED) // event is by user request if (evt.isUserRequest() || isServerReturnedErroneousInputEvent) { - ReconnectPluginActivator - .removeReconnectEnabledProviders(this); + this.clear(); + + removeReconnectEnabledProviders(this); } // if currently reconnecting cancel @@ -256,8 +271,8 @@ private void createReconnect(long delay) { if (this.currentReconnect == null) { - this.currentReconnect = ReconnectPluginActivator - .scheduleReconnectIfNeeded(delay, this.provider); + this.currentReconnect + = scheduleReconnectIfNeeded(delay, this.provider); } else { @@ -358,4 +373,93 @@ public String toString() return builder.toString(); } + + /** + * Schedules a reconnect if needed (if there is timer and connected + * interfaces and user request is not null). + * @param delay The delay to use when creating the reconnect task. + * @param pp the protocol provider that will be reconnected. + */ + private ReconnectTask scheduleReconnectIfNeeded( + long delay, ProtocolProviderService pp) + { + final ReconnectTask task = new ReconnectTask(); + task.delay = delay; + + if (timer == null) + { + return null; + } + + if (!anyConnectedInterfaces()) + { + // There is no network, nothing to do, when + // network is back it will be scheduled to reconnect. + // This means we started unregistering while + // network was going down and meanwhile there + // were no connected interface, this happens + // when we have more than one connected + // interface and we got 2 events for down iface + + return null; + } + + if(logger.isInfoEnabled()) + logger.info("Reconnect " + pp + " after " + task.delay + " ms."); + + timer.schedule(task, task.delay); + + return task; + } + + /** + * The task executed by the timer when time for reconnect comes. + */ + private class ReconnectTask + extends TimerTask + { + /** + * The delay with which was this task scheduled. + */ + long delay; + + /** + * The thread to execute this task. + */ + private Thread thread = null; + + /** + * Reconnects the provider. + */ + @Override + public void run() + { + if(thread == null || !Thread.currentThread().equals(thread)) + { + thread = new Thread(this); + thread.start(); + } + else + { + try + { + if (logger.isInfoEnabled()) + logger.info("Start reconnecting " + provider); + + provider.register( + getUIService().getDefaultSecurityAuthority(provider)); + } catch (OperationFailedException ex) + { + logger.error("cannot re-register provider will keep going", + ex); + } + } + } + + @Override + public String toString() + { + return super.toString() + "[delay=" + delay + "]"; + } + } } diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java index 11c1479dc3..5e06644167 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java @@ -101,11 +101,6 @@ public class ReconnectPluginActivator */ private static final Set connectedInterfaces = new HashSet<>(); - /** - * Timer for scheduling all reconnect operations. - */ - private static Timer timer = null; - /** * Start of the delay interval when starting a reconnect. */ @@ -169,9 +164,6 @@ public void start(BundleContext bundleContext) bundleContext.addServiceListener(this); - if(timer == null) - timer = new Timer("Reconnect timer", true); - this.networkAddressManagerService = ServiceUtils.getService( bundleContext, @@ -222,11 +214,6 @@ public void start(BundleContext bundleContext) public void stop(BundleContext bundleContext) throws Exception { - if(timer != null) - { - timer.cancel(); - timer = null; - } } /** @@ -609,111 +596,6 @@ static void notifyConnectionFailed(RegistrationStateChangeEvent evt) } } - /** - * Schedules a reconnect if needed (if there is timer and connected - * interfaces and user request is not null). - * @param delay The delay to use when creating the reconnect task. - * @param pp the protocol provider that will be reconnected. - */ - static ReconnectTask scheduleReconnectIfNeeded( - long delay, ProtocolProviderService pp) - { - final ReconnectTask task = new ReconnectTask(pp); - task.delay = delay; - - if (timer == null) - { - return null; - } - - if (!anyConnectedInterfaces()) - { - // There is no network, nothing to do, when - // network is back it will be scheduled to reconnect. - // This means we started unregistering while - // network was going down and meanwhile there - // were no connected interface, this happens - // when we have more than one connected - // interface and we got 2 events for down iface - - return null; - } - - if(logger.isInfoEnabled()) - logger.info("Reconnect " - + pp + " after " + task.delay + " ms."); - - timer.schedule(task, task.delay); - - return task; - } - - /** - * The task executed by the timer when time for reconnect comes. - */ - static class ReconnectTask - extends TimerTask - { - /** - * The provider to reconnect. - */ - private ProtocolProviderService provider; - - /** - * The delay with which was this task scheduled. - */ - long delay; - - /** - * The thread to execute this task. - */ - private Thread thread = null; - - /** - * Creates the task. - * - * @param provider the ProtocolProviderService to reconnect - */ - public ReconnectTask(ProtocolProviderService provider) - { - this.provider = provider; - } - - /** - * Reconnects the provider. - */ - @Override - public void run() - { - if(thread == null || !Thread.currentThread().equals(thread)) - { - thread = new Thread(this); - thread.start(); - } - else - { - try - { - if (logger.isInfoEnabled()) - logger.info("Start reconnecting " + provider); - - provider.register( - getUIService().getDefaultSecurityAuthority(provider)); - } catch (OperationFailedException ex) - { - logger.error("cannot re-register provider will keep going", - ex); - } - } - } - - @Override - public String toString() - { - return super.toString() + "[delay=" + delay + "]"; - } - } - /** * Check does the supplied protocol has the property set for at least * one successful connection. From dd13596158dd7ba4dee159e98048e336eda3d0b7 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 17 Jan 2020 10:12:30 +0000 Subject: [PATCH 4/6] Adds back the logs for info and debug. --- .../reconnectplugin/PPReconnectWrapper.java | 22 +++++++++++++++++-- .../ReconnectPluginActivator.java | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java index ef50b68069..35b7b676e4 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java @@ -189,6 +189,7 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) if (logger.isTraceEnabled()) { logger.trace("Got Registered for " + pp); + traceCurrentPPState(); } } else if (state.equals(RegistrationState.CONNECTION_FAILED) @@ -220,6 +221,13 @@ else if (state.equals(RegistrationState.CONNECTION_FAILED) reconnect(currentReconnect != null ? currentReconnect.delay : -1); } + + if(logger.isTraceEnabled()) + { + logger.trace("Got Connection Failed for " + pp, + new Exception("tracing exception")); + traceCurrentPPState(); + } } else if (state.equals(RegistrationState.UNREGISTERED) || isServerReturnedErroneousInputEvent) @@ -237,6 +245,12 @@ else if (state.equals(RegistrationState.UNREGISTERED) // if currently reconnecting cancel cancelReconnect(); + + if(logger.isTraceEnabled()) + { + logger.trace("Got Unregistered for " + pp); + traceCurrentPPState(); + } } } catch(Throwable ex) @@ -255,6 +269,9 @@ private void cancelReconnect() { if (this.currentReconnect != null) { + if(logger.isInfoEnabled()) + logger.info("Cancel reconnect " + this.currentReconnect); + this.currentReconnect.cancel(); this.currentReconnect = null; } @@ -363,7 +380,7 @@ void unregister() public String toString() { StringBuilder builder = new StringBuilder(); - builder.append(super.toString()) + builder.append(getClass().getSimpleName()) .append("[provider=").append(provider) .append(", currentlyUnregistering=").append(currentlyUnregistering) .append(", currentReconnect=").append(currentReconnect) @@ -459,7 +476,8 @@ public void run() @Override public String toString() { - return super.toString() + "[delay=" + delay + "]"; + return ReconnectTask.class.getSimpleName() + + " [delay=" + delay + ", provider=" + provider + "]"; } } } diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java index 5e06644167..1f42248416 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/ReconnectPluginActivator.java @@ -530,7 +530,7 @@ static boolean anyConnectedInterfaces() * Trace prints of current status of the lists with protocol providers, * that are currently in interest of the reconnect plugin. */ - private void traceCurrentPPState() + static void traceCurrentPPState() { logger.trace("connectedInterfaces: " + connectedInterfaces); logger.trace("reconnectEnabledProviders: " From e481ed7ee629b834c1c76c947456c22d0c4975df Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 17 Jan 2020 13:56:52 +0000 Subject: [PATCH 5/6] Removes duplicate method. --- .../JabberAccountRegistrationForm.java | 2 +- .../service/protocol/jabber/JabberAccountID.java | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java index 43195efcf6..1c12148b90 100644 --- a/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java +++ b/src/net/java/sip/communicator/plugin/jabberaccregwizz/JabberAccountRegistrationForm.java @@ -423,7 +423,7 @@ public void loadAccount(JabberAccountRegistration accountReg) iceConfigPanel.setUseIce(accountReg.isUseIce()); - iceConfigPanel.setAutoDiscoverStun(accountReg.isAutoDiscoverStun()); + iceConfigPanel.setAutoDiscoverStun(accountReg.isStunServerDiscoveryEnabled()); iceConfigPanel.setUseDefaultStunServer( accountReg.isUseDefaultStunServer()); diff --git a/src/net/java/sip/communicator/service/protocol/jabber/JabberAccountID.java b/src/net/java/sip/communicator/service/protocol/jabber/JabberAccountID.java index bfc39138d0..644dba8ac5 100644 --- a/src/net/java/sip/communicator/service/protocol/jabber/JabberAccountID.java +++ b/src/net/java/sip/communicator/service/protocol/jabber/JabberAccountID.java @@ -360,17 +360,6 @@ public void setUseIce(boolean isUseIce) putAccountProperty(ProtocolProviderFactory.IS_USE_ICE, isUseIce); } - /** - * Indicates if the stun server should be automatically discovered. - * @return true if the stun server should be automatically - * discovered, otherwise returns false. - */ - public boolean isAutoDiscoverStun() - { - return getAccountPropertyBoolean( - ProtocolProviderFactory.AUTO_DISCOVER_STUN, true); - } - /** * Sets the autoDiscoverStun property. * @param isAutoDiscover true to indicate that stun server should From 15234fd8bbffadbeeb857c8995f291af13e14335 Mon Sep 17 00:00:00 2001 From: damencho Date: Fri, 17 Jan 2020 18:16:34 +0000 Subject: [PATCH 6/6] No need of an extra thread as we have now Timer per connection. --- .../reconnectplugin/PPReconnectWrapper.java | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java index 35b7b676e4..5caa9073d4 100644 --- a/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java +++ b/src/net/java/sip/communicator/plugin/reconnectplugin/PPReconnectWrapper.java @@ -440,36 +440,23 @@ private class ReconnectTask */ long delay; - /** - * The thread to execute this task. - */ - private Thread thread = null; - /** * Reconnects the provider. */ @Override public void run() { - if(thread == null || !Thread.currentThread().equals(thread)) - { - thread = new Thread(this); - thread.start(); - } - else + try { - try - { - if (logger.isInfoEnabled()) - logger.info("Start reconnecting " + provider); + if (logger.isInfoEnabled()) + logger.info("Start reconnecting " + provider); - provider.register( - getUIService().getDefaultSecurityAuthority(provider)); - } catch (OperationFailedException ex) - { - logger.error("cannot re-register provider will keep going", - ex); - } + provider.register( + getUIService().getDefaultSecurityAuthority(provider)); + } catch (OperationFailedException ex) + { + logger.error("cannot re-register provider will keep going", + ex); } }