aboutsummaryrefslogtreecommitdiffstats
path: root/common/rfb/SMsgReader.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'common/rfb/SMsgReader.cxx')
-rw-r--r--common/rfb/SMsgReader.cxx192
1 files changed, 156 insertions, 36 deletions
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx
index dc7ddea6..944f9315 100644
--- a/common/rfb/SMsgReader.cxx
+++ b/common/rfb/SMsgReader.cxx
@@ -38,7 +38,7 @@ static LogWriter vlog("SMsgReader");
static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_)
- : handler(handler_), is(is_)
+ : handler(handler_), is(is_), state(MSGSTATE_IDLE)
{
}
@@ -46,71 +46,105 @@ SMsgReader::~SMsgReader()
{
}
-void SMsgReader::readClientInit()
+bool SMsgReader::readClientInit()
{
+ if (!is->hasData(1))
+ return false;
bool shared = is->readU8();
handler->clientInit(shared);
+ return true;
}
-void SMsgReader::readMsg()
+bool SMsgReader::readMsg()
{
- int msgType = is->readU8();
- switch (msgType) {
+ bool ret;
+
+ if (state == MSGSTATE_IDLE) {
+ if (!is->hasData(1))
+ return false;
+
+ currentMsgType = is->readU8();
+ state = MSGSTATE_MESSAGE;
+ }
+
+ switch (currentMsgType) {
case msgTypeSetPixelFormat:
- readSetPixelFormat();
+ ret = readSetPixelFormat();
break;
case msgTypeSetEncodings:
- readSetEncodings();
+ ret = readSetEncodings();
break;
case msgTypeSetDesktopSize:
- readSetDesktopSize();
+ ret = readSetDesktopSize();
break;
case msgTypeFramebufferUpdateRequest:
- readFramebufferUpdateRequest();
+ ret = readFramebufferUpdateRequest();
break;
case msgTypeEnableContinuousUpdates:
- readEnableContinuousUpdates();
+ ret = readEnableContinuousUpdates();
break;
case msgTypeClientFence:
- readFence();
+ ret = readFence();
break;
case msgTypeKeyEvent:
- readKeyEvent();
+ ret = readKeyEvent();
break;
case msgTypePointerEvent:
- readPointerEvent();
+ ret = readPointerEvent();
break;
case msgTypeClientCutText:
- readClientCutText();
+ ret = readClientCutText();
break;
case msgTypeQEMUClientMessage:
- readQEMUMessage();
+ ret = readQEMUMessage();
break;
default:
- vlog.error("unknown message type %d", msgType);
+ vlog.error("unknown message type %d", currentMsgType);
throw Exception("unknown message type");
}
+
+ if (ret)
+ state = MSGSTATE_IDLE;
+
+ return ret;
}
-void SMsgReader::readSetPixelFormat()
+bool SMsgReader::readSetPixelFormat()
{
+ if (!is->hasData(3 + 16))
+ return false;
is->skip(3);
PixelFormat pf;
pf.read(is);
handler->setPixelFormat(pf);
+ return true;
}
-void SMsgReader::readSetEncodings()
+bool SMsgReader::readSetEncodings()
{
+ if (!is->hasData(3))
+ return false;
+
+ is->setRestorePoint();
+
is->skip(1);
+
int nEncodings = is->readU16();
+
+ if (!is->hasDataOrRestore(nEncodings * 4))
+ return false;
+ is->clearRestorePoint();
+
rdr::S32Array encodings(nEncodings);
for (int i = 0; i < nEncodings; i++)
encodings.buf[i] = is->readU32();
+
handler->setEncodings(nEncodings, encodings.buf);
+
+ return true;
}
-void SMsgReader::readSetDesktopSize()
+bool SMsgReader::readSetDesktopSize()
{
int width, height;
int screens, i;
@@ -118,6 +152,11 @@ void SMsgReader::readSetDesktopSize()
int sx, sy, sw, sh;
ScreenSet layout;
+ if (!is->hasData(7))
+ return true;
+
+ is->setRestorePoint();
+
is->skip(1);
width = is->readU16();
@@ -126,6 +165,10 @@ void SMsgReader::readSetDesktopSize()
screens = is->readU8();
is->skip(1);
+ if (!is->hasDataOrRestore(screens * 24))
+ return false;
+ is->clearRestorePoint();
+
for (i = 0;i < screens;i++) {
id = is->readU32();
sx = is->readU16();
@@ -138,23 +181,31 @@ void SMsgReader::readSetDesktopSize()
}
handler->setDesktopSize(width, height, layout);
+
+ return true;
}
-void SMsgReader::readFramebufferUpdateRequest()
+bool SMsgReader::readFramebufferUpdateRequest()
{
+ if (!is->hasData(17))
+ return false;
bool inc = is->readU8();
int x = is->readU16();
int y = is->readU16();
int w = is->readU16();
int h = is->readU16();
handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc);
+ return true;
}
-void SMsgReader::readEnableContinuousUpdates()
+bool SMsgReader::readEnableContinuousUpdates()
{
bool enable;
int x, y, w, h;
+ if (!is->hasData(17))
+ return false;
+
enable = is->readU8();
x = is->readU16();
@@ -163,81 +214,121 @@ void SMsgReader::readEnableContinuousUpdates()
h = is->readU16();
handler->enableContinuousUpdates(enable, x, y, w, h);
+
+ return true;
}
-void SMsgReader::readFence()
+bool SMsgReader::readFence()
{
rdr::U32 flags;
rdr::U8 len;
char data[64];
+ if (!is->hasData(8))
+ return false;
+
+ is->setRestorePoint();
+
is->skip(3);
flags = is->readU32();
len = is->readU8();
+
+ if (!is->hasDataOrRestore(len))
+ return false;
+ is->clearRestorePoint();
+
if (len > sizeof(data)) {
vlog.error("Ignoring fence with too large payload");
is->skip(len);
- return;
+ return true;
}
is->readBytes(data, len);
handler->fence(flags, len, data);
+
+ return true;
}
-void SMsgReader::readKeyEvent()
+bool SMsgReader::readKeyEvent()
{
+ if (!is->hasData(7))
+ return false;
bool down = is->readU8();
is->skip(2);
rdr::U32 key = is->readU32();
handler->keyEvent(key, 0, down);
+ return true;
}
-void SMsgReader::readPointerEvent()
+bool SMsgReader::readPointerEvent()
{
+ if (!is->hasData(5))
+ return false;
int mask = is->readU8();
int x = is->readU16();
int y = is->readU16();
handler->pointerEvent(Point(x, y), mask);
+ return true;
}
-void SMsgReader::readClientCutText()
+bool SMsgReader::readClientCutText()
{
+ if (!is->hasData(7))
+ return false;
+
+ is->setRestorePoint();
+
is->skip(3);
rdr::U32 len = is->readU32();
if (len & 0x80000000) {
rdr::S32 slen = len;
slen = -slen;
- readExtendedClipboard(slen);
- return;
+ if (readExtendedClipboard(slen)) {
+ is->clearRestorePoint();
+ return true;
+ } else {
+ is->gotoRestorePoint();
+ return false;
+ }
}
+ if (!is->hasDataOrRestore(len))
+ return false;
+ is->clearRestorePoint();
+
if (len > (size_t)maxCutText) {
is->skip(len);
vlog.error("Cut text too long (%d bytes) - ignoring", len);
- return;
+ return true;
}
+
CharArray ca(len);
is->readBytes(ca.buf, len);
CharArray filtered(convertLF(ca.buf, len));
handler->clientCutText(filtered.buf);
+
+ return true;
}
-void SMsgReader::readExtendedClipboard(rdr::S32 len)
+bool SMsgReader::readExtendedClipboard(rdr::S32 len)
{
rdr::U32 flags;
rdr::U32 action;
+ if (!is->hasData(len))
+ return false;
+
if (len < 4)
throw Exception("Invalid extended clipboard message");
if (len > maxCutText) {
vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
is->skip(len);
- return;
+ return true;
}
flags = is->readU32();
@@ -279,7 +370,14 @@ void SMsgReader::readExtendedClipboard(rdr::S32 len)
if (!(flags & 1 << i))
continue;
+ if (!zis.hasData(4))
+ throw Exception("Extended clipboard decode error");
+
lengths[num] = zis.readU32();
+
+ if (!zis.hasData(lengths[num]))
+ throw Exception("Extended clipboard decode error");
+
if (lengths[num] > (size_t)maxCutText) {
vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
(unsigned)lengths[num]);
@@ -319,28 +417,50 @@ void SMsgReader::readExtendedClipboard(rdr::S32 len)
throw Exception("Invalid extended clipboard action");
}
}
+
+ return true;
}
-void SMsgReader::readQEMUMessage()
+bool SMsgReader::readQEMUMessage()
{
- int subType = is->readU8();
+ int subType;
+ bool ret;
+
+ if (!is->hasData(1))
+ return false;
+
+ is->setRestorePoint();
+
+ subType = is->readU8();
+
switch (subType) {
case qemuExtendedKeyEvent:
- readQEMUKeyEvent();
+ ret = readQEMUKeyEvent();
break;
default:
throw Exception("unknown QEMU submessage type %d", subType);
}
+
+ if (!ret) {
+ is->gotoRestorePoint();
+ return false;
+ } else {
+ is->clearRestorePoint();
+ return true;
+ }
}
-void SMsgReader::readQEMUKeyEvent()
+bool SMsgReader::readQEMUKeyEvent()
{
+ if (!is->hasData(10))
+ return false;
bool down = is->readU16();
rdr::U32 keysym = is->readU32();
rdr::U32 keycode = is->readU32();
if (!keycode) {
vlog.error("Key event without keycode - ignoring");
- return;
+ return true;
}
handler->keyEvent(keysym, keycode, down);
+ return true;
}