Mercurial > hg > Members > nobuyasu > tightVNCProxy
annotate src/myVncProxy/MyRfbProto.java @ 88:9b3b1e3e7db5
add test routine
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 03 Aug 2011 09:09:39 +0900 |
parents | a8c33757ac99 |
children | 462bca4c8cec |
rev | line source |
---|---|
24 | 1 package myVncProxy; |
54 | 2 |
88 | 3 import static org.junit.Assert.*; |
4 | |
25 | 5 import java.awt.Graphics; |
6 import java.awt.Image; | |
7 import java.awt.image.BufferedImage; | |
8 import java.io.BufferedOutputStream; | |
15 | 9 import java.io.BufferedReader; |
25 | 10 import java.io.ByteArrayInputStream; |
11 import java.io.ByteArrayOutputStream; | |
10 | 12 import java.io.IOException; |
43 | 13 import java.io.InputStream; |
15 | 14 import java.io.InputStreamReader; |
23 | 15 import java.net.BindException; |
10 | 16 import java.net.ServerSocket; |
17 import java.net.Socket; | |
18 import java.util.LinkedList; | |
19 | |
25 | 20 import javax.imageio.ImageIO; |
21 | |
88 | 22 import org.junit.Test; |
23 | |
54 | 24 import myVncProxy.MulticastQueue.Client; |
25 | |
40 | 26 import java.util.concurrent.ExecutorService; |
27 import java.util.concurrent.Executors; | |
80 | 28 import java.util.zip.DataFormatException; |
29 import java.util.zip.Deflater; | |
30 import java.util.zip.Inflater; | |
40 | 31 import java.io.OutputStream; |
10 | 32 |
88 | 33 public |
10 | 34 class MyRfbProto extends RfbProto { |
43 | 35 final static String versionMsg_3_998 = "RFB 003.998\n"; |
65 | 36 /** |
37 * CheckMillis is one of new msgType for RFB 3.998. | |
38 */ | |
77 | 39 final static int SpeedCheckMillis = 4; |
83 | 40 private static final int INFLATE_BUFSIZE = 1024*100; |
65 | 41 boolean printStatusFlag = false; |
42 long startCheckTime; | |
54 | 43 |
18 | 44 private int messageType; |
45 private int rectangles; | |
23 | 46 private int rectX; |
47 private int rectY; | |
48 private int rectW; | |
49 private int rectH; | |
18 | 50 private int encoding; |
27 | 51 private int zLen; |
18 | 52 |
23 | 53 private ServerSocket servSock; |
54 private int acceptPort; | |
10 | 55 private byte initData[]; |
54 | 56 private LinkedList<Socket> cliListTmp; |
57 private LinkedList<Socket> cliList; | |
58 private LinkedList<Thread> sendThreads; | |
27 | 59 boolean createBimgFlag; |
54 | 60 |
40 | 61 ExecutorService executor; |
54 | 62 |
25 | 63 byte[] pngBytes; |
54 | 64 |
84 | 65 private MulticastQueue<LinkedList<byte[]>> multicastqueue = new MostRecentMultiCast<LinkedList<byte[]>>(10); |
80 | 66 private int clients = 0; |
81
9109273b96dc
consume too much memory
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
80
diff
changeset
|
67 private Inflater inflater = new Inflater(); |
54 | 68 |
88 | 69 public |
70 MyRfbProto() throws IOException { | |
71 } | |
72 | |
54 | 73 MyRfbProto(String h, int p, VncViewer v) throws IOException { |
10 | 74 super(h, p, v); |
54 | 75 cliList = new LinkedList<Socket>(); |
76 cliListTmp = new LinkedList<Socket>(); | |
27 | 77 createBimgFlag = false; |
61 | 78 // sendThreads = new LinkedList<Thread>(); |
54 | 79 // executor = Executors.newCachedThreadPool(); |
80 // executor = Executors.newSingleThreadExecutor(); | |
10 | 81 } |
82 | |
13 | 83 MyRfbProto(String h, int p) throws IOException { |
84 super(h, p); | |
54 | 85 cliList = new LinkedList<Socket>(); |
86 cliListTmp = new LinkedList<Socket>(); | |
27 | 87 createBimgFlag = false; |
61 | 88 // sendThreads = new LinkedList<Thread>(); |
54 | 89 // executor = Executors.newCachedThreadPool(); |
90 // executor = Executors.newSingleThreadExecutor(); | |
13 | 91 } |
24 | 92 |
44 | 93 // over write |
43 | 94 void writeVersionMsg() throws IOException { |
95 clientMajor = 3; | |
96 if (serverMinor >= 9) { | |
54 | 97 clientMinor = 9; |
98 os.write(versionMsg_3_998.getBytes()); | |
43 | 99 } else if (serverMajor > 3 || serverMinor >= 8) { |
100 clientMinor = 8; | |
101 os.write(versionMsg_3_8.getBytes()); | |
102 } else if (serverMinor >= 9) { | |
103 clientMinor = 9; | |
104 os.write(versionMsg_3_998.getBytes()); | |
105 } else if (serverMinor >= 7) { | |
106 clientMinor = 7; | |
107 os.write(versionMsg_3_7.getBytes()); | |
108 } else { | |
109 clientMinor = 3; | |
110 os.write(versionMsg_3_3.getBytes()); | |
111 } | |
112 protocolTightVNC = false; | |
113 initCapabilities(); | |
114 } | |
115 | |
54 | 116 void initServSock(int port) throws IOException { |
10 | 117 servSock = new ServerSocket(port); |
23 | 118 acceptPort = port; |
10 | 119 } |
54 | 120 |
121 // 5550を開けるが、開いてないなら+1のポートを開ける。 | |
80 | 122 void selectPort(int p) { |
123 int port = p; | |
54 | 124 while (true) { |
125 try { | |
80 | 126 initServSock(port); |
23 | 127 break; |
54 | 128 } catch (BindException e) { |
80 | 129 port++; |
23 | 130 continue; |
54 | 131 } catch (IOException e) { |
10 | 132 |
23 | 133 } |
134 } | |
80 | 135 System.out.println("accept port = " + port); |
23 | 136 } |
54 | 137 |
138 int getAcceptPort() { | |
23 | 139 return acceptPort; |
140 } | |
54 | 141 |
10 | 142 void setSoTimeout(int num) throws IOException { |
143 servSock.setSoTimeout(num); | |
144 } | |
54 | 145 |
10 | 146 Socket accept() throws IOException { |
147 return servSock.accept(); | |
148 } | |
149 | |
54 | 150 void addSock(Socket sock) { |
10 | 151 cliList.add(sock); |
152 } | |
54 | 153 |
154 void addSockTmp(Socket sock) { | |
155 System.out.println("connected " + sock.getInetAddress()); | |
27 | 156 cliListTmp.add(sock); |
157 } | |
54 | 158 |
10 | 159 boolean markSupported() { |
160 return is.markSupported(); | |
161 } | |
54 | 162 |
10 | 163 void readServerInit() throws IOException { |
54 | 164 |
78 | 165 is.mark(255); |
10 | 166 skipBytes(20); |
167 int nlen = readU32(); | |
54 | 168 int blen = 20 + 4 + nlen; |
10 | 169 initData = new byte[blen]; |
78 | 170 is.reset(); |
10 | 171 |
78 | 172 is.mark(blen); |
10 | 173 readFully(initData); |
78 | 174 is.reset(); |
54 | 175 |
10 | 176 framebufferWidth = readU16(); |
177 framebufferHeight = readU16(); | |
178 bitsPerPixel = readU8(); | |
179 depth = readU8(); | |
180 bigEndian = (readU8() != 0); | |
181 trueColour = (readU8() != 0); | |
182 redMax = readU16(); | |
183 greenMax = readU16(); | |
184 blueMax = readU16(); | |
185 redShift = readU8(); | |
186 greenShift = readU8(); | |
187 blueShift = readU8(); | |
188 byte[] pad = new byte[3]; | |
189 readFully(pad); | |
190 int nameLength = readU32(); | |
191 byte[] name = new byte[nameLength]; | |
192 readFully(name); | |
193 desktopName = new String(name); | |
194 | |
195 // Read interaction capabilities (TightVNC protocol extensions) | |
196 if (protocolTightVNC) { | |
197 int nServerMessageTypes = readU16(); | |
198 int nClientMessageTypes = readU16(); | |
199 int nEncodingTypes = readU16(); | |
200 readU16(); | |
201 readCapabilityList(serverMsgCaps, nServerMessageTypes); | |
202 readCapabilityList(clientMsgCaps, nClientMessageTypes); | |
203 readCapabilityList(encodingCaps, nEncodingTypes); | |
204 } | |
205 | |
206 inNormalProtocol = true; | |
207 } | |
208 | |
54 | 209 void sendRfbVersion(OutputStream os) throws IOException { |
210 os.write(versionMsg_3_998.getBytes()); | |
43 | 211 } |
54 | 212 |
45 | 213 void readVersionMsg(InputStream is) throws IOException { |
214 | |
215 byte[] b = new byte[12]; | |
216 | |
217 is.read(b); | |
218 | |
219 if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') | |
220 || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') | |
221 || (b[6] < '0') || (b[6] > '9') || (b[7] != '.') | |
222 || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') | |
223 || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) { | |
224 throw new IOException("Host " + host + " port " + port | |
225 + " is not an RFB server"); | |
226 } | |
227 | |
228 serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); | |
229 serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0'); | |
230 | |
231 if (serverMajor < 3) { | |
232 throw new IOException( | |
233 "RFB server does not support protocol version 3"); | |
54 | 234 } |
235 | |
236 } | |
237 | |
43 | 238 void sendSecurityType(OutputStream os) throws IOException { |
239 // number-of-security-types | |
240 os.write(1); | |
54 | 241 // security-types |
43 | 242 // 1:None |
243 os.write(1); | |
244 } | |
54 | 245 |
46
11da7dacbc1a
modify MyRfbProto.java and acceptThread.java add readSecType
e085711
parents:
45
diff
changeset
|
246 void readSecType(InputStream is) throws IOException { |
11da7dacbc1a
modify MyRfbProto.java and acceptThread.java add readSecType
e085711
parents:
45
diff
changeset
|
247 byte[] b = new byte[1]; |
11da7dacbc1a
modify MyRfbProto.java and acceptThread.java add readSecType
e085711
parents:
45
diff
changeset
|
248 is.read(b); |
11da7dacbc1a
modify MyRfbProto.java and acceptThread.java add readSecType
e085711
parents:
45
diff
changeset
|
249 |
11da7dacbc1a
modify MyRfbProto.java and acceptThread.java add readSecType
e085711
parents:
45
diff
changeset
|
250 } |
54 | 251 |
47
b2bf4e44504a
modify MyRfbProto.java and acceptThread.java , add sendSecResult
e085711
parents:
46
diff
changeset
|
252 void sendSecResult(OutputStream os) throws IOException { |
b2bf4e44504a
modify MyRfbProto.java and acceptThread.java , add sendSecResult
e085711
parents:
46
diff
changeset
|
253 byte[] b = castIntByte(0); |
b2bf4e44504a
modify MyRfbProto.java and acceptThread.java , add sendSecResult
e085711
parents:
46
diff
changeset
|
254 os.write(b); |
b2bf4e44504a
modify MyRfbProto.java and acceptThread.java , add sendSecResult
e085711
parents:
46
diff
changeset
|
255 } |
54 | 256 |
43 | 257 void readClientInit(InputStream in) throws IOException { |
258 byte[] b = new byte[0]; | |
259 in.read(b); | |
260 } | |
54 | 261 |
262 void sendInitData(OutputStream os) throws IOException { | |
263 os.write(initData); | |
10 | 264 } |
265 | |
54 | 266 |
267 void sendPngImage() { | |
268 try { | |
269 for (Socket cli : cliListTmp) { | |
270 try { | |
27 | 271 sendPngData(cli); |
272 addSock(cli); | |
54 | 273 } catch (IOException e) { |
27 | 274 // if socket closed |
275 cliListTmp.remove(cli); | |
276 } | |
277 } | |
54 | 278 // System.out.println("cliSize="+cliSize()); |
279 } catch (Exception e) { | |
27 | 280 } |
281 cliListTmp.clear(); | |
282 } | |
283 | |
15 | 284 boolean ready() throws IOException { |
285 BufferedReader br = new BufferedReader(new InputStreamReader(is)); | |
286 return br.ready(); | |
54 | 287 } |
10 | 288 |
54 | 289 int cliSize() { |
10 | 290 return cliList.size(); |
54 | 291 } |
292 | |
293 void printNumBytesRead() { | |
294 System.out.println("numBytesRead=" + numBytesRead); | |
295 } | |
296 | |
297 | |
61 | 298 |
54 | 299 void regiFramebufferUpdate() throws IOException { |
78 | 300 is.mark(20); |
80 | 301 messageType = readU8(); // 0 |
302 skipBytes(1); // 1 | |
303 rectangles = readU16(); // 2 | |
304 rectX = readU16(); // 4 | |
305 rectY = readU16(); // 6 | |
306 rectW = readU16(); // 8 | |
307 rectH = readU16(); // 10 | |
308 encoding = readU32(); // 12 | |
78 | 309 System.out.println("encoding = "+encoding); |
80 | 310 if (encoding == EncodingZRLE) |
27 | 311 zLen = readU32(); |
80 | 312 else |
313 zLen = 0; | |
78 | 314 is.reset(); |
67 | 315 /* |
316 int dataLen; | |
317 switch (encoding) { | |
318 case RfbProto.EncodingRaw: | |
319 dataLen = rectW * rectH * 4 + 16; | |
320 mark(dataLen); | |
321 break; | |
322 case RfbProto.EncodingCopyRect: | |
323 dataLen = 16 + 4; | |
324 mark(dataLen); | |
325 break; | |
326 case RfbProto.EncodingRRE: | |
327 case RfbProto.EncodingCoRRE: | |
328 case RfbProto.EncodingHextile: | |
329 | |
330 case RfbProto.EncodingZlib: | |
331 case RfbProto.EncodingTight: | |
332 case RfbProto.EncodingZRLE: | |
333 dataLen = zLen + 20; | |
334 mark(dataLen); | |
335 break; | |
336 default: | |
337 dataLen = 1000000; | |
338 mark(dataLen); | |
339 } | |
340 | |
341 */ | |
342 | |
15 | 343 } |
54 | 344 |
61 | 345 int checkAndMark() throws IOException { |
346 int dataLen; | |
54 | 347 switch (encoding) { |
23 | 348 case RfbProto.EncodingRaw: |
39 | 349 dataLen = rectW * rectH * 4 + 16; |
78 | 350 is.mark(dataLen); |
23 | 351 break; |
67 | 352 case RfbProto.EncodingCopyRect: |
353 dataLen = 16 + 4; | |
78 | 354 is.mark(dataLen); |
67 | 355 break; |
356 case RfbProto.EncodingRRE: | |
357 case RfbProto.EncodingCoRRE: | |
358 case RfbProto.EncodingHextile: | |
80 | 359 case RfbProto.EncodingTight: |
360 dataLen = zLen + 20; | |
361 is.mark(dataLen); | |
362 break; | |
67 | 363 case RfbProto.EncodingZlib: |
27 | 364 case RfbProto.EncodingZRLE: |
54 | 365 dataLen = zLen + 20; |
78 | 366 is.mark(dataLen); |
367 break; | |
368 case RfbProto.EncodingXCursor: | |
369 case RfbProto.EncodingRichCursor: | |
370 int pixArray = rectW * rectH * 4; | |
371 int u8Array = (int)Math.floor((rectW + 7)/8) * rectH; | |
372 dataLen = pixArray + u8Array; | |
373 printFramebufferUpdate(); | |
374 is.mark(dataLen); | |
27 | 375 break; |
23 | 376 default: |
61 | 377 dataLen = 1000000; |
78 | 378 is.mark(dataLen); |
54 | 379 } |
61 | 380 return dataLen; |
381 } | |
65 | 382 |
383 | |
81
9109273b96dc
consume too much memory
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
80
diff
changeset
|
384 void sendDataToClient() throws Exception { |
61 | 385 regiFramebufferUpdate(); |
386 int dataLen = checkAndMark(); | |
387 readSendData(dataLen); | |
23 | 388 } |
54 | 389 |
390 BufferedImage createBufferedImage(Image img) { | |
391 BufferedImage bimg = new BufferedImage(img.getWidth(null), | |
392 img.getHeight(null), BufferedImage.TYPE_INT_RGB); | |
27 | 393 |
25 | 394 Graphics g = bimg.getGraphics(); |
395 g.drawImage(img, 0, 0, null); | |
396 g.dispose(); | |
397 return bimg; | |
398 } | |
399 | |
54 | 400 void createPngBytes(BufferedImage bimg) throws IOException { |
401 pngBytes = getImageBytes(bimg, "png"); | |
25 | 402 } |
54 | 403 |
404 byte[] getBytes(BufferedImage img) throws IOException { | |
25 | 405 byte[] b = getImageBytes(img, "png"); |
406 return b; | |
407 } | |
54 | 408 |
409 byte[] getImageBytes(BufferedImage image, String imageFormat) | |
410 throws IOException { | |
25 | 411 ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
412 BufferedOutputStream os = new BufferedOutputStream(bos); | |
413 image.flush(); | |
414 ImageIO.write(image, imageFormat, os); | |
415 os.flush(); | |
416 os.close(); | |
417 return bos.toByteArray(); | |
418 } | |
419 | |
54 | 420 void sendPngData(Socket sock) throws IOException { |
26 | 421 byte[] dataLength = castIntByte(pngBytes.length); |
422 sock.getOutputStream().write(dataLength); | |
25 | 423 sock.getOutputStream().write(pngBytes); |
424 } | |
54 | 425 |
426 byte[] castIntByte(int len) { | |
26 | 427 byte[] b = new byte[4]; |
54 | 428 b[0] = (byte) ((len >>> 24) & 0xFF); |
429 b[1] = (byte) ((len >>> 16) & 0xFF); | |
430 b[2] = (byte) ((len >>> 8) & 0xFF); | |
431 b[3] = (byte) ((len >>> 0) & 0xFF); | |
26 | 432 return b; |
433 } | |
54 | 434 |
435 BufferedImage createBimg() throws IOException { | |
25 | 436 BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(pngBytes)); |
437 return bimg; | |
438 } | |
65 | 439 /* |
54 | 440 void readPngData() throws IOException { |
25 | 441 pngBytes = new byte[is.available()]; |
442 readFully(pngBytes); | |
443 } | |
65 | 444 */ |
54 | 445 void printFramebufferUpdate() { |
446 | |
18 | 447 System.out.println("messageType=" + messageType); |
54 | 448 System.out.println("rectangles=" + rectangles); |
18 | 449 System.out.println("encoding=" + encoding); |
78 | 450 System.out.println("rectX = "+rectX+": rectY = "+rectY); |
451 System.out.println("rectW = "+rectW+": rectH = "+rectH); | |
54 | 452 switch (encoding) { |
23 | 453 case RfbProto.EncodingRaw: |
54 | 454 System.out.println("rectW * rectH * 4 + 16 =" + rectW * rectH * 4 |
455 + 16); | |
23 | 456 break; |
457 default: | |
458 } | |
18 | 459 } |
65 | 460 |
77 | 461 void readSpeedCheck() throws IOException { |
462 byte[] b = new byte[1]; | |
65 | 463 readFully(b); |
464 } | |
465 | |
77 | 466 void startSpeedCheck() { |
66 | 467 byte[] b = new byte[2]; |
77 | 468 b[0] = (byte) SpeedCheckMillis; |
66 | 469 b[1] = (byte) 0; |
470 startCheckTime = System.currentTimeMillis(); | |
471 System.out.println("startChckTime = "+ startCheckTime); | |
84 | 472 LinkedList<byte[]>bufs = new LinkedList<byte[]>(); |
473 bufs.add(b); | |
474 multicastqueue.put(bufs); | |
65 | 475 } |
476 | |
77 | 477 void endSpeedCheck() { |
65 | 478 long accTime = System.currentTimeMillis(); |
479 long time = accTime - startCheckTime; | |
480 System.out.println("checkMillis: " + time); | |
481 } | |
482 | |
483 void printStatus() { | |
484 System.out.println(); | |
485 } | |
486 | |
487 synchronized void changeStatusFlag() { | |
488 printStatusFlag = true; | |
489 } | |
490 | |
491 void printMills() { | |
492 if(printStatusFlag) { | |
493 | |
494 changeStatusFlag(); | |
495 } else { | |
496 changeStatusFlag(); | |
497 } | |
498 } | |
87 | 499 |
500 void speedCheckMillis() { | |
501 Runnable stdin = new Runnable() { | |
502 public void run() { | |
503 int c; | |
504 try { | |
505 while( (c = System.in.read()) != -1 ) { | |
506 switch(c) { | |
507 case 's': | |
508 break; | |
509 default: | |
510 startSpeedCheck(); | |
511 break; | |
512 } | |
513 } | |
514 }catch(IOException e){ | |
515 System.out.println(e); | |
516 } | |
517 } | |
518 }; | |
519 | |
520 new Thread(stdin).start(); | |
521 } | |
86 | 522 |
87 | 523 /** |
524 * gzip byte arrays | |
525 * @param deflater | |
526 * @param inputs | |
527 * byte len[4] total byte length | |
528 * byte data[] | |
529 * @param outputs | |
530 * byte len[4] total byte length | |
531 * byte data[] | |
532 * @return byte length in last byte array | |
533 * @throws IOException | |
534 */ | |
535 public int zip(Deflater deflater,LinkedList<byte[]> inputs, LinkedList<byte[]> outputs) throws IOException { | |
86 | 536 int clen = u32(inputs.poll(),0); |
537 int len = 0, count = 0; | |
538 int len2=0; | |
539 deflater.reset(); | |
540 do { | |
541 byte[] b1 = inputs.poll(); | |
542 if (inputs.size()==0) { | |
543 deflater.setInput(b1,0,clen); | |
544 deflater.finish(); | |
87 | 545 } else { |
86 | 546 deflater.setInput(b1); |
87 | 547 clen -= b1.length; |
548 } | |
86 | 549 int len1=0; |
550 do { | |
551 byte[] c1 = new byte[INFLATE_BUFSIZE]; | |
552 len2 = len1; | |
553 len1 = deflater.deflate(c1); | |
554 if (len1>0) { | |
555 outputs.addLast(c1); | |
556 count ++; | |
557 len += len1; | |
558 } | |
559 } while (len1 > 0); | |
560 } while(inputs.size()>0); | |
561 byte[] blen = castIntByte(len); | |
562 outputs.addFirst(blen); | |
563 return len2; | |
564 } | |
87 | 565 |
566 /** | |
567 * gunzip byte arrays | |
568 * @param inflater | |
569 * @param inputs | |
570 * byte len[4] total byte length | |
571 * byte data[] | |
572 * @param outputs | |
573 * byte len[4] total byte length | |
574 * byte data[] | |
575 * @throws IOException | |
576 */ | |
88 | 577 public void unzip(Inflater inflater, LinkedList<byte[]> inputs, LinkedList<byte[]> outputs) |
578 throws DataFormatException { | |
86 | 579 int len=0,len0; |
88 | 580 inputs.poll(); |
581 for(byte [] input:inputs) { | |
582 inflater.setInput(input); | |
583 do { | |
584 byte buf[] = new byte[INFLATE_BUFSIZE]; | |
585 len0 = inflater.inflate(buf); | |
586 len += len0; | |
587 outputs.addLast(buf); | |
588 } while (len0 ==INFLATE_BUFSIZE); | |
589 } | |
87 | 590 byte [] blen = castIntByte(len); |
86 | 591 outputs.addFirst(blen); |
592 } | |
65 | 593 |
86 | 594 void readSendData(int dataLen) throws IOException, DataFormatException { |
595 LinkedList<byte[]>bufs = new LinkedList<byte[]>(); | |
87 | 596 byte header[] = new byte[16]; |
597 readFully(header,0,16); | |
598 if (header[0]==RfbProto.FramebufferUpdate) { | |
599 int encoding = u32(header,12); | |
86 | 600 if (encoding==RfbProto.EncodingZlib||encoding==RfbProto.EncodingZRLE) { |
87 | 601 byte[] len = new byte[4]; |
602 readFully(len,0,4); | |
603 byte inputData[] = new byte[dataLen-20]; | |
604 readFully(inputData); | |
88 | 605 LinkedList<byte[]>inputs = new LinkedList<byte[]>(); |
606 inputs.add(len); | |
607 inputs.add(inputData); | |
608 unzip(inflater, inputs, bufs); | |
87 | 609 bufs.addFirst(header); |
86 | 610 multicastqueue.put(bufs); |
611 is.reset(); | |
612 return ; | |
613 } | |
614 } | |
87 | 615 bufs.add(header); |
616 if (dataLen>16) { | |
617 byte b[] = new byte[dataLen-16]; | |
618 readFully(b); | |
619 bufs.add(b); | |
620 } | |
86 | 621 multicastqueue.put(bufs); |
622 is.reset(); | |
623 | |
624 // It may be compressed. We can inflate here to avoid repeating clients decompressing here, | |
625 // but it may generate too many large data. It is better to do it in each client. | |
626 // But we have do inflation for all input data, so we have to do it here. | |
627 } | |
43 | 628 |
71 | 629 void newClient(AcceptThread acceptThread, final Socket newCli, |
54 | 630 final OutputStream os, final InputStream is) throws IOException { |
631 // createBimgFlag = true; | |
632 // rfb.addSockTmp(newCli); | |
633 // addSock(newCli); | |
84 | 634 final Client <LinkedList<byte[]>> c = multicastqueue.newClient(); |
54 | 635 Runnable sender = new Runnable() { |
636 public void run() { | |
80 | 637 |
638 Deflater deflater = new Deflater(); | |
54 | 639 try { |
65 | 640 /** |
641 * initial connection of RFB protocol | |
642 */ | |
54 | 643 sendRfbVersion(os); |
644 readVersionMsg(is); | |
645 sendSecurityType(os); | |
646 readSecType(is); | |
647 sendSecResult(os); | |
648 readClientInit(is); | |
649 sendInitData(os); | |
43 | 650 |
54 | 651 for (;;) { |
84 | 652 LinkedList<byte[]> bufs = c.poll(); |
87 | 653 byte[] header = bufs.poll(); |
654 if (header[0]==RfbProto.FramebufferUpdate) { | |
655 int encoding = u32(header,12); | |
80 | 656 if (encoding==RfbProto.EncodingZlib||encoding==RfbProto.EncodingZRLE) { |
84 | 657 LinkedList<byte[]> outs = new LinkedList<byte[]>(); |
87 | 658 int len2 = zip(deflater, bufs, outs); |
659 outs.addFirst(header); | |
86 | 660 while(!outs.isEmpty()) { |
661 byte [] out= outs.poll(); | |
662 if (outs.isEmpty()) | |
663 os.write(out,0,len2); | |
664 else | |
84 | 665 os.write(out); |
666 } | |
80 | 667 } |
87 | 668 os.flush(); |
669 return; | |
670 } | |
671 os.write(header); | |
672 for(byte [] b : bufs) { | |
80 | 673 os.write(b, 0, b.length); |
84 | 674 } |
85 | 675 os.flush(); |
54 | 676 } |
677 } catch (IOException e) { | |
87 | 678 /* if socket closed cliList.remove(newCli); */ |
54 | 679 } |
680 } | |
681 }; | |
80 | 682 clients++; |
54 | 683 new Thread(sender).start(); |
684 | |
685 } | |
66 | 686 |
84 | 687 private int u32(byte[] b, int i) { |
688 int ret = 0; | |
689 for(int j = 0;j<4;j++) { | |
690 ret *= 256; | |
691 ret += b[i+j] & 0xff; | |
692 } | |
693 return ret; | |
694 } | |
66 | 695 |
88 | 696 |
697 @Test | |
698 public void test1() { | |
699 try { | |
700 LinkedList<byte[]> in = new LinkedList<byte[]>(); | |
701 LinkedList<byte[]> out = new LinkedList<byte[]>(); | |
702 LinkedList<byte[]> out2 = new LinkedList<byte[]>(); | |
703 for(int i=0;i<10;i++) { | |
704 in.add("test1".getBytes()); | |
705 in.add("test1".getBytes()); | |
706 in.add("test1".getBytes()); | |
707 in.add("test1".getBytes()); | |
708 } | |
709 int len = 0; | |
710 for(byte[] b: in) len += b.length; | |
711 in.addFirst(castIntByte(len)); | |
712 | |
713 Deflater deflater = new Deflater(); | |
714 zip(deflater, in,out); | |
715 unzip(inflater, out, out2); | |
716 for(byte[] b:out) { | |
717 byte []c = out2.poll(); | |
718 assertEquals(b,c); | |
719 } | |
720 System.out.println("Test Ok."); | |
721 } catch (Exception e) { | |
722 assertEquals(0,1); | |
723 } | |
724 } | |
725 | |
54 | 726 } |
66 | 727 |
728 |