diff --git a/cmd/synergy/synergy.cpp b/cmd/synergy/synergy.cpp index 65256702..06d0481c 100644 --- a/cmd/synergy/synergy.cpp +++ b/cmd/synergy/synergy.cpp @@ -3,6 +3,7 @@ #include "CPlatform.h" #include "ProtocolTypes.h" #include "Version.h" +#include "XScreen.h" #include "CNetwork.h" #include "CNetworkAddress.h" #include "CTCPSocketFactory.h" @@ -125,7 +126,8 @@ realMain(CMutex* mutex) s_client->setStreamFilterFactory(NULL); // open client - if (s_client->open()) { + try { + s_client->open(); opened = true; // run client @@ -139,31 +141,33 @@ realMain(CMutex* mutex) mutex->lock(); } - // get client status - if (s_client->wasRejected()) { - // wait a while before retrying. we don't want - // to bother the server very often if it doesn't - // want us. - if (s_restartable) { - CThread::sleep(60.0); - } - else { - result = kExitFailed; - } - } - // clean up s_client->close(); + + // get client status + if (s_client->wasRejected()) { + // try again later. we don't want to bother + // the server very often if it doesn't want us. + throw XScreenUnavailable(60.0); + } } - else { + catch (XScreenUnavailable& e) { // wait a few seconds before retrying if (s_restartable) { - CThread::sleep(3.0); + CThread::sleep(e.getRetryTime()); } else { result = kExitFailed; } } + catch (...) { + // rethrow thread exceptions + RETHROW_XTHREAD + + // don't try to restart and fail + s_restartable = false; + result = kExitFailed; + } // clean up delete s_client; diff --git a/cmd/synergyd/synergyd.cpp b/cmd/synergyd/synergyd.cpp index 2db390a3..60d070c4 100644 --- a/cmd/synergyd/synergyd.cpp +++ b/cmd/synergyd/synergyd.cpp @@ -4,6 +4,7 @@ #include "CPlatform.h" #include "ProtocolTypes.h" #include "Version.h" +#include "XScreen.h" #include "CNetwork.h" #include "CTCPSocketFactory.h" #include "XSocket.h" @@ -156,7 +157,8 @@ realMain(CMutex* mutex) s_server->setStreamFilterFactory(NULL); // open server - if (s_server->open()) { + try { + s_server->open(); opened = true; // run server (unlocked) @@ -173,15 +175,23 @@ realMain(CMutex* mutex) // clean up s_server->close(); } - else { - // wait a few seconds before retrying + catch (XScreenUnavailable& e) { + // wait before retrying if we're going to retry if (s_restartable) { - CThread::sleep(3.0); + CThread::sleep(e.getRetryTime()); } else { result = kExitFailed; } } + catch (...) { + // rethrow thread exceptions + RETHROW_XTHREAD + + // don't try to restart and fail + s_restartable = false; + result = kExitFailed; + } // clean up delete s_server; diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index 6a70c2f8..bb3a8b98 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -149,19 +149,18 @@ CClient::onClipboardChanged(ClipboardID, const CString&) // ignore -- we'll check the clipboard when we leave } -bool +void CClient::open() { // open the screen try { log((CLOG_INFO "opening screen")); openSecondaryScreen(); - return true; } catch (XScreenOpenFailure&) { - // can't open screen yet. wait a few seconds to retry. + // can't open screen log((CLOG_INFO "failed to open screen")); - return false; + throw; } } @@ -368,7 +367,6 @@ void CClient::openSecondaryScreen() { assert(m_screen == NULL); - assert(m_screenFactory != NULL); // not active m_active = false; @@ -381,7 +379,9 @@ CClient::openSecondaryScreen() // create screen log((CLOG_DEBUG1 "creating secondary screen")); - m_screen = m_screenFactory->create(this); + if (m_screenFactory != NULL) { + m_screen = m_screenFactory->create(this); + } if (m_screen == NULL) { throw XScreenOpenFailure(); } @@ -402,12 +402,12 @@ CClient::openSecondaryScreen() void CClient::closeSecondaryScreen() { - assert(m_screen != NULL); - // close the secondary screen try { - log((CLOG_DEBUG1 "closing secondary screen")); - m_screen->close(); + if (m_screen != NULL) { + log((CLOG_DEBUG1 "closing secondary screen")); + m_screen->close(); + } } catch (...) { // ignore diff --git a/lib/client/CClient.h b/lib/client/CClient.h index 3cfb4543..61f0fe2b 100644 --- a/lib/client/CClient.h +++ b/lib/client/CClient.h @@ -98,7 +98,7 @@ public: virtual void onClipboardChanged(ClipboardID, const CString&); // IClient overrides - virtual bool open(); + virtual void open(); virtual void mainLoop(); virtual void close(); virtual void enter(SInt32 xAbs, SInt32 yAbs, diff --git a/lib/client/CXWindowsSecondaryScreen.cpp b/lib/client/CXWindowsSecondaryScreen.cpp index 4c921927..7c1f55a3 100644 --- a/lib/client/CXWindowsSecondaryScreen.cpp +++ b/lib/client/CXWindowsSecondaryScreen.cpp @@ -229,7 +229,7 @@ CXWindowsSecondaryScreen::createWindow() int majorOpcode, firstEvent, firstError; if (!XQueryExtension(display, XTestExtensionName, &majorOpcode, &firstEvent, &firstError)) { - // FIXME -- subclass exception for more info? + log((CLOG_ERR "XTEST extension not available")); throw XScreenOpenFailure(); } diff --git a/lib/platform/CXWindowsScreen.cpp b/lib/platform/CXWindowsScreen.cpp index e5e2fd8f..0b908981 100644 --- a/lib/platform/CXWindowsScreen.cpp +++ b/lib/platform/CXWindowsScreen.cpp @@ -197,7 +197,7 @@ CXWindowsScreen::open() log((CLOG_DEBUG "XOpenDisplay(\"%s\")", display)); m_display = XOpenDisplay(display); if (m_display == NULL) { - throw XScreenOpenFailure(); + throw XScreenUnavailable(60.0); } // get root window diff --git a/lib/server/CClientProxy.h b/lib/server/CClientProxy.h index 83cb3e14..46c47953 100644 --- a/lib/server/CClientProxy.h +++ b/lib/server/CClientProxy.h @@ -43,7 +43,7 @@ public: //@} // IClient overrides - virtual bool open() = 0; + virtual void open() = 0; virtual void mainLoop() = 0; virtual void close() = 0; virtual void enter(SInt32 xAbs, SInt32 yAbs, diff --git a/lib/server/CClientProxy1_0.cpp b/lib/server/CClientProxy1_0.cpp index ad0d45f1..eb76b3cc 100644 --- a/lib/server/CClientProxy1_0.cpp +++ b/lib/server/CClientProxy1_0.cpp @@ -29,7 +29,7 @@ CClientProxy1_0::~CClientProxy1_0() // do nothing } -bool +void CClientProxy1_0::open() { // send request @@ -55,8 +55,6 @@ CClientProxy1_0::open() // handle reply recvInfo(false); - - return true; } void diff --git a/lib/server/CClientProxy1_0.h b/lib/server/CClientProxy1_0.h index befb480c..01522865 100644 --- a/lib/server/CClientProxy1_0.h +++ b/lib/server/CClientProxy1_0.h @@ -14,7 +14,7 @@ public: ~CClientProxy1_0(); // IClient overrides - virtual bool open(); + virtual void open(); virtual void mainLoop(); virtual void close(); virtual void enter(SInt32 xAbs, SInt32 yAbs, diff --git a/lib/server/CMSWindowsPrimaryScreen.cpp b/lib/server/CMSWindowsPrimaryScreen.cpp index 3b257840..4b909412 100644 --- a/lib/server/CMSWindowsPrimaryScreen.cpp +++ b/lib/server/CMSWindowsPrimaryScreen.cpp @@ -399,6 +399,7 @@ CMSWindowsPrimaryScreen::onPreOpen() // initialize hook library m_threadID = GetCurrentThreadId(); if (m_init(m_threadID) == 0) { + log((CLOG_ERR "cannot initialize hook library")); throw XScreenOpenFailure(); } } diff --git a/lib/server/CPrimaryClient.cpp b/lib/server/CPrimaryClient.cpp index 44f01109..638c37c4 100644 --- a/lib/server/CPrimaryClient.cpp +++ b/lib/server/CPrimaryClient.cpp @@ -1,6 +1,7 @@ #include "CPrimaryClient.h" #include "IPrimaryScreenFactory.h" #include "IServer.h" +#include "XScreen.h" #include "XSynergy.h" #include "CPrimaryScreen.h" #include "CClipboard.h" @@ -19,11 +20,15 @@ CPrimaryClient::CPrimaryClient(IPrimaryScreenFactory* screenFactory, m_seqNum(0) { assert(m_server != NULL); - assert(screenFactory != NULL); // create screen log((CLOG_DEBUG1 "creating primary screen")); - m_screen = screenFactory->create(this, receiver); + if (screenFactory != NULL) { + m_screen = screenFactory->create(this, receiver); + } + if (m_screen == NULL) { + throw XScreenOpenFailure(); + } } CPrimaryClient::~CPrimaryClient() @@ -100,7 +105,7 @@ CPrimaryClient::onClipboardChanged(ClipboardID id, const CString& data) m_server->onClipboardChanged(id, m_seqNum, data); } -bool +void CPrimaryClient::open() { // all clipboards are clean @@ -110,8 +115,6 @@ CPrimaryClient::open() // now open the screen m_screen->open(); - - return true; } void diff --git a/lib/server/CPrimaryClient.h b/lib/server/CPrimaryClient.h index 84ea0bad..0c98e956 100644 --- a/lib/server/CPrimaryClient.h +++ b/lib/server/CPrimaryClient.h @@ -20,8 +20,9 @@ treated as if it was on a client. class CPrimaryClient : public IScreenReceiver, public IClient { public: /*! - \c name is the name of the server. the caller retains ownership of - \c factory. + \c name is the name of the server. The caller retains ownership of + \c factory. Throws XScreenOpenFailure or whatever the factory can + throw if the screen cannot be created. */ CPrimaryClient(IPrimaryScreenFactory* factory, IServer*, IPrimaryScreenReceiver*, const CString& name); @@ -75,7 +76,7 @@ public: virtual void onClipboardChanged(ClipboardID, const CString&); // IClient overrides - virtual bool open(); + virtual void open(); virtual void mainLoop(); virtual void close(); virtual void enter(SInt32 xAbs, SInt32 yAbs, diff --git a/lib/server/CServer.cpp b/lib/server/CServer.cpp index 822bac97..0b0bc327 100644 --- a/lib/server/CServer.cpp +++ b/lib/server/CServer.cpp @@ -53,24 +53,23 @@ CServer::~CServer() delete m_streamFilterFactory; } -bool +void CServer::open() { // open the screen try { log((CLOG_INFO "opening screen")); openPrimaryScreen(); - return true; } - catch (XScreenOpenFailure&) { - // can't open screen yet. wait a few seconds to retry. + catch (XScreen&) { + // can't open screen log((CLOG_INFO "failed to open screen")); - return false; + throw; } catch (XUnknownClient& e) { - // can't open screen yet. wait a few seconds to retry. + // can't open screen log((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str())); - return false; + throw; } } @@ -1529,7 +1528,6 @@ void CServer::openPrimaryScreen() { assert(m_primaryClient == NULL); - assert(m_screenFactory != NULL); // reset sequence number m_seqNum = 0; diff --git a/lib/server/CServer.h b/lib/server/CServer.h index a119fa6a..494da9ae 100644 --- a/lib/server/CServer.h +++ b/lib/server/CServer.h @@ -39,9 +39,12 @@ public: //! Open server /*! - Open the server and return true iff successful. + Open the server. Throws XScreenUnavailable if the server's + screen cannot be opened but might be available after some time. + Otherwise throws some other exception if the server's screen or + the server cannot be opened and retrying won't help. */ - bool open(); + void open(); //! Server main loop /*! diff --git a/lib/synergy/IClient.h b/lib/synergy/IClient.h index 01027abb..12c534d1 100644 --- a/lib/synergy/IClient.h +++ b/lib/synergy/IClient.h @@ -19,9 +19,11 @@ public: //! Open client /*! - Open the client and return true iff successful. + Open the client. Throw if the client cannot be opened. If the + screen cannot be opened but retrying later may succeed then throw + XScreenUnavailable. */ - virtual bool open() = 0; + virtual void open() = 0; //! Client main loop /*! diff --git a/lib/synergy/IScreen.h b/lib/synergy/IScreen.h index b60f56d6..48417984 100644 --- a/lib/synergy/IScreen.h +++ b/lib/synergy/IScreen.h @@ -19,7 +19,9 @@ public: //! Open screen /*! - Called to open and initialize the screen. + Called to open and initialize the screen. Throw XScreenUnavailable + if the screen cannot be opened but retrying later may succeed. + Otherwise throw some other XScreenOpenFailure exception. */ virtual void open() = 0; diff --git a/lib/synergy/XScreen.cpp b/lib/synergy/XScreen.cpp index b011b131..63684f5d 100644 --- a/lib/synergy/XScreen.cpp +++ b/lib/synergy/XScreen.cpp @@ -9,3 +9,31 @@ XScreenOpenFailure::getWhat() const throw() { return format("XScreenOpenFailure", "unable to open screen"); } + + +// +// XScreenUnavailable +// + +XScreenUnavailable::XScreenUnavailable(double timeUntilRetry) : + m_timeUntilRetry(timeUntilRetry) +{ + // do nothing +} + +XScreenUnavailable::~XScreenUnavailable() +{ + // do nothing +} + +double +XScreenUnavailable::getRetryTime() const +{ + return m_timeUntilRetry; +} + +CString +XScreenUnavailable::getWhat() const throw() +{ + return format("XScreenUnavailable", "unable to open screen"); +} diff --git a/lib/synergy/XScreen.h b/lib/synergy/XScreen.h index 2b71402a..b69fd61a 100644 --- a/lib/synergy/XScreen.h +++ b/lib/synergy/XScreen.h @@ -15,4 +15,36 @@ protected: virtual CString getWhat() const throw(); }; +//! Screen unavailable exception +/*! +Thrown when a screen cannot be opened or initialized but retrying later +may be successful. +*/ +class XScreenUnavailable : public XScreenOpenFailure { +public: + /*! + \c timeUntilRetry is the suggested time the caller should wait until + trying to open the screen again. + */ + XScreenUnavailable(double timeUntilRetry); + virtual ~XScreenUnavailable(); + + //! @name manipulators + //@{ + + //! Get retry time + /*! + Returns the suggested time to wait until retrying to open the screen. + */ + double getRetryTime() const; + + //@} + +protected: + virtual CString getWhat() const throw(); + +private: + double m_timeUntilRetry; +}; + #endif