mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 14:22: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:
parent
385798f9ba
commit
35317a19bd
2 changed files with 26 additions and 42 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue