1 /*
2  * Copyright (c) 1999, 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  * @test
26  * @key stress
27  *
28  * @summary converted from VM testbase nsk/stress/network/network001.
29  * VM testbase keywords: [stress, diehard, slow, nonconcurrent, quick]
30  * VM testbase readme:
31  * DESCRIPTION
32  *     This test transfers huge amount of data between server and client
33  *     TCP/IP sockets, and checks if those data are transfered correctly.
34  *     Both sockets are attached to local host name, or to the loopback
35  *     "localhost" (having IP address 127.0.0.1).
36  *     Information transfer is synchronized in this test. Client passes
37  *     a large data parcel to server, and server reads that parcel and checks
38  *     if it is same as expected (byte-to-byte equality). Then server passes
39  *     (some other) parcel to client, and client reads and verifies those bytes.
40  *     This ping-pong game is repeated 2000 times; and after that both sockets
41  *     check if there are no extra bytes accudentally passed through their
42  *     connection.
43  *     Parcels lengths and contents are chosen randomly, and average parcel
44  *     length is 125 bytes. So totally, each of the 2 sockets passes ~250Kb of
45  *     data to its partner, and thus ~500Kb of data are transfered by this test.
46  * COMMENTS
47  *     Note, that HotSpot 1.3beta-H fails to start this test due to the bug:
48  *         #4245704 (P1/S1) Fails to launch with: jre/bin/net.dll ...
49  *
50  * @run main/othervm nsk.stress.network.network001
51  */
52 
53 package nsk.stress.network;
54 
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.OutputStream;
58 import java.io.PrintStream;
59 import java.net.InetAddress;
60 import java.net.ServerSocket;
61 import java.net.Socket;
62 import java.net.UnknownHostException;
63 import java.util.Random;
64 
65 /**
66  * This test transfers huge amount of data between server and client
67  * TCP/IP sockets, and checks if those data are transfered correctly.
68  * Both sockets are attached to local host name, or to the loopback
69  * ``localhost'' (having IP address 127.0.0.1).
70  * <p>
71  * <p>Information transfer is synchronized in this test. Client passes
72  * a large data parcel to server, and server reads that parcel and checks
73  * if it is same as expected (byte-to-byte equality). Then server passes
74  * (some other) parcel to client, and client reads and verifies those bytes.
75  * This ping-pong game is repeated 2000 times; and after that both sockets
76  * check if there are no extra bytes accudentally passed through their
77  * connection.
78  * <p>
79  * <p>Parcels lengths and contents are chosen randomly, and average parcel
80  * length is 125 bytes. So totally, each of the 2 sockets passes ~250Kb of
81  * data to its partner, and thus ~500Kb of data are transfered by this test.
82  */
83 public class network001 {
84     /**
85      * Number of parcels to be sent/recieve.
86      */
87     private static final int DATA_PARCELS = 2000;
88 
89     /**
90      * Maximal length of data parcel to be sent/recieved
91      * (now it equals to 250 bytes).
92      */
93     private static final int MAX_PARCEL = 250;
94 
95     /**
96      * Either actually display optional reports or not.
97      */
98     static private final boolean DEBUG_MODE = false;
99 
100     /**
101      * Errors and optional reports log. Usually <code>System.out</code>.
102      */
103     static private PrintStream out = System.out;
104 
105     /**
106      * Print error message: both client and server may print
107      * concurently.
108      */
println(Object message)109     static private synchronized void println(Object message) {
110         out.println(message.toString());
111     }
112 
113     /**
114      * Display optional report: comment ca va.
115      */
display(Object report)116     static private void display(Object report) {
117         if (DEBUG_MODE)
118             println(report.toString());
119     }
120 
121     /**
122      * Server thread intended to reply to data parcels sent by Client thread.
123      */
124     static private class Server extends Thread {
125         /**
126          * This server thread listens the single socket.
127          */
128         private ServerSocket serverSocket;
129 
130         /**
131          * Address and port of this server socket.
132          */
toString()133         public String toString() {
134             return serverSocket.toString();
135         }
136 
137         /**
138          * Did the thread failed? If yes, what is the failure's reason.
139          */
140         Exception exception = null;
141 
142         /**
143          * Which port does this socket is listening.
144          */
getPort()145         int getPort() {
146             return serverSocket.getLocalPort();
147         }
148 
149         /**
150          * Find some free port at the given <code>address</code>
151          * and attach new server to hear that port.
152          */
Server(InetAddress address)153         Server(InetAddress address) throws IOException {
154             int someFreePort = 0;
155             int backlog = 50; // default for new ServerSocket(port)
156             serverSocket = new ServerSocket(someFreePort, backlog, address);
157         }
158 
159         /**
160          * Accept connection, read the string "abra", and respond "cadabra".
161          */
run()162         public void run() {
163             try {
164                 Socket socket = serverSocket.accept();
165                 display("Server socket: " + socket);
166 
167                 InputStream istream = socket.getInputStream();
168                 OutputStream ostream = socket.getOutputStream();
169 
170                 Random random = new Random(0);
171 
172                 for (int i = 0; i < DATA_PARCELS; i++) {
173                     Parcel etalon = new Parcel(random);
174 
175                     Parcel sample = new Parcel(istream); // read
176                     if (!sample.equals(etalon)) {
177                         println("Server thread got unexpected parcel:");
178                         println("sample=" + sample);
179                         println("etalon=" + etalon);
180                         throw new TestFailure(
181                                 "server has read unexpected parcel");
182                     }
183 
184                     etalon.send(ostream);
185                     ostream.flush();
186                 }
187 
188                 int datum = istream.read(); // wait for client close()
189                 if (datum >= 0)
190                     throw new TestFailure(
191                             "server has read ambigous byte: " + datum);
192 
193                 ostream.close(); // implies: socket.close();
194 
195             } catch (Exception oops) {
196                 exception = oops;
197             }
198         }
199 
200     }
201 
202     /**
203      * Client thread intended to send data parcels to Server thread and
204      * to recieve the server's replies.
205      */
206     static private class Client extends Thread {
207         /**
208          * This thread uses the single client socket.
209          */
210         private Socket socket;
211 
212         /**
213          * Address and port of this socket.
214          */
toString()215         public String toString() {
216             return socket.toString();
217         }
218 
219         /**
220          * Did the thread failed? If yes, what is the failure's reason.
221          */
222         Exception exception = null;
223 
224         /**
225          * Connect client socket on the given <code>address</code>
226          * and <code>port</code>.
227          */
Client(InetAddress address, int port)228         Client(InetAddress address, int port) throws IOException {
229             socket = new Socket(address, port);
230         }
231 
232         /**
233          * Accept connection, read the string "abra", and respond "cadabra".
234          */
run()235         public void run() {
236             try {
237                 InputStream istream = socket.getInputStream();
238                 OutputStream ostream = socket.getOutputStream();
239 
240                 Random random = new Random(0);
241 
242                 for (int i = 0; i < DATA_PARCELS; i++) {
243                     Parcel etalon = new Parcel(random);
244                     etalon.send(ostream);
245                     ostream.flush();
246 
247                     Parcel sample = new Parcel(istream); // read
248                     if (!sample.equals(etalon)) {
249                         println("Client thread got unexpected parcel:");
250                         println("sample=" + sample);
251                         println("etalon=" + etalon);
252                         throw new TestFailure(
253                                 "parcel context is unexpected to client");
254                     }
255                 }
256 
257                 if (istream.available() > 0) {
258                     int datum = istream.read();
259                     throw new TestFailure(
260                             "client has read ambigous byte: " + datum);
261                 }
262                 ostream.close(); // implies: socket.close()
263 
264             } catch (Exception oops) {
265                 exception = oops;
266             }
267         }
268 
269     }
270 
271     /**
272      * A data parcel to sent/recieved between Client and Server threads.
273      * When data parcel is sent, first 4 bytes transfered encode the size
274      * of the parcel (i.e.: number of data bytes in the parcel's contents).
275      * Then the parcel's contents bytes are transered.
276      */
277     static class Parcel {
278         private byte[] parcel;
279 
280         /**
281          * Display all bytes as integer values from 0 to 255;
282          * or return ``<tt>null</tt>'' if this Parcel is not
283          * yet initialized.
284          */
toString()285         public String toString() {
286             if (parcel == null)
287                 return "null";
288             String s = "{";
289             for (int i = 0; i < parcel.length; i++)
290                 s += (i > 0 ? ", " : "") + ((int) parcel[i] & 0xFF);
291             return s + "}";
292         }
293 
294         /**
295          * Generate new <code>parcel[]</code> array using the given
296          * <code>random</code> numbers generator. Client and Server
297          * threads should use identical <code>random</code> generators,
298          * so that those threads could generate equal data parcels and
299          * check the parcel just transfered.
300          */
Parcel(Random random)301         public Parcel(Random random) {
302             int size = random.nextInt(MAX_PARCEL) + 1;
303             parcel = new byte[size];
304             for (int i = 0; i < size; i++)
305                 parcel[i] = (byte) random.nextInt(256);
306         }
307 
308         /**
309          * Read exactly <code>size</code> bytes from the <code>istream</code>
310          * if possible, or throw <code>TestFailure</code> if unexpected end of
311          * <code>istream</code> occurs.
312          */
readBytes(int size, InputStream istream)313         private static byte[] readBytes(int size, InputStream istream)
314                 throws IOException {
315 
316             byte data[] = new byte[size];
317             for (int i = 0; i < size; i++) {
318                 int datum = istream.read();
319                 if (datum < 0)
320                     throw new TestFailure(
321                             "unexpected EOF: have read: " + i + " bytes of " + size);
322                 data[i] = (byte) datum;
323             }
324             return data;
325         }
326 
327         /**
328          * Read 4 bytes from <code>istream</code> and threat them to encode
329          * size of data parcel following these 4 bytes.
330          */
getSize(InputStream istream)331         private static int getSize(InputStream istream) throws IOException {
332             byte data[] = readBytes(4, istream);
333             int data0 = (int) data[0] & 0xFF;
334             int data1 = (int) data[1] & 0xFF;
335             int data2 = (int) data[2] & 0xFF;
336             int data3 = (int) data[3] & 0xFF;
337             int sizeWord = data0 + (data1 << 8) + (data2 << 16) + (data3 << 24);
338             int size = sizeWord + 1;
339             if (size <= 0)
340                 throw new TestFailure("illegal size: " + size);
341             return size;
342         }
343 
344         /**
345          * Send 4 bytes encoding actual size of the parcel just to be transfered.
346          */
putSize(OutputStream ostream, int size)347         private static void putSize(OutputStream ostream, int size)
348                 throws IOException {
349 
350             if (size <= 0)
351                 throw new TestFailure("illegal size: " + size);
352 
353             int sizeWord = size - 1;
354             byte data[] = new byte[4];
355             data[0] = (byte) sizeWord;
356             data[1] = (byte) (sizeWord >> 8);
357             data[2] = (byte) (sizeWord >> 16);
358             data[3] = (byte) (sizeWord >> 24);
359             ostream.write(data);
360         }
361 
362         /**
363          * Recieve data parcel.
364          */
Parcel(InputStream istream)365         public Parcel(InputStream istream) throws IOException {
366             int size = getSize(istream);
367             parcel = readBytes(size, istream);
368         }
369 
370         /**
371          * Send <code>this</code> data parcel.
372          */
send(OutputStream ostream)373         public void send(OutputStream ostream) throws IOException {
374             int size = parcel.length;
375             putSize(ostream, size);
376             ostream.write(parcel);
377         }
378 
379         /**
380          * Check byte-to-byte equality between <code>this</code> and the
381          * <code>other</code> parcels.
382          */
equals(Parcel other)383         public boolean equals(Parcel other) {
384             if (this.parcel.length != other.parcel.length)
385                 return false;
386             int size = parcel.length;
387             for (int i = 0; i < size; i++)
388                 if (this.parcel[i] != other.parcel[i])
389                     return false;
390             return true;
391         }
392 
393     }
394 
395     /**
396      * Server or Client thread may throw this exception to report the test
397      * failure.
398      */
399     static class TestFailure extends RuntimeException {
400         /**
401          * Report particular <code>purpose</code> of the test failure.
402          */
TestFailure(String purpose)403         public TestFailure(String purpose) {
404             super(purpose);
405         }
406 
407     }
408 
409     /**
410      * Attach client and server sockets to the local host, and check if
411      * huge amount of data could be correctly transfered between these
412      * sockets.
413      * <p>
414      * <p>Command-line parameters provided with <code>args[]</code> may
415      * prompt the local host IP address or domain name. Execute:
416      * <br>&nbsp;&nbsp;
417      * <code>java network001 [<i>IP-address</i> | <i>host_name</i> |
418      * localhost ]</code>
419      * <br>where parameters are:
420      * <br>&nbsp;&nbsp;
421      * <code><i>IP-address</i></code> - local hots's address, or 127.0.0.1
422      * <br>&nbsp;&nbsp;
423      * <code><i>host_name</i></code> - local host's domain name, or the
424      * keyword ``<code>localhost</code>''
425      * <br>&nbsp;&nbsp;
426      * <code>localhost</code> - placeholder for the IP-address 127.0.0.1
427      * <br>By default, the test uses the Internet address available via
428      * the method <code>InetAddress.getLocalHost()</code>
429      */
run(String args[], PrintStream out)430     public static int run(String args[], PrintStream out) {
431         network001.out = out;
432 
433         //
434         // Get IP address of the local machine.
435         //
436 
437         InetAddress address = null;
438         try {
439             switch (args.length) {
440                 case 0:
441                     address = InetAddress.getLocalHost();
442                     break;
443                 case 1:
444                     String hostName = args[0];
445                     address = InetAddress.getByName(args[0]);
446                     break;
447                 default:
448                     println("Use:");
449                     println("    java network001");
450                     println("or:");
451                     println("    java network001 ${IP_ADDRESS}");
452                     println("or:");
453                     println("    java network001 ${HOST_NAME}");
454                     println("or:");
455                     println("    java network001 localhost");
456                     return 2; // FAILED
457             }
458         } catch (UnknownHostException exception) {
459             println(exception);
460             return 2; // FAILED
461         }
462         display("Host: " + address);
463 
464         //
465         // Incarnate the server & the client sockets.
466         //
467 
468         Server server = null;
469         try {
470             server = new Server(address);
471         } catch (IOException io) {
472             println("Failed to create server: " + io);
473             return 2;
474         }
475         display("Server: " + server);
476 
477         int port = server.getPort();
478 
479         Client client = null;
480         try {
481             client = new Client(address, port);
482         } catch (IOException io) {
483             out.println("Failed to create client: " + io);
484             return 2;
485         }
486         display("Client socket: " + client);
487 
488         //
489         // Execute the server and client threads.
490         //
491 
492         Exception exception = null;
493         try {
494             server.start();
495             client.start();
496             while (client.isAlive() || server.isAlive())
497                 if (client.exception == null && server.exception == null)
498                     Thread.yield();
499                 else
500                     break;
501         } catch (TestFailure failure) {
502             exception = failure;
503         }
504 
505         // Failure diagnostics, if needed.
506 
507         Exception problem[] = new Exception[3];
508         problem[0] = exception;
509         problem[1] = server.exception;
510         problem[2] = client.exception;
511 
512         int exitCode = 0;
513 
514         for (int i = 0; i < 3; i++)
515             if (problem[i] != null) {
516                 out.println("#### OOPS ! ####");
517                 problem[i].printStackTrace(out);
518                 exitCode = 2;
519             }
520 
521         if (exitCode != 0) {
522             out.println("#### OOPS ! ####");
523             out.println("# Test failed.");
524             return 2; // FAILED
525         }
526         display("Test passed.");
527         return 0; // PASSED
528     }
529 
530     /**
531      * Re-calls to the method <code>run(args[],out)</code> actually
532      * performing the test; and stop with exit code 95 if the test
533      * has passed, or with code 97 if the test has failed.
534      * (This is JCK-like exit codes convention.)
535      *
536      * @see #run(String[], PrintStream)
537      */
main(String args[])538     public static void main(String args[]) {
539         int exitCode = run(args, System.out);
540         System.exit(exitCode + 95);
541         // JCK-like exit code.
542     }
543 
544 }
545