| /* |
| * Copyright (c) 1997, 2003, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| import java.io.*; |
| import java.security.*; |
| |
| class Traffic |
| { |
| private InputStream in; |
| private OutputStream out; |
| |
| // |
| // By default, traffic streams are predictable and what comes |
| // in is compared with what it's expected to be. |
| // |
| static private byte fixedSeed [] = { 1, 2, 3, 4}; |
| |
| private SecureRandom prng; |
| private boolean compareRandom = true; |
| |
| |
| Traffic (InputStream in, OutputStream out) |
| { |
| this.in = in; |
| this.out = out; |
| try { |
| prng = SecureRandom.getInstance("SHA1PRNG"); |
| } catch (NoSuchAlgorithmException e) { |
| throw new RuntimeException(e); |
| } |
| prng.setSeed(fixedSeed); |
| } |
| |
| // optionally provide PRNG for "truly" random data. |
| public void setPRNG (SecureRandom prng) |
| { |
| this.prng = prng; |
| compareRandom = false; |
| } |
| |
| |
| // |
| // Basic half-duplex testing, as used for RPC-style systems like |
| // HTTP, RMI, CORBA, ONC, etc. |
| // |
| // parameter 'n' is "0" for some fixed data tests, else is the |
| // number of passes of random data to send. |
| // |
| |
| public void initiate (int n) |
| throws IOException |
| { |
| // System.out.println ("Initiating N = " + n); |
| |
| if (n == 0) |
| initiateConst (); |
| else if (n < 0) |
| System.out.println ("** ERROR: initiate forever ??"); |
| else |
| for ( ; n > 0; n -= 1) { |
| initiateRandom (); |
| } |
| } |
| |
| |
| public void respond (int n) |
| throws IOException |
| { |
| if (n == 0) |
| respondConst (); |
| else if (n < 0) // n < 0 == respond forever |
| while (true) |
| respondRandom (); |
| else |
| while (n-- > 0) |
| respondRandom (); |
| } |
| |
| |
| // |
| // Test passing of fixed size (and content) data. |
| // |
| // For SSL, one test goal is to ensure that all the basic |
| // block cipher padding sizes get banged on. SSLv3 ciphers |
| // are all the same block size, but there are larger sizes |
| // coming along. (Big blocks in hardware can be fast!!) |
| // |
| |
| private static final int MAX_BLOCKSIZE = 8 * 2; |
| |
| private void writeConstData (int n) |
| throws IOException |
| { |
| if (n <= 0) |
| return; |
| |
| byte buf [] = new byte [n]; |
| |
| for (int i = 0; i < n; i++) |
| buf [i] = (byte) i; |
| |
| out.write (buf); |
| |
| /* |
| System.out.println (Thread.currentThread ().getName () |
| + " wrote const data size = " + n); |
| */ |
| } |
| |
| private void readConstData (int n) |
| throws IOException |
| { |
| if (n <= 0) |
| return; |
| |
| byte buf [] = new byte [n]; |
| |
| in.read (buf); |
| |
| for (int i = 0; i < n; i++) |
| if (buf [i] != (byte) i) |
| throw new IOException ("const data was incorrect, " |
| + "n = " + n + ", i = " + i); |
| |
| /* |
| System.out.println (Thread.currentThread ().getName () |
| + " read const data size = " + n); |
| */ |
| } |
| |
| private void initiateConst () |
| throws IOException |
| { |
| for (int i = 1; i <= MAX_BLOCKSIZE; i++) { |
| writeConstData (i); |
| readConstData (i); |
| } |
| |
| } |
| |
| private void respondConst () |
| throws IOException |
| { |
| for (int i = 1; i <= MAX_BLOCKSIZE; i++) { |
| readConstData (i); |
| writeConstData (i); |
| } |
| } |
| |
| |
| // |
| // Test passing of random size (and content) data. |
| // |
| // For SSL, one test goal is to ensure that all the basic |
| // record sizes get banged on. Traffic will normally |
| // be bimodal (small packets, and big ones) and we give |
| // a half-hearted effort at emulating that -- no real |
| // statistics to back up this particular distribution. |
| // |
| |
| private static final int MAX_RECORDSIZE = 16384 * 2; |
| |
| private int nextRecordSize () |
| { |
| double d = prng.nextGaussian (); |
| int n; |
| |
| // assume 1/3 traffic is "big", less variance |
| if ((prng.nextInt () % 3) == 0) { |
| n = (int) (d * 2048); |
| n += 15 * 1024; |
| |
| // ... and the rest is smaller, much variance |
| } else { |
| n = (int) (d * 4096); |
| n += 1024; |
| } |
| |
| if (n < 0) |
| return nextRecordSize (); |
| else if (n > MAX_RECORDSIZE) |
| return MAX_RECORDSIZE; |
| else |
| return n; |
| } |
| |
| |
| private void writeRandomData () |
| throws IOException |
| { |
| int n = nextRecordSize (); |
| byte buf [] = new byte [n]; |
| |
| // System.out.println ("write, size = " + n); |
| |
| prng.nextBytes (buf); |
| |
| writeInt (n); |
| out.write (buf); |
| } |
| |
| private void readRandomData () |
| throws IOException |
| { |
| int n = readInt (); |
| byte actual [] = new byte [n]; |
| |
| readFully (actual); |
| |
| if (compareRandom) { |
| byte expected []; |
| |
| if (n != nextRecordSize ()) |
| throw new IOException ("wrong record size"); |
| |
| expected = new byte [n]; |
| prng.nextBytes (expected); |
| |
| for (int i = 0; i < n; i++) |
| if (actual [i] != expected [i]) |
| throw new IOException ("random data was incorrect, " |
| + "n = " + n + ", i = " + i); |
| } |
| } |
| |
| private void initiateRandom () |
| throws IOException |
| { |
| writeRandomData (); |
| readRandomData (); |
| |
| } |
| |
| private void respondRandom () |
| throws IOException |
| { |
| readRandomData (); |
| writeRandomData (); |
| } |
| |
| |
| private void readFully (byte buf []) |
| throws IOException |
| { |
| int len = buf.length; |
| int offset = 0; |
| int value; |
| |
| while (len > 0) { |
| value = in.read (buf, offset, len); |
| if (value == -1) |
| throw new EOFException ("read buffer"); |
| offset += value; |
| len -= value; |
| } |
| } |
| |
| |
| private int readInt () |
| throws IOException |
| { |
| int b0, b1, b2, b3; |
| int n; |
| |
| b0 = in.read (); |
| b1 = in.read (); |
| b2 = in.read (); |
| b3 = in.read (); |
| |
| if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) |
| throw new EOFException (); |
| |
| /* |
| System.out.println ("READ: b0 = " + b0 + ", b1 = " + b1 |
| + ", b2 = " + b2 + ", b3 = " + b3); |
| */ |
| |
| n = (b3 & 0x0ff); |
| n |= (b2 & 0x0ff) << 8; |
| n |= (b1 & 0x0ff) << 16; |
| n |= (b0 & 0x0ff) << 24; |
| return n; |
| } |
| |
| private void writeInt (int n) |
| throws IOException |
| { |
| int b0, b1, b2, b3; |
| |
| b3 = n & 0x0ff; |
| n >>= 8; |
| b2 = n & 0x0ff; |
| n >>= 8; |
| b1 = n & 0x0ff; |
| n >>= 8; |
| b0 = n & 0x0ff; |
| |
| /* |
| System.out.println ("WRITE: b0 = " + b0 + ", b1 = " + b1 |
| + ", b2 = " + b2 + ", b3 = " + b3); |
| */ |
| |
| out.write (b0); |
| out.write (b1); |
| out.write (b2); |
| out.write (b3); |
| } |
| } |