Moved all IPC functions into the MUtilities libraries.
[MUtilities.git] / src / IPCChannel.cpp
blob9aab938a32d941ae0ce5248ddfe44c573cf75618
1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
22 //MUtils
23 #include <MUtils/IPCChannel.h>
24 #include <MUtils/Exception.h>
26 //Qt includes
27 #include <QRegExp>
28 #include <QSharedMemory>
29 #include <QSystemSemaphore>
30 #include <QWriteLocker>
32 ///////////////////////////////////////////////////////////////////////////////
33 // TYPES
34 ///////////////////////////////////////////////////////////////////////////////
36 namespace MUtils
38 static const size_t IPC_SLOTS = 128;
39 static const size_t MAX_MESSAGE_LEN = 4096;
41 typedef struct
43 unsigned int command;
44 unsigned int reserved_1;
45 unsigned int reserved_2;
46 char parameter[MAX_MESSAGE_LEN];
48 ipc_data_t;
50 typedef struct
52 unsigned int pos_wr;
53 unsigned int pos_rd;
54 ipc_data_t data[IPC_SLOTS];
56 ipc_t;
59 ///////////////////////////////////////////////////////////////////////////////
60 // UTILITIES
61 ///////////////////////////////////////////////////////////////////////////////
63 static inline QString ESCAPE(QString str)
65 return str.replace(QRegExp("[^A-Za-z0-9_]"), "_").toLower();
68 static QString MAKE_ID(const QString &applicationId, const QString &channelId, const QString &itemId)
70 return QString("ipc://mutilities.muldersoft.com:37402/%1/%2/%3").arg(ESCAPE(applicationId), ESCAPE(channelId), ESCAPE(itemId));
73 ///////////////////////////////////////////////////////////////////////////////
74 // PRIVATE DATA
75 ///////////////////////////////////////////////////////////////////////////////
77 namespace MUtils
79 class IPCChannel_Private
81 friend class IPCChannel;
83 protected:
84 volatile bool initialized;
85 QScopedPointer<QSharedMemory> sharedmem;
86 QScopedPointer<QSystemSemaphore> semaphore_rd;
87 QScopedPointer<QSystemSemaphore> semaphore_wr;
88 QReadWriteLock lock;
92 ///////////////////////////////////////////////////////////////////////////////
93 // CONSTRUCTOR & DESTRUCTOR
94 ///////////////////////////////////////////////////////////////////////////////
96 MUtils::IPCChannel::IPCChannel(const QString &applicationId, const QString &channelId)
98 p(new IPCChannel_Private()),
99 m_applicationId(applicationId),
100 m_channelId(channelId)
102 p->initialized = false;
105 MUtils::IPCChannel::~IPCChannel(void)
107 if(p->initialized)
109 if(p->sharedmem->isAttached())
111 p->sharedmem->detach();
115 delete p;
118 ///////////////////////////////////////////////////////////////////////////////
119 // INITIALIZATION
120 ///////////////////////////////////////////////////////////////////////////////
122 int MUtils::IPCChannel::initialize(void)
124 QWriteLocker writeLock(&p->lock);
126 if(p->initialized)
128 return IPC_RET_ALREADY_INITIALIZED;
131 p->sharedmem.reset(new QSharedMemory(MAKE_ID(m_applicationId, m_channelId, "sharedmem"), NULL));
132 p->semaphore_rd.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_rd"), 0));
133 p->semaphore_wr.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_wr"), 0));
135 if(p->semaphore_rd->error() != QSystemSemaphore::NoError)
137 const QString errorMessage = p->semaphore_rd->errorString();
138 qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
139 return IPC_RET_FAILURE;
142 if(p->semaphore_wr->error() != QSystemSemaphore::NoError)
144 const QString errorMessage = p->semaphore_wr->errorString();
145 qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
146 return IPC_RET_FAILURE;
149 if(!p->sharedmem->create(sizeof(ipc_t)))
151 if(p->sharedmem->error() == QSharedMemory::AlreadyExists)
153 if(!p->sharedmem->attach())
155 const QString errorMessage = p->sharedmem->errorString();
156 qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
157 return IPC_RET_FAILURE;
159 if(p->sharedmem->error() != QSharedMemory::NoError)
161 const QString errorMessage = p->sharedmem->errorString();
162 qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
163 return IPC_RET_FAILURE;
165 p->initialized = true;
166 return IPC_RET_SUCCESS_SLAVE;
168 else
170 const QString errorMessage = p->sharedmem->errorString();
171 qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
172 return IPC_RET_FAILURE;
176 if(p->sharedmem->error() != QSharedMemory::NoError)
178 const QString errorMessage = p->sharedmem->errorString();
179 qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
180 return IPC_RET_FAILURE;
183 if(void *const data = p->sharedmem->data())
185 memset(data, 0, sizeof(ipc_t));
188 if(!p->semaphore_wr->release(IPC_SLOTS))
190 const QString errorMessage = p->semaphore_wr->errorString();
191 qWarning("Failed to release system semaphore: %s", MUTILS_UTF8(errorMessage));
192 return IPC_RET_FAILURE;
195 p->initialized = true;
196 return IPC_RET_SUCCESS_MASTER;
199 ///////////////////////////////////////////////////////////////////////////////
200 // SEND MESSAGE
201 ///////////////////////////////////////////////////////////////////////////////
203 bool MUtils::IPCChannel::send(const unsigned int &command, const char *const message)
205 bool success = false;
206 QReadLocker readLock(&p->lock);
208 if(!p->initialized)
210 MUTILS_THROW("Shared memory for IPC not initialized yet.");
213 ipc_data_t ipc_data;
214 memset(&ipc_data, 0, sizeof(ipc_data_t));
215 ipc_data.command = command;
217 if(message)
219 strncpy_s(ipc_data.parameter, MAX_MESSAGE_LEN, message, _TRUNCATE);
222 if(!p->semaphore_wr->acquire())
224 const QString errorMessage = p->semaphore_wr->errorString();
225 qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
226 return false;
229 if(!p->sharedmem->lock())
231 const QString errorMessage = p->sharedmem->errorString();
232 qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
233 return false;
236 if(ipc_t *const ptr = reinterpret_cast<ipc_t*>(p->sharedmem->data()))
238 success = true;
239 memcpy(&ptr->data[ptr->pos_wr], &ipc_data, sizeof(ipc_data_t));
240 ptr->pos_wr = (ptr->pos_wr + 1) % IPC_SLOTS;
242 else
244 qWarning("Shared memory pointer is NULL -> unable to write data!");
247 if(!p->sharedmem->unlock())
249 const QString errorMessage = p->sharedmem->errorString();
250 qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
251 return false;
254 if(!p->semaphore_rd->release())
256 const QString errorMessage = p->semaphore_rd->errorString();
257 qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
258 return false;
261 return success;
264 ///////////////////////////////////////////////////////////////////////////////
265 // READ MESSAGE
266 ///////////////////////////////////////////////////////////////////////////////
268 bool MUtils::IPCChannel::read(unsigned int &command, char *const message, const size_t &buffSize)
270 bool success = false;
271 QReadLocker readLock(&p->lock);
273 command = 0;
274 if(message && (buffSize > 0))
276 message[0] = '\0';
279 if(!p->initialized)
281 MUTILS_THROW("Shared memory for IPC not initialized yet.");
284 ipc_data_t ipc_data;
285 memset(&ipc_data, 0, sizeof(ipc_data_t));
287 if(!p->semaphore_rd->acquire())
289 const QString errorMessage = p->semaphore_rd->errorString();
290 qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
291 return false;
294 if(!p->sharedmem->lock())
296 const QString errorMessage = p->sharedmem->errorString();
297 qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
298 return false;
301 if(ipc_t *const ptr = reinterpret_cast<ipc_t*>(p->sharedmem->data()))
303 success = true;
304 memcpy(&ipc_data, &ptr->data[ptr->pos_rd], sizeof(ipc_data_t));
305 ptr->pos_rd = (ptr->pos_rd + 1) % IPC_SLOTS;
307 if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
309 command = ipc_data.command;
310 strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
312 else
314 qWarning("Malformed IPC message, will be ignored");
317 else
319 qWarning("Shared memory pointer is NULL -> unable to write data!");
322 if(!p->sharedmem->unlock())
324 const QString errorMessage = p->sharedmem->errorString();
325 qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
326 return false;
329 if(!p->semaphore_wr->release())
331 const QString errorMessage = p->semaphore_wr->errorString();
332 qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
333 return false;
336 return success;