Moved all IPC functions into the MUtilities libraries.

This commit is contained in:
LoRd_MuldeR 2014-12-13 23:21:13 +01:00
parent 8b3e28a131
commit 563cc1c185
6 changed files with 406 additions and 2 deletions

View File

@ -24,6 +24,7 @@
<ClCompile Include="src\Global.cpp" />
<ClCompile Include="src\GUI.cpp" />
<ClCompile Include="src\GUI_Win32.cpp" />
<ClCompile Include="src\IPCChannel.cpp" />
<ClCompile Include="src\JobObject_Win32.cpp" />
<ClCompile Include="src\KeccakHash.cpp" />
<ClCompile Include="src\OSSupport_Win32.cpp" />
@ -39,6 +40,7 @@
<ClInclude Include="include\MUtils\Exception.h" />
<ClInclude Include="include\MUtils\Global.h" />
<ClInclude Include="include\MUtils\GUI.h" />
<ClInclude Include="include\MUtils\IPCChannel.h" />
<ClInclude Include="include\MUtils\JobObject.h" />
<ClInclude Include="include\MUtils\KeccakHash.h" />
<ClInclude Include="include\MUtils\OSSupport.h" />

View File

@ -78,6 +78,9 @@
<ClCompile Include="src\GUI_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\IPCChannel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\CriticalSection_Win32.h">
@ -131,6 +134,9 @@
<ClInclude Include="include\MUtils\JobObject.h">
<Filter>Public Headers</Filter>
</ClInclude>
<ClInclude Include="include\MUtils\IPCChannel.h">
<Filter>Public Headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="include\Mutils\UpdateChecker.h">

View File

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////
// MuldeR's Utilities for Qt
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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 GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// http://www.gnu.org/licenses/lgpl-2.1.txt
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <MUtils/Global.h>
namespace MUtils
{
typedef enum
{
IPC_RET_SUCCESS_MASTER = 0,
IPC_RET_SUCCESS_SLAVE = 1,
IPC_RET_ALREADY_INITIALIZED = 2,
IPC_RET_FAILURE = 3
}
ipc_result_t;
class MUTILS_API IPCChannel_Private;
class MUTILS_API IPCChannel
{
public:
IPCChannel(const QString &applicationId, const QString &channelId);
~IPCChannel(void);
int initialize(void);
bool send(const unsigned int &command, const char *const message);
bool read(unsigned int &command, char *const message, const size_t &buffSize);
private:
IPCChannel(const IPCChannel&) : p(NULL) {}
IPCChannel &operator=(const IPCChannel&) { return *this; }
IPCChannel_Private *const p;
const QString m_applicationId;
const QString m_channelId;
};
}

View File

@ -22,7 +22,6 @@
#pragma once
#include <MUtils/Global.h>
#include <QScopedPointer>
class QProcess;
@ -40,6 +39,6 @@ namespace MUtils
bool terminateJob(unsigned int exitCode);
private:
QScopedPointer<JobObject_Private> p;
JobObject_Private *const p;
};
}

337
src/IPCChannel.cpp Normal file
View File

