* 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)
This commit is contained in:
Nick Bolton 2012-07-10 01:51:51 +00:00
parent 21cf3f2478
commit 8bad45e8a2
37 changed files with 697 additions and 396 deletions

View File

@ -41,6 +41,9 @@ void IpcReader::read()
QMutexLocker locker(&m_Mutex);
std::cout << "ready read" << std::endl;
while (m_Socket->bytesAvailable()) {
std::cout << "bytes available" << std::endl;
char codeBuf[1];
readStream(codeBuf, 1);
int code = bytesToInt(codeBuf, 1);
@ -66,6 +69,7 @@ void IpcReader::read()
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

View File

@ -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;
}

View File

@ -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;

View File

@ -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()
{

View File

@ -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.

View File

@ -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);
}

View File

@ -28,6 +28,7 @@
#include "IArchMultithread.h"
#include <windows.h>
#include <winsock2.h>
#include <list>
#define ARCH_NETWORK CArchNetworkWinsock
@ -98,7 +99,10 @@ private:
void throwNameError(int);
private:
typedef std::list<WSAEVENT> CEventList;
CArchMutex m_mutex;
CEventList m_unblockEvents;
};
#endif

View File

@ -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;
}

View File

@ -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);
@ -65,6 +73,13 @@ public:
*/
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

View File

@ -71,6 +71,8 @@ CLog* CLog::s_log = NULL;
CLog::CLog()
{
assert(s_log == NULL);
// create mutex for multithread safe operation
m_mutex = ARCH->newMutex();
@ -78,6 +80,8 @@ CLog::CLog()
m_maxPriority = g_defaultMaxPriority;
m_maxNewlineLength = 0;
insert(new CConsoleLogOutputter);
s_log = this;
}
CLog::~CLog()
@ -97,9 +101,7 @@ CLog::~CLog()
CLog*
CLog::getInstance()
{
if (s_log == NULL)
s_log = new CLog();
assert(s_log != NULL);
return s_log;
}

View File

@ -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:

View File

@ -19,8 +19,6 @@
#include "CStopwatch.h"
#include "CArch.h"
class CEventQueueTimer { };
//
// CSimpleEventQueueBuffer
//

View File

@ -49,4 +49,11 @@ private:
CEventDeque m_queue;
};
class CEventQueueTimer
{
public:
CEventQueueTimer() { }
virtual ~CEventQueueTimer() { }
};
#endif

View File

@ -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<CIpcClient>(
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);
}

View File

@ -38,6 +38,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,11 +50,13 @@ 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;
@ -59,4 +64,5 @@ private:
CIpcServerProxy* m_server;
static CEvent::Type s_connectedEvent;
static CEvent::Type s_messageReceivedEvent;
};

View File

@ -99,36 +99,36 @@ CIpcClientProxy::handleData(const CEvent&, void*)
// don't allow the dtor to destroy the stream while we're using it.
CArchMutexLock lock(m_readMutex);
UInt8 code[1];
UInt32 n = m_stream.read(code, 1);
UInt8 codeBuf[1];
UInt32 n = m_stream.read(codeBuf, 1);
int code = codeBuf[0];
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));
LOG((CLOG_DEBUG "ipc client proxy read: %d", code[0]));
switch (type) {
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));
// 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(code, 1);
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()));
UInt8 code[1];
code[0] = message.m_type;
m_stream.write(code, 1);
CProtocolUtil::writef(&m_stream, "%1i", message.type());
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<const CIpcLogLineMessage&>(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<EIpcClientType>(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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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()
{
}

View File

@ -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;
};

View File

@ -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,7 +46,7 @@ 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);
@ -80,6 +81,11 @@ CIpcServer::handleClientConnecting(const CEvent&, void*)
new TMethodEventJob<CIpcServer>(
this, &CIpcServer::handleClientDisconnected));
EVENTQUEUE->adoptHandler(
CIpcClientProxy::getMessageReceivedEvent(), proxy,
new TMethodEventJob<CIpcServer>(
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<CIpcClientProxy*>(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)
{

View File

@ -58,12 +58,16 @@ 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<CIpcClientProxy*> CClientList;
@ -74,4 +78,5 @@ private:
CArchMutex m_clientsMutex;
static CEvent::Type s_clientConnectedEvent;
static CEvent::Type s_messageReceivedEvent;
};

View File

@ -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", code));
LOG((CLOG_DEBUG "ipc server proxy read: %d", m->m_type));
switch (m->m_type) {
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;
}
// event deletes data.
EVENTQUEUE->addEvent(CEvent(getMessageReceivedEvent(), this, m));
// 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(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<const CIpcHelloMessage&>(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<const CIpcCommandMessage&>(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);
CString s(buffer, len);
delete buffer;
return new CString((const char*)buffer, len);
// must be deleted by event handler.
return new CIpcLogLineMessage(s);
}
void

View File

@ -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;

View File

@ -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()
{

View File

@ -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();

View File

@ -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"));
}
}
}

View File

@ -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.

View File

