source: other-projects/trunk/gs3-release-maker/tasks/sshtaskdef/src/mindbright/vnc/rfbProto.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 18.6 KB
Line 
1//
2// Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
3//
4// This is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This software is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this software; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17// USA.
18//
19
20//
21// rfbProto.java
22//
23package mindbright.vnc;
24
25import java.io.*;
26import java.awt.*;
27import java.net.Socket;
28
29import mindbright.ssh.*;
30import mindbright.application.MindVNC;
31
32/*
33class myInputStream extends FilterInputStream {
34 public myInputStream(InputStream in) {
35 super(in);
36 }
37 public int read(byte[] b, int off, int len) throws IOException {
38 System.out.println("read(byte[] b, int off, int len) called");
39 return super.read(b, off, len);
40 }
41}
42*/
43
44public class rfbProto {
45
46 final String versionMsg = "RFB 003.003\n";
47 final int ConnFailed = 0, NoAuth = 1, VncAuth = 2;
48 final int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2;
49
50 final int FramebufferUpdate = 0, SetColourMapEntries = 1, Bell = 2,
51 ServerCutText = 3;
52
53 final int SetPixelFormat = 0, FixColourMapEntries = 1, SetEncodings = 2,
54 FramebufferUpdateRequest = 3, KeyEvent = 4, PointerEvent = 5,
55 ClientCutText = 6;
56
57 final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2,
58 EncodingCoRRE = 4, EncodingHextile = 5;
59
60 final int HextileRaw = (1 << 0);
61 final int HextileBackgroundSpecified = (1 << 1);
62 final int HextileForegroundSpecified = (1 << 2);
63 final int HextileAnySubrects = (1 << 3);
64 final int HextileSubrectsColoured = (1 << 4);
65
66 String vncHost;
67 int vncPort;
68
69 SSHSocket sock;
70 SSHSocketFactory fact;
71
72 DataInputStream is;
73 OutputStream os;
74 public boolean inNormalProtocol = false;
75 MindVNC v;
76
77
78 //
79 // Constructor. Just make TCP connection to RFB server.
80 //
81
82 public rfbProto(String sshHost, int sshPort, String sshUser, String sshPasswd,
83 String vncHost, int vncPort, MindVNC v1) throws IOException {
84 v = v1;
85
86 this.vncHost = vncHost;
87 this.vncPort = vncPort;
88
89 fact = new SSHSocketFactory(sshHost, sshPort, new SSHPasswordAuthenticator(sshUser, sshPasswd));
90
91 sock = fact.createSocket(vncHost, vncPort);
92
93 is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
94 16384));
95 os = sock.getOutputStream();
96 }
97
98
99 public void close() {
100 try {
101 sock.close();
102 } catch (Exception e) {
103 e.printStackTrace();
104 }
105 }
106
107 //
108 // Read server's protocol version message
109 //
110
111 int serverMajor, serverMinor;
112
113 void readVersionMsg() throws IOException {
114
115 byte[] b = new byte[12];
116
117 is.readFully(b);
118
119 if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ')
120 || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9')
121 || (b[6] < '0') || (b[6] > '9') || (b[7] != '.')
122 || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9')
123 || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
124 {
125 throw new IOException("Host " + vncHost + " port " + vncPort +
126 " is not an RFB server");
127 }
128
129 serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
130 serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
131 }
132
133 public boolean connectAndAuthenticate(authenticationPanel authenticator) throws IOException {
134 boolean authenticationDone = false;
135
136 readVersionMsg();
137
138 System.out.println("RFB server supports protocol version " +
139 serverMajor + "." + serverMinor);
140
141 writeVersionMsg();
142
143 switch (readAuthScheme()) {
144
145 case NoAuth:
146 System.out.println("No authentication needed");
147 authenticationDone = true;
148 break;
149
150 case VncAuth:
151 byte[] challenge = new byte[16];
152 is.readFully(challenge);
153
154 String pw = authenticator.vncPassword.getText();
155 if (pw.length() > 8) pw = pw.substring(0,8); // truncate to 8 chars
156
157 byte[] key = new byte[8];
158 pw.getBytes(0, pw.length(), key, 0);
159
160 for (int i = pw.length(); i < 8; i++) {
161 key[i] = (byte)0;
162 }
163
164 DesCipher des = new DesCipher(key);
165
166 des.encrypt(challenge,0,challenge,0);
167 des.encrypt(challenge,8,challenge,8);
168
169 os.write(challenge);
170
171 int authResult = is.readInt();
172
173 switch (authResult) {
174 case VncAuthOK:
175 System.out.println("VNC authentication succeeded");
176 authenticationDone = true;
177 break;
178 case VncAuthFailed:
179 System.out.println("VNC authentication failed");
180 authenticator.retry("VNC access denied");
181 break;
182 case VncAuthTooMany:
183 throw new IOException("VNC authentication failed - " +
184 "too many tries");
185 default:
186 throw new IOException("Unknown VNC authentication result " +
187 authResult);
188 }
189 break;
190 }
191
192 return authenticationDone;
193 }
194
195
196 //
197 // Write our protocol version message
198 //
199
200 void writeVersionMsg() throws IOException {
201 byte[] b = new byte[12];
202 versionMsg.getBytes(0, 12, b, 0);
203 os.write(b);
204 }
205
206
207 //
208 // Find out the authentication scheme.
209 //
210
211 int readAuthScheme() throws IOException {
212 int authScheme = is.readInt();
213
214 switch (authScheme) {
215
216 case ConnFailed:
217 int reasonLen = is.readInt();
218 byte[] reason = new byte[reasonLen];
219 is.readFully(reason);
220 throw new IOException(new String(reason, 0));
221
222 case NoAuth:
223 case VncAuth:
224 return authScheme;
225
226 default:
227 throw new IOException("Unknown authentication scheme from RFB " +
228 "server " + authScheme);
229
230 }
231 }
232
233
234 //
235 // Do the rest of the protocol initialisation.
236 //
237
238 public void doProtocolInitialisation(int[] encodings, int nEncodings) throws IOException {
239 System.out.println("sending client init");
240
241 writeClientInit();
242
243 readServerInit();
244
245 System.out.println("Desktop name is " + desktopName);
246 System.out.println("Desktop size is " + framebufferWidth + " x " +
247 framebufferHeight);
248
249 setEncodings(encodings, nEncodings);
250 }
251
252 //
253 // setEncodings() - send the current encodings from the options frame
254 // to the RFB server.
255 //
256
257 void setEncodings(int[] encodings, int nEncodings) {
258 try {
259 if (inNormalProtocol) {
260 writeSetEncodings(encodings, nEncodings);
261 }
262 } catch (Exception e) {
263 e.printStackTrace();
264 }
265 }
266
267 //
268 // Write the client initialisation message
269 //
270
271
272 void writeClientInit() throws IOException {
273 if (v.options.shareDesktop) {
274 os.write(1);
275 } else {
276 os.write(0);
277 }
278 v.options.disableShareDesktop();
279 }
280
281
282 //
283 // Read the server initialisation message
284 //
285
286 public String desktopName;
287 public int framebufferWidth, framebufferHeight;
288 int bitsPerPixel, depth;
289 boolean bigEndian, trueColour;
290 int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
291
292 void readServerInit() throws IOException {
293 framebufferWidth = is.readUnsignedShort();
294 framebufferHeight = is.readUnsignedShort();
295 bitsPerPixel = is.readUnsignedByte();
296 depth = is.readUnsignedByte();
297 bigEndian = (is.readUnsignedByte() != 0);
298 trueColour = (is.readUnsignedByte() != 0);
299 redMax = is.readUnsignedShort();
300 greenMax = is.readUnsignedShort();
301 blueMax = is.readUnsignedShort();
302 redShift = is.readUnsignedByte();
303 greenShift = is.readUnsignedByte();
304 blueShift = is.readUnsignedByte();
305 byte[] pad = new byte[3];
306 is.read(pad);
307 int nameLength = is.readInt();
308 byte[] name = new byte[nameLength];
309 is.readFully(name);
310 desktopName = new String(name, 0);
311
312 inNormalProtocol = true;
313 }
314
315
316 //
317 // Read the server message type
318 //
319
320 int readServerMessageType() throws IOException {
321 return is.read();
322 }
323
324
325 //
326 // Read a FramebufferUpdate message
327 //
328
329 int updateNRects;
330
331 void readFramebufferUpdate() throws IOException {
332 is.readByte();
333 updateNRects = is.readUnsignedShort();
334 }
335
336 // Read a FramebufferUpdate rectangle header
337
338 int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
339
340 void readFramebufferUpdateRectHdr() throws IOException {
341 updateRectX = is.readUnsignedShort();
342 updateRectY = is.readUnsignedShort();
343 updateRectW = is.readUnsignedShort();
344 updateRectH = is.readUnsignedShort();
345 updateRectEncoding = is.readInt();
346
347 if ((updateRectX + updateRectW > framebufferWidth) ||
348 (updateRectY + updateRectH > framebufferHeight)) {
349 throw new IOException("Framebuffer update rectangle too large: " +
350 updateRectW + "x" + updateRectH + " at (" +
351 updateRectX + "," + updateRectY + ")");
352 }
353 }
354
355 // Read CopyRect source X and Y.
356
357 int copyRectSrcX, copyRectSrcY;
358
359 void readCopyRect() throws IOException {
360 copyRectSrcX = is.readUnsignedShort();
361 copyRectSrcY = is.readUnsignedShort();
362 }
363
364
365 //
366 // Read a ServerCutText message
367 //
368
369 String readServerCutText() throws IOException {
370 byte[] pad = new byte[3];
371 is.read(pad);
372 int len = is.readInt();
373 byte[] text = new byte[len];
374 is.readFully(text);
375 return new String(text, 0);
376 }
377
378
379 //
380 // Write a FramebufferUpdateRequest message
381 //
382
383 void writeFramebufferUpdateRequest(int x, int y, int w, int h,
384 boolean incremental)
385 throws IOException
386 {
387 byte[] b = new byte[10];
388
389 b[0] = (byte) FramebufferUpdateRequest;
390 b[1] = (byte) (incremental ? 1 : 0);
391 b[2] = (byte) ((x >> 8) & 0xff);
392 b[3] = (byte) (x & 0xff);
393 b[4] = (byte) ((y >> 8) & 0xff);
394 b[5] = (byte) (y & 0xff);
395 b[6] = (byte) ((w >> 8) & 0xff);
396 b[7] = (byte) (w & 0xff);
397 b[8] = (byte) ((h >> 8) & 0xff);
398 b[9] = (byte) (h & 0xff);
399
400 os.write(b);
401 }
402
403
404 //
405 // Write a SetPixelFormat message
406 //
407
408 void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
409 boolean trueColour,
410 int redMax, int greenMax, int blueMax,
411 int redShift, int greenShift, int blueShift)
412 throws IOException
413 {
414 byte[] b = new byte[20];
415
416 b[0] = (byte) SetPixelFormat;
417 b[4] = (byte) bitsPerPixel;
418 b[5] = (byte) depth;
419 b[6] = (byte) (bigEndian ? 1 : 0);
420 b[7] = (byte) (trueColour ? 1 : 0);
421 b[8] = (byte) ((redMax >> 8) & 0xff);
422 b[9] = (byte) (redMax & 0xff);
423 b[10] = (byte) ((greenMax >> 8) & 0xff);
424 b[11] = (byte) (greenMax & 0xff);
425 b[12] = (byte) ((blueMax >> 8) & 0xff);
426 b[13] = (byte) (blueMax & 0xff);
427 b[14] = (byte) redShift;
428 b[15] = (byte) greenShift;
429 b[16] = (byte) blueShift;
430
431 os.write(b);
432 }
433
434
435 //
436 // Write a FixColourMapEntries message. The values in the red, green and
437 // blue arrays are from 0 to 65535.
438 //
439
440 void writeFixColourMapEntries(int firstColour, int nColours,
441 int[] red, int[] green, int[] blue)
442 throws IOException
443 {
444 byte[] b = new byte[6 + nColours * 6];
445
446 b[0] = (byte) FixColourMapEntries;
447 b[2] = (byte) ((firstColour >> 8) & 0xff);
448 b[3] = (byte) (firstColour & 0xff);
449 b[4] = (byte) ((nColours >> 8) & 0xff);
450 b[5] = (byte) (nColours & 0xff);
451
452 for (int i = 0; i < nColours; i++) {
453 b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
454 b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
455 b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
456 b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
457 b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
458 b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
459 }
460
461 os.write(b);
462 }
463
464
465 //
466 // Write a SetEncodings message
467 //
468
469 void writeSetEncodings(int[] encs, int len) throws IOException {
470 byte[] b = new byte[4 + 4 * len];
471
472 b[0] = (byte) SetEncodings;
473 b[2] = (byte) ((len >> 8) & 0xff);
474 b[3] = (byte) (len & 0xff);
475
476 for (int i = 0; i < len; i++) {
477 b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
478 b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
479 b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
480 b[7 + 4 * i] = (byte) (encs[i] & 0xff);
481 }
482
483 os.write(b);
484 }
485
486
487 //
488 // Write a ClientCutText message
489 //
490
491 public void writeClientCutText(String text) throws IOException {
492 byte[] b = new byte[8 + text.length()];
493
494 b[0] = (byte) ClientCutText;
495 b[4] = (byte) ((text.length() >> 24) & 0xff);
496 b[5] = (byte) ((text.length() >> 16) & 0xff);
497 b[6] = (byte) ((text.length() >> 8) & 0xff);
498 b[7] = (byte) (text.length() & 0xff);
499
500 text.getBytes(0, text.length(), b, 8);
501
502 os.write(b);
503 }
504
505
506 //
507 // A buffer for putting pointer and keyboard events before being sent. This
508 // is to ensure that multiple RFB events generated from a single Java Event
509 // will all be sent in a single network packet. The maximum possible
510 // length is 4 modifier down events, a single key event followed by 4
511 // modifier up events i.e. 9 key events or 72 bytes.
512 //
513
514 byte[] eventBuf = new byte[72];
515 int eventBufLen;
516
517
518 //
519 // Write a pointer event message. We may need to send modifier key events
520 // around it to set the correct modifier state. Also buttons 2 and 3 are
521 // represented as having ALT and META modifiers respectively.
522 //
523
524 int pointerMask = 0;
525
526 void writePointerEvent(Event evt)
527 throws IOException
528 {
529 byte[] b = new byte[6];
530
531 if (evt.id == Event.MOUSE_DOWN) {
532 pointerMask = 1;
533 if ((evt.modifiers & Event.ALT_MASK) != 0) {
534 if (v.options.reverseMouseButtons2And3)
535 pointerMask = 4;
536 else
537 pointerMask = 2;
538 }
539 if ((evt.modifiers & Event.META_MASK) != 0) {
540 if (v.options.reverseMouseButtons2And3)
541 pointerMask = 2;
542 else
543 pointerMask = 4;
544 }
545 } else if (evt.id == Event.MOUSE_UP) {
546 pointerMask = 0;
547 }
548
549 evt.modifiers &= ~(Event.ALT_MASK|Event.META_MASK);
550
551 eventBufLen = 0;
552
553 writeModifierKeyEvents(evt.modifiers);
554
555 if (evt.x < 0) evt.x = 0;
556 if (evt.y < 0) evt.y = 0;
557
558 eventBuf[eventBufLen++] = (byte) PointerEvent;
559 eventBuf[eventBufLen++] = (byte) pointerMask;
560 eventBuf[eventBufLen++] = (byte) ((evt.x >> 8) & 0xff);
561 eventBuf[eventBufLen++] = (byte) (evt.x & 0xff);
562 eventBuf[eventBufLen++] = (byte) ((evt.y >> 8) & 0xff);
563 eventBuf[eventBufLen++] = (byte) (evt.y & 0xff);
564
565 //
566 // Always release all modifiers after an "up" event
567 //
568
569 if (pointerMask == 0) {
570 writeModifierKeyEvents(0);
571 }
572
573 os.write(eventBuf, 0, eventBufLen);
574 }
575
576
577 //
578 // Write a key event message. We may need to send modifier key events
579 // around it to set the correct modifier state. Also we need to translate
580 // from the Java key values to the X keysym values used by the RFB protocol.
581 //
582
583 public void sendCtrlAltDel() {
584 try {
585 Event ctrlAltDelEvent = new Event(null, 0, null);
586 ctrlAltDelEvent.key = 127;
587 ctrlAltDelEvent.modifiers = Event.CTRL_MASK | Event.ALT_MASK;
588 ctrlAltDelEvent.id = Event.KEY_PRESS;
589 writeKeyEvent(ctrlAltDelEvent);
590 ctrlAltDelEvent.id = Event.KEY_RELEASE;
591 writeKeyEvent(ctrlAltDelEvent);
592 } catch (Exception e) {
593 e.printStackTrace();
594 }
595 }
596
597 void writeKeyEvent(Event evt)
598 throws IOException
599 {
600 int key = evt.key;
601 boolean down = false;
602
603 if ((evt.id == Event.KEY_PRESS) || (evt.id == Event.KEY_ACTION))
604 down = true;
605
606 if ((evt.id == Event.KEY_ACTION) || (evt.id == Event.KEY_ACTION_RELEASE)) {
607
608 //
609 // A KEY_ACTION event should be one of the following. If not then just
610 // ignore the event.
611 //
612
613 switch(key) {
614 case Event.HOME: key = 0xff50; break;
615 case Event.LEFT: key = 0xff51; break;
616 case Event.UP: key = 0xff52; break;
617 case Event.RIGHT: key = 0xff53; break;
618 case Event.DOWN: key = 0xff54; break;
619 case Event.PGUP: key = 0xff55; break;
620 case Event.PGDN: key = 0xff56; break;
621 case Event.END: key = 0xff57; break;
622 case Event.F1: key = 0xffbe; break;
623 case Event.F2: key = 0xffbf; break;
624 case Event.F3: key = 0xffc0; break;
625 case Event.F4: key = 0xffc1; break;
626 case Event.F5: key = 0xffc2; break;
627 case Event.F6: key = 0xffc3; break;
628 case Event.F7: key = 0xffc4; break;
629 case Event.F8: key = 0xffc5; break;
630 case Event.F9: key = 0xffc6; break;
631 case Event.F10: key = 0xffc7; break;
632 case Event.F11: key = 0xffc8; break;
633 case Event.F12: key = 0xffc9; break;
634 default:
635 return;
636 }
637
638 } else {
639
640 //
641 // A "normal" key press. Ordinary ASCII characters go straight through.
642 // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
643 // Backspace, tab, return, escape and delete have special keysyms.
644 // Anything else we ignore.
645 //
646
647 if (key < 32) {
648 if ((evt.modifiers & Event.CTRL_MASK) != 0) {
649 key += 96;
650 } else {
651 switch(key) {
652 case 8: key = 0xff08; break;
653 case 9: key = 0xff09; break;
654 case 10: key = 0xff0d; break;
655 case 27: key = 0xff1b; break;
656 }
657 }
658 } else if (key >= 127) {
659 if (key == 127) {
660 key = 0xffff;
661 } else {
662 // JDK1.1 on X incorrectly passes some keysyms straight through, so
663 // we do too. JDK1.1.4 seems to have fixed this.
664 if ((key < 0xff00) || (key > 0xffff))
665 return;
666 }
667 }
668 }
669
670 eventBufLen = 0;
671
672 writeModifierKeyEvents(evt.modifiers);
673
674 writeKeyEvent(key, down);
675
676 //
677 // Always release all modifiers after an "up" event
678 //
679
680 if (!down) {
681 writeModifierKeyEvents(0);
682 }
683
684 os.write(eventBuf, 0, eventBufLen);
685 }
686
687
688 //
689 // Add a raw key event with the given X keysym to eventBuf.
690 //
691
692 void writeKeyEvent(int keysym, boolean down)
693 throws IOException
694 {
695 eventBuf[eventBufLen++] = (byte) KeyEvent;
696 eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
697 eventBuf[eventBufLen++] = (byte) 0;
698 eventBuf[eventBufLen++] = (byte) 0;
699 eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
700 eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
701 eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
702 eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
703 }
704
705
706 //
707 // Write key events to set the correct modifier state.
708 //
709
710 int oldModifiers;
711
712 void writeModifierKeyEvents(int newModifiers)
713 throws IOException
714 {
715 if ((newModifiers & Event.CTRL_MASK) != (oldModifiers & Event.CTRL_MASK))
716 writeKeyEvent(0xffe3, (newModifiers & Event.CTRL_MASK) != 0);
717
718 if ((newModifiers & Event.SHIFT_MASK) != (oldModifiers & Event.SHIFT_MASK))
719 writeKeyEvent(0xffe1, (newModifiers & Event.SHIFT_MASK) != 0);
720
721 if ((newModifiers & Event.META_MASK) != (oldModifiers & Event.META_MASK))
722 writeKeyEvent(0xffe7, (newModifiers & Event.META_MASK) != 0);
723
724 if ((newModifiers & Event.ALT_MASK) != (oldModifiers & Event.ALT_MASK))
725 writeKeyEvent(0xffe9, (newModifiers & Event.ALT_MASK) != 0);
726
727 oldModifiers = newModifiers;
728 }
729}
Note: See TracBrowser for help on using the repository browser.