@ -0,0 +1,337 @@
///////////////////////////////////////////////////////////////////////////////
// MuldeR's Utilities for Qt
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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 GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// http://www.gnu.org/licenses/lgpl-2.1.txt
//////////////////////////////////////////////////////////////////////////////////
//MUtils
#include <MUtils/IPCChannel.h>
#include <MUtils/Exception.h>
//Qt includes
#include <QRegExp>
#include <QSharedMemory>
#include <QSystemSemaphore>
#include <QWriteLocker>
///////////////////////////////////////////////////////////////////////////////
// TYPES
///////////////////////////////////////////////////////////////////////////////
namespace MUtils
{
static const size_t IPC_SLOTS = 128;
static const size_t MAX_MESSAGE_LEN = 4096;
typedef struct
{
unsigned int command;
unsigned int reserved_1;
unsigned int reserved_2;
char parameter[MAX_MESSAGE_LEN];
}
ipc_data_t;
typedef struct
{
unsigned int pos_wr;
unsigned int pos_rd;
ipc_data_t data[IPC_SLOTS];
}
ipc_t;
}
///////////////////////////////////////////////////////////////////////////////
// UTILITIES
///////////////////////////////////////////////////////////////////////////////
static inline QString ESCAPE(QString str)
{
return str.replace(QRegExp("[^A-Za-z0-9_]"), "_").toLower();
}
static QString MAKE_ID(const QString &applicationId, const QString &channelId, const QString &itemId)
{
return QString("ipc://mutilities.muldersoft.com:37402/%1/%2/%3").arg(ESCAPE(applicationId), ESCAPE(channelId), ESCAPE(itemId));
}
///////////////////////////////////////////////////////////////////////////////
// PRIVATE DATA
///////////////////////////////////////////////////////////////////////////////
namespace MUtils
{
class IPCChannel_Private
{
friend class IPCChannel;
protected:
volatile bool initialized;
QScopedPointer<QSharedMemory> sharedmem;
QScopedPointer<QSystemSemaphore> semaphore_rd;
QScopedPointer<QSystemSemaphore> semaphore_wr;
QReadWriteLock lock;
};
}
///////////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR & DESTRUCTOR
///////////////////////////////////////////////////////////////////////////////
MUtils::IPCChannel::IPCChannel(const QString &applicationId, const QString &channelId)
:
p(new IPCChannel_Private()),
m_applicationId(applicationId),
m_channelId(channelId)
{
p->initialized = false;
}
MUtils::IPCChannel::~IPCChannel(void)
{
if(p->initialized)
{
if(p->sharedmem->isAttached())
{
p->sharedmem->detach();
}
}
delete p;
}
///////////////////////////////////////////////////////////////////////////////
// INITIALIZATION
///////////////////////////////////////////////////////////////////////////////
int MUtils::IPCChannel::initialize(void)
{
QWriteLocker writeLock(&p->lock);
if(p->initialized)
{
return IPC_RET_ALREADY_INITIALIZED;
}
p->sharedmem.reset(new QSharedMemory(MAKE_ID(m_applicationId, m_channelId, "sharedmem"), NULL));
p->semaphore_rd.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_rd"), 0));
p->semaphore_wr.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_wr"), 0));
if(p->semaphore_rd->error() != QSystemSemaphore::NoError)
{
const QString errorMessage = p->semaphore_rd->errorString();
qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
if(p->semaphore_wr->error() != QSystemSemaphore::NoError)
{
const QString errorMessage = p->semaphore_wr->errorString();
qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
if(!p->sharedmem->create(sizeof(ipc_t)))
{
if(p->sharedmem->error() == QSharedMemory::AlreadyExists)
{
if(!p->sharedmem->attach())
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
if(p->sharedmem->error() != QSharedMemory::NoError)
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
p->initialized = true;
return IPC_RET_SUCCESS_SLAVE;
}
else
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
}
if(p->sharedmem->error() != QSharedMemory::NoError)
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
if(void *const data = p->sharedmem->data())
{
memset(data, 0, sizeof(ipc_t));
}
if(!p->semaphore_wr->release(IPC_SLOTS))
{
const QString errorMessage = p->semaphore_wr->errorString();
qWarning("Failed to release system semaphore: %s", MUTILS_UTF8(errorMessage));
return IPC_RET_FAILURE;
}
p->initialized = true;
return IPC_RET_SUCCESS_MASTER;
}
///////////////////////////////////////////////////////////////////////////////
// SEND MESSAGE
///////////////////////////////////////////////////////////////////////////////
bool MUtils::IPCChannel::send(const unsigned int &command, const char *const message)
{
bool success = false;
QReadLocker readLock(&p->lock);
if(!p->initialized)
{
MUTILS_THROW("Shared memory for IPC not initialized yet.");
}
ipc_data_t ipc_data;
memset(&ipc_data, 0, sizeof(ipc_data_t));
ipc_data.command = command;
if(message)
{
strncpy_s(ipc_data.parameter, MAX_MESSAGE_LEN, message, _TRUNCATE);
}
if(!p->semaphore_wr->acquire())
{
const QString errorMessage = p->semaphore_wr->errorString();
qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(!p->sharedmem->lock())
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(ipc_t *const ptr = reinterpret_cast<ipc_t*>(p->sharedmem->data()))
{
success = true;
memcpy(&ptr->data[ptr->pos_wr], &ipc_data, sizeof(ipc_data_t));
ptr->pos_wr = (ptr->pos_wr + 1) % IPC_SLOTS;
}
else
{
qWarning("Shared memory pointer is NULL -> unable to write data!");
}
if(!p->sharedmem->unlock())
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(!p->semaphore_rd->release())
{
const QString errorMessage = p->semaphore_rd->errorString();
qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
return false;
}
return success;
}
///////////////////////////////////////////////////////////////////////////////
// READ MESSAGE
///////////////////////////////////////////////////////////////////////////////
bool MUtils::IPCChannel::read(unsigned int &command, char *const message, const size_t &buffSize)
{
bool success = false;
QReadLocker readLock(&p->lock);
command = 0;
if(message && (buffSize > 0))
{
message[0] = '\0';
}
if(!p->initialized)
{
MUTILS_THROW("Shared memory for IPC not initialized yet.");
}
ipc_data_t ipc_data;
memset(&ipc_data, 0, sizeof(ipc_data_t));
if(!p->semaphore_rd->acquire())
{
const QString errorMessage = p->semaphore_rd->errorString();
qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(!p->sharedmem->lock())
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(ipc_t *const ptr = reinterpret_cast<ipc_t*>(p->sharedmem->data()))
{
success = true;
memcpy(&ipc_data, &ptr->data[ptr->pos_rd], sizeof(ipc_data_t));
ptr->pos_rd = (ptr->pos_rd + 1) % IPC_SLOTS;
if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
{
command = ipc_data.command;
strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
}
else
{
qWarning("Malformed IPC message, will be ignored");
}
}
else
{
qWarning("Shared memory pointer is NULL -> unable to write data!");
}
if(!p->sharedmem->unlock())
{
const QString errorMessage = p->sharedmem->errorString();
qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
return false;
}
if(!p->semaphore_wr->release())
{
const QString errorMessage = p->semaphore_wr->errorString();
qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
return false;
}
return success;
}

View File

@ -84,6 +84,8 @@ MUtils::JobObject::~JobObject(void)
CloseHandle(p->m_hJobObject);
p->m_hJobObject = NULL;
}
delete p;
}
bool MUtils::JobObject::addProcessToJob(const QProcess *proc)