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