82 |
|
*/ |
83 |
|
public static final int QUIT = 5; |
84 |
|
|
85 |
+ |
/** |
86 |
+ |
* This is the time in seconds that this class |
87 |
+ |
* should wait on the DataReader class to fully |
88 |
+ |
* shutdown after calling shutdown() before |
89 |
+ |
* forcing a shutdown |
90 |
+ |
*/ |
91 |
+ |
public static final int DATAREADER_SHUTDOWN_TIMEOUT = 5; |
92 |
+ |
|
93 |
|
//---STATIC METHODS--- |
94 |
|
|
95 |
|
//---CONSTRUCTORS--- |
129 |
|
try { |
130 |
|
action = ((Integer) _actionQueue.get(_myQueue)).intValue(); |
131 |
|
} catch (InvalidQueueException e) { |
132 |
< |
// we 're never going to get this... |
132 |
> |
// we 're never going to get this |
133 |
> |
// but if we do we should do something nasty |
134 |
> |
throw new RuntimeException("unable to retrieve events from actionQueue!"); |
135 |
|
} |
136 |
|
|
137 |
|
// examine our action... |
138 |
|
// if it was to connect...then we connect... |
139 |
|
switch(action) { |
140 |
|
case CONNECT: |
141 |
< |
|
142 |
< |
Object serverQuestion = null; |
143 |
< |
serverQuestion = JOptionPane.showInputDialog(null, "Please enter the name of a server running the I-Scream client interface:", "I-Scream Server", JOptionPane.INFORMATION_MESSAGE); |
144 |
< |
if (serverQuestion instanceof String) { |
145 |
< |
_server = (String) serverQuestion; |
146 |
< |
Conient.setControlStatus("Connecting to - " + _server); |
147 |
< |
try { |
148 |
< |
_controlLink = new Socket(_server, _port); |
149 |
< |
_inBound = new BufferedReader(new InputStreamReader(_controlLink.getInputStream())); |
150 |
< |
_outBound = new PrintWriter(_controlLink.getOutputStream()); |
151 |
< |
Conient.setControlStatus("Connection Established - " + _server); |
152 |
< |
String response; |
153 |
< |
response = _inBound.readLine(); |
154 |
< |
if (!(Double.parseDouble(response.substring(10, response.length())) > PROTOCOL_VERSION)) { |
155 |
< |
Conient.addMessage("WARNING: server is using a newer protocol (" + response + "), please update your client, continuing with old protocol (PROTOCOL " + PROTOCOL_VERSION + ")" ); |
156 |
< |
} else if (!(Double.parseDouble(response.substring(10, response.length())) < PROTOCOL_VERSION)) { |
157 |
< |
throw new IOException("invalid protocol version"); |
141 |
> |
if (_controlLink == null) { |
142 |
> |
// get the server name |
143 |
> |
Object serverQuestion = null; |
144 |
> |
serverQuestion = JOptionPane.showInputDialog(null, "Please enter the name of a server running the I-Scream client interface:", "I-Scream Server", JOptionPane.INFORMATION_MESSAGE); |
145 |
> |
if (serverQuestion instanceof String) { |
146 |
> |
_server = (String) serverQuestion; |
147 |
> |
Conient.setControlStatus("Connecting to - " + _server); |
148 |
> |
try { |
149 |
> |
// open the socket to the server and bind the IO |
150 |
> |
_controlLink = new Socket(_server, _port); |
151 |
> |
_inBound = new BufferedReader(new InputStreamReader(_controlLink.getInputStream())); |
152 |
> |
_outBound = new PrintWriter(_controlLink.getOutputStream()); |
153 |
> |
Conient.setControlStatus("Connection Established - " + _server); |
154 |
> |
|
155 |
> |
String response; |
156 |
> |
response = _inBound.readLine(); |
157 |
> |
|
158 |
> |
// check the servers Protocol Identity against our own |
159 |
> |
// we SHOULD be backwards compatible, so we can continue if |
160 |
> |
// they are using a newer protocol, anything else then we die |
161 |
> |
if (!(Double.parseDouble(response.substring(10, response.length())) > PROTOCOL_VERSION)) { |
162 |
> |
Conient.addMessage("WARNING{control link}: server is using a newer protocol (" + response + "), please update your client, continuing with old protocol (PROTOCOL " + PROTOCOL_VERSION + ")" ); |
163 |
> |
} else if (!(Double.parseDouble(response.substring(10, response.length())) < PROTOCOL_VERSION)) { |
164 |
> |
// tidy up |
165 |
> |
throw new IOException("incompatible protocol version"); |
166 |
> |
} |
167 |
> |
|
168 |
> |
// send the name of the client |
169 |
> |
_outBound.println(_clientName); |
170 |
> |
_outBound.flush(); |
171 |
> |
response = _inBound.readLine(); |
172 |
> |
if (!response.equals("OK")) { |
173 |
> |
// tidy up |
174 |
> |
|
175 |
> |
throw new IOException("client name rejected - " + _clientName); |
176 |
> |
} |
177 |
> |
} catch (IOException e) { |
178 |
> |
// print the error and tidy up what's left |
179 |
> |
Conient.addMessage("ERROR{control link}: " + e); |
180 |
> |
_controlLink = null; |
181 |
> |
Conient.setControlStatus("Disconnected"); |
182 |
|
} |
149 |
– |
Conient.addMessage("Handshake Success"); |
150 |
– |
|
151 |
– |
// send the name - get from somewhere eventually |
152 |
– |
_outBound.println(_clientName); |
153 |
– |
_outBound.flush(); |
154 |
– |
response = _inBound.readLine(); |
155 |
– |
if (!response.equals("OK")) { |
156 |
– |
throw new IOException("client name rejected - " + response); |
157 |
– |
} |
158 |
– |
Conient.addMessage("Control Link Established"); |
159 |
– |
|
160 |
– |
} catch (IOException e) { |
161 |
– |
Conient.addMessage("Control Link Error: " + e); |
162 |
– |
Conient.setControlStatus("Disconnected"); |
183 |
|
} |
184 |
+ |
} else { |
185 |
+ |
Conient.addMessage("WARNING{control link}: already established"); |
186 |
|
} |
187 |
|
break; |
188 |
|
case STARTDATA: |
189 |
< |
Conient.addMessage("Attempting to open Data Channel"); |
190 |
< |
try { |
189 |
> |
// as long as the data link hasn't been established |
190 |
> |
// we want to establish it |
191 |
> |
if (_dataLink == null) { |
192 |
> |
// check that the control link is open, if it isn't we |
193 |
> |
// might want to sort that problemo out |
194 |
> |
// we do this by simply queueing the event to occour, then |
195 |
> |
// this event to run again ;-) |
196 |
|
if(_controlLink == null) { |
197 |
+ |
Conient.addMessage("WARNING{data link}: control link not established - queueing start events"); |
198 |
|
_actionQueue.add(new Integer(CONNECT)); |
199 |
|
_actionQueue.add(new Integer(STARTDATA)); |
200 |
< |
throw new IOException("Control Link not establised - queueing start events"); |
200 |
> |
} else { |
201 |
> |
try { |
202 |
> |
|
203 |
> |
// ask the server to start the data link |
204 |
> |
String response; |
205 |
> |
_outBound.println("STARTDATA"); |
206 |
> |
_outBound.flush(); |
207 |
> |
response = _inBound.readLine(); |
208 |
> |
// TEMPORARY FIREWALL FIX |
209 |
> |
// allows user to map an ssh pipe... |
210 |
> |
JOptionPane.showMessageDialog(null, "WARNING: about to connect to a port you may not have available!\nPlease ensure you have port \"" + response + "\" of your I-Scream server mapped to " + _server, "FIREWALL WARNING!", JOptionPane.INFORMATION_MESSAGE); |
211 |
> |
Conient.setDataStatus("Connecting to - " + _server + ":" + response); |
212 |
> |
|
213 |
> |
// see if the server suggested a good port |
214 |
> |
if (response.equals("ERROR")) { |
215 |
> |
throw new IOException("server unable to start data link at this time"); |
216 |
> |
} |
217 |
> |
try { |
218 |
> |
_dataLink = new Socket(_server, Integer.parseInt(response)); |
219 |
> |
} catch (NumberFormatException e) { |
220 |
> |
throw new IOException("invalid data port suggested by server - " + response); |
221 |
> |
} |
222 |
> |
|
223 |
> |
response = _inBound.readLine(); |
224 |
> |
if (!response.equals("OK")) { |
225 |
> |
throw new IOException("server reported error establishing data channel"); |
226 |
> |
} |
227 |
> |
|
228 |
> |
// if the socket was ok, then we attack our IO hooks |
229 |
> |
_dataInBound = new BufferedReader(new InputStreamReader(_dataLink.getInputStream())); |
230 |
> |
_dataOutBound = new PrintWriter(_dataLink.getOutputStream()); |
231 |
> |
Conient.setDataStatus("Connection Established - " + _server); |
232 |
> |
} catch (IOException e) { |
233 |
> |
// print the error and tidy up what's left |
234 |
> |
Conient.addMessage("ERROR{data link}: " + e); |
235 |
> |
_dataLink = null; |
236 |
> |
Conient.setDataStatus("Disconnected"); |
237 |
> |
} |
238 |
> |
// now we want to start reading the data in |
239 |
> |
// so we start the appropriate components on their way |
240 |
> |
// we create a queue to give to both the reader and the |
241 |
> |
// displayer |
242 |
> |
Queue theQueue = new Queue(); |
243 |
> |
_dataReader = new DataReader(_dataInBound, theQueue); |
244 |
> |
_data.setQueue(theQueue); |
245 |
> |
_data.cleanUpTabs(); |
246 |
> |
|
247 |
> |
// start the data rocking |
248 |
> |
new Thread(_data).start(); |
249 |
> |
_dataReader.start(); |
250 |
> |
// finished for us.... |
251 |
|
} |
252 |
< |
String response; |
253 |
< |
_outBound.println("STARTDATA"); |
176 |
< |
_outBound.flush(); |
177 |
< |
response = _inBound.readLine(); |
178 |
< |
|
179 |
< |
// TEMPORARY FIREWALL FIX |
180 |
< |
// allows user to map an ssh pipe... |
181 |
< |
JOptionPane.showMessageDialog(null, "WARNING: about to connect to a port you may not have available!\nPlease ensure you have port \"" + response + "\" of your I-Scream server mapped to " + _server, "FIREWALL WARNING!", JOptionPane.INFORMATION_MESSAGE); |
182 |
< |
Conient.setDataStatus("Connecting to - " + _server + ":" + response); |
183 |
< |
try { |
184 |
< |
_dataLink = new Socket(_server, Integer.parseInt(response)); |
185 |
< |
} catch (NumberFormatException e) { |
186 |
< |
throw new IOException("error, invalid data port suggested by server - " + response); |
187 |
< |
} |
188 |
< |
|
189 |
< |
response = _inBound.readLine(); |
190 |
< |
if (!response.equals("OK")) { |
191 |
< |
throw new IOException("server reported error establishing data channel - " + response); |
192 |
< |
} |
193 |
< |
_dataInBound = new BufferedReader(new InputStreamReader(_dataLink.getInputStream())); |
194 |
< |
_dataOutBound = new PrintWriter(_dataLink.getOutputStream()); |
195 |
< |
Conient.setDataStatus("Connection Established - " + _server); |
196 |
< |
Conient.addMessage("Data Link connection established"); |
197 |
< |
Conient.addMessage("Starting data reader"); |
198 |
< |
|
199 |
< |
// here we will do some connect stuff. |
200 |
< |
Queue theQueue = new Queue(); |
201 |
< |
_dataReader = new DataReader(_dataInBound, theQueue); |
202 |
< |
_data.setQueue(theQueue); |
203 |
< |
_data.cleanUpTabs(); |
204 |
< |
new Thread(_data).start(); |
205 |
< |
_dataReader.start(); |
206 |
< |
// finished for us.... |
207 |
< |
} catch (IOException e) { |
208 |
< |
Conient.addMessage("Data Link Error: " + e); |
209 |
< |
Conient.setDataStatus("Disconnected"); |
252 |
> |
} else { |
253 |
> |
Conient.addMessage("WARNING{data link}: already established"); |
254 |
|
} |
255 |
|
break; |
256 |
|
case STOPDATA: |
257 |
< |
Conient.addMessage("Attempting to close Data Channel"); |
258 |
< |
try { |
259 |
< |
String response; |
260 |
< |
_outBound.println("STOPDATA"); |
261 |
< |
_outBound.flush(); |
262 |
< |
response = _inBound.readLine(); |
263 |
< |
if (!response.equals("OK")) { |
264 |
< |
throw new IOException("server didn't OK request to stop data channel"); |
257 |
> |
if(_dataLink != null) { |
258 |
> |
try { |
259 |
> |
String response; |
260 |
> |
// shut down the data link |
261 |
> |
Conient.setDataStatus("Disconnecting - " + _server); |
262 |
> |
|
263 |
> |
// close the reader |
264 |
> |
_dataReader.shutdown(); |
265 |
> |
// wait for it to close |
266 |
> |
boolean dirtyShutdown = true; |
267 |
> |
long startTime = System.currentTimeMillis(); |
268 |
> |
while((System.currentTimeMillis() - startTime) < (DATAREADER_SHUTDOWN_TIMEOUT * 1000)) { |
269 |
> |
if (!_dataReader.isAlive()) { |
270 |
> |
dirtyShutdown = false; |
271 |
> |
break; |
272 |
> |
} |
273 |
> |
} |
274 |
> |
// warn if it didn't shutdown in time |
275 |
> |
if (dirtyShutdown) { |
276 |
> |
Conient.addMessage("WARNING{data link}: data reader thread did not close within timeout, killing its IO anyway!"); |
277 |
> |
} |
278 |
> |
|
279 |
> |
// tell the server |
280 |
> |
_outBound.println("STOPDATA"); |
281 |
> |
_outBound.flush(); |
282 |
> |
response = _inBound.readLine(); |
283 |
> |
|
284 |
> |
// check the server was ok with our request... |
285 |
> |
// even if it wasn't we will go anyway! |
286 |
> |
if (!response.equals("OK")) { |
287 |
> |
throw new IOException("server didn't OK request to stop data channel - stopping anyway"); |
288 |
> |
} |
289 |
> |
|
290 |
> |
|
291 |
> |
// close the lot down |
292 |
> |
_dataInBound.close(); |
293 |
> |
_dataOutBound.close(); |
294 |
> |
_dataLink.close(); |
295 |
> |
// get rid of the socket |
296 |
> |
_dataLink = null; |
297 |
> |
Conient.setDataStatus("Disconnected"); |
298 |
> |
} catch (IOException e) { |
299 |
> |
// print the error and tidy up what's left |
300 |
> |
Conient.addMessage("ERROR{data link}: " + e); |
301 |
> |
try { |
302 |
> |
_dataOutBound.close(); |
303 |
> |
_dataInBound.close(); |
304 |
> |
_dataLink.close(); |
305 |
> |
} catch (IOException e2) { |
306 |
> |
Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2); |
307 |
> |
} |
308 |
> |
_dataLink = null; |
309 |
> |
Conient.setDataStatus("Disconnected"); |
310 |
|
} |
311 |
< |
// kill the data reader - we should wait |
312 |
< |
// for it to die nicely...but we won't yet...we'll kill the socket! ;-p |
224 |
< |
Conient.setDataStatus("Disconnecting - " + _server); |
225 |
< |
_dataReader.shutdown(); |
226 |
< |
_dataInBound.close(); |
227 |
< |
_dataOutBound.close(); |
228 |
< |
_dataLink.close(); |
229 |
< |
// get rid of the socket |
230 |
< |
_dataLink = null; |
231 |
< |
Conient.setDataStatus("Disconnected"); |
232 |
< |
Conient.addMessage("Data Channel closed"); |
233 |
< |
} catch (IOException e) { |
234 |
< |
Conient.addMessage("Data Link Error: " + e); |
235 |
< |
Conient.setDataStatus("Unknown"); |
311 |
> |
} else { |
312 |
> |
Conient.addMessage("WARNING{data link}: already disconnected"); |
313 |
|
} |
314 |
|
break; |
315 |
|
case DISCONNECT: |
316 |
< |
Conient.addMessage("Attempting to close Control Channel"); |
240 |
< |
try { |
316 |
> |
if (_controlLink != null) { |
317 |
|
if (_dataLink != null) { |
318 |
< |
// we want to tell ourselves to stop it |
319 |
< |
_actionQueue.add(new Integer(STOPDATA)); |
320 |
< |
_actionQueue.add(new Integer(DISCONNECT)); |
321 |
< |
throw new IOException("Warning - Data Channel not closed - attempting to close it!"); |
318 |
> |
// we want to tell ourselves to stop it |
319 |
> |
Conient.addMessage("WARNING{control link}: data link not disconnected - queueing stop events"); |
320 |
> |
_actionQueue.add(new Integer(STOPDATA)); |
321 |
> |
_actionQueue.add(new Integer(DISCONNECT)); |
322 |
> |
} else { |
323 |
> |
try { |
324 |
> |
// request the server to disconnect |
325 |
> |
String response; |
326 |
> |
_outBound.println("DISCONNECT"); |
327 |
> |
_outBound.flush(); |
328 |
> |
response = _inBound.readLine(); |
329 |
> |
|
330 |
> |
// check the server was ok with our request... |
331 |
> |
// even if it wasn't we will go anyway! |
332 |
> |
if (!response.equals("OK")) { |
333 |
> |
throw new IOException("server didn't OK request to stop control channel - stopping anyway"); |
334 |
> |
} |
335 |
> |
|
336 |
> |
// then lets shutdown the link |
337 |
> |
Conient.setControlStatus("Disconnecting - " + _server); |
338 |
> |
_inBound.close(); |
339 |
> |
_outBound.close(); |
340 |
> |
_controlLink.close(); |
341 |
> |
// for good measure |
342 |
> |
_controlLink = null; |
343 |
> |
Conient.setControlStatus("Disconnected"); |
344 |
> |
} catch (IOException e) { |
345 |
> |
Conient.addMessage("Control Link Error: " + e); |
346 |
> |
try { |
347 |
> |
_inBound.close(); |
348 |
> |
_outBound.close(); |
349 |
> |
_controlLink.close(); |
350 |
> |
} catch (IOException e2) { |
351 |
> |
Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2); |
352 |
> |
} |
353 |
> |
_controlLink = null; |
354 |
> |
Conient.setControlStatus("Disconnected"); |
355 |
> |
} |
356 |
|
} |
357 |
< |
String response; |
358 |
< |
_outBound.println("DISCONNECT"); |
249 |
< |
_outBound.flush(); |
250 |
< |
response = _inBound.readLine(); |
251 |
< |
if (!response.equals("OK")) { |
252 |
< |
throw new IOException("server didn't OK request to stop control channel"); |
253 |
< |
} |
254 |
< |
// then lets go! |
255 |
< |
Conient.setControlStatus("Disconnecting - " + _server); |
256 |
< |
_inBound.close(); |
257 |
< |
_outBound.close(); |
258 |
< |
_controlLink.close(); |
259 |
< |
// for good measure |
260 |
< |
_controlLink = null; |
261 |
< |
Conient.setControlStatus("Disconnected"); |
262 |
< |
} catch (IOException e) { |
263 |
< |
Conient.addMessage("Control Link Error: " + e); |
264 |
< |
Conient.setControlStatus("Unknown"); |
357 |
> |
} else { |
358 |
> |
Conient.addMessage("WARNING{control link}: already disconnected"); |
359 |
|
} |
360 |
|
break; |
361 |
|
case QUIT: |
362 |
< |
Conient.addMessage("Exiting..."); |
362 |
> |
Conient.addMessage("Exiting."); |
363 |
|
try { |
364 |
|
// stop data and control if data up |
365 |
|
if (_dataLink != null) { |
378 |
|
// go! |
379 |
|
System.exit(0); |
380 |
|
} catch (IOException e) { |
381 |
< |
Conient.addMessage("Closing connections..."); |
381 |
> |
Conient.addMessage("WARNING: open connections detected - queueing stop events"); |
382 |
|
} |
383 |
|
break; |
384 |
+ |
|
385 |
|
} |
386 |
|
} |
387 |
|
} |
388 |
|
|
389 |
+ |
/** |
390 |
+ |
* This method allows other classes |
391 |
+ |
* to shutdown this connection handler. |
392 |
+ |
*/ |
393 |
+ |
public void shutdown() { |
394 |
+ |
_running = false; |
395 |
+ |
} |
396 |
+ |
|
397 |
|
//---PRIVATE METHODS--- |
398 |
|
|
399 |
|
//---ACCESSOR/MUTATOR METHODS--- |
400 |
|
|
401 |
|
//---ATTRIBUTES--- |
402 |
|
|
403 |
+ |
/** |
404 |
+ |
* The state if this thread |
405 |
+ |
*/ |
406 |
|
boolean _running = true; |
407 |
< |
Conient Conient; |
407 |
> |
|
408 |
> |
/** |
409 |
> |
* A reference to the displaying class DataPanel |
410 |
> |
*/ |
411 |
|
DataPanel _data; |
412 |
+ |
|
413 |
+ |
/** |
414 |
+ |
* The queue that actions are added to by other parts of the system |
415 |
+ |
*/ |
416 |
|
Queue _actionQueue; |
417 |
+ |
|
418 |
+ |
/** |
419 |
+ |
* The queue number that we are reading from on the action queue |
420 |
+ |
*/ |
421 |
|
int _myQueue; |
422 |
+ |
|
423 |
+ |
/** |
424 |
+ |
* The FQDN of the i-scream server we are connecting to |
425 |
+ |
*/ |
426 |
|
String _server; |
427 |
+ |
|
428 |
+ |
/** |
429 |
+ |
* The port that is running the client interface on the i-scream server |
430 |
+ |
*/ |
431 |
|
int _port = Conient.PORT; |
432 |
+ |
|
433 |
+ |
/** |
434 |
+ |
* The control link socket |
435 |
+ |
*/ |
436 |
|
Socket _controlLink; |
437 |
+ |
|
438 |
+ |
/** |
439 |
+ |
* The data link socket |
440 |
+ |
*/ |
441 |
|
Socket _dataLink; |
442 |
+ |
|
443 |
+ |
/** |
444 |
+ |
* The input for the control link |
445 |
+ |
*/ |
446 |
|
BufferedReader _inBound; |
447 |
+ |
|
448 |
+ |
/** |
449 |
+ |
* The output for the control link |
450 |
+ |
*/ |
451 |
|
PrintWriter _outBound; |
452 |
+ |
|
453 |
+ |
/** |
454 |
+ |
* The input for the data link |
455 |
+ |
*/ |
456 |
|
BufferedReader _dataInBound; |
457 |
+ |
|
458 |
+ |
/** |
459 |
+ |
* The output for the data link |
460 |
+ |
*/ |
461 |
|
PrintWriter _dataOutBound; |
462 |
+ |
|
463 |
+ |
/** |
464 |
+ |
* A reference to the DataReader in use |
465 |
+ |
*/ |
466 |
|
DataReader _dataReader; |
467 |
+ |
|
468 |
+ |
/** |
469 |
+ |
* The friendly identifier of this client |
470 |
+ |
* that is sent to the server |
471 |
+ |
*/ |
472 |
|
String _clientName = "Conient"; |
473 |
|
|
474 |
|
//---STATIC ATTRIBUTES--- |