1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
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.
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 //////////////////////////////////////////////////////////////////////////////////
23 #include <MUtils/IPCChannel.h>
24 #include <MUtils/Exception.h>
28 #include <QSharedMemory>
29 #include <QSystemSemaphore>
30 #include <QWriteLocker>
32 ///////////////////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////////////////
38 static const size_t IPC_SLOTS
= 128;
39 static const size_t MAX_MESSAGE_LEN
= 4096;
44 unsigned int reserved_1
;
45 unsigned int reserved_2
;
46 char parameter
[MAX_MESSAGE_LEN
];
54 ipc_data_t data
[IPC_SLOTS
];
59 ///////////////////////////////////////////////////////////////////////////////
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 ///////////////////////////////////////////////////////////////////////////////
75 ///////////////////////////////////////////////////////////////////////////////
79 class IPCChannel_Private
81 friend class IPCChannel
;
84 volatile bool initialized
;
85 QScopedPointer
<QSharedMemory
> sharedmem
;
86 QScopedPointer
<QSystemSemaphore
> semaphore_rd
;
87 QScopedPointer
<QSystemSemaphore
> semaphore_wr
;
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)
109 if(p
->sharedmem
->isAttached())
111 p
->sharedmem
->detach();
118 ///////////////////////////////////////////////////////////////////////////////
120 ///////////////////////////////////////////////////////////////////////////////
122 int MUtils::IPCChannel::initialize(void)
124 QWriteLocker
writeLock(&p
->lock
);
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
;
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 ///////////////////////////////////////////////////////////////////////////////
201 ///////////////////////////////////////////////////////////////////////////////
203 bool MUtils::IPCChannel::send(const unsigned int &command
, const char *const message
)
205 bool success
= false;
206 QReadLocker
readLock(&p
->lock
);
210 MUTILS_THROW("Shared memory for IPC not initialized yet.");
214 memset(&ipc_data
, 0, sizeof(ipc_data_t
));
215 ipc_data
.command
= command
;
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
));
229 if(!p
->sharedmem
->lock())
231 const QString errorMessage
= p
->sharedmem
->errorString();
232 qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage
));
236 if(ipc_t
*const ptr
= reinterpret_cast<ipc_t
*>(p
->sharedmem
->data()))
239 memcpy(&ptr
->data
[ptr
->pos_wr
], &ipc_data
, sizeof(ipc_data_t
));
240 ptr
->pos_wr
= (ptr
->pos_wr
+ 1) % IPC_SLOTS
;
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
));
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
));
264 ///////////////////////////////////////////////////////////////////////////////
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
);
274 if(message
&& (buffSize
> 0))
281 MUTILS_THROW("Shared memory for IPC not initialized yet.");
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
));
294 if(!p
->sharedmem
->lock())
296 const QString errorMessage
= p
->sharedmem
->errorString();
297 qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage
));
301 if(ipc_t
*const ptr
= reinterpret_cast<ipc_t
*>(p
->sharedmem
->data()))
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
);
314 qWarning("Malformed IPC message, will be ignored");
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
));
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
));