comparison src/org/tn5250j/framework/tn5250/DataStreamProducer.java @ 3:e8d2a24e85c6 tn5250

adding tn5250 files
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 12:11:10 -0700
parents
children 5949eb469a79
comparison
equal deleted inserted replaced
2:a01665cb683d 3:e8d2a24e85c6
1 package org.tn5250j.framework.tn5250;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedOutputStream;
5 import java.io.ByteArrayOutputStream;
6 import java.io.EOFException;
7 import java.io.FileNotFoundException;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.net.SocketException;
11 import java.util.concurrent.BlockingQueue;
12
13 import org.tn5250j.encoding.ICodePage;
14 import org.tn5250j.tools.logging.TN5250jLogFactory;
15 import org.tn5250j.tools.logging.TN5250jLogger;
16
17 public class DataStreamProducer implements Runnable {
18
19 private BufferedInputStream bin;
20 private ByteArrayOutputStream baosin;
21 private Thread me;
22 private byte[] saveStream;
23 private final BlockingQueue<Object> dsq;
24 private tnvt vt;
25 private byte[] abyte2;
26 private FileOutputStream fw;
27 private BufferedOutputStream dw;
28 private boolean dumpBytes = false;
29 private ICodePage codePage;
30
31 private TN5250jLogger log = TN5250jLogFactory.getLogger (this.getClass());
32
33 public DataStreamProducer(tnvt vt, BufferedInputStream in, BlockingQueue<Object> queue, byte[] init) {
34 bin = in;
35 this.vt = vt;
36 baosin = new ByteArrayOutputStream();
37 dsq = queue;
38 abyte2 = init;
39 }
40
41 public void setInputStream(ByteArrayOutputStream is) {
42
43 baosin = is;
44
45 }
46
47 public final void run() {
48
49 boolean done = false;
50
51 me = Thread.currentThread();
52
53 // load the first response screen
54 loadStream(abyte2, 0);
55
56 while (!done) {
57 try {
58
59 byte[] abyte0 = readIncoming();
60
61 // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK
62 // Restructured to the readIncoming() method to return null
63 // on TIMING MARK. Don't process in that case (abyte0 == null)!
64 if (abyte0 != null)
65 {
66 // WVL - LDC : 16/07/2003 : TR.000345
67 // When the socket has been closed, the reading returns
68 // no bytes (an empty byte arrray).
69 // But the loadStream fails on this, so we check it here!
70 if (abyte0.length > 0)
71 {
72 loadStream(abyte0, 0);
73 }
74 // WVL - LDC : 16/07/2003 : TR.000345
75 // Returning no bytes means the input buffer has
76 // reached end-of-stream, so we do a disconnect!
77 else
78 {
79 done = true;
80 vt.disconnect();
81 }
82 }
83
84 }
85
86 catch (SocketException se) {
87 log.warn(" DataStreamProducer thread interrupted and stopping " + se.getMessage());
88 done = true;
89 }
90
91 catch (IOException ioe) {
92
93 log.warn(ioe.getMessage());
94 if (me.isInterrupted())
95 done = true;
96
97 }
98 catch (Exception ex) {
99
100 log.warn(ex.getMessage());
101 if (me.isInterrupted())
102 done = true;
103
104 }
105 }
106 }
107
108 private final void loadStream(byte abyte0[], int i) {
109
110 int j = 0;
111 int size = 0;
112 if (saveStream == null) {
113 j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff;
114 size = abyte0.length;
115 }
116 else {
117 size = saveStream.length + abyte0.length;
118 byte[] inter = new byte[size];
119 System.arraycopy(saveStream, 0, inter, 0, saveStream.length);
120 System.arraycopy(abyte0, 0, inter, saveStream.length, abyte0.length);
121 abyte0 = new byte[size];
122 System.arraycopy(inter, 0, abyte0, 0, size);
123 saveStream = null;
124 inter = null;
125 j = (abyte0[i] & 0xff) << 8 | abyte0[i + 1] & 0xff;
126 log.debug("partial stream found");
127 }
128
129 if (j > size) {
130 saveStream = new byte[abyte0.length];
131 System.arraycopy(abyte0, 0, saveStream, 0, abyte0.length);
132 log.debug("partial stream saved");
133 }
134 else {
135 byte abyte1[];
136 try {
137 abyte1 = new byte[j + 2];
138
139 System.arraycopy(abyte0, i, abyte1, 0, j + 2);
140 dsq.put(abyte1);
141 if(abyte0.length > abyte1.length + i)
142 loadStream(abyte0, i + j + 2);
143 }
144 catch (Exception ex) {
145
146 log.warn("load stream error " + ex.getMessage());
147 // ex.printStackTrace();
148 // dump(abyte0);
149
150 }
151 }
152 }
153
154 public final byte[] readIncoming()
155 throws IOException {
156
157 boolean done = false;
158 boolean negotiate = false;
159
160 baosin.reset();
161 int j = -1;
162 int i = 0;
163
164 while(!done) {
165
166 i = bin.read();
167
168 // WVL - LDC : 16/07/2003 : TR.000345
169 // The inStream return -1 when end-of-stream is reached. This
170 // happens e.g. when the connection is closed from the AS/400.
171 // So we stop in this case!
172 // ==> an empty byte array is returned from this method.
173 if (i == -1) // nothing read!
174 {
175 done = true;
176 vt.disconnect();
177 continue;
178 }
179
180 // We use the values instead of the static values IAC and EOR
181 // because they are defined as bytes.
182 //
183 // The > if(i != 255 || j != 255) < is a hack for the double FF FF's
184 // that are being returned. I do not know why this is like this and
185 // can not find any documentation for it. It is also being returned
186 // on my Client Access tcp dump as well so they are handling it.
187 //
188 // my5250
189 // 0000: 00 50 DA 44 C8 45 42 00 00 00 00 24 08 00 45 00 .P.D.EB....$..E.
190 // 0010: 04 2A BC F9 00 00 40 06 D0 27 C1 A8 33 04 C1 A8 .*....@..'..3...
191 // 0020: 33 58 00 17 04 18 6F A2 83 CB 00 1E D1 BA 50 18 3X....o.......P.
192 // 0030: 20 00 8A 9A 00 00 03 FF FF 12 A0 00 00 04 00 00 ...............
193 // --------------------------- || || -------------------------------------
194 // 0040: 03 04 40 04 11 00 20 01 07 00 00 00 18 00 00 10 ..@... .........
195
196 if(j == 255 && i == 255) {
197 j = -1;
198 continue;
199 }
200 baosin.write(i);
201 // check for end of record EOR and IAC - FFEF
202 if(j == 255 && i == 239)
203 done = true;
204
205 // This is to check for the TELNET TIMING MARK OPTION
206 // rfc860 explains this in more detail. When we receive it
207 // we will negotiate with the server by sending a WONT'T TIMING-MARK
208 // This will let the server know that we processed the information
209 // and are just waiting for the user to enter some data so keep the
210 // socket alive. This is more or less a AYT (ARE YOU THERE) or not.
211 if(i == 253 && j == 255) {
212 done = true;
213 negotiate = true;
214 }
215 j = i;
216 }
217
218 // after the initial negotiation we might get other options such as
219 // timing marks ?????????????? do we ???????????? look at telnet spec
220 // yes we do. rfc860 explains about timing marks.
221
222 // WVL - LDC : 17/05/2004 : Device name negotiations send TIMING MARK
223 // to existing device!
224 // Handled incorrectly: we cannot continue processing the TIMING MARK DO
225 // after we have handled it in the vt.negotiate()
226 // We should not return the bytes;
227 // ==> restructured to return null after negotiation!
228 // Impacts the run method! Added the null check.
229 byte[] rBytes = baosin.toByteArray();
230
231 if (dumpBytes) {
232 dump(rBytes);
233 }
234
235 if (negotiate) {
236 // get the negotiation option
237 baosin.write(bin.read());
238 vt.negotiate(rBytes);
239
240 return null;
241 }
242 return rBytes;
243 }
244
245 protected final void toggleDebug (ICodePage cp) {
246
247 if (codePage == null)
248 codePage = cp;
249
250 dumpBytes = !dumpBytes;
251 if (dumpBytes) {
252
253 try {
254 if (fw == null) {
255 fw = new FileOutputStream("log.txt");
256 dw = new BufferedOutputStream(fw);
257 }
258 }
259 catch (FileNotFoundException fnfe) {
260 log.warn(fnfe.getMessage());
261 }
262
263 }
264 else {
265
266 try {
267
268 if (dw != null)
269 dw.close();
270 if (fw != null)
271 fw.close();
272 dw = null;
273 fw = null;
274 codePage = null;
275 }
276 catch(IOException ioe) {
277
278 log.warn(ioe.getMessage());
279 }
280 }
281
282 log.info("Data Stream output is now " + dumpBytes);
283 }
284
285 public void dump (byte[] abyte0) {
286 try {
287
288 log.info("\n Buffer Dump of data from AS400: ");
289 dw.write("\r\n Buffer Dump of data from AS400: ".getBytes());
290
291 StringBuffer h = new StringBuffer();
292 for (int x = 0; x < abyte0.length; x++) {
293 if (x % 16 == 0) {
294 System.out.println(" " + h.toString());
295 dw.write((" " + h.toString() + "\r\n").getBytes());
296
297 h.setLength(0);
298 h.append("+0000");
299 h.setLength(5 - Integer.toHexString(x).length());
300 h.append(Integer.toHexString(x).toUpperCase());
301
302 System.out.print(h.toString());
303 dw.write(h.toString().getBytes());
304
305 h.setLength(0);
306 }
307 char ac = codePage.ebcdic2uni(abyte0[x]);
308 if (ac < ' ')
309 h.append('.');
310 else
311 h.append(ac);
312 if (x % 4 == 0) {
313 System.out.print(" ");
314 dw.write((" ").getBytes());
315
316 }
317
318 if (Integer.toHexString(abyte0[x] & 0xff).length() == 1){
319 System.out.print("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase());
320 dw.write(("0" + Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes());
321
322 }
323 else {
324 System.out.print(Integer.toHexString(abyte0[x] & 0xff).toUpperCase());
325 dw.write((Integer.toHexString(abyte0[x] & 0xff).toUpperCase()).getBytes());
326 }
327
328 }
329 System.out.println();
330 dw.write("\r\n".getBytes());
331
332 dw.flush();
333 }
334 catch(EOFException _ex) { }
335 catch(Exception _ex) {
336 log.warn("Cannot dump from host\n\r");
337 }
338
339 }
340
341 // public void dumpBytes() {
342 // byte shit[] = bk.buffer;
343 // for (int i = 0;i < shit.length;i++)
344 // System.out.println(i + ">" + shit[i] + "< - ascii - >" + getASCIIChar(shit[i]) + "<");
345 // }
346 //
347 // public void dumpHexBytes(byte[] abyte) {
348 // byte shit[] = abyte;
349 // for (int i = 0;i < shit.length;i++)
350 // System.out.println(i + ">" + shit[i] + "< hex >" + Integer.toHexString((shit[i] & 0xff)));
351 // }
352
353 }