changeset 53336:f28d2ea795b3 fibers

Re-enable transparent SOCK/HTTP proxy with NioSocketImpl
author alanb
date Mon, 14 Jan 2019 19:19:10 +0000
parents 3e1a59e8c374
children 611bd8373681 cca90c36707e
files src/java.base/share/classes/java/net/HttpConnectSocketImpl.java src/java.base/share/classes/java/net/ServerSocket.java src/java.base/share/classes/java/net/Socket.java src/java.base/share/classes/java/net/SocksSocketImpl.java src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java test/jdk/java/net/Socks/SocksProxyVersion.java
diffstat 6 files changed, 41 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/net/HttpConnectSocketImpl.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/src/java.base/share/classes/java/net/HttpConnectSocketImpl.java	Mon Jan 14 19:19:10 2019 +0000
@@ -26,14 +26,14 @@
 package java.net;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
+import sun.nio.ch.NioSocketImpl;
+
 /**
  * Basic SocketImpl that relies on the internal HTTP protocol handler
  * implementation to perform the HTTP tunneling and authentication. The
@@ -43,7 +43,7 @@
  * @since 1.8
  */
 
-/*package*/ class HttpConnectSocketImpl extends SocketImpl {
+/*package*/ class HttpConnectSocketImpl extends NioSocketImpl {
 
     private static final String httpURLClazzStr =
                                   "sun.net.www.protocol.http.HttpURLConnection";
@@ -78,12 +78,8 @@
         }
     }
 
-    HttpConnectSocketImpl(String server, int port) {
-        this.server = server;
-        this.port = port;
-    }
-
     HttpConnectSocketImpl(Proxy proxy) {
+        super(false);
         SocketAddress a = proxy.address();
         if ( !(a instanceof InetSocketAddress) )
             throw new IllegalArgumentException("Unsupported address type");
@@ -94,13 +90,6 @@
     }
 
     @Override
-    protected void create(boolean stream) throws IOException {
-        if (!stream) {
-            throw new IOException("datagram socket not supported");
-        }
-    }
-
-    @Override
     protected void connect(String host, int port) throws IOException {
         connect(new InetSocketAddress(host, port), 0);
     }
@@ -137,7 +126,7 @@
 
         // update the Sockets impl to the impl from the http Socket
         SocketImpl si = httpSocket.impl;
-        this.getSocket().setImpl(si);
+        ((SocketImpl) this).getSocket().setImpl(si);
 
         // best effort is made to try and reset options previously set
         Set<Map.Entry<Integer,Object>> options = optionsMap.entrySet();
@@ -149,65 +138,16 @@
     }
 
     @Override
-    protected void bind(InetAddress host, int port) throws IOException {
-        throw new IOException("unable to bind HTTP proxy client to local address");
-    }
+    public void setOption(int opt, Object val) throws SocketException {
+        super.setOption(opt, val);
 
-    @Override
-    protected void listen(int backlog) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected void accept(SocketImpl s) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected InputStream getInputStream() throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected OutputStream getOutputStream() throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    protected int available() throws IOException {
-        return 0;
-    }
-
-    @Override
-    protected void close() throws IOException {
-    }
-
-    @Override
-    public void setOption(int opt, Object val) throws SocketException {
-        // set option on temporary socket to test that option/value are valid
-        try (Socket s = new Socket()) {
-            s.getImpl().setOption(opt, val);
-        } catch (IOException ioe) {
-            throw new SocketException(ioe.getMessage());
-        }
+        if (external_address != null)
+            return;  // we're connected, just return
 
         // store options so that they can be re-applied to the impl after connect
         optionsMap.put(opt, val);
     }
 
-    @Override
-    public Object getOption(int opt) throws SocketException {
-        Object value = optionsMap.get(opt);
-        if (value != null)
-            return value;
-        // get option value from temporary socket to test that option is valid
-        try (Socket s = new Socket()) {
-            return s.getImpl().getOption(opt);
-        } catch (IOException ioe) {
-            throw new SocketException(ioe.getMessage());
-        }
-    }
-
     private Socket privilegedDoTunnel(final String urlString,
                                       final int timeout)
         throws IOException
@@ -231,7 +171,7 @@
         URL destURL = new URL(urlString);
         HttpURLConnection conn = (HttpURLConnection) destURL.openConnection(proxy);
         conn.setConnectTimeout(connectTimeout);
-        Object value = optionsMap.get(SocketOptions.SO_TIMEOUT);
+        Object value = getOption(SocketOptions.SO_TIMEOUT);
         if (value != null) {
             Integer timeout = (Integer) value;
             conn.setReadTimeout(timeout);
@@ -269,9 +209,4 @@
         else
             return super.getPort();
     }
-
-    @Override
-    protected void sendUrgentData(int data) {
-        throw new UnsupportedOperationException();
-    }
 }
