1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 package com.buckosoft.fibs.net;
149
150 import java.io.IOException;
151 import java.io.InputStream;
152 import java.io.OutputStream;
153 import java.net.Socket;
154 import java.net.SocketException;
155 import java.net.UnknownHostException;
156 import java.util.LinkedList;
157 import java.util.Timer;
158 import java.util.TimerTask;
159
160
161
162
163
164
165
166
167
168
169 public class ClientConnection extends Thread {
170 private final static boolean DEBUG = false;
171
172 final static String eol = "\r\n";
173
174 private Socket sock = null;
175 private InputStream is = null;
176 private OutputStream os = null;
177
178 private ClientAdapter clientAdapter = null;
179 private CookieMonster cookieMonster;
180 private FIBSAttributes fibsAttributes;
181 private boolean shuttingDown = false;
182 private LinkedList<String> outMessages = new LinkedList<String>();
183 private Boolean listLock = new Boolean(false);
184 private String leftover = null;
185 private String pushbackString = null;
186 private final int resetCountdown = 60*1;
187 private int timerCountdown = resetCountdown;
188 private Timer timer;
189 private PingTimerTask pingTimerTask;
190
191 public ClientConnection() {
192 cookieMonster = new CookieMonster();
193 cookieMonster.setClientConnection(this);
194 timer = new Timer();
195 pingTimerTask = new PingTimerTask();
196 timer.scheduleAtFixedRate(pingTimerTask, 1000, 1000);
197 }
198
199 private class PingTimerTask extends TimerTask {
200
201
202
203
204 @Override
205 public void run() {
206 if (--timerCountdown <= 0) {
207 timerCountdown = resetCountdown;
208 sendMessage("\r\n");
209 }
210 }
211 }
212
213
214
215
216 public boolean isConnected() {
217 return(sock != null);
218 }
219
220
221
222
223 public void setClientAdapter(ClientAdapter clientAdapter) {
224 this.clientAdapter = clientAdapter;
225 }
226
227
228
229
230 public void setFibsAttributes(FIBSAttributes fibsAttributes) {
231 this.fibsAttributes = fibsAttributes;
232 }
233
234
235
236 public void resetFIBSCookieMonster() {
237 this.cookieMonster.reset();
238 }
239
240 public void pushBack(String s) {
241 pushbackString = s;
242 }
243
244
245
246
247 public void sendMessage(String s) {
248 if (s == null)
249 throw new RuntimeException("Can't send a null message");
250 if (DEBUG)
251 System.out.println("User sent '" + s + "'");
252 accessOutMessages(s);
253 timerCountdown = resetCountdown;
254 }
255
256
257
258 public void shutDown() {
259 shuttingDown = true;
260 try {
261 if (timer != null) {
262 timer.cancel();
263 timer = null;
264 }
265 if (pingTimerTask != null) {
266 pingTimerTask.cancel();
267 pingTimerTask = null;
268 }
269 } catch (Exception e1) {
270 e1.printStackTrace();
271 }
272 try {
273 if (os != null)
274 os.close();
275 os = null;
276 if (is != null)
277 is.close();
278 is = null;
279 if (sock != null) {
280 sock.shutdownInput();
281 sock.shutdownOutput();
282 sock.close();
283 }
284 sock = null;
285 } catch (SocketException sex) {
286 } catch (IOException e) {
287 e.printStackTrace();
288 }
289 }
290
291
292
293
294 private void accessOutMessages(String s) {
295 synchronized (listLock) {
296 if (s == null)
297 outMessages.remove();
298 else
299 outMessages.add(s);
300 }
301 }
302
303
304
305
306 @Override
307 public synchronized void run() {
308 sock = null;
309 String server = this.fibsAttributes.getServerName();
310 int port = this.fibsAttributes.getServerPort();
311 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.SYSTEM, "Connecting to Server:" + eol);
312 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.SYSTEM, server + ":" + port + eol);
313 try {
314 sock = new Socket(server, port);
315 } catch (UnknownHostException e) {
316 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.SYSTEM, "Can't connect: Unknown host");
317 e.printStackTrace();
318 return;
319 } catch (IOException e) {
320 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.SYSTEM, "Can't connect: " + e.getLocalizedMessage());
321
322 return;
323 } catch (Exception e) {
324 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.SYSTEM, "Can't connect: " + e.getLocalizedMessage());
325
326 return;
327 }
328
329 try {
330 is = sock.getInputStream();
331 os = sock.getOutputStream();
332
333 while (!shuttingDown) {
334 if (pushbackString != null) {
335 String s = pushbackString;
336 pushbackString = null;
337 handleMessage(s);
338 continue;
339 }
340 if (is.available() > 0) {
341 try {
342 readMessage();
343 } catch (Exception e) {
344 System.err.println(e.getMessage());
345 e.printStackTrace();
346 }
347 continue;
348 }
349 if (!outMessages.isEmpty()) {
350 writeMessage();
351 continue;
352 }
353 Thread.sleep(100);
354 }
355 } catch (IOException e) {
356 e.printStackTrace();
357 } catch (InterruptedException e) {
358 e.printStackTrace();
359 }
360 if (sock != null) {
361 try {
362 sock.shutdownInput();
363 sock.shutdownOutput();
364 sock.close();
365 sock = null;
366 } catch (SocketException e) {
367 } catch (IOException e) {
368 e.printStackTrace();
369 }
370 }
371 }
372
373 private void readMessage() {
374 byte[] b;
375 try {
376 int r = is.available();
377 b = new byte[r];
378 is.read(b);
379 } catch (IOException e) {
380 e.printStackTrace();
381 shuttingDown = true;
382 return;
383 }
384 String s = new String(b);
385 if (DEBUG)
386 System.out.println(s);
387 if (DEBUG)
388 this.clientAdapter.writeSystemMessageln(ClientAdapter.MessageRoute.DEBUG, s);
389 boolean hasLeftOver = false;
390 if (!s.endsWith("\r\n")) {
391 if (DEBUG)
392 System.out.println("Doesn't end with cr/lf" + eol);
393 hasLeftOver = true;
394 }
395 String[] ss = s.split("\r\n");
396 if (ss.length == 0)
397 return;
398 if (DEBUG)
399 System.out.println("Got " + ss.length + " lines" + eol);
400 if (leftover != null) {
401 ss[0] = leftover + ss[0];
402 leftover = null;
403 }
404 for (int i=0; i<ss.length; i++) {
405 if (i == ss.length-1 && hasLeftOver && !ss[i].startsWith("login:"))
406 leftover = ss[i];
407 else
408 handleMessage(ss[i]);
409 while (pushbackString != null) {
410 String t = pushbackString;
411 pushbackString = null;
412 handleMessage(t);
413 }
414 }
415 }
416
417
418
419 public void sendLogin() {
420 StringBuffer sb = new StringBuffer();
421 sb.append("login ");
422 sb.append(this.fibsAttributes.getAppSignature());
423 sb.append(" 1008 ");
424 sb.append(this.fibsAttributes.getUserName());
425 sb.append(" ");
426 sb.append(this.fibsAttributes.getUserPassword());
427 sb.append(eol);
428 this.sendMessage(sb.toString());
429 }
430
431 private void writeMessage() {
432 String s = outMessages.getFirst();
433 if (this.fibsAttributes.isDisplayXmit()) {
434 if (s.startsWith("login"))
435 this.clientAdapter.writeSystemMessageln(ClientAdapter.MessageRoute.NETWORKOUT, "login...");
436 else
437 this.clientAdapter.writeSystemMessage(ClientAdapter.MessageRoute.NETWORKOUT, s);
438 }
439 if (this.fibsAttributes.isStdoutNetworkMessages())
440 System.out.println("writeNetMessage: '" + s + "'");
441 try {
442 if (os == null) {
443 shuttingDown = true;
444 return;
445 }
446 os.write(s.getBytes());
447 } catch (Exception e) {
448 this.clientAdapter.writeSystemMessageln(ClientAdapter.MessageRoute.ERROR, "Disconnected from FIBS");
449 this.clientAdapter.writeSystemMessageln(ClientAdapter.MessageRoute.ERROR, e.getLocalizedMessage());
450 this.clientAdapter.connectionAborted();
451 e.printStackTrace();
452 shuttingDown = true;
453 }
454 this.accessOutMessages(null);
455 }
456
457 private void handleMessage(String s) {
458 if (s.length() > 1 && s.charAt(0) == 13)
459 s = s.substring(1);
460 if (s.length() > 1 && s.charAt(0) == 10)
461 s = s.substring(1);
462 int cookie = this.cookieMonster.fIBSCookie(s);
463 if (this.fibsAttributes.isStdoutNetworkMessages())
464 System.out.println("Handle: " + cookie + "'" + s + "'");
465 if (this.pushbackString != null) {
466 s = s.substring(0, s.length()-this.pushbackString.length());
467 if (DEBUG)
468 System.out.println("Truncating to '" + s + "'");
469 }
470 this.clientAdapter.dispatch(cookie, s);
471 }
472 }