From 35317a19bd373c3078ca249411de6668c295275e Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sun, 24 May 2015 17:18:48 +0200 Subject: [PATCH] Remove ConnectionListener from Socks5BytestreamManager and use weak references. Disabling the Socks5Manager every time the connection is terminated, and re-enabling it when it got connected again causes unwanted side effects. Like adding a new feature to the ServiceDiscoveryManager causes an update of the entity's capabilities, which then triggers a new outgoing presence (announcing the new caps version). SMACK-671 --- .../socks5/Socks5BytestreamManager.java | 59 +++++++------------ .../socks5/Socks5ClientForInitiator.java | 9 +-- 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java index 4145351b5..04bd3d9fe 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5BytestreamManager.java @@ -28,7 +28,7 @@ import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; -import org.jivesoftware.smack.AbstractConnectionClosedListener; +import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.FeatureNotSupportedException; @@ -86,7 +86,7 @@ import org.jivesoftware.smackx.filetransfer.FileTransferManager; * * @author Henning Staib */ -public final class Socks5BytestreamManager implements BytestreamManager { +public final class Socks5BytestreamManager extends Manager implements BytestreamManager { /* * create a new Socks5BytestreamManager and register a shutdown listener on every established @@ -98,22 +98,6 @@ public final class Socks5BytestreamManager implements BytestreamManager { public void connectionCreated(final XMPPConnection connection) { // create the manager for this connection Socks5BytestreamManager.getBytestreamManager(connection); - - // register shutdown listener - connection.addConnectionListener(new AbstractConnectionClosedListener() { - - @Override - public void connectionTerminated() { - Socks5BytestreamManager.getBytestreamManager(connection).disableService(); - } - - @Override - public void reconnectionSuccessful() { - // re-create the manager for this connection - Socks5BytestreamManager.getBytestreamManager(connection); - } - - }); } }); @@ -128,9 +112,6 @@ public final class Socks5BytestreamManager implements BytestreamManager { /* stores one Socks5BytestreamManager for each XMPP connection */ private final static Map managers = new HashMap(); - /* XMPP connection */ - private final XMPPConnection connection; - /* * assigns a user to a listener that is informed if a bytestream request for this user is * received @@ -185,7 +166,6 @@ public final class Socks5BytestreamManager implements BytestreamManager { if (manager == null) { manager = new Socks5BytestreamManager(connection); managers.put(connection, manager); - manager.activate(); } return manager; } @@ -196,8 +176,9 @@ public final class Socks5BytestreamManager implements BytestreamManager { * @param connection the XMPP connection */ private Socks5BytestreamManager(XMPPConnection connection) { - this.connection = connection; + super(connection); this.initiationListener = new InitiationListener(this); + activate(); } /** @@ -282,7 +263,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature. */ public synchronized void disableService() { - + XMPPConnection connection = connection(); // remove initiation packet listener connection.unregisterIQRequestHandler(initiationListener); @@ -299,7 +280,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { this.ignoredBytestreamRequests.clear(); // remove manager from static managers map - managers.remove(this.connection); + managers.remove(connection); // shutdown local SOCKS5 proxy if there are no more managers for other connections if (managers.size() == 0) { @@ -307,7 +288,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { } // remove feature from service discovery - ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); + ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); // check if service discovery is not already disposed by connection shutdown if (serviceDiscoveryManager != null) { @@ -423,7 +404,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { */ public Socks5BytestreamSession establishSession(String targetJID, String sessionID) throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException{ - + XMPPConnection connection = connection(); XMPPErrorException discoveryException = null; // check if target supports SOCKS5 Bytestream if (!supportsSocks5(targetJID)) { @@ -452,7 +433,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { } // compute digest - String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID); + String digest = Socks5Utils.createDigest(sessionID, connection.getUser(), targetJID); // prioritize last working SOCKS5 proxy if exists if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) { @@ -493,7 +474,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { // build SOCKS5 client Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest, - this.connection, sessionID, targetJID); + connection, sessionID, targetJID); // establish connection to proxy Socket socket = socks5Client.getSocket(getProxyConnectionTimeout()); @@ -503,7 +484,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { // negotiation successful, return the output stream return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals( - this.connection.getUser())); + connection.getUser())); } catch (TimeoutException e) { @@ -529,7 +510,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * @throws NotConnectedException */ private boolean supportsSocks5(String targetJID) throws NoResponseException, XMPPErrorException, NotConnectedException { - return ServiceDiscoveryManager.getInstanceFor(connection).supportsFeature(targetJID, Bytestream.NAMESPACE); + return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(targetJID, Bytestream.NAMESPACE); } /** @@ -542,12 +523,13 @@ public final class Socks5BytestreamManager implements BytestreamManager { * @throws NotConnectedException */ private List determineProxies() throws NoResponseException, XMPPErrorException, NotConnectedException { - ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); + XMPPConnection connection = connection(); + ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); List proxies = new ArrayList(); // get all items from XMPP server - DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(this.connection.getServiceName()); + DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(connection.getServiceName()); // query all items if they are SOCKS5 proxies for (Item item : discoverItems.getItems()) { @@ -590,6 +572,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * @return a list of stream hosts containing the IP address an the port */ private List determineStreamHostInfos(List proxies) { + XMPPConnection connection = connection(); List streamHosts = new ArrayList(); // add local proxy on first position if exists @@ -636,7 +619,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * is not running */ private List getLocalStreamHost() { - + XMPPConnection connection = connection(); // get local proxy singleton Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); @@ -704,7 +687,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { protected void replyRejectPacket(IQ packet) throws NotConnectedException { XMPPError xmppError = new XMPPError(XMPPError.Condition.not_acceptable); IQ errorIQ = IQ.createErrorResponse(packet, xmppError); - this.connection.sendStanza(errorIQ); + connection().sendStanza(errorIQ); } /** @@ -713,7 +696,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { */ private void activate() { // register bytestream initiation packet listener - connection.registerIQRequestHandler(initiationListener); + connection().registerIQRequestHandler(initiationListener); // enable SOCKS5 feature enableService(); @@ -723,7 +706,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * Adds the SOCKS5 Bytestream feature to the service discovery. */ private void enableService() { - ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection); + ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(connection()); manager.addFeature(Bytestream.NAMESPACE); } @@ -745,7 +728,7 @@ public final class Socks5BytestreamManager implements BytestreamManager { * @return the XMPP connection */ protected XMPPConnection getConnection() { - return this.connection; + return connection(); } /** diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java index 9653d78f8..d0a7c5897 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ClientForInitiator.java @@ -17,6 +17,7 @@ package org.jivesoftware.smackx.bytestreams.socks5; import java.io.IOException; +import java.lang.ref.WeakReference; import java.net.Socket; import java.util.concurrent.TimeoutException; @@ -41,7 +42,7 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost; class Socks5ClientForInitiator extends Socks5Client { /* the XMPP connection used to communicate with the SOCKS5 proxy */ - private XMPPConnection connection; + private WeakReference connection; /* the session ID used to activate SOCKS5 stream */ private String sessionID; @@ -61,7 +62,7 @@ class Socks5ClientForInitiator extends Socks5Client { public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection, String sessionID, String target) { super(streamHost, digest); - this.connection = connection; + this.connection = new WeakReference<>(connection); this.sessionID = sessionID; this.target = target; } @@ -71,7 +72,7 @@ class Socks5ClientForInitiator extends Socks5Client { Socket socket = null; // check if stream host is the local SOCKS5 proxy - if (this.streamHost.getJID().equals(this.connection.getUser())) { + if (this.streamHost.getJID().equals(this.connection.get().getUser())) { Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); socket = socks5Server.getSocket(this.digest); if (socket == null) { @@ -109,7 +110,7 @@ class Socks5ClientForInitiator extends Socks5Client { private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException { Bytestream activate = createStreamHostActivation(); // if activation fails #nextResultOrThrow() throws an exception - connection.createPacketCollectorAndSend(activate).nextResultOrThrow(); + connection.get().createPacketCollectorAndSend(activate).nextResultOrThrow(); } /**