refactored client code. it now uses IClient and IServer and
has a CServerProxy, making it's design similar to the server code.
This commit is contained in:
parent
df6748f669
commit
710e1bdd47
File diff suppressed because it is too large
Load Diff
104
client/CClient.h
104
client/CClient.h
|
@ -1,17 +1,18 @@
|
|||
#ifndef CCLIENT_H
|
||||
#define CCLIENT_H
|
||||
|
||||
#include "ClipboardTypes.h"
|
||||
#include "IClient.h"
|
||||
#include "IClipboard.h"
|
||||
#include "CNetworkAddress.h"
|
||||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
|
||||
class CNetworkAddress;
|
||||
class IInputStream;
|
||||
class IOutputStream;
|
||||
class CServerProxy;
|
||||
class CThread;
|
||||
class IDataSocket;
|
||||
class ISecondaryScreen;
|
||||
class IServer;
|
||||
|
||||
class CClient {
|
||||
class CClient : public IClient {
|
||||
public:
|
||||
CClient(const CString& clientName);
|
||||
~CClient();
|
||||
|
@ -24,74 +25,87 @@ public:
|
|||
// not call this while in run().
|
||||
void camp(bool on);
|
||||
|
||||
// open the client's screen
|
||||
bool open();
|
||||
|
||||
// start the client. does not return until quit() is called.
|
||||
// returns true if the client ever connected to the server
|
||||
// successfully. may also throw exceptions after successfully
|
||||
// connecting. a successful open() must preceed this call.
|
||||
bool run(const CNetworkAddress& serverAddress);
|
||||
// set the server's address that the client should connect to
|
||||
void setAddress(const CNetworkAddress& serverAddress);
|
||||
|
||||
// tell client to exit run() gracefully. this must only be called
|
||||
// after a successful open().
|
||||
void quit();
|
||||
|
||||
// handle events on client's screen
|
||||
// FIXME -- this should mimic methods on IServer
|
||||
// FIXME -- maybe create a IScreenReceiver with these methods and
|
||||
// have CPrimaryClient and CClient inherit from them. IServer
|
||||
// still needs similar methods with extra parameters, though. so
|
||||
// CServerProxy
|
||||
// CPrimaryClient
|
||||
// CClient
|
||||
// need IScreenReceiver. these classes effective receive notifications
|
||||
// from screens. note that there's another class of notifications that
|
||||
// only the server needs (key, mouyse, screensaver). so maybe we have
|
||||
// IPrimaryScreenReceiver and ISecondaryScreenReceiver (the latter is
|
||||
// derived with no extra methods from IScreenReceiver).
|
||||
void onClipboardChanged(ClipboardID);
|
||||
void onResolutionChanged();
|
||||
|
||||
// accessors
|
||||
|
||||
// returns true if the server rejected us
|
||||
bool wasRejected() const;
|
||||
|
||||
// IClient overrides
|
||||
virtual bool open();
|
||||
virtual void run();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
UInt32 seqNum, KeyModifierMask mask,
|
||||
bool screenSaver);
|
||||
virtual bool leave();
|
||||
virtual void setClipboard(ClipboardID, const CString&);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void setClipboardDirty(ClipboardID, bool dirty);
|
||||
virtual void keyDown(KeyID, KeyModifierMask);
|
||||
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void keyUp(KeyID, KeyModifierMask);
|
||||
virtual void mouseDown(ButtonID);
|
||||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void screenSaver(bool activate);
|
||||
virtual CString getName() const;
|
||||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCenter(SInt32& x, SInt32& y) const;
|
||||
virtual void getMousePos(SInt32& x, SInt32& y) const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
private:
|
||||
void runSession(void*);
|
||||
|
||||
// open/close the secondary screen
|
||||
void openSecondaryScreen();
|
||||
void closeSecondaryScreen();
|
||||
|
||||
// if compressing mouse motion then send the last motion now
|
||||
void flushCompressedMouse();
|
||||
// send the clipboard to the server
|
||||
void sendClipboard(ClipboardID);
|
||||
|
||||
// message handlers
|
||||
void onEnter();
|
||||
void onLeave();
|
||||
void onGrabClipboard();
|
||||
void onScreenSaver();
|
||||
void onQueryInfo();
|
||||
void onQueryInfoNoLock();
|
||||
void onInfoAcknowledgment();
|
||||
void onSetClipboard();
|
||||
void onKeyDown();
|
||||
void onKeyRepeat();
|
||||
void onKeyUp();
|
||||
void onMouseDown();
|
||||
void onMouseUp();
|
||||
void onMouseMove();
|
||||
void onMouseWheel();
|
||||
void onErrorIncompatible();
|
||||
void onErrorBusy();
|
||||
void onErrorUnknown();
|
||||
void onErrorBad();
|
||||
// handle server messaging
|
||||
void runSession(void*);
|
||||
void deleteSession(CThread*);
|
||||
void runServer();
|
||||
CServerProxy* handshakeServer(IDataSocket*);
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
CString m_name;
|
||||
IInputStream* m_input;
|
||||
IOutputStream* m_output;
|
||||
ISecondaryScreen* m_screen;
|
||||
const CNetworkAddress* m_serverAddress;
|
||||
IServer* m_server;
|
||||
CNetworkAddress m_serverAddress;
|
||||
bool m_camp;
|
||||
bool m_active;
|
||||
UInt32 m_seqNum;
|
||||
bool m_ignoreMove;
|
||||
bool m_rejected;
|
||||
bool m_ownClipboard[kClipboardEnd];
|
||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||
CString m_dataClipboard[kClipboardEnd];
|
||||
|
||||
bool m_compressMouse;
|
||||
SInt32 m_xMouse, m_yMouse;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,576 @@
|
|||
#include "CServerProxy.h"
|
||||
#include "CProtocolUtil.h"
|
||||
#include "IClient.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "IInputStream.h"
|
||||
#include "IOutputStream.h"
|
||||
#include "CLock.h"
|
||||
#include "CLog.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "XBase.h"
|
||||
#include <memory>
|
||||
|
||||
//
|
||||
// CServerProxy
|
||||
//
|
||||
|
||||
CServerProxy::CServerProxy(IClient* client,
|
||||
IInputStream* input, IOutputStream* output) :
|
||||
m_client(client),
|
||||
m_input(input),
|
||||
m_output(output)
|
||||
{
|
||||
assert(m_client != NULL);
|
||||
assert(m_input != NULL);
|
||||
assert(m_output != NULL);
|
||||
}
|
||||
|
||||
CServerProxy::~CServerProxy()
|
||||
{
|
||||
delete m_input;
|
||||
delete m_output;
|
||||
}
|
||||
|
||||
bool
|
||||
CServerProxy::run()
|
||||
{
|
||||
bool failedToConnect = false;
|
||||
try {
|
||||
// no compressed mouse motion yet
|
||||
m_compressMouse = false;
|
||||
|
||||
// not ignoring mouse motions
|
||||
m_ignoreMouse = false;
|
||||
|
||||
// handle messages from server
|
||||
CStopwatch heartbeat;
|
||||
for (;;) {
|
||||
// if no input is pending then flush compressed mouse motion
|
||||
if (getInputStream()->getSize() == 0) {
|
||||
flushCompressedMouse();
|
||||
}
|
||||
|
||||
// wait for a message
|
||||
log((CLOG_DEBUG2 "waiting for message"));
|
||||
UInt8 code[4];
|
||||
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
|
||||
|
||||
// check if server hungup
|
||||
if (n == 0) {
|
||||
log((CLOG_NOTE "server disconnected"));
|
||||
break;
|
||||
}
|
||||
|
||||
// check for time out
|
||||
if (n == (UInt32)-1 || heartbeat.getTime() > kHeartRate) {
|
||||
// send heartbeat
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCNoop);
|
||||
heartbeat.reset();
|
||||
if (n == (UInt32)-1) {
|
||||
// no message to process
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// verify we got an entire code
|
||||
if (n != 4) {
|
||||
// client sent an incomplete message
|
||||
log((CLOG_ERR "incomplete message from server"));
|
||||
break;
|
||||
}
|
||||
|
||||
// parse message
|
||||
log((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
||||
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
||||
mouseMove();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
||||
mouseWheel();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
||||
keyDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
||||
keyUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
||||
mouseDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
||||
mouseUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||
keyRepeat();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||
// accept and discard no-op
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||
enter();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
||||
leave();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||
grabClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||
screenSaver();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
queryInfo();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||
infoAcknowledgment();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||
setClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||
// server wants us to hangup
|
||||
log((CLOG_DEBUG1 "recv close"));
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
||||
SInt32 major, minor;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgEIncompatible + 4, &major, &minor);
|
||||
log((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
||||
log((CLOG_ERR "server already has a connected client with name \"%s\"", getName().c_str()));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
||||
log((CLOG_ERR "server refused client with name \"%s\"", getName().c_str()));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||
log((CLOG_ERR "server disconnected due to a protocol error"));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
// unknown message
|
||||
log((CLOG_ERR "unknown message from server"));
|
||||
failedToConnect = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "error: %s", e.what()));
|
||||
}
|
||||
catch (...) {
|
||||
throw;
|
||||
}
|
||||
|
||||
return !failedToConnect;
|
||||
}
|
||||
|
||||
IClient*
|
||||
CServerProxy::getClient() const
|
||||
{
|
||||
return m_client;
|
||||
}
|
||||
|
||||
CString
|
||||
CServerProxy::getName() const
|
||||
{
|
||||
return m_client->getName();
|
||||
}
|
||||
|
||||
IInputStream*
|
||||
CServerProxy::getInputStream() const
|
||||
{
|
||||
return m_input;
|
||||
}
|
||||
|
||||
IOutputStream*
|
||||
CServerProxy::getOutputStream() const
|
||||
{
|
||||
return m_output;
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onError()
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onInfoChanged(const CString&, const CClientInfo& info)
|
||||
{
|
||||
// ignore mouse motion until we receive acknowledgment of our info
|
||||
// change message.
|
||||
CLock lock(&m_mutex);
|
||||
m_ignoreMouse = true;
|
||||
|
||||
// send info update
|
||||
sendInfo(info);
|
||||
}
|
||||
|
||||
bool
|
||||
CServerProxy::onGrabClipboard(const CString&, ClipboardID id, UInt32 seqNum)
|
||||
{
|
||||
log((CLOG_DEBUG1 "sending clipboard %d changed", id));
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, seqNum);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onClipboardChanged(ClipboardID id,
|
||||
UInt32 seqNum, const CString& data)
|
||||
{
|
||||
log((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, seqNum, data.size()));
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, seqNum, &data);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onKeyDown(KeyID, KeyModifierMask)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onKeyUp(KeyID, KeyModifierMask)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onKeyRepeat(KeyID, KeyModifierMask, SInt32)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onMouseDown(ButtonID)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onMouseUp(ButtonID)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
bool
|
||||
CServerProxy::onMouseMovePrimary(SInt32, SInt32)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onMouseMoveSecondary(SInt32, SInt32)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onMouseWheel(SInt32)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::onScreenSaver(bool)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::flushCompressedMouse()
|
||||
{
|
||||
bool send = false;
|
||||
SInt32 x, y;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
if (m_compressMouse) {
|
||||
m_compressMouse = false;
|
||||
x = m_xMouse;
|
||||
y = m_yMouse;
|
||||
send = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (send) {
|
||||
getClient()->mouseMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::sendInfo(const CClientInfo& info)
|
||||
{
|
||||
// note -- m_mutex should be locked on entry
|
||||
log((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d zone=%d pos=%d,%d", info.m_x, info.m_y, info.m_w, info.m_h, info.m_zoneSize, info.m_mx, info.m_my));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDInfo,
|
||||
info.m_x, info.m_y,
|
||||
info.m_w, info.m_h,
|
||||
info.m_zoneSize,
|
||||
info.m_mx, info.m_my);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::enter()
|
||||
{
|
||||
// parse
|
||||
SInt16 x, y;
|
||||
UInt16 mask;
|
||||
UInt32 seqNum;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgCEnter + 4, &x, &y, &seqNum, &mask);
|
||||
log((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask));
|
||||
|
||||
// discard old compressed mouse motion, if any
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
m_compressMouse = false;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->enter(x, y, seqNum, static_cast<KeyModifierMask>(mask), false);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::leave()
|
||||
{
|
||||
// parse
|
||||
log((CLOG_DEBUG1 "recv leave"));
|
||||
|
||||
// send last mouse motion
|
||||
flushCompressedMouse();
|
||||
|
||||
// forward
|
||||
getClient()->leave();
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::setClipboard()
|
||||
{
|
||||
// parse
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CString data;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgDClipboard + 4, &id, &seqNum, &data);
|
||||
log((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
|
||||
|
||||
// validate
|
||||
if (id >= kClipboardEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->setClipboard(id, data);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::grabClipboard()
|
||||
{
|
||||
// parse
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
|
||||
log((CLOG_DEBUG "recv grab clipboard %d", id));
|
||||
|
||||
// validate
|
||||
if (id >= kClipboardEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// forward
|
||||
getClient()->grabClipboard(id);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyDown()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyDown + 4, &id, &mask);
|
||||
log((CLOG_DEBUG1 "recv key down id=%d, mask=0x%04x", id, mask));
|
||||
|
||||
// forward
|
||||
getClient()->keyDown(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyRepeat()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask, count;
|
||||
CProtocolUtil::readf(getInputStream(),
|
||||
kMsgDKeyRepeat + 4, &id, &mask, &count);
|
||||
log((CLOG_DEBUG1 "recv key repeat id=%d, mask=0x%04x, count=%d", id, mask, count));
|
||||
|
||||
// forward
|
||||
getClient()->keyRepeat(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask),
|
||||
count);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::keyUp()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
UInt16 id, mask;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDKeyUp + 4, &id, &mask);
|
||||
log((CLOG_DEBUG1 "recv key up id=%d, mask=0x%04x", id, mask));
|
||||
|
||||
// forward
|
||||
getClient()->keyUp(static_cast<KeyID>(id),
|
||||
static_cast<KeyModifierMask>(mask));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseDown()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt8 id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseDown + 4, &id);
|
||||
log((CLOG_DEBUG1 "recv mouse down id=%d", id));
|
||||
|
||||
// forward
|
||||
getClient()->mouseDown(static_cast<ButtonID>(id));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseUp()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt8 id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseUp + 4, &id);
|
||||
log((CLOG_DEBUG1 "recv mouse up id=%d", id));
|
||||
|
||||
// forward
|
||||
getClient()->mouseUp(static_cast<ButtonID>(id));
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseMove()
|
||||
{
|
||||
// parse
|
||||
bool ignore;
|
||||
SInt16 x, y;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseMove + 4, &x, &y);
|
||||
|
||||
{
|
||||
// note if we should ignore the move
|
||||
CLock lock(&m_mutex);
|
||||
ignore = m_ignoreMouse;
|
||||
|
||||
// compress mouse motion events if more input follows
|
||||
if (!ignore && !m_compressMouse && getInputStream()->getSize() > 0) {
|
||||
m_compressMouse = true;
|
||||
}
|
||||
|
||||
// if compressing then ignore the motion but record it
|
||||
if (m_compressMouse) {
|
||||
ignore = true;
|
||||
m_xMouse = x;
|
||||
m_yMouse = y;
|
||||
}
|
||||
}
|
||||
log((CLOG_DEBUG2 "recv mouse move %d,%d", x, y));
|
||||
|
||||
// forward
|
||||
if (!ignore) {
|
||||
getClient()->mouseMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::mouseWheel()
|
||||
{
|
||||
// get mouse up to date
|
||||
flushCompressedMouse();
|
||||
|
||||
// parse
|
||||
SInt16 delta;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDMouseWheel + 4, &delta);
|
||||
log((CLOG_DEBUG2 "recv mouse wheel %+d", delta));
|
||||
|
||||
// forward
|
||||
getClient()->mouseWheel(delta);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::screenSaver()
|
||||
{
|
||||
// parse
|
||||
SInt8 on;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCScreenSaver + 4, &on);
|
||||
log((CLOG_DEBUG1 "recv screen saver on=%d", on));
|
||||
|
||||
// forward
|
||||
getClient()->screenSaver(on != 0);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::queryInfo()
|
||||
{
|
||||
// get current info
|
||||
CClientInfo info;
|
||||
getClient()->getShape(info.m_x, info.m_y, info.m_w, info.m_h);
|
||||
getClient()->getMousePos(info.m_mx, info.m_my);
|
||||
info.m_zoneSize = getClient()->getJumpZoneSize();
|
||||
|
||||
// send it
|
||||
CLock lock(&m_mutex);
|
||||
sendInfo(info);
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::infoAcknowledgment()
|
||||
{
|
||||
// parse
|
||||
log((CLOG_DEBUG1 "recv info acknowledgment"));
|
||||
|
||||
// now allow mouse motion
|
||||
CLock lock(&m_mutex);
|
||||
m_ignoreMouse = false;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef CSERVERPROXY_H
|
||||
#define CSERVERPROXY_H
|
||||
|
||||
#include "IServer.h"
|
||||
#include "CMutex.h"
|
||||
|
||||
class IClient;
|
||||
class IInputStream;
|
||||
class IOutputStream;
|
||||
|
||||
class CServerProxy : public IServer {
|
||||
public:
|
||||
CServerProxy(IClient* client,
|
||||
IInputStream* adoptedInput,
|
||||
IOutputStream* adoptedOutput);
|
||||
~CServerProxy();
|
||||
|
||||
// manipulators
|
||||
|
||||
// handle messages. returns true iff server didn't reject our
|
||||
// connection.
|
||||
bool run();
|
||||
|
||||
// accessors
|
||||
|
||||
// get the client
|
||||
IClient* getClient() const;
|
||||
|
||||
// get the client name
|
||||
CString getName() const;
|
||||
|
||||
// get the input and output streams for the server
|
||||
IInputStream* getInputStream() const;
|
||||
IOutputStream* getOutputStream() const;
|
||||
|
||||
// IServer overrides
|
||||
virtual void onError();
|
||||
virtual void onInfoChanged(const CString& clientName,
|
||||
const CClientInfo&);
|
||||
virtual bool onGrabClipboard(const CString& clientName,
|
||||
ClipboardID, UInt32 seqNum);
|
||||
virtual void onClipboardChanged(ClipboardID,
|
||||
UInt32 seqNum, const CString& data);
|
||||
virtual void onKeyDown(KeyID, KeyModifierMask);
|
||||
virtual void onKeyUp(KeyID, KeyModifierMask);
|
||||
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
virtual void onMouseDown(ButtonID);
|
||||
virtual void onMouseUp(ButtonID);
|
||||
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
||||
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
||||
virtual void onMouseWheel(SInt32 delta);
|
||||
virtual void onScreenSaver(bool activated);
|
||||
|
||||
private:
|
||||
// if compressing mouse motion then send the last motion now
|
||||
void flushCompressedMouse();
|
||||
|
||||
void sendInfo(const CClientInfo&);
|
||||
|
||||
// message handlers
|
||||
void enter();
|
||||
void leave();
|
||||
void setClipboard();
|
||||
void grabClipboard();
|
||||
void keyDown();
|
||||
void keyRepeat();
|
||||
void keyUp();
|
||||
void mouseDown();
|
||||
void mouseUp();
|
||||
void mouseMove();
|
||||
void mouseWheel();
|
||||
void screenSaver();
|
||||
void queryInfo();
|
||||
void infoAcknowledgment();
|
||||
|
||||
private:
|
||||
CMutex m_mutex;
|
||||
|
||||
IClient* m_client;
|
||||
IInputStream* m_input;
|
||||
IOutputStream* m_output;
|
||||
|
||||
bool m_compressMouse;
|
||||
SInt32 m_xMouse, m_yMouse;
|
||||
|
||||
bool m_ignoreMouse;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -4,11 +4,14 @@ DEPTH = ..
|
|||
|
||||
bin_PROGRAMS = synergy
|
||||
synergy_SOURCES = \
|
||||
CXWindowsSecondaryScreen.cpp \
|
||||
CClient.cpp \
|
||||
CServerProxy.cpp \
|
||||
CXWindowsSecondaryScreen.cpp \
|
||||
client.cpp \
|
||||
CClient.h \
|
||||
CServerProxy.h \
|
||||
CXWindowsSecondaryScreen.h \
|
||||
ISecondaryScreen.h \
|
||||
$(NULL)
|
||||
synergy_LDADD = \
|
||||
$(DEPTH)/platform/libplatform.a \
|
||||
|
|
|
@ -81,6 +81,7 @@ realMain(CMutex* mutex)
|
|||
// create client
|
||||
s_client = new CClient(s_name);
|
||||
s_client->camp(s_camp);
|
||||
s_client->setAddress(s_serverAddress);
|
||||
if (!s_client->open()) {
|
||||
delete s_client;
|
||||
s_client = NULL;
|
||||
|
@ -92,13 +93,17 @@ realMain(CMutex* mutex)
|
|||
mutex->unlock();
|
||||
}
|
||||
locked = false;
|
||||
bool success = s_client->run(s_serverAddress);
|
||||
s_client->run();
|
||||
locked = true;
|
||||
if (mutex != NULL) {
|
||||
mutex->lock();
|
||||
}
|
||||
|
||||
// get client status
|
||||
bool success = !s_client->wasRejected();
|
||||
|
||||
// clean up
|
||||
s_client->close();
|
||||
delete s_client;
|
||||
s_client = NULL;
|
||||
CLog::setLock(NULL);
|
||||
|
@ -111,6 +116,7 @@ realMain(CMutex* mutex)
|
|||
if (!locked && mutex != NULL) {
|
||||
mutex->lock();
|
||||
}
|
||||
s_client->close();
|
||||
delete s_client;
|
||||
s_client = NULL;
|
||||
CLog::setLock(NULL);
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
IOutputStream* getOutputStream() const;
|
||||
|
||||
// IClient overrides
|
||||
virtual void open() = 0;
|
||||
virtual bool open() = 0;
|
||||
virtual void run() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
|
@ -49,6 +49,7 @@ public:
|
|||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const = 0;
|
||||
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
|
||||
virtual void getMousePos(SInt32& x, SInt32& y) const = 0;
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
private:
|
||||
|
|
|
@ -29,7 +29,7 @@ CClientProxy1_0::~CClientProxy1_0()
|
|||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
CClientProxy1_0::open()
|
||||
{
|
||||
// send request
|
||||
|
@ -55,6 +55,8 @@ CClientProxy1_0::open()
|
|||
|
||||
// handle reply
|
||||
recvInfo(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -258,6 +260,12 @@ CClientProxy1_0::getCenter(SInt32& x, SInt32& y) const
|
|||
y = m_info.m_my;
|
||||
}
|
||||
|
||||
void
|
||||
CClientProxy1_0::getMousePos(SInt32&, SInt32&) const
|
||||
{
|
||||
assert(0 && "shouldn't be called");
|
||||
}
|
||||
|
||||
SInt32
|
||||
CClientProxy1_0::getJumpZoneSize() const
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
~CClientProxy1_0();
|
||||
|
||||
// IClient overrides
|
||||
virtual void open();
|
||||
virtual bool open();
|
||||
virtual void run();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
|
@ -34,6 +34,7 @@ public:
|
|||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCenter(SInt32& x, SInt32& y) const;
|
||||
virtual void getMousePos(SInt32& x, SInt32& y) const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -149,7 +149,7 @@ CPrimaryClient::onScreenSaver(bool activated)
|
|||
m_server->onScreenSaver(activated);
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
CPrimaryClient::open()
|
||||
{
|
||||
// all clipboards are clean and owned by us
|
||||
|
@ -160,6 +160,8 @@ CPrimaryClient::open()
|
|||
|
||||
// now open the screen
|
||||
m_screen->open();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -296,6 +298,12 @@ CPrimaryClient::getCenter(SInt32& x, SInt32& y) const
|
|||
y = m_info.m_my;
|
||||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::getMousePos(SInt32&, SInt32&) const
|
||||
{
|
||||
assert(0 && "shouldn't be called");
|
||||
}
|
||||
|
||||
SInt32
|
||||
CPrimaryClient::getJumpZoneSize() const
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
virtual void onScreenSaver(bool activated);
|
||||
|
||||
// IClient overrides
|
||||
virtual void open();
|
||||
virtual bool open();
|
||||
virtual void run();
|
||||
virtual void close();
|
||||
virtual void enter(SInt32 xAbs, SInt32 yAbs,
|
||||
|
@ -74,6 +74,7 @@ public:
|
|||
virtual void getShape(SInt32& x, SInt32& y,
|
||||
SInt32& width, SInt32& height) const;
|
||||
virtual void getCenter(SInt32& x, SInt32& y) const;
|
||||
virtual void getMousePos(SInt32& x, SInt32& y) const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -21,14 +21,6 @@
|
|||
#include "CLog.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "TMethodJob.h"
|
||||
#include <memory>
|
||||
|
||||
// hack to work around operator=() bug in STL in g++ prior to v3
|
||||
#if defined(__GNUC__) && (__GNUC__ < 3)
|
||||
#define assign(_dst, _src, _type) _dst.reset(_src)
|
||||
#else
|
||||
#define assign(_dst, _src, _type) _dst = std::auto_ptr<_type >(_src)
|
||||
#endif
|
||||
|
||||
//
|
||||
// CServer
|
||||
|
@ -1106,11 +1098,11 @@ CServer::acceptClients(void*)
|
|||
{
|
||||
log((CLOG_DEBUG1 "starting to wait for clients"));
|
||||
|
||||
std::auto_ptr<IListenSocket> listen;
|
||||
IListenSocket* listen = NULL;
|
||||
try {
|
||||
// create socket listener
|
||||
// listen = std::auto_ptr<IListenSocket>(m_socketFactory->createListen());
|
||||
assign(listen, new CTCPListenSocket, IListenSocket); // FIXME
|
||||
listen = new CTCPListenSocket; // FIXME -- use factory
|
||||
|
||||
// bind to the desired port. keep retrying if we can't bind
|
||||
// the address immediately.
|
||||
|
@ -1147,11 +1139,19 @@ CServer::acceptClients(void*)
|
|||
startThread(new TMethodJob<CServer>(
|
||||
this, &CServer::runClient, socket));
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete listen;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "cannot listen for clients: %s", e.what()));
|
||||
delete listen;
|
||||
quit();
|
||||
}
|
||||
catch (...) {
|
||||
delete listen;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1159,12 +1159,20 @@ CServer::runClient(void* vsocket)
|
|||
{
|
||||
// get the socket pointer from the argument
|
||||
assert(vsocket != NULL);
|
||||
std::auto_ptr<IDataSocket> socket(reinterpret_cast<IDataSocket*>(vsocket));
|
||||
IDataSocket* socket = reinterpret_cast<IDataSocket*>(vsocket);
|
||||
|
||||
// create proxy
|
||||
CClientProxy* proxy = handshakeClient(socket.get());
|
||||
if (proxy == NULL) {
|
||||
return;
|
||||
CClientProxy* proxy = NULL;
|
||||
try {
|
||||
proxy = handshakeClient(socket);
|
||||
if (proxy == NULL) {
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
|
||||
// add the connection
|
||||
|
@ -1181,6 +1189,7 @@ CServer::runClient(void* vsocket)
|
|||
log((CLOG_WARN "a client with name \"%s\" is already connected", e.getName().c_str()));
|
||||
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEBusy);
|
||||
delete proxy;
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
catch (XUnknownClient& e) {
|
||||
|
@ -1188,10 +1197,12 @@ CServer::runClient(void* vsocket)
|
|||
log((CLOG_WARN "a client with name \"%s\" is not in the map", e.getName().c_str()));
|
||||
CProtocolUtil::writef(proxy->getOutputStream(), kMsgEUnknown);
|
||||
delete proxy;
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
delete proxy;
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -1222,11 +1233,13 @@ CServer::runClient(void* vsocket)
|
|||
catch (...) {
|
||||
// run() was probably cancelled
|
||||
removeConnection(proxy->getName());
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
|
||||
// remove the connection
|
||||
// clean up
|
||||
removeConnection(proxy->getName());
|
||||
delete socket;
|
||||
}
|
||||
|
||||
CClientProxy*
|
||||
|
@ -1244,13 +1257,14 @@ CServer::handshakeClient(IDataSocket* socket)
|
|||
/* FIXME -- implement ISecurityFactory
|
||||
input = m_securityFactory->createInputFilter(input, own);
|
||||
output = m_securityFactory->createOutputFilter(output, own);
|
||||
own = true;
|
||||
own = true;
|
||||
*/
|
||||
}
|
||||
|
||||
// attach the packetizing filters
|
||||
input = new CInputPacketStream(input, own);
|
||||
output = new COutputPacketStream(output, own);
|
||||
own = true;
|
||||
|
||||
CClientProxy* proxy = NULL;
|
||||
CString name("<unknown>");
|
||||
|
@ -1344,7 +1358,7 @@ CServer::handshakeClient(IDataSocket* socket)
|
|||
if (proxy != NULL) {
|
||||
delete proxy;
|
||||
}
|
||||
else {
|
||||
else if (own) {
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
|
@ -1355,7 +1369,7 @@ CServer::handshakeClient(IDataSocket* socket)
|
|||
if (proxy != NULL) {
|
||||
delete proxy;
|
||||
}
|
||||
else {
|
||||
else if (own) {
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
|
@ -1368,11 +1382,11 @@ CServer::acceptHTTPClients(void*)
|
|||
{
|
||||
log((CLOG_DEBUG1 "starting to wait for HTTP clients"));
|
||||
|
||||
std::auto_ptr<IListenSocket> listen;
|
||||
IListenSocket* listen = NULL;
|
||||
try {
|
||||
// create socket listener
|
||||
// listen = std::auto_ptr<IListenSocket>(m_socketFactory->createListen());
|
||||
assign(listen, new CTCPListenSocket, IListenSocket); // FIXME
|
||||
listen = new CTCPListenSocket; // FIXME -- use factory
|
||||
|
||||
// bind to the desired port. keep retrying if we can't bind
|
||||
// the address immediately.
|
||||
|
@ -1419,12 +1433,20 @@ CServer::acceptHTTPClients(void*)
|
|||
startThread(new TMethodJob<CServer>(
|
||||
this, &CServer::processHTTPRequest, socket));
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete listen;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
log((CLOG_ERR "cannot listen for HTTP clients: %s", e.what()));
|
||||
delete listen;
|
||||
// FIXME -- quit?
|
||||
quit();
|
||||
}
|
||||
catch (...) {
|
||||
delete listen;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -11,8 +11,8 @@ class IClient : public IInterface {
|
|||
public:
|
||||
// manipulators
|
||||
|
||||
// open client
|
||||
virtual void open() = 0;
|
||||
// open client. return true iff successful.
|
||||
virtual bool open() = 0;
|
||||
|
||||
// service client
|
||||
virtual void run() = 0;
|
||||
|
@ -68,6 +68,9 @@ public:
|
|||
// get the center pixel
|
||||
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
|
||||
|
||||
// get the mouse position
|
||||
virtual void getMousePos(SInt32& x, SInt32& y) const = 0;
|
||||
|
||||
// get the size of jump zone
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,6 @@ libsynergy_a_SOURCES = \
|
|||
IClient.h \
|
||||
IClipboard.h \
|
||||
IScreenSaver.h \
|
||||
ISecondaryScreen.h \
|
||||
IServer.h \
|
||||
ISocketFactory.h \
|
||||
KeyTypes.h \
|
||||
|
|
Loading…
Reference in New Issue