Files
barrier/lib/server/CClientProxy1_0.cpp
crs fee4095624 Reorganized source tree. Moved client.cpp into cmd/synergy as
synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp.
Moved and renamed related files.  Moved remaining source files
into lib/....  Modified and added makefiles as appropriate.
Result is that library files are under lib with each library
in its own directory and program files are under cmd with each
command in its own directory.
2002-07-30 16:52:46 +00:00

354 lines
8.4 KiB
C++

#include "CClientProxy1_0.h"
#include "CServer.h"
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "XSynergy.h"
#include "IInputStream.h"
#include "IOutputStream.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
#include "CStopwatch.h"
#include <cstring>
//
// CClientProxy1_0
//
CClientProxy1_0::CClientProxy1_0(IServer* server, const CString& name,
IInputStream* input, IOutputStream* output) :
CClientProxy(server, name, input, output)
{
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = true;
}
}
CClientProxy1_0::~CClientProxy1_0()
{
// do nothing
}
bool
CClientProxy1_0::open()
{
// send request
log((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
getOutputStream()->flush();
// 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(false);
return true;
}
void
CClientProxy1_0::mainLoop()
{
// 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", getName().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", getName().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", getName().c_str(), n));
// client sent an incomplete message
throw XBadClient();
}
// parse message
log((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
if (memcmp(code, kMsgDInfo, 4) == 0) {
recvInfo(true);
}
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();
}
// note -- more message handlers go here
else {
log((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
// unknown message
throw XBadClient();
}
}
}
void
CClientProxy1_0::close()
{
log((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
// force the close to be sent before we return
getOutputStream()->flush();
}
void
CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool)
{
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask);
}
bool
CClientProxy1_0::leave()
{
log((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
// we can never prevent the user from leaving
return true;
}
void
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
{
// ignore if this clipboard is already clean
CLock lock(&m_mutex);
if (m_clipboardDirty[id]) {
// this clipboard is now clean
m_clipboardDirty[id] = false;
log((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
}
}
void
CClientProxy1_0::grabClipboard(ClipboardID id)
{
log((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
// this clipboard is now dirty
CLock lock(&m_mutex);
m_clipboardDirty[id] = true;
}
void
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
{
CLock lock(&m_mutex);
m_clipboardDirty[id] = dirty;
}
void
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask);
}
void
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count)
{
log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
}
void
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask);
}
void
CClientProxy1_0::mouseDown(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
}
void
CClientProxy1_0::mouseUp(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
}
void
CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
{
log((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
}
void
CClientProxy1_0::mouseWheel(SInt32 delta)
{
log((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), delta));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
}
void
CClientProxy1_0::screensaver(bool on)
{
log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
}
SInt32
CClientProxy1_0::getJumpZoneSize() const
{
CLock lock(&m_mutex);
return m_info.m_zoneSize;
}
void
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
CLock lock(&m_mutex);
x = m_info.m_x;
y = m_info.m_y;
w = m_info.m_w;
h = m_info.m_h;
}
void
CClientProxy1_0::getCursorPos(SInt32&, SInt32&) const
{
assert(0 && "shouldn't be called");
}
void
CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
x = m_info.m_mx;
y = m_info.m_my;
}
void
CClientProxy1_0::recvInfo(bool notify)
{
{
CLock lock(&m_mutex);
// parse the message
SInt16 x, y, w, h, zoneSize, mx, my;
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &zoneSize, &mx, &my);
log((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), x, y, w, h, zoneSize, mx, my));
// validate
if (w <= 0 || h <= 0 || zoneSize < 0) {
throw XBadClient();
}
if (mx < x || my < y || mx >= x + w || my >= y + h) {
throw XBadClient();
}
// save
m_info.m_x = x;
m_info.m_y = y;
m_info.m_w = w;
m_info.m_h = h;
m_info.m_zoneSize = zoneSize;
m_info.m_mx = mx;
m_info.m_my = my;
}
// tell server of change
if (notify) {
getServer()->onInfoChanged(getName(), m_info);
}
// acknowledge receipt
log((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
}
void
CClientProxy1_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", getName().c_str(), id, seqNum, data.size()));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update. this calls us back to reset our clipboard dirty flag
// so don't hold a lock during the call.
getServer()->onClipboardChanged(id, seqNum, data);
}
void
CClientProxy1_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", getName().c_str(), id, seqNum));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update. this calls us back to reset our clipboard dirty flag
// so don't hold a lock during the call.
getServer()->onGrabClipboard(getName(), id, seqNum);
}