changeset 2356:cda90ceb7176

Merge
author ohair
date Fri, 12 Mar 2010 09:06:00 -0800
parents bf6eb240e718 ee385b4e2ffb
children f88f6f8ddd21
files test/ProblemList.txt
diffstat 9 files changed, 306 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/net/SocketInputStream.java	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/classes/java/net/SocketInputStream.java	Fri Mar 12 09:06:00 2010 -0800
@@ -118,6 +118,10 @@
      * @exception IOException If an I/O error has occurred.
      */
     public int read(byte b[], int off, int length) throws IOException {
+        return read(b, off, length, impl.getTimeout());
+    }
+
+    int read(byte b[], int off, int length, int timeout) throws IOException {
         int n;
 
         // EOF already encountered
@@ -143,7 +147,7 @@
         // acquire file descriptor and do the read
         FileDescriptor fd = impl.acquireFD();
         try {
-            n = socketRead0(fd, b, off, length, impl.getTimeout());
+            n = socketRead0(fd, b, off, length, timeout);
             if (n > 0) {
                 return n;
             }
@@ -161,7 +165,7 @@
             impl.setConnectionResetPending();
             impl.acquireFD();
             try {
-                n = socketRead0(fd, b, off, length, impl.getTimeout());
+                n = socketRead0(fd, b, off, length, timeout);
                 if (n > 0) {
                     return n;
                 }
--- a/src/share/classes/java/net/SocksSocketImpl.java	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/classes/java/net/SocksSocketImpl.java	Fri Mar 12 09:06:00 2010 -0800
@@ -98,11 +98,31 @@
         super.connect(new InetSocketAddress(host, port), timeout);
     }
 
+    private static int remainingMillis(long deadlineMillis) throws IOException {
+        if (deadlineMillis == 0L)
+            return 0;
+
+        final long remaining = deadlineMillis - System.currentTimeMillis();
+        if (remaining > 0)
+            return (int) remaining;
+
+        throw new SocketTimeoutException();
+    }
+
     private int readSocksReply(InputStream in, byte[] data) throws IOException {
+        return readSocksReply(in, data, 0L);
+    }
+
+    private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
         int len = data.length;
         int received = 0;
         for (int attempts = 0; received < len && attempts < 3; attempts++) {
-            int count = in.read(data, received, len - received);
+            int count;
+            try {
+                count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
+            } catch (SocketTimeoutException e) {
+                throw new SocketTimeoutException("Connect timed out");
+            }
             if (count < 0)
                 throw new SocketException("Malformed reply from SOCKS server");
             received += count;
@@ -115,6 +135,12 @@
      */
     private boolean authenticate(byte method, InputStream in,
                                  BufferedOutputStream out) throws IOException {
+        return authenticate(method, in, out, 0L);
+    }
+
+    private boolean authenticate(byte method, InputStream in,
+                                 BufferedOutputStream out,
+                                 long deadlineMillis) throws IOException {
         // No Authentication required. We're done then!
         if (method == NO_AUTH)
             return true;
@@ -162,7 +188,7 @@
                 out.write(0);
             out.flush();
             byte[] data = new byte[2];
-            int i = readSocksReply(in, data);
+            int i = readSocksReply(in, data, deadlineMillis);
             if (i != 2 || data[1] != 0) {
                 /* RFC 1929 specifies that the connection MUST be closed if
                    authentication fails */
@@ -201,18 +227,18 @@
 //                      out.write(outToken);
 //                      out.flush();
 //                      data = new byte[2];
-//                      i = readSocksReply(in, data);
+//                      i = readSocksReply(in, data, deadlineMillis);
 //                      if (i != 2 || data[1] == 0xff) {
 //                          in.close();
 //                          out.close();
 //                          return false;
 //                      }
-//                      i = readSocksReply(in, data);
+//                      i = readSocksReply(in, data, deadlineMillis);
 //                      int len = 0;
 //                      len = ((int)data[0] & 0xff) << 8;
 //                      len += data[1];
 //                      data = new byte[len];
-//                      i = readSocksReply(in, data);
+//                      i = readSocksReply(in, data, deadlineMillis);
 //                      if (i == len)
 //                          return true;
 //                      in.close();
@@ -231,7 +257,8 @@
     }
 
     private void connectV4(InputStream in, OutputStream out,
-                           InetSocketAddress endpoint) throws IOException {
+                           InetSocketAddress endpoint,
+                           long deadlineMillis) throws IOException {
         if (!(endpoint.getAddress() instanceof Inet4Address)) {
             throw new SocketException("SOCKS V4 requires IPv4 only addresses");
         }
@@ -249,7 +276,7 @@
         out.write(0);
         out.flush();
         byte[] data = new byte[8];
-        int n = readSocksReply(in, data);
+        int n = readSocksReply(in, data, deadlineMillis);
         if (n != 8)
             throw new SocketException("Reply from SOCKS server has bad length: " + n);
         if (data[0] != 0 && data[0] != 4)
@@ -296,6 +323,15 @@
      */
     @Override
     protected void connect(SocketAddress endpoint, int timeout) throws IOException {
+        final long deadlineMillis;
+
+        if (timeout == 0) {
+            deadlineMillis = 0L;
+        } else {
+            long finish = System.currentTimeMillis() + timeout;
+            deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish;
+        }
+
         SecurityManager security = System.getSecurityManager();
         if (endpoint == null || !(endpoint instanceof InetSocketAddress))
             throw new IllegalArgumentException("Unsupported address type");
@@ -322,7 +358,7 @@
                 /*
                  * No default proxySelector --> direct connection
                  */
-                super.connect(epoint, timeout);
+                super.connect(epoint, remainingMillis(deadlineMillis));
                 return;
             }
             URI uri;
@@ -345,13 +381,13 @@
             java.util.Iterator<Proxy> iProxy = null;
             iProxy = sel.select(uri).iterator();
             if (iProxy == null || !(iProxy.hasNext())) {
-                super.connect(epoint, timeout);
+                super.connect(epoint, remainingMillis(deadlineMillis));
                 return;
             }
             while (iProxy.hasNext()) {
                 p = iProxy.next();
                 if (p == null || p == Proxy.NO_PROXY) {
-                    super.connect(epoint, timeout);
+                    super.connect(epoint, remainingMillis(deadlineMillis));
                     return;
                 }
                 if (p.type() != Proxy.Type.SOCKS)
@@ -364,7 +400,7 @@
 
                 // Connects to the SOCKS server
                 try {
-                    privilegedConnect(server, serverPort, timeout);
+                    privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
                     // Worked, let's get outta here
                     break;
                 } catch (IOException e) {
@@ -388,7 +424,7 @@
         } else {
             // Connects to the SOCKS server
             try {
-                privilegedConnect(server, serverPort, timeout);
+                privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
             } catch (IOException e) {
                 throw new SocketException(e.getMessage());
             }
@@ -403,7 +439,7 @@
             // DOMAIN type of addresses (unresolved addresses here)
             if (epoint.isUnresolved())
                 throw new UnknownHostException(epoint.toString());
-            connectV4(in, out, epoint);
+            connectV4(in, out, epoint, deadlineMillis);
             return;
         }
 
@@ -414,7 +450,7 @@
         out.write(USER_PASSW);
         out.flush();
         byte[] data = new byte[2];
-        int i = readSocksReply(in, data);
+        int i = readSocksReply(in, data, deadlineMillis);
         if (i != 2 || ((int)data[0]) != PROTO_VERS) {
             // Maybe it's not a V5 sever after all
             // Let's try V4 before we give up
@@ -422,12 +458,12 @@
             // DOMAIN type of addresses (unresolved addresses here)
             if (epoint.isUnresolved())
                 throw new UnknownHostException(epoint.toString());
-            connectV4(in, out, epoint);
+            connectV4(in, out, epoint, deadlineMillis);
             return;
         }
         if (((int)data[1]) == NO_METHODS)
             throw new SocketException("SOCKS : No acceptable methods");
-        if (!authenticate(data[1], in, out)) {
+        if (!authenticate(data[1], in, out, deadlineMillis)) {
             throw new SocketException("SOCKS : authentication failed");
         }
         out.write(PROTO_VERS);
@@ -457,7 +493,7 @@
         }
         out.flush();
         data = new byte[4];
-        i = readSocksReply(in, data);
+        i = readSocksReply(in, data, deadlineMillis);
         if (i != 4)
             throw new SocketException("Reply from SOCKS server has bad length");
         SocketException ex = null;
@@ -469,33 +505,33 @@
             switch(data[3]) {
             case IPV4:
                 addr = new byte[4];
-                i = readSocksReply(in, addr);
+                i = readSocksReply(in, addr, deadlineMillis);
                 if (i != 4)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 data = new byte[2];
-                i = readSocksReply(in, data);
+                i = readSocksReply(in, data, deadlineMillis);
                 if (i != 2)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 break;
             case DOMAIN_NAME:
                 len = data[1];
                 byte[] host = new byte[len];
-                i = readSocksReply(in, host);
+                i = readSocksReply(in, host, deadlineMillis);
                 if (i != len)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 data = new byte[2];
-                i = readSocksReply(in, data);
+                i = readSocksReply(in, data, deadlineMillis);
                 if (i != 2)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 break;
             case IPV6:
                 len = data[1];
                 addr = new byte[len];
-                i = readSocksReply(in, addr);
+                i = readSocksReply(in, addr, deadlineMillis);
                 if (i != len)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 data = new byte[2];
-                i = readSocksReply(in, data);
+                i = readSocksReply(in, data, deadlineMillis);
                 if (i != 2)
                     throw new SocketException("Reply from SOCKS server badly formatted");
                 break;
--- a/src/share/classes/java/util/zip/ZipFile.java	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/classes/java/util/zip/ZipFile.java	Fri Mar 12 09:06:00 2010 -0800
@@ -36,6 +36,8 @@
 import java.util.Set;
 import java.util.HashSet;
 import java.util.NoSuchElementException;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
 import static java.util.zip.ZipConstants64.*;
 
 /**
@@ -78,6 +80,17 @@
 
     private static native void initIDs();
 
+    private static final boolean usemmap;
+
+    static {
+        // A system prpperty to disable mmap use to avoid vm crash when
+        // in-use zip file is accidently overwritten by others.
+        String prop = AccessController.doPrivileged(
+            new GetPropertyAction("sun.zip.disableMemoryMapping"));
+        usemmap = (prop == null ||
+                   !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
+    }
+
     /**
      * Opens a zip file for reading.
      *
@@ -196,7 +209,7 @@
             throw new NullPointerException("charset is null");
         this.zc = ZipCoder.get(charset);
         long t0 = System.nanoTime();
-        jzfile = open(name, mode, file.lastModified());
+        jzfile = open(name, mode, file.lastModified(), usemmap);
         sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
         sun.misc.PerfCounter.getZipFileCount().increment();
         this.name = name;
@@ -673,8 +686,8 @@
     }
 
 
-    private static native long open(String name, int mode, long lastModified)
-        throws IOException;
+    private static native long open(String name, int mode, long lastModified,
+                                    boolean usemmap) throws IOException;
     private static native int getTotal(long jzfile);
     private static native int read(long jzfile, long jzentry,
                                    long pos, byte[] b, int off, int len);
--- a/src/share/native/java/util/zip/ZipFile.c	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/native/java/util/zip/ZipFile.c	Fri Mar 12 09:06:00 2010 -0800
@@ -81,7 +81,8 @@
 
 JNIEXPORT jlong JNICALL
 Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
-                                        jint mode, jlong lastModified)
+                                        jint mode, jlong lastModified,
+                                        jboolean usemmap)
 {
     const char *path = JNU_GetStringPlatformChars(env, name, 0);
     char *msg = 0;
@@ -109,7 +110,7 @@
                 goto finally;
             }
 #endif
-            zip = ZIP_Put_In_Cache(path, zfd, &msg, lastModified);
+            zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
         }
 
         if (zip != 0) {
--- a/src/share/native/java/util/zip/zip_util.c	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/native/java/util/zip/zip_util.c	Fri Mar 12 09:06:00 2010 -0800
@@ -251,11 +251,16 @@
     if (zip->lock != NULL) MDESTROY(zip->lock);
     free(zip->name);
     freeCEN(zip);
+
 #ifdef USE_MMAP
-    if (zip->maddr != NULL) munmap((char *)zip->maddr, zip->mlen);
-#else
-    free(zip->cencache.data);
+    if (zip->usemmap) {
+        if (zip->maddr != NULL)
+            munmap((char *)zip->maddr, zip->mlen);
+    } else
 #endif
+    {
+        free(zip->cencache.data);
+    }
     if (zip->comment != NULL)
         free(zip->comment);
     if (zip->zfd != -1) ZFILE_Close(zip->zfd);
@@ -585,49 +590,53 @@
         ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");
 
 #ifdef USE_MMAP
-     /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
-      * read the jar file contents. However, this greatly increased the perceived
-      * footprint numbers because the mmap'ed pages were adding into the totals shown
-      * by 'ps' and 'top'. We switched to mmaping only the central directory of jar
-      * file while calling 'read' to read the rest of jar file. Here are a list of
-      * reasons apart from above of why we are doing so:
-      * 1. Greatly reduces mmap overhead after startup complete;
-      * 2. Avoids dual path code maintainance;
-      * 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
-      */
-    if (pagesize == 0) {
-        pagesize = (jlong)sysconf(_SC_PAGESIZE);
-        if (pagesize == 0) goto Catch;
+    if (zip->usemmap) {
+      /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
+       * read the jar file contents. However, this greatly increased the perceived
+       * footprint numbers because the mmap'ed pages were adding into the totals shown
+       * by 'ps' and 'top'. We switched to mmaping only the central directory of jar
+       * file while calling 'read' to read the rest of jar file. Here are a list of
+       * reasons apart from above of why we are doing so:
+       * 1. Greatly reduces mmap overhead after startup complete;
+       * 2. Avoids dual path code maintainance;
+       * 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
+       */
+        if (pagesize == 0) {
+            pagesize = (jlong)sysconf(_SC_PAGESIZE);
+            if (pagesize == 0) goto Catch;
+        }
+        if (cenpos > pagesize) {
+            offset = cenpos & ~(pagesize - 1);
+        } else {
+            offset = 0;
+        }
+        /* When we are not calling recursively, knownTotal is -1. */
+        if (knownTotal == -1) {
+            void* mappedAddr;
+            /* Mmap the CEN and END part only. We have to figure
+               out the page size in order to make offset to be multiples of
+               page size.
+            */
+            zip->mlen = cenpos - offset + cenlen + endhdrlen;
+            zip->offset = offset;
+            mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
+            zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
+                (unsigned char*)mappedAddr;
+
+            if (zip->maddr == NULL) {
+                jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
+                goto Catch;
+            }
+        }
+        cenbuf = zip->maddr + cenpos - offset;
+    } else
+#endif
+    {
+        if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
+            (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
+        goto Catch;
     }
-    if (cenpos > pagesize) {
-        offset = cenpos & ~(pagesize - 1);
-    } else {
-        offset = 0;
-    }
-    /* When we are not calling recursively, knownTotal is -1. */
-    if (knownTotal == -1) {
-        void* mappedAddr;
-        /* Mmap the CEN and END part only. We have to figure
-           out the page size in order to make offset to be multiples of
-           page size.
-        */
-        zip->mlen = cenpos - offset + cenlen + endhdrlen;
-        zip->offset = offset;
-        mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
-        zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
-            (unsigned char*)mappedAddr;
 
-        if (zip->maddr == NULL) {
-            jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
-            goto Catch;
-        }
-    }
-    cenbuf = zip->maddr + cenpos - offset;
-#else
-    if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
-        (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
-        goto Catch;
-#endif
     cenend = cenbuf + cenlen;
 
     /* Initialize zip file data structures based on the total number
@@ -700,9 +709,11 @@
     cenpos = -1;
 
  Finally:
-#ifndef USE_MMAP
-    free(cenbuf);
+#ifdef USE_MMAP
+    if (!zip->usemmap)
 #endif
+        free(cenbuf);
+
     return cenpos;
 }
 
@@ -782,9 +793,17 @@
  * If a zip error occurs, then *pmsg will be set to the error message text if
  * pmsg != 0. Otherwise, *pmsg will be set to NULL.
  */
+
 jzfile *
 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
 {
+    return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE);
+}
+
+jzfile *
+ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
+                 jboolean usemmap)
+{
     static char errbuf[256];
     jlong len;
     jzfile *zip;
@@ -793,6 +812,9 @@
         return NULL;
     }
 
+#ifdef USE_MMAP
+    zip->usemmap = usemmap;
+#endif
     zip->refs = 1;
     zip->lastModified = lastModified;
 
@@ -877,8 +899,6 @@
     return;
 }
 
-#ifndef USE_MMAP
-
 /* Empirically, most CEN headers are smaller than this. */
 #define AMPLE_CEN_HEADER_SIZE 160
 
@@ -928,7 +948,6 @@
     cache->pos  = cenpos;
     return cen;
 }
-#endif /* not USE_MMAP */
 
 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
 
@@ -953,14 +972,17 @@
     ze->comment = NULL;
 
 #ifdef USE_MMAP
-    cen = (char*) zip->maddr + zc->cenpos - zip->offset;
-#else
-    if (accessHint == ACCESS_RANDOM)
-        cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
-    else
-        cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
-    if (cen == NULL) goto Catch;
+    if (zip->usemmap) {
+        cen = (char*) zip->maddr + zc->cenpos - zip->offset;
+    } else
 #endif
+    {
+        if (accessHint == ACCESS_RANDOM)
+            cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
+        else
+            cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
+        if (cen == NULL) goto Catch;
+    }
 
     nlen      = CENNAM(cen);
     elen      = CENEXT(cen);
@@ -976,7 +998,6 @@
     if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
     memcpy(ze->name, cen + CENHDR, nlen);
     ze->name[nlen] = '\0';
-
     if (elen > 0) {
         char *extra = cen + CENHDR + nlen;
 
@@ -1037,9 +1058,10 @@
     ze = NULL;
 
  Finally:
-#ifndef USE_MMAP
-    if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
+#ifdef USE_MMAP
+    if (!zip->usemmap)
 #endif
+        if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
     return ze;
 }
 
--- a/src/share/native/java/util/zip/zip_util.h	Fri Mar 12 09:03:02 2010 -0800
+++ b/src/share/native/java/util/zip/zip_util.h	Fri Mar 12 09:06:00 2010 -0800
@@ -45,9 +45,6 @@
  * Header sizes including signatures
  */
 
-#ifdef USE_MMAP
-#define SIGSIZ  4
-#endif
 #define LOCHDR 30
 #define EXTHDR 16
 #define CENHDR 46
@@ -211,9 +208,9 @@
     jlong mlen;           /* length (in bytes) mmaped */
     jlong offset;         /* offset of the mmapped region from the
                              start of the file. */
-#else
+    jboolean usemmap;     /* if mmap is used. */
+#endif
     cencache cencache;    /* CEN header cache */
-#endif
     ZFILE zfd;            /* open file descriptor */
     void *lock;           /* read lock */
     char *comment;        /* zip file comment */
@@ -259,6 +256,9 @@
 jzfile *
 ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified);
 
+jzfile *
+ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, jboolean usemmap);
+
 void JNICALL
 ZIP_Close(jzfile *zip);
 
--- a/test/ProblemList.txt	Fri Mar 12 09:03:02 2010 -0800
+++ b/test/ProblemList.txt	Fri Mar 12 09:06:00 2010 -0800
@@ -700,7 +700,6 @@
 java/net/URLConnection/ZeroContentLength.java		 	generic-all
 
 # Solaris 11 i586 fails with samevm, not sure why
-java/net/HttpURLConnection/HttpResponseCode.java		generic-all
 java/net/ResponseCache/B6181108.java				generic-all
 java/net/ResponseCache/ResponseCacheTest.java			generic-all
 java/net/URL/GetContent.java					generic-all
--- a/test/java/net/CookieHandler/CookieHandlerTest.java	Fri Mar 12 09:03:02 2010 -0800
+++ b/test/java/net/CookieHandler/CookieHandlerTest.java	Fri Mar 12 09:06:00 2010 -0800
@@ -24,9 +24,13 @@
 /* @test
  * @summary Unit test for java.net.CookieHandler
  * @bug 4696506
+ * @run main/othervm CookieHandlerTest
  * @author Yingxian Wang
  */
 
+// Run in othervm since a default cookier handler is set and this
+// can effect other HTTP related tests.
+
 import java.net.*;
 import java.util.*;
 import java.io.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/net/Socket/SocksConnectTimeout.java	Fri Mar 12 09:06:00 2010 -0800
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6223635
+ * @summary Code hangs at connect call even when Timeout is specified
+ */
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.SocketTimeoutException;
+import java.io.IOException;
+import java.io.Closeable;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.TimeUnit;
+
+public class SocksConnectTimeout {
+    static ServerSocket serverSocket;
+    static final boolean debug = true;
+    static final Phaser startPhaser = new Phaser(2);
+    static final Phaser finishPhaser = new Phaser(2);
+    static int failed, passed;
+
+    public static void main(String[] args) {
+        try {
+            serverSocket = new ServerSocket(0);
+
+            (new Thread() {
+                @Override
+                public void run() { serve(); }
+            }).start();
+
+            Proxy socksProxy = new Proxy(Proxy.Type.SOCKS,
+                new InetSocketAddress(InetAddress.getLocalHost(), serverSocket.getLocalPort()));
+
+            test(socksProxy);
+        } catch (IOException e) {
+            unexpected(e);
+        } finally {
+            close(serverSocket);
+
+            if (failed > 0)
+                throw new RuntimeException("Test Failed: passed:" + passed + ", failed:" + failed);
+        }
+    }
+
+    static void test(Proxy proxy) {
+        startPhaser.arriveAndAwaitAdvance();
+        Socket socket = null;
+        try {
+            socket = new Socket(proxy);
+            connectWithTimeout(socket);
+            failed("connected successfully!");
+        } catch (SocketTimeoutException socketTimeout) {
+            debug("Passed: Received: " + socketTimeout);
+            passed();
+        } catch (Exception exception) {
+            failed("Connect timeout test failed", exception);
+        } finally {
+            finishPhaser.arriveAndAwaitAdvance();
+            close(socket);
+        }
+    }
+
+    static void connectWithTimeout(Socket socket) throws IOException {
+        socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 1234), 500);
+    }
+
+    static void serve() {
+        Socket client = null;
+        try {
+            startPhaser.arriveAndAwaitAdvance();
+            client = serverSocket.accept();
+            finishPhaser.awaitAdvanceInterruptibly(finishPhaser.arrive(), 5, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            unexpected(e);
+        } finally {
+            close(client);
+        }
+    }
+
+    static void debug(String message) {
+        if (debug)
+            System.out.println(message);
+    }
+
+    static void unexpected(Exception e ) {
+        System.out.println("Unexcepted Exception: " + e);
+    }
+
+    static void close(Closeable closeable) {
+        if (closeable != null) try { closeable.close(); } catch (IOException e) {unexpected(e);}
+    }
+
+    static void failed(String message) {
+        System.out.println(message);
+        failed++;
+    }
+
+    static void failed(String message, Exception e) {
+        System.out.println(message);
+        System.out.println(e);
+        failed++;
+    }
+
+    static void passed() { passed++; };
+
+}