1 |
tdb |
1.34 |
/* |
2 |
|
|
* i-scream central monitoring system |
3 |
tdb |
1.37 |
* http://www.i-scream.org |
4 |
tdb |
1.34 |
* Copyright (C) 2000-2002 i-scream |
5 |
|
|
* |
6 |
|
|
* This program is free software; you can redistribute it and/or |
7 |
|
|
* modify it under the terms of the GNU General Public License |
8 |
|
|
* as published by the Free Software Foundation; either version 2 |
9 |
|
|
* of the License, or (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 |
|
|
*/ |
20 |
|
|
|
21 |
ajm |
1.6 |
//---PACKAGE DECLARATION--- |
22 |
tdb |
1.33 |
package uk.org.iscream.cms.conient; |
23 |
ajm |
1.6 |
|
24 |
|
|
//---IMPORTS--- |
25 |
tdb |
1.36 |
import uk.org.iscream.cms.util.*; |
26 |
ajm |
1.2 |
import java.io.*; |
27 |
ajm |
1.1 |
import java.net.*; |
28 |
ajm |
1.2 |
import javax.swing.JOptionPane; |
29 |
ajm |
1.1 |
|
30 |
ajm |
1.6 |
/** |
31 |
|
|
* This is the main thread for the client. |
32 |
|
|
* Once started i continually checks it actionQueue |
33 |
|
|
* for actions that other areas of the system have placed |
34 |
|
|
* there, it then performs those actions. |
35 |
|
|
* |
36 |
|
|
* Currently this is the main thread where all non-GUI events |
37 |
|
|
* are dispatched to. |
38 |
|
|
* |
39 |
tdb |
1.34 |
* @author $Author: tdb $ |
40 |
tdb |
1.37 |
* @version $Id: ConnectionHandler.java,v 1.36 2003/02/05 19:35:04 tdb Exp $ |
41 |
ajm |
1.6 |
*/ |
42 |
ajm |
1.1 |
public class ConnectionHandler extends Thread { |
43 |
ajm |
1.2 |
|
44 |
ajm |
1.6 |
//---FINAL ATTRIBUTES--- |
45 |
|
|
|
46 |
|
|
/** |
47 |
|
|
* The current CVS revision of this class |
48 |
|
|
*/ |
49 |
tdb |
1.37 |
public final String REVISION = "$Revision: 1.36 $"; |
50 |
ajm |
1.6 |
|
51 |
tdb |
1.7 |
|
52 |
|
|
/** |
53 |
|
|
* The hardcoded protocol version that we are using. |
54 |
|
|
* Used when handshaking with the server |
55 |
|
|
*/ |
56 |
ajm |
1.20 |
public final double PROTOCOL_VERSION = 1.1; |
57 |
ajm |
1.2 |
|
58 |
tdb |
1.7 |
/** |
59 |
|
|
* Thread action DONOTHING. |
60 |
|
|
* This is an invalid action, but here for completeness |
61 |
|
|
* if anything sends this action it will warn appropriately |
62 |
|
|
* but do what it says, ie, nothing ;) |
63 |
|
|
*/ |
64 |
ajm |
1.1 |
public static final int DONOTHING = 0; |
65 |
tdb |
1.7 |
|
66 |
|
|
/** |
67 |
|
|
* Thread action CONNECT. |
68 |
|
|
* Opens the control link to the i-scream server. |
69 |
|
|
*/ |
70 |
ajm |
1.1 |
public static final int CONNECT = 1; |
71 |
tdb |
1.7 |
|
72 |
|
|
/** |
73 |
|
|
* Thread action STARTDATA. |
74 |
|
|
* Opens the data link to the i-scream server |
75 |
|
|
* and prepares all gui data components for data |
76 |
|
|
* it then starts all relavant threads going. |
77 |
|
|
*/ |
78 |
ajm |
1.2 |
public static final int STARTDATA = 2; |
79 |
tdb |
1.7 |
|
80 |
|
|
/** |
81 |
|
|
* Thread action STOPDATA. |
82 |
|
|
* Closes the data link and shuts down all components |
83 |
|
|
* that update gui for various things. |
84 |
|
|
*/ |
85 |
ajm |
1.2 |
public static final int STOPDATA = 3; |
86 |
tdb |
1.7 |
|
87 |
|
|
/** |
88 |
|
|
* Thread action DISCONNECT. |
89 |
|
|
* Checks to see if STOPDATA has been called if not, |
90 |
|
|
* it will add STOPDATA and then DISCONNECT to |
91 |
|
|
* the action queue and return. If STOPDATA has been |
92 |
|
|
* called it closes down the Control Link and tidies up |
93 |
|
|
* all relevant threads |
94 |
|
|
*/ |
95 |
ajm |
1.2 |
public static final int DISCONNECT = 4; |
96 |
tdb |
1.7 |
|
97 |
|
|
/** |
98 |
|
|
* Thread action QUIT. |
99 |
|
|
* Checks the status of the two links, if either |
100 |
|
|
* are still up, it queues the appropriate commands |
101 |
|
|
* to close them down. It then System.exit(0)'s! |
102 |
|
|
*/ |
103 |
ajm |
1.4 |
public static final int QUIT = 5; |
104 |
ajm |
1.6 |
|
105 |
ajm |
1.12 |
/** |
106 |
ajm |
1.14 |
* Thread action GETCONFIGURATION |
107 |
|
|
* Starts the command to obtain the configuration |
108 |
|
|
* from the server. |
109 |
|
|
* It then passes the IO to the Configuration object |
110 |
|
|
* so it can obtain any specific configuration |
111 |
|
|
*/ |
112 |
|
|
public static final int GETCONFIGURATION = 6; |
113 |
|
|
|
114 |
|
|
/** |
115 |
ajm |
1.12 |
* This is the time in seconds that this class |
116 |
|
|
* should wait on the DataReader class to fully |
117 |
|
|
* shutdown after calling shutdown() before |
118 |
|
|
* forcing a shutdown |
119 |
|
|
*/ |
120 |
|
|
public static final int DATAREADER_SHUTDOWN_TIMEOUT = 5; |
121 |
|
|
|
122 |
ajm |
1.13 |
/** |
123 |
|
|
* The default local server to connect to when a |
124 |
|
|
* firewall is in use if one is not specified in the server |
125 |
|
|
*/ |
126 |
|
|
public static final String DEFAULT_FIREWALL_SERVER = "localhost"; |
127 |
|
|
|
128 |
|
|
/** |
129 |
|
|
* The default time in seconds to wait for the |
130 |
|
|
* firewall setup command to execute |
131 |
|
|
*/ |
132 |
|
|
public static final int DEFAULT_FIREWALL_COMMANDWAIT = 5; |
133 |
ajm |
1.29 |
|
134 |
|
|
/** |
135 |
|
|
* The default maximum queue size in use for the data queue |
136 |
|
|
*/ |
137 |
|
|
public static final int DEFAULT_QUEUE_LIMIT = 500; |
138 |
|
|
|
139 |
|
|
/** |
140 |
|
|
* The algorithm we use to remove items from the queue |
141 |
|
|
* if it reaches its maximum size. |
142 |
|
|
* |
143 |
tdb |
1.36 |
* We use a FIFO algorithm, see the uk.org.iscream.cms.util.Queue |
144 |
ajm |
1.29 |
* class for other options. |
145 |
|
|
*/ |
146 |
|
|
public static final int QUEUE_ALGORITHM = Queue.FIRST; |
147 |
ajm |
1.13 |
|
148 |
ajm |
1.6 |
//---STATIC METHODS--- |
149 |
|
|
|
150 |
|
|
//---CONSTRUCTORS--- |
151 |
|
|
|
152 |
tdb |
1.7 |
/** |
153 |
|
|
* Constructs new data handler. |
154 |
|
|
* Needs a reference to the data panel so that |
155 |
|
|
* it can set it processing inBound data |
156 |
|
|
* Also gets a reference to the queue that will be |
157 |
|
|
* used by other areas of the system to send it actions |
158 |
|
|
* |
159 |
|
|
* @param data the DataPanel in use |
160 |
|
|
* @param actionQueue the actionQueue for this class |
161 |
|
|
*/ |
162 |
ajm |
1.1 |
public ConnectionHandler(DataPanel data, Queue actionQueue) { |
163 |
|
|
_data = data; |
164 |
|
|
_actionQueue = actionQueue; |
165 |
|
|
_myQueue = _actionQueue.getQueue(); |
166 |
ajm |
1.26 |
_configuration.setConnectionHandler(this); |
167 |
ajm |
1.1 |
} |
168 |
|
|
|
169 |
ajm |
1.6 |
//---PUBLIC METHODS--- |
170 |
|
|
|
171 |
tdb |
1.7 |
|
172 |
|
|
/** |
173 |
|
|
* Starts this ConnectionHandler running. |
174 |
|
|
* This basically runs until told to stop, it gets "actions" |
175 |
|
|
* from its actionQueue and switch's on them do determine |
176 |
|
|
* what it should do it then carries out the action |
177 |
|
|
* |
178 |
|
|
* For details on what each action does see the action |
179 |
|
|
* types. |
180 |
|
|
*/ |
181 |
ajm |
1.1 |
public void run() { |
182 |
ajm |
1.20 |
if(_configuration.getProperty("control.onstartconnect").equals("1")) { |
183 |
ajm |
1.13 |
_actionQueue.add(new Integer(CONNECT)); |
184 |
|
|
} |
185 |
ajm |
1.20 |
if(_configuration.getProperty("data.onstartconnect").equals("1")) { |
186 |
ajm |
1.13 |
_actionQueue.add(new Integer(STARTDATA)); |
187 |
|
|
} |
188 |
tdb |
1.7 |
while(_running) { |
189 |
ajm |
1.1 |
// we wait for a call... |
190 |
|
|
int action = 0; |
191 |
|
|
try { |
192 |
|
|
action = ((Integer) _actionQueue.get(_myQueue)).intValue(); |
193 |
|
|
} catch (InvalidQueueException e) { |
194 |
ajm |
1.12 |
// we 're never going to get this |
195 |
|
|
// but if we do we should do something nasty |
196 |
|
|
throw new RuntimeException("unable to retrieve events from actionQueue!"); |
197 |
ajm |
1.1 |
} |
198 |
|
|
|
199 |
|
|
// examine our action... |
200 |
|
|
// if it was to connect...then we connect... |
201 |
ajm |
1.2 |
switch(action) { |
202 |
|
|
case CONNECT: |
203 |
ajm |
1.12 |
if (_controlLink == null) { |
204 |
ajm |
1.13 |
try { |
205 |
|
|
// get the server name from the config |
206 |
|
|
_configuredServer = _configuration.getProperty("control.server"); |
207 |
|
|
|
208 |
|
|
if (_configuredServer == null) { |
209 |
|
|
throw new IOException("no i-scream server in current configuration"); |
210 |
|
|
} |
211 |
|
|
|
212 |
|
|
// open the socket to the server and bind the IO |
213 |
|
|
// get the port from the config |
214 |
|
|
String portString = _configuration.getProperty("control.port"); |
215 |
|
|
if (portString == null) { |
216 |
|
|
throw new IOException("no i-scream server port in current configuration"); |
217 |
|
|
} |
218 |
|
|
int port = 0; |
219 |
ajm |
1.12 |
try { |
220 |
ajm |
1.13 |
port = Integer.parseInt(portString); |
221 |
|
|
} catch (NumberFormatException e) { |
222 |
|
|
throw new IOException("no valid i-scream server port in current configuration"); |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
// start firewall if needed |
226 |
|
|
_server = handleFirewall(_configuredServer, port, _controlFirewallProcess); |
227 |
ajm |
1.32 |
|
228 |
ajm |
1.13 |
Conient.setControlStatus("Connecting to - " + _server); |
229 |
|
|
_controlLink = new Socket(_server, port); |
230 |
|
|
_inBound = new BufferedReader(new InputStreamReader(_controlLink.getInputStream())); |
231 |
|
|
_outBound = new PrintWriter(_controlLink.getOutputStream()); |
232 |
|
|
Conient.setControlStatus("Connection Established - " + _server); |
233 |
|
|
|
234 |
|
|
String response; |
235 |
|
|
response = _inBound.readLine(); |
236 |
|
|
|
237 |
|
|
// check the servers Protocol Identity against our own |
238 |
|
|
// we SHOULD be backwards compatible, so we can continue if |
239 |
|
|
// they are using a newer protocol, anything else then we die |
240 |
ajm |
1.23 |
double serverProtocolVersion = Double.parseDouble(response.substring(9, response.length())); |
241 |
|
|
Conient.addMessage("Protocol Versions: server [" + serverProtocolVersion + "] client [" + PROTOCOL_VERSION + "]"); |
242 |
|
|
if (serverProtocolVersion > PROTOCOL_VERSION) { |
243 |
ajm |
1.13 |
Conient.addMessage("WARNING{control link}: server is using a newer protocol (" + response + "), please update your client, continuing with old protocol (PROTOCOL " + PROTOCOL_VERSION + ")" ); |
244 |
ajm |
1.23 |
} else if (serverProtocolVersion < PROTOCOL_VERSION) { |
245 |
ajm |
1.13 |
// tidy up |
246 |
|
|
throw new IOException("incompatible protocol version"); |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
// send the name of the client |
250 |
|
|
_outBound.println(_configuration.getProperty("clientname")); |
251 |
|
|
_outBound.flush(); |
252 |
|
|
response = _inBound.readLine(); |
253 |
|
|
if (!response.equals("OK")) { |
254 |
|
|
// tidy up |
255 |
ajm |
1.12 |
|
256 |
ajm |
1.13 |
throw new IOException("client name rejected - " + _configuration.getProperty("clientname")); |
257 |
|
|
} |
258 |
ajm |
1.22 |
|
259 |
ajm |
1.13 |
} catch (IOException e) { |
260 |
|
|
// print the error and tidy up what's left |
261 |
|
|
Conient.addMessage("ERROR{control link}: " + e); |
262 |
|
|
_controlLink = null; |
263 |
|
|
// and the firewall handler if there is one |
264 |
ajm |
1.16 |
closeFirewall(_controlFirewallProcess); |
265 |
ajm |
1.13 |
_actionQueue.clearQueue(_myQueue); |
266 |
|
|
Conient.setControlStatus("Disconnected"); |
267 |
ajm |
1.2 |
} |
268 |
ajm |
1.12 |
} else { |
269 |
|
|
Conient.addMessage("WARNING{control link}: already established"); |
270 |
ajm |
1.2 |
} |
271 |
|
|
break; |
272 |
|
|
case STARTDATA: |
273 |
ajm |
1.12 |
// as long as the data link hasn't been established |
274 |
|
|
// we want to establish it |
275 |
|
|
if (_dataLink == null) { |
276 |
|
|
// check that the control link is open, if it isn't we |
277 |
|
|
// might want to sort that problemo out |
278 |
|
|
// we do this by simply queueing the event to occour, then |
279 |
|
|
// this event to run again ;-) |
280 |
tdb |
1.7 |
if(_controlLink == null) { |
281 |
ajm |
1.12 |
Conient.addMessage("WARNING{data link}: control link not established - queueing start events"); |
282 |
tdb |
1.7 |
_actionQueue.add(new Integer(CONNECT)); |
283 |
|
|
_actionQueue.add(new Integer(STARTDATA)); |
284 |
ajm |
1.12 |
} else { |
285 |
|
|
try { |
286 |
ajm |
1.22 |
// set our host list if we know we have one we need to set |
287 |
|
|
String hostList = _configuration.getProperty("hostList"); |
288 |
|
|
boolean hostListSet = false; |
289 |
|
|
// send our hostList if we have |
290 |
|
|
if (_configuration.getProperty("useHostList").equals("1")) { |
291 |
|
|
if (hostList.equals("")) { |
292 |
|
|
Conient.addMessage("WARNING{control link}: your host list is empty, the server will send ALL hosts"); |
293 |
|
|
} |
294 |
|
|
hostListSet = setHostList(hostList); |
295 |
|
|
// if not, indicate we want the lot |
296 |
|
|
} else { |
297 |
|
|
hostListSet = setHostList(""); |
298 |
|
|
} |
299 |
|
|
// warn if there was a problem, it will have already error'd |
300 |
|
|
if (!hostListSet) { |
301 |
|
|
Conient.addMessage("WARNING{control link}: unable to set host list"); |
302 |
|
|
} |
303 |
ajm |
1.12 |
// ask the server to start the data link |
304 |
|
|
String response; |
305 |
|
|
_outBound.println("STARTDATA"); |
306 |
|
|
_outBound.flush(); |
307 |
|
|
response = _inBound.readLine(); |
308 |
|
|
|
309 |
|
|
// see if the server suggested a good port |
310 |
|
|
if (response.equals("ERROR")) { |
311 |
|
|
throw new IOException("server unable to start data link at this time"); |
312 |
|
|
} |
313 |
ajm |
1.13 |
int port = 0; |
314 |
ajm |
1.12 |
try { |
315 |
ajm |
1.13 |
port = Integer.parseInt(response); |
316 |
ajm |
1.12 |
} catch (NumberFormatException e) { |
317 |
|
|
throw new IOException("invalid data port suggested by server - " + response); |
318 |
|
|
} |
319 |
|
|
|
320 |
ajm |
1.13 |
// start firewall if needed |
321 |
|
|
_server = handleFirewall(_configuredServer, port, _dataFirewallProcess); |
322 |
|
|
Conient.setDataStatus("Connecting to - " + _server + ":" + response); |
323 |
|
|
|
324 |
|
|
_dataLink = new Socket(_server, port); |
325 |
|
|
|
326 |
ajm |
1.12 |
response = _inBound.readLine(); |
327 |
|
|
if (!response.equals("OK")) { |
328 |
|
|
throw new IOException("server reported error establishing data channel"); |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
// if the socket was ok, then we attack our IO hooks |
332 |
|
|
_dataInBound = new BufferedReader(new InputStreamReader(_dataLink.getInputStream())); |
333 |
|
|
_dataOutBound = new PrintWriter(_dataLink.getOutputStream()); |
334 |
|
|
Conient.setDataStatus("Connection Established - " + _server); |
335 |
ajm |
1.15 |
// now we want to start reading the data in |
336 |
|
|
// so we start the appropriate components on their way |
337 |
|
|
// we create a queue to give to both the reader and the |
338 |
|
|
// displayer |
339 |
ajm |
1.29 |
|
340 |
|
|
String configQueueSize = _configuration.getProperty("dataQueueSize"); |
341 |
|
|
int queueLimit = DEFAULT_QUEUE_LIMIT; |
342 |
|
|
if (configQueueSize != null) { |
343 |
|
|
try { |
344 |
|
|
queueLimit = Integer.parseInt(configQueueSize); |
345 |
|
|
} catch (NumberFormatException e) { |
346 |
|
|
// if it fails it will be default |
347 |
|
|
Conient.addMessage("WARNING{data link}: invalid queue size in configuration, using default of - " + queueLimit); |
348 |
|
|
} |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
Queue theQueue = new Queue(queueLimit, QUEUE_ALGORITHM); |
352 |
ajm |
1.30 |
_dataReader = new DataReader(_dataInBound, theQueue, this); |
353 |
ajm |
1.15 |
_data.setQueue(theQueue); |
354 |
|
|
_data.cleanUpTabs(); |
355 |
|
|
|
356 |
|
|
// start the data rocking |
357 |
|
|
new Thread(_data).start(); |
358 |
|
|
_dataReader.start(); |
359 |
|
|
// finished for us.... |
360 |
ajm |
1.12 |
} catch (IOException e) { |
361 |
|
|
// print the error and tidy up what's left |
362 |
|
|
Conient.addMessage("ERROR{data link}: " + e); |
363 |
|
|
_dataLink = null; |
364 |
ajm |
1.16 |
// and the firewall handler if there is one |
365 |
|
|
closeFirewall(_dataFirewallProcess); |
366 |
ajm |
1.13 |
_actionQueue.clearQueue(_myQueue); |
367 |
ajm |
1.12 |
Conient.setDataStatus("Disconnected"); |
368 |
|
|
} |
369 |
ajm |
1.2 |
} |
370 |
ajm |
1.12 |
} else { |
371 |
|
|
Conient.addMessage("WARNING{data link}: already established"); |
372 |
ajm |
1.2 |
} |
373 |
|
|
break; |
374 |
|
|
case STOPDATA: |
375 |
ajm |
1.12 |
if(_dataLink != null) { |
376 |
|
|
try { |
377 |
|
|
String response; |
378 |
|
|
// shut down the data link |
379 |
|
|
Conient.setDataStatus("Disconnecting - " + _server); |
380 |
|
|
|
381 |
|
|
// close the reader |
382 |
|
|
_dataReader.shutdown(); |
383 |
|
|
// wait for it to close |
384 |
|
|
boolean dirtyShutdown = true; |
385 |
|
|
long startTime = System.currentTimeMillis(); |
386 |
|
|
while((System.currentTimeMillis() - startTime) < (DATAREADER_SHUTDOWN_TIMEOUT * 1000)) { |
387 |
|
|
if (!_dataReader.isAlive()) { |
388 |
|
|
dirtyShutdown = false; |
389 |
|
|
break; |
390 |
|
|
} |
391 |
|
|
} |
392 |
|
|
// warn if it didn't shutdown in time |
393 |
|
|
if (dirtyShutdown) { |
394 |
|
|
Conient.addMessage("WARNING{data link}: data reader thread did not close within timeout, killing its IO anyway!"); |
395 |
|
|
} |
396 |
|
|
|
397 |
|
|
// tell the server |
398 |
|
|
_outBound.println("STOPDATA"); |
399 |
|
|
_outBound.flush(); |
400 |
|
|
response = _inBound.readLine(); |
401 |
|
|
|
402 |
|
|
// check the server was ok with our request... |
403 |
|
|
// even if it wasn't we will go anyway! |
404 |
|
|
if (!response.equals("OK")) { |
405 |
|
|
throw new IOException("server didn't OK request to stop data channel - stopping anyway"); |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
|
409 |
|
|
// close the lot down |
410 |
|
|
_dataInBound.close(); |
411 |
|
|
_dataOutBound.close(); |
412 |
|
|
_dataLink.close(); |
413 |
|
|
// get rid of the socket |
414 |
|
|
_dataLink = null; |
415 |
ajm |
1.13 |
|
416 |
|
|
// and the firewall handler if there is one |
417 |
ajm |
1.16 |
closeFirewall(_dataFirewallProcess); |
418 |
ajm |
1.13 |
|
419 |
ajm |
1.12 |
Conient.setDataStatus("Disconnected"); |
420 |
|
|
} catch (IOException e) { |
421 |
|
|
// print the error and tidy up what's left |
422 |
|
|
Conient.addMessage("ERROR{data link}: " + e); |
423 |
|
|
try { |
424 |
|
|
_dataOutBound.close(); |
425 |
|
|
_dataInBound.close(); |
426 |
|
|
_dataLink.close(); |
427 |
ajm |
1.13 |
// and the firewall handler if there is one |
428 |
ajm |
1.16 |
closeFirewall(_dataFirewallProcess); |
429 |
ajm |
1.12 |
} catch (IOException e2) { |
430 |
|
|
Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2); |
431 |
|
|
} |
432 |
|
|
_dataLink = null; |
433 |
ajm |
1.13 |
_actionQueue.clearQueue(_myQueue); |
434 |
ajm |
1.12 |
Conient.setDataStatus("Disconnected"); |
435 |
ajm |
1.2 |
} |
436 |
ajm |
1.12 |
} else { |
437 |
|
|
Conient.addMessage("WARNING{data link}: already disconnected"); |
438 |
ajm |
1.2 |
} |
439 |
|
|
break; |
440 |
|
|
case DISCONNECT: |
441 |
ajm |
1.12 |
if (_controlLink != null) { |
442 |
ajm |
1.2 |
if (_dataLink != null) { |
443 |
ajm |
1.12 |
// we want to tell ourselves to stop it |
444 |
|
|
Conient.addMessage("WARNING{control link}: data link not disconnected - queueing stop events"); |
445 |
|
|
_actionQueue.add(new Integer(STOPDATA)); |
446 |
|
|
_actionQueue.add(new Integer(DISCONNECT)); |
447 |
|
|
} else { |
448 |
|
|
try { |
449 |
|
|
// request the server to disconnect |
450 |
|
|
String response; |
451 |
|
|
_outBound.println("DISCONNECT"); |
452 |
|
|
_outBound.flush(); |
453 |
|
|
response = _inBound.readLine(); |
454 |
|
|
|
455 |
|
|
// check the server was ok with our request... |
456 |
|
|
// even if it wasn't we will go anyway! |
457 |
|
|
if (!response.equals("OK")) { |
458 |
|
|
throw new IOException("server didn't OK request to stop control channel - stopping anyway"); |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
// then lets shutdown the link |
462 |
|
|
Conient.setControlStatus("Disconnecting - " + _server); |
463 |
|
|
_inBound.close(); |
464 |
|
|
_outBound.close(); |
465 |
|
|
_controlLink.close(); |
466 |
|
|
// for good measure |
467 |
|
|
_controlLink = null; |
468 |
ajm |
1.13 |
|
469 |
|
|
// and the firewall handler if there is one |
470 |
ajm |
1.16 |
closeFirewall(_controlFirewallProcess); |
471 |
ajm |
1.13 |
|
472 |
ajm |
1.12 |
Conient.setControlStatus("Disconnected"); |
473 |
|
|
} catch (IOException e) { |
474 |
ajm |
1.14 |
Conient.addMessage("ERROR{control link}: " + e); |
475 |
ajm |
1.12 |
try { |
476 |
|
|
_inBound.close(); |
477 |
|
|
_outBound.close(); |
478 |
|
|
_controlLink.close(); |
479 |
ajm |
1.13 |
// and the firewall handler if there is one |
480 |
ajm |
1.16 |
closeFirewall(_controlFirewallProcess); |
481 |
ajm |
1.12 |
} catch (IOException e2) { |
482 |
|
|
Conient.addMessage("CRITICAL{control link}: unable to close socket - " + e2); |
483 |
|
|
} |
484 |
|
|
_controlLink = null; |
485 |
ajm |
1.13 |
_actionQueue.clearQueue(_myQueue); |
486 |
ajm |
1.12 |
Conient.setControlStatus("Disconnected"); |
487 |
|
|
} |
488 |
ajm |
1.2 |
} |
489 |
ajm |
1.12 |
} else { |
490 |
|
|
Conient.addMessage("WARNING{control link}: already disconnected"); |
491 |
ajm |
1.1 |
} |
492 |
ajm |
1.2 |
break; |
493 |
ajm |
1.4 |
case QUIT: |
494 |
ajm |
1.12 |
Conient.addMessage("Exiting."); |
495 |
ajm |
1.5 |
try { |
496 |
|
|
// stop data and control if data up |
497 |
|
|
if (_dataLink != null) { |
498 |
|
|
_actionQueue.add(new Integer(STOPDATA)); |
499 |
|
|
_actionQueue.add(new Integer(DISCONNECT)); |
500 |
|
|
_actionQueue.add(new Integer(QUIT)); |
501 |
|
|
throw new IOException(); |
502 |
|
|
} |
503 |
|
|
// stop control |
504 |
|
|
if (_controlLink != null) { |
505 |
|
|
_actionQueue.add(new Integer(DISCONNECT)); |
506 |
|
|
_actionQueue.add(new Integer(QUIT)); |
507 |
|
|
throw new IOException(); |
508 |
|
|
} |
509 |
ajm |
1.11 |
Conient.addMessage("Finished."); |
510 |
ajm |
1.5 |
// go! |
511 |
|
|
System.exit(0); |
512 |
|
|
} catch (IOException e) { |
513 |
ajm |
1.12 |
Conient.addMessage("WARNING: open connections detected - queueing stop events"); |
514 |
ajm |
1.4 |
} |
515 |
|
|
break; |
516 |
ajm |
1.1 |
} |
517 |
|
|
} |
518 |
|
|
} |
519 |
ajm |
1.26 |
|
520 |
|
|
/** |
521 |
|
|
* This method is called by the Configuration object |
522 |
|
|
* when a request is made for a server property. |
523 |
|
|
* The Configuration object is informed of the Connection |
524 |
|
|
* Handler's whereabouts on construction of the ConnectionHandler. |
525 |
|
|
* |
526 |
|
|
* This implements the STARTCONFIG command in the 1.0 protocol. |
527 |
|
|
*/ |
528 |
|
|
public String getConfigFromServer(String configName, String propertyName) { |
529 |
|
|
String property = ""; |
530 |
|
|
if(_controlLink != null) { |
531 |
|
|
try { |
532 |
|
|
Conient.addMessage("Getting configuration from server"); |
533 |
|
|
String response = null; |
534 |
|
|
_outBound.println("STARTCONFIG"); |
535 |
|
|
_outBound.flush(); |
536 |
|
|
response = _inBound.readLine(); |
537 |
|
|
if (!response.equals("OK")) { |
538 |
|
|
throw new IOException("server refused (" + response + ")"); |
539 |
|
|
} |
540 |
|
|
|
541 |
tdb |
1.28 |
_outBound.println(configName + ";" + propertyName); |
542 |
ajm |
1.26 |
_outBound.flush(); |
543 |
|
|
response = _inBound.readLine(); |
544 |
|
|
if (response.equals("ERROR")) { |
545 |
|
|
throw new IOException("server did not returned ERROR"); |
546 |
|
|
} |
547 |
|
|
property = response; |
548 |
|
|
_outBound.println("ENDCONFIG"); |
549 |
|
|
_outBound.flush(); |
550 |
|
|
response = _inBound.readLine(); |
551 |
|
|
if (!response.equals("OK")) { |
552 |
|
|
throw new IOException("server reported error when finishing configuration"); |
553 |
|
|
} |
554 |
|
|
} catch (IOException e) { |
555 |
|
|
Conient.addMessage("ERROR{control link}: when getting configuration - " + e); |
556 |
|
|
} |
557 |
|
|
} |
558 |
|
|
return property; |
559 |
|
|
} |
560 |
|
|
|
561 |
ajm |
1.12 |
/** |
562 |
|
|
* This method allows other classes |
563 |
|
|
* to shutdown this connection handler. |
564 |
|
|
*/ |
565 |
|
|
public void shutdown() { |
566 |
|
|
_running = false; |
567 |
ajm |
1.30 |
} |
568 |
|
|
|
569 |
|
|
/** |
570 |
|
|
* Called by the DataReader if the link |
571 |
ajm |
1.31 |
* is unexpectedly lost. This closes the |
572 |
|
|
* data link. |
573 |
ajm |
1.30 |
*/ |
574 |
ajm |
1.31 |
public void shutdownDataLink() { |
575 |
|
|
_actionQueue.add(new Integer(STOPDATA)); |
576 |
ajm |
1.12 |
} |
577 |
|
|
|
578 |
ajm |
1.6 |
//---PRIVATE METHODS--- |
579 |
ajm |
1.18 |
|
580 |
|
|
/** |
581 |
ajm |
1.20 |
* This method performs the SETHOSTLIST command. |
582 |
|
|
* This is run by the CONNECT command. |
583 |
|
|
* It tells the server which hosts we are interested |
584 |
|
|
* in, if "" is sent, this indicates we want ALL hosts. |
585 |
|
|
* |
586 |
|
|
* @param hostList the list of hosts as gained from the config |
587 |
|
|
* @return if we succeeded in setting the host list |
588 |
|
|
*/ |
589 |
|
|
private boolean setHostList(String hostList) { |
590 |
|
|
boolean success = false; |
591 |
|
|
// must have a control link open |
592 |
|
|
if (_controlLink != null) { |
593 |
|
|
// data link must be closed (according to 1.1 PROTOCOL) |
594 |
|
|
if(_dataLink == null) { |
595 |
|
|
try { |
596 |
ajm |
1.21 |
Conient.addMessage("Setting host list to:" + hostList); |
597 |
ajm |
1.20 |
String response = null; |
598 |
|
|
_outBound.println("SETHOSTLIST"); |
599 |
|
|
_outBound.flush(); |
600 |
|
|
response = _inBound.readLine(); |
601 |
|
|
if (!response.equals("OK")) { |
602 |
|
|
throw new IOException("server refused - data link possibly still open?"); |
603 |
|
|
} |
604 |
|
|
_outBound.println(hostList); |
605 |
|
|
_outBound.flush(); |
606 |
|
|
response = _inBound.readLine(); |
607 |
|
|
if (!response.equals("OK")) { |
608 |
|
|
throw new IOException("server had trouble with our request"); |
609 |
|
|
} |
610 |
|
|
success = true; |
611 |
|
|
} catch (IOException e) { |
612 |
|
|
Conient.addMessage("ERROR{control link}: when setting hostlist - " + e); |
613 |
|
|
} |
614 |
|
|
} |
615 |
|
|
} |
616 |
|
|
return success; |
617 |
ajm |
1.18 |
} |
618 |
ajm |
1.6 |
|
619 |
ajm |
1.13 |
/** |
620 |
|
|
* Handles opening pipes through firewalls. |
621 |
|
|
* It checks the configuration for various entries |
622 |
|
|
* to set up the link or not. |
623 |
|
|
* |
624 |
|
|
* If a link is setup it will return the name of the |
625 |
|
|
* new server to connect to, if a link is NOT setup, |
626 |
|
|
* it will simply return the original server name. |
627 |
|
|
* |
628 |
|
|
* The name of the machine that the pipe is setup on |
629 |
|
|
* defaults to "localhost", unless the configuration |
630 |
|
|
* specifies otherwise. |
631 |
|
|
* |
632 |
|
|
* Once it has run the firewall command it then waits |
633 |
|
|
* a set period according to the config for the firewall |
634 |
|
|
* pipe to be set up. |
635 |
|
|
* |
636 |
|
|
* The firewall process should be destroyed when the |
637 |
|
|
* link is finished with. |
638 |
|
|
* |
639 |
|
|
* @param server the name of the server to open up the pipe to |
640 |
|
|
* @param port the port number to open up the pipe to |
641 |
|
|
* @param firewallProcess the holder for the new firewall process |
642 |
|
|
* @return the server to connect to, as determined by this routine |
643 |
|
|
*/ |
644 |
ajm |
1.32 |
private String handleFirewall(String server, int port, TunnelProcess firewallProcess) { |
645 |
ajm |
1.13 |
String firewallCommand = _configuration.getProperty("firewall.command"); |
646 |
ajm |
1.19 |
String useFirewall = _configuration.getProperty("useFirewall"); |
647 |
ajm |
1.13 |
String firewallCommandWait = _configuration.getProperty("firewall.commandwait"); |
648 |
|
|
String firewallServer = _configuration.getProperty("firewall.server"); |
649 |
|
|
// if we are running firewall support...then lets start it |
650 |
ajm |
1.20 |
if (useFirewall.equals("1")) { |
651 |
ajm |
1.13 |
// clean up the command with what we want |
652 |
ajm |
1.25 |
firewallCommand = StringUtils.replaceText(firewallCommand, "%PORT%", new Integer(port).toString()); |
653 |
|
|
firewallCommand = StringUtils.replaceText(firewallCommand, "%SERVER%", server); |
654 |
ajm |
1.13 |
Conient.addMessage("WARNING{firewall}: firewall pipes requested, running pipe setup command \"" + firewallCommand + "\""); |
655 |
|
|
try { |
656 |
|
|
// run the command |
657 |
ajm |
1.32 |
firewallProcess.setProcess(Runtime.getRuntime().exec(firewallCommand)); |
658 |
ajm |
1.13 |
|
659 |
|
|
// work out how long we should wait before carrying on |
660 |
|
|
int time = 0; |
661 |
|
|
try { |
662 |
|
|
time = Integer.parseInt(firewallCommandWait); |
663 |
|
|
} catch (NumberFormatException e) { |
664 |
|
|
time = 0; |
665 |
|
|
} |
666 |
|
|
if (time == 0) { |
667 |
|
|
time = DEFAULT_FIREWALL_COMMANDWAIT; |
668 |
|
|
} |
669 |
|
|
Conient.addMessage("WARNING{firewall}: waiting " + time + " seconds for command to complete!"); |
670 |
|
|
// wait for the command to finish |
671 |
|
|
try { |
672 |
|
|
Thread.sleep(time * 1000); |
673 |
|
|
} catch (InterruptedException e) { |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
// set the server we want to return |
677 |
|
|
server = firewallServer; |
678 |
ajm |
1.19 |
if (server.equals("")) { |
679 |
ajm |
1.13 |
server = DEFAULT_FIREWALL_SERVER; |
680 |
|
|
} |
681 |
|
|
} catch (IOException e) { |
682 |
|
|
Conient.addMessage("ERROR{firewall}: unable to start pipe to i-scream server"); |
683 |
|
|
} |
684 |
|
|
} |
685 |
|
|
return server; |
686 |
ajm |
1.16 |
} |
687 |
|
|
|
688 |
|
|
/** |
689 |
|
|
* Checks to see if the given firewall process |
690 |
|
|
* has been created. If it has it calls destroy() |
691 |
|
|
* on it. |
692 |
|
|
* |
693 |
|
|
* @param firewallProcess the process to check |
694 |
|
|
*/ |
695 |
ajm |
1.32 |
private void closeFirewall(TunnelProcess firewallProcess) { |
696 |
|
|
if (firewallProcess.getProcess() != null) { |
697 |
|
|
firewallProcess.getProcess().destroy(); |
698 |
|
|
firewallProcess.setProcess(null); |
699 |
ajm |
1.16 |
Conient.addMessage("WARNING{firewall}: firewall process destroyed"); |
700 |
|
|
} |
701 |
ajm |
1.13 |
} |
702 |
|
|
|
703 |
ajm |
1.6 |
//---ACCESSOR/MUTATOR METHODS--- |
704 |
|
|
|
705 |
|
|
//---ATTRIBUTES--- |
706 |
|
|
|
707 |
ajm |
1.12 |
/** |
708 |
|
|
* The state if this thread |
709 |
|
|
*/ |
710 |
ajm |
1.13 |
private boolean _running = true; |
711 |
ajm |
1.12 |
|
712 |
|
|
/** |
713 |
|
|
* A reference to the displaying class DataPanel |
714 |
|
|
*/ |
715 |
ajm |
1.13 |
private DataPanel _data; |
716 |
ajm |
1.12 |
|
717 |
|
|
/** |
718 |
|
|
* The queue that actions are added to by other parts of the system |
719 |
|
|
*/ |
720 |
ajm |
1.13 |
private Queue _actionQueue; |
721 |
ajm |
1.12 |
|
722 |
|
|
/** |
723 |
|
|
* The queue number that we are reading from on the action queue |
724 |
|
|
*/ |
725 |
ajm |
1.13 |
private int _myQueue; |
726 |
ajm |
1.12 |
|
727 |
|
|
/** |
728 |
|
|
* The control link socket |
729 |
|
|
*/ |
730 |
ajm |
1.13 |
private Socket _controlLink; |
731 |
ajm |
1.12 |
|
732 |
|
|
/** |
733 |
|
|
* The data link socket |
734 |
|
|
*/ |
735 |
ajm |
1.13 |
private Socket _dataLink; |
736 |
ajm |
1.12 |
|
737 |
|
|
/** |
738 |
|
|
* The input for the control link |
739 |
|
|
*/ |
740 |
ajm |
1.13 |
private BufferedReader _inBound; |
741 |
ajm |
1.12 |
|
742 |
|
|
/** |
743 |
|
|
* The output for the control link |
744 |
|
|
*/ |
745 |
ajm |
1.13 |
private PrintWriter _outBound; |
746 |
ajm |
1.12 |
|
747 |
|
|
/** |
748 |
|
|
* The input for the data link |
749 |
|
|
*/ |
750 |
ajm |
1.13 |
private BufferedReader _dataInBound; |
751 |
ajm |
1.12 |
|
752 |
|
|
/** |
753 |
|
|
* The output for the data link |
754 |
|
|
*/ |
755 |
ajm |
1.13 |
private PrintWriter _dataOutBound; |
756 |
ajm |
1.12 |
|
757 |
|
|
/** |
758 |
|
|
* A reference to the DataReader in use |
759 |
|
|
*/ |
760 |
ajm |
1.13 |
private DataReader _dataReader; |
761 |
|
|
|
762 |
|
|
/** |
763 |
|
|
* A reference to the system configuration component |
764 |
|
|
*/ |
765 |
|
|
private Configuration _configuration = Configuration.getInstance(); |
766 |
|
|
|
767 |
|
|
/** |
768 |
|
|
* The server we will be connecting to |
769 |
|
|
*/ |
770 |
|
|
private String _server = null; |
771 |
ajm |
1.12 |
|
772 |
|
|
/** |
773 |
ajm |
1.13 |
* The server that the config says we should connect to |
774 |
ajm |
1.12 |
*/ |
775 |
ajm |
1.13 |
private String _configuredServer = null; |
776 |
ajm |
1.6 |
|
777 |
ajm |
1.13 |
/** |
778 |
|
|
* The process used to start the firewall pipe |
779 |
|
|
* for the control link. |
780 |
|
|
*/ |
781 |
ajm |
1.32 |
private TunnelProcess _controlFirewallProcess = new TunnelProcess(); |
782 |
ajm |
1.13 |
|
783 |
|
|
/** |
784 |
|
|
* The process used to start the firewall pipe |
785 |
|
|
* for the data link. |
786 |
|
|
*/ |
787 |
ajm |
1.32 |
private TunnelProcess _dataFirewallProcess = new TunnelProcess(); |
788 |
ajm |
1.13 |
|
789 |
ajm |
1.6 |
//---STATIC ATTRIBUTES--- |
790 |
|
|
|
791 |
ajm |
1.27 |
} |