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 * @bug 7152176
27 * @summary More krb5 tests
28 * @library ../../../../java/security/testlibrary/
29 * @compile -XDignore.symbol.file ReplayCacheTestProc.java
30 * @run main/othervm/timeout=100 ReplayCacheTestProc
31 */
32
33 import java.io.*;
34 import java.nio.BufferUnderflowException;
35 import java.nio.channels.SeekableByteChannel;
36 import java.nio.file.Files;
37 import java.nio.file.Paths;
38 import java.nio.file.StandardCopyOption;
39 import java.nio.file.StandardOpenOption;
40 import java.security.MessageDigest;
41 import java.util.*;
42
43 import sun.security.jgss.GSSUtil;
44 import sun.security.krb5.internal.APReq;
45 import sun.security.krb5.internal.rcache.AuthTime;
46
47 // This test runs multiple acceptor Procs to mimin AP-REQ replays.
48 public class ReplayCacheTestProc {
49
50 private static Proc[] ps;
51 private static Proc pc;
52 private static List<Req> reqs = new ArrayList<>();
53 private static String HOST = "localhost";
54
55 // Where should the rcache be saved. It seems KRB5RCACHEDIR is not
56 // recognized on Solaris. Maybe version too low? I see 1.6.
57 private static String cwd =
58 System.getProperty("os.name").startsWith("SunOS") ?
59 "/var/krb5/rcache/" :
60 System.getProperty("user.dir");
61
62
63 private static long uid;
64
65 public static void main0(String[] args) throws Exception {
66 System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF);
67 if (args.length == 0) { // The controller
68 int ns = 5; // number of servers
69 int nu = 5; // number of users
70 int nx = 50; // number of experiments
71 int np = 5; // number of peers (services)
72 int mode = 0; // native(1), random(0), java(-1)
73 boolean random = true; // random experiments choreograph
74
75 // Do not test interop with native GSS on some platforms
76 String os = System.getProperty("os.name", "???");
77 if (!os.startsWith("SunOS") && !os.startsWith("Linux")) {
78 mode = -1;
79 }
80
81 uid = jdk.internal.misc.VM.geteuid();
82
83 KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true);
84 for (int i=0; i<nu; i++) {
85 kdc.addPrincipal(user(i), OneKDC.PASS);
86 }
87 kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
88 for (int i=0; i<np; i++) {
89 kdc.addPrincipalRandKey(peer(i));
90 }
91
92 kdc.writeKtab(OneKDC.KTAB);
93 KDC.saveConfig(OneKDC.KRB5_CONF, kdc);
94
95 if (mode != -1) {
96 // A special native server to check basic sanity
97 if (ns(-1).waitFor() != 0) {
98 Proc.d("Native mode sanity check failed, revert to java");
99 mode = -1;
100 }
101 }
102
103 pc = Proc.create("ReplayCacheTestProc").debug("C")
104 .args("client")
105 .start();
106 ps = new Proc[ns];
107 Ex[] result = new Ex[nx];
108
109 if (!random) {
110 // 2 experiments, 2 server, 1 peer, 1 user
111 nx = 2; ns = 2; np = 1; nu = 1;
112
113 // Creates reqs from user# to peer#
114 req(0, 0);
115
116 // Creates server#
117 ps[0] = ns(0);
118 ps[1] = js(1);
119
120 // Runs ex# using req# to server# with expected result
121 result[0] = round(0, 0, 0, true);
122 result[1] = round(1, 0, 1, false);
123 } else {
124 Random r = new Random();
125 for (int i=0; i<ns; i++) {
126 boolean useNative = (mode == 1) ? true
127 : (mode == -1 ? false : r.nextBoolean());
128 ps[i] = useNative?ns(i):js(i);
129 }
130 for (int i=0; i<nx; i++) {
131 result[i] = new Ex();
132 int old; // which req to send
133 boolean expected;
134 if (reqs.isEmpty() || r.nextBoolean()) {
135 Proc.d("Console get new AP-REQ");
136 old = req(r.nextInt(nu), r.nextInt(np));
137 expected = true;
138 } else {
139 Proc.d("Console resue old");
140 old = r.nextInt(reqs.size());
141 expected = false;
142 }
143 int s = r.nextInt(ns);
144 Proc.d("Console send to " + s);
145 result[i] = round(i, old, s, expected);
146 Proc.d("Console sees " + result[i].actual);
147 }
148 }
149
150 pc.println("END");
151 for (int i=0; i<ns; i++) {
152 ps[i].println("END");
153 }
154 System.out.println("Result\n======");
155 boolean finalOut = true;
156 for (int i=0; i<nx; i++) {
157 boolean out = result[i].expected==result[i].actual;
158 finalOut &= out;
159 System.out.printf("%3d: %s (%2d): u%d h%d %s %s %s %2d\n",
160 i,
161 result[i].expected?"----":" ",
162 result[i].old,
163 result[i].user, result[i].peer, result[i].server,
164 result[i].actual?"Good":"Bad ",
165 out?" ":"xxx",
166 result[i].csize);
167 }
168 if (!finalOut) throw new Exception();
169 } else if (args[0].equals("N-1")) {
170 // Native mode sanity check
171 Proc.d("Detect start");
172 Context s = Context.fromUserKtab("*", OneKDC.KTAB, true);
173 s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
174 } else if (args[0].equals("client")) {
175 while (true) {
176 String title = Proc.textIn();
177 Proc.d("Client see " + title);
178 if (title.equals("END")) break;
179 String[] cas = title.split(" ");
180 Context c = Context.fromUserPass(cas[0], OneKDC.PASS, false);
181 c.startAsClient(cas[1], GSSUtil.GSS_KRB5_MECH_OID);
182 c.x().requestCredDeleg(true);
183 byte[] token = c.take(new byte[0]);
184 Proc.d("Client AP-REQ generated");
185 Proc.binOut(token);
186 }
187 } else {
188 Proc.d("Server start");
189 Context s = Context.fromUserKtab("*", OneKDC.KTAB, true);
190 Proc.d("Server login");
191 while (true) {
192 String title = Proc.textIn();
193 Proc.d("Server " + args[0] + " sees " + title);
194 if (title.equals("END")) break;
200 Proc.d(args[0] + " Good");
201 } catch (Exception e) {
202 Proc.textOut("false");
203 Proc.d(args[0] + " Bad");
204 }
205 }
206 }
207 }
208
209 public static void main(String[] args) throws Exception {
210 try {
211 main0(args);
212 } catch (Exception e) {
213 Proc.d(e);
214 throw e;
215 }
216 }
217
218 // returns the user name
219 private static String user(int p) {
220 return "USER" + p;
221 }
222 // returns the peer name
223 private static String peer(int p) {
224 return "host" + p + "/" + HOST;
225 }
226 // returns the dfl name for a host
227 private static String dfl(int p) {
228 return cwd + "host" + p + (uid == -1 ? "" : ("_"+uid));
229 }
230 // generates an ap-req and save into reqs, returns the index
231 private static int req(int user, int peer) throws Exception {
232 pc.println(user(user) + " " + peer(peer));
233 Req req = new Req(user, peer, pc.readData());
234 reqs.add(req);
235 return reqs.size() - 1;
236 }
237 // carries out a round of experiment
238 // i: ex#, old: which req, server: which server, expected: result?
239 private static Ex round(int i, int old, int server, boolean expected)
240 throws Exception {
241 ps[server].println("TEST");
242 ps[server].println(reqs.get(old).msg);
243 String reply = ps[server].readData();
244 Ex result = new Ex();
245 result.i = i;
246 result.expected = expected;
247 result.server = ps[server].debug();
248 result.actual = Boolean.valueOf(reply);
249 result.user = reqs.get(old).user;
250 result.peer = reqs.get(old).peer;
251 result.old = old;
252 result.csize = csize(result.peer);
253 result.hash = hash(reqs.get(old).msg);
254 if (new File(dfl(result.peer)).exists()) {
255 Files.copy(Paths.get(dfl(result.peer)), Paths.get(
256 String.format("%03d-USER%d-host%d-%s-%s",
257 i, result.user, result.peer, result.server,
258 result.actual)
259 + "-" + result.hash),
260 StandardCopyOption.COPY_ATTRIBUTES);
261 }
262 return result;
263 }
264 // create a native server
265 private static Proc ns(int i) throws Exception {
266 return Proc.create("ReplayCacheTestProc")
267 .args("N"+i)
268 .env("KRB5_CONFIG", OneKDC.KRB5_CONF)
269 .env("KRB5_KTNAME", OneKDC.KTAB)
270 .env("KRB5RCACHEDIR", cwd)
271 .prop("sun.security.jgss.native", "true")
272 .prop("javax.security.auth.useSubjectCredsOnly", "false")
273 .prop("sun.security.nativegss.debug", "true")
274 .debug("N"+i)
275 .start();
276 }
277 // creates a java server
278 private static Proc js(int i) throws Exception {
279 return Proc.create("ReplayCacheTestProc")
280 .debug("S"+i)
281 .args("S"+i)
282 .prop("sun.security.krb5.rcache", "dfl")
283 .prop("java.io.tmpdir", cwd)
284 .start();
285 }
286 // generates hash of authenticator inside ap-req inside initsectoken
287 private static String hash(String req) throws Exception {
288 byte[] data = Base64.getDecoder().decode(req);
289 data = Arrays.copyOfRange(data, 17, data.length);
290 byte[] hash = MessageDigest.getInstance("MD5").digest(new APReq(data).authenticator.getBytes());
291 char[] h = new char[hash.length * 2];
292 char[] hexConst = "0123456789ABCDEF".toCharArray();
293 for (int i=0; i<hash.length; i++) {
294 h[2*i] = hexConst[(hash[i]&0xff)>>4];
295 h[2*i+1] = hexConst[hash[i]&0xf];
296 }
297 return new String(h);
298 }
299 // return size of dfl file, excluding the null hash ones
300 private static int csize(int p) throws Exception {
301 try (SeekableByteChannel chan = Files.newByteChannel(
302 Paths.get(dfl(p)), StandardOpenOption.READ)) {
303 chan.position(6);
304 int cc = 0;
305 while (true) {
306 try {
307 if (AuthTime.readFrom(chan) != null) cc++;
308 } catch (BufferUnderflowException e) {
309 break;
310 }
311 }
312 return cc;
313 } catch (IOException ioe) {
314 return 0;
315 }
316 }
317 // models an experiement
318 private static class Ex {
319 int i; // #
320 boolean expected; // expected result
321 boolean actual; // actual output
322 int old; // which ap-req to send
323 String server; // which server to send to
324 String hash; // the hash of req
325 int user; // which initiator
326 int peer; // which acceptor
327 int csize; // size of rcache after test
328 }
329 // models a saved ap-req msg
330 private static class Req {
331 String msg; // based64-ed req
332 int user; // which initiator
333 int peer; // which accceptor
334 Req(int user, int peer, String msg) {
335 this.msg = msg;
336 this.user= user;
337 this.peer = peer;
338 }
339 }
340 }
|
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 * @bug 7152176
27 * @summary More krb5 tests
28 * @library ../../../../java/security/testlibrary/ /test/lib
29 * @compile -XDignore.symbol.file ReplayCacheTestProc.java
30 * @run main/othervm/timeout=300 ReplayCacheTestProc
31 * @run main/othervm/timeout=300 -Djdk.krb5.rcache.usemd5=true ReplayCacheTestProc
32 */
33
34 import java.io.*;
35 import java.nio.BufferUnderflowException;
36 import java.nio.channels.SeekableByteChannel;
37 import java.nio.file.Files;
38 import java.nio.file.Paths;
39 import java.nio.file.StandardCopyOption;
40 import java.nio.file.StandardOpenOption;
41 import java.security.MessageDigest;
42 import java.util.*;
43
44 import jdk.test.lib.Platform;
45 import sun.security.jgss.GSSUtil;
46 import sun.security.krb5.internal.APReq;
47 import sun.security.krb5.internal.rcache.AuthTime;
48 import sun.security.krb5.internal.rcache.AuthTimeWithHash;
49
50 /**
51 * This test runs multiple acceptor Procs to mimin AP-REQ replays.
52 * It can either run with automatic (random) test runs or user can provide
53 * these system properties:
54 *
55 * - test.libs on what types of acceptors to use
56 * Format: CSV of (J|N|N<libname>)
57 * Example: J,N,N/krb5-1.14/lib/libgssapi_krb5.so
58 *
59 * - test.runs on runs
60 * Format: (req# | client# service#) acceptor# expected...
61 * Example: c0h0J0v,c1h1N0v,r0J1x means 1st req is new c0 to h0 sent to J0,
62 * 2nd req is new c1 to h1 sent to N0,
63 * 3rd req is old (1st replayed) sent to J1.
64 * For all old reqs, client# and service# MUST be -
65 *
66 * - test.autoruns on how many autoruns
67 * Format: number
68 */
69 public class ReplayCacheTestProc {
70
71 private static Proc[] pa; // all acceptors
72 private static Proc pi; // the single initiator
73 private static List<Req> reqs = new ArrayList<>();
74 private static String HOST = "localhost";
75
76 // Where should the rcache be saved. It seems KRB5RCACHEDIR is not
77 // recognized on Solaris. Maybe version too low? I see 1.6.
78 private static String cwd =
79 System.getProperty("os.name").startsWith("SunOS") ?
80 "/var/krb5/rcache/" :
81 System.getProperty("user.dir");
82
83
84 private static long uid;
85
86 public static void main0(String[] args) throws Exception {
87 System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF);
88 if (args.length == 0) { // The controller
89 int nu = 5; // number of users
90 int nh = 5; // number of hosts (services)
91 String[] libs; // available acceptor types:
92 // J: java
93 // N: default native lib
94 // N<libname>: native lib with the given name
95 Ex[] result;
96 int numPerType = 2; // number of servers per type
97
98 uid = jdk.internal.misc.VM.geteuid();
99
100 KDC kdc = KDC.create(OneKDC.REALM, HOST, 0, true);
101 for (int i=0; i<nu; i++) {
102 kdc.addPrincipal(user(i), OneKDC.PASS);
103 }
104 kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
105 for (int i=0; i<nh; i++) {
106 kdc.addPrincipalRandKey(host(i));
107 }
108
109 kdc.writeKtab(OneKDC.KTAB);
110 KDC.saveConfig(OneKDC.KRB5_CONF, kdc);
111
112 // User-provided libs
113 String userLibs = System.getProperty("test.libs");
114
115 if (userLibs != null) {
116 libs = userLibs.split(",");
117 } else {
118 if (Platform.isOSX() || Platform.isWindows()) {
119 // macOS uses Heimdal and Windows has no native lib
120 libs = new String[]{"J"};
121 } else {
122 // Test interop between Java and native (if available)
123 if (acceptor("N", "sanity").waitFor() != 0) {
124 Proc.d("Native mode sanity check failed, revert to java");
125 libs = new String[]{"J"};
126 } else {
127 libs = new String[]{"J", "N"};
128 }
129 }
130 }
131
132 pi = Proc.create("ReplayCacheTestProc").debug("C")
133 .args("initiator")
134 .start();
135
136 int na = libs.length * numPerType; // total number of acceptors
137 pa = new Proc[na];
138
139 // Acceptors, numPerType for 1st, numForType for 2nd, ...
140 for (int i=0; i<na; i++) {
141 int type = i / numPerType;
142 String label; // N/J for N/J, ABC... for N<lib>
143 if (libs[type].length() == 1) {
144 label = libs[type];
145 } else {
146 label = "" + (char)('A' + type);
147 }
148 pa[i] = acceptor(libs[type], label + i % numPerType);
149 }
150
151 String userRuns = System.getProperty("test.runs");
152
153 if (userRuns != null) {
154 String[] runs = userRuns.split(",");
155 result = new Ex[runs.length];
156 for (int i = 0; i < runs.length; i++) {
157 boolean expected = false;
158 int req = -1;
159 int client = -1;
160 int host = -1;
161 UserRun run = new UserRun(runs[i]);
162 while (true) {
163 char type = run.nextAction();
164 if (type == ' ') {
165 break;
166 }
167 switch (type) {
168 case 'r':
169 req = result[run.nextValue()].req;
170 break;
171 case 'c':
172 client = run.nextValue();
173 break;
174 case 'h':
175 req = req(client, run.nextValue());
176 break;
177 case 'J':
178 case 'N':
179 for (int j = 0; j < libs.length; j++) {
180 if (libs[j].equals("" + type)) {
181 host = j * numPerType + run.nextValue();
182 break;
183 }
184 }
185 break;
186 case 'v':
187 expected = true;
188 break;
189 case 'x':
190 expected = false;
191 break;
192 default: // ABC...
193 host = (type - 'A') * numPerType + run.nextValue();
194 }
195 }
196 result[i] = new Ex(i, req, host, expected);
197 }
198 } else {
199 result = new Ex[Integer.parseInt(
200 System.getProperty("test.autoruns", "100"))];
201 Random r = new Random();
202 for (int i = 0; i < result.length; i++) {
203 int old; // which req to send
204 boolean expected;
205 if (reqs.isEmpty() || r.nextBoolean()) {
206 old = req(r.nextInt(nu), r.nextInt(nh));
207 expected = true;
208 } else {
209 old = r.nextInt(reqs.size());
210 expected = false;
211 }
212 int s = r.nextInt(na);
213 result[i] = new Ex(i, old, s, expected);
214 }
215 }
216
217 for (Ex x : result) {
218 x.run();
219 }
220
221 pi.println("END");
222 for (int i=0; i<na; i++) {
223 pa[i].println("END");
224 }
225 System.out.println("Result\n======");
226 boolean finalOut = true;
227 System.out.println(" #: expected (req): client host acceptor Result size");
228 System.out.println("---- -------- ------ ------ ---- -------- ------ ----");
229 for (int i=0; i<result.length; i++) {
230 boolean out = result[i].expected==result[i].actual;
231 finalOut &= out;
232 System.out.printf("%3d: %8s (%3d): u%d h%d %8s %s %s %4d\n",
233 i,
234 result[i].expected?"----":" ",
235 result[i].req,
236 reqs.get(result[i].req).user,
237 reqs.get(result[i].req).peer,
238 pa[result[i].acceptor].debug(),
239 result[i].actual?"Good":"Bad ",
240 out?" ":"xxx",
241 result[i].csize);
242 }
243 if (!finalOut) throw new Exception();
244 } else if (args[0].equals("sanity")) {
245 // Native mode sanity check
246 Proc.d("Detect start");
247 Context s = Context.fromUserKtab("*", OneKDC.KTAB, true);
248 s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
249 } else if (args[0].equals("initiator")) {
250 while (true) {
251 String title = Proc.textIn();
252 Proc.d("Client see " + title);
253 if (title.equals("END")) break;
254 String[] cas = title.split(" ");
255 Context c = Context.fromUserPass(cas[0], OneKDC.PASS, false);
256 c.startAsClient(cas[1], GSSUtil.GSS_KRB5_MECH_OID);
257 c.x().requestCredDeleg(true);
258 byte[] token = c.take(new byte[0]);
259 Proc.d("Client AP-REQ generated");
260 Proc.binOut(token);
261 }
262 } else {
263 Proc.d("Server start");
264 Context s = Context.fromUserKtab("*", OneKDC.KTAB, true);
265 Proc.d("Server login");
266 while (true) {
267 String title = Proc.textIn();
268 Proc.d("Server " + args[0] + " sees " + title);
269 if (title.equals("END")) break;
275 Proc.d(args[0] + " Good");
276 } catch (Exception e) {
277 Proc.textOut("false");
278 Proc.d(args[0] + " Bad");
279 }
280 }
281 }
282 }
283
284 public static void main(String[] args) throws Exception {
285 try {
286 main0(args);
287 } catch (Exception e) {
288 Proc.d(e);
289 throw e;
290 }
291 }
292
293 // returns the user name
294 private static String user(int p) {
295 return "user" + p;
296 }
297
298 // returns the host name
299 private static String host(int p) {
300 return "host" + p + "/" + HOST;
301 }
302
303 // returns the dfl name for a host
304 private static String dfl(int p) {
305 return "host" + p + (uid == -1 ? "" : ("_"+uid));
306 }
307
308 // generates an ap-req and save into reqs, returns the index
309 private static int req(int user, int peer) throws Exception {
310 pi.println(user(user) + " " + host(peer));
311 Req req = new Req(user, peer, pi.readData());
312 reqs.add(req);
313 return reqs.size() - 1;
314 }
315
316 // create a acceptor
317 private static Proc acceptor(String type, String label) throws Exception {
318 Proc p = Proc.create("ReplayCacheTestProc")
319 .args(label)
320 .debug(label);
321 if (type.equals("J")) {
322 p.prop("sun.security.krb5.rcache", "dfl")
323 .prop("java.io.tmpdir", cwd);
324 String useMD5 = System.getProperty("jdk.krb5.rcache.usemd5");
325 if (useMD5 != null) {
326 p.prop("jdk.krb5.rcache.usemd5", useMD5);
327 }
328 } else {
329 p.env("KRB5_CONFIG", OneKDC.KRB5_CONF)
330 .env("KRB5_KTNAME", OneKDC.KTAB)
331 .env("KRB5RCACHEDIR", cwd)
332 .prop("sun.security.jgss.native", "true")
333 .prop("javax.security.auth.useSubjectCredsOnly", "false")
334 .prop("sun.security.nativegss.debug", "true");
335 if (type.length() > 1) {
336 String lib = type.substring(1);
337 String libDir = lib.substring(0, lib.lastIndexOf('/'));
338 p.prop("sun.security.jgss.lib", lib)
339 .env("DYLD_LIBRARY_PATH", libDir)
340 .env("LD_LIBRARY_PATH", libDir);
341 }
342 }
343 return p.start();
344 }
345
346 // generates hash of authenticator inside ap-req inside initsectoken
347 private static String hash(String req) throws Exception {
348 byte[] data = Base64.getDecoder().decode(req);
349 data = Arrays.copyOfRange(data, 17, data.length);
350 byte[] hash = MessageDigest.getInstance(
351 AuthTimeWithHash.realAlg(AuthTimeWithHash.DEFAULT_HASH_ALG))
352 .digest(new APReq(data).authenticator.getBytes());
353 char[] h = new char[hash.length * 2];
354 char[] hexConst = "0123456789ABCDEF".toCharArray();
355 for (int i=0; i<hash.length; i++) {
356 h[2*i] = hexConst[(hash[i]&0xff)>>4];
357 h[2*i+1] = hexConst[hash[i]&0xf];
358 }
359 return new String(h);
360 }
361
362 // return size of dfl file, excluding the null hash ones
363 private static int csize(int p) throws Exception {
364 try (SeekableByteChannel chan = Files.newByteChannel(
365 Paths.get(cwd, dfl(p)), StandardOpenOption.READ)) {
366 chan.position(6);
367 int cc = 0;
368 while (true) {
369 try {
370 if (AuthTime.readFrom(chan) != null) cc++;
371 } catch (BufferUnderflowException e) {
372 break;
373 }
374 }
375 return cc;
376 } catch (IOException ioe) {
377 return 0;
378 }
379 }
380
381 // models an experiement
382 private static class Ex {
383 int i; // #
384 int req; // which ap-req to send
385 int acceptor; // which acceptor to send to
386 boolean expected; // expected result
387
388 boolean actual; // actual output
389 int csize; // size of rcache after test
390 String hash; // the hash of req
391
392 Ex(int i, int req, int acceptor, boolean expected) {
393 this.i = i;
394 this.req = req;
395 this.acceptor = acceptor;
396 this.expected = expected;
397 }
398
399 void run() throws Exception {
400 Req r = reqs.get(req);
401 pa[acceptor].println("TEST");
402 pa[acceptor].println(r.msg);
403 String reply = pa[acceptor].readData();
404
405 actual = Boolean.valueOf(reply);
406 csize = csize(r.peer);
407 hash = hash(r.msg);
408 if (new File(cwd, dfl(r.peer)).exists()) {
409 Files.copy(Paths.get(cwd, dfl(r.peer)), Paths.get(
410 String.format("%03d-USER%d-host%d-%s-%s",
411 i, r.user, r.peer, acceptor,
412 actual)
413 + "-" + hash),
414 StandardCopyOption.COPY_ATTRIBUTES);
415 }
416 }
417 }
418
419 // models a saved ap-req msg
420 private static class Req {
421 String msg; // based64-ed req
422 int user; // which client
423 int peer; // which service
424 Req(int user, int peer, String msg) {
425 this.msg = msg;
426 this.user= user;
427 this.peer = peer;
428 }
429 }
430
431 private static class UserRun {
432 String run;
433 int pos = 0;
434 UserRun(String run) {
435 this.run = run;
436 }
437 char nextAction() {
438 return pos < run.length() ? run.charAt(pos++) : ' ';
439 }
440 int nextValue() {
441 int result = 0;
442 for (; pos < run.length(); pos++) {
443 char c = run.charAt(pos);
444 if (!Character.isDigit(c)) {
445 break;
446 }
447 result = result * 10 + (c - '0');
448 }
449 return result;
450 }
451 }
452 }
|