00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "CClient.h"
00020 #include "CServerProxy.h"
00021 #include "CScreen.h"
00022 #include "CClipboard.h"
00023 #include "CPacketStreamFilter.h"
00024 #include "CProtocolUtil.h"
00025 #include "ProtocolTypes.h"
00026 #include "XSynergy.h"
00027 #include "IDataSocket.h"
00028 #include "ISocketFactory.h"
00029 #include "IStreamFilterFactory.h"
00030 #include "CLog.h"
00031 #include "IEventQueue.h"
00032 #include "TMethodEventJob.h"
00033 #include <cstring>
00034 #include <cstdlib>
00035 #include "CArch.h"
00036 #include "IPlatformScreen.h"
00037 #include "CCryptoStream.h"
00038
00039
00040
00041
00042
00043 CEvent::Type CClient::s_connectedEvent = CEvent::kUnknown;
00044 CEvent::Type CClient::s_connectionFailedEvent = CEvent::kUnknown;
00045 CEvent::Type CClient::s_disconnectedEvent = CEvent::kUnknown;
00046
00047 CClient::CClient(IEventQueue* eventQueue,
00048 const CString& name, const CNetworkAddress& address,
00049 ISocketFactory* socketFactory,
00050 IStreamFilterFactory* streamFilterFactory,
00051 CScreen* screen,
00052 const CCryptoOptions& crypto) :
00053 m_mock(false),
00054 m_name(name),
00055 m_serverAddress(address),
00056 m_socketFactory(socketFactory),
00057 m_streamFilterFactory(streamFilterFactory),
00058 m_screen(screen),
00059 m_stream(NULL),
00060 m_timer(NULL),
00061 m_server(NULL),
00062 m_ready(false),
00063 m_active(false),
00064 m_suspended(false),
00065 m_connectOnResume(false),
00066 m_eventQueue(eventQueue),
00067 m_cryptoStream(NULL),
00068 m_crypto(crypto)
00069 {
00070 assert(m_socketFactory != NULL);
00071 assert(m_screen != NULL);
00072
00073
00074 m_eventQueue->adoptHandler(IScreen::getSuspendEvent(),
00075 getEventTarget(),
00076 new TMethodEventJob<CClient>(this,
00077 &CClient::handleSuspend));
00078 m_eventQueue->adoptHandler(IScreen::getResumeEvent(),
00079 getEventTarget(),
00080 new TMethodEventJob<CClient>(this,
00081 &CClient::handleResume));
00082 m_eventQueue->adoptHandler(IPlatformScreen::getGameDeviceTimingRespEvent(),
00083 getEventTarget(),
00084 new TMethodEventJob<CClient>(this,
00085 &CClient::handleGameDeviceTimingResp));
00086 m_eventQueue->adoptHandler(IPlatformScreen::getGameDeviceFeedbackEvent(),
00087 getEventTarget(),
00088 new TMethodEventJob<CClient>(this,
00089 &CClient::handleGameDeviceFeedback));
00090 }
00091
00092 CClient::~CClient()
00093 {
00094 if (m_mock) {
00095 return;
00096 }
00097
00098 m_eventQueue->removeHandler(IScreen::getSuspendEvent(),
00099 getEventTarget());
00100 m_eventQueue->removeHandler(IScreen::getResumeEvent(),
00101 getEventTarget());
00102
00103 cleanupTimer();
00104 cleanupScreen();
00105 cleanupConnecting();
00106 cleanupConnection();
00107 delete m_socketFactory;
00108 delete m_streamFilterFactory;
00109 }
00110
00111 void
00112 CClient::connect()
00113 {
00114 if (m_stream != NULL) {
00115 return;
00116 }
00117 if (m_suspended) {
00118 m_connectOnResume = true;
00119 return;
00120 }
00121
00122 try {
00123
00124
00125
00126
00127
00128 m_serverAddress.resolve();
00129
00130
00131 if (m_serverAddress.getAddress() != NULL) {
00132
00133 LOG((CLOG_NOTE "connecting to '%s': %s:%i",
00134 m_serverAddress.getHostname().c_str(),
00135 ARCH->addrToString(m_serverAddress.getAddress()).c_str(),
00136 m_serverAddress.getPort()));
00137 }
00138
00139
00140 IDataSocket* socket = m_socketFactory->create();
00141
00142
00143 m_stream = socket;
00144 if (m_streamFilterFactory != NULL) {
00145 m_stream = m_streamFilterFactory->create(m_stream, true);
00146 }
00147 m_stream = new CPacketStreamFilter(m_stream, true);
00148
00149 if (m_crypto.m_mode != kDisabled) {
00150 m_cryptoStream = new CCryptoStream(
00151 EVENTQUEUE, m_stream, m_crypto, true);
00152 m_stream = m_cryptoStream;
00153 }
00154
00155
00156 LOG((CLOG_DEBUG1 "connecting to server"));
00157 setupConnecting();
00158 setupTimer();
00159 socket->connect(m_serverAddress);
00160 }
00161 catch (XBase& e) {
00162 cleanupTimer();
00163 cleanupConnecting();
00164 delete m_stream;
00165 m_stream = NULL;
00166 LOG((CLOG_DEBUG1 "connection failed"));
00167 sendConnectionFailedEvent(e.what());
00168 return;
00169 }
00170 }
00171
00172 void
00173 CClient::disconnect(const char* msg)
00174 {
00175 m_connectOnResume = false;
00176 cleanupTimer();
00177 cleanupScreen();
00178 cleanupConnecting();
00179 cleanupConnection();
00180 if (msg != NULL) {
00181 sendConnectionFailedEvent(msg);
00182 }
00183 else {
00184 sendEvent(getDisconnectedEvent(), NULL);
00185 }
00186 }
00187
00188 void
00189 CClient::handshakeComplete()
00190 {
00191 m_ready = true;
00192 m_screen->enable();
00193 sendEvent(getConnectedEvent(), NULL);
00194 }
00195
00196 void
00197 CClient::setDecryptIv(const UInt8* iv)
00198 {
00199 if (m_cryptoStream != NULL) {
00200 m_cryptoStream->setDecryptIv(iv);
00201 }
00202 }
00203
00204 bool
00205 CClient::isConnected() const
00206 {
00207 return (m_server != NULL);
00208 }
00209
00210 bool
00211 CClient::isConnecting() const
00212 {
00213 return (m_timer != NULL);
00214 }
00215
00216 CNetworkAddress
00217 CClient::getServerAddress() const
00218 {
00219 return m_serverAddress;
00220 }
00221
00222 CEvent::Type
00223 CClient::getConnectedEvent()
00224 {
00225 return EVENTQUEUE->registerTypeOnce(s_connectedEvent,
00226 "CClient::connected");
00227 }
00228
00229 CEvent::Type
00230 CClient::getConnectionFailedEvent()
00231 {
00232 return EVENTQUEUE->registerTypeOnce(s_connectionFailedEvent,
00233 "CClient::failed");
00234 }
00235
00236 CEvent::Type
00237 CClient::getDisconnectedEvent()
00238 {
00239 return EVENTQUEUE->registerTypeOnce(s_disconnectedEvent,
00240 "CClient::disconnected");
00241 }
00242
00243 void*
00244 CClient::getEventTarget() const
00245 {
00246 return m_screen->getEventTarget();
00247 }
00248
00249 bool
00250 CClient::getClipboard(ClipboardID id, IClipboard* clipboard) const
00251 {
00252 return m_screen->getClipboard(id, clipboard);
00253 }
00254
00255 void
00256 CClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
00257 {
00258 m_screen->getShape(x, y, w, h);
00259 }
00260
00261 void
00262 CClient::getCursorPos(SInt32& x, SInt32& y) const
00263 {
00264 m_screen->getCursorPos(x, y);
00265 }
00266
00267 void
00268 CClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool)
00269 {
00270 m_active = true;
00271 m_screen->mouseMove(xAbs, yAbs);
00272 m_screen->enter(mask);
00273 }
00274
00275 bool
00276 CClient::leave()
00277 {
00278 m_screen->leave();
00279
00280 m_active = false;
00281
00282
00283 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00284 if (m_ownClipboard[id]) {
00285 sendClipboard(id);
00286 }
00287 }
00288
00289 return true;
00290 }
00291
00292 void
00293 CClient::setClipboard(ClipboardID id, const IClipboard* clipboard)
00294 {
00295 m_screen->setClipboard(id, clipboard);
00296 m_ownClipboard[id] = false;
00297 m_sentClipboard[id] = false;
00298 }
00299
00300 void
00301 CClient::grabClipboard(ClipboardID id)
00302 {
00303 m_screen->grabClipboard(id);
00304 m_ownClipboard[id] = false;
00305 m_sentClipboard[id] = false;
00306 }
00307
00308 void
00309 CClient::setClipboardDirty(ClipboardID, bool)
00310 {
00311 assert(0 && "shouldn't be called");
00312 }
00313
00314 void
00315 CClient::keyDown(KeyID id, KeyModifierMask mask, KeyButton button)
00316 {
00317 m_screen->keyDown(id, mask, button);
00318 }
00319
00320 void
00321 CClient::keyRepeat(KeyID id, KeyModifierMask mask,
00322 SInt32 count, KeyButton button)
00323 {
00324 m_screen->keyRepeat(id, mask, count, button);
00325 }
00326
00327 void
00328 CClient::keyUp(KeyID id, KeyModifierMask mask, KeyButton button)
00329 {
00330 m_screen->keyUp(id, mask, button);
00331 }
00332
00333 void
00334 CClient::mouseDown(ButtonID id)
00335 {
00336 m_screen->mouseDown(id);
00337 }
00338
00339 void
00340 CClient::mouseUp(ButtonID id)
00341 {
00342 m_screen->mouseUp(id);
00343 }
00344
00345 void
00346 CClient::mouseMove(SInt32 x, SInt32 y)
00347 {
00348 m_screen->mouseMove(x, y);
00349 }
00350
00351 void
00352 CClient::mouseRelativeMove(SInt32 dx, SInt32 dy)
00353 {
00354 m_screen->mouseRelativeMove(dx, dy);
00355 }
00356
00357 void
00358 CClient::mouseWheel(SInt32 xDelta, SInt32 yDelta)
00359 {
00360 m_screen->mouseWheel(xDelta, yDelta);
00361 }
00362
00363 void
00364 CClient::screensaver(bool activate)
00365 {
00366 m_screen->screensaver(activate);
00367 }
00368
00369 void
00370 CClient::resetOptions()
00371 {
00372 m_screen->resetOptions();
00373 }
00374
00375 void
00376 CClient::setOptions(const COptionsList& options)
00377 {
00378 m_screen->setOptions(options);
00379 }
00380
00381 void
00382 CClient::gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons)
00383 {
00384 m_screen->gameDeviceButtons(id, buttons);
00385 }
00386
00387 void
00388 CClient::gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2)
00389 {
00390 m_screen->gameDeviceSticks(id, x1, y1, x2, y2);
00391 }
00392
00393 void
00394 CClient::gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2)
00395 {
00396 m_screen->gameDeviceTriggers(id, t1, t2);
00397 }
00398
00399 void
00400 CClient::gameDeviceTimingReq()
00401 {
00402 m_screen->gameDeviceTimingReq();
00403 }
00404
00405 CString
00406 CClient::getName() const
00407 {
00408 return m_name;
00409 }
00410
00411 void
00412 CClient::sendClipboard(ClipboardID id)
00413 {
00414
00415 assert(m_screen != NULL);
00416 assert(m_server != NULL);
00417
00418
00419
00420
00421
00422 CClipboard clipboard;
00423 if (clipboard.open(m_timeClipboard[id])) {
00424 clipboard.close();
00425 }
00426 m_screen->getClipboard(id, &clipboard);
00427
00428
00429 if (m_timeClipboard[id] == 0 ||
00430 clipboard.getTime() != m_timeClipboard[id]) {
00431
00432 m_timeClipboard[id] = clipboard.getTime();
00433
00434
00435 CString data = clipboard.marshall();
00436
00437
00438 if (!m_sentClipboard[id] || data != m_dataClipboard[id]) {
00439 m_sentClipboard[id] = true;
00440 m_dataClipboard[id] = data;
00441 m_server->onClipboardChanged(id, &clipboard);
00442 }
00443 }
00444 }
00445
00446 void
00447 CClient::sendEvent(CEvent::Type type, void* data)
00448 {
00449 m_eventQueue->addEvent(CEvent(type, getEventTarget(), data));
00450 }
00451
00452 void
00453 CClient::sendConnectionFailedEvent(const char* msg)
00454 {
00455 CFailInfo* info = new CFailInfo(msg);
00456 info->m_retry = true;
00457 CEvent event(getConnectionFailedEvent(), getEventTarget(), info, CEvent::kDontFreeData);
00458 m_eventQueue->addEvent(event);
00459 }
00460
00461 void
00462 CClient::setupConnecting()
00463 {
00464 assert(m_stream != NULL);
00465
00466 m_eventQueue->adoptHandler(IDataSocket::getConnectedEvent(),
00467 m_stream->getEventTarget(),
00468 new TMethodEventJob<CClient>(this,
00469 &CClient::handleConnected));
00470 m_eventQueue->adoptHandler(IDataSocket::getConnectionFailedEvent(),
00471 m_stream->getEventTarget(),
00472 new TMethodEventJob<CClient>(this,
00473 &CClient::handleConnectionFailed));
00474 }
00475
00476 void
00477 CClient::setupConnection()
00478 {
00479 assert(m_stream != NULL);
00480
00481 m_eventQueue->adoptHandler(ISocket::getDisconnectedEvent(),
00482 m_stream->getEventTarget(),
00483 new TMethodEventJob<CClient>(this,
00484 &CClient::handleDisconnected));
00485 m_eventQueue->adoptHandler(m_stream->getInputReadyEvent(),
00486 m_stream->getEventTarget(),
00487 new TMethodEventJob<CClient>(this,
00488 &CClient::handleHello));
00489 m_eventQueue->adoptHandler(m_stream->getOutputErrorEvent(),
00490 m_stream->getEventTarget(),
00491 new TMethodEventJob<CClient>(this,
00492 &CClient::handleOutputError));
00493 m_eventQueue->adoptHandler(m_stream->getInputShutdownEvent(),
00494 m_stream->getEventTarget(),
00495 new TMethodEventJob<CClient>(this,
00496 &CClient::handleDisconnected));
00497 m_eventQueue->adoptHandler(m_stream->getOutputShutdownEvent(),
00498 m_stream->getEventTarget(),
00499 new TMethodEventJob<CClient>(this,
00500 &CClient::handleDisconnected));
00501 }
00502
00503 void
00504 CClient::setupScreen()
00505 {
00506 assert(m_server == NULL);
00507
00508 m_ready = false;
00509 m_server = new CServerProxy(this, m_stream, m_eventQueue);
00510 m_eventQueue->adoptHandler(IScreen::getShapeChangedEvent(),
00511 getEventTarget(),
00512 new TMethodEventJob<CClient>(this,
00513 &CClient::handleShapeChanged));
00514 m_eventQueue->adoptHandler(IScreen::getClipboardGrabbedEvent(),
00515 getEventTarget(),
00516 new TMethodEventJob<CClient>(this,
00517 &CClient::handleClipboardGrabbed));
00518 }
00519
00520 void
00521 CClient::setupTimer()
00522 {
00523 assert(m_timer == NULL);
00524
00525 m_timer = m_eventQueue->newOneShotTimer(15.0, NULL);
00526 m_eventQueue->adoptHandler(CEvent::kTimer, m_timer,
00527 new TMethodEventJob<CClient>(this,
00528 &CClient::handleConnectTimeout));
00529 }
00530
00531 void
00532 CClient::cleanupConnecting()
00533 {
00534 if (m_stream != NULL) {
00535 m_eventQueue->removeHandler(IDataSocket::getConnectedEvent(),
00536 m_stream->getEventTarget());
00537 m_eventQueue->removeHandler(IDataSocket::getConnectionFailedEvent(),
00538 m_stream->getEventTarget());
00539 }
00540 }
00541
00542 void
00543 CClient::cleanupConnection()
00544 {
00545 if (m_stream != NULL) {
00546 m_eventQueue->removeHandler(m_stream->getInputReadyEvent(),
00547 m_stream->getEventTarget());
00548 m_eventQueue->removeHandler(m_stream->getOutputErrorEvent(),
00549 m_stream->getEventTarget());
00550 m_eventQueue->removeHandler(m_stream->getInputShutdownEvent(),
00551 m_stream->getEventTarget());
00552 m_eventQueue->removeHandler(m_stream->getOutputShutdownEvent(),
00553 m_stream->getEventTarget());
00554 m_eventQueue->removeHandler(ISocket::getDisconnectedEvent(),
00555 m_stream->getEventTarget());
00556 delete m_stream;
00557 m_stream = NULL;
00558 }
00559 }
00560
00561 void
00562 CClient::cleanupScreen()
00563 {
00564 if (m_server != NULL) {
00565 if (m_ready) {
00566 m_screen->disable();
00567 m_ready = false;
00568 }
00569 m_eventQueue->removeHandler(IScreen::getShapeChangedEvent(),
00570 getEventTarget());
00571 m_eventQueue->removeHandler(IScreen::getClipboardGrabbedEvent(),
00572 getEventTarget());
00573 delete m_server;
00574 m_server = NULL;
00575 }
00576 }
00577
00578 void
00579 CClient::cleanupTimer()
00580 {
00581 if (m_timer != NULL) {
00582 m_eventQueue->removeHandler(CEvent::kTimer, m_timer);
00583 m_eventQueue->deleteTimer(m_timer);
00584 m_timer = NULL;
00585 }
00586 }
00587
00588 void
00589 CClient::handleConnected(const CEvent&, void*)
00590 {
00591 LOG((CLOG_DEBUG1 "connected; wait for hello"));
00592 cleanupConnecting();
00593 setupConnection();
00594
00595
00596 for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
00597 m_ownClipboard[id] = false;
00598 m_sentClipboard[id] = false;
00599 m_timeClipboard[id] = 0;
00600 }
00601 }
00602
00603 void
00604 CClient::handleConnectionFailed(const CEvent& event, void*)
00605 {
00606 IDataSocket::CConnectionFailedInfo* info =
00607 reinterpret_cast<IDataSocket::CConnectionFailedInfo*>(event.getData());
00608
00609 cleanupTimer();
00610 cleanupConnecting();
00611 delete m_stream;
00612 m_stream = NULL;
00613 LOG((CLOG_DEBUG1 "connection failed"));
00614 sendConnectionFailedEvent(info->m_what.c_str());
00615 delete info;
00616 }
00617
00618 void
00619 CClient::handleConnectTimeout(const CEvent&, void*)
00620 {
00621 cleanupTimer();
00622 cleanupConnecting();
00623 cleanupConnection();
00624 delete m_stream;
00625 m_stream = NULL;
00626 LOG((CLOG_DEBUG1 "connection timed out"));
00627 sendConnectionFailedEvent("Timed out");
00628 }
00629
00630 void
00631 CClient::handleOutputError(const CEvent&, void*)
00632 {
00633 cleanupTimer();
00634 cleanupScreen();
00635 cleanupConnection();
00636 LOG((CLOG_WARN "error sending to server"));
00637 sendEvent(getDisconnectedEvent(), NULL);
00638 }
00639
00640 void
00641 CClient::handleDisconnected(const CEvent&, void*)
00642 {
00643 cleanupTimer();
00644 cleanupScreen();
00645 cleanupConnection();
00646 LOG((CLOG_DEBUG1 "disconnected"));
00647 sendEvent(getDisconnectedEvent(), NULL);
00648 }
00649
00650 void
00651 CClient::handleShapeChanged(const CEvent&, void*)
00652 {
00653 LOG((CLOG_DEBUG "resolution changed"));
00654 m_server->onInfoChanged();
00655 }
00656
00657 void
00658 CClient::handleClipboardGrabbed(const CEvent& event, void*)
00659 {
00660 const IScreen::CClipboardInfo* info =
00661 reinterpret_cast<const IScreen::CClipboardInfo*>(event.getData());
00662
00663
00664 m_server->onGrabClipboard(info->m_id);
00665
00666
00667 m_ownClipboard[info->m_id] = true;
00668 m_sentClipboard[info->m_id] = false;
00669 m_timeClipboard[info->m_id] = 0;
00670
00671
00672
00673 if (!m_active) {
00674 sendClipboard(info->m_id);
00675 }
00676 }
00677
00678 void
00679 CClient::handleHello(const CEvent&, void*)
00680 {
00681 SInt16 major, minor;
00682 if (!CProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) {
00683 sendConnectionFailedEvent("Protocol error from server");
00684 cleanupTimer();
00685 cleanupConnection();
00686 return;
00687 }
00688
00689
00690 LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor));
00691 if (major < kProtocolMajorVersion ||
00692 (major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) {
00693 sendConnectionFailedEvent(XIncompatibleClient(major, minor).what());
00694 cleanupTimer();
00695 cleanupConnection();
00696 return;
00697 }
00698
00699
00700 LOG((CLOG_DEBUG1 "say hello version %d.%d", kProtocolMajorVersion, kProtocolMinorVersion));
00701 CProtocolUtil::writef(m_stream, kMsgHelloBack,
00702 kProtocolMajorVersion,
00703 kProtocolMinorVersion, &m_name);
00704
00705
00706 setupScreen();
00707 cleanupTimer();
00708
00709
00710
00711
00712 if (m_stream->isReady()) {
00713 m_eventQueue->addEvent(CEvent(m_stream->getInputReadyEvent(),
00714 m_stream->getEventTarget()));
00715 }
00716 }
00717
00718 void
00719 CClient::handleSuspend(const CEvent&, void*)
00720 {
00721 LOG((CLOG_INFO "suspend"));
00722 m_suspended = true;
00723 bool wasConnected = isConnected();
00724 disconnect(NULL);
00725 m_connectOnResume = wasConnected;
00726 }
00727
00728 void
00729 CClient::handleResume(const CEvent&, void*)
00730 {
00731 LOG((CLOG_INFO "resume"));
00732 m_suspended = false;
00733 if (m_connectOnResume) {
00734 m_connectOnResume = false;
00735 connect();
00736 }
00737 }
00738
00739 void
00740 CClient::handleGameDeviceTimingResp(const CEvent& event, void*)
00741 {
00742 IPlatformScreen::CGameDeviceTimingRespInfo* info =
00743 reinterpret_cast<IPlatformScreen::CGameDeviceTimingRespInfo*>(event.getData());
00744
00745 m_server->onGameDeviceTimingResp(info->m_freq);
00746 }
00747
00748 void
00749 CClient::handleGameDeviceFeedback(const CEvent& event, void*)
00750 {
00751 IPlatformScreen::CGameDeviceFeedbackInfo* info =
00752 reinterpret_cast<IPlatformScreen::CGameDeviceFeedbackInfo*>(event.getData());
00753
00754 m_server->onGameDeviceFeedback(info->m_id, info->m_m1, info->m_m2);
00755 }