/* * 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); } }