OpenJDK / amber / amber
changeset 5150:ba30c55414f6
Merge
author | ohair |
---|---|
date | Fri, 12 Mar 2010 09:06:00 -0800 |
parents | efce9634bfc0 2bf5469864ea |
children | e62028f44cf6 |
files | jdk/test/ProblemList.txt |
diffstat | 9 files changed, 306 insertions(+), 95 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/java/net/SocketInputStream.java Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/src/share/classes/java/net/SocksSocketImpl.java Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/src/share/classes/java/util/zip/ZipFile.java Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/src/share/native/java/util/zip/ZipFile.c Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/src/share/native/java/util/zip/zip_util.c Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/src/share/native/java/util/zip/zip_util.h Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/test/ProblemList.txt Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/test/java/net/CookieHandler/CookieHandlerTest.java Fri Mar 12 09:03:02 2010 -0800 +++ b/jdk/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/jdk/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++; }; + +}