blob: ab96440c661311594920b06aacf6fad77a3d0b99 [file] [log] [blame]
/*
* 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);
}
}