mirror of
https://github.com/debauchee/barrier.git
synced 2026-02-08 12:53:53 +08:00
init() it while it's already running. fixed an uninitialized pointer bug in CServer and some cleanup-on-error code in CMSWindowsPrimaryScreen. also added timeout to read() on IInputStream and a heartbeat sent by clients so the server can disconnect clients that are dead but never reset the TCP connection. previously the server would keep these dead clients around forever and if the user was locked on the client screen for some reason then the server would have to be rebooted (or the server would have to be killed via a remote login).
282 lines
7.1 KiB
C++
282 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) {
|
|
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());
|
|
}
|