blob: 080dfad860e4be5941e66c342c890a7ed24a1702 [file] [log] [blame]
Constantin Kaplinsky1215b992008-04-18 09:51:44 +00001//
2// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
3// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
4// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
5// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
6//
7// This is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This software is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this software; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20// USA.
21//
22
23//
24// RfbProto.java
25//
26
Constantin Kaplinskycf689b32008-04-30 12:50:34 +000027package com.tightvnc.rfbplayer;
wimba.comc23aeb02004-09-16 00:00:00 +000028
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000029import java.io.*;
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000030import java.net.*;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000031
32class RfbProto {
33
34 final String versionMsg = "RFB 003.003\n";
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000035 final static int ConnFailed = 0, NoAuth = 1, VncAuth = 2;
36 final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000037
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000038 final static int FramebufferUpdate = 0, SetColourMapEntries = 1, Bell = 2, ServerCutText =
39 3;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000040
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000041 final int SetPixelFormat = 0, FixColourMapEntries = 1, SetEncodings = 2, FramebufferUpdateRequest =
42 3, KeyboardEvent = 4, PointerEvent = 5, ClientCutText = 6;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000043
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000044 final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2, EncodingCoRRE =
45 4, EncodingHextile = 5, EncodingZlib = 6, EncodingTight = 7, EncodingCompressLevel0 =
46 0xFFFFFF00, EncodingQualityLevel0 = 0xFFFFFFE0, EncodingXCursor =
wimba.coma27098c2004-09-21 15:22:02 +000047 0xFFFFFF10, EncodingRichCursor = 0xFFFFFF11, EncodingPointerPos =
48 0xFFFFFF18, EncodingLastRect = 0xFFFFFF20, EncodingNewFBSize =
49 0xFFFFFF21;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000050
wimba.com93cc0db2004-10-13 16:19:45 +000051 final static int MaxNormalEncoding = 7;
52
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000053 final int HextileRaw = (1 << 0);
54 final int HextileBackgroundSpecified = (1 << 1);
55 final int HextileForegroundSpecified = (1 << 2);
56 final int HextileAnySubrects = (1 << 3);
57 final int HextileSubrectsColoured = (1 << 4);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000058
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000059 final static int TightExplicitFilter = 0x04;
60 final static int TightFill = 0x08;
61 final static int TightJpeg = 0x09;
62 final static int TightMaxSubencoding = 0x09;
63 final static int TightFilterCopy = 0x00;
64 final static int TightFilterPalette = 0x01;
65 final static int TightFilterGradient = 0x02;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000066
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +000067 final static int TightMinToCompress = 12;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000068
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000069 FbsInputStream fbs;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000070 DataInputStream is;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000071
72
73 //
Constantin Kaplinsky903009e2002-05-20 10:55:47 +000074 // Constructor.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000075 //
Constantin Kaplinsky285809b2008-06-17 10:31:41 +000076 RfbProto(URL url, long timeOffset) throws Exception {
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000077 fbs = null;
Constantin Kaplinsky285809b2008-06-17 10:31:41 +000078 newSession(url, timeOffset);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +000079 }
80
wimba.comd1f56df2004-11-01 16:18:54 +000081 // Force processing to quit
82 public void quit() {
83 fbs.quit();
84 try {
wimba.com30ff9ed2004-11-01 20:54:08 +000085 fbs.close();
wimba.comd1f56df2004-11-01 16:18:54 +000086 } catch (IOException e) {
87 System.out.println("IOException quitting RfbProto: " + e);
88 }
89 }
90
Constantin Kaplinskyc833e012002-05-30 17:59:22 +000091 //
92 // Open new session URL.
93 //
Constantin Kaplinsky285809b2008-06-17 10:31:41 +000094 public void newSession(URL url, long timeOffset) throws Exception {
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +000095 if (fbs != null)
96 fbs.close();
wimba.com9831b812007-11-14 22:25:34 +000097
wimba.com5cf6b2a2008-01-02 21:50:38 +000098 // open the connection, and use caching
wimba.com9831b812007-11-14 22:25:34 +000099 URLConnection connection = url.openConnection();
wimba.com5cf6b2a2008-01-02 21:50:38 +0000100 connection.setUseCaches(true);
wimba.com9831b812007-11-14 22:25:34 +0000101
102 fbs = new FbsInputStream(connection.getInputStream());
Constantin Kaplinsky37cc43e2002-05-30 17:30:11 +0000103 is = new DataInputStream(fbs);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000104
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000105 readVersionMsg();
106 if (readAuthScheme() != NoAuth) {
Constantin Kaplinskyf392f442002-05-20 13:05:42 +0000107 throw new Exception("Wrong authentication type in the session file");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000108 }
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000109 readServerInit();
Constantin Kaplinsky285809b2008-06-17 10:31:41 +0000110
111 // Go to initial position but make sure not to seek backwards.
112 if (timeOffset > fbs.getTimeOffset()) {
113 fbs.setTimeOffset(timeOffset);
114 }
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000115 }
116
117 //
Constantin Kaplinskyc833e012002-05-30 17:59:22 +0000118 // Read server's protocol version message.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000119 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000120 int serverMajor, serverMinor;
121
122 void readVersionMsg() throws IOException {
123
124 byte[] b = new byte[12];
125
wimba.comc23aeb02004-09-16 00:00:00 +0000126 for (int i = 0; i < b.length; i++)
127 b[i] = (byte)'0';
128
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000129 is.readFully(b);
130
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000131 if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') ||
132 (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') || (b[6] <
133 '0') || (b[6] > '9') || (b[7] != '.') || (b[8] < '0') || (b[8] > '9') ||
134 (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') ||
135 (b[11] != '\n')) {
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000136 throw new IOException("Incorrect protocol version");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000137 }
138
139 serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
140 serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
141 }
142
143
144 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000145 // Find out the authentication scheme.
146 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000147 int readAuthScheme() throws IOException {
148 int authScheme = is.readInt();
149
150 switch (authScheme) {
151
152 case ConnFailed:
153 int reasonLen = is.readInt();
154 byte[] reason = new byte[reasonLen];
155 is.readFully(reason);
156 throw new IOException(new String(reason));
157
158 case NoAuth:
159 case VncAuth:
160 return authScheme;
161
162 default:
Constantin Kaplinsky903009e2002-05-20 10:55:47 +0000163 throw new IOException("Unknown authentication scheme " + authScheme);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000164
165 }
166 }
167
168
169 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000170 // Read the server initialisation message
171 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000172 String desktopName;
173 int framebufferWidth, framebufferHeight;
174 int bitsPerPixel, depth;
175 boolean bigEndian, trueColour;
176 int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
177
Constantin Kaplinskyf392f442002-05-20 13:05:42 +0000178 void readServerInit() throws Exception {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000179 framebufferWidth = is.readUnsignedShort();
180 framebufferHeight = is.readUnsignedShort();
181 bitsPerPixel = is.readUnsignedByte();
182 depth = is.readUnsignedByte();
183 bigEndian = (is.readUnsignedByte() != 0);
184 trueColour = (is.readUnsignedByte() != 0);
185 redMax = is.readUnsignedShort();
186 greenMax = is.readUnsignedShort();
187 blueMax = is.readUnsignedShort();
188 redShift = is.readUnsignedByte();
189 greenShift = is.readUnsignedByte();
190 blueShift = is.readUnsignedByte();
191 byte[] pad = new byte[3];
192 is.readFully(pad);
193 int nameLength = is.readInt();
194 byte[] name = new byte[nameLength];
195 is.readFully(name);
196 desktopName = new String(name);
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000197 }
198
199
200 //
201 // Set new framebuffer size
202 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000203 void setFramebufferSize(int width, int height) {
204 framebufferWidth = width;
205 framebufferHeight = height;
206 }
207
208
209 //
210 // Read the server message type
211 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000212 int readServerMessageType() throws IOException {
213 return is.readUnsignedByte();
214 }
215
216
217 //
218 // Read a FramebufferUpdate message
219 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000220 int updateNRects;
221
222 void readFramebufferUpdate() throws IOException {
223 is.readByte();
224 updateNRects = is.readUnsignedShort();
225 }
226
227 // Read a FramebufferUpdate rectangle header
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000228 int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
229
230 void readFramebufferUpdateRectHdr() throws IOException {
231 updateRectX = is.readUnsignedShort();
232 updateRectY = is.readUnsignedShort();
233 updateRectW = is.readUnsignedShort();
234 updateRectH = is.readUnsignedShort();
235 updateRectEncoding = is.readInt();
236
wimba.com93cc0db2004-10-13 16:19:45 +0000237 if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000238 return;
239
240 if ((updateRectX + updateRectW > framebufferWidth) ||
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000241 (updateRectY + updateRectH > framebufferHeight)) {
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000242 throw new IOException("Framebuffer update rectangle too large: " +
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000243 updateRectW + "x" + updateRectH + " at (" +
244 updateRectX + "," + updateRectY + ")");
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000245 }
246 }
247
248 // Read CopyRect source X and Y.
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000249 int copyRectSrcX, copyRectSrcY;
250
251 void readCopyRect() throws IOException {
252 copyRectSrcX = is.readUnsignedShort();
253 copyRectSrcY = is.readUnsignedShort();
254 }
255
256
257 //
258 // Read a ServerCutText message
259 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000260 String readServerCutText() throws IOException {
261 byte[] pad = new byte[3];
262 is.readFully(pad);
263 int len = is.readInt();
264 byte[] text = new byte[len];
265 is.readFully(text);
266 return new String(text);
267 }
268
269
270 //
271 // Read integer in compact representation
272 //
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000273 int readCompactLen() throws IOException {
274 int portion = is.readUnsignedByte();
275 int len = portion & 0x7F;
276 if ((portion & 0x80) != 0) {
277 portion = is.readUnsignedByte();
278 len |= (portion & 0x7F) << 7;
279 if ((portion & 0x80) != 0) {
Constantin Kaplinsky72e47ef2008-04-18 17:48:16 +0000280 portion = is.readUnsignedByte();
281 len |= (portion & 0xFF) << 14;
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000282 }
283 }
284 return len;
285 }
286
Constantin Kaplinsky1215b992008-04-18 09:51:44 +0000287}