1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-26 08:12:05 +01:00

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
This commit is contained in:
Florian Schmaus 2015-05-24 17:18:48 +02:00
parent 385798f9ba
commit 35317a19bd
2 changed files with 26 additions and 42 deletions

View file

@ -28,7 +28,7 @@ import java.util.Random;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException; 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;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException; import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
@ -86,7 +86,7 @@ import org.jivesoftware.smackx.filetransfer.FileTransferManager;
* *
* @author Henning Staib * @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 * 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) { public void connectionCreated(final XMPPConnection connection) {
// create the manager for this connection // create the manager for this connection
Socks5BytestreamManager.getBytestreamManager(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 */ /* stores one Socks5BytestreamManager for each XMPP connection */
private final static Map<XMPPConnection, Socks5BytestreamManager> managers = new HashMap<XMPPConnection, Socks5BytestreamManager>(); private final static Map<XMPPConnection, Socks5BytestreamManager> managers = new HashMap<XMPPConnection, Socks5BytestreamManager>();
/* XMPP connection */
private final XMPPConnection connection;
/* /*
* assigns a user to a listener that is informed if a bytestream request for this user is * assigns a user to a listener that is informed if a bytestream request for this user is
* received * received
@ -185,7 +166,6 @@ public final class Socks5BytestreamManager implements BytestreamManager {
if (manager == null) { if (manager == null) {
manager = new Socks5BytestreamManager(connection); manager = new Socks5BytestreamManager(connection);
managers.put(connection, manager); managers.put(connection, manager);
manager.activate();
} }
return manager; return manager;
} }
@ -196,8 +176,9 @@ public final class Socks5BytestreamManager implements BytestreamManager {
* @param connection the XMPP connection * @param connection the XMPP connection
*/ */
private Socks5BytestreamManager(XMPPConnection connection) { private Socks5BytestreamManager(XMPPConnection connection) {
this.connection = connection; super(connection);
this.initiationListener = new InitiationListener(this); 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. * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature.
*/ */
public synchronized void disableService() { public synchronized void disableService() {
XMPPConnection connection = connection();
// remove initiation packet listener // remove initiation packet listener
connection.unregisterIQRequestHandler(initiationListener); connection.unregisterIQRequestHandler(initiationListener);
@ -299,7 +280,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
this.ignoredBytestreamRequests.clear(); this.ignoredBytestreamRequests.clear();
// remove manager from static managers map // 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 // shutdown local SOCKS5 proxy if there are no more managers for other connections
if (managers.size() == 0) { if (managers.size() == 0) {
@ -307,7 +288,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
} }
// remove feature from service discovery // 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 // check if service discovery is not already disposed by connection shutdown
if (serviceDiscoveryManager != null) { if (serviceDiscoveryManager != null) {
@ -423,7 +404,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
*/ */
public Socks5BytestreamSession establishSession(String targetJID, String sessionID) public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException{ throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException{
XMPPConnection connection = connection();
XMPPErrorException discoveryException = null; XMPPErrorException discoveryException = null;
// check if target supports SOCKS5 Bytestream // check if target supports SOCKS5 Bytestream
if (!supportsSocks5(targetJID)) { if (!supportsSocks5(targetJID)) {
@ -452,7 +433,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
} }
// compute digest // 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 // prioritize last working SOCKS5 proxy if exists
if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) { if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
@ -493,7 +474,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
// build SOCKS5 client // build SOCKS5 client
Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest, Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
this.connection, sessionID, targetJID); connection, sessionID, targetJID);
// establish connection to proxy // establish connection to proxy
Socket socket = socks5Client.getSocket(getProxyConnectionTimeout()); Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
@ -503,7 +484,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
// negotiation successful, return the output stream // negotiation successful, return the output stream
return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals( return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(
this.connection.getUser())); connection.getUser()));
} }
catch (TimeoutException e) { catch (TimeoutException e) {
@ -529,7 +510,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
* @throws NotConnectedException * @throws NotConnectedException
*/ */
private boolean supportsSocks5(String targetJID) throws NoResponseException, XMPPErrorException, 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 * @throws NotConnectedException
*/ */
private List<String> determineProxies() throws NoResponseException, XMPPErrorException, NotConnectedException { private List<String> determineProxies() throws NoResponseException, XMPPErrorException, NotConnectedException {
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); XMPPConnection connection = connection();
ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
List<String> proxies = new ArrayList<String>(); List<String> proxies = new ArrayList<String>();
// get all items from XMPP server // 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 // query all items if they are SOCKS5 proxies
for (Item item : discoverItems.getItems()) { 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 * @return a list of stream hosts containing the IP address an the port
*/ */
private List<StreamHost> determineStreamHostInfos(List<String> proxies) { private List<StreamHost> determineStreamHostInfos(List<String> proxies) {
XMPPConnection connection = connection();
List<StreamHost> streamHosts = new ArrayList<StreamHost>(); List<StreamHost> streamHosts = new ArrayList<StreamHost>();
// add local proxy on first position if exists // add local proxy on first position if exists
@ -636,7 +619,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
* is not running * is not running
*/ */
private List<StreamHost> getLocalStreamHost() { private List<StreamHost> getLocalStreamHost() {
XMPPConnection connection = connection();
// get local proxy singleton // get local proxy singleton
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
@ -704,7 +687,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
protected void replyRejectPacket(IQ packet) throws NotConnectedException { protected void replyRejectPacket(IQ packet) throws NotConnectedException {
XMPPError xmppError = new XMPPError(XMPPError.Condition.not_acceptable); XMPPError xmppError = new XMPPError(XMPPError.Condition.not_acceptable);
IQ errorIQ = IQ.createErrorResponse(packet, xmppError); 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() { private void activate() {
// register bytestream initiation packet listener // register bytestream initiation packet listener
connection.registerIQRequestHandler(initiationListener); connection().registerIQRequestHandler(initiationListener);
// enable SOCKS5 feature // enable SOCKS5 feature
enableService(); enableService();
@ -723,7 +706,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
* Adds the SOCKS5 Bytestream feature to the service discovery. * Adds the SOCKS5 Bytestream feature to the service discovery.
*/ */
private void enableService() { private void enableService() {
ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection); ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(connection());
manager.addFeature(Bytestream.NAMESPACE); manager.addFeature(Bytestream.NAMESPACE);
} }
@ -745,7 +728,7 @@ public final class Socks5BytestreamManager implements BytestreamManager {
* @return the XMPP connection * @return the XMPP connection
*/ */
protected XMPPConnection getConnection() { protected XMPPConnection getConnection() {
return this.connection; return connection();
} }
/** /**

View file

@ -17,6 +17,7 @@
package org.jivesoftware.smackx.bytestreams.socks5; package org.jivesoftware.smackx.bytestreams.socks5;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.Socket; import java.net.Socket;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@ -41,7 +42,7 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
class Socks5ClientForInitiator extends Socks5Client { class Socks5ClientForInitiator extends Socks5Client {
/* the XMPP connection used to communicate with the SOCKS5 proxy */ /* the XMPP connection used to communicate with the SOCKS5 proxy */
private XMPPConnection connection; private WeakReference<XMPPConnection> connection;
/* the session ID used to activate SOCKS5 stream */ /* the session ID used to activate SOCKS5 stream */
private String sessionID; private String sessionID;
@ -61,7 +62,7 @@ class Socks5ClientForInitiator extends Socks5Client {
public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection, public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection,
String sessionID, String target) { String sessionID, String target) {
super(streamHost, digest); super(streamHost, digest);
this.connection = connection; this.connection = new WeakReference<>(connection);
this.sessionID = sessionID; this.sessionID = sessionID;
this.target = target; this.target = target;
} }
@ -71,7 +72,7 @@ class Socks5ClientForInitiator extends Socks5Client {
Socket socket = null; Socket socket = null;
// check if stream host is the local SOCKS5 proxy // 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(); Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
socket = socks5Server.getSocket(this.digest); socket = socks5Server.getSocket(this.digest);
if (socket == null) { if (socket == null) {
@ -109,7 +110,7 @@ class Socks5ClientForInitiator extends Socks5Client {
private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException { private void activate() throws NoResponseException, XMPPErrorException, NotConnectedException {
Bytestream activate = createStreamHostActivation(); Bytestream activate = createStreamHostActivation();
// if activation fails #nextResultOrThrow() throws an exception // if activation fails #nextResultOrThrow() throws an exception
connection.createPacketCollectorAndSend(activate).nextResultOrThrow(); connection.get().createPacketCollectorAndSend(activate).nextResultOrThrow();
} }
/** /**