Checkpoint. Code does not run. Still converting over to new

event loop model.  Streams, stream filters, and sockets are
converted.  Client proxies are almost converted.  CServer is
in progress.  Removed all HTTP code.  Haven't converted the
necessary win32 arch stuff.
This commit is contained in:
crs
2004-02-01 21:09:22 +00:00
parent 618aa7fedd
commit 848aee7a3a
64 changed files with 2581 additions and 2942 deletions

View File

@@ -17,46 +17,189 @@
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "XSynergy.h"
#include "IInputStream.h"
#include "IOutputStream.h"
#include "IStream.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
#include "CStopwatch.h"
#include "IEventQueue.h"
#include "TMethodEventJob.h"
#include <cstring>
//
// CClientProxy1_0
//
CClientProxy1_0::CClientProxy1_0(IServer* server, const CString& name,
IInputStream* input, IOutputStream* output) :
CClientProxy(server, name, input, output),
m_heartRate(kHeartRate),
m_heartDeath(kHeartRate * kHeartBeatsUntilDeath)
CClientProxy1_0::CClientProxy1_0(IServer* server,
const CString& name, IStream* stream) :
CClientProxy(server, name, stream),
m_heartbeatAlarm(kHeartRate * kHeartBeatsUntilDeath),
m_heartbeatTimer(NULL)
{
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = true;
}
// install event handlers
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleData, NULL));
EVENTQUEUE->adoptHandler(IStream::getOutputErrorEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleWriteError, NULL));
EVENTQUEUE->adoptHandler(IStream::getInputShutdownEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleDisconnect, NULL));
EVENTQUEUE->adoptHandler(IStream::getOutputShutdownEvent(),
stream->getEventTarget(),
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleWriteError, NULL));
EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
new TMethodEventJob<CClientProxy1_0>(this,
&CClientProxy1_0::handleFlatline, NULL));
// FIXME -- open() replacement must install initial heartbeat timer
}
CClientProxy1_0::~CClientProxy1_0()
{
// do nothing
removeHandlers();
}
void
CClientProxy1_0::disconnect()
{
CLock lock(getMutex());
removeHandlers();
// FIXME -- send disconnect event (server should be listening for this)
getStream()->flush();
getStream()->close();
}
void
CClientProxy1_0::removeHandlers()
{
// uninstall event handlers
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getOutputErrorEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getInputShutdownEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(IStream::getOutputShutdownEvent(),
getStream()->getEventTarget());
EVENTQUEUE->removeHandler(CEvent::kTimer, this);
// remove timer
removeHeartbeatTimer();
}
void
CClientProxy1_0::addHeartbeatTimer()
{
CLock lock(getMutex());
if (m_heartbeatAlarm > 0.0) {
m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
}
}
void
CClientProxy1_0::removeHeartbeatTimer()
{
CLock lock(getMutex());
if (m_heartbeatTimer != NULL) {
EVENTQUEUE->deleteTimer(m_heartbeatTimer);
m_heartbeatTimer = NULL;
}
}
void
CClientProxy1_0::handleData(const CEvent&, void*)
{
// handle messages until there are no more. first read message code.
UInt8 code[4];
UInt32 n = getStream()->read(code, 4);
while (n != 0) {
// verify we got an entire code
if (n != 4) {
LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
disconnect();
return;
}
// parse message
LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
if (!parseMessage(code)) {
LOG((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
disconnect();
return;
}
// next message
n = getStream()->read(code, 4);
}
// restart heartbeat timer
removeHeartbeatTimer();
addHeartbeatTimer();
}
bool
CClientProxy1_0::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDInfo, 4) == 0) {
return recvInfo(true);
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
return true;
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
return recvGrabClipboard();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
return recvClipboard();
}
return false;
}
void
CClientProxy1_0::handleDisconnect(const CEvent&, void*)
{
LOG((CLOG_NOTE "client \"%s\" disconnected", getName().c_str()));
disconnect();
}
void
CClientProxy1_0::handleWriteError(const CEvent&, void*)
{
LOG((CLOG_ERR "error writing to client \"%s\"", getName().c_str()));
disconnect();
}
void
CClientProxy1_0::handleFlatline(const CEvent&, void*)
{
// didn't get a heartbeat fast enough. assume client is dead.
LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
disconnect();
}
// FIXME -- replace this
void
CClientProxy1_0::open()
{
// send request
LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
getOutputStream()->flush();
CProtocolUtil::writef(getStream(), kMsgQInfo);
getStream()->flush();
// wait for and verify reply
UInt8 code[4];
for (;;) {
UInt32 n = getInputStream()->read(code, 4, -1.0);
UInt32 n = getStream()->read(code, 4);
if (n == 4) {
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard heartbeats
@@ -73,79 +216,15 @@ CClientProxy1_0::open()
recvInfo(false);
}
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, m_heartRate);
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) {
if (m_heartDeath >= 0.0 && heartTimer.getTime() > m_heartDeath) {
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
LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
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();
}
}
}
// FIXME -- replace this
void
CClientProxy1_0::close()
{
LOG((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
CProtocolUtil::writef(getStream(), kMsgCClose);
// force the close to be sent before we return
getOutputStream()->flush();
getStream()->flush();
}
void
@@ -153,7 +232,7 @@ 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,
CProtocolUtil::writef(getStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask);
}
@@ -161,7 +240,7 @@ bool
CClientProxy1_0::leave()
{
LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
CProtocolUtil::writef(getStream(), kMsgCLeave);
// we can never prevent the user from leaving
return true;
@@ -177,7 +256,7 @@ CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
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);
CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
}
}
@@ -185,7 +264,7 @@ 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);
CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
// this clipboard is now dirty
CLock lock(getMutex());
@@ -203,7 +282,7 @@ void
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
{
LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown1_0, key, mask);
CProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask);
}
void
@@ -211,78 +290,81 @@ CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
SInt32 count, KeyButton)
{
LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat1_0, key, mask, count);
CProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count);
}
void
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
{
LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp1_0, key, mask);
CProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, 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);
CProtocolUtil::writef(getStream(), 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);
CProtocolUtil::writef(getStream(), 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);
CProtocolUtil::writef(getStream(), 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);
CProtocolUtil::writef(getStream(), 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);
CProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0);
}
void
CClientProxy1_0::resetOptions()
{
LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCResetOptions);
CProtocolUtil::writef(getStream(), kMsgCResetOptions);
// reset heart rate and death
CLock lock(getMutex());
m_heartRate = kHeartRate;
m_heartDeath = kHeartRate * kHeartBeatsUntilDeath;
m_heartbeatAlarm = kHeartRate * kHeartBeatsUntilDeath;
removeHeartbeatTimer();
addHeartbeatTimer();
}
void
CClientProxy1_0::setOptions(const COptionsList& options)
{
LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDSetOptions, &options);
CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
// check options
CLock lock(getMutex());
for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
if (options[i] == kOptionHeartbeat) {
m_heartRate = 1.0e-3 * static_cast<double>(options[i + 1]);
if (m_heartRate <= 0.0) {
m_heartRate = -1.0;
double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
if (rate <= 0.0) {
rate = -1.0;
}
m_heartDeath = m_heartRate * kHeartBeatsUntilDeath;
m_heartbeatAlarm = rate * kHeartBeatsUntilDeath;
removeHeartbeatTimer();
addHeartbeatTimer();
}
}
}
@@ -318,7 +400,7 @@ CClientProxy1_0::getCursorCenter(SInt32& x, SInt32& y) const
y = m_info.m_my;
}
void
bool
CClientProxy1_0::recvInfo(bool notify)
{
{
@@ -326,16 +408,18 @@ CClientProxy1_0::recvInfo(bool notify)
// parse the message
SInt16 x, y, w, h, zoneSize, mx, my;
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &zoneSize, &mx, &my);
if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &zoneSize, &mx, &my)) {
return false;
}
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();
return false;
}
if (mx < x || my < y || mx >= x + w || my >= y + h) {
throw XBadClient();
return false;
}
// save
@@ -355,44 +439,52 @@ CClientProxy1_0::recvInfo(bool notify)
// acknowledge receipt
LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
CProtocolUtil::writef(getStream(), kMsgCInfoAck);
return true;
}
void
bool
CClientProxy1_0::recvClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CString data;
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
if (!CProtocolUtil::readf(getStream(),
kMsgDClipboard + 4, &id, &seqNum, &data)) {
return false;
}
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();
return false;
}
// 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);
return true;
}
void
bool
CClientProxy1_0::recvGrabClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
if (!CProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) {
return false;
}
LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
return false;
}
// 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);
return true;
}