--- a/src/java.base/share/classes/java/net/ServerSocket.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/src/java.base/share/classes/java/net/ServerSocket.java	Mon Jan 14 19:19:10 2019 +0000
@@ -551,11 +551,14 @@
             // create a SocketImpl and accept the connection
             si = Socket.createImpl();
             impl.accept(si);
-            securityCheckAccept(si);
 
-            // a custom impl has accepted the connection with a NIO SocketImpl
-            if (!(impl instanceof NioSocketImpl) && (si instanceof NioSocketImpl)) {
-                ((NioSocketImpl) si).postCustomAccept();
+            try {
+                // a custom impl has accepted the connection with a NIO SocketImpl
+                if (!(impl instanceof NioSocketImpl) && (si instanceof NioSocketImpl)) {
+                    ((NioSocketImpl) si).postCustomAccept();
+                }
+            } finally {
+                securityCheckAccept(si);  // closes si if permission check fails
             }
 
             // bind Socket to the SocketImpl and update socket state
@@ -566,14 +569,14 @@
 
         // ServerSocket or Socket is using NIO SocketImpl
         if (impl instanceof NioSocketImpl || si instanceof NioSocketImpl) {
-            // not implemented yet
+            // not implemented
             if (impl instanceof NioSocketImpl && impl.getClass() != NioSocketImpl.class)
                 throw new UnsupportedOperationException();
 
             // accept connection via new SocketImpl
             NioSocketImpl nsi = new NioSocketImpl(false);
             impl.accept(nsi);
-            securityCheckAccept(nsi);
+            securityCheckAccept(nsi);  // closes si if permission check fails
 
             // copy state to the existing SocketImpl and update socket state
             nsi.copyTo(si);
@@ -589,7 +592,7 @@
             si.fd = new FileDescriptor();
             si.address = new InetAddress();
             impl.accept(si);
-            securityCheckAccept(si);
+            securityCheckAccept(si);  // closes si if permission check fails
             completed = true;
         } finally {
             if (!completed)
--- a/src/java.base/share/classes/java/net/Socket.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/src/java.base/share/classes/java/net/Socket.java	Mon Jan 14 19:19:10 2019 +0000
@@ -497,7 +497,7 @@
         if (factory != null) {
             return factory.createSocketImpl();
         } else {
-            return new NioSocketImpl(false);
+            return new SocksSocketImpl();
         }
     }
 
@@ -517,7 +517,7 @@
         } else {
             // No need to do a checkOldImpl() here, we know it's an up to date
             // SocketImpl!
-            impl = new NioSocketImpl(false);
+            impl = new SocksSocketImpl();
         }
         if (impl != null)
             impl.setSocket(this);
