|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation, version 2.1 of the License. |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU Lesser General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Lesser General Public License |
|
15 * along with this program. If not, |
|
16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". |
|
17 * |
|
18 * Description: |
|
19 * |
|
20 */ |
|
21 |
|
22 #include "xqservicelog.h" |
|
23 |
|
24 #include "xqserviceipcclient.h" |
|
25 #include "xqservicechannel.h" |
|
26 #include "xqservicethreaddata.h" |
|
27 #include "xqrequestutil.h" |
|
28 |
|
29 #include <xqserviceutil.h> |
|
30 #include <xqserviceipc.h> |
|
31 #include <xqserviceipcserver.h> |
|
32 #include <xqserviceipcrequest.h> |
|
33 #include <QProcess> |
|
34 #ifdef QT_S60_AIW_PLUGIN |
|
35 #include <xqplugin.h> |
|
36 #include <xqpluginloader.h> |
|
37 #include <xqplugininfo.h> |
|
38 #endif |
|
39 #include <QList> |
|
40 #include <xqserviceprovider.h> |
|
41 #include <e32err.h> |
|
42 |
|
43 #include <xqsharablefile.h> |
|
44 |
|
45 struct XQServicePacketHeader |
|
46 { |
|
47 int totalLength; |
|
48 int command; |
|
49 int chLength; |
|
50 int msgLength; |
|
51 int dataLength; |
|
52 }; |
|
53 |
|
54 XQServiceIpcClient::XQServiceIpcClient(const QString& ipcConName, bool isServer, |
|
55 bool isSync, XQServiceRequestCompletedAsync* rc, |
|
56 const void *userData) |
|
57 : QObject(), cancelledRequest(NULL), serviceIpc(NULL), serviceIpcServer(NULL), callBackRequestComplete(rc), |
|
58 mUserData(userData) // User data can be NULL ! |
|
59 { |
|
60 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::XQServiceIpcClient"); |
|
61 XQSERVICE_DEBUG_PRINT("ipcConName: %s, isServer: %d, isSync: %d", qPrintable(ipcConName), isServer, isSync); |
|
62 XQSERVICE_DEBUG_PRINT("userData: %x, (int)userData)"); |
|
63 |
|
64 |
|
65 mIpcConName = ipcConName; |
|
66 server = isServer; |
|
67 synchronous = isSync ; |
|
68 sendSyncLoop = NULL; |
|
69 |
|
70 // Incomplete in-process plugin support (just null data members) |
|
71 plugin=NULL; |
|
72 localProvider=NULL; |
|
73 lastId = 0; // Start IDs from 1 |
|
74 |
|
75 #ifdef QT_S60_AIW_PLUGIN |
|
76 QList<XQPluginInfo> impls; |
|
77 XQPluginLoader pluginLoader; |
|
78 |
|
79 pluginLoader.listImplementations(ipcConName, impls); |
|
80 if (impls.count()) { |
|
81 pluginLoader.setUid(impls.at(0).uid()); |
|
82 // Use the very first plugin found, otherwise impl. ui need to be passed here |
|
83 plugin = pluginLoader.instance(); |
|
84 } |
|
85 #endif |
|
86 } |
|
87 |
|
88 XQServiceIpcClient::~XQServiceIpcClient() |
|
89 { |
|
90 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::~XQServiceIpcClient"); |
|
91 #ifdef QT_S60_AIW_PLUGIN |
|
92 delete plugin; |
|
93 delete localProvider; |
|
94 #endif |
|
95 // disconnected(); |
|
96 } |
|
97 |
|
98 bool XQServiceIpcClient::listen() |
|
99 { |
|
100 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::listen,isServer?=%d", server); |
|
101 # |
|
102 #ifdef QT_S60_AIW_PLUGIN |
|
103 if (plugin) return true; |
|
104 #endif |
|
105 |
|
106 if (server) { |
|
107 serviceIpcServer = new ServiceFwIPCServer(this, this, ESymbianApaServer); |
|
108 bool embedded = XQServiceUtil::isEmbedded(); |
|
109 XQSERVICE_DEBUG_PRINT("embedded: %d", embedded); |
|
110 QString conName = mIpcConName; |
|
111 if (embedded) { |
|
112 // For embedded launch ass the server app ID to connection name |
|
113 // The client side will check the same embedded options and use the |
|
114 // same pattern |
|
115 quint64 processId = qApp->applicationPid(); |
|
116 conName = mIpcConName + "." + QString::number(processId); |
|
117 } |
|
118 XQSERVICE_DEBUG_PRINT("conName: %s", qPrintable(conName)); |
|
119 return serviceIpcServer->listen(conName); |
|
120 } |
|
121 XQSERVICE_DEBUG_PRINT("No server"); |
|
122 return false; |
|
123 } |
|
124 |
|
125 bool XQServiceIpcClient::connectToServer() |
|
126 { |
|
127 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::connectToServer, isServer?=%d", server); |
|
128 #ifdef QT_S60_AIW_PLUGIN |
|
129 if (plugin) |
|
130 { |
|
131 localProvider= new XQServiceProvider( mIpcConName, NULL); |
|
132 localProvider->SetPlugin(plugin); |
|
133 // localProvider->publishAll(); |
|
134 return true; |
|
135 } |
|
136 #endif |
|
137 |
|
138 // Attension. |
|
139 // The 'mIpcConName' may contai the unique session identifier to separate connections using the same |
|
140 // By default server name is the same as the channel name. |
|
141 // When embedded launch, we add the server process ID to name to make it unique |
|
142 QString serverName = XQRequestUtil::channelName(mIpcConName); |
|
143 |
|
144 if (!serviceIpc) { |
|
145 XQSERVICE_DEBUG_PRINT("New serviceIpc:mIpcConName=%s,serverName=%s", |
|
146 qPrintable(mIpcConName), qPrintable(serverName)); |
|
147 |
|
148 serviceIpc = new ServiceFwIPC(this, ESymbianApaServer); |
|
149 serviceIpc->setUserData(mUserData); // Attach user data, if any, to request |
|
150 const XQRequestUtil *util = static_cast<const XQRequestUtil*>(mUserData); |
|
151 bool embedded = util->mInfo.isEmbedded(); |
|
152 |
|
153 connect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int))); |
|
154 connect(serviceIpc, SIGNAL(readyRead()), this, SLOT(readyRead())); |
|
155 XQSERVICE_DEBUG_PRINT("\tembedded: %d", embedded); |
|
156 if (embedded) { |
|
157 quint64 processId=0; |
|
158 // Embedded server launch. |
|
159 // Server executable is always started with common name. |
|
160 // The server has to add the it's process ID to server names when creating Symbian server names to |
|
161 // be connected to. That's how client and server can establish unique connection. |
|
162 // |
|
163 bool ret = serviceIpc->startServer(serverName,"", processId, ServiceFwIPC::EStartInEmbeddedMode); |
|
164 XQSERVICE_DEBUG_PRINT("ret: %d", ret); |
|
165 if (ret && (processId > 0)) { |
|
166 // |
|
167 // Start application in embedded mode. Add process ID to server name to make |
|
168 // server connection unique. |
|
169 serverName = serverName + "." + QString::number(processId); |
|
170 XQSERVICE_DEBUG_PRINT("Try connect to embedded service: %s", qPrintable(serverName)); |
|
171 retryCount = 0; |
|
172 while (!serviceIpc->connect(serverName) && retryCount < retryToServerMax) { |
|
173 XQSERVICE_DEBUG_PRINT("retryCount: %d", retryCount+1); |
|
174 ++retryCount; |
|
175 wait(200); |
|
176 } |
|
177 if (retryCount == retryToServerMax) { |
|
178 XQSERVICE_DEBUG_PRINT("Couldn't connect to embedded server"); |
|
179 XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionError); // Set error also |
|
180 processId = 0; |
|
181 } |
|
182 } |
|
183 if (!processId) { |
|
184 XQSERVICE_WARNING_PRINT("Could not connect to embedded service %s", qPrintable(serverName)); |
|
185 delete serviceIpc; |
|
186 serviceIpc = NULL; |
|
187 return false; |
|
188 } |
|
189 XQSERVICE_DEBUG_PRINT("Embedded connection created"); |
|
190 } |
|
191 else { |
|
192 // Not embedded |
|
193 XQSERVICE_DEBUG_PRINT("Use existing serviceIpc:mIpcConName=%s, serverName=%s", |
|
194 qPrintable(mIpcConName), qPrintable(serverName)); |
|
195 if (!serviceIpc->connect(serverName)) { |
|
196 XQSERVICE_DEBUG_PRINT("Trying to start server %s", qPrintable(serverName)); |
|
197 quint64 processId=0; |
|
198 bool ret=serviceIpc->startServer(serverName,"",processId); |
|
199 XQSERVICE_DEBUG_PRINT("starServer ret=%d", ret); |
|
200 if (ret && (processId > 0)) { |
|
201 retryCount = 0; |
|
202 while (!serviceIpc->connect(serverName) && retryCount < retryToServerMax) { |
|
203 XQSERVICE_DEBUG_PRINT("retryCount: %d", retryCount+1); |
|
204 ++retryCount; |
|
205 wait(200); |
|
206 } |
|
207 if (retryCount == retryToServerMax) { |
|
208 XQSERVICE_DEBUG_PRINT("Couldn't connect to server"); |
|
209 XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionError); // Set error also |
|
210 processId = 0; |
|
211 } |
|
212 } |
|
213 if (!processId) { |
|
214 XQSERVICE_WARNING_PRINT("Could not connect to the service %s", qPrintable(serverName)); |
|
215 delete serviceIpc; |
|
216 serviceIpc = NULL; |
|
217 return false; |
|
218 } |
|
219 } |
|
220 XQSERVICE_DEBUG_PRINT("Connection created"); |
|
221 } |
|
222 } |
|
223 return true; |
|
224 } |
|
225 |
|
226 bool XQServiceIpcClient::handleRequest( ServiceIPCRequest *aRequest ) |
|
227 { |
|
228 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleRequest,isServer?=%d", server); |
|
229 XQService::serviceThreadData()->setLatestError(KErrNone); |
|
230 bool result(true); |
|
231 int index = setCurrentRequest(aRequest); |
|
232 XQSERVICE_DEBUG_PRINT("index: %d", index); |
|
233 const QString oper = aRequest->getOperation(); |
|
234 XQSERVICE_DEBUG_PRINT("oper: %s", qPrintable(oper)); |
|
235 const QByteArray packet=aRequest->getData(); |
|
236 const char *startPtr = packet.constData(); |
|
237 XQSERVICE_DEBUG_PRINT("packet: %s", packet.constData()); |
|
238 |
|
239 |
|
240 // We have a full packet to be processed. Parse the command |
|
241 // and the channel name, but nothing else just yet. |
|
242 XQServicePacketHeader *header = (XQServicePacketHeader *)startPtr; |
|
243 int command = header->command; |
|
244 XQSERVICE_DEBUG_PRINT("command: %d", command); |
|
245 QString channel; |
|
246 const char *ptr = startPtr + sizeof(XQServicePacketHeader); |
|
247 if (header->chLength > 0) { |
|
248 channel = QString::fromUtf16 |
|
249 ((const ushort *)ptr, header->chLength); |
|
250 ptr += header->chLength * 2; |
|
251 } |
|
252 XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel)); |
|
253 // Parse the rest of the packet now that we know we need it. |
|
254 QString msg; |
|
255 QByteArray data; |
|
256 if (header->msgLength > 0) { |
|
257 msg = QString::fromUtf16 |
|
258 ((const ushort *)ptr, header->msgLength); |
|
259 ptr += header->msgLength * 2; |
|
260 } |
|
261 XQSERVICE_DEBUG_PRINT("msg: %s", qPrintable(msg)); |
|
262 if (header->dataLength > 0) { |
|
263 data = QByteArray ((const char *)ptr, header->dataLength); |
|
264 ptr += header->dataLength; |
|
265 } |
|
266 XQSERVICE_DEBUG_PRINT("data: %s", data.constData()); |
|
267 QVariant ret; |
|
268 // Processing command on server side. |
|
269 if (command == XQServiceCmd_Send) { |
|
270 //Only support 1 sharable file, so index is 0 |
|
271 ret=XQServiceChannel::sendLocally(channel, msg, data, aRequest->sharableFile(0) ); |
|
272 } |
|
273 else if (command == XQServiceCmd_ReturnValueDelivered) { |
|
274 XQServiceChannel::sendCommand(channel,XQServiceChannel::ReturnValueDelivered); |
|
275 } |
|
276 |
|
277 if (XQService::serviceThreadData()->latestError() || |
|
278 !aRequest->isAsync()) { |
|
279 ret=completeRequest(index,ret); |
|
280 } |
|
281 XQSERVICE_DEBUG_PRINT("ret: %d", result); |
|
282 return result; |
|
283 } |
|
284 |
|
285 /*! |
|
286 * From MServiceIPCObserver |
|
287 * \see MServiceIPCObserver::handleCancelRequest( ServiceIPCRequest *aRequest ) |
|
288 */ |
|
289 void XQServiceIpcClient::handleCancelRequest(ServiceIPCRequest* aRequest) |
|
290 { |
|
291 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleCancelRequest isServer?=%d", server); |
|
292 if (server) |
|
293 { |
|
294 // Save the request to be cancelled if service provider wants to as |
|
295 // XQRequestInfo for details |
|
296 // Valid only upon sendCommand call |
|
297 cancelledRequest = aRequest; |
|
298 |
|
299 //Attention! At the moment in server side channel name and connection name are the same |
|
300 // it might be that in the future will be different then this is not valid anymore. |
|
301 XQServiceChannel::sendCommand(mIpcConName,XQServiceChannel::ClientDisconnected); |
|
302 |
|
303 // Remember to reset immediatelly |
|
304 cancelledRequest = 0; |
|
305 |
|
306 cancelRequest(aRequest); |
|
307 } |
|
308 } |
|
309 |
|
310 /* |
|
311 * From MServiceIPCObserver |
|
312 * \see MServiceIPCObserver::handleDeleteRequest( ServiceIPCRequest *aRequest ) |
|
313 */ |
|
314 void XQServiceIpcClient::handleDeleteRequest(ServiceIPCRequest* aRequest) |
|
315 { |
|
316 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleDeleteRequest isServer?=%d, reqId=", server); |
|
317 if (server) |
|
318 { |
|
319 cancelRequest(aRequest); |
|
320 } |
|
321 } |
|
322 |
|
323 bool XQServiceIpcClient::cancelRequest(ServiceIPCRequest* aRequest) { |
|
324 bool ret(false); |
|
325 |
|
326 if (aRequest == NULL) |
|
327 return ret; |
|
328 |
|
329 if (server) { |
|
330 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelRequest, isServer?=%d, reqId=%d", server, aRequest->id()); |
|
331 if (requestsMap.contains(aRequest->id())) { |
|
332 requestsMap.take(aRequest->id()); // Use "take" not to delete the request !! |
|
333 ret = true; |
|
334 } else { |
|
335 ret = false; |
|
336 } |
|
337 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelRequest, ret=%d", ret); |
|
338 } |
|
339 return ret; |
|
340 } |
|
341 |
|
342 bool XQServiceIpcClient::sendChannelCommand(int cmd, const QString& ch) |
|
343 { |
|
344 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::sendChannelCommand, isServer?=%d", server); |
|
345 XQSERVICE_DEBUG_PRINT("cmd: %d, ch: %s", cmd, qPrintable(ch)); |
|
346 if (!connectToServer()){ |
|
347 XQSERVICE_DEBUG_PRINT("Couldn't connect to the server"); |
|
348 return false; |
|
349 } |
|
350 int len = ch.length() * 2 + sizeof(XQServicePacketHeader); |
|
351 XQSERVICE_DEBUG_PRINT("cmd: %d", len); |
|
352 int writelen; |
|
353 char *buf; |
|
354 bool freeBuf = false; |
|
355 if (len <= minPacketSize) { |
|
356 buf = outBuffer; |
|
357 memset(buf + len, 0, minPacketSize - len); |
|
358 writelen = minPacketSize; |
|
359 } else { |
|
360 buf = new char [len]; |
|
361 writelen = len; |
|
362 freeBuf = true; |
|
363 } |
|
364 XQSERVICE_DEBUG_PRINT("writelen: %d", writelen); |
|
365 XQServicePacketHeader *header = (XQServicePacketHeader *)buf; |
|
366 header->command = cmd; |
|
367 header->totalLength = len; |
|
368 header->chLength = ch.length(); |
|
369 header->msgLength = 0; |
|
370 header->dataLength = 0; |
|
371 char *ptr = buf + sizeof(XQServicePacketHeader); |
|
372 memcpy(ptr, ch.constData(), ch.length() * 2); |
|
373 QByteArray sndBuf(buf,writelen); |
|
374 XQSERVICE_DEBUG_PRINT("sndBuf: %s", sndBuf.constData()); |
|
375 |
|
376 bool ret = serviceIpc->sendSync("sendChannelCommand",sndBuf); |
|
377 |
|
378 if (freeBuf) |
|
379 delete[] buf; |
|
380 |
|
381 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::sendChannelCommand: ret=%d", ret); |
|
382 return ret; |
|
383 } |
|
384 |
|
385 bool XQServiceIpcClient::send(const QString& ch, |
|
386 const QString& msg, |
|
387 const QByteArray& data, |
|
388 QByteArray &retData, |
|
389 int cmd) |
|
390 { |
|
391 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::send, isServer?=%d", server); |
|
392 |
|
393 // Attension. The 'ch' name may contain unique session identifier to separate requests going |
|
394 // the same channel. Before real IPC calls need to get the normalized channel name. |
|
395 // The 'mIpcConName' contains the same session identifier to separate connections using the same |
|
396 // channel name. |
|
397 QString channel = XQRequestUtil::channelName(ch); |
|
398 |
|
399 XQSERVICE_DEBUG_PRINT("\tchannel: %s, msg: %s", qPrintable(channel), qPrintable(msg)); |
|
400 XQSERVICE_DEBUG_PRINT("\tdata: %s, cmd: %d", data.constData(), cmd); |
|
401 |
|
402 XQService::serviceThreadData()->setLatestError(KErrNone); |
|
403 if (!connectToServer()){ |
|
404 XQSERVICE_DEBUG_PRINT("\tCouldn't connect to the server"); |
|
405 return false; |
|
406 } |
|
407 |
|
408 #ifdef QT_S60_AIW_PLUGIN |
|
409 if (plugin) { |
|
410 QVariant ret=XQServiceChannel::sendLocally(channel, msg, data); |
|
411 retData = XQServiceThreadData::serializeRetData(ret, XQService::serviceThreadData()->latestError()); |
|
412 return true; |
|
413 } |
|
414 #endif |
|
415 int len = channel.length() * 2 + msg.length() * 2 + data.length(); |
|
416 len += sizeof(XQServicePacketHeader); |
|
417 XQSERVICE_DEBUG_PRINT("\tcmd: %d", len); |
|
418 int writelen; |
|
419 char *buf; |
|
420 bool freeBuf = false; |
|
421 if (len <= minPacketSize) { |
|
422 buf = outBuffer; |
|
423 memset(buf + len, 0, minPacketSize - len); |
|
424 writelen = minPacketSize; |
|
425 } else { |
|
426 buf = new char [len]; |
|
427 writelen = len; |
|
428 freeBuf = true; |
|
429 } |
|
430 XQSERVICE_DEBUG_PRINT("\twritelen: %d", writelen); |
|
431 XQServicePacketHeader *header = (XQServicePacketHeader *)buf; |
|
432 header->command = cmd; |
|
433 header->totalLength = len; |
|
434 header->chLength = channel.length(); |
|
435 header->msgLength = msg.length(); |
|
436 header->dataLength = data.length(); |
|
437 char *ptr = buf + sizeof(XQServicePacketHeader); |
|
438 memcpy(ptr, channel.constData(), channel.length() * 2); |
|
439 ptr += channel.length() * 2; |
|
440 memcpy(ptr, msg.constData(), msg.length() * 2); |
|
441 ptr += msg.length() * 2; |
|
442 memcpy(ptr, data.constData(), data.length()); |
|
443 QByteArray sndBuf(buf,writelen); |
|
444 XQSERVICE_DEBUG_PRINT("\tsndBuf: %s", sndBuf.constData()); |
|
445 bool ret = true; |
|
446 XQSERVICE_DEBUG_PRINT("\tsynchronous: %d", synchronous); |
|
447 |
|
448 if (synchronous) { |
|
449 |
|
450 ret=serviceIpc->sendSync("send",sndBuf); |
|
451 if (ret) { |
|
452 retData=serviceIpc->readAll(); |
|
453 XQSERVICE_DEBUG_PRINT("\t readAll done, error=%d", XQService::serviceThreadData()->latestError()); |
|
454 if (!XQService::serviceThreadData()->latestError()) |
|
455 { |
|
456 // No point to send channel command on error. Error could be also |
|
457 // caused by server exit without completing the actual request |
|
458 sendChannelCommand(XQServiceCmd_ReturnValueDelivered,channel); |
|
459 } |
|
460 else |
|
461 ret = false; |
|
462 } |
|
463 } |
|
464 else { |
|
465 // At the moment we can not have multiple send async |
|
466 if (serviceIpc->requestPending()) { |
|
467 XQSERVICE_DEBUG_PRINT("Request already pending"); |
|
468 XQService::serviceThreadData()->setLatestError(ServiceFwIPC::ERequestPending); // maparnan |
|
469 ret = false ; |
|
470 } |
|
471 else { |
|
472 serviceIpc->sendAsync("send",sndBuf); |
|
473 ret = true; |
|
474 } |
|
475 } |
|
476 if (freeBuf) |
|
477 delete[] buf; |
|
478 XQSERVICE_DEBUG_PRINT("\tret: %d", ret); |
|
479 return ret; |
|
480 } |
|
481 |
|
482 |
|
483 /*! |
|
484 * This method cancels requests. |
|
485 */ |
|
486 bool XQServiceIpcClient::cancelPendingSend(const QString& ch) |
|
487 { |
|
488 Q_UNUSED(ch); // |
|
489 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelPendingSend, isServer?=%d", server); |
|
490 if (serviceIpc) { |
|
491 // Close the client connection silently |
|
492 disconnect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int))); |
|
493 XQService::serviceThreadData()->closeClientConnection(mIpcConName); |
|
494 // No callback wanted any more |
|
495 callBackRequestComplete = NULL; |
|
496 } |
|
497 |
|
498 return true; |
|
499 } |
|
500 |
|
501 void XQServiceIpcClient::disconnected() |
|
502 { |
|
503 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::disconnected START"); |
|
504 XQSERVICE_DEBUG_PRINT("\t server: %d, lastId=%d", server, lastId); |
|
505 if (server) { |
|
506 // Closing down IPC |
|
507 ServiceIPCRequest* request = NULL; |
|
508 |
|
509 // |
|
510 // Go through all requests and send disconnected error to them |
|
511 // |
|
512 QHashIterator<int, ServiceIPCRequest*> iter(requestsMap); |
|
513 while (iter.hasNext()) { |
|
514 iter.next(); |
|
515 int reqId = iter.key(); |
|
516 request=iter.value(); |
|
517 XQSERVICE_DEBUG_PRINT("\t request iter: id=%d", reqId); |
|
518 XQSERVICE_DEBUG_PRINT("\t request iter requestAsync=%d", request->isAsync()); |
|
519 if (request->isAsync()) { |
|
520 QVariant ret; |
|
521 // Consider server side end as connection closure. |
|
522 XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionClosed); |
|
523 completeRequest(reqId, ret); |
|
524 // In disconnnect phase let's wait a bit in order to be sure |
|
525 // That completeRequest and application exit notification event goes in the client side |
|
526 wait(200); |
|
527 } |
|
528 } |
|
529 if (serviceIpcServer) { |
|
530 serviceIpcServer->disconnect(); |
|
531 delete serviceIpcServer; |
|
532 serviceIpcServer = NULL; |
|
533 XQSERVICE_DEBUG_PRINT("\tXQServiceIpcClient deleteLater"); |
|
534 wait(200); |
|
535 XQSERVICE_DEBUG_PRINT("\tXQServiceIpcClient deleteLater over"); |
|
536 } |
|
537 } else { |
|
538 if (sendSyncLoop && sendSyncLoop->isRunning()) { |
|
539 XQSERVICE_DEBUG_PRINT("Quit sendSyncLoop"); |
|
540 sendSyncLoop->quit(); |
|
541 } |
|
542 if (serviceIpc) { |
|
543 XQSERVICE_DEBUG_PRINT("Disconnect serviceIpc"); |
|
544 serviceIpc->disconnect(); |
|
545 delete serviceIpc; |
|
546 serviceIpc = NULL; |
|
547 } |
|
548 } |
|
549 deleteLater(); |
|
550 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::disconnected END"); |
|
551 } |
|
552 |
|
553 void XQServiceIpcClient::clientError(int error) |
|
554 { |
|
555 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::clientError, isServer?=%d", server); |
|
556 XQSERVICE_DEBUG_PRINT("error: %d", error); |
|
557 |
|
558 |
|
559 if (serviceIpc) { |
|
560 XQService::serviceThreadData()->setLatestError(error); |
|
561 disconnect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int))); |
|
562 //disconnected(); |
|
563 XQService::serviceThreadData()->closeClientConnection(mIpcConName); |
|
564 } |
|
565 |
|
566 //complete the client request with error value |
|
567 if (callBackRequestComplete) { |
|
568 XQSERVICE_DEBUG_PRINT("requestErrorAsync mapped error=%d", error); |
|
569 callBackRequestComplete->requestErrorAsync(error); |
|
570 } |
|
571 XQSERVICE_DEBUG_PRINT("clientError end mapped error=%d", error); |
|
572 } |
|
573 |
|
574 /** |
|
575 * Async read operation |
|
576 */ |
|
577 |
|
578 void XQServiceIpcClient::readyRead() |
|
579 { |
|
580 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::readyRead, isServer?=%d", server); |
|
581 |
|
582 // Clear error |
|
583 XQService::serviceThreadData()->setLatestError(KErrNone); |
|
584 |
|
585 //in case it has been connected before |
|
586 //this prevents calling twice of the callback functions |
|
587 disconnect(serviceIpc, SIGNAL(ReadDone()), this, SLOT(readDone())); |
|
588 connect(serviceIpc, SIGNAL(ReadDone()), this, SLOT(readDone())); |
|
589 serviceIpc->readAll( iRetData ); |
|
590 } |
|
591 |
|
592 |
|
593 /** |
|
594 * readDone, send return value back to client |
|
595 */ |
|
596 void XQServiceIpcClient::readDone() |
|
597 { |
|
598 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::readDone"); |
|
599 QVariant retValue = XQServiceThreadData::deserializeRetData(iRetData); |
|
600 |
|
601 #ifdef XQSERVICE_DEBUG |
|
602 QString s = retValue.toString(); |
|
603 int len=s.length(); |
|
604 XQSERVICE_DEBUG_PRINT("retValue: type=%s,len=%d,value(max.1024)=%s", |
|
605 retValue.typeName(),len,qPrintable(s.left(1024))); |
|
606 #endif |
|
607 int err = XQService::serviceThreadData()->latestError(); |
|
608 XQSERVICE_DEBUG_PRINT("err: %d", err); |
|
609 |
|
610 if (err) |
|
611 { |
|
612 XQSERVICE_DEBUG_PRINT("there is error!"); |
|
613 //emitError(err); |
|
614 clientError(err); |
|
615 } |
|
616 else if (iRetData.length()) |
|
617 { |
|
618 XQSERVICE_DEBUG_PRINT("there is return data"); |
|
619 if (callBackRequestComplete && |
|
620 // !retValue.isNull() && (retValue.type() != QVariant::Invalid)) maparnan |
|
621 retValue.isValid()) |
|
622 { |
|
623 XQSERVICE_DEBUG_PRINT("before compelete async request"); |
|
624 |
|
625 //should this send before compete the request ? |
|
626 //Attention ! Map mIpcConName name may contain unique identifier to separate connections using the same |
|
627 // channel name. So need to get channel name. |
|
628 QString channel = XQRequestUtil::channelName(mIpcConName); |
|
629 sendChannelCommand(XQServiceCmd_ReturnValueDelivered, channel); |
|
630 |
|
631 callBackRequestComplete->requestCompletedAsync( retValue ); |
|
632 XQSERVICE_DEBUG_PRINT("After complete async request"); |
|
633 } |
|
634 else |
|
635 { |
|
636 clientError( KErrUnknown ); |
|
637 } |
|
638 //attention at the moment channel name and connection name are the same |
|
639 // it might be that in the future will be different then this is not valid anymore. |
|
640 //sendChannelCommand(XQServiceCmd_ReturnValueDelivered,mIpcConName); |
|
641 } |
|
642 else |
|
643 { |
|
644 //err is KErrNone but no return value |
|
645 //reading failed |
|
646 clientError( KErrUnknown ); |
|
647 } |
|
648 } |
|
649 |
|
650 |
|
651 int XQServiceIpcClient::setCurrentRequest(ServiceIPCRequest* request) |
|
652 { |
|
653 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequest START"); |
|
654 XQSERVICE_DEBUG_PRINT("\t isServer=%d", server); |
|
655 int id = -1; |
|
656 if (request) { |
|
657 lastId = lastId + 1; |
|
658 XQSERVICE_DEBUG_PRINT("\t new id=%d assigned to current request", lastId); |
|
659 request->setAsync(false); |
|
660 request->setId(lastId); |
|
661 requestsMap.insert(lastId, request); |
|
662 id = lastId; |
|
663 } else { |
|
664 XQSERVICE_DEBUG_PRINT("\t request was NULL"); |
|
665 } |
|
666 XQSERVICE_DEBUG_PRINT("\t returning id=%d", id); |
|
667 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequest END"); |
|
668 return id; |
|
669 } |
|
670 |
|
671 // |
|
672 // This function need to be called during a slot call before returning from |
|
673 // the slot. |
|
674 // The lastId might change after returning from the slot call as |
|
675 // other possible requests may arrive |
|
676 // |
|
677 int XQServiceIpcClient::setCurrentRequestAsync() |
|
678 { |
|
679 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequestAsync"); |
|
680 XQSERVICE_DEBUG_PRINT("\t isServer=%d", server); |
|
681 ServiceIPCRequest* request = requestPtr(lastId); |
|
682 int id = -1; |
|
683 |
|
684 if (request) { |
|
685 request->setAsync(true); |
|
686 id = request->id(); |
|
687 } |
|
688 |
|
689 XQSERVICE_DEBUG_PRINT("\t returning request's id=%d", id); |
|
690 return id; |
|
691 } |
|
692 |
|
693 bool XQServiceIpcClient::completeRequest(int index, const QVariant& retValue) |
|
694 { |
|
695 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest START"); |
|
696 XQSERVICE_DEBUG_PRINT("\t isServer=%d", server); |
|
697 XQSERVICE_DEBUG_PRINT("\t index=%d", index); |
|
698 #ifdef XQSERVICE_DEBUG |
|
699 QString s = retValue.toString(); |
|
700 int len=s.length(); |
|
701 XQSERVICE_DEBUG_PRINT("retValue: type=%s,len=%d,value(max.1024)=%s", |
|
702 retValue.typeName(),len,qPrintable(s.left(1024))); |
|
703 #endif |
|
704 |
|
705 ServiceIPCRequest* request = requestPtr(index); |
|
706 if (!request){ |
|
707 XQSERVICE_DEBUG_PRINT("\t request = NULL"); |
|
708 XQSERVICE_DEBUG_PRINT("\t return false"); |
|
709 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (1)"); |
|
710 return false; |
|
711 } |
|
712 #ifdef QT_S60_AIW_PLUGIN |
|
713 if (plugin) { |
|
714 if (callBackRequestComplete && |
|
715 !retValue.isNull() && (retValue.type() != QVariant::Invalid)) |
|
716 { |
|
717 callBackRequestComplete->requestCompletedAsync(retValue); |
|
718 } |
|
719 XQSERVICE_DEBUG_PRINT("\t return true"); |
|
720 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (2)"); |
|
721 return true; |
|
722 } |
|
723 #endif |
|
724 QByteArray array = XQServiceThreadData::serializeRetData(retValue, |
|
725 XQService::serviceThreadData()->latestError() ); |
|
726 XQSERVICE_DEBUG_PRINT("\t array: %s", array.constData()); |
|
727 XQService::serviceThreadData()->setLatestError(KErrNone); |
|
728 request->write(array); |
|
729 bool ret = request->completeRequest(); |
|
730 // cancelRequest(request); |
|
731 XQSERVICE_DEBUG_PRINT("\t return %d", ret); |
|
732 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (3)"); |
|
733 return ret; |
|
734 } |
|
735 |
|
736 |
|
737 // |
|
738 // This function need to be called during a slot call before returning from |
|
739 // the slot. |
|
740 // The lastId might change after returning from the slot call as |
|
741 // other possible requests may arrive |
|
742 // |
|
743 XQRequestInfo XQServiceIpcClient::requestInfo() const |
|
744 { |
|
745 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::requestInfo"); |
|
746 XQSERVICE_DEBUG_PRINT("\t isServer=%d", server); |
|
747 ServiceIPCRequest* request = requestPtr(lastId); |
|
748 |
|
749 if (request) { |
|
750 return request->requestInfo(); |
|
751 } |
|
752 return XQRequestInfo(); |
|
753 } |
|
754 |
|
755 // |
|
756 // This internal function need to be called before a slot call to set the request info |
|
757 // The provider can then call requestInfo() to get the data. |
|
758 // The lastId might change after returning from the slot call as |
|
759 // other possible requests may arrive |
|
760 // |
|
761 bool XQServiceIpcClient::setRequestInfo(XQRequestInfo &info) |
|
762 { |
|
763 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setRequestInfo"); |
|
764 XQSERVICE_DEBUG_PRINT("\t isServer=%d", server); |
|
765 ServiceIPCRequest* request = requestPtr(lastId); |
|
766 |
|
767 if (request) { |
|
768 request->setRequestInfo(&info); |
|
769 } |
|
770 return request != NULL; |
|
771 } |
|
772 |
|
773 |
|
774 // in disconnnect phase let's wait a bit in order to be sure |
|
775 // that completeRequest and application exit notification event goes in the client side |
|
776 void XQServiceIpcClient::wait(int msec) |
|
777 { |
|
778 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait, isServer?=%d", server); |
|
779 |
|
780 if (server) |
|
781 return; |
|
782 |
|
783 User::After(1000 * msec); //Contribution from Seppo |
|
784 |
|
785 /* |
|
786 if (!QCoreApplication::instance()) |
|
787 { |
|
788 User::After(1000 * msec); //Contribution from Seppo |
|
789 return; |
|
790 } |
|
791 |
|
792 QTime t1 = QTime::currentTime(); |
|
793 QEventLoop w = QEventLoop(); |
|
794 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait start"); |
|
795 QTimer::singleShot(msec, &w, SLOT(quit())); |
|
796 w.exec(); |
|
797 QTime t2 = QTime::currentTime(); |
|
798 XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait end elapsed=%d", t1.msecsTo(t2)); |
|
799 */ |
|
800 } |
|
801 |
|
802 // |
|
803 // Returns the handle of the current request |
|
804 // |
|
805 ServiceIPCRequest *XQServiceIpcClient::requestPtr(int index) const |
|
806 { |
|
807 ServiceIPCRequest* request = NULL; |
|
808 |
|
809 // If request is being cancelled (saved by handleCancelRequest()) use it's id instead |
|
810 // By that way service provider can access the XQRequestInfo of the cancelled request |
|
811 // Upon handling clientDisconnected |
|
812 if (cancelledRequest) |
|
813 { |
|
814 index = cancelledRequest->id(); |
|
815 XQSERVICE_DEBUG_PRINT("\t Cancelled request id=%d", index); |
|
816 } |
|
817 |
|
818 if (requestsMap.contains(index)) { |
|
819 XQSERVICE_DEBUG_PRINT("\t request having id=%d FOUND", index); |
|
820 request = requestsMap[index]; |
|
821 } else { |
|
822 XQSERVICE_DEBUG_PRINT("\t request having id=%d NOT FOUND", index); |
|
823 } |
|
824 |
|
825 return request; |
|
826 |
|
827 } |