1 /*
2  * Copyright (c) 1997, 2003, 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 import java.io.*;
25 import java.security.*;
26 
27 class Traffic
28 {
29     private InputStream         in;
30     private OutputStream        out;
31 
32     //
33     // By default, traffic streams are predictable and what comes
34     // in is compared with what it's expected to be.
35     //
36     static private byte fixedSeed [] = { 1, 2, 3, 4};
37 
38     private SecureRandom        prng;
39     private boolean             compareRandom = true;
40 
41 
Traffic(InputStream in, OutputStream out)42     Traffic (InputStream in, OutputStream out)
43     {
44         this.in = in;
45         this.out = out;
46         try {
47             prng = SecureRandom.getInstance("SHA1PRNG");
48         } catch (NoSuchAlgorithmException e) {
49             throw new RuntimeException(e);
50         }
51         prng.setSeed(fixedSeed);
52     }
53 
54     // optionally provide PRNG for "truly" random data.
setPRNG(SecureRandom prng)55     public void setPRNG (SecureRandom prng)
56     {
57         this.prng = prng;
58         compareRandom = false;
59     }
60 
61 
62     //
63     // Basic half-duplex testing, as used for RPC-style systems like
64     // HTTP, RMI, CORBA, ONC, etc.
65     //
66     // parameter 'n' is "0" for some fixed data tests, else is the
67     // number of passes of random data to send.
68     //
69 
initiate(int n)70     public void initiate (int n)
71     throws IOException
72     {
73         // System.out.println ("Initiating N = " + n);
74 
75         if (n == 0)
76             initiateConst ();
77         else if (n < 0)
78             System.out.println ("** ERROR:  initiate forever ??");
79         else
80             for ( ; n > 0; n -= 1) {
81                 initiateRandom ();
82             }
83     }
84 
85 
respond(int n)86     public void respond (int n)
87     throws IOException
88     {
89         if (n == 0)
90             respondConst ();
91         else if (n < 0)                 // n < 0 == respond forever
92             while (true)
93                 respondRandom ();
94         else
95             while (n-- > 0)
96                 respondRandom ();
97     }
98 
99 
100     //
101     // Test passing of fixed size (and content) data.
102     //
103     // For SSL, one test goal is to ensure that all the basic
104     // block cipher padding sizes get banged on.  SSLv3 ciphers
105     // are all the same block size, but there are larger sizes
106     // coming along.  (Big blocks in hardware can be fast!!)
107     //
108 
109     private static final int MAX_BLOCKSIZE = 8 * 2;
110 
writeConstData(int n)111     private void writeConstData (int n)
112     throws IOException
113     {
114         if (n <= 0)
115             return;
116 
117         byte buf [] = new byte [n];
118 
119         for (int i = 0; i < n; i++)
120             buf [i] = (byte) i;
121 
122         out.write (buf);
123 
124         /*
125         System.out.println (Thread.currentThread ().getName ()
126             + " wrote const data size = " + n);
127         */
128     }
129 
readConstData(int n)130     private void readConstData (int n)
131     throws IOException
132     {
133         if (n <= 0)
134             return;
135 
136         byte buf [] = new byte [n];
137 
138         in.read (buf);
139 
140         for (int i = 0; i < n; i++)
141             if (buf [i] != (byte) i)
142                 throw new IOException ("const data was incorrect, "
143                     + "n = " + n + ", i = " + i);
144 
145         /*
146         System.out.println (Thread.currentThread ().getName ()
147             + " read const data size = " + n);
148         */
149     }
150 
initiateConst()151     private void initiateConst ()
152     throws IOException
153     {
154         for (int i = 1; i <= MAX_BLOCKSIZE; i++) {
155             writeConstData (i);
156             readConstData (i);
157         }
158 
159     }
160 
respondConst()161     private void respondConst ()
162     throws IOException
163     {
164         for (int i = 1; i <= MAX_BLOCKSIZE; i++) {
165             readConstData (i);
166             writeConstData (i);
167         }
168     }
169 
170 
171     //
172     // Test passing of random size (and content) data.
173     //
174     // For SSL, one test goal is to ensure that all the basic
175     // record sizes get banged on.  Traffic will normally
176     // be bimodal (small packets, and big ones) and we give
177     // a half-hearted effort at emulating that -- no real
178     // statistics to back up this particular distribution.
179     //
180 
181     private static final int MAX_RECORDSIZE = 16384 * 2;
182 
nextRecordSize()183     private int nextRecordSize ()
184     {
185         double  d = prng.nextGaussian ();
186         int     n;
187 
188         // assume 1/3 traffic is "big", less variance
189         if ((prng.nextInt () % 3)  == 0) {
190             n = (int) (d * 2048);
191             n += 15 * 1024;
192 
193         // ... and the rest is smaller, much variance
194         } else {
195             n = (int) (d * 4096);
196             n += 1024;
197         }
198 
199         if (n < 0)
200             return nextRecordSize ();
201         else if (n > MAX_RECORDSIZE)
202             return MAX_RECORDSIZE;
203         else
204             return n;
205     }
206 
207 
writeRandomData()208     private void writeRandomData ()
209     throws IOException
210     {
211         int n = nextRecordSize ();
212         byte buf [] = new byte [n];
213 
214         // System.out.println ("write, size = " + n);
215 
216         prng.nextBytes (buf);
217 
218         writeInt (n);
219         out.write (buf);
220     }
221 
readRandomData()222     private void readRandomData ()
223     throws IOException
224     {
225         int     n = readInt ();
226         byte    actual [] = new byte [n];
227 
228         readFully (actual);
229 
230         if (compareRandom) {
231             byte        expected [];
232 
233             if (n != nextRecordSize ())
234                 throw new IOException ("wrong record size");
235 
236             expected = new byte [n];
237             prng.nextBytes (expected);
238 
239             for (int i = 0; i < n; i++)
240                 if (actual [i] != expected [i])
241                     throw new IOException ("random data was incorrect, "
242                         + "n = " + n + ", i = " + i);
243         }
244     }
245 
initiateRandom()246     private void initiateRandom ()
247     throws IOException
248     {
249         writeRandomData ();
250         readRandomData ();
251 
252     }
253 
respondRandom()254     private void respondRandom ()
255     throws IOException
256     {
257         readRandomData ();
258         writeRandomData ();
259     }
260 
261 
readFully(byte buf [])262     private void readFully (byte buf [])
263     throws IOException
264     {
265         int len = buf.length;
266         int offset = 0;
267         int value;
268 
269         while (len > 0) {
270             value = in.read (buf, offset, len);
271             if (value == -1)
272                 throw new EOFException ("read buffer");
273             offset += value;
274             len -= value;
275         }
276     }
277 
278 
readInt()279     private int readInt ()
280     throws IOException
281     {
282         int b0, b1, b2, b3;
283         int n;
284 
285         b0 = in.read ();
286         b1 = in.read ();
287         b2 = in.read ();
288         b3 = in.read ();
289 
290         if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
291             throw new EOFException ();
292 
293         /*
294         System.out.println ("READ:   b0 = " + b0 + ", b1 = " + b1
295             + ", b2 = " + b2 + ", b3 = " + b3);
296         */
297 
298         n =  (b3 & 0x0ff);
299         n |= (b2 & 0x0ff) << 8;
300         n |= (b1 & 0x0ff) << 16;
301         n |= (b0 & 0x0ff) << 24;
302         return n;
303     }
304 
writeInt(int n)305     private void writeInt (int n)
306     throws IOException
307     {
308         int b0, b1, b2, b3;
309 
310         b3 = n & 0x0ff;
311         n >>= 8;
312         b2 = n & 0x0ff;
313         n >>= 8;
314         b1 = n & 0x0ff;
315         n >>= 8;
316         b0 = n & 0x0ff;
317 
318         /*
319         System.out.println ("WRITE:  b0 = " + b0 + ", b1 = " + b1
320             + ", b2 = " + b2 + ", b3 = " + b3);
321         */
322 
323         out.write (b0);
324         out.write (b1);
325         out.write (b2);
326         out.write (b3);
327     }
328 }
329