@ -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<CApp>(this, &CApp::handleIpcConnected));
CIpcClient::getMessageReceivedEvent(), m_ipcClient,
new TMethodEventJob<CApp>(this, &CApp::handleIpcMessage));
}
void
CApp::handleIpcConnected(const CEvent& e, void*)
CApp::cleanupIpcClient()
{
EVENTQUEUE->adoptHandler(
CIpcServerProxy::getMessageReceivedEvent(), e.getData(),
new TMethodEventJob<CApp>(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<CIpcMessage*>(e.getData());
if (m->m_type == kIpcShutdown) {
CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject());
if (m->type() == kIpcShutdown) {
LOG((CLOG_INFO "got ipc shutdown message"));
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}

View File

@ -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;

View File

@ -552,6 +552,10 @@ CClientApp::mainLoop()
updateStatus();
LOG((CLOG_NOTE "stopped client"));
if (argsBase().m_enableIpc) {
cleanupIpcClient();
}
return kExitSuccess;
}

View File

@ -43,6 +43,7 @@
#include "CIpcMessage.h"
#include "CSocketMultiplexer.h"
#include "CIpcLogOutputter.h"
#include "CLog.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -90,24 +91,29 @@ CDaemonApp::~CDaemonApp()
int
CDaemonApp::run(int argc, char** argv)
{
bool uninstall = false;
try
{
#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
// 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<CDaemonApp>(this, &CDaemonApp::handleIpcConnected));
CIpcServer::getMessageReceivedEvent(), m_ipcServer,
new TMethodEventJob<CDaemonApp>(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<CDaemonApp>(
this, &CDaemonApp::handleIpcMessage));
}
void
CDaemonApp::handleIpcMessage(const CEvent& e, void*)
{
CIpcMessage& m = *static_cast<CIpcMessage*>(e.getData());
switch (m.m_type) {
CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject());
switch (m->type()) {
case kIpcCommand: {
CString& command = *static_cast<CString*>(m.m_data);
CIpcCommandMessage* cm = static_cast<CIpcCommandMessage*>(m);
CString& command = cm->command();
LOG((CLOG_DEBUG "got new command: %s", command.c_str()));
CString debugArg("--debug");

View File

@ -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:

View File

@ -831,6 +831,10 @@ CServerApp::mainLoop()
updateStatus();
LOG((CLOG_NOTE "stopped server"));
if (argsBase().m_enableIpc) {
cleanupIpcClient();
}
return kExitSuccess;
}

View File

@ -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<CIpcTests>(
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);
}
@ -87,18 +93,26 @@ 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<CIpcTests>(
this, &CIpcTests::sendMessageToServer_handleClientConnected));
quitTimeout(2);
m_events.adoptHandler(
CIpcServer::getMessageReceivedEvent(), &server,
new TMethodEventJob<CIpcTests>(
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<CIpcTests>(
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<CIpcTests>(
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*)
{
CIpcMessage* m = static_cast<CIpcMessage*>(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<CIpcTests>(
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<CIpcMessage*>(e.getData());
CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject());
if (m->m_type == kIpcCommand) {
m_sendMessageToServer_receivedString = *static_cast<CString*>(m->m_data);
CIpcCommandMessage* cm = static_cast<CIpcCommandMessage*>(m);
m_sendMessageToServer_receivedString = cm->command();
raiseQuitEvent();
}
}
void
CIpcTests::sendMessageToClient_handleConnected(const CEvent& e, void*)
CIpcTests::sendMessageToClient_handleClientConnected(const CEvent& e, void*)
{
m_events.adoptHandler(
CIpcServerProxy::getMessageReceivedEvent(), e.getData(),
new TMethodEventJob<CIpcTests>(
this, &CIpcTests::sendMessageToClient_handleMessageReceived));
CIpcMessage m;
m.m_type = kIpcLogLine;
m.m_data = new CString("test");
CIpcLogLineMessage m("test");
m_sendMessageToClient_server->send(m, kIpcClientUnknown);
}
void
CIpcTests::sendMessageToClient_handleMessageReceived(const CEvent& e, void*)
{
CIpcMessage* m = static_cast<CIpcMessage*>(e.getData());
CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject());
if (m->m_type == kIpcLogLine) {
m_sendMessageToClient_receivedString = *static_cast<CString*>(m->m_data);
CIpcLogLineMessage* llm = static_cast<CIpcLogLineMessage*>(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<CIpcTests>(this, &CIpcTests::handleQuitTimeout, timer));
assert(m_quitTimeoutTimer == nullptr);
m_quitTimeoutTimer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, m_quitTimeoutTimer,
new TMethodEventJob<CIpcTests>(
this, &CIpcTests::handleQuitTimeout));
}
void
CIpcTests::cleanupQuitTimeout()
{
EVENTQUEUE->removeHandler(CEvent::kTimer, m_quitTimeoutTimer);
delete m_quitTimeoutTimer;
m_quitTimeoutTimer = nullptr;
}
void

View File

@ -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) {