From 8bad45e8a25ac219bf603716789aa62bdfde6633 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Tue, 10 Jul 2012 01:51:51 +0000 Subject: [PATCH] * fixed a shit-ton of memory leaks (lots in the ipc log handler, oops) * added non-pod data support to events (event delete can now call dtors) * improved cleanup of ipc message objects (because of non-pod event data support) * moved the "message received" event up to ipc server and client (passed on from proxies) --- src/gui/src/IpcReader.cpp | 50 ++-- src/lib/arch/CArch.cpp | 12 +- src/lib/arch/CArch.h | 14 +- src/lib/arch/CArchMiscWindows.cpp | 6 + src/lib/arch/CArchMiscWindows.h | 3 + src/lib/arch/CArchNetworkWinsock.cpp | 6 + src/lib/arch/CArchNetworkWinsock.h | 4 + src/lib/base/CEvent.cpp | 20 +- src/lib/base/CEvent.h | 34 ++- src/lib/base/CLog.cpp | 306 +++++++++++----------- src/lib/base/CLog.h | 4 +- src/lib/base/CSimpleEventQueueBuffer.cpp | 2 - src/lib/base/CSimpleEventQueueBuffer.h | 7 + src/lib/ipc/CIpcClient.cpp | 40 ++- src/lib/ipc/CIpcClient.h | 8 +- src/lib/ipc/CIpcClientProxy.cpp | 70 ++--- src/lib/ipc/CIpcClientProxy.h | 16 +- src/lib/ipc/CIpcLogOutputter.cpp | 18 +- src/lib/ipc/CIpcLogOutputter.h | 2 +- src/lib/ipc/CIpcMessage.cpp | 49 +++- src/lib/ipc/CIpcMessage.h | 58 +++- src/lib/ipc/CIpcServer.cpp | 39 ++- src/lib/ipc/CIpcServer.h | 7 +- src/lib/ipc/CIpcServerProxy.cpp | 71 ++--- src/lib/ipc/CIpcServerProxy.h | 13 +- src/lib/platform/CMSWindowsClipboard.cpp | 8 + src/lib/platform/CMSWindowsClipboard.h | 2 +- src/lib/platform/CMSWindowsDesks.cpp | 2 +- src/lib/platform/CMSWindowsRelauncher.cpp | 12 +- src/lib/synergy/CApp.cpp | 22 +- src/lib/synergy/CApp.h | 2 +- src/lib/synergy/CClientApp.cpp | 4 + src/lib/synergy/CDaemonApp.cpp | 54 ++-- src/lib/synergy/CDaemonApp.h | 1 - src/lib/synergy/CServerApp.cpp | 4 + src/test/integtests/CIpcTests.cpp | 118 +++++---- src/test/integtests/Main.cpp | 5 + 37 files changed, 697 insertions(+), 396 deletions(-) diff --git a/src/gui/src/IpcReader.cpp b/src/gui/src/IpcReader.cpp index a741874a..94d82c16 100644 --- a/src/gui/src/IpcReader.cpp +++ b/src/gui/src/IpcReader.cpp @@ -41,30 +41,34 @@ void IpcReader::read() QMutexLocker locker(&m_Mutex); std::cout << "ready read" << std::endl; - char codeBuf[1]; - readStream(codeBuf, 1); - int code = bytesToInt(codeBuf, 1); + while (m_Socket->bytesAvailable()) { + std::cout << "bytes available" << std::endl; - switch (code) { - case kIpcLogLine: { - std::cout << "reading log line" << std::endl; + char codeBuf[1]; + readStream(codeBuf, 1); + int code = bytesToInt(codeBuf, 1); - char lenBuf[4]; - readStream(lenBuf, 4); - int len = bytesToInt(lenBuf, 4); + switch (code) { + case kIpcLogLine: { + std::cout << "reading log line" << std::endl; - char* data = new char[len]; - readStream(data, len); - QString line = QString::fromUtf8(data, len); - delete data; + char lenBuf[4]; + readStream(lenBuf, 4); + int len = bytesToInt(lenBuf, 4); - readLogLine(line); - break; + char* data = new char[len]; + readStream(data, len); + QString line = QString::fromUtf8(data, len); + delete data; + + readLogLine(line); + break; + } + + default: + std::cerr << "aborting, message invalid: " << code << std::endl; + return; } - - default: - std::cerr << "aborting, message invalid: " << code << std::endl; - return; } std::cout << "read done" << std::endl; @@ -82,13 +86,7 @@ bool IpcReader::readStream(char* buffer, int length) m_Socket->waitForReadyRead(-1); } - // i really don't trust qt not to copy beyond the array length. - // seems like a convoluted an expensive way to copy from the stream :/ - char* tempBuffer = new char[ask]; - int got = m_Socket->read(tempBuffer, ask); - memcpy(buffer, tempBuffer, got); - delete tempBuffer; - + int got = m_Socket->read(buffer, ask); read += got; std::cout << "> ask=" << ask << " got=" << got diff --git a/src/lib/arch/CArch.cpp b/src/lib/arch/CArch.cpp index 0ff78cd6..d3fc996b 100644 --- a/src/lib/arch/CArch.cpp +++ b/src/lib/arch/CArch.cpp @@ -25,16 +25,20 @@ CArch* CArch::s_instance = NULL; CArch::CArch() { + assert(s_instance == NULL); + s_instance = this; } CArch::~CArch() { +#if SYSAPI_WIN32 + CArchMiscWindows::cleanup(); +#endif } void CArch::init() { - // initialization that requires ARCH is done here. ARCH_NETWORK::init(); #if SYSAPI_WIN32 ARCH_TASKBAR::init(); @@ -45,10 +49,6 @@ CArch::init() CArch* CArch::getInstance() { - if (s_instance == NULL) { - s_instance = new CArch(); - s_instance->init(); - } - + assert(s_instance != NULL); return s_instance; } diff --git a/src/lib/arch/CArch.h b/src/lib/arch/CArch.h index c011c95d..9eecc68f 100644 --- a/src/lib/arch/CArch.h +++ b/src/lib/arch/CArch.h @@ -96,7 +96,15 @@ class CArch : public ARCH_CONSOLE, public ARCH_TASKBAR, public ARCH_TIME { public: - ~CArch(); + CArch(); + virtual ~CArch(); + + //! Call init on other arch classes. + /*! + Some arch classes depend on others to exist first. When init is called + these clases will have ARCH available for use. + */ + virtual void init(); // // accessors @@ -111,10 +119,6 @@ public: ARCH_PLUGIN& plugin() const { return (ARCH_PLUGIN&)m_plugin; } -private: - CArch(); - void init(); - private: static CArch* s_instance; ARCH_PLUGIN m_plugin; diff --git a/src/lib/arch/CArchMiscWindows.cpp b/src/lib/arch/CArchMiscWindows.cpp index 1420fe25..90df083f 100644 --- a/src/lib/arch/CArchMiscWindows.cpp +++ b/src/lib/arch/CArchMiscWindows.cpp @@ -50,6 +50,12 @@ HICON CArchMiscWindows::s_largeIcon = NULL; HICON CArchMiscWindows::s_smallIcon = NULL; HINSTANCE CArchMiscWindows::s_instanceWin32 = NULL; +void +CArchMiscWindows::cleanup() +{ + delete s_dialogs; +} + void CArchMiscWindows::init() { diff --git a/src/lib/arch/CArchMiscWindows.h b/src/lib/arch/CArchMiscWindows.h index 3abad463..6348218e 100644 --- a/src/lib/arch/CArchMiscWindows.h +++ b/src/lib/arch/CArchMiscWindows.h @@ -48,6 +48,9 @@ public: //! Initialize static void init(); + //! Delete memory + static void cleanup(); + //! Test if windows 95, et al. /*! Returns true iff the platform is win95/98/me. diff --git a/src/lib/arch/CArchNetworkWinsock.cpp b/src/lib/arch/CArchNetworkWinsock.cpp index 55bfba6a..1204ae99 100644 --- a/src/lib/arch/CArchNetworkWinsock.cpp +++ b/src/lib/arch/CArchNetworkWinsock.cpp @@ -109,6 +109,11 @@ CArchNetworkWinsock::~CArchNetworkWinsock() s_networkModule = NULL; } ARCH->closeMutex(m_mutex); + + CEventList::iterator it; + for (it = m_unblockEvents.begin(); it != m_unblockEvents.end(); it++) { + delete *it; + } } void @@ -429,6 +434,7 @@ CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout) ARCH->closeThread(thread); if (unblockEvent == NULL) { unblockEvent = new WSAEVENT; + m_unblockEvents.push_back(unblockEvent); *unblockEvent = WSACreateEvent_winsock(); mt->setNetworkDataForCurrentThread(unblockEvent); } diff --git a/src/lib/arch/CArchNetworkWinsock.h b/src/lib/arch/CArchNetworkWinsock.h index c0c371b1..5bcd0a86 100644 --- a/src/lib/arch/CArchNetworkWinsock.h +++ b/src/lib/arch/CArchNetworkWinsock.h @@ -28,6 +28,7 @@ #include "IArchMultithread.h" #include #include +#include #define ARCH_NETWORK CArchNetworkWinsock @@ -98,7 +99,10 @@ private: void throwNameError(int); private: + typedef std::list CEventList; + CArchMutex m_mutex; + CEventList m_unblockEvents; }; #endif diff --git a/src/lib/base/CEvent.cpp b/src/lib/base/CEvent.cpp index b2e5cd86..a8a30f37 100644 --- a/src/lib/base/CEvent.cpp +++ b/src/lib/base/CEvent.cpp @@ -26,7 +26,8 @@ CEvent::CEvent() : m_type(kUnknown), m_target(NULL), m_data(NULL), - m_flags(0) + m_flags(0), + m_dataObject(nullptr) { // do nothing } @@ -35,7 +36,8 @@ CEvent::CEvent(Type type, void* target, void* data, Flags flags) : m_type(type), m_target(target), m_data(data), - m_flags(flags) + m_flags(flags), + m_dataObject(nullptr) { // do nothing } @@ -58,6 +60,12 @@ CEvent::getData() const return m_data; } +CEventData* +CEvent::getDataObject() const +{ + return m_dataObject; +} + CEvent::Flags CEvent::getFlags() const { @@ -77,7 +85,15 @@ CEvent::deleteData(const CEvent& event) default: if ((event.getFlags() & kDontFreeData) == 0) { free(event.getData()); + delete event.getDataObject(); } break; } } + +void +CEvent::setDataObject(CEventData* dataObject) +{ + assert(m_dataObject == nullptr); + m_dataObject = dataObject; +} diff --git a/src/lib/base/CEvent.h b/src/lib/base/CEvent.h index 37f322e4..aae80783 100644 --- a/src/lib/base/CEvent.h +++ b/src/lib/base/CEvent.h @@ -21,6 +21,12 @@ #include "BasicTypes.h" #include "stdmap.h" +class CEventData { +public: + CEventData() { } + virtual ~CEventData() { } +}; + //! Event /*! A \c CEvent holds an event type and a pointer to event data. @@ -45,13 +51,15 @@ public: CEvent(); - //! Create \c CEvent with data + //! Create \c CEvent with data (POD) /*! The \p type must have been registered using \c registerType(). The \p data must be POD (plain old data) allocated by malloc(), which means it cannot have a constructor, destructor or be - composed of any types that do. \p target is the intended - recipient of the event. \p flags is any combination of \c Flags. + composed of any types that do. For non-POD (normal C++ objects + use \c setDataObject(). + \p target is the intended recipient of the event. + \p flags is any combination of \c Flags. */ CEvent(Type type, void* target = NULL, void* data = NULL, Flags flags = kNone); @@ -64,6 +72,13 @@ public: Deletes event data for the given event (using free()). */ static void deleteData(const CEvent&); + + //! Set data (non-POD) + /*! + Set non-POD (non plain old data), where delete is called when the event + is deleted, and the destructor is called. + */ + void setDataObject(CEventData* dataObject); //@} //! @name accessors @@ -81,12 +96,20 @@ public: */ void* getTarget() const; - //! Get the event data + //! Get the event data (POD). /*! - Returns the event data. + Returns the event data (POD). */ void* getData() const; + //! Get the event data (non-POD) + /*! + Returns the event data (non-POD). The difference between this and + \c getData() is that when delete is called on this data, so non-POD + (non plain old data) dtor is called. + */ + CEventData* getDataObject() const; + //! Get event flags /*! Returns the event flags. @@ -100,6 +123,7 @@ private: void* m_target; void* m_data; Flags m_flags; + CEventData* m_dataObject; }; #endif diff --git a/src/lib/base/CLog.cpp b/src/lib/base/CLog.cpp index 1b670cc2..a402dbbd 100644 --- a/src/lib/base/CLog.cpp +++ b/src/lib/base/CLog.cpp @@ -8,11 +8,11 @@ * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * along with this program. If not, see . */ #include "CLog.h" @@ -28,79 +28,81 @@ #include // names of priorities -static const char* g_priority[] = { - "FATAL", - "ERROR", - "WARNING", - "NOTE", - "INFO", +static const char* g_priority[] = { + "FATAL", + "ERROR", + "WARNING", + "NOTE", + "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4", "DEBUG5" - }; + }; // number of priorities static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0])); // the default priority #if defined(_DEBUG) || defined(DEBUG) -static const int g_defaultMaxPriority = kDEBUG; +static const int g_defaultMaxPriority = kDEBUG; #else -static const int g_defaultMaxPriority = kINFO; +static const int g_defaultMaxPriority = kINFO; #endif // length of longest string in g_priority -static const int g_maxPriorityLength = 7; +static const int g_maxPriorityLength = 7; // length of suffix string (": ") -static const int g_prioritySuffixLength = 2; +static const int g_prioritySuffixLength = 2; // amount of padded required to fill in the priority prefix -static const int g_priorityPad = g_maxPriorityLength + - g_prioritySuffixLength; +static const int g_priorityPad = g_maxPriorityLength + + g_prioritySuffixLength; // // CLog // -CLog* CLog::s_log = NULL; +CLog* CLog::s_log = NULL; CLog::CLog() { - // create mutex for multithread safe operation - m_mutex = ARCH->newMutex(); + assert(s_log == NULL); - // other initalization - m_maxPriority = g_defaultMaxPriority; - m_maxNewlineLength = 0; - insert(new CConsoleLogOutputter); + // create mutex for multithread safe operation + m_mutex = ARCH->newMutex(); + + // other initalization + m_maxPriority = g_defaultMaxPriority; + m_maxNewlineLength = 0; + insert(new CConsoleLogOutputter); + + s_log = this; } CLog::~CLog() { - // clean up - for (COutputterList::iterator index = m_outputters.begin(); - index != m_outputters.end(); ++index) { - delete *index; - } - for (COutputterList::iterator index = m_alwaysOutputters.begin(); - index != m_alwaysOutputters.end(); ++index) { - delete *index; - } - ARCH->closeMutex(m_mutex); + // clean up + for (COutputterList::iterator index = m_outputters.begin(); + index != m_outputters.end(); ++index) { + delete *index; + } + for (COutputterList::iterator index = m_alwaysOutputters.begin(); + index != m_alwaysOutputters.end(); ++index) { + delete *index; + } + ARCH->closeMutex(m_mutex); } CLog* CLog::getInstance() { - if (s_log == NULL) - s_log = new CLog(); - - return s_log; + assert(s_log != NULL); + return s_log; } const char* @@ -118,180 +120,180 @@ CLog::getFilterName(int level) const void CLog::print(const char* file, int line, const char* fmt, ...) { - // check if fmt begins with a priority argument - ELevel priority = kINFO; - if ((strlen(fmt) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) { + // check if fmt begins with a priority argument + ELevel priority = kINFO; + if ((strlen(fmt) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) { - // 060 in octal is 0 (48 in decimal), so subtracting this converts ascii - // number it a true number. we could use atoi instead, but this is how - // it was done originally. - priority = (ELevel)(fmt[2] - '\060'); + // 060 in octal is 0 (48 in decimal), so subtracting this converts ascii + // number it a true number. we could use atoi instead, but this is how + // it was done originally. + priority = (ELevel)(fmt[2] - '\060'); - // move the pointer on past the debug priority char - fmt += 3; - } + // move the pointer on past the debug priority char + fmt += 3; + } - // done if below priority threshold - if (priority > getFilter()) { - return; - } + // done if below priority threshold + if (priority > getFilter()) { + return; + } - // compute prefix padding length - char stack[1024]; + // compute prefix padding length + char stack[1024]; - // compute suffix padding length - int sPad = m_maxNewlineLength; + // compute suffix padding length + int sPad = m_maxNewlineLength; - // print to buffer, leaving space for a newline at the end and prefix - // at the beginning. - char* buffer = stack; - int len = (int)(sizeof(stack) / sizeof(stack[0])); - while (true) { - // try printing into the buffer - va_list args; - va_start(args, fmt); - int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args); - va_end(args); + // print to buffer, leaving space for a newline at the end and prefix + // at the beginning. + char* buffer = stack; + int len = (int)(sizeof(stack) / sizeof(stack[0])); + while (true) { + // try printing into the buffer + va_list args; + va_start(args, fmt); + int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args); + va_end(args); - // if the buffer wasn't big enough then make it bigger and try again - if (n < 0 || n > (int)len) { - if (buffer != stack) { - delete[] buffer; - } - len *= 2; - buffer = new char[len]; - } + // if the buffer wasn't big enough then make it bigger and try again + if (n < 0 || n > (int)len) { + if (buffer != stack) { + delete[] buffer; + } + len *= 2; + buffer = new char[len]; + } - // if the buffer was big enough then continue - else { - break; - } - } + // if the buffer was big enough then continue + else { + break; + } + } - // print the prefix to the buffer. leave space for priority label. - // do not prefix time and file for kPRINT (CLOG_PRINT) - if (priority != kPRINT) { + // print the prefix to the buffer. leave space for priority label. + // do not prefix time and file for kPRINT (CLOG_PRINT) + if (priority != kPRINT) { - char message[2048]; + char message[2048]; #if defined(_DEBUG) || defined(DEBUG) - struct tm *tm; - char tmp[220]; - time_t t; - time(&t); - tm = localtime(&t); - sprintf(tmp, "%04i-%02i-%02iT%02i:%02i:%02i", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - sprintf(message, "%s %s: %s\n\t%s,%d", tmp, g_priority[priority], buffer, file, line); + struct tm *tm; + char tmp[220]; + time_t t; + time(&t); + tm = localtime(&t); + sprintf(tmp, "%04i-%02i-%02iT%02i:%02i:%02i", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + sprintf(message, "%s %s: %s\n\t%s,%d", tmp, g_priority[priority], buffer, file, line); #else - sprintf(message, "%s: %s", g_priority[priority], buffer); + sprintf(message, "%s: %s", g_priority[priority], buffer); #endif - output(priority, message); - } else { - output(priority, buffer); - } + output(priority, message); + } else { + output(priority, buffer); + } - // clean up - if (buffer != stack) { - delete[] buffer; - } + // clean up + if (buffer != stack) { + delete[] buffer; + } } void CLog::insert(ILogOutputter* outputter, bool alwaysAtHead) { - assert(outputter != NULL); + assert(outputter != NULL); - CArchMutexLock lock(m_mutex); - if (alwaysAtHead) { - m_alwaysOutputters.push_front(outputter); - } - else { - m_outputters.push_front(outputter); - } + CArchMutexLock lock(m_mutex); + if (alwaysAtHead) { + m_alwaysOutputters.push_front(outputter); + } + else { + m_outputters.push_front(outputter); + } - outputter->open(kAppVersion); + outputter->open(kAppVersion); - // Issue 41 - // don't show log unless user requests it, as some users find this - // feature irritating (i.e. when they lose network connectivity). - // in windows the log window can be displayed by selecting "show log" - // from the synergy system tray icon. - // if this causes problems for other architectures, then a different - // work around should be attempted. - //outputter->show(false); + // Issue 41 + // don't show log unless user requests it, as some users find this + // feature irritating (i.e. when they lose network connectivity). + // in windows the log window can be displayed by selecting "show log" + // from the synergy system tray icon. + // if this causes problems for other architectures, then a different + // work around should be attempted. + //outputter->show(false); } void CLog::remove(ILogOutputter* outputter) { - CArchMutexLock lock(m_mutex); - m_outputters.remove(outputter); - m_alwaysOutputters.remove(outputter); + CArchMutexLock lock(m_mutex); + m_outputters.remove(outputter); + m_alwaysOutputters.remove(outputter); } void CLog::pop_front(bool alwaysAtHead) { - CArchMutexLock lock(m_mutex); - COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; - if (!list->empty()) { - delete list->front(); - list->pop_front(); - } + CArchMutexLock lock(m_mutex); + COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; + if (!list->empty()) { + delete list->front(); + list->pop_front(); + } } bool CLog::setFilter(const char* maxPriority) { - if (maxPriority != NULL) { - for (int i = 0; i < g_numPriority; ++i) { - if (strcmp(maxPriority, g_priority[i]) == 0) { - setFilter(i); - return true; - } - } - return false; - } - return true; + if (maxPriority != NULL) { + for (int i = 0; i < g_numPriority; ++i) { + if (strcmp(maxPriority, g_priority[i]) == 0) { + setFilter(i); + return true; + } + } + return false; + } + return true; } void CLog::setFilter(int maxPriority) { - CArchMutexLock lock(m_mutex); - m_maxPriority = maxPriority; + CArchMutexLock lock(m_mutex); + m_maxPriority = maxPriority; } int CLog::getFilter() const { - CArchMutexLock lock(m_mutex); - return m_maxPriority; + CArchMutexLock lock(m_mutex); + return m_maxPriority; } void CLog::output(ELevel priority, char* msg) { - assert(priority >= -1 && priority < g_numPriority); - assert(msg != NULL); - if (!msg) return; + assert(priority >= -1 && priority < g_numPriority); + assert(msg != NULL); + if (!msg) return; - CArchMutexLock lock(m_mutex); + CArchMutexLock lock(m_mutex); - COutputterList::const_iterator i; + COutputterList::const_iterator i; - for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) { + for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) { - // write to outputter - (*i)->write(priority, msg); - } + // write to outputter + (*i)->write(priority, msg); + } - for (i = m_outputters.begin(); i != m_outputters.end(); ++i) { + for (i = m_outputters.begin(); i != m_outputters.end(); ++i) { - // write to outputter and break out of loop if it returns false - if (!(*i)->write(priority, msg)) { - break; - } - } + // write to outputter and break out of loop if it returns false + if (!(*i)->write(priority, msg)) { + break; + } + } } diff --git a/src/lib/base/CLog.h b/src/lib/base/CLog.h index 54dfbd99..6e83aeb0 100644 --- a/src/lib/base/CLog.h +++ b/src/lib/base/CLog.h @@ -38,6 +38,7 @@ LOGC() provide convenient access. */ class CLog { public: + CLog(); ~CLog(); //! @name manipulators @@ -86,6 +87,8 @@ public: then it simply returns true. */ bool setFilter(const char* name); + + //! Set the minimum priority filter (by ordinal). void setFilter(int); //@} @@ -119,7 +122,6 @@ public: //@} private: - CLog(); void output(ELevel priority, char* msg); private: diff --git a/src/lib/base/CSimpleEventQueueBuffer.cpp b/src/lib/base/CSimpleEventQueueBuffer.cpp index a8ca65d2..6fbce095 100644 --- a/src/lib/base/CSimpleEventQueueBuffer.cpp +++ b/src/lib/base/CSimpleEventQueueBuffer.cpp @@ -19,8 +19,6 @@ #include "CStopwatch.h" #include "CArch.h" -class CEventQueueTimer { }; - // // CSimpleEventQueueBuffer // diff --git a/src/lib/base/CSimpleEventQueueBuffer.h b/src/lib/base/CSimpleEventQueueBuffer.h index 673f136b..0987a206 100644 --- a/src/lib/base/CSimpleEventQueueBuffer.h +++ b/src/lib/base/CSimpleEventQueueBuffer.h @@ -49,4 +49,11 @@ private: CEventDeque m_queue; }; +class CEventQueueTimer +{ +public: + CEventQueueTimer() { } + virtual ~CEventQueueTimer() { } +}; + #endif diff --git a/src/lib/ipc/CIpcClient.cpp b/src/lib/ipc/CIpcClient.cpp index 9cbf5fd2..4d494068 100644 --- a/src/lib/ipc/CIpcClient.cpp +++ b/src/lib/ipc/CIpcClient.cpp @@ -22,6 +22,7 @@ #include "CIpcMessage.h" CEvent::Type CIpcClient::s_connectedEvent = CEvent::kUnknown; +CEvent::Type CIpcClient::s_messageReceivedEvent = CEvent::kUnknown; CIpcClient::CIpcClient() : m_serverAddress(CNetworkAddress(IPC_HOST, IPC_PORT)), @@ -37,6 +38,8 @@ m_server(nullptr) CIpcClient::~CIpcClient() { + EVENTQUEUE->removeHandler(m_socket.getConnectedEvent(), m_socket.getEventTarget()); + EVENTQUEUE->removeHandler(CIpcServerProxy::getMessageReceivedEvent(), m_server); delete m_server; } @@ -45,12 +48,25 @@ CIpcClient::connect() { m_socket.connect(m_serverAddress); m_server = new CIpcServerProxy(m_socket); + + EVENTQUEUE->adoptHandler( + CIpcServerProxy::getMessageReceivedEvent(), m_server, + new TMethodEventJob( + this, &CIpcClient::handleMessageReceived)); +} + +void +CIpcClient::disconnect() +{ + m_server->disconnect(); + delete m_server; + m_server = nullptr; } void CIpcClient::send(const CIpcMessage& message) { - assert(m_server != NULL); + assert(m_server != nullptr); m_server->send(message); } @@ -61,13 +77,27 @@ CIpcClient::getConnectedEvent() s_connectedEvent, "CIpcClient::connected"); } +CEvent::Type +CIpcClient::getMessageReceivedEvent() +{ + return EVENTQUEUE->registerTypeOnce( + s_messageReceivedEvent, "CIpcClient::messageReceived"); +} + void CIpcClient::handleConnected(const CEvent&, void*) { - EVENTQUEUE->addEvent(CEvent(getConnectedEvent(), this, m_server, CEvent::kDontFreeData)); + EVENTQUEUE->addEvent(CEvent( + getConnectedEvent(), this, m_server, CEvent::kDontFreeData)); - CIpcMessage message; - message.m_type = kIpcHello; - message.m_data = new UInt8(kIpcClientNode); + CIpcHelloMessage message(kIpcClientNode); send(message); } + +void +CIpcClient::handleMessageReceived(const CEvent& e, void*) +{ + CEvent event(getMessageReceivedEvent(), this); + event.setDataObject(e.getDataObject()); + EVENTQUEUE->addEvent(event); +} diff --git a/src/lib/ipc/CIpcClient.h b/src/lib/ipc/CIpcClient.h index 91e94a8e..ae7d8c27 100644 --- a/src/lib/ipc/CIpcClient.h +++ b/src/lib/ipc/CIpcClient.h @@ -37,6 +37,9 @@ public: //! Connects to the IPC server at localhost. void connect(); + + //! Disconnects from the IPC server. + void disconnect(); //! Sends a message to the server. void send(const CIpcMessage& message); @@ -47,16 +50,19 @@ public: //! Raised when the socket is connected. static CEvent::Type getConnectedEvent(); + static CEvent::Type getMessageReceivedEvent(); //@} private: void handleConnected(const CEvent&, void*); + void handleMessageReceived(const CEvent&, void*); private: CNetworkAddress m_serverAddress; CTCPSocket m_socket; CIpcServerProxy* m_server; - + static CEvent::Type s_connectedEvent; + static CEvent::Type s_messageReceivedEvent; }; diff --git a/src/lib/ipc/CIpcClientProxy.cpp b/src/lib/ipc/CIpcClientProxy.cpp index d958144b..e22e833c 100644 --- a/src/lib/ipc/CIpcClientProxy.cpp +++ b/src/lib/ipc/CIpcClientProxy.cpp @@ -98,37 +98,37 @@ CIpcClientProxy::handleData(const CEvent&, void*) // don't allow the dtor to destroy the stream while we're using it. CArchMutexLock lock(m_readMutex); + + UInt8 codeBuf[1]; + UInt32 n = m_stream.read(codeBuf, 1); + int code = codeBuf[0]; - UInt8 code[1]; - UInt32 n = m_stream.read(code, 1); while (n != 0) { - UInt8 type = code[0]; - CIpcMessage* m = new CIpcMessage(); - m->m_type = type; - m->m_source = this; - - LOG((CLOG_DEBUG "ipc client proxy read: %d", code[0])); - - switch (type) { + LOG((CLOG_DEBUG "ipc client proxy read: %d", code)); + + CIpcMessage* m = nullptr; + switch (code) { case kIpcHello: - parseHello(); + m = parseHello(); break; case kIpcCommand: - m->m_data = parseCommand(); + m = parseCommand(); break; default: - delete m; disconnect(); return; } - - // event deletes data. - EVENTQUEUE->addEvent(CEvent(getMessageReceivedEvent(), this, m)); - - n = m_stream.read(code, 1); + + // don't delete with this event; the data is passed to a new event. + CEvent e(getMessageReceivedEvent(), this, NULL, CEvent::kDontFreeData); + e.setDataObject(m); + EVENTQUEUE->addEvent(e); + + n = m_stream.read(codeBuf, 1); + code = codeBuf[0]; } LOG((CLOG_DEBUG "finished ipc client proxy handle data")); @@ -142,20 +142,19 @@ CIpcClientProxy::send(const CIpcMessage& message) // also, don't allow the dtor to destroy the stream while we're using it. CArchMutexLock lock(m_writeMutex); - LOG((CLOG_DEBUG "ipc client proxy write: %d", message.m_type)); + LOG((CLOG_DEBUG "ipc client proxy write: %d", message.type())); + + CProtocolUtil::writef(&m_stream, "%1i", message.type()); - UInt8 code[1]; - code[0] = message.m_type; - m_stream.write(code, 1); - - switch (message.m_type) { + switch (message.type()) { case kIpcLogLine: { - CString* s = (CString*)message.m_data; - const char* data = s->c_str(); + const CIpcLogLineMessage& llm = static_cast(message); + CString logLine = llm.logLine(); + const char* data = logLine.c_str(); int len = strlen(data); - CProtocolUtil::writef(&m_stream, "%4i", len); + CProtocolUtil::writef(&m_stream, "%4i", len); m_stream.write(data, len); break; } @@ -165,30 +164,35 @@ CIpcClientProxy::send(const CIpcMessage& message) break; default: - LOG((CLOG_ERR "message not supported: %d", message.m_type)); + LOG((CLOG_ERR "message not supported: %d", message.type())); break; } } -void +CIpcHelloMessage* CIpcClientProxy::parseHello() { UInt8 buffer[1]; m_stream.read(buffer, 1); m_clientType = static_cast(buffer[0]); + + // must be deleted by event handler. + return new CIpcHelloMessage(m_clientType); } -void* +CIpcCommandMessage* CIpcClientProxy::parseCommand() { int len = 0; CProtocolUtil::readf(&m_stream, "%2i", &len); - UInt8* buffer = new UInt8[len]; + char* buffer = new char[len]; m_stream.read(buffer, len); + CString s(buffer, len); + delete buffer; - // delete by event cleanup. - return new CString((const char*)buffer, len); + // must be deleted by event handler. + return new CIpcCommandMessage(s); } void diff --git a/src/lib/ipc/CIpcClientProxy.h b/src/lib/ipc/CIpcClientProxy.h index 1f67baa0..b15a05aa 100644 --- a/src/lib/ipc/CIpcClientProxy.h +++ b/src/lib/ipc/CIpcClientProxy.h @@ -23,12 +23,17 @@ namespace synergy { class IStream; } class CIpcMessage; +class CIpcCommandMessage; +class CIpcHelloMessage; class CIpcClientProxy { + friend class CIpcServer; + public: CIpcClientProxy(synergy::IStream& stream); virtual ~CIpcClientProxy(); +private: //! Send a message to the client. void send(const CIpcMessage& message); @@ -38,20 +43,17 @@ public: //! Raised when the client disconnects from the server. static CEvent::Type getDisconnectedEvent(); -private: void handleData(const CEvent&, void*); void handleDisconnect(const CEvent&, void*); void handleWriteError(const CEvent&, void*); - void parseHello(); - void* parseCommand(); + CIpcHelloMessage* parseHello(); + CIpcCommandMessage* parseCommand(); void disconnect(); - -public: + +private: synergy::IStream& m_stream; EIpcClientType m_clientType; bool m_disconnecting; - -private: CArchMutex m_readMutex; CArchMutex m_writeMutex; diff --git a/src/lib/ipc/CIpcLogOutputter.cpp b/src/lib/ipc/CIpcLogOutputter.cpp index cfffd939..e958772b 100644 --- a/src/lib/ipc/CIpcLogOutputter.cpp +++ b/src/lib/ipc/CIpcLogOutputter.cpp @@ -109,12 +109,21 @@ CIpcLogOutputter::bufferThread(void*) { try { while (m_running) { + if (m_ipcServer.hasClients(kIpcClientGui)) { - while (!m_buffer.empty()) { + + // buffer is sent in chunks, so keep sending until it's + // empty (or the program has stopped in the meantime). + while (m_running && !m_buffer.empty()) { sendBuffer(); } } + // program may be stopping while we were in the send loop. + if (!m_running) { + break; + } + m_bufferWaiting = true; ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1); m_bufferWaiting = false; @@ -138,7 +147,7 @@ CIpcLogOutputter::notifyBuffer() } CString -CIpcLogOutputter::emptyBuffer(size_t count) +CIpcLogOutputter::getChunk(size_t count) { CArchMutexLock lock(m_bufferMutex); @@ -155,13 +164,10 @@ CIpcLogOutputter::emptyBuffer(size_t count) return chunk; } - void CIpcLogOutputter::sendBuffer() { - CIpcMessage message; - message.m_type = kIpcLogLine; - message.m_data = new CString(emptyBuffer(MAX_SEND)); + CIpcLogLineMessage message(getChunk(MAX_SEND)); m_sending = true; m_ipcServer.send(message, kIpcClientGui); diff --git a/src/lib/ipc/CIpcLogOutputter.h b/src/lib/ipc/CIpcLogOutputter.h index 273ab582..4db8c281 100644 --- a/src/lib/ipc/CIpcLogOutputter.h +++ b/src/lib/ipc/CIpcLogOutputter.h @@ -48,7 +48,7 @@ public: private: void bufferThread(void*); - CString emptyBuffer(size_t count); + CString getChunk(size_t count); void sendBuffer(); void appendBuffer(const CString& text); diff --git a/src/lib/ipc/CIpcMessage.cpp b/src/lib/ipc/CIpcMessage.cpp index d1cdc50f..03f58f74 100644 --- a/src/lib/ipc/CIpcMessage.cpp +++ b/src/lib/ipc/CIpcMessage.cpp @@ -16,17 +16,52 @@ */ #include "CIpcMessage.h" +#include "Ipc.h" -CIpcMessage::CIpcMessage() : -m_type(0), -m_data(nullptr), -m_source(nullptr) +CIpcMessage::CIpcMessage(UInt8 type) : +m_type(type) { } CIpcMessage::~CIpcMessage() { - if (m_data != nullptr) { - delete m_data; - } +} + +CIpcHelloMessage::CIpcHelloMessage(EIpcClientType clientType) : +CIpcMessage(kIpcHello), +m_clientType(clientType) +{ +} + +CIpcHelloMessage::~CIpcHelloMessage() +{ +} + +CIpcShutdownMessage::CIpcShutdownMessage() : +CIpcMessage(kIpcShutdown) +{ +} + +CIpcShutdownMessage::~CIpcShutdownMessage() +{ +} + +CIpcLogLineMessage::CIpcLogLineMessage(const CString& logLine) : +CIpcMessage(kIpcLogLine), +m_logLine(logLine) +{ +} + +CIpcLogLineMessage::~CIpcLogLineMessage() +{ +} + +CIpcCommandMessage::CIpcCommandMessage(const CString& command) : +CIpcMessage(kIpcCommand), +m_command(command) +{ +} + +CIpcCommandMessage::~CIpcCommandMessage() +{ } diff --git a/src/lib/ipc/CIpcMessage.h b/src/lib/ipc/CIpcMessage.h index bcdea76a..23acb4f4 100644 --- a/src/lib/ipc/CIpcMessage.h +++ b/src/lib/ipc/CIpcMessage.h @@ -18,13 +18,63 @@ #pragma once #include "BasicTypes.h" +#include "CString.h" +#include "Ipc.h" +#include "CEvent.h" -class CIpcMessage { +class CIpcMessage : public CEventData { public: - CIpcMessage(); virtual ~CIpcMessage(); + //! Gets the message type ID. + UInt8 type() const { return m_type; } + +protected: + CIpcMessage(UInt8 type); + +private: UInt8 m_type; - void* m_data; - void* m_source; +}; + +class CIpcHelloMessage : public CIpcMessage { +public: + CIpcHelloMessage(EIpcClientType clientType); + virtual ~CIpcHelloMessage(); + + //! Gets the message type ID. + EIpcClientType clientType() const { return m_clientType; } + +private: + EIpcClientType m_clientType; +}; + +class CIpcShutdownMessage : public CIpcMessage { +public: + CIpcShutdownMessage(); + virtual ~CIpcShutdownMessage(); +}; + + +class CIpcLogLineMessage : public CIpcMessage { +public: + CIpcLogLineMessage(const CString& logLine); + virtual ~CIpcLogLineMessage(); + + //! Gets the log line. + CString logLine() const { return m_logLine; } + +private: + CString m_logLine; +}; + +class CIpcCommandMessage : public CIpcMessage { +public: + CIpcCommandMessage(const CString& command); + virtual ~CIpcCommandMessage(); + + //! Gets the command. + CString command() const { return m_command; } + +private: + CString m_command; }; diff --git a/src/lib/ipc/CIpcServer.cpp b/src/lib/ipc/CIpcServer.cpp index 873f0cb9..a4bf805b 100644 --- a/src/lib/ipc/CIpcServer.cpp +++ b/src/lib/ipc/CIpcServer.cpp @@ -27,6 +27,7 @@ #include "CIpcMessage.h" CEvent::Type CIpcServer::s_clientConnectedEvent = CEvent::kUnknown; +CEvent::Type CIpcServer::s_messageReceivedEvent = CEvent::kUnknown; CIpcServer::CIpcServer() : m_address(CNetworkAddress(IPC_HOST, IPC_PORT)) @@ -45,12 +46,12 @@ CIpcServer::~CIpcServer() ARCH->lockMutex(m_clientsMutex); CClientList::iterator it; for (it = m_clients.begin(); it != m_clients.end(); it++) { - delete *it; + deleteClient(*it); } m_clients.empty(); ARCH->unlockMutex(m_clientsMutex); ARCH->closeMutex(m_clientsMutex); - + EVENTQUEUE->removeHandler(m_socket.getConnectingEvent(), &m_socket); } @@ -80,6 +81,11 @@ CIpcServer::handleClientConnecting(const CEvent&, void*) new TMethodEventJob( this, &CIpcServer::handleClientDisconnected)); + EVENTQUEUE->adoptHandler( + CIpcClientProxy::getMessageReceivedEvent(), proxy, + new TMethodEventJob( + this, &CIpcServer::handleMessageReceived)); + EVENTQUEUE->addEvent(CEvent( getClientConnectedEvent(), this, proxy, CEvent::kDontFreeData)); } @@ -89,15 +95,29 @@ CIpcServer::handleClientDisconnected(const CEvent& e, void*) { CIpcClientProxy* proxy = static_cast(e.getTarget()); - EVENTQUEUE->removeHandler( - CIpcClientProxy::getDisconnectedEvent(), proxy); - CArchMutexLock lock(m_clientsMutex); m_clients.remove(proxy); - delete proxy; + deleteClient(proxy); + LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size())); } +void +CIpcServer::handleMessageReceived(const CEvent& e, void*) +{ + CEvent event(getMessageReceivedEvent(), this); + event.setDataObject(e.getDataObject()); + EVENTQUEUE->addEvent(event); +} + +void +CIpcServer::deleteClient(CIpcClientProxy* proxy) +{ + EVENTQUEUE->removeHandler(CIpcClientProxy::getMessageReceivedEvent(), proxy); + EVENTQUEUE->removeHandler(CIpcClientProxy::getDisconnectedEvent(), proxy); + delete proxy; +} + bool CIpcServer::hasClients(EIpcClientType clientType) const { @@ -127,6 +147,13 @@ CIpcServer::getClientConnectedEvent() s_clientConnectedEvent, "CIpcServer::clientConnected"); } +CEvent::Type +CIpcServer::getMessageReceivedEvent() +{ + return EVENTQUEUE->registerTypeOnce( + s_messageReceivedEvent, "CIpcServer::messageReceived"); +} + void CIpcServer::send(const CIpcMessage& message, EIpcClientType filterType) { diff --git a/src/lib/ipc/CIpcServer.h b/src/lib/ipc/CIpcServer.h index 089fdad7..39a7e314 100644 --- a/src/lib/ipc/CIpcServer.h +++ b/src/lib/ipc/CIpcServer.h @@ -57,13 +57,17 @@ public: //! Raised when we have created the client proxy. static CEvent::Type getClientConnectedEvent(); + + //! Raised when a message is received through a client proxy. + static CEvent::Type getMessageReceivedEvent(); //@} private: void handleClientConnecting(const CEvent&, void*); void handleClientDisconnected(const CEvent&, void*); - void handleClientMessage(const CEvent&, void*); + void handleMessageReceived(const CEvent&, void*); + void deleteClient(CIpcClientProxy* proxy); private: typedef std::list CClientList; @@ -74,4 +78,5 @@ private: CArchMutex m_clientsMutex; static CEvent::Type s_clientConnectedEvent; + static CEvent::Type s_messageReceivedEvent; }; diff --git a/src/lib/ipc/CIpcServerProxy.cpp b/src/lib/ipc/CIpcServerProxy.cpp index cfcfa322..e6a34aa8 100644 --- a/src/lib/ipc/CIpcServerProxy.cpp +++ b/src/lib/ipc/CIpcServerProxy.cpp @@ -45,77 +45,88 @@ CIpcServerProxy::~CIpcServerProxy() void CIpcServerProxy::handleData(const CEvent&, void*) { - UInt8 code[1]; - UInt32 n = m_stream.read(code, 1); + LOG((CLOG_DEBUG "start ipc server proxy handle data")); + + UInt8 codeBuf[1]; + UInt32 n = m_stream.read(codeBuf, 1); + int code = codeBuf[0]; + while (n != 0) { - CIpcMessage* m = new CIpcMessage(); - m->m_type = code[0]; - - LOG((CLOG_DEBUG "ipc server proxy read: %d", m->m_type)); - switch (m->m_type) { + LOG((CLOG_DEBUG "ipc server proxy read: %d", code)); + + CIpcMessage* m = nullptr; + switch (code) { case kIpcLogLine: - m->m_data = parseLogLine(); + m = parseLogLine(); break; case kIpcShutdown: - // no data. + m = new CIpcShutdownMessage(); break; default: - delete m; disconnect(); return; } + + // don't delete with this event; the data is passed to a new event. + CEvent e(getMessageReceivedEvent(), this, NULL, CEvent::kDontFreeData); + e.setDataObject(m); + EVENTQUEUE->addEvent(e); - // event deletes data. - EVENTQUEUE->addEvent(CEvent(getMessageReceivedEvent(), this, m)); - - n = m_stream.read(code, 1); + n = m_stream.read(codeBuf, 1); + code = codeBuf[0]; } + + LOG((CLOG_DEBUG "finished ipc server proxy handle data")); } void CIpcServerProxy::send(const CIpcMessage& message) { - LOG((CLOG_DEBUG "ipc server proxy write: %d", message.m_type)); + LOG((CLOG_DEBUG "ipc server proxy write: %d", message.type())); - UInt8 code[1]; - code[0] = message.m_type; - m_stream.write(code, 1); + CProtocolUtil::writef(&m_stream, "%1i", message.type()); - switch (message.m_type) { - case kIpcHello: - m_stream.write(message.m_data, 1); + switch (message.type()) { + case kIpcHello: { + const CIpcHelloMessage& hm = static_cast(message); + CProtocolUtil::writef(&m_stream, "%1i", hm.clientType()); break; + } case kIpcCommand: { - CString* s = (CString*)message.m_data; - const char* data = s->c_str(); - + const CIpcCommandMessage& cm = static_cast(message); + + CString command = cm.command(); + const char* data = command.c_str(); int len = strlen(data); - CProtocolUtil::writef(&m_stream, "%2i", len); + CProtocolUtil::writef(&m_stream, "%2i", len); m_stream.write(data, len); break; } default: - LOG((CLOG_ERR "message not supported: %d", message.m_type)); + LOG((CLOG_ERR "message not supported: %d", message.type())); break; } } -void* +CIpcLogLineMessage* CIpcServerProxy::parseLogLine() { int len = 0; CProtocolUtil::readf(&m_stream, "%4i", &len); - UInt8* buffer = new UInt8[len]; + char* buffer = new char[len]; m_stream.read(buffer, len); - - return new CString((const char*)buffer, len); + CString s(buffer, len); + delete buffer; + + // must be deleted by event handler. + return new CIpcLogLineMessage(s); } void diff --git a/src/lib/ipc/CIpcServerProxy.h b/src/lib/ipc/CIpcServerProxy.h index a5e3147b..7ec78a8d 100644 --- a/src/lib/ipc/CIpcServerProxy.h +++ b/src/lib/ipc/CIpcServerProxy.h @@ -21,22 +21,25 @@ namespace synergy { class IStream; } class CIpcMessage; +class CIpcLogLineMessage; class CIpcServerProxy { + friend class CIpcClient; + public: CIpcServerProxy(synergy::IStream& stream); virtual ~CIpcServerProxy(); +private: void send(const CIpcMessage& message); + void handleData(const CEvent&, void*); + CIpcLogLineMessage* parseLogLine(); + void disconnect(); + //! Raised when the client receives a message from the server. static CEvent::Type getMessageReceivedEvent(); -private: - void handleData(const CEvent&, void*); - void* parseLogLine(); - void disconnect(); - private: synergy::IStream& m_stream; diff --git a/src/lib/platform/CMSWindowsClipboard.cpp b/src/lib/platform/CMSWindowsClipboard.cpp index 7ba83480..8fd41344 100644 --- a/src/lib/platform/CMSWindowsClipboard.cpp +++ b/src/lib/platform/CMSWindowsClipboard.cpp @@ -58,6 +58,14 @@ CMSWindowsClipboard::~CMSWindowsClipboard() delete m_facade; } +void +CMSWindowsClipboard::setFacade(IMSWindowsClipboardFacade& facade) +{ + delete m_facade; + m_facade = &facade; + m_deleteFacade = false; +} + bool CMSWindowsClipboard::emptyUnowned() { diff --git a/src/lib/platform/CMSWindowsClipboard.h b/src/lib/platform/CMSWindowsClipboard.h index f00d7647..1918599b 100644 --- a/src/lib/platform/CMSWindowsClipboard.h +++ b/src/lib/platform/CMSWindowsClipboard.h @@ -61,7 +61,7 @@ public: virtual bool has(EFormat) const; virtual CString get(EFormat) const; - void setFacade(IMSWindowsClipboardFacade& facade) { m_facade = &facade; m_deleteFacade = false; } + void setFacade(IMSWindowsClipboardFacade& facade); private: void clearConverters(); diff --git a/src/lib/platform/CMSWindowsDesks.cpp b/src/lib/platform/CMSWindowsDesks.cpp index ee94672c..18729ae0 100644 --- a/src/lib/platform/CMSWindowsDesks.cpp +++ b/src/lib/platform/CMSWindowsDesks.cpp @@ -186,7 +186,7 @@ CMSWindowsDesks::setOptions(const COptionsList& options) for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { if (options[i] == kOptionWin32KeepForeground) { m_leaveForegroundOption = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "Don\'t grab" : "Grab")); + LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "don\'t grab" : "grab")); } } } diff --git a/src/lib/platform/CMSWindowsRelauncher.cpp b/src/lib/platform/CMSWindowsRelauncher.cpp index ca61642a..a10b58ce 100644 --- a/src/lib/platform/CMSWindowsRelauncher.cpp +++ b/src/lib/platform/CMSWindowsRelauncher.cpp @@ -73,7 +73,12 @@ void CMSWindowsRelauncher::stop() { m_running = false; + m_thread->wait(5); + delete m_thread; + + m_outputThread->wait(5); + delete m_outputThread; } // this still gets the physical session (the one the keyboard and @@ -360,6 +365,8 @@ CMSWindowsRelauncher::mainLoop(void*) LOG((CLOG_DEBUG "terminated running process on exit")); shutdownProcess(pi, 10); } + + LOG((CLOG_DEBUG "relauncher main thread finished")); } void @@ -403,7 +410,7 @@ CMSWindowsRelauncher::outputLoop(void*) // +1 char for \0 CHAR buffer[kOutputBufferSize + 1]; - while (true) { + while (m_running) { DWORD bytesRead; BOOL success = ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL); @@ -432,8 +439,7 @@ CMSWindowsRelauncher::shutdownProcess(const PROCESS_INFORMATION& pi, int timeout if (exitCode != STILL_ACTIVE) return; - CIpcMessage shutdown; - shutdown.m_type = kIpcShutdown; + CIpcShutdownMessage shutdown; m_ipcServer.send(shutdown, kIpcClientNode); // wait for process to exit gracefully. diff --git a/src/lib/synergy/CApp.cpp b/src/lib/synergy/CApp.cpp index 0063089d..0d42f1b8 100644 --- a/src/lib/synergy/CApp.cpp +++ b/src/lib/synergy/CApp.cpp @@ -248,6 +248,11 @@ CApp::run(int argc, char** argv) CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif + CArch arch; + arch.init(); + + CLog log; + #if MAC_OS_X_VERSION_10_7 // dock hide only supported on lion :( ProcessSerialNumber psn = { 0, kCurrentProcess }; @@ -348,28 +353,27 @@ CApp::initApp(int argc, const char** argv) void CApp::initIpcClient() { - // TODO: delete ipc client on shutdown and the 2 event handlers. m_ipcClient = new CIpcClient(); m_ipcClient->connect(); EVENTQUEUE->adoptHandler( - CIpcClient::getConnectedEvent(), m_ipcClient, - new TMethodEventJob(this, &CApp::handleIpcConnected)); + CIpcClient::getMessageReceivedEvent(), m_ipcClient, + new TMethodEventJob(this, &CApp::handleIpcMessage)); } void -CApp::handleIpcConnected(const CEvent& e, void*) +CApp::cleanupIpcClient() { - EVENTQUEUE->adoptHandler( - CIpcServerProxy::getMessageReceivedEvent(), e.getData(), - new TMethodEventJob(this, &CApp::handleIpcMessage)); + m_ipcClient->disconnect(); + EVENTQUEUE->removeHandler(CIpcClient::getMessageReceivedEvent(), m_ipcClient); + delete m_ipcClient; } void CApp::handleIpcMessage(const CEvent& e, void*) { - CIpcMessage* m = static_cast(e.getData()); - if (m->m_type == kIpcShutdown) { + CIpcMessage* m = static_cast(e.getDataObject()); + if (m->type() == kIpcShutdown) { LOG((CLOG_INFO "got ipc shutdown message")); EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); } diff --git a/src/lib/synergy/CApp.h b/src/lib/synergy/CApp.h index ce229fa0..c3929248 100644 --- a/src/lib/synergy/CApp.h +++ b/src/lib/synergy/CApp.h @@ -94,13 +94,13 @@ public: virtual void bye(int error) { m_bye(error); } private: - void handleIpcConnected(const CEvent&, void*); void handleIpcMessage(const CEvent&, void*); protected: virtual void parseArgs(int argc, const char* const* argv, int &i); virtual bool parseArg(const int& argc, const char* const* argv, int& i); void initIpcClient(); + void cleanupIpcClient(); IArchTaskBarReceiver* m_taskBarReceiver; bool m_suspended; diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp index a3d56745..5d33a40e 100644 --- a/src/lib/synergy/CClientApp.cpp +++ b/src/lib/synergy/CClientApp.cpp @@ -552,6 +552,10 @@ CClientApp::mainLoop() updateStatus(); LOG((CLOG_NOTE "stopped client")); + if (argsBase().m_enableIpc) { + cleanupIpcClient(); + } + return kExitSuccess; } diff --git a/src/lib/synergy/CDaemonApp.cpp b/src/lib/synergy/CDaemonApp.cpp index 4fe2b317..9b1d0db9 100644 --- a/src/lib/synergy/CDaemonApp.cpp +++ b/src/lib/synergy/CDaemonApp.cpp @@ -43,6 +43,7 @@ #include "CIpcMessage.h" #include "CSocketMultiplexer.h" #include "CIpcLogOutputter.h" +#include "CLog.h" #define WIN32_LEAN_AND_MEAN #include @@ -91,23 +92,28 @@ CDaemonApp::~CDaemonApp() int CDaemonApp::run(int argc, char** argv) { +#if SYSAPI_WIN32 + // win32 instance needed for threading, etc. + CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#endif + + CArch arch; + arch.init(); + + CLog log; + bool uninstall = false; try { -#if SYSAPI_WIN32 - // win32 instance needed for threading, etc. - CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); -#endif - #if SYSAPI_WIN32 // sends debug messages to visual studio console window. - CLOG->insert(new CMSWindowsDebugOutputter()); + log.insert(new CMSWindowsDebugOutputter()); #endif // default log level to system setting. - string logLevel = ARCH->setting("LogLevel"); + string logLevel = arch.setting("LogLevel"); if (logLevel != "") - CLOG->setFilter(logLevel.c_str()); + log.setFilter(logLevel.c_str()); bool foreground = false; @@ -120,11 +126,11 @@ CDaemonApp::run(int argc, char** argv) #if SYSAPI_WIN32 else if (arg == "/install") { uninstall = true; - ARCH->installDaemon(); + arch.installDaemon(); return kExitSuccess; } else if (arg == "/uninstall") { - ARCH->uninstallDaemon(); + arch.uninstallDaemon(); return kExitSuccess; } #endif @@ -143,9 +149,9 @@ CDaemonApp::run(int argc, char** argv) } else { #if SYSAPI_WIN32 - ARCH->daemonize("Synergy", winMainLoopStatic); + arch.daemonize("Synergy", winMainLoopStatic); #elif SYSAPI_UNIX - ARCH->daemonize("Synergy", unixMainLoopStatic); + arch.daemonize("Synergy", unixMainLoopStatic); #endif } @@ -203,8 +209,8 @@ CDaemonApp::mainLoop(bool logToFile) #endif eventQueue.adoptHandler( - CIpcServer::getClientConnectedEvent(), m_ipcServer, - new TMethodEventJob(this, &CDaemonApp::handleIpcConnected)); + CIpcServer::getMessageReceivedEvent(), m_ipcServer, + new TMethodEventJob(this, &CDaemonApp::handleIpcMessage)); m_ipcServer->listen(); @@ -228,10 +234,11 @@ CDaemonApp::mainLoop(bool logToFile) #if SYSAPI_WIN32 m_relauncher->stop(); + delete m_relauncher; #endif eventQueue.removeHandler( - CIpcServer::getClientConnectedEvent(), m_ipcServer); + CIpcServer::getMessageReceivedEvent(), m_ipcServer); CLOG->remove(m_ipcLogOutputter); delete m_ipcLogOutputter; @@ -278,23 +285,14 @@ CDaemonApp::logPath() #endif } -void -CDaemonApp::handleIpcConnected(const CEvent& e, void*) -{ - LOG((CLOG_DEBUG "ipc client connected")); - EVENTQUEUE->adoptHandler( - CIpcClientProxy::getMessageReceivedEvent(), e.getData(), - new TMethodEventJob( - this, &CDaemonApp::handleIpcMessage)); -} - void CDaemonApp::handleIpcMessage(const CEvent& e, void*) { - CIpcMessage& m = *static_cast(e.getData()); - switch (m.m_type) { + CIpcMessage* m = static_cast(e.getDataObject()); + switch (m->type()) { case kIpcCommand: { - CString& command = *static_cast(m.m_data); + CIpcCommandMessage* cm = static_cast(m); + CString& command = cm->command(); LOG((CLOG_DEBUG "got new command: %s", command.c_str())); CString debugArg("--debug"); diff --git a/src/lib/synergy/CDaemonApp.h b/src/lib/synergy/CDaemonApp.h index 54dbd6a1..55561180 100644 --- a/src/lib/synergy/CDaemonApp.h +++ b/src/lib/synergy/CDaemonApp.h @@ -41,7 +41,6 @@ private: void daemonize(); void foregroundError(const char* message); std::string logPath(); - void handleIpcConnected(const CEvent&, void*); void handleIpcMessage(const CEvent&, void*); public: diff --git a/src/lib/synergy/CServerApp.cpp b/src/lib/synergy/CServerApp.cpp index b954a9b3..3a42a665 100644 --- a/src/lib/synergy/CServerApp.cpp +++ b/src/lib/synergy/CServerApp.cpp @@ -831,6 +831,10 @@ CServerApp::mainLoop() updateStatus(); LOG((CLOG_NOTE "stopped server")); + if (argsBase().m_enableIpc) { + cleanupIpcClient(); + } + return kExitSuccess; } diff --git a/src/test/integtests/CIpcTests.cpp b/src/test/integtests/CIpcTests.cpp index b3ee8c06..cf56e8e9 100644 --- a/src/test/integtests/CIpcTests.cpp +++ b/src/test/integtests/CIpcTests.cpp @@ -34,6 +34,7 @@ #include "CString.h" #include "CIpcServerProxy.h" #include "CIpcMessage.h" +#include "CSimpleEventQueueBuffer.h" class CIpcTests : public ::testing::Test { @@ -41,14 +42,15 @@ public: CIpcTests(); virtual ~CIpcTests(); - void connectToServer_handleClientConnected(const CEvent&, void*); + void connectToServer_handleMessageReceived(const CEvent&, void*); void sendMessageToServer_handleClientConnected(const CEvent&, void*); void sendMessageToServer_handleMessageReceived(const CEvent&, void*); - void sendMessageToClient_handleConnected(const CEvent&, void*); + void sendMessageToClient_handleClientConnected(const CEvent&, void*); void sendMessageToClient_handleMessageReceived(const CEvent&, void*); void handleQuitTimeout(const CEvent&, void* vclient); void raiseQuitEvent(); - void quitTimeout(double timeout); + void initQuitTimeout(double timeout); + void cleanupQuitTimeout(); private: void timeoutThread(void*); @@ -56,11 +58,13 @@ private: public: CSocketMultiplexer m_multiplexer; CEventQueue m_events; + CEventQueueTimer* m_quitTimeoutTimer; bool m_connectToServer_clientConnected; CString m_sendMessageToServer_receivedString; CString m_sendMessageToClient_receivedString; CIpcClient* m_sendMessageToServer_client; CIpcServer* m_sendMessageToClient_server; + }; TEST_F(CIpcTests, connectToServer) @@ -69,15 +73,17 @@ TEST_F(CIpcTests, connectToServer) server.listen(); m_events.adoptHandler( - CIpcServer::getClientConnectedEvent(), &server, + CIpcServer::getMessageReceivedEvent(), &server, new TMethodEventJob( - this, &CIpcTests::connectToServer_handleClientConnected)); + this, &CIpcTests::connectToServer_handleMessageReceived)); CIpcClient client; client.connect(); - quitTimeout(2); + initQuitTimeout(2); m_events.loop(); + m_events.removeHandler(CIpcServer::getMessageReceivedEvent(), &server); + cleanupQuitTimeout(); EXPECT_EQ(true, m_connectToServer_clientConnected); } @@ -86,19 +92,27 @@ TEST_F(CIpcTests, sendMessageToServer) { CIpcServer server; server.listen(); - - CIpcClient client; - client.connect(); - m_sendMessageToServer_client = &client; - // event handler sends "test" log line to client. + // event handler sends "test" command to server. m_events.adoptHandler( CIpcServer::getClientConnectedEvent(), &server, new TMethodEventJob( this, &CIpcTests::sendMessageToServer_handleClientConnected)); - quitTimeout(2); + m_events.adoptHandler( + CIpcServer::getMessageReceivedEvent(), &server, + new TMethodEventJob( + this, &CIpcTests::sendMessageToServer_handleMessageReceived)); + + CIpcClient client; + client.connect(); + m_sendMessageToServer_client = &client; + + initQuitTimeout(2); m_events.loop(); + m_events.removeHandler(CIpcServer::getClientConnectedEvent(), &server); + m_events.removeHandler(CIpcServer::getMessageReceivedEvent(), &server); + cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToServer_receivedString); } @@ -109,22 +123,31 @@ TEST_F(CIpcTests, sendMessageToClient) server.listen(); m_sendMessageToClient_server = &server; + // event handler sends "test" log line to client. + m_events.adoptHandler( + CIpcServer::getClientConnectedEvent(), &server, + new TMethodEventJob( + this, &CIpcTests::sendMessageToClient_handleClientConnected)); + CIpcClient client; client.connect(); - // event handler sends "test" log line to server. m_events.adoptHandler( - CIpcClient::getConnectedEvent(), &client, + CIpcClient::getMessageReceivedEvent(), &client, new TMethodEventJob( - this, &CIpcTests::sendMessageToClient_handleConnected)); + this, &CIpcTests::sendMessageToClient_handleMessageReceived)); - quitTimeout(2); + initQuitTimeout(2); m_events.loop(); + m_events.removeHandler(CIpcServer::getClientConnectedEvent(), &server); + m_events.removeHandler(CIpcClient::getMessageReceivedEvent(), &client); + cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToClient_receivedString); } CIpcTests::CIpcTests() : +m_quitTimeoutTimer(nullptr), m_connectToServer_clientConnected(false), m_sendMessageToClient_server(nullptr), m_sendMessageToServer_client(nullptr) @@ -136,56 +159,47 @@ CIpcTests::~CIpcTests() } void -CIpcTests::connectToServer_handleClientConnected(const CEvent&, void*) +CIpcTests::connectToServer_handleMessageReceived(const CEvent& e, void*) { - m_connectToServer_clientConnected = true; - raiseQuitEvent(); + CIpcMessage* m = static_cast(e.getDataObject()); + if (m->m_type == kIpcHello) { + m_connectToServer_clientConnected = true; + raiseQuitEvent(); + } } void CIpcTests::sendMessageToServer_handleClientConnected(const CEvent& e, void*) -{ - m_events.adoptHandler( - CIpcClientProxy::getMessageReceivedEvent(), e.getData(), - new TMethodEventJob( - this, &CIpcTests::sendMessageToServer_handleMessageReceived)); - - CIpcMessage m; - m.m_type = kIpcCommand; - m.m_data = new CString("test"); +{ + CIpcCommandMessage m("test"); m_sendMessageToServer_client->send(m); } void CIpcTests::sendMessageToServer_handleMessageReceived(const CEvent& e, void*) { - CIpcMessage* m = static_cast(e.getData()); + CIpcMessage* m = static_cast(e.getDataObject()); if (m->m_type == kIpcCommand) { - m_sendMessageToServer_receivedString = *static_cast(m->m_data); + CIpcCommandMessage* cm = static_cast(m); + m_sendMessageToServer_receivedString = cm->command(); raiseQuitEvent(); } } void -CIpcTests::sendMessageToClient_handleConnected(const CEvent& e, void*) -{ - m_events.adoptHandler( - CIpcServerProxy::getMessageReceivedEvent(), e.getData(), - new TMethodEventJob( - this, &CIpcTests::sendMessageToClient_handleMessageReceived)); - - CIpcMessage m; - m.m_type = kIpcLogLine; - m.m_data = new CString("test"); +CIpcTests::sendMessageToClient_handleClientConnected(const CEvent& e, void*) +{ + CIpcLogLineMessage m("test"); m_sendMessageToClient_server->send(m, kIpcClientUnknown); } void CIpcTests::sendMessageToClient_handleMessageReceived(const CEvent& e, void*) { - CIpcMessage* m = static_cast(e.getData()); + CIpcMessage* m = static_cast(e.getDataObject()); if (m->m_type == kIpcLogLine) { - m_sendMessageToClient_receivedString = *static_cast(m->m_data); + CIpcLogLineMessage* llm = static_cast(m); + m_sendMessageToClient_receivedString = llm->logLine(); raiseQuitEvent(); } } @@ -193,15 +207,25 @@ CIpcTests::sendMessageToClient_handleMessageReceived(const CEvent& e, void*) void CIpcTests::raiseQuitEvent() { - EVENTQUEUE->addEvent(CEvent(CEvent::kQuit, nullptr)); + EVENTQUEUE->addEvent(CEvent(CEvent::kQuit)); } void -CIpcTests::quitTimeout(double timeout) +CIpcTests::initQuitTimeout(double timeout) { - CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL); - EVENTQUEUE->adoptHandler(CEvent::kTimer, timer, - new TMethodEventJob(this, &CIpcTests::handleQuitTimeout, timer)); + assert(m_quitTimeoutTimer == nullptr); + m_quitTimeoutTimer = EVENTQUEUE->newOneShotTimer(timeout, NULL); + EVENTQUEUE->adoptHandler(CEvent::kTimer, m_quitTimeoutTimer, + new TMethodEventJob( + this, &CIpcTests::handleQuitTimeout)); +} + +void +CIpcTests::cleanupQuitTimeout() +{ + EVENTQUEUE->removeHandler(CEvent::kTimer, m_quitTimeoutTimer); + delete m_quitTimeoutTimer; + m_quitTimeoutTimer = nullptr; } void diff --git a/src/test/integtests/Main.cpp b/src/test/integtests/Main.cpp index 680ebd27..456bd01b 100644 --- a/src/test/integtests/Main.cpp +++ b/src/test/integtests/Main.cpp @@ -40,6 +40,11 @@ main(int argc, char **argv) CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif + CArch arch; + arch.init(); + + CLog log; + string lockFile; for (int i = 0; i < argc; i++) { if (string(argv[i]).compare("--lock-file") == 0) {