// returning EINTR. | // returning EINTR. | ||||
// | // | ||||
size_t FdInStream::readFd(void* buf, size_t len) | |||||
size_t FdInStream::readFd(uint8_t* buf, size_t len) | |||||
{ | { | ||||
int n; | int n; | ||||
do { | do { |
private: | private: | ||||
virtual bool fillBuffer(); | virtual bool fillBuffer(); | ||||
size_t readFd(void* buf, size_t len); | |||||
size_t readFd(uint8_t* buf, size_t len); | |||||
int fd; | int fd; | ||||
bool closeWhenDone; | bool closeWhenDone; |
bool FdOutStream::flushBuffer() | bool FdOutStream::flushBuffer() | ||||
{ | { | ||||
size_t n = writeFd((const void*) sentUpTo, ptr - sentUpTo); | |||||
size_t n = writeFd(sentUpTo, ptr - sentUpTo); | |||||
if (n == 0) | if (n == 0) | ||||
return false; | return false; | ||||
// returning EINTR. | // returning EINTR. | ||||
// | // | ||||
size_t FdOutStream::writeFd(const void* data, size_t length) | |||||
size_t FdOutStream::writeFd(const uint8_t* data, size_t length) | |||||
{ | { | ||||
int n; | int n; | ||||
private: | private: | ||||
virtual bool flushBuffer(); | virtual bool flushBuffer(); | ||||
size_t writeFd(const void* data, size_t length); | |||||
size_t writeFd(const uint8_t* data, size_t length); | |||||
int fd; | int fd; | ||||
struct timeval lastWrite; | struct timeval lastWrite; | ||||
}; | }; |
// readBytes() reads an exact number of bytes. | // readBytes() reads an exact number of bytes. | ||||
void readBytes(void* data, size_t length) { | |||||
void readBytes(uint8_t* data, size_t length) { | |||||
check(length); | check(length); | ||||
memcpy(data, ptr, length); | memcpy(data, ptr, length); | ||||
ptr += length; | ptr += length; |
public: | public: | ||||
MemInStream(const void* data, size_t len, bool deleteWhenDone_=false) | |||||
: start((const uint8_t*)data), deleteWhenDone(deleteWhenDone_) | |||||
MemInStream(const uint8_t* data, size_t len, bool deleteWhenDone_=false) | |||||
: start(data), deleteWhenDone(deleteWhenDone_) | |||||
{ | { | ||||
ptr = start; | ptr = start; | ||||
end = start + len; | end = start + len; |
// data() returns a pointer to the buffer. | // data() returns a pointer to the buffer. | ||||
const void* data() { return (const void*)start; } | |||||
const uint8_t* data() { return start; } | |||||
protected: | protected: | ||||
// writeBytes() writes an exact number of bytes. | // writeBytes() writes an exact number of bytes. | ||||
void writeBytes(const void* data, size_t length) { | |||||
void writeBytes(const uint8_t* data, size_t length) { | |||||
while (length > 0) { | while (length > 0) { | ||||
check(1); | check(1); | ||||
size_t n = length; | size_t n = length; |
if (in->avail() < size) | if (in->avail() < size) | ||||
size = in->avail(); | size = in->avail(); | ||||
in->readBytes(data, size); | |||||
in->readBytes((uint8_t*)data, size); | |||||
} catch (EndOfStream&) { | } catch (EndOfStream&) { | ||||
return 0; | return 0; | ||||
} catch (SystemException &e) { | } catch (SystemException &e) { |
self->saved_exception = NULL; | self->saved_exception = NULL; | ||||
try { | try { | ||||
out->writeBytes(data, size); | |||||
out->writeBytes((const uint8_t*)data, size); | |||||
out->flush(); | out->flush(); | ||||
} catch (SystemException &e) { | } catch (SystemException &e) { | ||||
vlog.error("Failure sending TLS data: %s", e.str()); | vlog.error("Failure sending TLS data: %s", e.str()); |
if (!is->hasData(12)) | if (!is->hasData(12)) | ||||
return false; | return false; | ||||
is->readBytes(verStr, 12); | |||||
is->readBytes((uint8_t*)verStr, 12); | |||||
verStr[12] = '\0'; | verStr[12] = '\0'; | ||||
if (sscanf(verStr, "RFB %03d.%03d\n", | if (sscanf(verStr, "RFB %03d.%03d\n", | ||||
sprintf(verStr, "RFB %03d.%03d\n", | sprintf(verStr, "RFB %03d.%03d\n", | ||||
server.majorVersion, server.minorVersion); | server.majorVersion, server.minorVersion); | ||||
os->writeBytes(verStr, 12); | |||||
os->writeBytes((const uint8_t*)verStr, 12); | |||||
os->flush(); | os->flush(); | ||||
state_ = RFBSTATE_SECURITY_TYPES; | state_ = RFBSTATE_SECURITY_TYPES; | ||||
is->clearRestorePoint(); | is->clearRestorePoint(); | ||||
std::vector<char> reason(len + 1); | std::vector<char> reason(len + 1); | ||||
is->readBytes(reason.data(), len); | |||||
is->readBytes((uint8_t*)reason.data(), len); | |||||
reason[len] = '\0'; | reason[len] = '\0'; | ||||
state_ = RFBSTATE_INVALID; | state_ = RFBSTATE_INVALID; | ||||
{ | { | ||||
hasLocalClipboard = false; | hasLocalClipboard = false; | ||||
serverClipboard = latin1ToUTF8(str); | |||||
serverClipboard = str; | |||||
hasRemoteClipboard = true; | hasRemoteClipboard = true; | ||||
handleClipboardAnnounce(true); | handleClipboardAnnounce(true); | ||||
return; | return; | ||||
} | } | ||||
// FIXME: This conversion magic should be in CMsgReader | |||||
if (!isValidUTF8((const char*)data[0], lengths[0])) { | |||||
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring"); | |||||
return; | |||||
} | |||||
serverClipboard = convertLF((const char*)data[0], lengths[0]); | serverClipboard = convertLF((const char*)data[0], lengths[0]); | ||||
hasRemoteClipboard = true; | hasRemoteClipboard = true; | ||||
void CConnection::sendClipboardData(const char* data) | void CConnection::sendClipboardData(const char* data) | ||||
{ | { | ||||
if (server.clipboardFlags() & rfb::clipboardProvide) { | if (server.clipboardFlags() & rfb::clipboardProvide) { | ||||
// FIXME: This conversion magic should be in CMsgWriter | |||||
std::string filtered(convertCRLF(data)); | std::string filtered(convertCRLF(data)); | ||||
size_t sizes[1] = { filtered.size() + 1 }; | size_t sizes[1] = { filtered.size() + 1 }; | ||||
const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; | const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; | ||||
writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); | writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); | ||||
} else { | } else { | ||||
std::string latin1(utf8ToLatin1(data)); | |||||
writer()->writeClientCutText(latin1.c_str()); | |||||
writer()->writeClientCutText(data); | |||||
} | } | ||||
} | } | ||||
formatChange = true; | formatChange = true; | ||||
} | } | ||||
void CConnection::fence(uint32_t flags, unsigned len, const char data[]) | |||||
void CConnection::fence(uint32_t flags, unsigned len, const uint8_t data[]) | |||||
{ | { | ||||
CMsgHandler::fence(flags, len, data); | CMsgHandler::fence(flags, len, data); | ||||
// responds to requests, stating no support for synchronisation. | // responds to requests, stating no support for synchronisation. | ||||
// When overriding, call CMsgHandler::fence() directly in order to | // When overriding, call CMsgHandler::fence() directly in order to | ||||
// state correct support for fence flags. | // state correct support for fence flags. | ||||
virtual void fence(uint32_t flags, unsigned len, const char data[]); | |||||
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
private: | private: | ||||
bool processVersionMsg(); | bool processVersionMsg(); |
} | } | ||||
void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/, | void CMsgHandler::fence(uint32_t /*flags*/, unsigned /*len*/, | ||||
const char /*data*/ []) | |||||
const uint8_t /*data*/ []) | |||||
{ | { | ||||
server.supportsFence = true; | server.supportsFence = true; | ||||
} | } |
virtual void setCursorPos(const Point& pos) = 0; | virtual void setCursorPos(const Point& pos) = 0; | ||||
virtual void setPixelFormat(const PixelFormat& pf); | virtual void setPixelFormat(const PixelFormat& pf); | ||||
virtual void setName(const char* name); | virtual void setName(const char* name); | ||||
virtual void fence(uint32_t flags, unsigned len, const char data[]); | |||||
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
virtual void endOfContinuousUpdates(); | virtual void endOfContinuousUpdates(); | ||||
virtual void supportsQEMUKeyEvent(); | virtual void supportsQEMUKeyEvent(); | ||||
virtual void serverInit(int width, int height, | virtual void serverInit(int width, int height, |
return false; | return false; | ||||
is->clearRestorePoint(); | is->clearRestorePoint(); | ||||
std::vector<char> name(len + 1); | std::vector<char> name(len + 1); | ||||
is->readBytes(name.data(), len); | |||||
is->readBytes((uint8_t*)name.data(), len); | |||||
name[len] = '\0'; | name[len] = '\0'; | ||||
handler->serverInit(width, height, pf, name.data()); | |||||
if (isValidUTF8(name.data())) | |||||
handler->serverInit(width, height, pf, name.data()); | |||||
else | |||||
handler->serverInit(width, height, pf, | |||||
latin1ToUTF8(name.data()).c_str()); | |||||
return true; | return true; | ||||
} | } | ||||
vlog.error("cut text too long (%d bytes) - ignoring",len); | vlog.error("cut text too long (%d bytes) - ignoring",len); | ||||
return true; | return true; | ||||
} | } | ||||
std::vector<char> ca(len); | std::vector<char> ca(len); | ||||
is->readBytes(ca.data(), len); | |||||
std::string filtered(convertLF(ca.data(), len)); | |||||
is->readBytes((uint8_t*)ca.data(), len); | |||||
std::string utf8(latin1ToUTF8(ca.data(), ca.size())); | |||||
std::string filtered(convertLF(utf8.data(), utf8.size())); | |||||
handler->serverCutText(filtered.c_str()); | handler->serverCutText(filtered.c_str()); | ||||
return true; | return true; | ||||
{ | { | ||||
uint32_t flags; | uint32_t flags; | ||||
uint8_t len; | uint8_t len; | ||||
char data[64]; | |||||
uint8_t data[64]; | |||||
if (!is->hasData(3 + 4 + 1)) | if (!is->hasData(3 + 4 + 1)) | ||||
return false; | return false; | ||||
is->clearRestorePoint(); | is->clearRestorePoint(); | ||||
std::vector<char> name(len + 1); | std::vector<char> name(len + 1); | ||||
is->readBytes(name.data(), len); | |||||
is->readBytes((uint8_t*)name.data(), len); | |||||
name[len] = '\0'; | name[len] = '\0'; | ||||
if (x || y || w || h) { | if (x || y || w || h) { | ||||
vlog.error("Ignoring DesktopName rect with non-zero position/size"); | vlog.error("Ignoring DesktopName rect with non-zero position/size"); | ||||
} else { | |||||
handler->setName(name.data()); | |||||
return true; | |||||
} | } | ||||
if (!isValidUTF8(name.data())) { | |||||
vlog.error("Ignoring DesktopName rect with invalid UTF-8 sequence"); | |||||
return true; | |||||
} | |||||
handler->setName(name.data()); | |||||
return true; | return true; | ||||
} | } | ||||
#include <rfb/Rect.h> | #include <rfb/Rect.h> | ||||
#include <rfb/ServerParams.h> | #include <rfb/ServerParams.h> | ||||
#include <rfb/CMsgWriter.h> | #include <rfb/CMsgWriter.h> | ||||
#include <rfb/util.h> | |||||
using namespace rfb; | using namespace rfb; | ||||
endMsg(); | endMsg(); | ||||
} | } | ||||
void CMsgWriter::writeFence(uint32_t flags, unsigned len, const char data[]) | |||||
void CMsgWriter::writeFence(uint32_t flags, unsigned len, const uint8_t data[]) | |||||
{ | { | ||||
if (!server->supportsFence) | if (!server->supportsFence) | ||||
throw Exception("Server does not support fences"); | throw Exception("Server does not support fences"); | ||||
void CMsgWriter::writeClientCutText(const char* str) | void CMsgWriter::writeClientCutText(const char* str) | ||||
{ | { | ||||
size_t len; | |||||
if (strchr(str, '\r') != NULL) | if (strchr(str, '\r') != NULL) | ||||
throw Exception("Invalid carriage return in clipboard data"); | throw Exception("Invalid carriage return in clipboard data"); | ||||
len = strlen(str); | |||||
std::string latin1(utf8ToLatin1(str)); | |||||
startMsg(msgTypeClientCutText); | startMsg(msgTypeClientCutText); | ||||
os->pad(3); | os->pad(3); | ||||
os->writeU32(len); | |||||
os->writeBytes(str, len); | |||||
os->writeU32(latin1.size()); | |||||
os->writeBytes((const uint8_t*)latin1.data(), latin1.size()); | |||||
endMsg(); | endMsg(); | ||||
} | } | ||||
void writeFramebufferUpdateRequest(const Rect& r,bool incremental); | void writeFramebufferUpdateRequest(const Rect& r,bool incremental); | ||||
void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h); | void writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h); | ||||
void writeFence(uint32_t flags, unsigned len, const char data[]); | |||||
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); | void writeKeyEvent(uint32_t keysym, uint32_t keycode, bool down); | ||||
void writePointerEvent(const Point& pos, int buttonMask); | void writePointerEvent(const Point& pos, int buttonMask); |
struct aes128_ctx aesCtx; | struct aes128_ctx aesCtx; | ||||
aes128_set_encrypt_key(&aesCtx, key); | aes128_set_encrypt_key(&aesCtx, key); | ||||
char buf[128]; | |||||
uint8_t buf[128]; | |||||
if (!rs.hasData(128)) | if (!rs.hasData(128)) | ||||
throw ConnFailedException("failed to generate random padding"); | throw ConnFailedException("failed to generate random padding"); | ||||
rs.readBytes(buf, 128); | rs.readBytes(buf, 128); | ||||
if (password.size() >= 64) | if (password.size() >= 64) | ||||
throw AuthFailureException("password is too long"); | throw AuthFailureException("password is too long"); | ||||
memcpy(buf + 64, password.c_str(), password.size() + 1); | memcpy(buf + 64, password.c_str(), password.size() + 1); | ||||
aes128_encrypt(&aesCtx, 128, (uint8_t *)buf, (uint8_t *)buf); | |||||
aes128_encrypt(&aesCtx, 128, buf, buf); | |||||
rdr::OutStream* os = cc->getOutStream(); | rdr::OutStream* os = cc->getOutStream(); | ||||
os->writeBytes(buf, 128); | os->writeBytes(buf, 128); |
// Return the response to the server | // Return the response to the server | ||||
os->writeU32(username.size()); | os->writeU32(username.size()); | ||||
os->writeU32(password.size()); | os->writeU32(password.size()); | ||||
os->writeBytes(username.data(), username.size()); | |||||
os->writeBytes(password.data(), password.size()); | |||||
os->writeBytes((const uint8_t*)username.data(), username.size()); | |||||
os->writeBytes((const uint8_t*)password.data(), password.size()); | |||||
os->flush(); | os->flush(); | ||||
return true; | return true; | ||||
} | } |
if (username.size() > 255) | if (username.size() > 255) | ||||
throw AuthFailureException("username is too long"); | throw AuthFailureException("username is too long"); | ||||
raos->writeU8(username.size()); | raos->writeU8(username.size()); | ||||
raos->writeBytes(username.data(), username.size()); | |||||
raos->writeBytes((const uint8_t*)username.data(), username.size()); | |||||
} else { | } else { | ||||
raos->writeU8(0); | raos->writeU8(0); | ||||
} | } | ||||
if (password.size() > 255) | if (password.size() > 255) | ||||
throw AuthFailureException("password is too long"); | throw AuthFailureException("password is too long"); | ||||
raos->writeU8(password.size()); | raos->writeU8(password.size()); | ||||
raos->writeBytes(password.data(), password.size()); | |||||
raos->writeBytes((const uint8_t*)password.data(), password.size()); | |||||
raos->flush(); | raos->flush(); | ||||
} | } |
void CopyRectDecoder::getAffectedRegion(const Rect& rect, | void CopyRectDecoder::getAffectedRegion(const Rect& rect, | ||||
const void* buffer, | |||||
const uint8_t* buffer, | |||||
size_t buflen, | size_t buflen, | ||||
const ServerParams& server, | const ServerParams& server, | ||||
Region* region) | Region* region) | ||||
srcY-rect.tl.y)))); | srcY-rect.tl.y)))); | ||||
} | } | ||||
void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void CopyRectDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, | size_t buflen, | ||||
const ServerParams& /*server*/, | const ServerParams& /*server*/, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) |
virtual ~CopyRectDecoder(); | virtual ~CopyRectDecoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void getAffectedRegion(const Rect& rect, const void* buffer, | |||||
virtual void getAffectedRegion(const Rect& rect, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
Region* region); | Region* region); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
}; | }; |
} | } | ||||
void Decoder::getAffectedRegion(const Rect& rect, | void Decoder::getAffectedRegion(const Rect& rect, | ||||
const void* /*buffer*/, | |||||
const uint8_t* /*buffer*/, | |||||
size_t /*buflen*/, | size_t /*buflen*/, | ||||
const ServerParams& /*server*/, | const ServerParams& /*server*/, | ||||
Region* region) | Region* region) | ||||
} | } | ||||
bool Decoder::doRectsConflict(const Rect& /*rectA*/, | bool Decoder::doRectsConflict(const Rect& /*rectA*/, | ||||
const void* /*bufferA*/, | |||||
const uint8_t* /*bufferA*/, | |||||
size_t /*buflenA*/, | size_t /*buflenA*/, | ||||
const Rect& /*rectB*/, | const Rect& /*rectB*/, | ||||
const void* /*bufferB*/, | |||||
const uint8_t* /*bufferB*/, | |||||
size_t /*buflenB*/, | size_t /*buflenB*/, | ||||
const ServerParams& /*server*/) | const ServerParams& /*server*/) | ||||
{ | { |
#ifndef __RFB_DECODER_H__ | #ifndef __RFB_DECODER_H__ | ||||
#define __RFB_DECODER_H__ | #define __RFB_DECODER_H__ | ||||
#include <stdint.h> | |||||
namespace rdr { | namespace rdr { | ||||
class InStream; | class InStream; | ||||
class OutStream; | class OutStream; | ||||
// getAffectedRegion() returns the parts of the frame buffer will | // getAffectedRegion() returns the parts of the frame buffer will | ||||
// be either read from or written do when decoding this rect. The | // be either read from or written do when decoding this rect. The | ||||
// default implementation simply returns the given rectangle. | // default implementation simply returns the given rectangle. | ||||
virtual void getAffectedRegion(const Rect& rect, const void* buffer, | |||||
virtual void getAffectedRegion(const Rect& rect, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
Region* region); | Region* region); | ||||
// in the order they were received. This will only be called if the | // in the order they were received. This will only be called if the | ||||
// DecoderPartiallyOrdered flag has been set. | // DecoderPartiallyOrdered flag has been set. | ||||
virtual bool doRectsConflict(const Rect& rectA, | virtual bool doRectsConflict(const Rect& rectA, | ||||
const void* bufferA, | |||||
const uint8_t* bufferA, | |||||
size_t buflenA, | size_t buflenA, | ||||
const Rect& rectB, | const Rect& rectB, | ||||
const void* bufferB, | |||||
const uint8_t* bufferB, | |||||
size_t buflenB, | size_t buflenB, | ||||
const ServerParams& server); | const ServerParams& server); | ||||
// given buffer, onto the ModifiablePixelBuffer. The PixelFormat of | // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of | ||||
// the PixelBuffer might not match the ConnParams and it is up to | // the PixelBuffer might not match the ConnParams and it is up to | ||||
// the decoder to do any necessary conversion. | // the decoder to do any necessary conversion. | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb)=0; | ModifiablePixelBuffer* pb)=0; | ||||
return true; | return true; | ||||
} | } | ||||
void H264Decoder::decodeRect(const Rect& r, const void* buffer, | |||||
void H264Decoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, | size_t buflen, | ||||
const ServerParams& /*server*/, | const ServerParams& /*server*/, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) |
virtual ~H264Decoder(); | virtual ~H264Decoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
return true; | return true; | ||||
} | } | ||||
void HextileDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void HextileDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) | ||||
{ | { | ||||
int tileType = is->readU8(); | int tileType = is->readU8(); | ||||
if (tileType & hextileRaw) { | if (tileType & hextileRaw) { | ||||
is->readBytes(buf, t.area() * sizeof(T)); | |||||
is->readBytes((uint8_t*)buf, t.area() * sizeof(T)); | |||||
pb->imageRect(pf, t, buf); | pb->imageRect(pf, t, buf); | ||||
continue; | continue; | ||||
} | } |
virtual ~HextileDecoder(); | virtual ~HextileDecoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
private: | private: |
if (encodedLen < 0) { | if (encodedLen < 0) { | ||||
pb->getImage(buf, t); | pb->getImage(buf, t); | ||||
os->writeU8(hextileRaw); | os->writeU8(hextileRaw); | ||||
os->writeBytes(buf, t.width() * t.height() * sizeof(T)); | |||||
os->writeBytes((const uint8_t*)buf, | |||||
t.width() * t.height() * sizeof(T)); | |||||
oldBgValid = oldFgValid = false; | oldBgValid = oldFgValid = false; | ||||
continue; | continue; | ||||
} | } | ||||
if ( (tileType & hextileRaw) != 0 || | if ( (tileType & hextileRaw) != 0 || | ||||
encodedLen >= t.width() * t.height() * sizeof(T)) { | encodedLen >= t.width() * t.height() * sizeof(T)) { | ||||
os->writeU8(hextileRaw); | os->writeU8(hextileRaw); | ||||
os->writeBytes(buf, t.width() * t.height() * sizeof(T)); | |||||
os->writeBytes((const uint8_t*)buf, | |||||
t.width() * t.height() * sizeof(T)); | |||||
oldBgValid = oldFgValid = false; | oldBgValid = oldFgValid = false; | ||||
continue; | continue; | ||||
} | } |
delete[] rowPointer; | delete[] rowPointer; | ||||
} | } | ||||
void JpegCompressor::writeBytes(const void* /*data*/, int /*length*/) | |||||
void JpegCompressor::writeBytes(const uint8_t* /*data*/, int /*length*/) | |||||
{ | { | ||||
throw rdr::Exception("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead."); | throw rdr::Exception("writeBytes() is not valid with a JpegCompressor instance. Use compress() instead."); | ||||
} | } |
void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int); | void compress(const uint8_t *, int, const Rect&, const PixelFormat&, int, int); | ||||
void writeBytes(const void*, int); | |||||
void writeBytes(const uint8_t*, int); | |||||
private: | private: | ||||
return true; | return true; | ||||
} | } | ||||
void RREDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void RREDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) | ||||
{ | { |
virtual ~RREDecoder(); | virtual ~RREDecoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
private: | private: |
return true; | return true; | ||||
} | } | ||||
void RawDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void RawDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) | ||||
{ | { |
virtual ~RawDecoder(); | virtual ~RawDecoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
}; | }; |
char str[13]; | char str[13]; | ||||
sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion); | sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion); | ||||
os->writeBytes(str, 12); | |||||
os->writeBytes((const uint8_t*)str, 12); | |||||
os->flush(); | os->flush(); | ||||
state_ = RFBSTATE_PROTOCOL_VERSION; | state_ = RFBSTATE_PROTOCOL_VERSION; | ||||
if (!is->hasData(12)) | if (!is->hasData(12)) | ||||
return false; | return false; | ||||
is->readBytes(verStr, 12); | |||||
is->readBytes((uint8_t*)verStr, 12); | |||||
verStr[12] = '\0'; | verStr[12] = '\0'; | ||||
if (sscanf(verStr, "RFB %03d.%03d\n", | if (sscanf(verStr, "RFB %03d.%03d\n", | ||||
os->writeU32(secResultFailed); | os->writeU32(secResultFailed); | ||||
if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message | if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message | ||||
os->writeU32(authFailureMsg.size()); | os->writeU32(authFailureMsg.size()); | ||||
os->writeBytes(authFailureMsg.data(), authFailureMsg.size()); | |||||
os->writeBytes((const uint8_t*)authFailureMsg.data(), | |||||
authFailureMsg.size()); | |||||
} | } | ||||
os->flush(); | os->flush(); | ||||
} catch (rdr::Exception& e) { | } catch (rdr::Exception& e) { | ||||
if (client.majorVersion == 3 && client.minorVersion == 3) { | if (client.majorVersion == 3 && client.minorVersion == 3) { | ||||
os->writeU32(0); | os->writeU32(0); | ||||
os->writeU32(strlen(str)); | os->writeU32(strlen(str)); | ||||
os->writeBytes(str, strlen(str)); | |||||
os->writeBytes((const uint8_t*)str, strlen(str)); | |||||
os->flush(); | os->flush(); | ||||
} else { | } else { | ||||
os->writeU8(0); | os->writeU8(0); | ||||
os->writeU32(strlen(str)); | os->writeU32(strlen(str)); | ||||
os->writeBytes(str, strlen(str)); | |||||
os->writeBytes((const uint8_t*)str, strlen(str)); | |||||
os->flush(); | os->flush(); | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
hasLocalClipboard = false; | hasLocalClipboard = false; | ||||
clientClipboard = latin1ToUTF8(str); | |||||
clientClipboard = str; | |||||
hasRemoteClipboard = true; | hasRemoteClipboard = true; | ||||
handleClipboardAnnounce(true); | handleClipboardAnnounce(true); | ||||
return; | return; | ||||
} | } | ||||
// FIXME: This conversion magic should be in SMsgReader | |||||
if (!isValidUTF8((const char*)data[0], lengths[0])) { | |||||
vlog.error("Invalid UTF-8 sequence in clipboard - ignoring"); | |||||
return; | |||||
} | |||||
clientClipboard = convertLF((const char*)data[0], lengths[0]); | clientClipboard = convertLF((const char*)data[0], lengths[0]); | ||||
hasRemoteClipboard = true; | hasRemoteClipboard = true; | ||||
if (!reason) | if (!reason) | ||||
reason = "Authentication failure"; | reason = "Authentication failure"; | ||||
os->writeU32(strlen(reason)); | os->writeU32(strlen(reason)); | ||||
os->writeBytes(reason, strlen(reason)); | |||||
os->writeBytes((const uint8_t*)reason, strlen(reason)); | |||||
} | } | ||||
} | } | ||||
os->flush(); | os->flush(); | ||||
} | } | ||||
} | } | ||||
void SConnection::fence(uint32_t flags, unsigned len, const char data[]) | |||||
void SConnection::fence(uint32_t flags, unsigned len, | |||||
const uint8_t data[]) | |||||
{ | { | ||||
if (!(flags & fenceFlagRequest)) | if (!(flags & fenceFlagRequest)) | ||||
return; | return; | ||||
{ | { | ||||
if (client.supportsEncoding(pseudoEncodingExtendedClipboard) && | if (client.supportsEncoding(pseudoEncodingExtendedClipboard) && | ||||
(client.clipboardFlags() & rfb::clipboardProvide)) { | (client.clipboardFlags() & rfb::clipboardProvide)) { | ||||
// FIXME: This conversion magic should be in SMsgWriter | |||||
std::string filtered(convertCRLF(data)); | std::string filtered(convertCRLF(data)); | ||||
size_t sizes[1] = { filtered.size() + 1 }; | size_t sizes[1] = { filtered.size() + 1 }; | ||||
const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; | const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() }; | ||||
writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); | writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data); | ||||
} else { | } else { | ||||
std::string latin1(utf8ToLatin1(data)); | |||||
writer()->writeServerCutText(latin1.c_str()); | |||||
writer()->writeServerCutText(data); | |||||
} | } | ||||
} | } | ||||
// it responds directly to requests (stating it doesn't support any | // it responds directly to requests (stating it doesn't support any | ||||
// synchronisation) and drops responses. Override to implement more proper | // synchronisation) and drops responses. Override to implement more proper | ||||
// support. | // support. | ||||
virtual void fence(uint32_t flags, unsigned len, const char data[]); | |||||
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
// enableContinuousUpdates() is called when the client wants to enable | // enableContinuousUpdates() is called when the client wants to enable | ||||
// or disable continuous updates, or change the active area. | // or disable continuous updates, or change the active area. |
virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0; | virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0; | ||||
virtual void setDesktopSize(int fb_width, int fb_height, | virtual void setDesktopSize(int fb_width, int fb_height, | ||||
const ScreenSet& layout) = 0; | const ScreenSet& layout) = 0; | ||||
virtual void fence(uint32_t flags, unsigned len, const char data[]) = 0; | |||||
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]) = 0; | |||||
virtual void enableContinuousUpdates(bool enable, | virtual void enableContinuousUpdates(bool enable, | ||||
int x, int y, int w, int h) = 0; | int x, int y, int w, int h) = 0; | ||||
{ | { | ||||
uint32_t flags; | uint32_t flags; | ||||
uint8_t len; | uint8_t len; | ||||
char data[64]; | |||||
uint8_t data[64]; | |||||
if (!is->hasData(3 + 4 + 1)) | if (!is->hasData(3 + 4 + 1)) | ||||
return false; | return false; | ||||
} | } | ||||
std::vector<char> ca(len); | std::vector<char> ca(len); | ||||
is->readBytes(ca.data(), len); | |||||
std::string filtered(convertLF(ca.data(), len)); | |||||
is->readBytes((uint8_t*)ca.data(), len); | |||||
std::string utf8(latin1ToUTF8(ca.data(), ca.size())); | |||||
std::string filtered(convertLF(utf8.data(), utf8.size())); | |||||
handler->clientCutText(filtered.c_str()); | handler->clientCutText(filtered.c_str()); | ||||
return true; | return true; |
#include <rfb/SMsgWriter.h> | #include <rfb/SMsgWriter.h> | ||||
#include <rfb/LogWriter.h> | #include <rfb/LogWriter.h> | ||||
#include <rfb/ledStates.h> | #include <rfb/ledStates.h> | ||||
#include <rfb/util.h> | |||||
using namespace rfb; | using namespace rfb; | ||||
os->writeU16(height); | os->writeU16(height); | ||||
pf.write(os); | pf.write(os); | ||||
os->writeU32(strlen(name)); | os->writeU32(strlen(name)); | ||||
os->writeBytes(name, strlen(name)); | |||||
os->writeBytes((const uint8_t*)name, strlen(name)); | |||||
endMsg(); | endMsg(); | ||||
} | } | ||||
void SMsgWriter::writeServerCutText(const char* str) | void SMsgWriter::writeServerCutText(const char* str) | ||||
{ | { | ||||
size_t len; | |||||
if (strchr(str, '\r') != NULL) | if (strchr(str, '\r') != NULL) | ||||
throw Exception("Invalid carriage return in clipboard data"); | throw Exception("Invalid carriage return in clipboard data"); | ||||
len = strlen(str); | |||||
std::string latin1(utf8ToLatin1(str)); | |||||
startMsg(msgTypeServerCutText); | startMsg(msgTypeServerCutText); | ||||
os->pad(3); | os->pad(3); | ||||
os->writeU32(len); | |||||
os->writeBytes(str, len); | |||||
os->writeU32(latin1.size()); | |||||
os->writeBytes((const uint8_t*)latin1.data(), latin1.size()); | |||||
endMsg(); | endMsg(); | ||||
} | } | ||||
endMsg(); | endMsg(); | ||||
} | } | ||||
void SMsgWriter::writeFence(uint32_t flags, unsigned len, const char data[]) | |||||
void SMsgWriter::writeFence(uint32_t flags, unsigned len, | |||||
const uint8_t data[]) | |||||
{ | { | ||||
if (!client->supportsEncoding(pseudoEncodingFence)) | if (!client->supportsEncoding(pseudoEncodingFence)) | ||||
throw Exception("Client does not support fences"); | throw Exception("Client does not support fences"); | ||||
os->writeU16(0); | os->writeU16(0); | ||||
os->writeU32(pseudoEncodingDesktopName); | os->writeU32(pseudoEncodingDesktopName); | ||||
os->writeU32(strlen(name)); | os->writeU32(strlen(name)); | ||||
os->writeBytes(name, strlen(name)); | |||||
os->writeBytes((const uint8_t*)name, strlen(name)); | |||||
} | } | ||||
void SMsgWriter::writeSetCursorRect(int width, int height, | void SMsgWriter::writeSetCursorRect(int width, int height, | ||||
int hotspotX, int hotspotY, | int hotspotX, int hotspotY, | ||||
const void* data, const void* mask) | |||||
const uint8_t* data, | |||||
const uint8_t* mask) | |||||
{ | { | ||||
if (!client->supportsEncoding(pseudoEncodingCursor)) | if (!client->supportsEncoding(pseudoEncodingCursor)) | ||||
throw Exception("Client does not support local cursors"); | throw Exception("Client does not support local cursors"); | ||||
void SMsgWriter::writeSetXCursorRect(int width, int height, | void SMsgWriter::writeSetXCursorRect(int width, int height, | ||||
int hotspotX, int hotspotY, | int hotspotX, int hotspotY, | ||||
const void* data, const void* mask) | |||||
const uint8_t* data, | |||||
const uint8_t* mask) | |||||
{ | { | ||||
if (!client->supportsEncoding(pseudoEncodingXCursor)) | if (!client->supportsEncoding(pseudoEncodingXCursor)) | ||||
throw Exception("Client does not support local cursors"); | throw Exception("Client does not support local cursors"); |
const uint8_t* const* data); | const uint8_t* const* data); | ||||
// writeFence() sends a new fence request or response to the client. | // writeFence() sends a new fence request or response to the client. | ||||
void writeFence(uint32_t flags, unsigned len, const char data[]); | |||||
void writeFence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
// writeEndOfContinuousUpdates() indicates that we have left continuous | // writeEndOfContinuousUpdates() indicates that we have left continuous | ||||
// updates mode. | // updates mode. | ||||
void writeSetDesktopNameRect(const char *name); | void writeSetDesktopNameRect(const char *name); | ||||
void writeSetCursorRect(int width, int height, | void writeSetCursorRect(int width, int height, | ||||
int hotspotX, int hotspotY, | int hotspotX, int hotspotY, | ||||
const void* data, const void* mask); | |||||
const uint8_t* data, const uint8_t* mask); | |||||
void writeSetXCursorRect(int width, int height, | void writeSetXCursorRect(int width, int height, | ||||
int hotspotX, int hotspotY, | int hotspotX, int hotspotY, | ||||
const void* data, const void* mask); | |||||
const uint8_t* data, const uint8_t* mask); | |||||
void writeSetCursorWithAlphaRect(int width, int height, | void writeSetCursorWithAlphaRect(int width, int height, | ||||
int hotspotX, int hotspotY, | int hotspotX, int hotspotY, | ||||
const uint8_t* data); | const uint8_t* data); |
if (!is->hasData(ulen + plen)) | if (!is->hasData(ulen + plen)) | ||||
return false; | return false; | ||||
state = 2; | state = 2; | ||||
is->readBytes(username, ulen); | |||||
is->readBytes(password, plen); | |||||
is->readBytes((uint8_t*)username, ulen); | |||||
is->readBytes((uint8_t*)password, plen); | |||||
password[plen] = 0; | password[plen] = 0; | ||||
username[ulen] = 0; | username[ulen] = 0; | ||||
plen = 0; | plen = 0; |
uint8_t lenUsername = rais->readU8(); | uint8_t lenUsername = rais->readU8(); | ||||
if (!rais->hasDataOrRestore(lenUsername + 1)) | if (!rais->hasDataOrRestore(lenUsername + 1)) | ||||
return false; | return false; | ||||
rais->readBytes(username, lenUsername); | |||||
rais->readBytes((uint8_t*)username, lenUsername); | |||||
username[lenUsername] = 0; | username[lenUsername] = 0; | ||||
uint8_t lenPassword = rais->readU8(); | uint8_t lenPassword = rais->readU8(); | ||||
if (!rais->hasDataOrRestore(lenPassword)) | if (!rais->hasDataOrRestore(lenPassword)) | ||||
return false; | return false; | ||||
rais->readBytes(password, lenPassword); | |||||
rais->readBytes((uint8_t*)password, lenPassword); | |||||
password[lenPassword] = 0; | password[lenPassword] = 0; | ||||
rais->clearRestorePoint(); | rais->clearRestorePoint(); | ||||
return true; | return true; |
} | } | ||||
bool TightDecoder::doRectsConflict(const Rect& /*rectA*/, | bool TightDecoder::doRectsConflict(const Rect& /*rectA*/, | ||||
const void* bufferA, | |||||
const uint8_t* bufferA, | |||||
size_t buflenA, | size_t buflenA, | ||||
const Rect& /*rectB*/, | const Rect& /*rectB*/, | ||||
const void* bufferB, | |||||
const uint8_t* bufferB, | |||||
size_t buflenB, | size_t buflenB, | ||||
const ServerParams& /*server*/) | const ServerParams& /*server*/) | ||||
{ | { | ||||
return false; | return false; | ||||
} | } | ||||
void TightDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void TightDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) | ||||
{ | { |
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual bool doRectsConflict(const Rect& rectA, | virtual bool doRectsConflict(const Rect& rectA, | ||||
const void* bufferA, | |||||
const uint8_t* bufferA, | |||||
size_t buflenA, | size_t buflenA, | ||||
const Rect& rectB, | const Rect& rectB, | ||||
const void* bufferB, | |||||
const uint8_t* bufferB, | |||||
size_t buflenB, | size_t buflenB, | ||||
const ServerParams& server); | const ServerParams& server); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
writer()->writeDesktopSize(reasonClient, result); | writer()->writeDesktopSize(reasonClient, result); | ||||
} | } | ||||
void VNCSConnectionST::fence(uint32_t flags, unsigned len, const char data[]) | |||||
void VNCSConnectionST::fence(uint32_t flags, unsigned len, const uint8_t data[]) | |||||
{ | { | ||||
uint8_t type; | uint8_t type; | ||||
delete [] fenceData; | delete [] fenceData; | ||||
fenceData = NULL; | fenceData = NULL; | ||||
if (len > 0) { | if (len > 0) { | ||||
fenceData = new char[len]; | |||||
fenceData = new uint8_t[len]; | |||||
memcpy(fenceData, data, len); | memcpy(fenceData, data, len); | ||||
} | } | ||||
void VNCSConnectionST::supportsFence() | void VNCSConnectionST::supportsFence() | ||||
{ | { | ||||
char type = 0; | |||||
uint8_t type = 0; | |||||
writer()->writeFence(fenceFlagRequest, sizeof(type), &type); | writer()->writeFence(fenceFlagRequest, sizeof(type), &type); | ||||
} | } | ||||
void VNCSConnectionST::writeRTTPing() | void VNCSConnectionST::writeRTTPing() | ||||
{ | { | ||||
char type; | |||||
uint8_t type; | |||||
if (!client.supportsFence()) | if (!client.supportsFence()) | ||||
return; | return; |
virtual void framebufferUpdateRequest(const Rect& r, bool incremental); | virtual void framebufferUpdateRequest(const Rect& r, bool incremental); | ||||
virtual void setDesktopSize(int fb_width, int fb_height, | virtual void setDesktopSize(int fb_width, int fb_height, | ||||
const ScreenSet& layout); | const ScreenSet& layout); | ||||
virtual void fence(uint32_t flags, unsigned len, const char data[]); | |||||
virtual void fence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
virtual void enableContinuousUpdates(bool enable, | virtual void enableContinuousUpdates(bool enable, | ||||
int x, int y, int w, int h); | int x, int y, int w, int h); | ||||
virtual void handleClipboardRequest(); | virtual void handleClipboardRequest(); | ||||
bool pendingSyncFence, syncFence; | bool pendingSyncFence, syncFence; | ||||
uint32_t fenceFlags; | uint32_t fenceFlags; | ||||
unsigned fenceDataLen; | unsigned fenceDataLen; | ||||
char *fenceData; | |||||
uint8_t *fenceData; | |||||
Congestion congestion; | Congestion congestion; | ||||
Timer congestionTimer; | Timer congestionTimer; |
rdr::OutStream& os = sock->outStream(); | rdr::OutStream& os = sock->outStream(); | ||||
// Shortest possible way to tell a client it is not welcome | // Shortest possible way to tell a client it is not welcome | ||||
os.writeBytes("RFB 003.003\n", 12); | |||||
os.writeBytes((const uint8_t*)"RFB 003.003\n", 12); | |||||
os.writeU32(0); | os.writeU32(0); | ||||
const char* reason = "Too many security failures"; | const char* reason = "Too many security failures"; | ||||
os.writeU32(strlen(reason)); | os.writeU32(strlen(reason)); | ||||
os.writeBytes(reason, strlen(reason)); | |||||
os.writeBytes((const uint8_t*)reason, strlen(reason)); | |||||
os.flush(); | os.flush(); | ||||
} catch (rdr::Exception&) { | } catch (rdr::Exception&) { | ||||
} | } |
return true; | return true; | ||||
} | } | ||||
void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer, | |||||
void ZRLEDecoder::decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb) | ModifiablePixelBuffer* pb) | ||||
{ | { | ||||
*ptr = readOpaque24B(zis); | *ptr = readOpaque24B(zis); | ||||
} | } | ||||
} else { | } else { | ||||
zis->readBytes(buf, t.area() * sizeof(T)); | |||||
zis->readBytes((uint8_t*)buf, t.area() * sizeof(T)); | |||||
} | } | ||||
} else { | } else { |
virtual ~ZRLEDecoder(); | virtual ~ZRLEDecoder(); | ||||
virtual bool readRect(const Rect& r, rdr::InStream* is, | virtual bool readRect(const Rect& r, rdr::InStream* is, | ||||
const ServerParams& server, rdr::OutStream* os); | const ServerParams& server, rdr::OutStream* os); | ||||
virtual void decodeRect(const Rect& r, const void* buffer, | |||||
virtual void decodeRect(const Rect& r, const uint8_t* buffer, | |||||
size_t buflen, const ServerParams& server, | size_t buflen, const ServerParams& server, | ||||
ModifiablePixelBuffer* pb); | ModifiablePixelBuffer* pb); | ||||
*dst++ = 0x80 | (src & 0x3f); | *dst++ = 0x80 | (src & 0x3f); | ||||
*dst++ = '\0'; | *dst++ = '\0'; | ||||
return 2; | return 2; | ||||
} else if ((src >= 0xd800) && (src < 0xe000)) { | |||||
return ucs4ToUTF8(0xfffd, dst); | |||||
} else if (src < 0x10000) { | } else if (src < 0x10000) { | ||||
*dst++ = 0xe0 | (src >> 12); | *dst++ = 0xe0 | (src >> 12); | ||||
*dst++ = 0x80 | ((src >> 6) & 0x3f); | *dst++ = 0x80 | ((src >> 6) & 0x3f); | ||||
max--; | max--; | ||||
} | } | ||||
// UTF-16 surrogate code point? | |||||
if ((*dst >= 0xd800) && (*dst < 0xe000)) | |||||
*dst = 0xfffd; | |||||
return consumed; | return consumed; | ||||
} | } | ||||
return out; | return out; | ||||
} | } | ||||
bool isValidUTF8(const char* str, size_t bytes) | |||||
{ | |||||
while ((bytes > 0) && (*str != '\0')) { | |||||
size_t len; | |||||
unsigned ucs; | |||||
len = utf8ToUCS4(str, bytes, &ucs); | |||||
str += len; | |||||
bytes -= len; | |||||
if (ucs == 0xfffd) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool isValidUTF16(const wchar_t* wstr, size_t units) | |||||
{ | |||||
while ((units > 0) && (*wstr != '\0')) { | |||||
size_t len; | |||||
unsigned ucs; | |||||
len = utf16ToUCS4(wstr, units, &ucs); | |||||
wstr += len; | |||||
units -= len; | |||||
if (ucs == 0xfffd) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
unsigned msBetween(const struct timeval *first, | unsigned msBetween(const struct timeval *first, | ||||
const struct timeval *second) | const struct timeval *second) | ||||
{ | { |
std::string utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1); | std::string utf16ToUTF8(const wchar_t* src, size_t units = (size_t)-1); | ||||
std::wstring utf8ToUTF16(const char* src, size_t bytes = (size_t)-1); | std::wstring utf8ToUTF16(const char* src, size_t bytes = (size_t)-1); | ||||
bool isValidUTF8(const char* str, size_t bytes = (size_t)-1); | |||||
bool isValidUTF16(const wchar_t* wstr, size_t units = (size_t)-1); | |||||
// HELPER functions for timeout handling | // HELPER functions for timeout handling | ||||
// soonestTimeout() is a function to help work out the soonest of several | // soonestTimeout() is a function to help work out the soonest of several |
{ 0x1f638, "\xf0\x9f\x98\xb8" }, | { 0x1f638, "\xf0\x9f\x98\xb8" }, | ||||
{ 0x2d006, "\xf0\xad\x80\x86" }, | { 0x2d006, "\xf0\xad\x80\x86" }, | ||||
{ 0xfffd, "\xe5\xe4" }, | { 0xfffd, "\xe5\xe4" }, | ||||
{ 0xfffd, "\xed\xa2\x80" }, | |||||
{ 0xfffd, "\xed\xbb\xbf" }, | |||||
{ 0xd880, "\xef\xbf\xbd" }, | |||||
{ 0xdeff, "\xef\xbf\xbd" }, | |||||
{ 0x110200, "\xef\xbf\xbd" }, | { 0x110200, "\xef\xbf\xbd" }, | ||||
}; | }; | ||||
{ "\xed\xa1\xbf", L"\xfffd" }, | { "\xed\xa1\xbf", L"\xfffd" }, | ||||
}; | }; | ||||
const char *validutf8[] = { | |||||
"abc", | |||||
"\xc3\xa5\xc3\xa4\xc3\xb6", | |||||
"\xf0\xad\x80\x86", | |||||
}; | |||||
const char *invalidutf8[] = { | |||||
"\xe5\xe4\xf6", | |||||
"\xf8\xa1\xa1\xa1\xa1", | |||||
"\xed\xa2\x80", | |||||
}; | |||||
const wchar_t *validutf16[] = { | |||||
L"abc", | |||||
L"\xe5\xe4\xf6", | |||||
L"\xd83d\xde38\xd83d\xde41\xd83d\xde42", | |||||
}; | |||||
const wchar_t *invalidutf16[] = { | |||||
L"\xdc40\xdc12", | |||||
}; | |||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a)) | #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a)) | ||||
int main(int /*argc*/, char** /*argv*/) | int main(int /*argc*/, char** /*argv*/) | ||||
} | } | ||||
} | } | ||||
for (i = 0;i < ARRAY_SIZE(validutf8);i++) { | |||||
if (!rfb::isValidUTF8(validutf8[i])) { | |||||
printf("FAILED: isValidUTF8() #%d\n", (int)i+1); | |||||
failures++; | |||||
} | |||||
} | |||||
for (i = 0;i < ARRAY_SIZE(invalidutf8);i++) { | |||||
if (rfb::isValidUTF8(invalidutf8[i])) { | |||||
printf("FAILED: ! isValidUTF8() #%d\n", (int)i+1); | |||||
failures++; | |||||
} | |||||
} | |||||
for (i = 0;i < ARRAY_SIZE(validutf16);i++) { | |||||
if (!rfb::isValidUTF16(validutf16[i])) { | |||||
printf("FAILED: isValidUTF16() #%d\n", (int)i+1); | |||||
failures++; | |||||
} | |||||
} | |||||
for (i = 0;i < ARRAY_SIZE(invalidutf16);i++) { | |||||
if (rfb::isValidUTF16(invalidutf16[i])) { | |||||
printf("FAILED: ! isValidUTF16() #%d\n", (int)i+1); | |||||
failures++; | |||||
} | |||||
} | |||||
if (failures == 0) { | if (failures == 0) { | ||||
printf("OK\n"); | printf("OK\n"); | ||||
} else { | } else { |
return NULL; | return NULL; | ||||
} | } | ||||
} | } | ||||
int vncIsValidUTF8(const char* str, size_t bytes) | |||||
{ | |||||
try { | |||||
return isValidUTF8(str, bytes); | |||||
} catch (...) { | |||||
return 0; | |||||
} | |||||
} |
char* vncLatin1ToUTF8(const char* src, size_t bytes); | char* vncLatin1ToUTF8(const char* src, size_t bytes); | ||||
char* vncUTF8ToLatin1(const char* src, size_t bytes); | char* vncUTF8ToLatin1(const char* src, size_t bytes); | ||||
int vncIsValidUTF8(const char* str, size_t bytes); | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #endif |
if (prop->type != xaUTF8_STRING) | if (prop->type != xaUTF8_STRING) | ||||
return; | return; | ||||
if (!vncIsValidUTF8(prop->data, prop->size)) { | |||||
LOG_ERROR("Invalid UTF-8 sequence in clipboard"); | |||||
return; | |||||
} | |||||
filtered = vncConvertLF(prop->data, prop->size); | filtered = vncConvertLF(prop->data, prop->size); | ||||
if (filtered == NULL) | if (filtered == NULL) | ||||
return; | return; |
desktop->setCursorPos(pos); | desktop->setCursorPos(pos); | ||||
} | } | ||||
void CConn::fence(uint32_t flags, unsigned len, const char data[]) | |||||
void CConn::fence(uint32_t flags, unsigned len, const uint8_t data[]) | |||||
{ | { | ||||
CMsgHandler::fence(flags, len, data); | CMsgHandler::fence(flags, len, data); | ||||
const uint8_t* data); | const uint8_t* data); | ||||
void setCursorPos(const rfb::Point& pos); | void setCursorPos(const rfb::Point& pos); | ||||
void fence(uint32_t flags, unsigned len, const char data[]); | |||||
void fence(uint32_t flags, unsigned len, const uint8_t data[]); | |||||
void setLEDState(unsigned int state); | void setLEDState(unsigned int state); | ||||
switch (event) { | switch (event) { | ||||
case FL_PASTE: | case FL_PASTE: | ||||
if (!isValidUTF8(Fl::event_text(), Fl::event_length())) { | |||||
vlog.error("Invalid UTF-8 sequence in system clipboard"); | |||||
return 1; | |||||
} | |||||
filtered = convertLF(Fl::event_text(), Fl::event_length()); | filtered = convertLF(Fl::event_text(), Fl::event_length()); | ||||
vlog.debug("Sending clipboard data (%d bytes)", (int)filtered.size()); | vlog.debug("Sending clipboard data (%d bytes)", (int)filtered.size()); |