284 lines
7.1 KiB
C++
284 lines
7.1 KiB
C++
#include "CServerProtocol1_0.h"
|
|
#include "CServer.h"
|
|
#include "CClipboard.h"
|
|
#include "CProtocolUtil.h"
|
|
#include "ProtocolTypes.h"
|
|
#include "XSynergy.h"
|
|
#include "IInputStream.h"
|
|
#include "IOutputStream.h"
|
|
#include "CThread.h"
|
|
#include "CLog.h"
|
|
#include "CStopwatch.h"
|
|
#include <cstring>
|
|
|
|
//
|
|
// CServerProtocol1_0
|
|
//
|
|
|
|
CServerProtocol1_0::CServerProtocol1_0(CServer* server, const CString& client,
|
|
IInputStream* input, IOutputStream* output) :
|
|
CServerProtocol(server, client, input, output)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
CServerProtocol1_0::~CServerProtocol1_0()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::run()
|
|
{
|
|
// handle messages until the client hangs up or stops sending heartbeats
|
|
CStopwatch heartTimer;
|
|
for (;;) {
|
|
CThread::testCancel();
|
|
|
|
// wait for a message
|
|
UInt8 code[4];
|
|
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
|
|
CThread::testCancel();
|
|
|
|
// check if client hungup
|
|
if (n == 0) {
|
|
log((CLOG_NOTE "client \"%s\" disconnected", getClient().c_str()));
|
|
return;
|
|
}
|
|
|
|
// check if client has stopped sending heartbeats
|
|
if (n == (UInt32)-1) {
|
|
/* FIXME -- disabled to avoid masking bugs
|
|
if (heartTimer.getTime() > kHeartDeath) {
|
|
log((CLOG_NOTE "client \"%s\" is dead", getClient().c_str()));
|
|
return;
|
|
}
|
|
*/
|
|
continue;
|
|
}
|
|
|
|
// got a message so reset heartbeat monitor
|
|
heartTimer.reset();
|
|
|
|
// verify we got an entire code
|
|
if (n != 4) {
|
|
log((CLOG_ERR "incomplete message from \"%s\": %d bytes", getClient().c_str(), n));
|
|
|
|
// client sent an incomplete message
|
|
throw XBadClient();
|
|
}
|
|
|
|
// parse message
|
|
log((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getClient().c_str(), code[0], code[1], code[2], code[3]));
|
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
|
recvInfo();
|
|
}
|
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
|
// discard no-ops
|
|
continue;
|
|
}
|
|
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
|
recvGrabClipboard();
|
|
}
|
|
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
|
recvClipboard();
|
|
}
|
|
// FIXME -- more message here
|
|
else {
|
|
log((CLOG_ERR "invalid message from client \"%s\"", getClient().c_str()));
|
|
|
|
// unknown message
|
|
throw XBadClient();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::queryInfo()
|
|
{
|
|
log((CLOG_DEBUG1 "querying client \"%s\" info", getClient().c_str()));
|
|
|
|
// send request
|
|
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
|
|
|
|
// wait for and verify reply
|
|
UInt8 code[4];
|
|
for (;;) {
|
|
UInt32 n = getInputStream()->read(code, 4, -1.0);
|
|
if (n == 4) {
|
|
if (memcmp(code, kMsgCNoop, 4) == 0) {
|
|
// discard heartbeats
|
|
continue;
|
|
}
|
|
if (memcmp(code, kMsgDInfo, 4) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
throw XBadClient();
|
|
}
|
|
|
|
// handle reply
|
|
recvInfo();
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendClose()
|
|
{
|
|
log((CLOG_DEBUG1 "send close to \"%s\"", getClient().c_str()));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
|
|
|
|
// force the close to be sent before we return
|
|
getOutputStream()->flush();
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendEnter(SInt32 xAbs, SInt32 yAbs,
|
|
UInt32 seqNum, KeyModifierMask mask)
|
|
{
|
|
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getClient().c_str(), xAbs, yAbs, seqNum, mask));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
|
|
xAbs, yAbs, seqNum, mask);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendLeave()
|
|
{
|
|
log((CLOG_DEBUG1 "send leave to \"%s\"", getClient().c_str()));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendClipboard(ClipboardID id, const CString& data)
|
|
{
|
|
log((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getClient().c_str(), data.size()));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendGrabClipboard(ClipboardID id)
|
|
{
|
|
log((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getClient().c_str()));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendScreenSaver(bool on)
|
|
{
|
|
log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getClient().c_str(), on ? 1 : 0));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendInfoAcknowledgment()
|
|
{
|
|
log((CLOG_DEBUG1 "send info ack to \"%s\"", getClient().c_str()));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendKeyDown(KeyID key, KeyModifierMask mask)
|
|
{
|
|
log((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendKeyRepeat(KeyID key, KeyModifierMask mask, SInt32 count)
|
|
{
|
|
log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getClient().c_str(), key, mask, count));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendKeyUp(KeyID key, KeyModifierMask mask)
|
|
{
|
|
log((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendMouseDown(ButtonID button)
|
|
{
|
|
log((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getClient().c_str(), button));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendMouseUp(ButtonID button)
|
|
{
|
|
log((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getClient().c_str(), button));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendMouseMove(SInt32 xAbs, SInt32 yAbs)
|
|
{
|
|
log((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getClient().c_str(), xAbs, yAbs));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::sendMouseWheel(SInt32 delta)
|
|
{
|
|
log((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getClient().c_str(), delta));
|
|
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::recvInfo()
|
|
{
|
|
// parse the message
|
|
SInt16 x, y, w, h, zoneInfo, mx, my;
|
|
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
|
|
&x, &y, &w, &h, &zoneInfo, &mx, &my);
|
|
log((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getClient().c_str(), x, y, w, h, zoneInfo, mx, my));
|
|
|
|
// validate
|
|
if (w <= 0 || h <= 0 || zoneInfo < 0) {
|
|
throw XBadClient();
|
|
}
|
|
if (mx < x || my < y || mx >= x + w || my >= y + h) {
|
|
throw XBadClient();
|
|
}
|
|
|
|
// tell server of change
|
|
getServer()->setInfo(getClient(), x, y, w, h, zoneInfo, mx, my);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::recvClipboard()
|
|
{
|
|
// parse message
|
|
ClipboardID id;
|
|
UInt32 seqNum;
|
|
CString data;
|
|
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
|
|
log((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getClient().c_str(), id, seqNum, data.size()));
|
|
|
|
// validate
|
|
if (id >= kClipboardEnd) {
|
|
throw XBadClient();
|
|
}
|
|
|
|
// send update
|
|
getServer()->setClipboard(id, seqNum, data);
|
|
}
|
|
|
|
void
|
|
CServerProtocol1_0::recvGrabClipboard()
|
|
{
|
|
// parse message
|
|
ClipboardID id;
|
|
UInt32 seqNum;
|
|
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
|
|
log((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getClient().c_str(), id, seqNum));
|
|
|
|
// validate
|
|
if (id >= kClipboardEnd) {
|
|
throw XBadClient();
|
|
}
|
|
|
|
// send update
|
|
getServer()->grabClipboard(id, seqNum, getClient());
|
|
}
|