diff --git a/lib/server/CServer.cpp b/lib/server/CServer.cpp index a4d124f0..aede8ca9 100644 --- a/lib/server/CServer.cpp +++ b/lib/server/CServer.cpp @@ -46,6 +46,7 @@ const SInt32 CServer::s_httpMaxSimultaneousRequests = 3; CServer::CServer(const CString& serverName) : m_name(serverName), + m_error(false), m_bindTimeout(5.0 * 60.0), m_screenFactory(NULL), m_socketFactory(NULL), @@ -161,6 +162,12 @@ CServer::mainLoop() throw; } #undef FINALLY + + // throw if there was an error + if (m_error) { + LOG((CLOG_DEBUG "forwarding child thread exception")); + throw XServerRethrow(); + } } void @@ -169,6 +176,16 @@ CServer::exitMainLoop() m_primaryClient->exitMainLoop(); } +void +CServer::exitMainLoopWithError() +{ + { + CLock lock(&m_mutex); + m_error = true; + } + exitMainLoop(); +} + void CServer::close() { @@ -1186,7 +1203,7 @@ CServer::acceptClients(void*) listen->bind(m_config.getSynergyAddress()); break; } - catch (XSocketBind& e) { + catch (XSocketAddressInUse& e) { LOG((CLOG_WARN "bind failed: %s", e.getErrstr())); // give up if we've waited too long @@ -1220,7 +1237,7 @@ CServer::acceptClients(void*) catch (XBase& e) { LOG((CLOG_ERR "cannot listen for clients: %s", e.what())); delete listen; - exitMainLoop(); + exitMainLoopWithError(); } catch (...) { delete listen; @@ -1505,7 +1522,7 @@ CServer::acceptHTTPClients(void*) catch (XBase& e) { LOG((CLOG_ERR "cannot listen for HTTP clients: %s", e.what())); delete listen; - exitMainLoop(); + exitMainLoopWithError(); } catch (...) { delete listen; @@ -1691,6 +1708,17 @@ CServer::removeConnection(const CString& name) } +// +// CServer::CClipboardInfo +// + +CString +CServer::XServerRethrow::getWhat() const throw() +{ + return format("XServerRethrow", "child thread failed"); +} + + // // CServer::CClipboardInfo // diff --git a/lib/server/CServer.h b/lib/server/CServer.h index e9a1224f..49583c6e 100644 --- a/lib/server/CServer.h +++ b/lib/server/CServer.h @@ -157,6 +157,14 @@ protected: */ bool onCommandKey(KeyID, KeyModifierMask, bool down); + //! Exit event loop and note an error condition + /*! + Force mainLoop() to return by throwing an exception. This call + can return before mainLoop() does (i.e. asynchronously). This + may only be called between a successful open() and close(). + */ + void exitMainLoopWithError(); + private: typedef std::list CThreadList; @@ -230,6 +238,12 @@ private: void removeConnection(const CString& name); private: + class XServerRethrow : public XBase { + protected: + // XBase overrides + virtual CString getWhat() const throw(); + }; + class CClipboardInfo { public: CClipboardInfo(); @@ -246,6 +260,14 @@ private: // the name of the primary screen CString m_name; + // true if we should exit the main loop by throwing an exception. + // this is used to propagate an exception from one of our threads + // to the mainLoop() thread. but, since we can't make a copy of + // the original exception, we return an arbitrary, unique + // exception type. the caller of mainLoop() cannot catch this + // exception except through XBase or .... + bool m_error; + // how long to wait to bind our socket until we give up double m_bindTimeout;