From 70326881237d3965a90177d0da42f12be2df068b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 17 Jul 2015 08:50:19 +0200 Subject: [PATCH] Rework Proxy API Instead of extending SocketFactory, the proxy support classes now implement ProxySocketConnection. This removes a lot of unnecessary code. Also re-enables proxy support, which was broken in previous versions because none of extended SocketFactories did override createSocket() (SMACK-683). --- .../smack/bosh/BOSHConfiguration.java | 8 ++- .../smack/ConnectionConfiguration.java | 18 ++--- .../smack/proxy/DirectSocketFactory.java | 70 ------------------- ...ry.java => HTTPProxySocketConnection.java} | 54 +++----------- .../jivesoftware/smack/proxy/ProxyInfo.java | 51 +++++--------- .../smack/proxy/ProxySocketConnection.java | 28 ++++++++ ....java => Socks4ProxySocketConnection.java} | 69 ++++-------------- ....java => Socks5ProxySocketConnection.java} | 62 +++------------- .../smack/tcp/XMPPTCPConnection.java | 10 ++- 9 files changed, 104 insertions(+), 266 deletions(-) delete mode 100644 smack-core/src/main/java/org/jivesoftware/smack/proxy/DirectSocketFactory.java rename smack-core/src/main/java/org/jivesoftware/smack/proxy/{HTTPProxySocketFactory.java => HTTPProxySocketConnection.java} (73%) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxySocketConnection.java rename smack-core/src/main/java/org/jivesoftware/smack/proxy/{Socks4ProxySocketFactory.java => Socks4ProxySocketConnection.java} (73%) rename smack-core/src/main/java/org/jivesoftware/smack/proxy/{Socks5ProxySocketFactory.java => Socks5ProxySocketConnection.java} (87%) diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java index 58646dd45..92615f32e 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/BOSHConfiguration.java @@ -37,6 +37,12 @@ public final class BOSHConfiguration extends ConnectionConfiguration { private BOSHConfiguration(Builder builder) { super(builder); + if (proxy != null) { + if (proxy.getProxyType() != ProxyInfo.ProxyType.HTTP) { + throw new IllegalArgumentException( + "Only HTTP proxies are support with BOSH connections"); + } + } https = builder.https; if (builder.file.charAt(0) != '/') { file = '/' + builder.file; @@ -46,7 +52,7 @@ public final class BOSHConfiguration extends ConnectionConfiguration { } public boolean isProxyEnabled() { - return (proxy != null && proxy.getProxyType() != ProxyInfo.ProxyType.NONE); + return proxy != null; } public ProxyInfo getProxyInfo() { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java index d9360efa2..f4b781a56 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java @@ -125,14 +125,7 @@ public abstract class ConnectionConfiguration { port = builder.port; proxy = builder.proxy; - if (proxy != null) { - if (builder.socketFactory != null) { - throw new IllegalArgumentException("Can not use proxy together with custom socket factory"); - } - socketFactory = proxy.getSocketFactory(); - } else { - socketFactory = builder.socketFactory; - } + socketFactory = builder.socketFactory; securityMode = builder.securityMode; keystoreType = builder.keystoreType; @@ -300,6 +293,15 @@ public abstract class ConnectionConfiguration { return this.socketFactory; } + /** + * Get the configured proxy information (if any). + * + * @return the configured proxy information or null. + */ + public ProxyInfo getProxyInfo() { + return proxy; + } + /** * An enumeration for TLS security modes that are available when making a connection * to the XMPP server. diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/DirectSocketFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/DirectSocketFactory.java deleted file mode 100644 index a62158720..000000000 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/DirectSocketFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * - * Copyright the original author or authors - * - * 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 org.jivesoftware.smack.proxy; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.Socket; -import java.net.UnknownHostException; -import javax.net.SocketFactory; - -/** - * SocketFactory for direct connection - * - * @author Atul Aggarwal - */ -class DirectSocketFactory - extends SocketFactory -{ - - public DirectSocketFactory() - { - } - - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException - { - Socket newSocket = new Socket(Proxy.NO_PROXY); - newSocket.connect(new InetSocketAddress(host,port)); - return newSocket; - } - - public Socket createSocket(String host ,int port, InetAddress localHost, - int localPort) - throws IOException, UnknownHostException - { - return new Socket(host,port,localHost,localPort); - } - - public Socket createSocket(InetAddress host, int port) - throws IOException - { - Socket newSocket = new Socket(Proxy.NO_PROXY); - newSocket.connect(new InetSocketAddress(host,port)); - return newSocket; - } - - public Socket createSocket( InetAddress address, int port, - InetAddress localAddress, int localPort) - throws IOException - { - return new Socket(address,port,localAddress,localPort); - } - -} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java similarity index 73% rename from smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketFactory.java rename to smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java index 3b9b3fa5c..6087f09ca 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/HTTPProxySocketConnection.java @@ -22,10 +22,8 @@ import java.io.InputStream; import java.io.StringReader; import java.net.HttpURLConnection; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; import org.jivesoftware.smack.util.stringencoder.Base64; @@ -33,56 +31,26 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Http Proxy Socket Factory which returns socket connected to Http Proxy + * HTTP Proxy Socket Connection which connects the socket using a HTTP Proxy. * * @author Atul Aggarwal */ -class HTTPProxySocketFactory - extends SocketFactory -{ +class HTTPProxySocketConnection implements ProxySocketConnection { - private ProxyInfo proxy; + private final ProxyInfo proxy; - public HTTPProxySocketFactory(ProxyInfo proxy) + HTTPProxySocketConnection(ProxyInfo proxy) { this.proxy = proxy; } - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException - { - return httpProxifiedSocket(host, port); - } - - public Socket createSocket(String host ,int port, InetAddress localHost, - int localPort) - throws IOException, UnknownHostException - { - return httpProxifiedSocket(host, port); - } - - public Socket createSocket(InetAddress host, int port) - throws IOException - { - return httpProxifiedSocket(host.getHostAddress(), port); - - } - - public Socket createSocket( InetAddress address, int port, - InetAddress localAddress, int localPort) - throws IOException - { - return httpProxifiedSocket(address.getHostAddress(), port); - } - - private Socket httpProxifiedSocket(String host, int port) - throws IOException - { + @Override + public void connect(Socket socket, InetAddress inetAddress, int port, int timeout) + throws IOException { String proxyhost = proxy.getProxyAddress(); int proxyPort = proxy.getProxyPort(); - @SuppressWarnings("resource") - Socket socket = new Socket(proxyhost,proxyPort); - String hostport = "CONNECT " + host + ":" + port; + socket.connect(new InetSocketAddress(proxyhost, proxyPort)); + String hostport = "CONNECT " + inetAddress.getCanonicalHostName() + ":" + port; String proxyLine; String username = proxy.getProxyUsername(); if (username == null) @@ -164,8 +132,6 @@ class HTTPProxySocketFactory { throw new ProxyException(ProxyInfo.ProxyType.HTTP); } - - return socket; } private static final Pattern RESPONSE_PATTERN diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxyInfo.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxyInfo.java index c1b0ad943..1807dbf05 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxyInfo.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxyInfo.java @@ -16,8 +16,6 @@ */ package org.jivesoftware.smack.proxy; -import javax.net.SocketFactory; - /** * Class which stores proxy information such as proxy type, host, port, * authentication etc. @@ -29,7 +27,6 @@ public class ProxyInfo { public static enum ProxyType { - NONE, HTTP, SOCKS4, SOCKS5 @@ -40,6 +37,7 @@ public class ProxyInfo private String proxyUsername; private String proxyPassword; private ProxyType proxyType; + private final ProxySocketConnection proxySocketConnection; public ProxyInfo( ProxyType pType, String pHost, int pPort, String pUser, String pPass) @@ -49,6 +47,19 @@ public class ProxyInfo this.proxyPort = pPort; this.proxyUsername = pUser; this.proxyPassword = pPass; + switch (proxyType) { + case HTTP: + proxySocketConnection = new HTTPProxySocketConnection(this); + break; + case SOCKS4: + proxySocketConnection = new Socks4ProxySocketConnection(this); + break; + case SOCKS5: + proxySocketConnection = new Socks5ProxySocketConnection(this); + break; + default: + throw new IllegalStateException(); + } } public static ProxyInfo forHttpProxy(String pHost, int pPort, String pUser, @@ -69,16 +80,6 @@ public class ProxyInfo return new ProxyInfo(ProxyType.SOCKS5, pHost, pPort, pUser, pPass); } - public static ProxyInfo forNoProxy() - { - return new ProxyInfo(ProxyType.NONE, null, 0, null, null); - } - - public static ProxyInfo forDefaultProxy() - { - return new ProxyInfo(ProxyType.NONE, null, 0, null, null); - } - public ProxyType getProxyType() { return proxyType; @@ -104,27 +105,7 @@ public class ProxyInfo return proxyPassword; } - public SocketFactory getSocketFactory() - { - if(proxyType == ProxyType.NONE) - { - return new DirectSocketFactory(); - } - else if(proxyType == ProxyType.HTTP) - { - return new HTTPProxySocketFactory(this); - } - else if(proxyType == ProxyType.SOCKS4) - { - return new Socks4ProxySocketFactory(this); - } - else if(proxyType == ProxyType.SOCKS5) - { - return new Socks5ProxySocketFactory(this); - } - else - { - return null; - } + public ProxySocketConnection getProxySocketConnection() { + return proxySocketConnection; } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxySocketConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxySocketConnection.java new file mode 100644 index 000000000..75ce286df --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/ProxySocketConnection.java @@ -0,0 +1,28 @@ +/** + * + * Copyright 2015 Florian Schmaus. + * + * 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 org.jivesoftware.smack.proxy; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; + +public interface ProxySocketConnection { + + public void connect(Socket socket, InetAddress inetAddress, int port, int timeout) + throws IOException; + +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketConnection.java similarity index 73% rename from smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketFactory.java rename to smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketConnection.java index 85857c10f..cf0c354c9 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks4ProxySocketConnection.java @@ -20,59 +20,25 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; /** * Socket factory for socks4 proxy. * * @author Atul Aggarwal */ -public class Socks4ProxySocketFactory - extends SocketFactory -{ - private ProxyInfo proxy; +public class Socks4ProxySocketConnection implements ProxySocketConnection { + private final ProxyInfo proxy; - public Socks4ProxySocketFactory(ProxyInfo proxy) + Socks4ProxySocketConnection(ProxyInfo proxy) { this.proxy = proxy; } - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException - { - return socks4ProxifiedSocket(host,port); - - } - - public Socket createSocket(String host ,int port, InetAddress localHost, - int localPort) - throws IOException, UnknownHostException - { - return socks4ProxifiedSocket(host,port); - } - - public Socket createSocket(InetAddress host, int port) - throws IOException - { - return socks4ProxifiedSocket(host.getHostAddress(),port); - } - - public Socket createSocket( InetAddress address, int port, - InetAddress localAddress, int localPort) - throws IOException - { - return socks4ProxifiedSocket(address.getHostAddress(),port); - - } - - @SuppressWarnings("resource") - private Socket socks4ProxifiedSocket(String host, int port) - throws IOException - { - Socket socket = null; + @Override + public void connect(Socket socket, InetAddress inetAddress, int port, int timeout) + throws IOException { InputStream in = null; OutputStream out = null; String proxy_host = proxy.getProxyAddress(); @@ -81,7 +47,7 @@ public class Socks4ProxySocketFactory try { - socket=new Socket(proxy_host, proxy_port); + socket.connect(new InetSocketAddress(proxy_host, proxy_port), timeout); in=socket.getInputStream(); out=socket.getOutputStream(); socket.setTcpNoDelay(true); @@ -114,19 +80,10 @@ public class Socks4ProxySocketFactory buf[index++]=(byte)(port>>>8); buf[index++]=(byte)(port&0xff); - try + byte[] byteAddress = inetAddress.getAddress(); + for (int i = 0; i < byteAddress.length; i++) { - InetAddress addr=InetAddress.getByName(host); - byte[] byteAddress = addr.getAddress(); - for (int i = 0; i < byteAddress.length; i++) - { - buf[index++]=byteAddress[i]; - } - } - catch(UnknownHostException uhe) - { - throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, - uhe.toString(), uhe); + buf[index++]=byteAddress[i]; } if(user!=null) @@ -195,7 +152,6 @@ public class Socks4ProxySocketFactory } byte[] temp = new byte[2]; in.read(temp, 0, 2); - return socket; } catch(RuntimeException e) { @@ -205,7 +161,7 @@ public class Socks4ProxySocketFactory { try { - if(socket!=null)socket.close(); + socket.close(); } catch(Exception eee) { @@ -213,4 +169,5 @@ public class Socks4ProxySocketFactory throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, e.toString()); } } + } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketConnection.java similarity index 87% rename from smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketFactory.java rename to smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketConnection.java index 03d8f6b18..4d71559d3 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/proxy/Socks5ProxySocketConnection.java @@ -20,61 +20,25 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; -import javax.net.SocketFactory; /** * Socket factory for Socks5 proxy. * * @author Atul Aggarwal */ -public class Socks5ProxySocketFactory - extends SocketFactory -{ - private ProxyInfo proxy; +public class Socks5ProxySocketConnection implements ProxySocketConnection { + private final ProxyInfo proxy; - public Socks5ProxySocketFactory(ProxyInfo proxy) + Socks5ProxySocketConnection(ProxyInfo proxy) { this.proxy = proxy; } - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException - { - return socks5ProxifiedSocket(host,port); - } - - public Socket createSocket(String host ,int port, InetAddress localHost, - int localPort) - throws IOException, UnknownHostException - { - - return socks5ProxifiedSocket(host,port); - - } - - public Socket createSocket(InetAddress host, int port) - throws IOException - { - - return socks5ProxifiedSocket(host.getHostAddress(),port); - - } - - public Socket createSocket( InetAddress address, int port, - InetAddress localAddress, int localPort) - throws IOException - { - - return socks5ProxifiedSocket(address.getHostAddress(),port); - - } - - private Socket socks5ProxifiedSocket(String host, int port) - throws IOException - { - Socket socket = null; + @Override + public void connect(Socket socket, InetAddress inetAddress, int port, int timeout) + throws IOException { InputStream in = null; OutputStream out = null; String proxy_host = proxy.getProxyAddress(); @@ -84,7 +48,7 @@ public class Socks5ProxySocketFactory try { - socket=new Socket(proxy_host, proxy_port); + socket.connect(new InetSocketAddress(proxy_host, proxy_port), timeout); in=socket.getInputStream(); out=socket.getOutputStream(); @@ -247,7 +211,7 @@ public class Socks5ProxySocketFactory buf[index++]=1; // CONNECT buf[index++]=0; - byte[] hostb=host.getBytes(); + byte[] hostb= inetAddress.getCanonicalHostName().getBytes(); int len=hostb.length; buf[index++]=3; // DOMAINNAME buf[index++]=(byte)(len); @@ -327,8 +291,6 @@ public class Socks5ProxySocketFactory break; default: } - return socket; - } catch(RuntimeException e) { @@ -338,10 +300,7 @@ public class Socks5ProxySocketFactory { try { - if(socket!=null) - { - socket.close(); - } + socket.close(); } catch(Exception eee) { @@ -371,4 +330,5 @@ public class Socks5ProxySocketFactory s+=i; } } + } diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index fbb58d667..9f4a1f1fc 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -68,6 +68,7 @@ import org.jivesoftware.smack.sm.predicates.Predicate; import org.jivesoftware.smack.sm.provider.ParseStreamManagement; import org.jivesoftware.smack.packet.Nonza; import org.jivesoftware.smack.packet.XMPPError; +import org.jivesoftware.smack.proxy.ProxyInfo; import org.jivesoftware.smack.util.ArrayBlockingQueueWithShutdown; import org.jivesoftware.smack.util.Async; import org.jivesoftware.smack.util.PacketParserUtils; @@ -531,6 +532,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { private void connectUsingConfiguration() throws IOException, ConnectionException { List failedAddresses = populateHostAddresses(); SocketFactory socketFactory = config.getSocketFactory(); + ProxyInfo proxyInfo = config.getProxyInfo(); + int timeout = config.getConnectTimeout(); if (socketFactory == null) { socketFactory = SocketFactory.getDefault(); } @@ -550,7 +553,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { final String inetAddressAndPort = inetAddress + " at port " + port; LOGGER.finer("Trying to establish TCP connection to " + inetAddressAndPort); try { - socket.connect(new InetSocketAddress(inetAddress, port), config.getConnectTimeout()); + if (proxyInfo == null) { + socket.connect(new InetSocketAddress(inetAddress, port), timeout); + } + else { + proxyInfo.getProxySocketConnection().connect(socket, inetAddress, port, timeout); + } } catch (Exception e) { if (inetAddresses.hasNext()) { continue innerloop;