test/hotspot/jtreg/vmTestbase/nsk/stress/network/network003.java
branchJDK-8200758-branch
changeset 57063 1fa5c73d3c5a
parent 57062 044e7a644ee3
parent 52899 325c95779368
child 57064 a7fdadf67a92
equal deleted inserted replaced
57062:044e7a644ee3 57063:1fa5c73d3c5a
     1 /*
       
     2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 
       
    25 /*
       
    26  * @test
       
    27  * @key stress
       
    28  *
       
    29  * @summary converted from VM testbase nsk/stress/network/network003.
       
    30  * VM testbase keywords: [stress, slow, nonconcurrent, quick]
       
    31  * VM testbase readme:
       
    32  * DESCRIPTION
       
    33  *     This test transfers huge amount of data between one server and multiple
       
    34  *     clients communicating via TCP/IP sockets, and checks if those data are
       
    35  *     transfered correctly. All TCP/IP sockets are attached to local host
       
    36  *     (by its domain name), or to the ``localhost'' loopback (having the IP
       
    37  *     address 127.0.0.1).
       
    38  *     In this test, 128 client/server connections are established. Once a
       
    39  *     connection is established, client passes a large data parcel to server,
       
    40  *     and server reads that parcel and checks if it is same as expected
       
    41  *     (byte-to-byte equality is desired). Then server passes (some other) parcel
       
    42  *     to the client, and client reads and verifies those bytes. This ping-pong
       
    43  *     game is repeated 128 times; and after that each pair of sockets checks if
       
    44  *     there are no extra bytes accudentally passed through their connection.
       
    45  *     Parcels lengths and contents are chosen randomly, and average parcel
       
    46  *     length is 128 bytes. So totally, each pair of sockets passes ~16Kb of
       
    47  *     data to each other, and thus ~32Kb of data are transfered by each sockets
       
    48  *     pair. Totally, ~4Mb of data are transfered by all client/server pairs.
       
    49  * COMMENTS
       
    50  *     The production Solaris_JDK_1.3-b12 Server VM crashes under this test:
       
    51  *         #
       
    52  *         # HotSpot Virtual Machine Error, Unexpected Signal 10
       
    53  *         # Please report this error at
       
    54  *         # http://java.sun.com/cgi-bin/bugreport.cgi
       
    55  *         #
       
    56  *         # Error ID: 4F533F534F4C415249530E43505007D9 01
       
    57  *         #
       
    58  *         # Problematic Thread: prio=5 tid=0x214418 nid=0x103 runnable
       
    59  *         #
       
    60  *     (ErrorID == "os_solaris.cpp, 2009")
       
    61  *
       
    62  * @run main/othervm nsk.stress.network.network003
       
    63  */
       
    64 
       
    65 package nsk.stress.network;
       
    66 
       
    67 import java.io.IOException;
       
    68 import java.io.InputStream;
       
    69 import java.io.OutputStream;
       
    70 import java.io.PrintStream;
       
    71 import java.net.InetAddress;
       
    72 import java.net.ServerSocket;
       
    73 import java.net.Socket;
       
    74 import java.net.UnknownHostException;
       
    75 import java.util.Random;
       
    76 
       
    77 /**
       
    78  * This test transfers huge amount of data between one server and multiple
       
    79  * clients communicating via TCP/IP sockets, and checks if those data are
       
    80  * transfered correctly. All TCP/IP sockets are attached to local host
       
    81  * (by its domain name), or to the ``localhost'' loopback (having the IP
       
    82  * address 127.0.0.1).
       
    83  * <p>
       
    84  * <p>In this test, 128 client/server connections are established. Once a
       
    85  * connection is established, client passes a large data parcel to server,
       
    86  * and server reads that parcel and checks if it is same as expected
       
    87  * (byte-to-byte equality is desired). Then server passes (some other) parcel
       
    88  * to the client, and client reads and verifies those bytes. This ping-pong
       
    89  * game is repeated 128 times; and after that each pair of sockets checks if
       
    90  * there are no extra bytes accudentally passed through their connection.
       
    91  * <p>
       
    92  * <p>Parcels lengths and contents are chosen randomly, and average parcel
       
    93  * length is 128 bytes. So totally, each pair of sockets passes ~16Kb of
       
    94  * data to each other, and thus ~32Kb of data are transfered by each sockets
       
    95  * pair. Totally, ~4Mb of data are transfered by all client/server pairs.
       
    96  */
       
    97 public class network003 {
       
    98     /**
       
    99      * Do actually display optional reports?
       
   100      */
       
   101     static private final boolean DEBUG_MODE = false;
       
   102 
       
   103     /**
       
   104      * Errors and optional reports log. Usually <code>System.out</code>.
       
   105      */
       
   106     static private PrintStream out = System.out;
       
   107 
       
   108     /**
       
   109      * Print error message: all clients and servers may print concurently.
       
   110      */
       
   111     static private synchronized void println(Object message) {
       
   112         out.println(message.toString());
       
   113     }
       
   114 
       
   115     /**
       
   116      * Display optional report: comment ca va.
       
   117      */
       
   118     static private void display(Object report) {
       
   119         if (DEBUG_MODE)
       
   120             println(report.toString());
       
   121     }
       
   122 
       
   123     /**
       
   124      * Maximal number of connections this test should open simultaneously.
       
   125      */
       
   126     private final static int MAX_CONNECTIONS = 128;
       
   127 
       
   128     /**
       
   129      * Check few more connections to make sure that MAX_CONNECTIONS are safe.
       
   130      */
       
   131     private final static int CONNECTIONS_RESERVE = 10;
       
   132 
       
   133     /**
       
   134      * Number of client/server connections to establish.
       
   135      */
       
   136     private static final int CONNECTIONS = detectOSLimitation();
       
   137 
       
   138     /**
       
   139      * Number of parcels to be sent/recieved.
       
   140      */
       
   141     private static final int DATA_PARCELS = 128;
       
   142 
       
   143     /**
       
   144      * Maximal length of data parcel to be sent/recieved
       
   145      * (it equals to 256 bytes now).
       
   146      */
       
   147     private static final int MAX_PARCEL = 1 << 8;
       
   148 
       
   149     /**
       
   150      * How many IP sockets can we open simultaneously?
       
   151      * Check if <code>MAX_CONNECTIONS</code> connections
       
   152      * can be open simultaneously.
       
   153      */
       
   154     private static int detectOSLimitation() {
       
   155         final int CONNECTIONS_TO_TRY = MAX_CONNECTIONS + CONNECTIONS_RESERVE;
       
   156         ServerSocket ssoc[] = new ServerSocket[CONNECTIONS_TO_TRY];
       
   157         display("--- Trying to open " + CONNECTIONS_TO_TRY + " connections:");
       
   158         int i;
       
   159         for (i = 0; i < CONNECTIONS_TO_TRY; i++)
       
   160             try {
       
   161                 ssoc[i] = new ServerSocket(0);
       
   162                 display("--- Open: ssoc[" + i + "] = " + ssoc[i]);
       
   163             } catch (IOException ioe) {
       
   164                 display("--- OOPS! -- failed to open connection #" + i);
       
   165                 break;
       
   166             }
       
   167         display("--- Could open " +
       
   168                 (i < CONNECTIONS_TO_TRY ? "only " : "") + i + " connections.");
       
   169         display("--- Closing them:");
       
   170         for (int j = 0; j < i; j++)
       
   171             try {
       
   172                 ssoc[j].close();
       
   173             } catch (IOException ioe) {
       
   174                 throw new Error("FATAL error while loading the test: " + ioe);
       
   175             }
       
   176         display("--- OK.");
       
   177         int safeConnections = i - CONNECTIONS_RESERVE;
       
   178         if (safeConnections < 1)
       
   179             safeConnections = 1;
       
   180         if (safeConnections < MAX_CONNECTIONS) {
       
   181             println("# ------------------------- CAUTION: -------------------");
       
   182             println("# While checking the OS limitations, the test found that");
       
   183             println("# only " + i + " TCP/IP socket connections could be safely open");
       
   184             println("# simultaneously. However, possibility to open at least");
       
   185             println("# " + MAX_CONNECTIONS + "+" + CONNECTIONS_RESERVE
       
   186                     + " connections were expected.");
       
   187             println("# ");
       
   188             println("# So, the test will check only " + safeConnections + " connection"
       
   189                     + (safeConnections == 1 ? "" : "s") + " which seem");
       
   190             println("# safe to be open simultaneously.");
       
   191             println("# ------------------------------------------------------");
       
   192         }
       
   193         return safeConnections;
       
   194     }
       
   195 
       
   196     /**
       
   197      * Server thread intended to reply to data parcels sent by Client thread.
       
   198      */
       
   199     static private class Server extends Thread {
       
   200         /**
       
   201          * This server thread listens the single socket.
       
   202          */
       
   203         private ServerSocket serverSocket;
       
   204 
       
   205         /**
       
   206          * Address and port of this server socket.
       
   207          */
       
   208         public String toString() {
       
   209             return serverSocket.toString();
       
   210         }
       
   211 
       
   212         /**
       
   213          * Did the thread failed? If yes, what is the failure's reason.
       
   214          */
       
   215         Exception exception = null;
       
   216 
       
   217         /**
       
   218          * What is the port number this socket is listening for?
       
   219          */
       
   220         int getPort() {
       
   221             return serverSocket.getLocalPort();
       
   222         }
       
   223 
       
   224         /**
       
   225          * Find some free port at the given <code>address</code>
       
   226          * and attach new server to hear that port.
       
   227          */
       
   228         Server(InetAddress address) throws IOException {
       
   229             int someFreePort = 0;
       
   230             int backlog = 50; // default for new ServerSocket(port)
       
   231             serverSocket = new ServerSocket(someFreePort, backlog, address);
       
   232         }
       
   233 
       
   234         /**
       
   235          * Accept connection, then read/respond <code>DATA_PARCELS</code> parcels
       
   236          * of random data. Set initial seed for pseudo-random numbers generator
       
   237          * to the value of the local port number.
       
   238          *
       
   239          * @see #DATA_PARCELS
       
   240          * @see #getPort()
       
   241          */
       
   242         public void run() {
       
   243             try {
       
   244                 Socket socket = serverSocket.accept();
       
   245                 display("Server socket: " + socket);
       
   246 
       
   247                 InputStream istream = socket.getInputStream();
       
   248                 OutputStream ostream = socket.getOutputStream();
       
   249 
       
   250                 Random random = new Random(getPort());
       
   251 
       
   252                 for (int i = 0; i < DATA_PARCELS; i++) {
       
   253                     Parcel etalon = new Parcel(random);
       
   254 
       
   255                     Parcel sample = new Parcel(istream); // read
       
   256                     if (!sample.equals(etalon)) {
       
   257                         println("Server thread for port #"
       
   258                                 + getPort() + " got unexpected parcel:\n"
       
   259                                 + "sample=" + sample + "\n"
       
   260                                 + "etalon=" + etalon);
       
   261                         throw new TestFailure(
       
   262                                 "server has read unexpected parcel");
       
   263                     }
       
   264 
       
   265                     etalon.send(ostream);
       
   266                     ostream.flush();
       
   267                 }
       
   268 
       
   269                 int datum = istream.read(); // wait for client close()
       
   270                 if (datum >= 0)
       
   271                     throw new TestFailure(
       
   272                             "server has read ambigous byte: " + datum);
       
   273 
       
   274                 ostream.close(); // implies: socket.close();
       
   275 
       
   276             } catch (Exception oops) {
       
   277                 exception = oops;
       
   278             }
       
   279         }
       
   280 
       
   281     }
       
   282 
       
   283     /**
       
   284      * Client thread intended to send data parcels to Server thread and
       
   285      * to recieve the server's replies.
       
   286      */
       
   287     static private class Client extends Thread {
       
   288         /**
       
   289          * This thread uses the single client socket.
       
   290          */
       
   291         private Socket socket;
       
   292 
       
   293         /**
       
   294          * Address and port of this socket.
       
   295          */
       
   296         public String toString() {
       
   297             return socket.toString();
       
   298         }
       
   299 
       
   300         /**
       
   301          * Did the thread failed? If yes, what is the failure's reason.
       
   302          */
       
   303         Exception exception = null;
       
   304 
       
   305         /**
       
   306          * Connect client socket on the given <code>address</code>
       
   307          * and <code>port</code>.
       
   308          */
       
   309         Client(InetAddress address, int port) throws IOException {
       
   310             socket = new Socket(address, port);
       
   311         }
       
   312 
       
   313         /**
       
   314          * What is the port number this socket is listening for?
       
   315          */
       
   316         int getPort() {
       
   317             return socket.getPort();
       
   318         }
       
   319 
       
   320 
       
   321         /**
       
   322          * Establish connection, then read/respond <code>DATA_PARCELS</code> parcels
       
   323          * of random data. Set initial seed for pseudo-random numbers generator
       
   324          * to the value of the local port number.
       
   325          *
       
   326          * @see #DATA_PARCELS
       
   327          * @see #getPort()
       
   328          */
       
   329         public void run() {
       
   330             try {
       
   331                 InputStream istream = socket.getInputStream();
       
   332                 OutputStream ostream = socket.getOutputStream();
       
   333 
       
   334                 Random random = new Random(getPort());
       
   335 
       
   336                 for (int i = 0; i < DATA_PARCELS; i++) {
       
   337                     Parcel etalon = new Parcel(random);
       
   338                     etalon.send(ostream);
       
   339                     ostream.flush();
       
   340 
       
   341                     Parcel sample = new Parcel(istream); // read
       
   342                     if (!sample.equals(etalon)) {
       
   343                         println("Client thread for port #"
       
   344                                 + getPort() + " got unexpected parcel:\n"
       
   345                                 + "sample=" + sample + "\n"
       
   346                                 + "etalon=" + etalon);
       
   347                         throw new TestFailure(
       
   348                                 "parcel context is unexpected to client");
       
   349                     }
       
   350                 }
       
   351 
       
   352                 if (istream.available() > 0) {
       
   353                     int datum = istream.read();
       
   354                     throw new TestFailure(
       
   355                             "client has read ambigous byte: " + datum);
       
   356                 }
       
   357                 ostream.close(); // implies: socket.close()
       
   358 
       
   359             } catch (Exception oops) {
       
   360                 exception = oops;
       
   361             }
       
   362         }
       
   363 
       
   364     }
       
   365 
       
   366     /**
       
   367      * A data parcel to sent/recieved between Client and Server threads.
       
   368      * When data parcel is sent, first 4 bytes transfered encode the size
       
   369      * of the parcel (i.e.: number of data bytes in the parcel's contents).
       
   370      * Then the parcel's contents bytes are transered.
       
   371      */
       
   372     static class Parcel {
       
   373         private byte[] parcel;
       
   374 
       
   375         /**
       
   376          * Display all bytes as integer values from 0 to 255;
       
   377          * or return ``<tt>null</tt>'' if this Parcel is not
       
   378          * yet initialized.
       
   379          */
       
   380         public String toString() {
       
   381             if (parcel == null)
       
   382                 return "null";
       
   383             String s = "{";
       
   384             for (int i = 0; i < parcel.length; i++)
       
   385                 s += (i > 0 ? ", " : "") + ((int) parcel[i] & 0xFF);
       
   386             return s + "}";
       
   387         }
       
   388 
       
   389         /**
       
   390          * Generate new <code>parcel[]</code> array using the given
       
   391          * <code>random</code> numbers generator. Client and Server
       
   392          * threads should use identical <code>random</code> generators,
       
   393          * so that those threads could generate equal data parcels and
       
   394          * check the parcel just transfered.
       
   395          */
       
   396         public Parcel(Random random) {
       
   397             int size = random.nextInt(MAX_PARCEL) + 1;
       
   398             parcel = new byte[size];
       
   399             for (int i = 0; i < size; i++)
       
   400                 parcel[i] = (byte) random.nextInt(256);
       
   401         }
       
   402 
       
   403         /**
       
   404          * Read exactly <code>size</code> bytes from the <code>istream</code>
       
   405          * if possible, or throw <code>TestFailure</code> if unexpected end of
       
   406          * <code>istream</code> occurs.
       
   407          */
       
   408         private static byte[] readBytes(int size, InputStream istream)
       
   409                 throws IOException {
       
   410 
       
   411             byte data[] = new byte[size];
       
   412             for (int i = 0; i < size; i++) {
       
   413                 int datum = istream.read();
       
   414                 if (datum < 0)
       
   415                     throw new TestFailure(
       
   416                             "unexpected EOF: have read: " + i + " bytes of " + size);
       
   417                 data[i] = (byte) datum;
       
   418             }
       
   419             return data;
       
   420         }
       
   421 
       
   422         /**
       
   423          * Read 4 bytes from <code>istream</code> and threat them to encode
       
   424          * size of data parcel following these 4 bytes.
       
   425          */
       
   426         private static int getSize(InputStream istream) throws IOException {
       
   427             byte data[] = readBytes(4, istream);
       
   428             int data0 = (int) data[0] & 0xFF;
       
   429             int data1 = (int) data[1] & 0xFF;
       
   430             int data2 = (int) data[2] & 0xFF;
       
   431             int data3 = (int) data[3] & 0xFF;
       
   432             int sizeWord = data0 + (data1 << 8) + (data2 << 16) + (data3 << 24);
       
   433             int size = sizeWord + 1;
       
   434             if (size <= 0)
       
   435                 throw new TestFailure("illegal size: " + size);
       
   436             return size;
       
   437         }
       
   438 
       
   439         /**
       
   440          * Send 4 bytes encoding actual size of the parcel just to be transfered.
       
   441          */
       
   442         private static void putSize(OutputStream ostream, int size)
       
   443                 throws IOException {
       
   444 
       
   445             if (size <= 0)
       
   446                 throw new TestFailure("illegal size: " + size);
       
   447 
       
   448             int sizeWord = size - 1;
       
   449             byte data[] = new byte[4];
       
   450             data[0] = (byte) sizeWord;
       
   451             data[1] = (byte) (sizeWord >> 8);
       
   452             data[2] = (byte) (sizeWord >> 16);
       
   453             data[3] = (byte) (sizeWord >> 24);
       
   454             ostream.write(data);
       
   455         }
       
   456 
       
   457         /**
       
   458          * Recieve data parcel.
       
   459          */
       
   460         public Parcel(InputStream istream) throws IOException {
       
   461             int size = getSize(istream);
       
   462             parcel = readBytes(size, istream);
       
   463         }
       
   464 
       
   465         /**
       
   466          * Send <code>this</code> data parcel.
       
   467          */
       
   468         public void send(OutputStream ostream) throws IOException {
       
   469             int size = parcel.length;
       
   470             putSize(ostream, size);
       
   471             ostream.write(parcel);
       
   472         }
       
   473 
       
   474         /**
       
   475          * Check byte-to-byte equality between <code>this</code> and the
       
   476          * <code>other</code> parcels.
       
   477          */
       
   478         public boolean equals(Parcel other) {
       
   479             if (this.parcel.length != other.parcel.length)
       
   480                 return false;
       
   481             int size = parcel.length;
       
   482             for (int i = 0; i < size; i++)
       
   483                 if (this.parcel[i] != other.parcel[i])
       
   484                     return false;
       
   485             return true;
       
   486         }
       
   487 
       
   488     }
       
   489 
       
   490     /**
       
   491      * Server or Client thread may throw this exception to report the test
       
   492      * failure.
       
   493      */
       
   494     static class TestFailure extends RuntimeException {
       
   495         /**
       
   496          * Report particular <code>purpose</code> of the test failure.
       
   497          */
       
   498         public TestFailure(String purpose) {
       
   499             super(purpose);
       
   500         }
       
   501 
       
   502     }
       
   503 
       
   504     /**
       
   505      * Attach client and server sockets to the local host, and check if
       
   506      * huge amount of data could be correctly transfered between these
       
   507      * sockets.
       
   508      * <p>
       
   509      * <p>Command-line parameters provided with <code>args[]</code> may
       
   510      * prompt the local host IP address or domain name. Execute:
       
   511      * <br>&nbsp;&nbsp;
       
   512      * <code>java network003 [<i>IP-address</i> | <i>host_name</i> |
       
   513      * localhost ]</code>
       
   514      * <br>where parameters are:
       
   515      * <br>&nbsp;&nbsp;
       
   516      * <code><i>IP-address</i></code> - local hots's address, or 127.0.0.1
       
   517      * <br>&nbsp;&nbsp;
       
   518      * <code><i>host_name</i></code> - local host's domain name, or the
       
   519      * keyword ``<code>localhost</code>''
       
   520      * <br>&nbsp;&nbsp;
       
   521      * <code>localhost</code> - placeholder for the IP-address 127.0.0.1
       
   522      * <br>By default, the test uses the Internet address available via
       
   523      * the method <code>InetAddress.getLocalHost()</code>
       
   524      */
       
   525     public static int run(String args[], PrintStream out) {
       
   526         network003.out = out;
       
   527 
       
   528         //
       
   529         // Get IP address of the local machine.
       
   530         //
       
   531 
       
   532         InetAddress address = null;
       
   533         try {
       
   534             switch (args.length) {
       
   535                 case 0:
       
   536                     address = InetAddress.getLocalHost();
       
   537                     break;
       
   538                 case 1:
       
   539                     String hostName = args[0];
       
   540                     address = InetAddress.getByName(args[0]);
       
   541                     break;
       
   542                 default:
       
   543                     println("Use:");
       
   544                     println("    java network003");
       
   545                     println("or:");
       
   546                     println("    java network003 ${IP_ADDRESS}");
       
   547                     println("or:");
       
   548                     println("    java network003 ${HOST_NAME}");
       
   549                     println("or:");
       
   550                     println("    java network003 localhost");
       
   551                     return 2; // FAILED
       
   552             }
       
   553         } catch (UnknownHostException exception) {
       
   554             println(exception);
       
   555             return 2; // FAILED
       
   556         }
       
   557         display("Host: " + address);
       
   558 
       
   559         //
       
   560         // Incarnate the server & the client sockets.
       
   561         //
       
   562 
       
   563         Server server[] = new Server[CONNECTIONS];
       
   564         Client client[] = new Client[CONNECTIONS];
       
   565 
       
   566         for (int i = 0; i < CONNECTIONS; i++) {
       
   567             try {
       
   568                 server[i] = new Server(address);
       
   569             } catch (IOException io) {
       
   570                 println("Failed to create server #" + i + ": " + io);
       
   571                 return 2;
       
   572             }
       
   573             display("Server #" + i + ": " + server[i]);
       
   574         }
       
   575 
       
   576         for (int i = 0; i < CONNECTIONS; i++) {
       
   577             int port = server[i].getPort();
       
   578             try {
       
   579                 client[i] = new Client(address, port);
       
   580             } catch (IOException io) {
       
   581                 out.println("Failed to create client #" + i + ": " + io);
       
   582                 return 2;
       
   583             }
       
   584             display("Client socket #" + i + ": " + client[i]);
       
   585         }
       
   586 
       
   587         //
       
   588         // Execute the server and client threads.
       
   589         //
       
   590 
       
   591         Exception exception = null;
       
   592         try {
       
   593             for (int i = 0; i < CONNECTIONS; i++)
       
   594                 server[i].start();
       
   595             for (int i = 0; i < CONNECTIONS; i++)
       
   596                 client[i].start();
       
   597             boolean someIsAlive = true;
       
   598             while (someIsAlive) {
       
   599                 boolean aliveFound = false;
       
   600                 boolean someBroken = false;
       
   601                 for (int i = 0; i < CONNECTIONS; i++)
       
   602                     if (client[i].isAlive() || server[i].isAlive()) {
       
   603                         if ((client[i].exception != null) ||
       
   604                                 (server[i].exception != null))
       
   605                             someBroken = true;
       
   606                         aliveFound = true;
       
   607                         Thread.yield();
       
   608                     }
       
   609                 someIsAlive = aliveFound;
       
   610                 if (someBroken)
       
   611                     break;
       
   612             }
       
   613         } catch (TestFailure failure) {
       
   614             exception = failure;
       
   615         }
       
   616 
       
   617         // Failure diagnostics, if needed.
       
   618 
       
   619         Exception problem[] = new Exception[2 * CONNECTIONS + 1];
       
   620         problem[0] = exception;
       
   621         for (int i = 0; i < CONNECTIONS; i++) {
       
   622             problem[2 * i + 1] = server[i].exception;
       
   623             problem[2 * i + 2] = client[i].exception;
       
   624         }
       
   625 
       
   626         int exitCode = 0;
       
   627 
       
   628         for (int i = 0; i < 2 * CONNECTIONS + 1; i++)
       
   629             if (problem[i] != null) {
       
   630                 out.println("#### OOPS ! ####");
       
   631                 problem[i].printStackTrace(out);
       
   632                 exitCode = 2;
       
   633             }
       
   634 
       
   635         if (exitCode != 0) {
       
   636             out.println("#### OOPS ! ####");
       
   637             out.println("# Test failed.");
       
   638             return 2; // FAILED
       
   639         }
       
   640         display("Test passed.");
       
   641         return 0; // PASSED
       
   642     }
       
   643 
       
   644     /**
       
   645      * Re-calls to the method <code>run(args[],out)</code> actually
       
   646      * performing the test; and stop with exit code 95 if the test
       
   647      * has passed, or with code 97 if the test has failed.
       
   648      * (This is JCK-like exit codes convention.)
       
   649      *
       
   650      * @see #run(String[], PrintStream)
       
   651      */
       
   652     public static void main(String args[]) {
       
   653         int exitCode = run(args, System.out);
       
   654         System.exit(exitCode + 95);
       
   655         // JCK-like exit code.
       
   656     }
       
   657 
       
   658 }