00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CClientProxy1_0.h"
00016 #include "CProtocolUtil.h"
00017 #include "XSynergy.h"
00018 #include "IStream.h"
00019 #include "CLog.h"
00020 #include "IEventQueue.h"
00021 #include "TMethodEventJob.h"
00022 #include <cstring>
00023
00024
00025
00026
00027
00028 CClientProxy1_0::CClientProxy1_0(const CString& name, IStream* stream) :
00029 CClientProxy(name, stream),
00030 m_heartbeatTimer(NULL),
00031 m_parser(&CClientProxy1_0::parseHandshakeMessage)
00032 {
00033
00034 EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
00035 stream->getEventTarget(),
00036 new TMethodEventJob<CClientProxy1_0>(this,
00037 &CClientProxy1_0::handleData, NULL));
00038 EVENTQUEUE->adoptHandler(IStream::getOutputErrorEvent(),
00039 stream->getEventTarget(),
00040 new TMethodEventJob<CClientProxy1_0>(this,
00041 &CClientProxy1_0::handleWriteError, NULL));
00042 EVENTQUEUE->adoptHandler(IStream::getInputShutdownEvent(),
00043 stream->getEventTarget(),
00044 new TMethodEventJob<CClientProxy1_0>(this,
00045 &CClientProxy1_0::handleDisconnect, NULL));
00046 EVENTQUEUE->adoptHandler(IStream::getOutputShutdownEvent(),
00047 stream->getEventTarget(),
00048 new TMethodEventJob<CClientProxy1_0>(this,
00049 &CClientProxy1_0::handleWriteError, NULL));
00050 EVENTQUEUE->adoptHandler(CEvent::kTimer, this,
00051 new TMethodEventJob<CClientProxy1_0>(this,
00052 &CClientProxy1_0::handleFlatline, NULL));
00053
00054 setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath);
00055
00056 LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
00057 CProtocolUtil::writef(getStream(), kMsgQInfo);
00058 }
00059
00060 CClientProxy1_0::~CClientProxy1_0()
00061 {
00062 removeHandlers();
00063 }
00064
00065 void
00066 CClientProxy1_0::disconnect()
00067 {
00068 removeHandlers();
00069 getStream()->close();
00070 EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget()));
00071 }
00072
00073 void
00074 CClientProxy1_0::removeHandlers()
00075 {
00076
00077 EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
00078 getStream()->getEventTarget());
00079 EVENTQUEUE->removeHandler(IStream::getOutputErrorEvent(),
00080 getStream()->getEventTarget());
00081 EVENTQUEUE->removeHandler(IStream::getInputShutdownEvent(),
00082 getStream()->getEventTarget());
00083 EVENTQUEUE->removeHandler(IStream::getOutputShutdownEvent(),
00084 getStream()->getEventTarget());
00085 EVENTQUEUE->removeHandler(CEvent::kTimer, this);
00086
00087
00088 removeHeartbeatTimer();
00089 }
00090
00091 void
00092 CClientProxy1_0::addHeartbeatTimer()
00093 {
00094 if (m_heartbeatAlarm > 0.0) {
00095 m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this);
00096 }
00097 }
00098
00099 void
00100 CClientProxy1_0::removeHeartbeatTimer()
00101 {
00102 if (m_heartbeatTimer != NULL) {
00103 EVENTQUEUE->deleteTimer(m_heartbeatTimer);
00104 m_heartbeatTimer = NULL;
00105 }
00106 }
00107
00108 void
00109 CClientProxy1_0::resetHeartbeatTimer()
00110 {
00111
00112 removeHeartbeatTimer();
00113 addHeartbeatTimer();
00114 }
00115
00116 void
00117 CClientProxy1_0::resetHeartbeatRate()
00118 {
00119 setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath);
00120 }
00121
00122 void
00123 CClientProxy1_0::setHeartbeatRate(double, double alarm)
00124 {
00125 m_heartbeatAlarm = alarm;
00126 }
00127
00128 void
00129 CClientProxy1_0::handleData(const CEvent&, void*)
00130 {
00131
00132 UInt8 code[4];
00133 UInt32 n = getStream()->read(code, 4);
00134 while (n != 0) {
00135
00136 if (n != 4) {
00137 LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
00138 disconnect();
00139 return;
00140 }
00141
00142
00143 LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
00144 if (!(this->*m_parser)(code)) {
00145 LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
00146 disconnect();
00147 return;
00148 }
00149
00150
00151 n = getStream()->read(code, 4);
00152 }
00153
00154
00155 resetHeartbeatTimer();
00156 }
00157
00158 bool
00159 CClientProxy1_0::parseHandshakeMessage(const UInt8* code)
00160 {
00161 if (memcmp(code, kMsgCNoop, 4) == 0) {
00162
00163 LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
00164 return true;
00165 }
00166 else if (memcmp(code, kMsgDInfo, 4) == 0) {
00167
00168 m_parser = &CClientProxy1_0::parseMessage;
00169 if (recvInfo()) {
00170 EVENTQUEUE->addEvent(CEvent(getReadyEvent(), getEventTarget()));
00171 addHeartbeatTimer();
00172 return true;
00173 }
00174 }
00175 return false;
00176 }
00177
00178 bool
00179 CClientProxy1_0::parseMessage(const UInt8* code)
00180 {
00181 if (memcmp(code, kMsgDInfo, 4) == 0) {
00182 if (recvInfo()) {
00183 EVENTQUEUE->addEvent(
00184 CEvent(getShapeChangedEvent(), getEventTarget()));
00185 return true;
00186 }
00187 return false;
00188 }
00189 else if (memcmp(code, kMsgCNoop, 4) == 0) {
00190
00191 LOG((CLOG_DEBUG2 "no-op from", getName().c_str()));
00192 return true;
00193 }
00194 else if (memcmp(code, kMsgCClipboard, 4) == 0) {
00195 return recvGrabClipboard();
00196 }
00197 else if (memcmp(code, kMsgDClipboard, 4) == 0) {
00198 return recvClipboard();
00199 }
00200 return false;
00201 }
00202
00203 void
00204 CClientProxy1_0::handleDisconnect(const CEvent&, void*)
00205 {
00206 LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str()));
00207 disconnect();
00208 }
00209
00210 void
00211 CClientProxy1_0::handleWriteError(const CEvent&, void*)
00212 {
00213 LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str()));
00214 disconnect();
00215 }
00216
00217 void
00218 CClientProxy1_0::handleFlatline(const CEvent&, void*)
00219 {
00220
00221 LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
00222 disconnect();
00223 }
00224
00225 bool
00226 CClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const
00227 {
00228 CClipboard::copy(clipboard, &m_clipboard[id].m_clipboard);
00229 return true;
00230 }
00231
00232 void
00233 CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
00234 {
00235 x = m_info.m_x;
00236 y = m_info.m_y;
00237 w = m_info.m_w;
00238 h = m_info.m_h;
00239 }
00240
00241 void
00242 CClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const
00243 {
00244
00245 x = m_info.m_mx;
00246 y = m_info.m_my;
00247 }
00248
00249 void
00250 CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
00251 UInt32 seqNum, KeyModifierMask mask, bool)
00252 {
00253 LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
00254 CProtocolUtil::writef(getStream(), kMsgCEnter,
00255 xAbs, yAbs, seqNum, mask);
00256 }
00257
00258 bool
00259 CClientProxy1_0::leave()
00260 {
00261 LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
00262 CProtocolUtil::writef(getStream(), kMsgCLeave);
00263
00264
00265 return true;
00266 }
00267
00268 void
00269 CClientProxy1_0::setClipboard(ClipboardID id, const IClipboard* clipboard)
00270 {
00271
00272 if (m_clipboard[id].m_dirty) {
00273
00274 m_clipboard[id].m_dirty = false;
00275 CClipboard::copy(&m_clipboard[id].m_clipboard, clipboard);
00276
00277 CString data = m_clipboard[id].m_clipboard.marshall();
00278 LOG((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
00279 CProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &data);
00280 }
00281 }
00282
00283 void
00284 CClientProxy1_0::grabClipboard(ClipboardID id)
00285 {
00286 LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
00287 CProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0);
00288
00289
00290 m_clipboard[id].m_dirty = true;
00291 }
00292
00293 void
00294 CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
00295 {
00296 m_clipboard[id].m_dirty = dirty;
00297 }
00298
00299 void
00300 CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton)
00301 {
00302 LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
00303 CProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask);
00304 }
00305
00306 void
00307 CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask,
00308 SInt32 count, KeyButton)
00309 {
00310 LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
00311 CProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count);
00312 }
00313
00314 void
00315 CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton)
00316 {
00317 LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
00318 CProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, key, mask);
00319 }
00320
00321 void
00322 CClientProxy1_0::mouseDown(ButtonID button)
00323 {
00324 LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
00325 CProtocolUtil::writef(getStream(), kMsgDMouseDown, button);
00326 }
00327
00328 void
00329 CClientProxy1_0::mouseUp(ButtonID button)
00330 {
00331 LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
00332 CProtocolUtil::writef(getStream(), kMsgDMouseUp, button);
00333 }
00334
00335 void
00336 CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
00337 {
00338 LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs));
00339 CProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs);
00340 }
00341
00342 void
00343 CClientProxy1_0::mouseRelativeMove(SInt32, SInt32)
00344 {
00345
00346 }
00347
00348 void
00349 CClientProxy1_0::mouseWheel(SInt32, SInt32 yDelta)
00350 {
00351
00352 LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), yDelta));
00353 CProtocolUtil::writef(getStream(), kMsgDMouseWheel1_0, yDelta);
00354 }
00355
00356 void
00357 CClientProxy1_0::screensaver(bool on)
00358 {
00359 LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
00360 CProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0);
00361 }
00362
00363 void
00364 CClientProxy1_0::resetOptions()
00365 {
00366 LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str()));
00367 CProtocolUtil::writef(getStream(), kMsgCResetOptions);
00368
00369
00370 resetHeartbeatRate();
00371 removeHeartbeatTimer();
00372 addHeartbeatTimer();
00373 }
00374
00375 void
00376 CClientProxy1_0::setOptions(const COptionsList& options)
00377 {
00378 LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size()));
00379 CProtocolUtil::writef(getStream(), kMsgDSetOptions, &options);
00380
00381
00382 for (UInt32 i = 0, n = options.size(); i < n; i += 2) {
00383 if (options[i] == kOptionHeartbeat) {
00384 double rate = 1.0e-3 * static_cast<double>(options[i + 1]);
00385 if (rate <= 0.0) {
00386 rate = -1.0;
00387 }
00388 setHeartbeatRate(rate, rate * kHeartBeatsUntilDeath);
00389 removeHeartbeatTimer();
00390 addHeartbeatTimer();
00391 }
00392 }
00393 }
00394
00395 bool
00396 CClientProxy1_0::recvInfo()
00397 {
00398
00399 SInt16 x, y, w, h, dummy1, mx, my;
00400 if (!CProtocolUtil::readf(getStream(), kMsgDInfo + 4,
00401 &x, &y, &w, &h, &dummy1, &mx, &my)) {
00402 return false;
00403 }
00404 LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d at %d,%d", getName().c_str(), x, y, w, h, mx, my));
00405
00406
00407 if (w <= 0 || h <= 0) {
00408 return false;
00409 }
00410 if (mx < x || mx >= x + w || my < y || my >= y + h) {
00411 mx = x + w / 2;
00412 my = y + h / 2;
00413 }
00414
00415
00416 m_info.m_x = x;
00417 m_info.m_y = y;
00418 m_info.m_w = w;
00419 m_info.m_h = h;
00420 m_info.m_mx = mx;
00421 m_info.m_my = my;
00422
00423
00424 LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
00425 CProtocolUtil::writef(getStream(), kMsgCInfoAck);
00426 return true;
00427 }
00428
00429 bool
00430 CClientProxy1_0::recvClipboard()
00431 {
00432
00433 ClipboardID id;
00434 UInt32 seqNum;
00435 CString data;
00436 if (!CProtocolUtil::readf(getStream(),
00437 kMsgDClipboard + 4, &id, &seqNum, &data)) {
00438 return false;
00439 }
00440 LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seqNum, data.size()));
00441
00442
00443 if (id >= kClipboardEnd) {
00444 return false;
00445 }
00446
00447
00448 m_clipboard[id].m_clipboard.unmarshall(data, 0);
00449 m_clipboard[id].m_sequenceNumber = seqNum;
00450
00451
00452 CClipboardInfo* info = new CClipboardInfo;
00453 info->m_id = id;
00454 info->m_sequenceNumber = seqNum;
00455 EVENTQUEUE->addEvent(CEvent(getClipboardChangedEvent(),
00456 getEventTarget(), info));
00457
00458 return true;
00459 }
00460
00461 bool
00462 CClientProxy1_0::recvGrabClipboard()
00463 {
00464
00465 ClipboardID id;
00466 UInt32 seqNum;
00467 if (!CProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) {
00468 return false;
00469 }
00470 LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
00471
00472
00473 if (id >= kClipboardEnd) {
00474 return false;
00475 }
00476
00477
00478 CClipboardInfo* info = new CClipboardInfo;
00479 info->m_id = id;
00480 info->m_sequenceNumber = seqNum;
00481 EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(),
00482 getEventTarget(), info));
00483
00484 return true;
00485 }
00486
00487
00488
00489
00490
00491
00492 CClientProxy1_0::CClientClipboard::CClientClipboard() :
00493 m_clipboard(),
00494 m_sequenceNumber(0),
00495 m_dirty(true)
00496 {
00497
00498 }