deskflow/src/lib/synergy/ProtocolUtil.cpp

563 lines
15 KiB
C++
Raw Normal View History

2012-06-10 16:50:54 +00:00
/*
* synergy -- mouse and keyboard sharing utility
2016-09-07 14:24:00 +00:00
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
2012-06-10 16:50:54 +00:00
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
2012-06-10 16:50:54 +00:00
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <array>
#include <iterator>
#include "synergy/ProtocolUtil.h"
#include "io/IStream.h"
#include "base/Log.h"
#include "common/stdvector.h"
2012-06-10 16:50:54 +00:00
#include <cctype>
#include <cstring>
//
2014-11-11 13:51:47 +00:00
// ProtocolUtil
2012-06-10 16:50:54 +00:00
//
namespace {
void
writeInt(UInt32 Value, UInt32 Length, std::vector<UInt8>& Buffer)
{
switch(Length)
{
case 1:
Buffer.push_back(static_cast<UInt8>(Value & 0xffU));
break;
case 4:
Buffer.push_back(static_cast<UInt8>((Value >> 24U) & 0xffU));
Buffer.push_back(static_cast<UInt8>((Value >> 16U) & 0xffU));
Buffer.push_back(static_cast<UInt8>((Value >> 8U) & 0xffU));
Buffer.push_back(static_cast<UInt8>( Value & 0xffU));
break;
case 2:
Buffer.push_back(static_cast<UInt8>((Value >> 8U) & 0xffU));
Buffer.push_back(static_cast<UInt8>( Value & 0xffU));
break;
default:
assert(0 && "invalid integer format length");
return;
}
}
template <typename T>
void
writeVectorInt(const std::vector<T>* VectorData, std::vector<UInt8>& Buffer)
{
if (VectorData) {
const std::vector<T>& Vector = *VectorData;
writeInt((UInt32)Vector.size(), sizeof(UInt32), Buffer);
for (size_t i = 0; i < Vector.size(); ++i) {
writeInt(Vector[i], sizeof(T), Buffer);
}
}
}
void
writeString(const String* StringData, std::vector<UInt8>& Buffer)
{
const UInt32 len = (StringData != NULL) ? (UInt32)StringData->size() : 0;
writeInt(len, sizeof(len), Buffer);
if (len != 0) {
std::copy(StringData->begin(), StringData->end(), std::back_inserter(Buffer));
}
}
} //namespace
2012-06-10 16:50:54 +00:00
void
2014-11-11 13:51:47 +00:00
ProtocolUtil::writef(synergy::IStream* stream, const char* fmt, ...)
2012-06-10 16:50:54 +00:00
{
assert(stream != NULL);
assert(fmt != NULL);
LOG((CLOG_DEBUG2 "writef(%s)", fmt));
va_list args;
va_start(args, fmt);
UInt32 size = getLength(fmt, args);
va_end(args);
va_start(args, fmt);
vwritef(stream, fmt, size, args);
va_end(args);
2012-06-10 16:50:54 +00:00
}
bool
2014-11-11 13:51:47 +00:00
ProtocolUtil::readf(synergy::IStream* stream, const char* fmt, ...)
2012-06-10 16:50:54 +00:00
{
bool result = false;
if (stream && fmt) {
LOG((CLOG_DEBUG2 "readf(%s)", fmt));
va_list args;
va_start(args, fmt);
try {
vreadf(stream, fmt, args);
result = true;
}
catch (XIO&) {
result = false;
}
catch (const std::bad_alloc&) {
result = false;
}
va_end(args);
}
return result;
2012-06-10 16:50:54 +00:00
}
void
2014-11-11 13:51:47 +00:00
ProtocolUtil::vwritef(synergy::IStream* stream,
const char* fmt, UInt32 size, va_list args)
2012-06-10 16:50:54 +00:00
{
assert(stream != NULL);
assert(fmt != NULL);
// done if nothing to write
if (size == 0) {
return;
}
// fill buffer
std::vector<UInt8> Buffer;
writef(Buffer, fmt, args);
try {
// write buffer
stream->write(Buffer.data(), size);
LOG((CLOG_DEBUG2 "wrote %d bytes", size));
}
catch (const XBase& exception) {
LOG((CLOG_DEBUG2 "Exception <%s> during wrote %d bytes into stream", exception.what(), size));
throw;
}
2012-06-10 16:50:54 +00:00
}
void
2014-11-11 13:51:47 +00:00
ProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args)
2012-06-10 16:50:54 +00:00
{
assert(stream != NULL);
assert(fmt != NULL);
// begin scanning
while (*fmt) {
if (*fmt == '%') {
// format specifier. determine argument size.
++fmt;
UInt32 len = eatLength(&fmt);
switch (*fmt) {
case 'i': {
void* destination = va_arg(args, void*);
switch (len) {
case 1:
// 1 byte integer
*static_cast<UInt8*>(destination) = read1ByteInt(stream);
break;
case 2:
// 2 byte integer
*static_cast<UInt16*>(destination) = read2BytesInt(stream);
break;
case 4:
// 4 byte integer
*static_cast<UInt32*>(destination) = read4BytesInt(stream);
break;
default:
//the length is wrong
LOG((CLOG_ERR "read: length to be read is wrong: '%d' should be 1,2, or 4", len));
assert(false); //assert for debugging
break;
}
break;
}
case 'I': {
void* destination = va_arg(args, void*);
switch (len) {
case 1:
// 1 byte integer
readVector1ByteInt(stream, *static_cast<std::vector<UInt8>*>(destination));
break;
case 2:
// 2 byte integer
readVector2BytesInt(stream, *static_cast<std::vector<UInt16>*>(destination));
break;
case 4:
// 4 byte integer
readVector4BytesInt(stream, *static_cast<std::vector<UInt32>*>(destination));
break;
default:
//the length is wrong
LOG((CLOG_ERR "read: length to be read is wrong: '%d' should be 1,2, or 4", len));
assert(false); //assert for debugging
break;
}
break;
}
case 's': {
String* destination = va_arg(args, String*);
readBytes(stream, len, destination);
break;
}
case '%':
assert(len == 0);
break;
default:
assert(0 && "invalid format specifier");
}
// next format character
++fmt;
}
else {
// read next character
char buffer[1];
read(stream, buffer, 1);
// verify match
if (buffer[0] != *fmt) {
LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0]));
throw XIOReadMismatch();
}
// next format character
++fmt;
}
}
2012-06-10 16:50:54 +00:00
}
UInt32
2014-11-11 13:51:47 +00:00
ProtocolUtil::getLength(const char* fmt, va_list args)
2012-06-10 16:50:54 +00:00
{
UInt32 n = 0;
while (*fmt) {
if (*fmt == '%') {
// format specifier. determine argument size.
++fmt;
UInt32 len = eatLength(&fmt);
switch (*fmt) {
case 'i':
assert(len == 1 || len == 2 || len == 4);
(void)va_arg(args, UInt32);
break;
case 'I':
assert(len == 1 || len == 2 || len == 4);
switch (len) {
case 1:
len = (UInt32)(va_arg(args, std::vector<UInt8>*))->size() + 4;
break;
case 2:
len = 2 * (UInt32)(va_arg(args, std::vector<UInt16>*))->size() + 4;
break;
case 4:
len = 4 * (UInt32)(va_arg(args, std::vector<UInt32>*))->size() + 4;
break;
}
break;
case 's':
assert(len == 0);
len = (UInt32)(va_arg(args, String*))->size() + 4;
break;
case 'S':
assert(len == 0);
len = va_arg(args, UInt32) + 4;
break;
case '%':
assert(len == 0);
len = 1;
break;
default:
assert(0 && "invalid format specifier");
}
// accumulate size
n += len;
++fmt;
}
else {
// regular character
++n;
++fmt;
}
}
return n;
2012-06-10 16:50:54 +00:00
}
2012-06-10 16:50:54 +00:00
void
ProtocolUtil::writef(std::vector<UInt8>& buffer, const char* fmt, va_list args)
2012-06-10 16:50:54 +00:00
{
while (*fmt) {
if (*fmt == '%') {
// format specifier. determine argument size.
++fmt;
UInt32 len = eatLength(&fmt);
switch (*fmt) {
case 'i': {
const UInt32 v = va_arg(args, UInt32);
writeInt(v, len, buffer);
break;
}
case 'I': {
switch (len) {
case 1: {
// 1 byte integers
const std::vector<UInt8>* list = va_arg(args, const std::vector<UInt8>*);
writeVectorInt(list, buffer);
break;
}
case 2: {
// 2 byte integers
const std::vector<UInt16>* list = va_arg(args, const std::vector<UInt16>*);
writeVectorInt(list, buffer);
break;
}
case 4: {
// 4 byte integers
const std::vector<UInt32>* list = va_arg(args, const std::vector<UInt32>*);
writeVectorInt(list, buffer);
break;
}
default:
assert(0 && "invalid integer vector format length");
return;
}
break;
}
case 's': {
assert(len == 0);
const String* src = va_arg(args, String*);
writeString(src, buffer);
break;
}
case 'S': {
assert(len == 0);
const UInt32 len = va_arg(args, UInt32);
const UInt8* src = va_arg(args, UInt8*);
writeInt(len, sizeof(len), buffer);
std::copy(src, src + len, std::back_inserter(buffer));
break;
}
case '%':
assert(len == 0);
buffer.push_back('%');
break;
default:
assert(0 && "invalid format specifier");
}
// next format character
++fmt;
}
else {
// copy regular character
buffer.push_back(*fmt++);
}
}
2012-06-10 16:50:54 +00:00
}
UInt32
2014-11-11 13:51:47 +00:00
ProtocolUtil::eatLength(const char** pfmt)
2012-06-10 16:50:54 +00:00
{
const char* fmt = *pfmt;
UInt32 n = 0;
for (;;) {
UInt32 d;
switch (*fmt) {
case '0': d = 0; break;
case '1': d = 1; break;
case '2': d = 2; break;
case '3': d = 3; break;
case '4': d = 4; break;
case '5': d = 5; break;
case '6': d = 6; break;
case '7': d = 7; break;
case '8': d = 8; break;
case '9': d = 9; break;
default: *pfmt = fmt; return n;
}
n = 10 * n + d;
++fmt;
}
2012-06-10 16:50:54 +00:00
}
void
2014-11-11 13:51:47 +00:00
ProtocolUtil::read(synergy::IStream* stream, void* vbuffer, UInt32 count)
2012-06-10 16:50:54 +00:00
{
assert(stream != NULL);
assert(vbuffer != NULL);
UInt8* buffer = static_cast<UInt8*>(vbuffer);
while (count > 0) {
// read more
UInt32 n = stream->read(buffer, count);
// bail if stream has hungup
if (n == 0) {
LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", count));
throw XIOEndOfStream();
}
// prepare for next read
buffer += n;
count -= n;
}
2012-06-10 16:50:54 +00:00
}
UInt8 ProtocolUtil::read1ByteInt(synergy::IStream * stream)
{
const UInt32 BufferSize = 1;
std::array<UInt8, 1> buffer = {};
read(stream, buffer.data(), BufferSize);
UInt8 Result = buffer[0];
LOG((CLOG_DEBUG2 "readf: read 1 byte integer: %d (0x%x)", Result, Result));
return Result;
}
UInt16 ProtocolUtil::read2BytesInt(synergy::IStream * stream)
{
const UInt32 BufferSize = 2;
std::array<UInt8, BufferSize> buffer = {};
read(stream, buffer.data(), BufferSize);
UInt16 Result = static_cast<UInt16>((static_cast<UInt16>(buffer[0]) << 8) | static_cast<UInt16>(buffer[1]));
LOG((CLOG_DEBUG2 "readf: read 2 byte integer: %d (0x%x)", Result, Result));
return Result;
}
UInt32 ProtocolUtil::read4BytesInt(synergy::IStream * stream)
{
const int BufferSize = 4;
std::array<UInt8, BufferSize> buffer = {};
read(stream, buffer.data(), BufferSize);
UInt32 Result = (static_cast<UInt32>(buffer[0]) << 24) |
(static_cast<UInt32>(buffer[1]) << 16) |
(static_cast<UInt32>(buffer[2]) << 8) |
(static_cast<UInt32>(buffer[3]));
LOG((CLOG_DEBUG2 "readf: read 4 byte integer: %d (0x%x)", Result, Result));
return Result;
}
void ProtocolUtil::readVector1ByteInt(synergy::IStream* stream, std::vector<UInt8>& destination)
{
UInt32 size = read4BytesInt(stream);
for (UInt32 i = 0; i < size; ++i) {
destination.push_back(read1ByteInt(stream));
}
}
void ProtocolUtil::readVector2BytesInt(synergy::IStream* stream, std::vector<UInt16>& destination)
{
UInt32 size = read4BytesInt(stream);
for (UInt32 i = 0; i < size; ++i) {
destination.push_back(read2BytesInt(stream));
}
}
void ProtocolUtil::readVector4BytesInt(synergy::IStream* stream, std::vector<UInt32>& destination)
{
UInt32 size = read4BytesInt(stream);
for (UInt32 i = 0; i < size; ++i) {
destination.push_back(read4BytesInt(stream));
}
}
void ProtocolUtil::readBytes(synergy::IStream * stream, UInt32 len, String* destination) {
assert(len == 0);
// read the string length
UInt8 buffer[128];
len = read4BytesInt(stream);
// use a fixed size buffer if its big enough
const bool useFixed = (len <= sizeof(buffer));
// allocate a buffer to read the data
UInt8* sBuffer = buffer;
if (!useFixed) {
try{
sBuffer = new UInt8[len];
}
catch (std::bad_alloc & exception) {
// Added try catch due to GHSA-chfm-333q-gfpp
LOG((CLOG_ERR "ALLOC: Unable to allocate memory %d bytes", len));
LOG((CLOG_DEBUG "bad_alloc detected: Do you have enough free memory?"));
throw exception;
}
}
// read the data
try {
read(stream, sBuffer, len);
}
catch (...) {
if (!useFixed) {
delete[] sBuffer;
}
throw;
}
LOG((CLOG_DEBUG2 "readf: read %d byte string", len));
// save the data
if (destination){
destination->assign((const char*)sBuffer, len);
}
// release the buffer
if (!useFixed) {
delete[] sBuffer;
}
}
2012-06-10 16:50:54 +00:00
//
// XIOReadMismatch
//
2014-11-11 13:51:47 +00:00
String
2012-06-10 16:50:54 +00:00
XIOReadMismatch::getWhat() const throw()
{
return format("XIOReadMismatch", "ProtocolUtil::readf() mismatch");
2012-06-10 16:50:54 +00:00
}