blob: 4afad7191d2abcd427f3abd0bcd181aec70a8b64 [file] [log] [blame]
Constantin Kaplinsky1215b992008-04-18 09:51:44 +00001//
Constantin Kaplinsky8920b552008-06-18 06:08:59 +00002// Copyright (C) 2008 Wimba, Inc. All Rights Reserved.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +00003// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
4// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
5// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
6// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
7//
8// This is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 2 of the License, or
11// (at your option) any later version.
12//
13// This software is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this software; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21// USA.
22//
23
24//
25// RfbProto.java
26//
27
Constantin Kaplinskycf689b32008-04-30 12:50:34 +000028package com.tightvnc.rfbplayer;
wimba.comc23aeb02004-09-16 00:00:00 +000029
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000030import java.io.*;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000031import java.net.*;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000032
33class RfbProto {
34
Constantin Kaplinsky8920b552008-06-18 06:08:59 +000035 final static String versionMsg = "RFB 003.003\n";
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000036
Constantin Kaplinsky8920b552008-06-18 06:08:59 +000037 final static int ConnFailed = 0;
38 final static int NoAuth = 1;
39 final static int VncAuth = 2;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000040
Constantin Kaplinsky8920b552008-06-18 06:08:59 +000041 final static int VncAuthOK = 0;
42 final static int VncAuthFailed = 1;
43 final static int VncAuthTooMany = 2;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000044
Constantin Kaplinsky8920b552008-06-18 06:08:59 +000045 final static int FramebufferUpdate = 0;
46 final static int SetColourMapEntries = 1;
47 final static int Bell = 2;
48 final static int ServerCutText = 3;
49
50 final static int SetPixelFormat = 0;
51 final static int FixColourMapEntries = 1;
52 final static int SetEncodings = 2;
53 final static int FramebufferUpdateRequest = 3;
54 final static int KeyboardEvent = 4;
55 final static int PointerEvent = 5;
56 final static int ClientCutText = 6;
57
58 final static int EncodingRaw = 0;
59 final static int EncodingCopyRect = 1;
60 final static int EncodingRRE = 2;
61 final static int EncodingCoRRE = 4;
62 final static int EncodingHextile = 5;
63 final static int EncodingZlib = 6;
64 final static int EncodingTight = 7;
65 final static int EncodingCompressLevel0 = 0xFFFFFF00;
66 final static int EncodingQualityLevel0 = 0xFFFFFFE0;
67 final static int EncodingXCursor = 0xFFFFFF10;
68 final static int EncodingRichCursor = 0xFFFFFF11;
69 final static int EncodingPointerPos = 0xFFFFFF18;
70 final static int EncodingLastRect = 0xFFFFFF20;
71 final static int EncodingNewFBSize = 0xFFFFFF21;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000072
wimba.com93cc0db2004-10-13 16:19:45 +000073 final static int MaxNormalEncoding = 7;
74
Constantin Kaplinsky8920b552008-06-18 06:08:59 +000075 final static int HextileRaw = (1 << 0);
76 final static int HextileBackgroundSpecified = (1 << 1);
77 final static int HextileForegroundSpecified = (1 << 2);
78 final static int HextileAnySubrects = (1 << 3);
79 final static int HextileSubrectsColoured = (1 << 4);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000080
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000081 final static int TightExplicitFilter = 0x04;
82 final static int TightFill = 0x08;
83 final static int TightJpeg = 0x09;
84 final static int TightMaxSubencoding = 0x09;
85 final static int TightFilterCopy = 0x00;
86 final static int TightFilterPalette = 0x01;
87 final static int TightFilterGradient = 0x02;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000088
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000089 final static int TightMinToCompress = 12;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000090
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000091 FbsInputStream fbs;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000092 DataInputStream is;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000093
94
95 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000096 // Constructor.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000097 //
Constantin Kaplinsky285809b2008-06-17 10:31:41 +000098 RfbProto(URL url, long timeOffset) throws Exception {
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000099 fbs = null;
Constantin Kaplinsky285809b2008-06-17 10:31:41 +0000100 newSession(url, timeOffset);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000101 }
102
wimba.comd1f56df2004-11-01 16:18:54 +0000103 // Force processing to quit
104 public void quit() {
105 fbs.quit();
106 try {
wimba.com30ff9ed2004-11-01 20:54:08 +0000107 fbs.close();
wimba.comd1f56df2004-11-01 16:18:54 +0000108 } catch (IOException e) {
109 System.out.println("IOException quitting RfbProto: " + e);
110 }
111 }
112
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000113 //
114 // Open new session URL.
115 //
Constantin Kaplinsky285809b2008-06-17 10:31:41 +0000116 public void newSession(URL url, long timeOffset) throws Exception {
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000117 if (fbs != null)
118 fbs.close();
wimba.com9831b812007-11-14 22:25:34 +0000119
wimba.com5cf6b2a2008-01-02 21:50:38 +0000120 // open the connection, and use caching
wimba.com9831b812007-11-14 22:25:34 +0000121 URLConnection connection = url.openConnection();
wimba.com5cf6b2a2008-01-02 21:50:38 +0000122 connection.setUseCaches(true);
wimba.com9831b812007-11-14 22:25:34 +0000123
124 fbs = new FbsInputStream(connection.getInputStream());
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000125 is = new DataInputStream(fbs);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000126
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000127 readVersionMsg();
128 if (readAuthScheme() != NoAuth) {
Constantin Kaplinskyf392f442002-05-20 13:05:42 +0000129 throw new Exception("Wrong authentication type in the session file");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000130 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000131 readServerInit();
Constantin Kaplinsky285809b2008-06-17 10:31:41 +0000132
133 // Go to initial position but make sure not to seek backwards.
134 if (timeOffset > fbs.getTimeOffset()) {
135 fbs.setTimeOffset(timeOffset);
136 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000137 }
138
139 //
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000140 // Read server's protocol version message.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000141 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000142 int serverMajor, serverMinor;
143
144 void readVersionMsg() throws IOException {
145
146 byte[] b = new byte[12];
147
wimba.comc23aeb02004-09-16 00:00:00 +0000148 for (int i = 0; i < b.length; i++)
149 b[i] = (byte)'0';
150
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000151 is.readFully(b);
152
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000153 if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') ||
154 (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') || (b[6] <
155 '0') || (b[6] > '9') || (b[7] != '.') || (b[8] < '0') || (b[8] > '9') ||
156 (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') ||
157 (b[11] != '\n')) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000158 throw new IOException("Incorrect protocol version");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000159 }
160
161 serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
162 serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
163 }
164
165
166 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000167 // Find out the authentication scheme.
168 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000169 int readAuthScheme() throws IOException {
170 int authScheme = is.readInt();
171
172 switch (authScheme) {
173
174 case ConnFailed:
175 int reasonLen = is.readInt();
176 byte[] reason = new byte[reasonLen];
177 is.readFully(reason);
178 throw new IOException(new String(reason));
179
180 case NoAuth:
181 case VncAuth:
182 return authScheme;
183
184 default:
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000185 throw new IOException("Unknown authentication scheme " + authScheme);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000186
187 }
188 }
189
190
191 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000192 // Read the server initialisation message
193 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000194 String desktopName;
195 int framebufferWidth, framebufferHeight;
196 int bitsPerPixel, depth;
197 boolean bigEndian, trueColour;
198 int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
199
Constantin Kaplinskyf392f442002-05-20 13:05:42 +0000200 void readServerInit() throws Exception {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000201 framebufferWidth = is.readUnsignedShort();
202 framebufferHeight = is.readUnsignedShort();
203 bitsPerPixel = is.readUnsignedByte();
204 depth = is.readUnsignedByte();
205 bigEndian = (is.readUnsignedByte() != 0);
206 trueColour = (is.readUnsignedByte() != 0);
207 redMax = is.readUnsignedShort();
208 greenMax = is.readUnsignedShort();
209 blueMax = is.readUnsignedShort();
210 redShift = is.readUnsignedByte();
211 greenShift = is.readUnsignedByte();
212 blueShift = is.readUnsignedByte();
213 byte[] pad = new byte[3];
214 is.readFully(pad);
215 int nameLength = is.readInt();
216 byte[] name = new byte[nameLength];
217 is.readFully(name);
218 desktopName = new String(name);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000219 }
220
221
222 //
223 // Set new framebuffer size
224 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000225 void setFramebufferSize(int width, int height) {
226 framebufferWidth = width;
227 framebufferHeight = height;
228 }
229
230
231 //
232 // Read the server message type
233 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000234 int readServerMessageType() throws IOException {
235 return is.readUnsignedByte();
236 }
237
238
239 //
240 // Read a FramebufferUpdate message
241 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000242 int updateNRects;
243
244 void readFramebufferUpdate() throws IOException {
245 is.readByte();
246 updateNRects = is.readUnsignedShort();
247 }
248
249 // Read a FramebufferUpdate rectangle header
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000250 int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
251
252 void readFramebufferUpdateRectHdr() throws IOException {
253 updateRectX = is.readUnsignedShort();
254 updateRectY = is.readUnsignedShort();
255 updateRectW = is.readUnsignedShort();
256 updateRectH = is.readUnsignedShort();
257 updateRectEncoding = is.readInt();
258
wimba.com93cc0db2004-10-13 16:19:45 +0000259 if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000260 return;
261
262 if ((updateRectX + updateRectW > framebufferWidth) ||
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000263 (updateRectY + updateRectH > framebufferHeight)) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000264 throw new IOException("Framebuffer update rectangle too large: " +
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000265 updateRectW + "x" + updateRectH + " at (" +
266 updateRectX + "," + updateRectY + ")");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000267 }
268 }
269
270 // Read CopyRect source X and Y.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000271 int copyRectSrcX, copyRectSrcY;
272
273 void readCopyRect() throws IOException {
274 copyRectSrcX = is.readUnsignedShort();
275 copyRectSrcY = is.readUnsignedShort();
276 }
277
278
279 //
280 // Read a ServerCutText message
281 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000282 String readServerCutText() throws IOException {
283 byte[] pad = new byte[3];
284 is.readFully(pad);
285 int len = is.readInt();
286 byte[] text = new byte[len];
287 is.readFully(text);
288 return new String(text);
289 }
290
291
292 //
293 // Read integer in compact representation
294 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000295 int readCompactLen() throws IOException {
296 int portion = is.readUnsignedByte();
297 int len = portion & 0x7F;
298 if ((portion & 0x80) != 0) {
299 portion = is.readUnsignedByte();
300 len |= (portion & 0x7F) << 7;
301 if ((portion & 0x80) != 0) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000302 portion = is.readUnsignedByte();
303 len |= (portion & 0xFF) << 14;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000304 }
305 }
306 return len;
307 }
308
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000309}