@@ -1128,7 +1128,7 @@
      * Tests if {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled.
      *
      * @return a {@code boolean} indicating whether or not
-     *         {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}is enabled.
+     *         {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled.
      *
      * @exception SocketException if there is an error
      * in the underlying protocol, such as a TCP error.
--- a/src/java.base/share/classes/java/net/SocksSocketImpl.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/src/java.base/share/classes/java/net/SocksSocketImpl.java	Mon Jan 14 19:19:10 2019 +0000
@@ -55,9 +55,8 @@
     /* true if the Proxy has been set programmatically */
     private boolean applicationSetProxy;  /* false */
 
-
-    SocksSocketImpl(boolean server) {
-        super(server);
+    SocksSocketImpl() {
+        super(false);
     }
 
     SocksSocketImpl(Proxy proxy) {
@@ -932,8 +931,6 @@
      *               connection.
      */
     protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
-        if (true) throw new RuntimeException("Should not get here");
-
         if (cmdsock == null) {
             // Not a Socks ServerSocket.
             return;
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java	Mon Jan 14 19:19:10 2019 +0000
@@ -83,6 +83,8 @@
  * 1. "Connection reset" handling differs to PlainSocketImpl for cases where
  * an application continues to call read or available after a reset.
  * 2. Bounds checks on SocketInputStream/SocketOutputStream throws AIOOBE.
+ * 3. SocketInputStream/SocketOutputStream limit I/O buffer size to 128K.
+ * 4. Solaris specific SO_FLOW_SLA option not implemented yet.
  */
 
 public class NioSocketImpl extends SocketImpl {
@@ -383,10 +385,11 @@
      * connection is accepted by a ServerSocket using a custom SocketImpl.
      * The protected fields defined by SocketImpl should be set.
      */
-    public void postCustomAccept() {
+    public void postCustomAccept() throws IOException {
         synchronized (stateLock) {
             assert state == ST_NEW;
             assert fd.valid() && localport != 0 && address != null && port != 0;
+            IOUtil.configureBlocking(fd, true);
             stream = true;
             closer = FileDescriptorCloser.create(this);
             state = ST_CONNECTED;
@@ -870,15 +873,15 @@
         return Collections.unmodifiableSet(options);
     }
 
-    private boolean booleanValue(Object value, String desc) throws SocketException {
+    private boolean booleanValue(Object value, String desc) {
         if (!(value instanceof Boolean))
-            throw new SocketException("Bad value for " + desc);
+            throw new IllegalArgumentException("Bad value for " + desc);
         return (boolean) value;
     }
 
-    private int intValue(Object value, String desc) throws SocketException {
+    private int intValue(Object value, String desc) {
         if (!(value instanceof Integer))
-            throw new SocketException("Bad value for " + desc);
+            throw new IllegalArgumentException("Bad value for " + desc);
         return (int) value;
     }
 
@@ -889,15 +892,12 @@
             try {
                 switch (opt) {
                 case SO_LINGER: {
-                    if (!(value instanceof Integer) && !(value instanceof Boolean))
-                        throw new SocketException("Bad value for SO_LINGER");
-                    int i = 0;
-                    if (value instanceof Integer) {
-                        i = ((Integer) value).intValue();
-                        if (i < 0)
-                            i = Integer.valueOf(-1);
-                        if (i > 65535)
-                            i = Integer.valueOf(65535);
+                    int i;
+                    if (value instanceof Boolean) {
+                        // maintain compatibility with PlainSocketImpl
+                        i = 0;
+                    } else {
+                        i = intValue(value, "SO_LINGER");
                     }
                     Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_LINGER, i);
                     break;
@@ -911,8 +911,6 @@
                 }
                 case IP_TOS: {
                     int i = intValue(value, "IP_TOS");
-                    if (i < 0 || i > 255)
-                        throw new IllegalArgumentException("Invalid IP_TOS value");
                     Net.setSocketOption(fd, protocolFamily(), StandardSocketOptions.IP_TOS, i);
                     break;
                 }
@@ -923,15 +921,11 @@
                 }
                 case SO_SNDBUF: {
                     int i = intValue(value, "SO_SNDBUF");
-                    if (i < 0)
-                        throw new SocketException("bad parameter for SO_SNDBUF");
                     Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_SNDBUF, i);
                     break;
                 }
                 case SO_RCVBUF: {
                     int i = intValue(value, "SO_RCVBUF");
-                    if (i < 0)
-                        throw new SocketException("bad parameter for SO_RCVBUF");
                     Net.setSocketOption(fd, Net.UNSPEC, StandardSocketOptions.SO_RCVBUF, i);
                     break;
                 }
--- a/test/jdk/java/net/Socks/SocksProxyVersion.java	Sun Jan 13 17:36:41 2019 +0000
+++ b/test/jdk/java/net/Socks/SocksProxyVersion.java	Mon Jan 14 19:19:10 2019 +0000
@@ -83,13 +83,13 @@
         // SOCKS V4
         System.setProperty("socksProxyVersion", Integer.toString(4));
         this.expected = 4;
-        //check(new Socket(), addr, port);
+        check(new Socket(), addr, port);
         check(new Socket(proxy), addr, port);
 
         // SOCKS V5
         System.setProperty("socksProxyVersion", Integer.toString(5));
         this.expected = 5;
-        //check(new Socket(), addr, port);
+        check(new Socket(), addr, port);
         check(new Socket(proxy), addr, port);
     }