Files
barrier/server/CServerProtocol1_0.cpp
crs ed8ed72f26 synergy hook DLL will now restart itself if a client tries to
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).
2002-06-26 16:31:48 +00:00

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());
}