|
0
|
1 |
import java.util.*;
|
|
|
2 |
import java.io.*;
|
|
|
3 |
import java.net.*;
|
|
|
4 |
import javax.net.ssl.*;
|
|
|
5 |
import java.security.*;
|
|
|
6 |
import java.nio.*;
|
|
|
7 |
import java.nio.channels.*;
|
|
|
8 |
import java.awt.*;
|
|
|
9 |
import java.awt.image.*;
|
|
|
10 |
import java.awt.event.*;
|
|
|
11 |
import javax.swing.*;
|
|
|
12 |
import javax.swing.border.*;
|
|
|
13 |
|
|
|
14 |
class Debug {
|
|
|
15 |
static int debug;
|
|
|
16 |
String debid = "";
|
|
|
17 |
Debug(Debug d) { debid = d.debid; }
|
|
|
18 |
Debug(String debid) { this.debid = debid; }
|
|
|
19 |
Debug() {}
|
|
|
20 |
static void pRe(Object o) {
|
|
|
21 |
System.err.println((new Date().getTime()) + " " + o);
|
|
|
22 |
System.err.flush();
|
|
|
23 |
}
|
|
|
24 |
void log(int level, Object o) {
|
|
|
25 |
if(debug == 7) { if(level == 7) pRe(debid + ": " + o); }
|
|
|
26 |
else if(debug >= level) pRe(debid + ": " + o);
|
|
|
27 |
}
|
|
|
28 |
boolean abendMsg(String msg, Exception x) {
|
|
|
29 |
log(0, "ABEND: " + msg + (x == null ? "" : (": " + x.getClass().getSimpleName() + ": " + x.getMessage())));
|
|
|
30 |
return false;
|
|
|
31 |
}
|
|
|
32 |
String prBuf(ByteBuffer b) { return b.position() + "/" + b.remaining() + "/" + b.limit(); }
|
|
|
33 |
}
|
|
|
34 |
class Data extends Debug implements Serializable {
|
|
|
35 |
static final long serialVersionUID = 42;
|
|
|
36 |
class DataObj implements Serializable {
|
|
|
37 |
static final long serialVersionUID = 42;
|
|
|
38 |
String text;
|
|
|
39 |
int ttl;
|
|
|
40 |
int lport;
|
|
|
41 |
int rport;
|
|
|
42 |
DataObj(String s, int ttl) {
|
|
|
43 |
this.text = s;
|
|
|
44 |
this.ttl = ttl;
|
|
|
45 |
this.lport = 0;
|
|
|
46 |
this.rport = 0;
|
|
|
47 |
}
|
|
|
48 |
}
|
|
|
49 |
ByteBuffer buf;
|
|
|
50 |
DataObj data;
|
|
|
51 |
Data(Debug deb, String s, int ttl) throws Exception {
|
|
|
52 |
super(deb.debid + " DATA");
|
|
|
53 |
data = new DataObj(s, ttl);
|
|
|
54 |
if(CS.fake != 0 && debid.equals("DEMO SSL MASH DATA")) throw new Exception("faked error"); // <-----------------------------------------------
|
|
|
55 |
load();
|
|
|
56 |
}
|
|
|
57 |
Data(Debug deb, ByteBuffer b) throws Exception {
|
|
|
58 |
super(deb);
|
|
|
59 |
debid += " DATA";
|
|
|
60 |
log(5, "unloading data objects from buffer...");
|
|
|
61 |
unload();
|
|
|
62 |
}
|
|
|
63 |
Data(Debug deb) {
|
|
|
64 |
super(deb);
|
|
|
65 |
debid += " DATA";
|
|
|
66 |
}
|
|
|
67 |
void load() throws IOException {
|
|
|
68 |
log(5, "loading data objects to buffer...");
|
|
|
69 |
ByteArrayOutputStream bas = new ByteArrayOutputStream();
|
|
|
70 |
try {
|
|
|
71 |
new ObjectOutputStream(bas).writeObject(data);
|
|
|
72 |
buf = ByteBuffer.wrap(bas.toByteArray());
|
|
|
73 |
} catch(IOException x) { abendMsg("data buffer " + data + " load error", x); throw new IOException(x); }
|
|
|
74 |
}
|
|
|
75 |
void unload() throws Exception {
|
|
|
76 |
buf.rewind();
|
|
|
77 |
data = (DataObj) new ObjectInputStream(new ByteArrayInputStream(buf.array())).readObject();
|
|
|
78 |
}
|
|
|
79 |
int dttl() {
|
|
|
80 |
return --data.ttl;
|
|
|
81 |
}
|
|
|
82 |
int ttl() {
|
|
|
83 |
return data.ttl;
|
|
|
84 |
}
|
|
|
85 |
boolean equals(Data data) {
|
|
|
86 |
return this.data.text.equals(data.data.text);
|
|
|
87 |
}
|
|
|
88 |
public String toString() {
|
|
|
89 |
return "data: ttl=" + data.ttl + ", text=" +
|
|
|
90 |
(data.text.length() < 24 ? data.text : data.text.substring(0, 8) + "-------" + data.text.substring(data.text.length() - 8));
|
|
|
91 |
}
|
|
|
92 |
}
|
|
|
93 |
class Node extends Debug implements Runnable {
|
|
|
94 |
boolean kicker, closing = false;
|
|
|
95 |
int thisNode, nextNode, closingThreshHold = 0;
|
|
|
96 |
Data data;
|
|
|
97 |
Selector selector;
|
|
|
98 |
ServerSocketChannel ssc;
|
|
|
99 |
SelectionKey ssk;
|
|
|
100 |
SSLContext sslC = null;
|
|
|
101 |
HashMap<Integer, SockIO> cliSide = new HashMap<Integer, SockIO>();
|
|
|
102 |
HashMap<SelectionKey, SockIO> srvSide = new HashMap<SelectionKey, SockIO>();
|
|
|
103 |
Constellation con;
|
|
|
104 |
Node(Constellation con, int port) {
|
|
|
105 |
super(con);
|
|
|
106 |
debid = (con.ssl ? "" : "non") + "SSL " + (con.mash ? "mash" : "ring") + " node " + port;
|
|
|
107 |
log(4, "initalizing...");
|
|
|
108 |
try {
|
|
|
109 |
this.con = con;
|
|
|
110 |
thisNode = port;
|
|
|
111 |
kicker = (thisNode == con.first);
|
|
|
112 |
if(con.ssl) try { prepareSSL(); } catch(Exception x) { abend("SSL preparation", x); throw new Exception(); }
|
|
|
113 |
try { bind(); } catch(Exception x) { abend("bind", x); throw new Exception(); }
|
|
|
114 |
data = new Data(this);
|
|
|
115 |
data.buf = ByteBuffer.allocate(con.data.buf.limit());
|
|
|
116 |
log(5, "initalized");
|
|
|
117 |
} catch(Exception x) { abend("initialization", x); }
|
|
|
118 |
}
|
|
|
119 |
public void run() {
|
|
|
120 |
runLoop();
|
|
|
121 |
log(2, "ended");
|
|
|
122 |
synchronized(con.glob) { con.glob.spawned--; con.glob.notify(); }
|
|
|
123 |
}
|
|
|
124 |
public void runLoop() {
|
|
|
125 |
if(con.glob.doForward && kicker) { // kick off
|
|
|
126 |
log(1, "ready to initial send (" + con.data.buf.limit() + " bytes) " + con.data.toString());
|
|
|
127 |
data.buf.put(con.data.buf); data.buf.flip();
|
|
|
128 |
try { data.unload(); data.load(); } catch(Exception x) {};
|
|
|
129 |
doForward();
|
|
|
130 |
}
|
|
|
131 |
//if(con.glob.doForward && !con.glob.abend) do { // main loop
|
|
|
132 |
if(con.glob.doForward) do { // main loop
|
|
|
133 |
int k = 0;
|
|
|
134 |
log(5, "main loop, waiting for " + (con.glob.doForward ? "data" : "close") +
|
|
|
135 |
" from " + srvSide.size() + " open sockets, timeout=" + CS.selTO + " msecs, closingThreshHold=" + closingThreshHold);
|
|
|
136 |
if(!con.glob.doForward && closingThreshHold == 0) closingThreshHold = 5000 / CS.selTO;
|
|
|
137 |
try {
|
|
|
138 |
try { while((k = selector.select(CS.selTO)) == 0 && con.glob.doForward) {}
|
|
|
139 |
} catch(Exception x) { abend("socket channel select", x); throw new Exception(x); }
|
|
|
140 |
if(k > 0) {
|
|
|
141 |
for(Iterator<SelectionKey> ski = selector.selectedKeys().iterator(); ski.hasNext();) {
|
|
|
142 |
SelectionKey sk = ski.next();
|
|
|
143 |
if(sk.isAcceptable())
|
|
|
144 |
try { acc(); } catch(Exception x) { abend("main loop accept error", x); throw new Exception(x); }
|
|
|
145 |
if(sk.isReadable())
|
|
|
146 |
try { forward(sk); } catch(Exception x) { abend("main loop forward error", x); throw new Exception(x); }
|
|
|
147 |
ski.remove();
|
|
|
148 |
}
|
|
|
149 |
}
|
|
|
150 |
} catch (Exception x) { abend("main loop", x); }
|
|
|
151 |
if(con.glob.stop) {
|
|
|
152 |
log(1, "constellation stop, closing all connections");
|
|
|
153 |
stop(); return;
|
|
|
154 |
}
|
|
|
155 |
} while(con.glob.doForward || ((srvSide.size() > 0) && (closingThreshHold-- > 0)));
|
|
|
156 |
//} while((con.glob.doForward || (srvSide.size() > 0)) && !con.glob.abend);
|
|
|
157 |
log(5, "closing ssc...");
|
|
|
158 |
try { ssc.close(); } catch (Exception x) { abend("ssc close", x); }
|
|
|
159 |
if(kicker && !con.glob.stop && !con.glob.abend) con.glob.abend = !data.equals(con.data);
|
|
|
160 |
}
|
|
|
161 |
private void forward(SelectionKey sk) {
|
|
|
162 |
log(5, "entering 'forward'...");
|
|
|
163 |
SockIO si = srvSide.get(sk);
|
|
|
164 |
if(!si.get()) {
|
|
|
165 |
stop();
|
|
|
166 |
si.close();
|
|
|
167 |
srvSide.remove(sk);
|
|
|
168 |
}
|
|
|
169 |
else {
|
|
|
170 |
log(5, "received " + prBuf(data.buf));
|
|
|
171 |
try { data.unload(); } catch(Exception x) { abend("data unload at forwarding", x); return; }
|
|
|
172 |
if(kicker) {
|
|
|
173 |
log(3, "received from " + (con.mash ? "mash: " : "ring: ") + data.toString());
|
|
|
174 |
if(data.dttl() <= 0) {
|
|
|
175 |
if(CS.isGui) con.cBox.ttl = data.ttl();
|
|
|
176 |
log(1, "TTL 0 reached, received " + data.toString() + ", leaving 'forward' closing all connections");
|
|
|
177 |
stop(); return;
|
|
|
178 |
}
|
|
|
179 |
try { data.load(); } catch(Exception x) { abend("data load at forwarding", x); return; }
|
|
|
180 |
}
|
|
|
181 |
if(con.glob.doForward) doForward();
|
|
|
182 |
}
|
|
|
183 |
log(4, "leaving 'forward'");
|
|
|
184 |
}
|
|
|
185 |
private void doForward() {
|
|
|
186 |
if((nextNode = chooseNextNode()) == 0) { stop(); return; }
|
|
|
187 |
log(3, "forwarding data to " + nextNode);
|
|
|
188 |
if(CS.pacing) pacing(nextNode);
|
|
|
189 |
if(CS.pace > 0) try { Thread.sleep(CS.pace); } catch(InterruptedException i) {};
|
|
|
190 |
if(!cliSide.get(nextNode).put()) stop();
|
|
|
191 |
}
|
|
|
192 |
private int chooseNextNode() {
|
|
|
193 |
int next;
|
|
|
194 |
if(con.mash) while((next = (con.first + CS.r.nextInt(con.nodes))) == thisNode);
|
|
|
195 |
else { next = thisNode + 1; if(next > con.last) next = con.first; }
|
|
|
196 |
if(cliSide.containsKey(next)) return next;
|
|
|
197 |
else return (conn(next) ? next : 0);
|
|
|
198 |
}
|
|
|
199 |
private void pacing(int nextNode) {
|
|
|
200 |
log(4, "constls.pacing");
|
|
|
201 |
synchronized(CS.constls) {
|
|
|
202 |
if(!con.glob.pacingGo) try { CS.constls.wait(); } catch(InterruptedException x) {}
|
|
|
203 |
if(nextNode > 0) {
|
|
|
204 |
con.cBox.currLink[0] = thisNode - con.first;
|
|
|
205 |
con.cBox.currLink[1] = nextNode - con.first;
|
|
|
206 |
}
|
|
|
207 |
con.cBox.ttl = data.ttl();
|
|
|
208 |
log(4, "constls.notify"); CS.constls.notify();
|
|
|
209 |
con.glob.pacingGo = false;
|
|
|
210 |
}
|
|
|
211 |
}
|
|
|
212 |
public void stop() {
|
|
|
213 |
con.glob.doForward = false;
|
|
|
214 |
synchronized(con) { con.notify(); }
|
|
|
215 |
closeNode();
|
|
|
216 |
}
|
|
|
217 |
private void abend(String msg, Exception x) {
|
|
|
218 |
abendMsg(msg, x);
|
|
|
219 |
con.glob.abend = true;
|
|
|
220 |
CS.isRun = false;
|
|
|
221 |
stop();
|
|
|
222 |
}
|
|
|
223 |
private void closeNode() {
|
|
|
224 |
if(!closing) new Thread(new closeClients(this)).start();
|
|
|
225 |
closing = true;
|
|
|
226 |
}
|
|
|
227 |
private class closeClients extends Debug implements Runnable {
|
|
|
228 |
closeClients(Debug deb) { this.debid = deb.debid + " clients CLOSE"; }
|
|
|
229 |
public void run() {
|
|
|
230 |
log(4, "starting...");
|
|
|
231 |
for(Iterator<Integer> i = cliSide.keySet().iterator(); i.hasNext();) {
|
|
|
232 |
int port = i.next();
|
|
|
233 |
log(4, "closing conn to " + port);
|
|
|
234 |
cliSide.get(port).close();
|
|
|
235 |
}
|
|
|
236 |
log(4, "end");
|
|
|
237 |
}
|
|
|
238 |
}
|
|
|
239 |
private void prepareSSL() throws Exception {
|
|
|
240 |
char[] passphrase = "passphrase".toCharArray();
|
|
|
241 |
KeyStore ks = KeyStore.getInstance("JKS");
|
|
|
242 |
String ksFile = (System.getenv("KSF") == null) ? CS.cePath + "/testkeys" : System.getenv("KSF");
|
|
|
243 |
FileInputStream kfs = new FileInputStream(ksFile);
|
|
|
244 |
ks.load(kfs, passphrase);
|
|
|
245 |
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
|
|
246 |
kmf.init(ks, passphrase);
|
|
|
247 |
KeyStore ts = KeyStore.getInstance("JKS");
|
|
|
248 |
FileInputStream tfs = new FileInputStream(ksFile);
|
|
|
249 |
ts.load(tfs, passphrase);
|
|
|
250 |
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
|
|
251 |
tmf.init(ts);
|
|
|
252 |
sslC = SSLContext.getInstance("TLS");
|
|
|
253 |
sslC.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
|
|
254 |
kfs.close();
|
|
|
255 |
tfs.close();
|
|
|
256 |
}
|
|
|
257 |
private void bind() throws IOException {
|
|
|
258 |
log(5, "binding...");
|
|
|
259 |
selector = Selector.open();
|
|
|
260 |
ssc = ServerSocketChannel.open();
|
|
|
261 |
ssc.configureBlocking(false);
|
|
|
262 |
ssc.socket().bind(new InetSocketAddress(thisNode), 1024);
|
|
|
263 |
ssk = ssc.register(selector, SelectionKey.OP_ACCEPT);
|
|
|
264 |
log(2, "bound to " + thisNode);
|
|
|
265 |
}
|
|
|
266 |
private boolean conn(int remPort) {
|
|
|
267 |
int retry = CS.connThreshold;
|
|
|
268 |
boolean connected = false;
|
|
|
269 |
SocketChannel sc = null;
|
|
|
270 |
log(4, "connecting to " + remPort + ", timeout=" + (CS.connThreshold*CS.connTO)/1000 + " secs. ...");
|
|
|
271 |
while(!connected && retry-- > 0 && con.glob.doForward) {
|
|
|
272 |
try {
|
|
|
273 |
sc = SocketChannel.open(new InetSocketAddress("localhost", remPort));
|
|
|
274 |
connected = true;
|
|
|
275 |
} catch(Exception x) {
|
|
|
276 |
if(x.getMessage().equals("Connection refused")) {
|
|
|
277 |
try { Thread.sleep(CS.connTO); } catch(InterruptedException i) {}
|
|
|
278 |
} else { abendMsg("connection to " + remPort, x); return false; }
|
|
|
279 |
}
|
|
|
280 |
}
|
|
|
281 |
if(!con.glob.doForward) return false;
|
|
|
282 |
if(connected) {
|
|
|
283 |
try { cliSide.put(remPort, new SockIO(this, sc, false));
|
|
|
284 |
} catch(Exception x) { abendMsg("connection to " + remPort, x); return false; }
|
|
|
285 |
log(2, "connected after " + (CS.connThreshold - retry + 1) + " retries");
|
|
|
286 |
return true;
|
|
|
287 |
}
|
|
|
288 |
else { abendMsg("connection to " + remPort + " timeout", null); return false; }
|
|
|
289 |
}
|
|
|
290 |
private void acc() throws Exception {
|
|
|
291 |
try {
|
|
|
292 |
SocketChannel sc = ssc.accept();
|
|
|
293 |
sc.configureBlocking(false);
|
|
|
294 |
SockIO si = new SockIO(this, sc, true);
|
|
|
295 |
SelectionKey sk = sc.register(selector, SelectionKey.OP_READ);
|
|
|
296 |
srvSide.put(sk, si);
|
|
|
297 |
CS.connCnt++;
|
|
|
298 |
log(2, "connection accepted");
|
|
|
299 |
} catch(Exception x) { abend("connection accept", x); throw new Exception(x); }
|
|
|
300 |
}
|
|
|
301 |
private class SockIO extends Debug {
|
|
|
302 |
SocketChannel sc;
|
|
|
303 |
Selector handshakeSelector;
|
|
|
304 |
SelectionKey sk;
|
|
|
305 |
Runnable ru;
|
|
|
306 |
SSLSession session;
|
|
|
307 |
SSLEngine e;
|
|
|
308 |
SSLEngineResult r;
|
|
|
309 |
ByteBuffer ci, co, ib;
|
|
|
310 |
boolean wrapper;
|
|
|
311 |
SockIO(Debug deb, SocketChannel sc, boolean server) throws Exception {
|
|
|
312 |
this.debid = deb.debid + " socket " + (server ? "(server)" : "(client)");
|
|
|
313 |
log(5, "initializing...");
|
|
|
314 |
this.sc = sc;
|
|
|
315 |
if(con.ssl) {
|
|
|
316 |
handshakeSelector = Selector.open();
|
|
|
317 |
sc.configureBlocking(false);
|
|
|
318 |
sk = sc.register(handshakeSelector, SelectionKey.OP_READ);
|
|
|
319 |
e = sslC.createSSLEngine();
|
|
|
320 |
session = e.getSession();
|
|
|
321 |
int am = session.getApplicationBufferSize();
|
|
|
322 |
int pm = session.getPacketBufferSize();
|
|
|
323 |
ib = ByteBuffer.allocate(am); // pišvejcova konstanta
|
|
|
324 |
co = ByteBuffer.allocateDirect(pm);
|
|
|
325 |
ci = ByteBuffer.allocateDirect(pm);
|
|
|
326 |
if(server) {
|
|
|
327 |
e.setUseClientMode(false);
|
|
|
328 |
e.setNeedClientAuth(true);
|
|
|
329 |
} else e.setUseClientMode(true);
|
|
|
330 |
}
|
|
|
331 |
log(4, "initialized");
|
|
|
332 |
}
|
|
|
333 |
String prBuf(ByteBuffer b) { return b.position() + "/" + b.remaining() + "/" + b.limit() + "/" + b.capacity(); }
|
|
|
334 |
private String eStat() {
|
|
|
335 |
String stat;
|
|
|
336 |
if (r != null)
|
|
|
337 |
stat = r.getStatus() + "/" + r.getHandshakeStatus() + "/" + e.getHandshakeStatus() +
|
|
|
338 |
", bytes: " + r.bytesConsumed() + "/" + r.bytesProduced();
|
|
|
339 |
else stat = "-/-/" + e.getHandshakeStatus() + " -/-";
|
|
|
340 |
return stat;
|
|
|
341 |
}
|
|
|
342 |
//-- result status
|
|
|
343 |
private boolean isOK() {
|
|
|
344 |
return r.getStatus() == SSLEngineResult.Status.OK; }
|
|
|
345 |
private boolean isClosed() {
|
|
|
346 |
return r.getStatus() == SSLEngineResult.Status.CLOSED; }
|
|
|
347 |
private boolean isBad() {
|
|
|
348 |
return r.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW; }
|
|
|
349 |
//-- result handshake status
|
|
|
350 |
private boolean handShake() {
|
|
|
351 |
return r.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; }
|
|
|
352 |
private boolean handShakeEnd() {
|
|
|
353 |
return r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED; }
|
|
|
354 |
private boolean needTask() {
|
|
|
355 |
return r.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK; }
|
|
|
356 |
//-- engine handshake status
|
|
|
357 |
private boolean needUnwrap() {
|
|
|
358 |
return e.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP; }
|
|
|
359 |
private boolean needWrap() {
|
|
|
360 |
return e.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP; }
|
|
|
361 |
private int read(SocketChannel sc, ByteBuffer b) {
|
|
|
362 |
int n = -1, k = 0;
|
|
|
363 |
log(5, "read, " + prBuf(b) + " ...");
|
|
|
364 |
if(con.ssl) {
|
|
|
365 |
try { while((k = handshakeSelector.select(CS.selTO)) == 0) { if(!con.glob.doForward) break; }
|
|
|
366 |
} catch (Exception x) { abendMsg("handshake select", x); k = 0; }
|
|
|
367 |
if(k>0 && sk.isReadable()) {
|
|
|
368 |
try { n = sc.read(b); } catch(Exception x) { abendMsg("socket channel read", x); n = -1; }
|
|
|
369 |
handshakeSelector.selectedKeys().remove(sk);
|
|
|
370 |
}
|
|
|
371 |
} else
|
|
|
372 |
try { while(b.hasRemaining()) { n += sc.read(b); if(n < 0) break; }; n++;
|
|
|
373 |
} catch(Exception x) { abendMsg("socket channel read", x); n = -1; };
|
|
|
374 |
log(4, "read " + n);
|
|
|
375 |
return n;
|
|
|
376 |
}
|
|
|
377 |
private int write(SocketChannel sc, ByteBuffer b) {
|
|
|
378 |
log(5, "writing " + prBuf(b) + " ...");
|
|
|
379 |
int n = 0;
|
|
|
380 |
try { n = sc.write(b); } catch(Exception x) { abendMsg("socket channel write", x); n = -1; }
|
|
|
381 |
log(4, "written " + n);
|
|
|
382 |
return n;
|
|
|
383 |
}
|
|
|
384 |
private boolean replenish() {
|
|
|
385 |
log(5, "replenishing ci...");
|
|
|
386 |
ci.clear();
|
|
|
387 |
int n = read(sc, ci);
|
|
|
388 |
ci.flip();
|
|
|
389 |
return (n >= 0);
|
|
|
390 |
|
|
|
391 |
}
|
|
|
392 |
void handleUnWrapStatus() {
|
|
|
393 |
ByteBuffer b;
|
|
|
394 |
if(r.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) {
|
|
|
395 |
log(5, "unwrap: ib BUFFER_OVERFLOW " + prBuf(ib));
|
|
|
396 |
if(ib.position() > 0) { ib.flip(); data.buf.put(ib); ib.clear(); }
|
|
|
397 |
else {
|
|
|
398 |
b = ByteBuffer.allocate((int)(1.25 * ib.capacity()));
|
|
|
399 |
ib.flip(); b.put(ib); ib = b; }
|
|
|
400 |
log(5, "ib " + prBuf(ib));
|
|
|
401 |
}
|
|
|
402 |
if(r.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
|
|
|
403 |
int n;
|
|
|
404 |
log(5, "unwrap: ci BUFFER_UNDERFLOW " + prBuf(ci));
|
|
|
405 |
if(ci.limit() < ci.capacity()) {
|
|
|
406 |
ci.mark(); ci.position(ci.limit()); ci.limit(ci.capacity());
|
|
|
407 |
n = read(sc, ci); ci.limit(ci.position()); ci.reset(); }
|
|
|
408 |
else {
|
|
|
409 |
n = ci.capacity(); if(ci.position() == 0) n *= 2;
|
|
|
410 |
b = ByteBuffer.allocate(n); b.put(ci); ci = b;
|
|
|
411 |
n = read(sc, ci); ci.flip(); }
|
|
|
412 |
log(5, "additional " + n + " bytes read: " + prBuf(ci)); }
|
|
|
413 |
}
|
|
|
414 |
boolean doWrap() {
|
|
|
415 |
log(5, "entering " + "wrap, ob: " + prBuf(data.buf) + ", co: " + prBuf(co) + " ...");
|
|
|
416 |
try { r = e.wrap(data.buf, co); } catch (Exception x) { abend("SSL engine wrap", x); return false; }
|
|
|
417 |
//if(isBad()) { con.glob.abend = true; return abendMsg("SSL engine status: " + r.getStatus().toString(), null); }
|
|
|
418 |
if(isBad()) { abend("SSL engine status: " + r.getStatus().toString(), null); return false; }
|
|
|
419 |
log(4, "after " + (wrapper ? "wrapper" : "unwrapper") + " wrap: " + eStat() + ", ob: " + prBuf(data.buf) + ", co: " + prBuf(co));
|
|
|
420 |
if(isClosed()) return false;
|
|
|
421 |
return true;
|
|
|
422 |
}
|
|
|
423 |
private boolean wrap() {
|
|
|
424 |
do {co.clear();
|
|
|
425 |
if(!doWrap()) return false;
|
|
|
426 |
if(needTask()) while((ru = e.getDelegatedTask()) != null) ru.run();
|
|
|
427 |
co.flip();
|
|
|
428 |
if(handShake() && (write(sc, co) == -1)) return false;
|
|
|
429 |
} while (needWrap());
|
|
|
430 |
if(needUnwrap() && !( replenish() && unwrap() )) return false;
|
|
|
431 |
log(5, (wrapper ? "wrapper" : "unwrapper") + " wrap HS finished=" + handShakeEnd());
|
|
|
432 |
if(wrapper && handShakeEnd()) {
|
|
|
433 |
co.clear();
|
|
|
434 |
if(!doWrap()) return false;
|
|
|
435 |
co.flip();
|
|
|
436 |
}
|
|
|
437 |
return true;
|
|
|
438 |
}
|
|
|
439 |
boolean doUnwrap() {
|
|
|
440 |
log(5, "entering " + "unwrap, ib: " + prBuf(ib) + ", ci: " + prBuf(ci) + " ...");
|
|
|
441 |
try { r = e.unwrap(ci, ib); } catch (Exception x) { abend("SSL engine unwrap", x); return false; }
|
|
|
442 |
log(4, "after " + (wrapper ? "wrapper" : "unwrapper") + " unwrap: " + eStat() + ", ib: " + prBuf(ib) + ", ci: " + prBuf(ci));
|
|
|
443 |
if(isClosed()) return false;
|
|
|
444 |
return true;
|
|
|
445 |
}
|
|
|
446 |
private boolean unwrap() {
|
|
|
447 |
do { // while( needUnwrap() )
|
|
|
448 |
do { // while( needUnwrap() && ci.hasRemaining() )
|
|
|
449 |
if(!doUnwrap()) return false;
|
|
|
450 |
if(needTask()) while((ru = e.getDelegatedTask()) != null) ru.run();
|
|
|
451 |
} while(needUnwrap() && ci.hasRemaining());
|
|
|
452 |
if(needUnwrap() && !replenish()) return false;
|
|
|
453 |
} while(needUnwrap());
|
|
|
454 |
if(needWrap() && !wrap()) return false;
|
|
|
455 |
if(!wrapper) {
|
|
|
456 |
if(handShakeEnd() && !replenish()) return false;
|
|
|
457 |
if(handShakeEnd() || !handShake()) {
|
|
|
458 |
handleUnWrapStatus();
|
|
|
459 |
while(ci.hasRemaining()) {
|
|
|
460 |
do {
|
|
|
461 |
if(!doUnwrap()) return false;
|
|
|
462 |
handleUnWrapStatus();
|
|
|
463 |
} while(!isOK());
|
|
|
464 |
}
|
|
|
465 |
}
|
|
|
466 |
}
|
|
|
467 |
return true;
|
|
|
468 |
}
|
|
|
469 |
boolean get() {
|
|
|
470 |
wrapper = false;
|
|
|
471 |
boolean got = false;
|
|
|
472 |
data.buf.clear();
|
|
|
473 |
if(con.ssl) {
|
|
|
474 |
while(data.buf.hasRemaining()) {
|
|
|
475 |
ib.clear();
|
|
|
476 |
int n;
|
|
|
477 |
ci.clear(); n = read(sc, ci); ci.flip();
|
|
|
478 |
if(n < 0) { got = false; break; }
|
|
|
479 |
else got = (unwrap() && !isClosed());
|
|
|
480 |
if(got) { ib.flip(); data.buf.put(ib); log(4, "partially got " + prBuf(data.buf)); }
|
|
|
481 |
else break;
|
|
|
482 |
}
|
|
|
483 |
}
|
|
|
484 |
else try { got = (read(sc, data.buf) >= 0); } catch(Exception x) { got = abendMsg("socket read", x); }
|
|
|
485 |
return got;
|
|
|
486 |
}
|
|
|
487 |
boolean put() {
|
|
|
488 |
wrapper = true;
|
|
|
489 |
boolean put = false;
|
|
|
490 |
log(4, "put: ob: " + prBuf(data.buf));
|
|
|
491 |
try {
|
|
|
492 |
do {
|
|
|
493 |
if(con.ssl) {
|
|
|
494 |
if(!wrap() || isClosed()) return false;
|
|
|
495 |
else put = (write(sc, co) >= 0);
|
|
|
496 |
} else put = (write(sc, data.buf) >= 0);
|
|
|
497 |
} while(put && data.buf.hasRemaining());
|
|
|
498 |
if(put) CS.forwCnt++;
|
|
|
499 |
} catch(Exception x) { put = abendMsg("socket write", x); }
|
|
|
500 |
return put;
|
|
|
501 |
}
|
|
|
502 |
void close() {
|
|
|
503 |
log(4, "terminating connection...");
|
|
|
504 |
try {
|
|
|
505 |
if(con.ssl) {
|
|
|
506 |
data.buf.put(ByteBuffer.wrap("".getBytes()));
|
|
|
507 |
e.closeOutbound();
|
|
|
508 |
wrap();
|
|
|
509 |
}
|
|
|
510 |
sc.close();
|
|
|
511 |
} catch(Exception x) {}
|
|
|
512 |
}
|
|
|
513 |
}
|
|
|
514 |
}
|
|
|
515 |
class Constellation extends Debug implements Runnable {
|
|
|
516 |
class Glob {
|
|
|
517 |
boolean doForward = true;
|
|
|
518 |
boolean pacingGo = false;
|
|
|
519 |
boolean stop = false;
|
|
|
520 |
boolean abend = false;
|
|
|
521 |
int D = 0;
|
|
|
522 |
int spawned = 0;
|
|
|
523 |
int from = 0, to = 0;
|
|
|
524 |
}
|
|
|
525 |
volatile Glob glob;
|
|
|
526 |
boolean mash, ssl;
|
|
|
527 |
int first, last, nodes;
|
|
|
528 |
Data data;
|
|
|
529 |
CS cs;
|
|
|
530 |
Gui.CBox cBox;
|
|
|
531 |
String label;
|
|
|
532 |
Constellation(CS cs, Gui.CBox cBox, boolean mash, boolean ssl) {
|
|
|
533 |
label = (ssl ? "" : "non") + "SSL " + (mash ? "MASH" : "RING");
|
|
|
534 |
debid = "DEMO " + label;
|
|
|
535 |
this.cs = cs;
|
|
|
536 |
this.cBox = cBox;
|
|
|
537 |
this.mash = mash;
|
|
|
538 |
this.ssl = ssl;
|
|
|
539 |
if(mash) { first = CS.mp0; nodes = CS.mn; }
|
|
|
540 |
else { first = CS.rp0; nodes = CS.rn; }
|
|
|
541 |
glob = new Glob();
|
|
|
542 |
}
|
|
|
543 |
Constellation(Constellation con) {
|
|
|
544 |
super(con);
|
|
|
545 |
this.cs = con.cs;
|
|
|
546 |
this.mash = con.mash;
|
|
|
547 |
this.ssl = con.ssl;
|
|
|
548 |
this.first = con.first;
|
|
|
549 |
this.last = con.last;
|
|
|
550 |
this.nodes = con.nodes;
|
|
|
551 |
this.glob = con.glob;
|
|
|
552 |
}
|
|
|
553 |
void stop() { glob.stop = true; }
|
|
|
554 |
//void reset() {
|
|
|
555 |
//first = mash ? CS.mp0 : CS.rp0;
|
|
|
556 |
//first += nodes;
|
|
|
557 |
//glob.doForward = true;
|
|
|
558 |
//glob.abend = false;
|
|
|
559 |
//glob.spawned = 0;
|
|
|
560 |
//}
|
|
|
561 |
public void run() {
|
|
|
562 |
log(4, "starting");
|
|
|
563 |
glob.pacingGo = true;
|
|
|
564 |
runNodes();
|
|
|
565 |
synchronized(CS.constls) { CS.constls.notify(); }
|
|
|
566 |
synchronized(cs) {
|
|
|
567 |
if(--CS.notFinished == 0) cs.notifyAll();
|
|
|
568 |
else try { cs.wait(); } catch(InterruptedException e) {};
|
|
|
569 |
}
|
|
|
570 |
log(1, glob.abend ? "BAD: constellation not finished correctly" : "OK, constellation finished correctly");
|
|
|
571 |
if(glob.abend) CS.abend = true;
|
|
|
572 |
CS.spawned--;
|
|
|
573 |
synchronized(cs) { cs.notify(); }
|
|
|
574 |
}
|
|
|
575 |
void runNodes() {
|
|
|
576 |
log(1, nodes + " nodes constellation, ttl=" + CS.pttl + " starting...");
|
|
|
577 |
first += (ssl ? 500 : 0);
|
|
|
578 |
last = first + nodes - 1;
|
|
|
579 |
if(data == null)
|
|
|
580 |
try { data = new Data(this, CS.text, CS.pttl);
|
|
|
581 |
} catch(Exception x) { abendMsg("creating initial data", x); return; }
|
|
|
582 |
synchronized(glob) {
|
|
|
583 |
for(int port = first; (port < first + nodes); port++) {
|
|
|
584 |
try {
|
|
|
585 |
new Thread(new Node(this, port), "Node " + port).start();
|
|
|
586 |
log(3, "node " + port + " established");
|
|
|
587 |
glob.spawned++;
|
|
|
588 |
} catch(Exception x) { glob.doForward = false; glob.abend = true; break; }
|
|
|
589 |
}
|
|
|
590 |
if(glob.doForward) log(2, "all nodes established");
|
|
|
591 |
while(glob.spawned > 0) try { glob.wait(); } catch(InterruptedException e) {};
|
|
|
592 |
}
|
|
|
593 |
log(2, "all nodes finished");
|
|
|
594 |
}
|
|
|
595 |
}
|
|
|
596 |
class Gui extends Debug implements Runnable {
|
|
|
597 |
class Parms extends JPanel {
|
|
|
598 |
static final long serialVersionUID = 43;
|
|
|
599 |
class Parm implements ActionListener {
|
|
|
600 |
JComboBox<Number> valueEntry;
|
|
|
601 |
JLabel valueLabel;
|
|
|
602 |
Parm(Number[] values, Number value, String label, boolean editable, boolean rowEnd) {
|
|
|
603 |
log(5, "parm " + label);
|
|
|
604 |
valueLabel = new JLabel(label);
|
|
|
605 |
valueLabel.setBorder(b);
|
|
|
606 |
if(orientation == HORIZONTAL) gridC.gridwidth = 1;
|
|
|
607 |
else gridC.gridwidth = GridBagConstraints.REMAINDER;
|
|
|
608 |
gridL.setConstraints(valueLabel, gridC);
|
|
|
609 |
add(valueLabel);
|
|
|
610 |
valueEntry = new JComboBox<Number>(values);
|
|
|
611 |
valueEntry.setPreferredSize(new Dimension(prefComboWidth, prefComboHeight));
|
|
|
612 |
if(value != null) valueEntry.setSelectedItem(value);
|
|
|
613 |
valueEntry.setEditable(editable);
|
|
|
614 |
valueEntry.addActionListener(this);
|
|
|
615 |
if(orientation == HORIZONTAL && rowEnd) gridC.gridwidth = GridBagConstraints.REMAINDER;
|
|
|
616 |
gridL.setConstraints(valueEntry, gridC);
|
|
|
617 |
add(valueEntry);
|
|
|
618 |
}
|
|
|
619 |
public void actionPerformed(ActionEvent e) {
|
|
|
620 |
try { setVal((Number)((JComboBox)e.getSource()).getSelectedItem()); } catch(Exception x) { log(0, x.getMessage()); }
|
|
|
621 |
}
|
|
|
622 |
void getEnv() {}
|
|
|
623 |
void setVal(Number v) {}
|
|
|
624 |
}
|
|
|
625 |
class Buttons extends Box {
|
|
|
626 |
class GoButton extends JButton implements ActionListener {
|
|
|
627 |
static final long serialVersionUID = 44;
|
|
|
628 |
GoButton() {
|
|
|
629 |
super("go");
|
|
|
630 |
addActionListener(this);
|
|
|
631 |
gridC.gridwidth = 1;
|
|
|
632 |
gridL.setConstraints(this, gridC);
|
|
|
633 |
CS.go = true;
|
|
|
634 |
}
|
|
|
635 |
public void actionPerformed(ActionEvent e) {
|
|
|
636 |
log(5, getText() + " button pressed");
|
|
|
637 |
if(getText().equals("go")) { setText("pause"); CS.go = true; CS.pacing = true; CS.isRun = true; awake(); }
|
|
|
638 |
else { setText("go"); CS.go = false; }
|
|
|
639 |
}
|
|
|
640 |
}
|
|
|
641 |
class StepButton extends JButton implements ActionListener {
|
|
|
642 |
static final long serialVersionUID = 44;
|
|
|
643 |
StepButton() {
|
|
|
644 |
super("step");
|
|
|
645 |
addActionListener(this);
|
|
|
646 |
gridC.gridwidth = 1;
|
|
|
647 |
gridL.setConstraints(this, gridC);
|
|
|
648 |
}
|
|
|
649 |
public void actionPerformed(ActionEvent e) {
|
|
|
650 |
log(5, getText() + " button pressed");
|
|
|
651 |
CS.go = false; CS.pacing = true; CS.isRun = true;
|
|
|
652 |
setGo();
|
|
|
653 |
awake();
|
|
|
654 |
}
|
|
|
655 |
}
|
|
|
656 |
class ResetButton extends JButton implements ActionListener {
|
|
|
657 |
static final long serialVersionUID = 45;
|
|
|
658 |
ResetButton() {
|
|
|
659 |
super("reset");
|
|
|
660 |
addActionListener(this);
|
|
|
661 |
gridC.gridwidth = 1;
|
|
|
662 |
gridL.setConstraints(this, gridC);
|
|
|
663 |
}
|
|
|
664 |
public void actionPerformed(ActionEvent e) { CS.isRun = false; CS.isReset = true; CS.go = true; awake(); }
|
|
|
665 |
}
|
|
|
666 |
class StopButton extends JButton implements ActionListener {
|
|
|
667 |
static final long serialVersionUID = 46;
|
|
|
668 |
StopButton() {
|
|
|
669 |
super("end");
|
|
|
670 |
addActionListener(this);
|
|
|
671 |
gridC.gridwidth = 1;
|
|
|
672 |
//gridC.gridwidth = GridBagConstraints.REMAINDER;
|
|
|
673 |
gridL.setConstraints(this, gridC);
|
|
|
674 |
}
|
|
|
675 |
public void actionPerformed(ActionEvent e) { closeUI(); }
|
|
|
676 |
}
|
|
|
677 |
GoButton go;
|
|
|
678 |
ResetButton reset;
|
|
|
679 |
StepButton step;
|
|
|
680 |
StopButton stop;
|
|
|
681 |
Box row1, row2;
|
|
|
682 |
Buttons() {
|
|
|
683 |
super(BoxLayout.Y_AXIS);
|
|
|
684 |
setBorder(b);
|
|
|
685 |
add(row1 = new Box(BoxLayout.X_AXIS));
|
|
|
686 |
add(row2 = new Box(BoxLayout.X_AXIS));
|
|
|
687 |
row1.add(go = new GoButton());
|
|
|
688 |
row1.add(step = new StepButton());
|
|
|
689 |
row2.add(reset = new ResetButton());
|
|
|
690 |
row2.add(stop = new StopButton());
|
|
|
691 |
}
|
|
|
692 |
void setGo() { go.setText("go"); }
|
|
|
693 |
void setPause() { go.setText("pause"); }
|
|
|
694 |
void enableStep(boolean b) { step.setEnabled(b); }
|
|
|
695 |
}
|
|
|
696 |
static final boolean EDITABLE = true;
|
|
|
697 |
static final boolean ROW_END = true;
|
|
|
698 |
boolean orientation;
|
|
|
699 |
EmptyBorder b = new EmptyBorder(0,7,0,7);
|
|
|
700 |
GridBagLayout gridL = new GridBagLayout();
|
|
|
701 |
GridBagConstraints gridC = new GridBagConstraints();
|
|
|
702 |
int prefComboWidth, prefComboHeight;
|
|
|
703 |
Buttons buttons;
|
|
|
704 |
Parms(boolean orientation) {
|
|
|
705 |
textHeight = (int)Math.round(1.5 * getFontMetrics(getFont()).getHeight());
|
|
|
706 |
prefComboWidth = (int)Math.round(1.5 * getFontMetrics(getFont()).bytesWidth("000000".getBytes(), 0, 6));
|
|
|
707 |
prefComboHeight = textHeight;
|
|
|
708 |
this.orientation = orientation;
|
|
|
709 |
gridC.fill = GridBagConstraints.BOTH;
|
|
|
710 |
setFont(new Font("SansSerif", Font.PLAIN, 9));
|
|
|
711 |
setLayout(gridL);
|
|
|
712 |
new Parm(new Integer[] {0,1,2,3,4,5,7,9}, new Integer(CS.debug), "Debug level", !EDITABLE, !ROW_END) {
|
|
|
713 |
void setVal(Number v) { CS.debug = v.intValue(); } };
|
|
|
714 |
new Parm(new Integer[] {0,1,2}, new Integer(CS.issl), "SSL", !EDITABLE, !ROW_END) {
|
|
|
715 |
void setVal(Number v) { CS.issl = v.intValue(); } };
|
|
|
716 |
new Parm(new Integer[] {CS.pttl}, null, "TTL", EDITABLE, ROW_END) {
|
|
|
717 |
void setVal(Number v) { CS.pttl = v.intValue(); } };
|
|
|
718 |
new Parm(new Double[] {(double)CS.ipace/1000}, null, "pace in secs.", EDITABLE, !ROW_END) {
|
|
|
719 |
void setVal(Number v) { CS.ipace = (int)(1000.0 * v.doubleValue()); CS.pace = CS.ipace; } };
|
|
|
720 |
new Parm(new Integer[] {CS.mp0}, null, "listen port of first MASH node", EDITABLE, !ROW_END) {
|
|
|
721 |
void setVal(Number v) { CS.mp0 = v.intValue(); } };
|
|
|
722 |
new Parm(new Integer[] {CS.rp0}, null, "listen port of first RING node", EDITABLE, ROW_END) {
|
|
|
723 |
void setVal(Number v) { CS.rp0 = v.intValue(); } };
|
|
|
724 |
new Parm(new Integer[] {CS.mn}, null, "MASH constellation size", EDITABLE, !ROW_END) {
|
|
|
725 |
void setVal(Number v) { CS.mn = v.intValue(); } };
|
|
|
726 |
new Parm(new Integer[] {CS.rn}, null, "RING constellation size", EDITABLE, !ROW_END) {
|
|
|
727 |
void setVal(Number v) { CS.rn = v.intValue(); } };
|
|
|
728 |
new Parm(new Double[] {(double)CS.selTO/1000}, null, "I/O selection timeout in secs.", EDITABLE, ROW_END) {
|
|
|
729 |
void setVal(Number v) { CS.selTO = 1000 * v.intValue(); } };
|
|
|
730 |
new Parm(new Integer[] {CS.fake}, null, "point of faked exception (integer)", EDITABLE, !ROW_END) {
|
|
|
731 |
void setVal(Number v) { CS.fake = v.intValue(); } };
|
|
|
732 |
new Parm(new Integer[] {CS.rs}, null, "random seed (integer)", EDITABLE, !ROW_END) {
|
|
|
733 |
void setVal(Number v) { CS.rs = v.intValue(); } };
|
|
|
734 |
//gridC.gridwidth = 0;
|
|
|
735 |
gridC.gridwidth = GridBagConstraints.REMAINDER;
|
|
|
736 |
add(buttons = new Buttons());
|
|
|
737 |
}
|
|
|
738 |
}
|
|
|
739 |
class CBoxBg extends BufferedImage {
|
|
|
740 |
final int nodeC[][]; // node centers
|
|
|
741 |
CBoxBg(int n) {
|
|
|
742 |
super(cBoxSize , cBoxSize, BufferedImage.TYPE_INT_RGB);
|
|
|
743 |
nodeC = new int[n][2];
|
|
|
744 |
log(5, "cnstlltn bg image beg, node centers array length=" + nodeC.length);
|
|
|
745 |
final double a0 = Math.PI / 2;
|
|
|
746 |
final double aN = 2 * Math.PI / n;
|
|
|
747 |
final int b = 3; // border
|
|
|
748 |
final int r = 5; // node diameter
|
|
|
749 |
int cx, cy; // constellation center coordinates
|
|
|
750 |
cx = cy = cBoxSize/2;
|
|
|
751 |
int R = cBoxSize/2 - r - 2*b; // distance of node centers from constellation center
|
|
|
752 |
int dx, dy; // deltas of node center coordinates
|
|
|
753 |
final Graphics2D g2 = (Graphics2D)this.getGraphics();
|
|
|
754 |
g2.setBackground(Color.WHITE);
|
|
|
755 |
g2.clearRect(0, 0, cBoxSize, cBoxSize);
|
|
|
756 |
g2.setColor(Color.BLACK);
|
|
|
757 |
g2.draw3DRect(b, b, cBoxSize - 2*b, cBoxSize - 2*b, true);
|
|
|
758 |
if(n < 2) return;
|
|
|
759 |
for(int i=0; i<n; i++) {
|
|
|
760 |
dx = (int)Math.round(Math.cos(a0 + i * aN) * R);
|
|
|
761 |
dy = (int)Math.round(Math.sin(a0 + i * aN) * R);
|
|
|
762 |
nodeC[i][0] = dx; nodeC[i][1] = dy;
|
|
|
763 |
g2.drawOval(cx-dx-r, cy-dy-r, 2*r, 2*r);
|
|
|
764 |
}
|
|
|
765 |
log(5, "cnstlltn bg image end, node centers array length=" + nodeC.length);
|
|
|
766 |
}
|
|
|
767 |
}
|
|
|
768 |
class Arrow extends Polygon {
|
|
|
769 |
final double z, D, sin, cos, xd, yd, dx, dy;
|
|
|
770 |
final int x0, y0, x3, y3;
|
|
|
771 |
Arrow(int x1, int y1, int x2, int y2, int d) {
|
|
|
772 |
super();
|
|
|
773 |
z=d/(2*1.618034);
|
|
|
774 |
D = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
|
|
|
775 |
sin = (x2-x1)/D;
|
|
|
776 |
cos = (y2-y1)/D;
|
|
|
777 |
xd = x2-d*sin;
|
|
|
778 |
yd = y2-d*cos;
|
|
|
779 |
dx = z*cos;
|
|
|
780 |
dy = z*sin;
|
|
|
781 |
x0 = (int)Math.round(xd-dx);
|
|
|
782 |
y0 = (int)Math.round(yd+dy);
|
|
|
783 |
x3 = (int)Math.round(xd+dx);
|
|
|
784 |
y3 = (int)Math.round(yd-dy);
|
|
|
785 |
addPoint(x0, y0);
|
|
|
786 |
addPoint(x2, y2);
|
|
|
787 |
addPoint(x3, y3);
|
|
|
788 |
}
|
|
|
789 |
}
|
|
|
790 |
class CBox extends Box {
|
|
|
791 |
static final long serialVersionUID = 45;
|
|
|
792 |
class CHead extends JPanel {
|
|
|
793 |
final JLabel field = new JLabel();
|
|
|
794 |
CHead() {
|
|
|
795 |
setPreferredSize(new Dimension(cBoxSize, textHeight - 4));
|
|
|
796 |
add(field);
|
|
|
797 |
}
|
|
|
798 |
public void paint(Graphics g) {
|
|
|
799 |
super.paint(g);
|
|
|
800 |
field.setText(label + ttl);
|
|
|
801 |
}
|
|
|
802 |
}
|
|
|
803 |
class CPanel extends JPanel {
|
|
|
804 |
CPanel() { setPreferredSize(new Dimension(cBoxSize, cBoxSize)); }
|
|
|
805 |
public void paint(Graphics g) {
|
|
|
806 |
super.paint(g);
|
|
|
807 |
final Graphics2D g2 = (Graphics2D)g;
|
|
|
808 |
Polygon p;
|
|
|
809 |
g2.drawImage(bg, 0, 0, Color.WHITE, null);
|
|
|
810 |
final int n1 = currLink[0], n2 = currLink[1];
|
|
|
811 |
if(n1 > -1) {
|
|
|
812 |
final int x1 = cx-bg.nodeC[n1][0], y1 = cy-bg.nodeC[n1][1];
|
|
|
813 |
final int x2 = cx-bg.nodeC[n2][0], y2 = cy-bg.nodeC[n2][1];
|
|
|
814 |
log(5, label + " paint, n1=" + n1 + ", n2=" + n2 + ", nodeC.length=" + bg.nodeC.length);
|
|
|
815 |
g2.setColor(Color.CYAN);
|
|
|
816 |
g2.setStroke(new BasicStroke(2));
|
|
|
817 |
g2.drawLine(x1, y1, x2, y2);
|
|
|
818 |
g2.setColor(Color.BLUE);
|
|
|
819 |
g2.setStroke(new BasicStroke(0));
|
|
|
820 |
g2.drawPolygon(p = new Arrow(x1, y1, x2, y2, 12));
|
|
|
821 |
g2.fill(p);
|
|
|
822 |
}
|
|
|
823 |
}
|
|
|
824 |
}
|
|
|
825 |
volatile int[] currLink = {-1,-1};
|
|
|
826 |
volatile int ttl;
|
|
|
827 |
CBoxBg bg;
|
|
|
828 |
final int cx = cBoxSize / 2, cy = cx;
|
|
|
829 |
final String label;
|
|
|
830 |
CBox(String label, CBoxBg bg) {
|
|
|
831 |
super(BoxLayout.Y_AXIS);
|
|
|
832 |
setMaximumSize(new Dimension(cBoxSize, cBoxSize + textHeight));
|
|
|
833 |
this.bg = bg;
|
|
|
834 |
this.label = label + ", ttl=";
|
|
|
835 |
ttl = CS.pttl;
|
|
|
836 |
add(new CHead());
|
|
|
837 |
add(new CPanel());
|
|
|
838 |
}
|
|
|
839 |
void reset(CBoxBg bg) { currLink[0] = -1; currLink[1] = -1; ttl = CS.pttl; this.bg = bg; }
|
|
|
840 |
}
|
|
|
841 |
class CcBox extends Box {
|
|
|
842 |
CBox ringBox, mashBox;
|
|
|
843 |
CcBox(String label) {
|
|
|
844 |
super(BoxLayout.X_AXIS);
|
|
|
845 |
add(mashBox = new CBox("MASH " + label + " SSL", mashBg));
|
|
|
846 |
add(ringBox = new CBox("RING " + label + " SSL", ringBg));
|
|
|
847 |
}
|
|
|
848 |
}
|
|
|
849 |
CS cs;
|
|
|
850 |
JFrame ui = new JFrame(debid);
|
|
|
851 |
Container dashboard;
|
|
|
852 |
static final boolean HORIZONTAL = true;
|
|
|
853 |
static final boolean VERTICAL = false;
|
|
|
854 |
boolean dashboardLayout = HORIZONTAL;
|
|
|
855 |
int textHeight;
|
|
|
856 |
Parms parms;
|
|
|
857 |
Box resultBox = null;
|
|
|
858 |
CcBox sslBox = null, nonSslBox = null;
|
|
|
859 |
CBoxBg ringBg = null, mashBg = null;
|
|
|
860 |
CBox nonSslMashBox, nonSslRingBox, sslMashBox, sslRingBox;
|
|
|
861 |
int cBoxSize;
|
|
|
862 |
WindowAdapter uiLstnr = new WindowAdapter() {
|
|
|
863 |
public void windowOpened(WindowEvent e) { log(5, "window opened"); }
|
|
|
864 |
public void windowClosing(WindowEvent e) { closeUI(); }
|
|
|
865 |
public void windowClosed(WindowEvent e) { log(5, "window closed"); synchronized(CS.gui) { CS.gui.notify(); }
|
|
|
866 |
}
|
|
|
867 |
};
|
|
|
868 |
Gui(CS cs) {
|
|
|
869 |
super(cs);
|
|
|
870 |
this.cs = cs;
|
|
|
871 |
debid = cs.debid + " GUI";
|
|
|
872 |
log(5, "start parms panel");
|
|
|
873 |
ui.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
|
|
874 |
ui.addWindowListener(uiLstnr);
|
|
|
875 |
ui.setLocation(600, 100);
|
|
|
876 |
dashboard = ui.getContentPane();
|
|
|
877 |
dashboard.setFont(new Font("SansSerif", Font.PLAIN, 9));
|
|
|
878 |
dashboard.setLayout(new BoxLayout(dashboard, dashboardLayout == HORIZONTAL ? BoxLayout.X_AXIS : BoxLayout.Y_AXIS));
|
|
|
879 |
ui.add(parms = new Parms(!dashboardLayout));
|
|
|
880 |
ui.pack();
|
|
|
881 |
}
|
|
|
882 |
public void run() {
|
|
|
883 |
log(5, "repaint");
|
|
|
884 |
ui.setVisible(true);
|
|
|
885 |
ui.repaint();
|
|
|
886 |
}
|
|
|
887 |
void cboxes() {
|
|
|
888 |
log(5, "create constellation panels");
|
|
|
889 |
cBoxSize = (dashboardLayout == VERTICAL ? dashboard.getSize().width : dashboard.getSize().height)/2 - textHeight;
|
|
|
890 |
ringBg = new CBoxBg(CS.rn);
|
|
|
891 |
mashBg = new CBoxBg(CS.mn);
|
|
|
892 |
if(resultBox != null) dashboard.remove(resultBox);
|
|
|
893 |
dashboard.add(resultBox = new Box(BoxLayout.Y_AXIS));
|
|
|
894 |
if(CS.issl > 0) {
|
|
|
895 |
resultBox.add(sslBox = new CcBox("w/"));
|
|
|
896 |
sslMashBox = sslBox.mashBox;
|
|
|
897 |
sslRingBox = sslBox.ringBox;
|
|
|
898 |
}
|
|
|
899 |
if(CS.issl != 1) {
|
|
|
900 |
resultBox.add(nonSslBox = new CcBox("non"));
|
|
|
901 |
nonSslMashBox = nonSslBox.mashBox;
|
|
|
902 |
nonSslRingBox = nonSslBox.ringBox;
|
|
|
903 |
}
|
|
|
904 |
ui.pack();
|
|
|
905 |
}
|
|
|
906 |
void awake() { synchronized(CS.gui) { CS.gui.notify(); } }
|
|
|
907 |
void dashboardReset() {
|
|
|
908 |
//parms.buttons.setGo();
|
|
|
909 |
parms.buttons.enableStep(true);
|
|
|
910 |
}
|
|
|
911 |
void closeUI() {
|
|
|
912 |
log(5, "closing window");
|
|
|
913 |
CS.isGui = false; CS.isRun = false; CS.go = true; awake();
|
|
|
914 |
}
|
|
|
915 |
}
|
|
|
916 |
public class CS extends Debug {
|
|
|
917 |
volatile static int
|
|
|
918 |
connCnt = 0,
|
|
|
919 |
forwCnt = 0,
|
|
|
920 |
notFinished = 0,
|
|
|
921 |
spawned = 0;
|
|
|
922 |
volatile static boolean abend = false;
|
|
|
923 |
static String text = "bla bla";
|
|
|
924 |
static String clsPath;
|
|
|
925 |
static String cePath;
|
|
|
926 |
static final String sslPathSuffP = "../CS";
|
|
|
927 |
static Random r;
|
|
|
928 |
static int
|
|
|
929 |
mn = 0,
|
|
|
930 |
mp0 = 11000,
|
|
|
931 |
rn = 0,
|
|
|
932 |
rp0 = 12000,
|
|
|
933 |
pttl = 3,
|
|
|
934 |
issl = 0,
|
|
|
935 |
connThreshold = 77, // connection retries threshold
|
|
|
936 |
connTO = 99, // connection sleep time in msecs
|
|
|
937 |
selTO = 999, // selection timeout in msecs
|
|
|
938 |
ipace = 0,
|
|
|
939 |
pace = 0,
|
|
|
940 |
rs = 0,
|
|
|
941 |
fake = 0;
|
|
|
942 |
static boolean isGui = false, isRun = true, isReset = false, go = true, pacing = false;
|
|
|
943 |
static ArrayList<Constellation> constls;
|
|
|
944 |
public static Constellation nonSslMashCon, nonSslRingCon, sslMashCon, sslRingCon;
|
|
|
945 |
static Gui gui;
|
|
|
946 |
static Gui.CBox nonSslMashBox, nonSslRingBox, sslMashBox, sslRingBox;
|
|
|
947 |
CS() {
|
|
|
948 |
debid = "client server DEMO";
|
|
|
949 |
getArgs();
|
|
|
950 |
}
|
|
|
951 |
boolean isArg(String a) { return System.getenv(a) != null; }
|
|
|
952 |
int getArgI(String a) throws Exception {
|
|
|
953 |
int i = -1;
|
|
|
954 |
if(System.getenv(a) != null)
|
|
|
955 |
if(!System.getenv(a).equals(""))
|
|
|
956 |
try { i = Integer.valueOf(System.getenv(a));
|
|
|
957 |
} catch(NumberFormatException x) { throw new Exception(a + "=\terror in number format"); }
|
|
|
958 |
return i;
|
|
|
959 |
}
|
|
|
960 |
double getArgF(String a) throws Exception {
|
|
|
961 |
double d = -1;
|
|
|
962 |
if(System.getenv(a) != null)
|
|
|
963 |
if(!System.getenv(a).equals(""))
|
|
|
964 |
try { d = Double.valueOf(System.getenv(a));
|
|
|
965 |
} catch(NumberFormatException x) { throw new Exception(a + "=\terror in number format"); }
|
|
|
966 |
return d;
|
|
|
967 |
}
|
|
|
968 |
int getMArg(String a) throws Exception {
|
|
|
969 |
int i;
|
|
|
970 |
if((i = getArgI(a)) == 0) throw new Exception(a + " is mandatory");
|
|
|
971 |
return i;
|
|
|
972 |
}
|
|
|
973 |
void getArgs() {
|
|
|
974 |
try {
|
|
|
975 |
clsPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
|
|
|
976 |
if(getArgI("DEB") >= 0) debug = getArgI("DEB");
|
|
|
977 |
if(System.getenv("T") != null) text = System.getenv("T");
|
|
|
978 |
if(getArgI("TTL") > 0) pttl = getArgI("TTL");
|
|
|
979 |
if(getArgF("P") >= 0) ipace = (int)(getArgF("P") * 1000);
|
|
|
980 |
if(getArgI("MP0") > 0) mp0 = getArgI("MP0");
|
|
|
981 |
if(getArgI("RP0") > 0) rp0 = getArgI("RP0");
|
|
|
982 |
if(getArgI("N") >= 0) { mn = getArgI("N"); rn = mn; }
|
|
|
983 |
if(getArgI("SSL") >= 0) issl = getArgI("SSL");
|
|
|
984 |
if(System.getenv("CEP") != null) cePath = System.getenv("CEP");
|
|
|
985 |
else cePath = clsPath + sslPathSuffP;
|
|
|
986 |
if(getArgI("MN") >= 0) mn = getArgI("MN");
|
|
|
987 |
if(getArgI("RN") >= 0) rn = getArgI("RN");
|
|
|
988 |
if(getArgF("STO") >= 0) selTO = (int)(getArgF("STO") * 1000);
|
|
|
989 |
if(getArgI("FAKE") >= 0) fake = getArgI("FAKE");
|
|
|
990 |
if(isArg("RS")) rs = getArgI("RS");
|
|
|
991 |
if(isArg("G")) isGui = getArgI("G") == 1;
|
|
|
992 |
} catch(Exception x) { log(0, x.getMessage()); return; }
|
|
|
993 |
}
|
|
|
994 |
void dashboard() {
|
|
|
995 |
gui = new Gui(this);
|
|
|
996 |
log(4, "wait for args from GUI");
|
|
|
997 |
synchronized(gui) {
|
|
|
998 |
try { SwingUtilities.invokeAndWait(gui); } catch(Exception x) { throw new Error(x); }
|
|
|
999 |
try { gui.wait(); } catch(InterruptedException x) {}
|
|
|
1000 |
}
|
|
|
1001 |
if(isGui) cboxes();
|
|
|
1002 |
}
|
|
|
1003 |
void cboxes() {
|
|
|
1004 |
log(4, "cboxes");
|
|
|
1005 |
try { gui.cboxes(); } catch(Exception x) { log(0, x.getMessage()); }
|
|
|
1006 |
try { SwingUtilities.invokeAndWait(gui); } catch(Exception x) { throw new Error(x); }
|
|
|
1007 |
nonSslMashBox = gui.nonSslMashBox;
|
|
|
1008 |
nonSslRingBox = gui.nonSslRingBox;
|
|
|
1009 |
sslMashBox = gui.sslMashBox;
|
|
|
1010 |
sslRingBox = gui.sslRingBox;
|
|
|
1011 |
|
|
|
1012 |
}
|
|
|
1013 |
void constellations() {
|
|
|
1014 |
pace = ipace;
|
|
|
1015 |
spawned = 0; notFinished = 0;
|
|
|
1016 |
constls = new ArrayList<Constellation>();
|
|
|
1017 |
if(mn == 1) log(0, "one-node MASH configuration not implemented");
|
|
|
1018 |
if(mn > 1) {
|
|
|
1019 |
if(issl > 0) { sslMashCon = new Constellation(this, sslMashBox, true, true); constls.add(sslMashCon); }
|
|
|
1020 |
if(issl != 1) { nonSslMashCon = new Constellation(this, nonSslMashBox, true, false); constls.add(nonSslMashCon); }
|
|
|
1021 |
}
|
|
|
1022 |
if(rn == 1) log(0, "one-node RING configuration not implemented");
|
|
|
1023 |
if(rn > 1) {
|
|
|
1024 |
if(issl > 0) { sslRingCon = new Constellation(this, sslRingBox, false, true); constls.add(sslRingCon); }
|
|
|
1025 |
if(issl != 1) { nonSslRingCon = new Constellation(this, nonSslRingBox, false, false); constls.add(nonSslRingCon); }
|
|
|
1026 |
}
|
|
|
1027 |
}
|
|
|
1028 |
void stop() {
|
|
|
1029 |
if(sslMashCon != null) sslMashCon.stop();
|
|
|
1030 |
if(sslRingCon != null) sslRingCon.stop();
|
|
|
1031 |
if(nonSslMashCon != null) nonSslMashCon.stop();
|
|
|
1032 |
if(nonSslRingCon != null) nonSslRingCon.stop();
|
|
|
1033 |
pacing = false;
|
|
|
1034 |
pace = 0;
|
|
|
1035 |
go = true;
|
|
|
1036 |
}
|
|
|
1037 |
void reset() {
|
|
|
1038 |
gui.dashboardReset();
|
|
|
1039 |
cboxes();
|
|
|
1040 |
mp0 += mn; rp0 += rn; // port is unusable 30 secs after port close due to special timeout
|
|
|
1041 |
constellations();
|
|
|
1042 |
isReset = false;
|
|
|
1043 |
}
|
|
|
1044 |
String switches(String label) {
|
|
|
1045 |
return label + ": isGui=" + isGui + ", isRun=" + isRun + ", go=" + go + ", pacing=" + pacing + ", spawned=" + spawned;
|
|
|
1046 |
}
|
|
|
1047 |
void pacingGo() { for(Constellation con : constls) con.glob.pacingGo = true; }
|
|
|
1048 |
void runGuiCon() {
|
|
|
1049 |
synchronized(constls) {
|
|
|
1050 |
while(isGui && isRun && spawned > 0) {
|
|
|
1051 |
log(4, switches("runCons constls.wait"));
|
|
|
1052 |
try { constls.wait(); } catch(InterruptedException x) {}
|
|
|
1053 |
pacingGo();
|
|
|
1054 |
log(4, switches("runCons constls.paint"));
|
|
|
1055 |
if(!isGui) break;
|
|
|
1056 |
try { SwingUtilities.invokeAndWait(CS.gui); } catch(Exception x) { throw new Error(x); }
|
|
|
1057 |
if(!isGui || !isRun) break;
|
|
|
1058 |
if(!go) {
|
|
|
1059 |
log(4, switches("runCons constls.gui.wait"));
|
|
|
1060 |
synchronized(gui) { try { gui.wait(); } catch(InterruptedException x) {} }
|
|
|
1061 |
}
|
|
|
1062 |
if(!isGui || !isRun) break;
|
|
|
1063 |
log(4, switches("runCons constls.notifyAll"));
|
|
|
1064 |
constls.notifyAll();
|
|
|
1065 |
}
|
|
|
1066 |
}
|
|
|
1067 |
if(isGui && isRun) {
|
|
|
1068 |
log(4, switches("runCons last repaint"));
|
|
|
1069 |
try { SwingUtilities.invokeAndWait(CS.gui); } catch(Exception x) { throw new Error(x); }
|
|
|
1070 |
if(!go) synchronized(gui) { try { gui.wait(); } catch(InterruptedException x) {} }
|
|
|
1071 |
}
|
|
|
1072 |
else {
|
|
|
1073 |
log(4, switches("runCons stop"));
|
|
|
1074 |
stop();
|
|
|
1075 |
synchronized(constls) { constls.notifyAll(); }
|
|
|
1076 |
while(spawned > 0) synchronized(this) { try { wait(); } catch(InterruptedException x) {} }
|
|
|
1077 |
}
|
|
|
1078 |
}
|
|
|
1079 |
void runCons() {
|
|
|
1080 |
if(isGui) pacing = true;
|
|
|
1081 |
else pacing = false;
|
|
|
1082 |
for(Constellation con : constls) { notFinished++; new Thread(con, con.label).start(); spawned++; }
|
|
|
1083 |
if(isGui) runGuiCon();
|
|
|
1084 |
else while(spawned > 0) synchronized(this) { try { wait(); } catch(InterruptedException x) {} }
|
|
|
1085 |
}
|
|
|
1086 |
public void run() {
|
|
|
1087 |
if(isGui) dashboard();
|
|
|
1088 |
if(isRun) {
|
|
|
1089 |
log(1, "pgm=" + clsPath + getClass().getName() +
|
|
|
1090 |
", ttl=" + pttl + ", pace=" + ipace + "msecs, seed=" + rs + ", SSL=" + issl + ", fake=" + fake + ", debug=" + debug);
|
|
|
1091 |
if(issl > 0) log(3, "cePath=" + cePath);
|
|
|
1092 |
constellations();
|
|
|
1093 |
if(!isGui) { r = new Random(rs); runCons(); }
|
|
|
1094 |
else while(isGui) {
|
|
|
1095 |
r = new Random(rs);
|
|
|
1096 |
runCons();
|
|
|
1097 |
log(1, "all constellations finished");
|
|
|
1098 |
if(!isGui) break;
|
|
|
1099 |
gui.parms.buttons.setGo();
|
|
|
1100 |
if(!go) gui.parms.buttons.step.setEnabled(false);
|
|
|
1101 |
if(abend) {
|
|
|
1102 |
gui.parms.buttons.go.setEnabled(false);
|
|
|
1103 |
gui.parms.buttons.step.setEnabled(false);
|
|
|
1104 |
gui.parms.buttons.reset.setEnabled(false);
|
|
|
1105 |
}
|
|
|
1106 |
try { SwingUtilities.invokeAndWait(gui); } catch(Exception x) { throw new Error(x); }
|
|
|
1107 |
if(!isReset) synchronized(gui) { try { gui.wait(); } catch(InterruptedException x) {} }
|
|
|
1108 |
if(isGui) {
|
|
|
1109 |
reset();
|
|
|
1110 |
do synchronized(gui) {
|
|
|
1111 |
try { SwingUtilities.invokeAndWait(gui); } catch(Exception x) { throw new Error(x); }
|
|
|
1112 |
if(!isRun) try { gui.wait(); } catch(InterruptedException x) {}
|
|
|
1113 |
if(isGui && isReset) reset();
|
|
|
1114 |
} while(isGui && !isRun);
|
|
|
1115 |
}
|
|
|
1116 |
}
|
|
|
1117 |
}
|
|
|
1118 |
log(1, "final balance, connections=" + connCnt + ", forwards=" + forwCnt);
|
|
|
1119 |
if(gui != null) gui.ui.dispose();
|
|
|
1120 |
log(2, "run end");
|
|
|
1121 |
}
|
|
|
1122 |
public static void main(String[] args) throws Exception {
|
|
|
1123 |
CS cs = new CS();
|
|
|
1124 |
cs.run();
|
|
|
1125 |
cs.log(1, "cs end");
|
|
|
1126 |
//try { cs.run(); } catch(Exception x) { cs.log(0, "interrupted execution"); };
|
|
|
1127 |
}
|
|
|
1128 |
}
|
|
|
1129 |
// rozeznání konce ve step-módu
|
|
|
1130 |
// pacing slide
|
|
|
1131 |
// input fields
|
|
|
1132 |
// ukládání parametrů
|
|
|
1133 |
// too many open files
|
|
|
1134 |
// exceptions
|
|
|
1135 |
// stavové zprávy na dashboardu |