diff options
author | Mark Spruiell <mes@zeroc.com> | 2013-04-11 16:06:49 -0700 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2013-04-11 16:06:49 -0700 |
commit | 5b0880e399cffc38f83f7a610ef68d4c6af65b2d (patch) | |
tree | b7bd2e8a67e779ab8578ba06c30b1ae9d31a898e /java/src | |
parent | Fixed (ICE-5327) - Using completed or sent as variable names causes badness (diff) | |
download | ice-5b0880e399cffc38f83f7a610ef68d4c6af65b2d.tar.bz2 ice-5b0880e399cffc38f83f7a610ef68d4c6af65b2d.tar.xz ice-5b0880e399cffc38f83f7a610ef68d4c6af65b2d.zip |
SOCKS support for Java
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/Ice/ConnectionI.java | 2 | ||||
-rw-r--r-- | java/src/IceInternal/EndpointHostResolver.java | 58 | ||||
-rw-r--r-- | java/src/IceInternal/EndpointI.java | 22 | ||||
-rw-r--r-- | java/src/IceInternal/Instance.java | 24 | ||||
-rw-r--r-- | java/src/IceInternal/Network.java | 77 | ||||
-rw-r--r-- | java/src/IceInternal/NetworkProxy.java | 48 | ||||
-rw-r--r-- | java/src/IceInternal/ProtocolPluginFacade.java | 5 | ||||
-rw-r--r-- | java/src/IceInternal/ProtocolPluginFacadeI.java | 8 | ||||
-rw-r--r-- | java/src/IceInternal/SOCKSNetworkProxy.java | 104 | ||||
-rw-r--r-- | java/src/IceInternal/TcpAcceptor.java | 2 | ||||
-rw-r--r-- | java/src/IceInternal/TcpConnector.java | 20 | ||||
-rw-r--r-- | java/src/IceInternal/TcpEndpointI.java | 25 | ||||
-rw-r--r-- | java/src/IceInternal/TcpTransceiver.java | 180 | ||||
-rw-r--r-- | java/src/IceInternal/Transceiver.java | 2 | ||||
-rw-r--r-- | java/src/IceInternal/UdpEndpointI.java | 25 | ||||
-rw-r--r-- | java/src/IceInternal/UdpTransceiver.java | 2 | ||||
-rw-r--r-- | java/src/IceSSL/AcceptorI.java | 2 | ||||
-rw-r--r-- | java/src/IceSSL/ConnectorI.java | 13 | ||||
-rw-r--r-- | java/src/IceSSL/EndpointI.java | 25 | ||||
-rw-r--r-- | java/src/IceSSL/TransceiverI.java | 266 |
20 files changed, 732 insertions, 178 deletions
diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java index f597ee65ec9..cf74ec87305 100644 --- a/java/src/Ice/ConnectionI.java +++ b/java/src/Ice/ConnectionI.java @@ -1930,7 +1930,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne private boolean initialize(int operation) { - int s = _transceiver.initialize(); + int s = _transceiver.initialize(_readStream.getBuffer(), _writeStream.getBuffer()); if(s != IceInternal.SocketOperation.None) { scheduleTimeout(s, connectTimeout()); diff --git a/java/src/IceInternal/EndpointHostResolver.java b/java/src/IceInternal/EndpointHostResolver.java index b5908e3d28a..25f144c66a5 100644 --- a/java/src/IceInternal/EndpointHostResolver.java +++ b/java/src/IceInternal/EndpointHostResolver.java @@ -34,9 +34,24 @@ public class EndpointHostResolver } } - public java.util.List<Connector> + public java.util.List<Connector> resolve(String host, int port, Ice.EndpointSelectionType selType, EndpointI endpoint) { + // + // Try to get the addresses without DNS lookup. If this doesn't + // work, we retry with DNS lookup (and observer). + // + NetworkProxy networkProxy = _instance.networkProxy(); + if(networkProxy == null) + { + java.util.List<java.net.InetSocketAddress> addrs = + Network.getAddresses(host, port, _protocol, selType, _preferIPv6); + if(!addrs.isEmpty()) + { + return endpoint.connectors(addrs, null); + } + } + Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer; Ice.Instrumentation.Observer observer = null; if(obsv != null) @@ -47,11 +62,17 @@ public class EndpointHostResolver observer.attach(); } } - + java.util.List<Connector> connectors = null; - try + try { - connectors = endpoint.connectors(Network.getAddresses(host, port, _protocol, selType, _preferIPv6)); + if(networkProxy != null) + { + networkProxy = networkProxy.resolveHost(); + } + + connectors = endpoint.connectors(Network.getAddresses(host, port, _protocol, selType, _preferIPv6), + networkProxy); } catch(Ice.LocalException ex) { @@ -70,7 +91,7 @@ public class EndpointHostResolver } return connectors; } - + synchronized public void resolve(String host, int port, Ice.EndpointSelectionType selType, EndpointI endpoint, EndpointI_connectors callback) { @@ -163,19 +184,26 @@ public class EndpointHostResolver { if(threadObserver != null) { - threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle, + threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateIdle, Ice.Instrumentation.ThreadState.ThreadStateInUseForOther); } - r.callback.connectors(r.endpoint.connectors(Network.getAddresses(r.host, - r.port, - _protocol, + NetworkProxy networkProxy = _instance.networkProxy(); + if(networkProxy != null) + { + networkProxy = networkProxy.resolveHost(); + } + + r.callback.connectors(r.endpoint.connectors(Network.getAddresses(r.host, + r.port, + _protocol, r.selType, - _preferIPv6))); + _preferIPv6), + networkProxy)); if(threadObserver != null) { - threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther, + threadObserver.stateChanged(Ice.Instrumentation.ThreadState.ThreadStateInUseForOther, Ice.Instrumentation.ThreadState.ThreadStateIdle); } } @@ -215,9 +243,9 @@ public class EndpointHostResolver Ice.Instrumentation.CommunicatorObserver obsv = _instance.initializationData().observer; if(obsv != null) { - _observer = obsv.getThreadObserver("Communicator", - _thread.getName(), - Ice.Instrumentation.ThreadState.ThreadStateIdle, + _observer = obsv.getThreadObserver("Communicator", + _thread.getName(), + Ice.Instrumentation.ThreadState.ThreadStateIdle, _observer); if(_observer != null) { @@ -242,7 +270,7 @@ public class EndpointHostResolver private boolean _destroyed; private java.util.LinkedList<ResolveEntry> _queue = new java.util.LinkedList<ResolveEntry>(); private Ice.Instrumentation.ThreadObserver _observer; - + private final class HelperThread extends Thread { HelperThread() diff --git a/java/src/IceInternal/EndpointI.java b/java/src/IceInternal/EndpointI.java index ed4cd9aa195..c50499ac481 100644 --- a/java/src/IceInternal/EndpointI.java +++ b/java/src/IceInternal/EndpointI.java @@ -126,6 +126,17 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En // public abstract boolean equivalent(EndpointI endpoint); + public java.util.List<Connector> + connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) + { + // + // This method must be extended by endpoints which use the EndpointHostResolver to create + // connectors from IP addresses. + // + assert(false); + return null; + } + // // Compare endpoints for sorting purposes. // @@ -148,16 +159,5 @@ abstract public class EndpointI implements Ice.Endpoint, java.lang.Comparable<En return 0; } - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses) - { - // - // This method must be extended by endpoints which use the EndpointHostResolver to create - // connectors from IP addresses. - // - assert(false); - return null; - } - protected String _connectionId = ""; } diff --git a/java/src/IceInternal/Instance.java b/java/src/IceInternal/Instance.java index ac49c4cd576..bd20af30ff6 100644 --- a/java/src/IceInternal/Instance.java +++ b/java/src/IceInternal/Instance.java @@ -189,6 +189,12 @@ public final class Instance return _preferIPv6; } + public NetworkProxy + networkProxy() + { + return _networkProxy; + } + public synchronized ThreadPool clientThreadPool() { @@ -760,8 +766,17 @@ public final class Instance _proxyFactory = new ProxyFactory(this); + final String proxyHost = _initData.properties.getProperty("Ice.SOCKSProxyHost"); + int defaultIPv6 = 1; // IPv6 enabled by default. + if(proxyHost.length() > 0) + { + final int proxyPort = _initData.properties.getPropertyAsIntWithDefault("Ice.SOCKSProxyPort", 1080); + _networkProxy = new SOCKSNetworkProxy(proxyHost, proxyPort); + defaultIPv6 = 0; // IPv6 is not supported with SOCKS + } + boolean ipv4 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv4", 1) > 0; - boolean ipv6 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv6", 1) > 0; + boolean ipv6 = _initData.properties.getPropertyAsIntWithDefault("Ice.IPv6", defaultIPv6) > 0; if(!ipv4 && !ipv6) { throw new Ice.InitializationException("Both IPV4 and IPv6 support cannot be disabled."); @@ -779,6 +794,12 @@ public final class Instance _protocolSupport = Network.EnableIPv6; } _preferIPv6 = _initData.properties.getPropertyAsInt("Ice.PreferIPv6Address") > 0; + + if(ipv6 && _networkProxy instanceof SOCKSNetworkProxy) + { + throw new Ice.InitializationException("IPv6 is not supported with SOCKS4 proxies"); + } + _endpointFactoryManager = new EndpointFactoryManager(this); EndpointFactory tcpEndpointFactory = new TcpEndpointFactory(this); _endpointFactoryManager.add(tcpEndpointFactory); @@ -1204,6 +1225,7 @@ public final class Instance private ObjectAdapterFactory _objectAdapterFactory; private int _protocolSupport; private boolean _preferIPv6; + private NetworkProxy _networkProxy; private ThreadPool _clientThreadPool; private ThreadPool _serverThreadPool; private EndpointHostResolver _endpointHostResolver; diff --git a/java/src/IceInternal/Network.java b/java/src/IceInternal/Network.java index c406ef7b893..e37abd25c75 100644 --- a/java/src/IceInternal/Network.java +++ b/java/src/IceInternal/Network.java @@ -1041,6 +1041,41 @@ public final class Network } public static String + fdToString(java.nio.channels.SelectableChannel fd, NetworkProxy proxy, java.net.InetSocketAddress target) + { + if(fd == null) + { + return "<closed>"; + } + + java.net.InetAddress localAddr = null, remoteAddr = null; + int localPort = -1, remotePort = -1; + + if(fd instanceof java.nio.channels.SocketChannel) + { + java.net.Socket socket = ((java.nio.channels.SocketChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else if(fd instanceof java.nio.channels.DatagramChannel) + { + java.net.DatagramSocket socket = ((java.nio.channels.DatagramChannel)fd).socket(); + localAddr = socket.getLocalAddress(); + localPort = socket.getLocalPort(); + remoteAddr = socket.getInetAddress(); + remotePort = socket.getPort(); + } + else + { + assert(false); + } + + return addressesToString(localAddr, localPort, remoteAddr, remotePort, proxy, target); + } + + public static String fdToString(java.nio.channels.SelectableChannel fd) { if(fd == null) @@ -1092,25 +1127,57 @@ public final class Network } public static String - addressesToString(java.net.InetAddress localAddr, int localPort, java.net.InetAddress remoteAddr, int remotePort) + addressesToString(java.net.InetAddress localAddr, int localPort, java.net.InetAddress remoteAddr, int remotePort, + NetworkProxy proxy, java.net.InetSocketAddress target) { StringBuilder s = new StringBuilder(128); s.append("local address = "); s.append(addrToString(localAddr, localPort)); - if(remoteAddr == null) + + if(proxy != null) { - s.append("\nremote address = <not connected>"); + if(remoteAddr == null) + { + java.net.InetSocketAddress addr = proxy.getAddress(); + remoteAddr = addr.getAddress(); + remotePort = addr.getPort(); + } + s.append("\n"); + s.append(proxy.getName()); + s.append(" proxy address = "); + s.append(addrToString(remoteAddr, remotePort)); + s.append("\nremote address = "); + s.append(addrToString(target.getAddress(), target.getPort())); } else { - s.append("\nremote address = "); - s.append(addrToString(remoteAddr, remotePort)); + if(remoteAddr == null && target != null) + { + remoteAddr = target.getAddress(); + remotePort = target.getPort(); + } + + if(remoteAddr == null) + { + s.append("\nremote address = <not connected>"); + } + else + { + s.append("\nremote address = "); + s.append(addrToString(remoteAddr, remotePort)); + } } return s.toString(); } public static String + addressesToString(java.net.InetAddress localAddr, int localPort, java.net.InetAddress remoteAddr, int remotePort) + { + return addressesToString(localAddr, localPort, remoteAddr, remotePort, null, null); + } + + public static String addrToString(java.net.InetSocketAddress addr) { StringBuilder s = new StringBuilder(128); diff --git a/java/src/IceInternal/NetworkProxy.java b/java/src/IceInternal/NetworkProxy.java new file mode 100644 index 00000000000..c035770fd97 --- /dev/null +++ b/java/src/IceInternal/NetworkProxy.java @@ -0,0 +1,48 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2013 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public interface NetworkProxy +{ + // + // Write the connection request on the connection established + // with the network proxy server. This is called right after + // the connection establishment succeeds. + // + void beginWriteConnectRequest(java.net.InetSocketAddress endpoint, Buffer buf); + void endWriteConnectRequest(Buffer buf); + + // + // Once the connection request has been sent, this is called + // to prepare and read the response from the proxy server. + // + void beginReadConnectRequestResponse(Buffer buf); + void endReadConnectRequestResponse(Buffer buf); + + // + // If the proxy host needs to be resolved, this should return + // a new NetworkProxy containing the IP address of the proxy. + // This is called from the endpoint host resolver thread, so + // it's safe if this this method blocks. + // + NetworkProxy resolveHost(); + + // + // Returns the IP address of the network proxy. This method + // must not block. It's only called on a network proxy object + // returned by resolveHost(). + // + java.net.InetSocketAddress getAddress(); + + // + // Returns the name of the proxy, used for tracing purposes. + // + String getName(); +} diff --git a/java/src/IceInternal/ProtocolPluginFacade.java b/java/src/IceInternal/ProtocolPluginFacade.java index 94533a3eb50..9dfe234ac1e 100644 --- a/java/src/IceInternal/ProtocolPluginFacade.java +++ b/java/src/IceInternal/ProtocolPluginFacade.java @@ -33,6 +33,11 @@ public interface ProtocolPluginFacade boolean getPreferIPv6(); // + // Get the network proxy. + // + NetworkProxy getNetworkProxy(); + + // // Get the default encoding to be used in endpoints. // Ice.EncodingVersion getDefaultEncoding(); diff --git a/java/src/IceInternal/ProtocolPluginFacadeI.java b/java/src/IceInternal/ProtocolPluginFacadeI.java index 229bae0a663..1171e258725 100644 --- a/java/src/IceInternal/ProtocolPluginFacadeI.java +++ b/java/src/IceInternal/ProtocolPluginFacadeI.java @@ -53,6 +53,14 @@ public class ProtocolPluginFacadeI implements ProtocolPluginFacade } // + // Get the network proxy. + // + public NetworkProxy getNetworkProxy() + { + return _instance.networkProxy(); + } + + // // Get the default encoding to be used in endpoints. // public Ice.EncodingVersion diff --git a/java/src/IceInternal/SOCKSNetworkProxy.java b/java/src/IceInternal/SOCKSNetworkProxy.java new file mode 100644 index 00000000000..140db18c20f --- /dev/null +++ b/java/src/IceInternal/SOCKSNetworkProxy.java @@ -0,0 +1,104 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2013 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package IceInternal; + +public final class SOCKSNetworkProxy implements NetworkProxy +{ + public SOCKSNetworkProxy(String host, int port) + { + _host = host; + _port = port; + } + + private SOCKSNetworkProxy(java.net.InetSocketAddress address) + { + _address = address; + } + + public void beginWriteConnectRequest(java.net.InetSocketAddress endpoint, Buffer buf) + { + final java.net.InetAddress addr = endpoint.getAddress(); + if(addr == null) + { + throw new Ice.FeatureNotSupportedException("SOCKS4 does not support domain names"); + } + else if(!(addr instanceof java.net.Inet4Address)) + { + throw new Ice.FeatureNotSupportedException("SOCKS4 only supports IPv4 addresses"); + } + + // + // SOCKS connect request + // + buf.resize(9, false); + final java.nio.ByteOrder order = buf.b.order(); + buf.b.order(java.nio.ByteOrder.BIG_ENDIAN); // Network byte order. + buf.b.position(0); + buf.b.put((byte)0x04); // SOCKS version 4. + buf.b.put((byte)0x01); // Command, establish a TCP/IP stream connection + buf.b.putShort((short)endpoint.getPort()); // Port + buf.b.put(addr.getAddress()); // IPv4 address + buf.b.put((byte)0x00); // User ID. + buf.b.position(0); + buf.b.limit(buf.size()); + buf.b.order(order); + } + + public void endWriteConnectRequest(Buffer buf) + { + buf.reset(); + } + + public void beginReadConnectRequestResponse(Buffer buf) + { + // + // Read the SOCKS4 response whose size is 8 bytes. + // + buf.resize(8, true); + buf.b.position(0); + } + + public void endReadConnectRequestResponse(Buffer buf) + { + buf.b.position(0); + byte b1 = buf.b.get(); + byte b2 = buf.b.get(); + if(b1 != 0x00 || b2 != 0x5a) + { + throw new Ice.ConnectFailedException(); + } + buf.reset(); + } + + public NetworkProxy resolveHost() + { + assert(_host != null); + return new SOCKSNetworkProxy(Network.getAddresses(_host, + _port, + Network.EnableIPv4, + Ice.EndpointSelectionType.Random, + false).get(0)); + } + + public java.net.InetSocketAddress getAddress() + { + assert(_address != null); // Host must be resolved. + return _address; + } + + public String getName() + { + return "SOCKS"; + } + + private String _host; + private int _port; + private java.net.InetSocketAddress _address; +} diff --git a/java/src/IceInternal/TcpAcceptor.java b/java/src/IceInternal/TcpAcceptor.java index 44c64957b0b..8d5e2f86989 100644 --- a/java/src/IceInternal/TcpAcceptor.java +++ b/java/src/IceInternal/TcpAcceptor.java @@ -66,7 +66,7 @@ class TcpAcceptor implements Acceptor _logger.trace(_traceLevels.networkCat, s); } - return new TcpTransceiver(_instance, fd, true, null); + return new TcpTransceiver(_instance, fd); } public String diff --git a/java/src/IceInternal/TcpConnector.java b/java/src/IceInternal/TcpConnector.java index be65420bb09..2598123423c 100644 --- a/java/src/IceInternal/TcpConnector.java +++ b/java/src/IceInternal/TcpConnector.java @@ -25,16 +25,9 @@ final class TcpConnector implements Connector java.nio.channels.SocketChannel fd = Network.createTcpSocket(); Network.setBlock(fd, false); Network.setTcpBufSize(fd, _instance.initializationData().properties, _logger); - boolean connected = Network.doConnect(fd, _addr); - if(connected) - { - if(_traceLevels.network >= 1) - { - String s = "tcp connection established\n" + Network.fdToString(fd); - _logger.trace(_traceLevels.networkCat, s); - } - } - return new TcpTransceiver(_instance, fd, connected, _addr); + final java.net.InetSocketAddress addr = _proxy != null ? _proxy.getAddress() : _addr; + Network.doConnect(fd, addr); + return new TcpTransceiver(_instance, fd, _proxy, _addr); } catch(Ice.LocalException ex) { @@ -56,7 +49,7 @@ final class TcpConnector implements Connector public String toString() { - return Network.addrToString(_addr); + return Network.addrToString(_proxy == null ? _addr : _proxy.getAddress()); } public int @@ -68,12 +61,14 @@ final class TcpConnector implements Connector // // Only for use by TcpEndpoint // - TcpConnector(Instance instance, java.net.InetSocketAddress addr, int timeout, String connectionId) + TcpConnector(Instance instance, java.net.InetSocketAddress addr, NetworkProxy proxy, int timeout, + String connectionId) { _instance = instance; _traceLevels = instance.traceLevels(); _logger = instance.initializationData().logger; _addr = addr; + _proxy = proxy; _timeout = timeout; _connectionId = connectionId; @@ -115,6 +110,7 @@ final class TcpConnector implements Connector private TraceLevels _traceLevels; private Ice.Logger _logger; private java.net.InetSocketAddress _addr; + private NetworkProxy _proxy; private int _timeout; private String _connectionId = ""; private int _hashCode; diff --git a/java/src/IceInternal/TcpEndpointI.java b/java/src/IceInternal/TcpEndpointI.java index 5030431f7fb..3b99a9b6a05 100644 --- a/java/src/IceInternal/TcpEndpointI.java +++ b/java/src/IceInternal/TcpEndpointI.java @@ -392,8 +392,7 @@ final class TcpEndpointI extends EndpointI public java.util.List<Connector> connectors(Ice.EndpointSelectionType selType) { - return connectors(Network.getAddresses(_host, _port, _instance.protocolSupport(), selType, - _instance.preferIPv6())); + return _instance.endpointHostResolver().resolve(_host, _port, selType, this); } public void @@ -454,6 +453,17 @@ final class TcpEndpointI extends EndpointI return tcpEndpointI._host.equals(_host) && tcpEndpointI._port == _port; } + public java.util.List<Connector> + connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) + { + java.util.List<Connector> connectors = new java.util.ArrayList<Connector>(); + for(java.net.InetSocketAddress p : addresses) + { + connectors.add(new TcpConnector(_instance, p, proxy, _timeout, _connectionId)); + } + return connectors; + } + public int hashCode() { @@ -515,17 +525,6 @@ final class TcpEndpointI extends EndpointI return _host.compareTo(p._host); } - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses) - { - java.util.List<Connector> connectors = new java.util.ArrayList<Connector>(); - for(java.net.InetSocketAddress p : addresses) - { - connectors.add(new TcpConnector(_instance, p, _timeout, _connectionId)); - } - return connectors; - } - private void calcHashValue() { diff --git a/java/src/IceInternal/TcpTransceiver.java b/java/src/IceInternal/TcpTransceiver.java index 166cab15488..0f451b9d74b 100644 --- a/java/src/IceInternal/TcpTransceiver.java +++ b/java/src/IceInternal/TcpTransceiver.java @@ -19,45 +19,106 @@ final class TcpTransceiver implements Transceiver } public int - initialize() + initialize(Buffer readBuffer, Buffer writeBuffer) { - if(_state == StateNeedConnect) - { - _state = StateConnectPending; - return SocketOperation.Connect; - } - else if(_state <= StateConnectPending) + try { - try + if(_state == StateNeedConnect) { - Network.doFinishConnect(_fd); - _state = StateConnected; - _desc = Network.fdToString(_fd); + _state = StateConnectPending; + return SocketOperation.Connect; } - catch(Ice.LocalException ex) + else if(_state == StateConnectPending) { - if(_traceLevels.network >= 2) + Network.doFinishConnect(_fd); + _desc = Network.fdToString(_fd, _proxy, _addr); + + if(_proxy != null) { - java.net.Socket fd = (java.net.Socket)_fd.socket(); - StringBuilder s = new StringBuilder(128); - s.append("failed to establish tcp connection\n"); - s.append("local address = "); - s.append(Network.addrToString(fd.getLocalAddress(), fd.getLocalPort())); - s.append("\nremote address = "); - assert(_connectAddr != null); - s.append(Network.addrToString(_connectAddr)); - _logger.trace(_traceLevels.networkCat, s.toString()); + // + // Prepare the read & write buffers in advance. + // + _proxy.beginWriteConnectRequest(_addr, writeBuffer); + _proxy.beginReadConnectRequestResponse(readBuffer); + + // + // Write the proxy connection message. + // + if(write(writeBuffer)) + { + // + // Write completed without blocking. + // + _proxy.endWriteConnectRequest(writeBuffer); + + // + // Try to read the response. + // + Ice.BooleanHolder dummy = new Ice.BooleanHolder(); + if(read(readBuffer, dummy)) + { + // + // Read completed without blocking - fall through. + // + _proxy.endReadConnectRequestResponse(readBuffer); + } + else + { + // + // Return SocketOperationRead to indicate we need to complete the read. + // + _state = StateProxyConnectRequestPending; // Wait for proxy response + return SocketOperation.Read; + } + } + else + { + // + // Return SocketOperationWrite to indicate we need to complete the write. + // + _state = StateProxyConnectRequest; // Send proxy connect request + return SocketOperation.Write; + } } - throw ex; - } - if(_traceLevels.network >= 1) + _state = StateConnected; + } + else if(_state == StateProxyConnectRequest) + { + // + // Write completed. + // + _proxy.endWriteConnectRequest(writeBuffer); + _state = StateProxyConnectRequestPending; // Wait for proxy response + return SocketOperation.Read; + } + else if(_state == StateProxyConnectRequestPending) + { + // + // Read completed. + // + _proxy.endReadConnectRequestResponse(readBuffer); + _state = StateConnected; + } + } + catch(Ice.LocalException ex) + { + if(_traceLevels.network >= 2) { - String s = "tcp connection established\n" + _desc; - _logger.trace(_traceLevels.networkCat, s); + StringBuilder s = new StringBuilder(128); + s.append("failed to establish tcp connection\n"); + s.append(Network.fdToString(_fd, _proxy, _addr)); + _logger.trace(_traceLevels.networkCat, s.toString()); } + throw ex; } + assert(_state == StateConnected); + if(_traceLevels.network >= 1) + { + String s = "tcp connection established\n" + _desc; + _logger.trace(_traceLevels.networkCat, s); + } return SocketOperation.None; } @@ -73,7 +134,7 @@ final class TcpTransceiver implements Transceiver assert(_fd != null); try { - _fd.close(); + _fd.close(); } catch(java.io.IOException ex) { @@ -84,8 +145,8 @@ final class TcpTransceiver implements Transceiver _fd = null; } } - - @SuppressWarnings("deprecation") + + @SuppressWarnings("deprecation") public boolean write(Buffer buf) { @@ -169,7 +230,7 @@ final class TcpTransceiver implements Transceiver return true; } - @SuppressWarnings("deprecation") + @SuppressWarnings("deprecation") public boolean read(Buffer buf, Ice.BooleanHolder moreData) { @@ -182,17 +243,17 @@ final class TcpTransceiver implements Transceiver { assert(_fd != null); int ret = _fd.read(buf.b); - + if(ret == -1) { throw new Ice.ConnectionLostException(); } - + if(ret == 0) { return false; } - + if(ret > 0) { if(_traceLevels.network >= 3) @@ -261,19 +322,43 @@ final class TcpTransceiver implements Transceiver } } - // - // Only for use by TcpConnector, TcpAcceptor - // - @SuppressWarnings("deprecation") - TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd, boolean connected, - java.net.InetSocketAddress connectAddr) + @SuppressWarnings("deprecation") + TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd, NetworkProxy proxy, + java.net.InetSocketAddress addr) + { + _fd = fd; + _proxy = proxy; + _addr = addr; + _traceLevels = instance.traceLevels(); + _logger = instance.initializationData().logger; + _stats = instance.initializationData().stats; + _state = StateNeedConnect; + _desc = ""; + + _maxSendPacketSize = 0; + if(System.getProperty("os.name").startsWith("Windows")) + { + // + // On Windows, limiting the buffer size is important to prevent + // poor throughput performances when transfering large amount of + // data. See Microsoft KB article KB823764. + // + _maxSendPacketSize = Network.getSendBufferSize(_fd) / 2; + if(_maxSendPacketSize < 512) + { + _maxSendPacketSize = 0; + } + } + } + + @SuppressWarnings("deprecation") + TcpTransceiver(Instance instance, java.nio.channels.SocketChannel fd) { _fd = fd; - _connectAddr = connectAddr; _traceLevels = instance.traceLevels(); _logger = instance.initializationData().logger; _stats = instance.initializationData().stats; - _state = connected ? StateConnected : StateNeedConnect; + _state = StateConnected; _desc = Network.fdToString(_fd); _maxSendPacketSize = 0; @@ -310,17 +395,20 @@ final class TcpTransceiver implements Transceiver } private java.nio.channels.SocketChannel _fd; - private java.net.InetSocketAddress _connectAddr; + private NetworkProxy _proxy; + private java.net.InetSocketAddress _addr; private TraceLevels _traceLevels; private Ice.Logger _logger; - + @SuppressWarnings("deprecation") private Ice.Stats _stats; private String _desc; private int _state; private int _maxSendPacketSize; - + private static final int StateNeedConnect = 0; private static final int StateConnectPending = 1; - private static final int StateConnected = 2; + private static final int StateProxyConnectRequest = 2; + private static final int StateProxyConnectRequestPending = 3; + private static final int StateConnected = 4; } diff --git a/java/src/IceInternal/Transceiver.java b/java/src/IceInternal/Transceiver.java index 3ad423f5067..49585e7d708 100644 --- a/java/src/IceInternal/Transceiver.java +++ b/java/src/IceInternal/Transceiver.java @@ -18,7 +18,7 @@ public interface Transceiver // // Returns the status if the initialize operation. // - int initialize(); + int initialize(Buffer readBuffer, Buffer writeBuffer); void close(); diff --git a/java/src/IceInternal/UdpEndpointI.java b/java/src/IceInternal/UdpEndpointI.java index 08bd67b1b15..6568b7ec2b4 100644 --- a/java/src/IceInternal/UdpEndpointI.java +++ b/java/src/IceInternal/UdpEndpointI.java @@ -453,8 +453,7 @@ final class UdpEndpointI extends EndpointI public java.util.List<Connector> connectors(Ice.EndpointSelectionType selType) { - return connectors(Network.getAddresses(_host, _port, _instance.protocolSupport(), selType, - _instance.preferIPv6())); + return _instance.endpointHostResolver().resolve(_host, _port, selType, this); } public void @@ -516,6 +515,17 @@ final class UdpEndpointI extends EndpointI return udpEndpointI._host.equals(_host) && udpEndpointI._port == _port; } + public java.util.List<Connector> + connectors(java.util.List<java.net.InetSocketAddress> addresses, NetworkProxy proxy) + { + java.util.ArrayList<Connector> connectors = new java.util.ArrayList<Connector>(); + for(java.net.InetSocketAddress p : addresses) + { + connectors.add(new UdpConnector(_instance, p, _mcastInterface, _mcastTtl, _connectionId)); + } + return connectors; + } + public int hashCode() { @@ -589,17 +599,6 @@ final class UdpEndpointI extends EndpointI return _host.compareTo(p._host); } - public java.util.List<Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses) - { - java.util.ArrayList<Connector> connectors = new java.util.ArrayList<Connector>(); - for(java.net.InetSocketAddress p : addresses) - { - connectors.add(new UdpConnector(_instance, p, _mcastInterface, _mcastTtl, _connectionId)); - } - return connectors; - } - private void calcHashValue() { diff --git a/java/src/IceInternal/UdpTransceiver.java b/java/src/IceInternal/UdpTransceiver.java index 1b17f8591ab..17ca53e8081 100644 --- a/java/src/IceInternal/UdpTransceiver.java +++ b/java/src/IceInternal/UdpTransceiver.java @@ -19,7 +19,7 @@ final class UdpTransceiver implements Transceiver } public int - initialize() + initialize(Buffer readBuffer, Buffer writeBuffer) { // // Nothing to do. diff --git a/java/src/IceSSL/AcceptorI.java b/java/src/IceSSL/AcceptorI.java index b35ddf1d208..546cdd1213b 100644 --- a/java/src/IceSSL/AcceptorI.java +++ b/java/src/IceSSL/AcceptorI.java @@ -89,7 +89,7 @@ final class AcceptorI implements IceInternal.Acceptor IceInternal.Network.fdToString(fd)); } - return new TransceiverI(_instance, engine, fd, "", true, true, _adapterName, null); + return new TransceiverI(_instance, engine, fd, _adapterName); } public String diff --git a/java/src/IceSSL/ConnectorI.java b/java/src/IceSSL/ConnectorI.java index 385532102ea..788287c6d0d 100644 --- a/java/src/IceSSL/ConnectorI.java +++ b/java/src/IceSSL/ConnectorI.java @@ -35,11 +35,12 @@ final class ConnectorI implements IceInternal.Connector java.nio.channels.SocketChannel fd = IceInternal.Network.createTcpSocket(); IceInternal.Network.setBlock(fd, false); IceInternal.Network.setTcpBufSize(fd, _instance.communicator().getProperties(), _logger); - boolean connected = IceInternal.Network.doConnect(fd, _addr); + final java.net.InetSocketAddress addr = _proxy != null ? _proxy.getAddress() : _addr; + IceInternal.Network.doConnect(fd, addr); try { javax.net.ssl.SSLEngine engine = _instance.createSSLEngine(false, _addr); - return new TransceiverI(_instance, engine, fd, _host, connected, false, "", _addr); + return new TransceiverI(_instance, engine, fd, _proxy, _host, _addr); } catch(RuntimeException ex) { @@ -67,7 +68,7 @@ final class ConnectorI implements IceInternal.Connector public String toString() { - return IceInternal.Network.addrToString(_addr); + return IceInternal.Network.addrToString(_proxy == null ? _addr : _proxy.getAddress()); } public int @@ -79,13 +80,14 @@ final class ConnectorI implements IceInternal.Connector // // Only for use by EndpointI. // - ConnectorI(Instance instance, String host, java.net.InetSocketAddress addr, int timeout, - String connectionId) + ConnectorI(Instance instance, String host, java.net.InetSocketAddress addr, IceInternal.NetworkProxy proxy, + int timeout, String connectionId) { _instance = instance; _logger = instance.communicator().getLogger(); _host = host; _addr = addr; + _proxy = proxy; _timeout = timeout; _connectionId = connectionId; @@ -127,6 +129,7 @@ final class ConnectorI implements IceInternal.Connector private Ice.Logger _logger; private String _host; private java.net.InetSocketAddress _addr; + private IceInternal.NetworkProxy _proxy; private int _timeout; private String _connectionId; private int _hashCode; diff --git a/java/src/IceSSL/EndpointI.java b/java/src/IceSSL/EndpointI.java index b5c9f16cd29..dbd46bda378 100644 --- a/java/src/IceSSL/EndpointI.java +++ b/java/src/IceSSL/EndpointI.java @@ -392,8 +392,7 @@ final class EndpointI extends IceInternal.EndpointI public java.util.List<IceInternal.Connector> connectors(Ice.EndpointSelectionType selType) { - return connectors(IceInternal.Network.getAddresses(_host, _port, _instance.protocolSupport(), selType, - _instance.preferIPv6())); + return _instance.endpointHostResolver().resolve(_host, _port, selType, this); } public void @@ -455,6 +454,17 @@ final class EndpointI extends IceInternal.EndpointI return sslEndpointI._host.equals(_host) && sslEndpointI._port == _port; } + public java.util.List<IceInternal.Connector> + connectors(java.util.List<java.net.InetSocketAddress> addresses, IceInternal.NetworkProxy proxy) + { + java.util.List<IceInternal.Connector> connectors = new java.util.ArrayList<IceInternal.Connector>(); + for(java.net.InetSocketAddress p : addresses) + { + connectors.add(new ConnectorI(_instance, _host, p, proxy, _timeout, _connectionId)); + } + return connectors; + } + public int hashCode() { @@ -516,17 +526,6 @@ final class EndpointI extends IceInternal.EndpointI return _host.compareTo(p._host); } - public java.util.List<IceInternal.Connector> - connectors(java.util.List<java.net.InetSocketAddress> addresses) - { - java.util.List<IceInternal.Connector> connectors = new java.util.ArrayList<IceInternal.Connector>(); - for(java.net.InetSocketAddress p : addresses) - { - connectors.add(new ConnectorI(_instance, _host, p, _timeout, _connectionId)); - } - return connectors; - } - private void calcHashValue() { diff --git a/java/src/IceSSL/TransceiverI.java b/java/src/IceSSL/TransceiverI.java index 13d0304ea7e..09435e145ef 100644 --- a/java/src/IceSSL/TransceiverI.java +++ b/java/src/IceSSL/TransceiverI.java @@ -23,7 +23,7 @@ final class TransceiverI implements IceInternal.Transceiver } public int - initialize() + initialize(IceInternal.Buffer readBuffer, IceInternal.Buffer writeBuffer) { try { @@ -32,42 +32,90 @@ final class TransceiverI implements IceInternal.Transceiver _state = StateConnectPending; return IceInternal.SocketOperation.Connect; } - else if(_state <= StateConnectPending) + else if(_state == StateConnectPending) { IceInternal.Network.doFinishConnect(_fd); + _desc = IceInternal.Network.fdToString(_fd, _proxy, _addr); + + if(_proxy != null) + { + // + // Prepare the read & write buffers in advance. + // + _proxy.beginWriteConnectRequest(_addr, writeBuffer); + _proxy.beginReadConnectRequestResponse(readBuffer); + + // + // Write the proxy connection message. + // + if(writeRaw(writeBuffer)) + { + // + // Write completed without blocking. + // + _proxy.endWriteConnectRequest(writeBuffer); + + // + // Try to read the response. + // + if(readRaw(readBuffer)) + { + // + // Read completed without blocking - fall through. + // + _proxy.endReadConnectRequestResponse(readBuffer); + } + else + { + // + // Return SocketOperationRead to indicate we need to complete the read. + // + _state = StateProxyConnectRequestPending; // Wait for proxy response + return IceInternal.SocketOperation.Read; + } + } + else + { + // + // Return SocketOperationWrite to indicate we need to complete the write. + // + _state = StateProxyConnectRequest; // Send proxy connect request + return IceInternal.SocketOperation.Write; + } + } + + _state = StateConnected; + } + else if(_state == StateProxyConnectRequest) + { + // + // Write completed. + // + _proxy.endWriteConnectRequest(writeBuffer); + _state = StateProxyConnectRequestPending; // Wait for proxy response + return IceInternal.SocketOperation.Read; + } + else if(_state == StateProxyConnectRequestPending) + { + // + // Read completed. + // + _proxy.endReadConnectRequestResponse(readBuffer); _state = StateConnected; - _desc = IceInternal.Network.fdToString(_fd); } - assert(_state == StateConnected); - int status = handshakeNonBlocking(); - if(status != IceInternal.SocketOperation.None) + if(_state == StateConnected) { - return status; + return handshakeNonBlocking(); } } catch(Ice.LocalException ex) { if(_instance.networkTraceLevel() >= 2) { - java.net.Socket fd = (java.net.Socket)_fd.socket(); StringBuilder s = new StringBuilder(128); s.append("failed to establish ssl connection\n"); - s.append("local address = "); - s.append(IceInternal.Network.addrToString(fd.getLocalAddress(), fd.getLocalPort())); - s.append("\nremote address = "); - if(_incoming) - { - final java.net.InetSocketAddress addr = (java.net.InetSocketAddress)fd.getRemoteSocketAddress(); - final java.net.InetAddress remoteAddr = addr != null ? addr.getAddress() : null; - final int remotePort = addr != null ? addr.getPort() : -1; - s.append(IceInternal.Network.addrToString(remoteAddr, remotePort)); - } - else - { - assert(_connectAddr != null); - s.append(IceInternal.Network.addrToString(_connectAddr)); - } + s.append(IceInternal.Network.fdToString(_fd, _proxy, _addr)); _logger.trace(_instance.networkTraceCategory(), s.toString()); } throw ex; @@ -155,6 +203,14 @@ final class TransceiverI implements IceInternal.Transceiver public boolean write(IceInternal.Buffer buf) { + if(_state == StateProxyConnectRequest) + { + // + // We need to write the proxy message, but we have to use TCP and not SSL. + // + return writeRaw(buf); + } + // // If the handshake isn't completed yet, we shouldn't be writing. // @@ -186,6 +242,16 @@ final class TransceiverI implements IceInternal.Transceiver public boolean read(IceInternal.Buffer buf, Ice.BooleanHolder moreData) { + moreData.value = false; + + if(_state == StateProxyConnectRequestPending) + { + // + // We need to read the proxy reply, but we have to use TCP and not SSL. + // + return readRaw(buf); + } + // // If the handshake isn't completed yet, we shouldn't be reading (read can be // called by the thread pool when the connection is registered/unregistered @@ -244,7 +310,6 @@ final class TransceiverI implements IceInternal.Transceiver if(status != IceInternal.SocketOperation.None) { assert(status == IceInternal.SocketOperation.Read); - moreData.value = false; return false; } continue; @@ -313,22 +378,35 @@ final class TransceiverI implements IceInternal.Transceiver } } - // - // Only for use by ConnectorI, AcceptorI. - // - @SuppressWarnings("deprecation") TransceiverI(Instance instance, javax.net.ssl.SSLEngine engine, java.nio.channels.SocketChannel fd, - String host, boolean connected, boolean incoming, String adapterName, - java.net.InetSocketAddress connectAddr) + IceInternal.NetworkProxy proxy, String host, java.net.InetSocketAddress addr) + { + init(instance, engine, fd); + _proxy = proxy; + _host = host; + _incoming = false; + _addr = addr; + _state = StateNeedConnect; + _desc = IceInternal.Network.fdToString(_fd, _proxy, _addr); + } + + TransceiverI(Instance instance, javax.net.ssl.SSLEngine engine, java.nio.channels.SocketChannel fd, + String adapterName) + { + init(instance, engine, fd); + _host = ""; + _adapterName = adapterName; + _incoming = true; + _state = StateConnected; + _desc = IceInternal.Network.fdToString(_fd); + } + + @SuppressWarnings("deprecation") + private void init(Instance instance, javax.net.ssl.SSLEngine engine, java.nio.channels.SocketChannel fd) { _instance = instance; _engine = engine; _fd = fd; - _host = host; - _incoming = incoming; - _adapterName = adapterName; - _connectAddr = connectAddr; - _state = connected ? StateConnected : StateNeedConnect; _logger = instance.communicator().getLogger(); try { @@ -338,7 +416,6 @@ final class TransceiverI implements IceInternal.Transceiver { // Ignore. } - _desc = IceInternal.Network.fdToString(_fd); _maxPacketSize = 0; if(System.getProperty("os.name").startsWith("Windows")) { @@ -817,13 +894,122 @@ final class TransceiverI implements IceInternal.Transceiver _appInput.compact(); } + @SuppressWarnings("deprecation") + private boolean + writeRaw(IceInternal.Buffer buf) + { + // + // We don't want write to be called on android main thread as this will cause + // NetworkOnMainThreadException to be thrown. If that is the android main thread + // we return false and this method will be later called from the thread pool. + // + if(IceInternal.Util.isAndroidMainThread(Thread.currentThread())) + { + return false; + } + + final int size = buf.b.limit(); + int packetSize = size - buf.b.position(); + + while(buf.b.hasRemaining()) + { + try + { + assert(_fd != null); + int ret = _fd.write(buf.b); + + if(ret == -1) + { + throw new Ice.ConnectionLostException(); + } + else if(ret == 0) + { + return false; + } + + if(_instance.networkTraceLevel() >= 3) + { + String s = "sent " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); + _logger.trace(_instance.networkTraceCategory(), s); + } + + if(_stats != null) + { + _stats.bytesSent(type(), ret); + } + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.SocketException(ex); + } + } + return true; + } + + @SuppressWarnings("deprecation") + private boolean + readRaw(IceInternal.Buffer buf) + { + int packetSize = buf.b.remaining(); + + while(buf.b.hasRemaining()) + { + try + { + assert(_fd != null); + int ret = _fd.read(buf.b); + + if(ret == -1) + { + throw new Ice.ConnectionLostException(); + } + + if(ret == 0) + { + return false; + } + + if(ret > 0) + { + if(_instance.networkTraceLevel() >= 3) + { + String s = "received " + ret + " of " + packetSize + " bytes via tcp\n" + toString(); + _logger.trace(_instance.networkTraceCategory(), s); + } + + if(_stats != null) + { + _stats.bytesReceived(type(), ret); + } + } + + packetSize = buf.b.remaining(); + } + catch(java.io.InterruptedIOException ex) + { + continue; + } + catch(java.io.IOException ex) + { + throw new Ice.ConnectionLostException(ex); + } + } + + return true; + } + private Instance _instance; private java.nio.channels.SocketChannel _fd; private javax.net.ssl.SSLEngine _engine; + private IceInternal.NetworkProxy _proxy; private String _host; private boolean _incoming; private String _adapterName; - private java.net.InetSocketAddress _connectAddr; + private java.net.InetSocketAddress _addr; private int _state; private Ice.Logger _logger; @@ -838,6 +1024,8 @@ final class TransceiverI implements IceInternal.Transceiver private static final int StateNeedConnect = 0; private static final int StateConnectPending = 1; - private static final int StateConnected = 2; - private static final int StateHandshakeComplete = 3; + private static final int StateProxyConnectRequest = 2; + private static final int StateProxyConnectRequestPending = 3; + private static final int StateConnected = 4; + private static final int StateHandshakeComplete = 5; } |