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> 417 * <code>java network001 [<i>IP-address</i> | <i>host_name</i> | 418 * localhost ]</code> 419 * <br>where parameters are: 420 * <br> 421 * <code><i>IP-address</i></code> - local hots's address, or 127.0.0.1 422 * <br> 423 * <code><i>host_name</i></code> - local host's domain name, or the 424 * keyword ``<code>localhost</code>'' 425 * <br> 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