blob: 5efbfe2b4b530792cbd0eb7220c164fd33916a09 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman7638e9c2014-01-16 13:12:40 +01002 * Copyright 2009-2014 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
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#include <stdio.h>
20#include <rdr/InStream.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010021#include <rfb/msgTypes.h>
Pierre Ossman5ae28212017-05-16 14:30:38 +020022#include <rfb/qemuTypes.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rfb/Exception.h>
24#include <rfb/util.h>
25#include <rfb/SMsgHandler.h>
26#include <rfb/SMsgReader.h>
27#include <rfb/Configuration.h>
Constantin Kaplinskyc7755da2008-04-24 11:01:55 +000028#include <rfb/LogWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029
30using namespace rfb;
31
Constantin Kaplinskyc7755da2008-04-24 11:01:55 +000032static LogWriter vlog("SMsgReader");
33
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
35
36SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
37 : handler(handler_), is(is_)
38{
39}
40
41SMsgReader::~SMsgReader()
42{
43}
44
Pierre Ossman7638e9c2014-01-16 13:12:40 +010045void SMsgReader::readClientInit()
46{
47 bool shared = is->readU8();
48 handler->clientInit(shared);
49}
50
51void SMsgReader::readMsg()
52{
53 int msgType = is->readU8();
54 switch (msgType) {
55 case msgTypeSetPixelFormat:
56 readSetPixelFormat();
57 break;
58 case msgTypeSetEncodings:
59 readSetEncodings();
60 break;
61 case msgTypeSetDesktopSize:
62 readSetDesktopSize();
63 break;
64 case msgTypeFramebufferUpdateRequest:
65 readFramebufferUpdateRequest();
66 break;
67 case msgTypeEnableContinuousUpdates:
68 readEnableContinuousUpdates();
69 break;
70 case msgTypeClientFence:
71 readFence();
72 break;
73 case msgTypeKeyEvent:
74 readKeyEvent();
75 break;
76 case msgTypePointerEvent:
77 readPointerEvent();
78 break;
79 case msgTypeClientCutText:
80 readClientCutText();
81 break;
Pierre Ossman5ae28212017-05-16 14:30:38 +020082 case msgTypeQEMUClientMessage:
83 readQEMUMessage();
84 break;
Pierre Ossman7638e9c2014-01-16 13:12:40 +010085 default:
Pierre Ossmane9e7da92016-04-20 09:38:06 +020086 vlog.error("unknown message type %d", msgType);
Pierre Ossman7638e9c2014-01-16 13:12:40 +010087 throw Exception("unknown message type");
88 }
89}
90
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000091void SMsgReader::readSetPixelFormat()
92{
93 is->skip(3);
94 PixelFormat pf;
95 pf.read(is);
96 handler->setPixelFormat(pf);
97}
98
99void SMsgReader::readSetEncodings()
100{
101 is->skip(1);
102 int nEncodings = is->readU16();
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000103 rdr::S32Array encodings(nEncodings);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000104 for (int i = 0; i < nEncodings; i++)
105 encodings.buf[i] = is->readU32();
106 handler->setEncodings(nEncodings, encodings.buf);
107}
108
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100109void SMsgReader::readSetDesktopSize()
110{
111 int width, height;
112 int screens, i;
113 rdr::U32 id, flags;
114 int sx, sy, sw, sh;
115 ScreenSet layout;
116
117 is->skip(1);
118
119 width = is->readU16();
120 height = is->readU16();
121
122 screens = is->readU8();
123 is->skip(1);
124
125 for (i = 0;i < screens;i++) {
126 id = is->readU32();
127 sx = is->readU16();
128 sy = is->readU16();
129 sw = is->readU16();
130 sh = is->readU16();
131 flags = is->readU32();
132
133 layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
134 }
135
136 handler->setDesktopSize(width, height, layout);
137}
138
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000139void SMsgReader::readFramebufferUpdateRequest()
140{
141 bool inc = is->readU8();
142 int x = is->readU16();
143 int y = is->readU16();
144 int w = is->readU16();
145 int h = is->readU16();
146 handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
147}
148
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100149void SMsgReader::readEnableContinuousUpdates()
150{
151 bool enable;
152 int x, y, w, h;
153
154 enable = is->readU8();
155
156 x = is->readU16();
157 y = is->readU16();
158 w = is->readU16();
159 h = is->readU16();
160
161 handler->enableContinuousUpdates(enable, x, y, w, h);
162}
163
164void SMsgReader::readFence()
165{
166 rdr::U32 flags;
167 rdr::U8 len;
168 char data[64];
169
170 is->skip(3);
171
172 flags = is->readU32();
173
174 len = is->readU8();
175 if (len > sizeof(data)) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200176 vlog.error("Ignoring fence with too large payload");
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100177 is->skip(len);
178 return;
179 }
180
181 is->readBytes(data, len);
182
183 handler->fence(flags, len, data);
184}
185
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000186void SMsgReader::readKeyEvent()
187{
188 bool down = is->readU8();
189 is->skip(2);
190 rdr::U32 key = is->readU32();
Pierre Ossman5ae28212017-05-16 14:30:38 +0200191 handler->keyEvent(key, 0, down);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000192}
193
194void SMsgReader::readPointerEvent()
195{
196 int mask = is->readU8();
197 int x = is->readU16();
198 int y = is->readU16();
199 handler->pointerEvent(Point(x, y), mask);
200}
201
202
203void SMsgReader::readClientCutText()
204{
205 is->skip(3);
206 int len = is->readU32();
Michal Srbbf3bdac2017-03-27 13:37:11 +0300207 if (len < 0) {
208 throw Exception("Cut text too long.");
209 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000210 if (len > maxCutText) {
211 is->skip(len);
Constantin Kaplinskyc7755da2008-04-24 11:01:55 +0000212 vlog.error("Cut text too long (%d bytes) - ignoring", len);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000213 return;
214 }
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200215 CharArray ca(len);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000216 is->readBytes(ca.buf, len);
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200217 CharArray filtered(convertLF(ca.buf, len));
Pierre Ossman66f1db52019-05-02 12:32:03 +0200218 handler->clientCutText(filtered.buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000219}
Constantin Kaplinskydafbb012007-04-05 08:43:25 +0000220
Pierre Ossman5ae28212017-05-16 14:30:38 +0200221void SMsgReader::readQEMUMessage()
222{
223 int subType = is->readU8();
224 switch (subType) {
225 case qemuExtendedKeyEvent:
226 readQEMUKeyEvent();
227 break;
228 default:
229 throw Exception("unknown QEMU submessage type %d", subType);
230 }
231}
232
233void SMsgReader::readQEMUKeyEvent()
234{
235 bool down = is->readU16();
236 rdr::U32 keysym = is->readU32();
237 rdr::U32 keycode = is->readU32();
238 if (!keycode) {
239 vlog.error("Key event without keycode - ignoring");
240 return;
241 }
242 handler->keyEvent(keysym, keycode, down);
243}