--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqserviceipcclient.cpp Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,827 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+*
+* This program 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, version 2.1 of the License.
+*
+* This program 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 program. If not,
+* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
+*
+* Description:
+*
+*/
+
+#include "xqservicelog.h"
+
+#include "xqserviceipcclient.h"
+#include "xqservicechannel.h"
+#include "xqservicethreaddata.h"
+#include "xqrequestutil.h"
+
+#include <xqserviceutil.h>
+#include <xqserviceipc.h>
+#include <xqserviceipcserver.h>
+#include <xqserviceipcrequest.h>
+#include <QProcess>
+#ifdef QT_S60_AIW_PLUGIN
+#include <xqplugin.h>
+#include <xqpluginloader.h>
+#include <xqplugininfo.h>
+#endif
+#include <QList>
+#include <xqserviceprovider.h>
+#include <e32err.h>
+
+#include <xqsharablefile.h>
+
+struct XQServicePacketHeader
+{
+ int totalLength;
+ int command;
+ int chLength;
+ int msgLength;
+ int dataLength;
+};
+
+XQServiceIpcClient::XQServiceIpcClient(const QString& ipcConName, bool isServer,
+ bool isSync, XQServiceRequestCompletedAsync* rc,
+ const void *userData)
+ : QObject(), cancelledRequest(NULL), serviceIpc(NULL), serviceIpcServer(NULL), callBackRequestComplete(rc),
+ mUserData(userData) // User data can be NULL !
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::XQServiceIpcClient");
+ XQSERVICE_DEBUG_PRINT("ipcConName: %s, isServer: %d, isSync: %d", qPrintable(ipcConName), isServer, isSync);
+ XQSERVICE_DEBUG_PRINT("userData: %x, (int)userData)");
+
+
+ mIpcConName = ipcConName;
+ server = isServer;
+ synchronous = isSync ;
+ sendSyncLoop = NULL;
+
+ // Incomplete in-process plugin support (just null data members)
+ plugin=NULL;
+ localProvider=NULL;
+ lastId = 0; // Start IDs from 1
+
+#ifdef QT_S60_AIW_PLUGIN
+ QList<XQPluginInfo> impls;
+ XQPluginLoader pluginLoader;
+
+ pluginLoader.listImplementations(ipcConName, impls);
+ if (impls.count()) {
+ pluginLoader.setUid(impls.at(0).uid());
+ // Use the very first plugin found, otherwise impl. ui need to be passed here
+ plugin = pluginLoader.instance();
+ }
+#endif
+}
+
+XQServiceIpcClient::~XQServiceIpcClient()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::~XQServiceIpcClient");
+#ifdef QT_S60_AIW_PLUGIN
+ delete plugin;
+ delete localProvider;
+#endif
+// disconnected();
+}
+
+bool XQServiceIpcClient::listen()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::listen,isServer?=%d", server);
+#
+#ifdef QT_S60_AIW_PLUGIN
+ if (plugin) return true;
+#endif
+
+ if (server) {
+ serviceIpcServer = new ServiceFwIPCServer(this, this, ESymbianApaServer);
+ bool embedded = XQServiceUtil::isEmbedded();
+ XQSERVICE_DEBUG_PRINT("embedded: %d", embedded);
+ QString conName = mIpcConName;
+ if (embedded) {
+ // For embedded launch ass the server app ID to connection name
+ // The client side will check the same embedded options and use the
+ // same pattern
+ quint64 processId = qApp->applicationPid();
+ conName = mIpcConName + "." + QString::number(processId);
+ }
+ XQSERVICE_DEBUG_PRINT("conName: %s", qPrintable(conName));
+ return serviceIpcServer->listen(conName);
+ }
+ XQSERVICE_DEBUG_PRINT("No server");
+ return false;
+}
+
+bool XQServiceIpcClient::connectToServer()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::connectToServer, isServer?=%d", server);
+#ifdef QT_S60_AIW_PLUGIN
+ if (plugin)
+ {
+ localProvider= new XQServiceProvider( mIpcConName, NULL);
+ localProvider->SetPlugin(plugin);
+ // localProvider->publishAll();
+ return true;
+ }
+#endif
+
+ // Attension.
+ // The 'mIpcConName' may contai the unique session identifier to separate connections using the same
+ // By default server name is the same as the channel name.
+ // When embedded launch, we add the server process ID to name to make it unique
+ QString serverName = XQRequestUtil::channelName(mIpcConName);
+
+ if (!serviceIpc) {
+ XQSERVICE_DEBUG_PRINT("New serviceIpc:mIpcConName=%s,serverName=%s",
+ qPrintable(mIpcConName), qPrintable(serverName));
+
+ serviceIpc = new ServiceFwIPC(this, ESymbianApaServer);
+ serviceIpc->setUserData(mUserData); // Attach user data, if any, to request
+ const XQRequestUtil *util = static_cast<const XQRequestUtil*>(mUserData);
+ bool embedded = util->mInfo.isEmbedded();
+
+ connect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int)));
+ connect(serviceIpc, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ XQSERVICE_DEBUG_PRINT("\tembedded: %d", embedded);
+ if (embedded) {
+ quint64 processId=0;
+ // Embedded server launch.
+ // Server executable is always started with common name.
+ // The server has to add the it's process ID to server names when creating Symbian server names to
+ // be connected to. That's how client and server can establish unique connection.
+ //
+ bool ret = serviceIpc->startServer(serverName,"", processId, ServiceFwIPC::EStartInEmbeddedMode);
+ XQSERVICE_DEBUG_PRINT("ret: %d", ret);
+ if (ret && (processId > 0)) {
+ //
+ // Start application in embedded mode. Add process ID to server name to make
+ // server connection unique.
+ serverName = serverName + "." + QString::number(processId);
+ XQSERVICE_DEBUG_PRINT("Try connect to embedded service: %s", qPrintable(serverName));
+ retryCount = 0;
+ while (!serviceIpc->connect(serverName) && retryCount < retryToServerMax) {
+ XQSERVICE_DEBUG_PRINT("retryCount: %d", retryCount+1);
+ ++retryCount;
+ wait(200);
+ }
+ if (retryCount == retryToServerMax) {
+ XQSERVICE_DEBUG_PRINT("Couldn't connect to embedded server");
+ XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionError); // Set error also
+ processId = 0;
+ }
+ }
+ if (!processId) {
+ XQSERVICE_WARNING_PRINT("Could not connect to embedded service %s", qPrintable(serverName));
+ delete serviceIpc;
+ serviceIpc = NULL;
+ return false;
+ }
+ XQSERVICE_DEBUG_PRINT("Embedded connection created");
+ }
+ else {
+ // Not embedded
+ XQSERVICE_DEBUG_PRINT("Use existing serviceIpc:mIpcConName=%s, serverName=%s",
+ qPrintable(mIpcConName), qPrintable(serverName));
+ if (!serviceIpc->connect(serverName)) {
+ XQSERVICE_DEBUG_PRINT("Trying to start server %s", qPrintable(serverName));
+ quint64 processId=0;
+ bool ret=serviceIpc->startServer(serverName,"",processId);
+ XQSERVICE_DEBUG_PRINT("starServer ret=%d", ret);
+ if (ret && (processId > 0)) {
+ retryCount = 0;
+ while (!serviceIpc->connect(serverName) && retryCount < retryToServerMax) {
+ XQSERVICE_DEBUG_PRINT("retryCount: %d", retryCount+1);
+ ++retryCount;
+ wait(200);
+ }
+ if (retryCount == retryToServerMax) {
+ XQSERVICE_DEBUG_PRINT("Couldn't connect to server");
+ XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionError); // Set error also
+ processId = 0;
+ }
+ }
+ if (!processId) {
+ XQSERVICE_WARNING_PRINT("Could not connect to the service %s", qPrintable(serverName));
+ delete serviceIpc;
+ serviceIpc = NULL;
+ return false;
+ }
+ }
+ XQSERVICE_DEBUG_PRINT("Connection created");
+ }
+ }
+ return true;
+}
+
+bool XQServiceIpcClient::handleRequest( ServiceIPCRequest *aRequest )
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleRequest,isServer?=%d", server);
+ XQService::serviceThreadData()->setLatestError(KErrNone);
+ bool result(true);
+ int index = setCurrentRequest(aRequest);
+ XQSERVICE_DEBUG_PRINT("index: %d", index);
+ const QString oper = aRequest->getOperation();
+ XQSERVICE_DEBUG_PRINT("oper: %s", qPrintable(oper));
+ const QByteArray packet=aRequest->getData();
+ const char *startPtr = packet.constData();
+ XQSERVICE_DEBUG_PRINT("packet: %s", packet.constData());
+
+
+ // We have a full packet to be processed. Parse the command
+ // and the channel name, but nothing else just yet.
+ XQServicePacketHeader *header = (XQServicePacketHeader *)startPtr;
+ int command = header->command;
+ XQSERVICE_DEBUG_PRINT("command: %d", command);
+ QString channel;
+ const char *ptr = startPtr + sizeof(XQServicePacketHeader);
+ if (header->chLength > 0) {
+ channel = QString::fromUtf16
+ ((const ushort *)ptr, header->chLength);
+ ptr += header->chLength * 2;
+ }
+ XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel));
+ // Parse the rest of the packet now that we know we need it.
+ QString msg;
+ QByteArray data;
+ if (header->msgLength > 0) {
+ msg = QString::fromUtf16
+ ((const ushort *)ptr, header->msgLength);
+ ptr += header->msgLength * 2;
+ }
+ XQSERVICE_DEBUG_PRINT("msg: %s", qPrintable(msg));
+ if (header->dataLength > 0) {
+ data = QByteArray ((const char *)ptr, header->dataLength);
+ ptr += header->dataLength;
+ }
+ XQSERVICE_DEBUG_PRINT("data: %s", data.constData());
+ QVariant ret;
+ // Processing command on server side.
+ if (command == XQServiceCmd_Send) {
+ //Only support 1 sharable file, so index is 0
+ ret=XQServiceChannel::sendLocally(channel, msg, data, aRequest->sharableFile(0) );
+ }
+ else if (command == XQServiceCmd_ReturnValueDelivered) {
+ XQServiceChannel::sendCommand(channel,XQServiceChannel::ReturnValueDelivered);
+ }
+
+ if (XQService::serviceThreadData()->latestError() ||
+ !aRequest->isAsync()) {
+ ret=completeRequest(index,ret);
+ }
+ XQSERVICE_DEBUG_PRINT("ret: %d", result);
+ return result;
+}
+
+/*!
+ * From MServiceIPCObserver
+ * \see MServiceIPCObserver::handleCancelRequest( ServiceIPCRequest *aRequest )
+ */
+void XQServiceIpcClient::handleCancelRequest(ServiceIPCRequest* aRequest)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleCancelRequest isServer?=%d", server);
+ if (server)
+ {
+ // Save the request to be cancelled if service provider wants to as
+ // XQRequestInfo for details
+ // Valid only upon sendCommand call
+ cancelledRequest = aRequest;
+
+ //Attention! At the moment in server side channel name and connection name are the same
+ // it might be that in the future will be different then this is not valid anymore.
+ XQServiceChannel::sendCommand(mIpcConName,XQServiceChannel::ClientDisconnected);
+
+ // Remember to reset immediatelly
+ cancelledRequest = 0;
+
+ cancelRequest(aRequest);
+ }
+}
+
+/*
+* From MServiceIPCObserver
+* \see MServiceIPCObserver::handleDeleteRequest( ServiceIPCRequest *aRequest )
+*/
+void XQServiceIpcClient::handleDeleteRequest(ServiceIPCRequest* aRequest)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::handleDeleteRequest isServer?=%d, reqId=", server);
+ if (server)
+ {
+ cancelRequest(aRequest);
+ }
+}
+
+bool XQServiceIpcClient::cancelRequest(ServiceIPCRequest* aRequest) {
+ bool ret(false);
+
+ if (aRequest == NULL)
+ return ret;
+
+ if (server) {
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelRequest, isServer?=%d, reqId=%d", server, aRequest->id());
+ if (requestsMap.contains(aRequest->id())) {
+ requestsMap.take(aRequest->id()); // Use "take" not to delete the request !!
+ ret = true;
+ } else {
+ ret = false;
+ }
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelRequest, ret=%d", ret);
+ }
+ return ret;
+}
+
+bool XQServiceIpcClient::sendChannelCommand(int cmd, const QString& ch)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::sendChannelCommand, isServer?=%d", server);
+ XQSERVICE_DEBUG_PRINT("cmd: %d, ch: %s", cmd, qPrintable(ch));
+ if (!connectToServer()){
+ XQSERVICE_DEBUG_PRINT("Couldn't connect to the server");
+ return false;
+ }
+ int len = ch.length() * 2 + sizeof(XQServicePacketHeader);
+ XQSERVICE_DEBUG_PRINT("cmd: %d", len);
+ int writelen;
+ char *buf;
+ bool freeBuf = false;
+ if (len <= minPacketSize) {
+ buf = outBuffer;
+ memset(buf + len, 0, minPacketSize - len);
+ writelen = minPacketSize;
+ } else {
+ buf = new char [len];
+ writelen = len;
+ freeBuf = true;
+ }
+ XQSERVICE_DEBUG_PRINT("writelen: %d", writelen);
+ XQServicePacketHeader *header = (XQServicePacketHeader *)buf;
+ header->command = cmd;
+ header->totalLength = len;
+ header->chLength = ch.length();
+ header->msgLength = 0;
+ header->dataLength = 0;
+ char *ptr = buf + sizeof(XQServicePacketHeader);
+ memcpy(ptr, ch.constData(), ch.length() * 2);
+ QByteArray sndBuf(buf,writelen);
+ XQSERVICE_DEBUG_PRINT("sndBuf: %s", sndBuf.constData());
+
+ bool ret = serviceIpc->sendSync("sendChannelCommand",sndBuf);
+
+ if (freeBuf)
+ delete[] buf;
+
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::sendChannelCommand: ret=%d", ret);
+ return ret;
+}
+
+bool XQServiceIpcClient::send(const QString& ch,
+ const QString& msg,
+ const QByteArray& data,
+ QByteArray &retData,
+ int cmd)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::send, isServer?=%d", server);
+
+ // Attension. The 'ch' name may contain unique session identifier to separate requests going
+ // the same channel. Before real IPC calls need to get the normalized channel name.
+ // The 'mIpcConName' contains the same session identifier to separate connections using the same
+ // channel name.
+ QString channel = XQRequestUtil::channelName(ch);
+
+ XQSERVICE_DEBUG_PRINT("\tchannel: %s, msg: %s", qPrintable(channel), qPrintable(msg));
+ XQSERVICE_DEBUG_PRINT("\tdata: %s, cmd: %d", data.constData(), cmd);
+
+ XQService::serviceThreadData()->setLatestError(KErrNone);
+ if (!connectToServer()){
+ XQSERVICE_DEBUG_PRINT("\tCouldn't connect to the server");
+ return false;
+ }
+
+#ifdef QT_S60_AIW_PLUGIN
+ if (plugin) {
+ QVariant ret=XQServiceChannel::sendLocally(channel, msg, data);
+ retData = XQServiceThreadData::serializeRetData(ret, XQService::serviceThreadData()->latestError());
+ return true;
+ }
+#endif
+ int len = channel.length() * 2 + msg.length() * 2 + data.length();
+ len += sizeof(XQServicePacketHeader);
+ XQSERVICE_DEBUG_PRINT("\tcmd: %d", len);
+ int writelen;
+ char *buf;
+ bool freeBuf = false;
+ if (len <= minPacketSize) {
+ buf = outBuffer;
+ memset(buf + len, 0, minPacketSize - len);
+ writelen = minPacketSize;
+ } else {
+ buf = new char [len];
+ writelen = len;
+ freeBuf = true;
+ }
+ XQSERVICE_DEBUG_PRINT("\twritelen: %d", writelen);
+ XQServicePacketHeader *header = (XQServicePacketHeader *)buf;
+ header->command = cmd;
+ header->totalLength = len;
+ header->chLength = channel.length();
+ header->msgLength = msg.length();
+ header->dataLength = data.length();
+ char *ptr = buf + sizeof(XQServicePacketHeader);
+ memcpy(ptr, channel.constData(), channel.length() * 2);
+ ptr += channel.length() * 2;
+ memcpy(ptr, msg.constData(), msg.length() * 2);
+ ptr += msg.length() * 2;
+ memcpy(ptr, data.constData(), data.length());
+ QByteArray sndBuf(buf,writelen);
+ XQSERVICE_DEBUG_PRINT("\tsndBuf: %s", sndBuf.constData());
+ bool ret = true;
+ XQSERVICE_DEBUG_PRINT("\tsynchronous: %d", synchronous);
+
+ if (synchronous) {
+
+ ret=serviceIpc->sendSync("send",sndBuf);
+ if (ret) {
+ retData=serviceIpc->readAll();
+ XQSERVICE_DEBUG_PRINT("\t readAll done, error=%d", XQService::serviceThreadData()->latestError());
+ if (!XQService::serviceThreadData()->latestError())
+ {
+ // No point to send channel command on error. Error could be also
+ // caused by server exit without completing the actual request
+ sendChannelCommand(XQServiceCmd_ReturnValueDelivered,channel);
+ }
+ else
+ ret = false;
+ }
+ }
+ else {
+ // At the moment we can not have multiple send async
+ if (serviceIpc->requestPending()) {
+ XQSERVICE_DEBUG_PRINT("Request already pending");
+ XQService::serviceThreadData()->setLatestError(ServiceFwIPC::ERequestPending); // maparnan
+ ret = false ;
+ }
+ else {
+ serviceIpc->sendAsync("send",sndBuf);
+ ret = true;
+ }
+ }
+ if (freeBuf)
+ delete[] buf;
+ XQSERVICE_DEBUG_PRINT("\tret: %d", ret);
+ return ret;
+}
+
+
+/*!
+ * This method cancels requests.
+ */
+bool XQServiceIpcClient::cancelPendingSend(const QString& ch)
+{
+ Q_UNUSED(ch); //
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::cancelPendingSend, isServer?=%d", server);
+ if (serviceIpc) {
+ // Close the client connection silently
+ disconnect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int)));
+ XQService::serviceThreadData()->closeClientConnection(mIpcConName);
+ // No callback wanted any more
+ callBackRequestComplete = NULL;
+ }
+
+ return true;
+}
+
+void XQServiceIpcClient::disconnected()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::disconnected START");
+ XQSERVICE_DEBUG_PRINT("\t server: %d, lastId=%d", server, lastId);
+ if (server) {
+ // Closing down IPC
+ ServiceIPCRequest* request = NULL;
+
+ //
+ // Go through all requests and send disconnected error to them
+ //
+ QHashIterator<int, ServiceIPCRequest*> iter(requestsMap);
+ while (iter.hasNext()) {
+ iter.next();
+ int reqId = iter.key();
+ request=iter.value();
+ XQSERVICE_DEBUG_PRINT("\t request iter: id=%d", reqId);
+ XQSERVICE_DEBUG_PRINT("\t request iter requestAsync=%d", request->isAsync());
+ if (request->isAsync()) {
+ QVariant ret;
+ // Consider server side end as connection closure.
+ XQService::serviceThreadData()->setLatestError(ServiceFwIPC::EConnectionClosed);
+ completeRequest(reqId, ret);
+ // In disconnnect phase let's wait a bit in order to be sure
+ // That completeRequest and application exit notification event goes in the client side
+ wait(200);
+ }
+ }
+ if (serviceIpcServer) {
+ serviceIpcServer->disconnect();
+ delete serviceIpcServer;
+ serviceIpcServer = NULL;
+ XQSERVICE_DEBUG_PRINT("\tXQServiceIpcClient deleteLater");
+ wait(200);
+ XQSERVICE_DEBUG_PRINT("\tXQServiceIpcClient deleteLater over");
+ }
+ } else {
+ if (sendSyncLoop && sendSyncLoop->isRunning()) {
+ XQSERVICE_DEBUG_PRINT("Quit sendSyncLoop");
+ sendSyncLoop->quit();
+ }
+ if (serviceIpc) {
+ XQSERVICE_DEBUG_PRINT("Disconnect serviceIpc");
+ serviceIpc->disconnect();
+ delete serviceIpc;
+ serviceIpc = NULL;
+ }
+ }
+ deleteLater();
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::disconnected END");
+}
+
+void XQServiceIpcClient::clientError(int error)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::clientError, isServer?=%d", server);
+ XQSERVICE_DEBUG_PRINT("error: %d", error);
+
+
+ if (serviceIpc) {
+ XQService::serviceThreadData()->setLatestError(error);
+ disconnect(serviceIpc, SIGNAL(error(int)), this, SLOT(clientError(int)));
+ //disconnected();
+ XQService::serviceThreadData()->closeClientConnection(mIpcConName);
+ }
+
+ //complete the client request with error value
+ if (callBackRequestComplete) {
+ XQSERVICE_DEBUG_PRINT("requestErrorAsync mapped error=%d", error);
+ callBackRequestComplete->requestErrorAsync(error);
+ }
+ XQSERVICE_DEBUG_PRINT("clientError end mapped error=%d", error);
+}
+
+/**
+* Async read operation
+*/
+
+void XQServiceIpcClient::readyRead()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::readyRead, isServer?=%d", server);
+
+ // Clear error
+ XQService::serviceThreadData()->setLatestError(KErrNone);
+
+ //in case it has been connected before
+ //this prevents calling twice of the callback functions
+ disconnect(serviceIpc, SIGNAL(ReadDone()), this, SLOT(readDone()));
+ connect(serviceIpc, SIGNAL(ReadDone()), this, SLOT(readDone()));
+ serviceIpc->readAll( iRetData );
+}
+
+
+/**
+* readDone, send return value back to client
+*/
+void XQServiceIpcClient::readDone()
+ {
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::readDone");
+ QVariant retValue = XQServiceThreadData::deserializeRetData(iRetData);
+
+#ifdef XQSERVICE_DEBUG
+ QString s = retValue.toString();
+ int len=s.length();
+ XQSERVICE_DEBUG_PRINT("retValue: type=%s,len=%d,value(max.1024)=%s",
+ retValue.typeName(),len,qPrintable(s.left(1024)));
+#endif
+ int err = XQService::serviceThreadData()->latestError();
+ XQSERVICE_DEBUG_PRINT("err: %d", err);
+
+ if (err)
+ {
+ XQSERVICE_DEBUG_PRINT("there is error!");
+ //emitError(err);
+ clientError(err);
+ }
+ else if (iRetData.length())
+ {
+ XQSERVICE_DEBUG_PRINT("there is return data");
+ if (callBackRequestComplete &&
+// !retValue.isNull() && (retValue.type() != QVariant::Invalid)) maparnan
+ retValue.isValid())
+ {
+ XQSERVICE_DEBUG_PRINT("before compelete async request");
+
+ //should this send before compete the request ?
+ //Attention ! Map mIpcConName name may contain unique identifier to separate connections using the same
+ // channel name. So need to get channel name.
+ QString channel = XQRequestUtil::channelName(mIpcConName);
+ sendChannelCommand(XQServiceCmd_ReturnValueDelivered, channel);
+
+ callBackRequestComplete->requestCompletedAsync( retValue );
+ XQSERVICE_DEBUG_PRINT("After complete async request");
+ }
+ else
+ {
+ clientError( KErrUnknown );
+ }
+ //attention at the moment channel name and connection name are the same
+ // it might be that in the future will be different then this is not valid anymore.
+ //sendChannelCommand(XQServiceCmd_ReturnValueDelivered,mIpcConName);
+ }
+ else
+ {
+ //err is KErrNone but no return value
+ //reading failed
+ clientError( KErrUnknown );
+ }
+ }
+
+
+int XQServiceIpcClient::setCurrentRequest(ServiceIPCRequest* request)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequest START");
+ XQSERVICE_DEBUG_PRINT("\t isServer=%d", server);
+ int id = -1;
+ if (request) {
+ lastId = lastId + 1;
+ XQSERVICE_DEBUG_PRINT("\t new id=%d assigned to current request", lastId);
+ request->setAsync(false);
+ request->setId(lastId);
+ requestsMap.insert(lastId, request);
+ id = lastId;
+ } else {
+ XQSERVICE_DEBUG_PRINT("\t request was NULL");
+ }
+ XQSERVICE_DEBUG_PRINT("\t returning id=%d", id);
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequest END");
+ return id;
+}
+
+//
+// This function need to be called during a slot call before returning from
+// the slot.
+// The lastId might change after returning from the slot call as
+// other possible requests may arrive
+//
+int XQServiceIpcClient::setCurrentRequestAsync()
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setCurrentRequestAsync");
+ XQSERVICE_DEBUG_PRINT("\t isServer=%d", server);
+ ServiceIPCRequest* request = requestPtr(lastId);
+ int id = -1;
+
+ if (request) {
+ request->setAsync(true);
+ id = request->id();
+ }
+
+ XQSERVICE_DEBUG_PRINT("\t returning request's id=%d", id);
+ return id;
+}
+
+bool XQServiceIpcClient::completeRequest(int index, const QVariant& retValue)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest START");
+ XQSERVICE_DEBUG_PRINT("\t isServer=%d", server);
+ XQSERVICE_DEBUG_PRINT("\t index=%d", index);
+#ifdef XQSERVICE_DEBUG
+ QString s = retValue.toString();
+ int len=s.length();
+ XQSERVICE_DEBUG_PRINT("retValue: type=%s,len=%d,value(max.1024)=%s",
+ retValue.typeName(),len,qPrintable(s.left(1024)));
+#endif
+
+ ServiceIPCRequest* request = requestPtr(index);
+ if (!request){
+ XQSERVICE_DEBUG_PRINT("\t request = NULL");
+ XQSERVICE_DEBUG_PRINT("\t return false");
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (1)");
+ return false;
+ }
+#ifdef QT_S60_AIW_PLUGIN
+ if (plugin) {
+ if (callBackRequestComplete &&
+ !retValue.isNull() && (retValue.type() != QVariant::Invalid))
+ {
+ callBackRequestComplete->requestCompletedAsync(retValue);
+ }
+ XQSERVICE_DEBUG_PRINT("\t return true");
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (2)");
+ return true;
+ }
+#endif
+ QByteArray array = XQServiceThreadData::serializeRetData(retValue,
+ XQService::serviceThreadData()->latestError() );
+ XQSERVICE_DEBUG_PRINT("\t array: %s", array.constData());
+ XQService::serviceThreadData()->setLatestError(KErrNone);
+ request->write(array);
+ bool ret = request->completeRequest();
+ // cancelRequest(request);
+ XQSERVICE_DEBUG_PRINT("\t return %d", ret);
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::completeRequest END (3)");
+ return ret;
+}
+
+
+//
+// This function need to be called during a slot call before returning from
+// the slot.
+// The lastId might change after returning from the slot call as
+// other possible requests may arrive
+//
+XQRequestInfo XQServiceIpcClient::requestInfo() const
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::requestInfo");
+ XQSERVICE_DEBUG_PRINT("\t isServer=%d", server);
+ ServiceIPCRequest* request = requestPtr(lastId);
+
+ if (request) {
+ return request->requestInfo();
+ }
+ return XQRequestInfo();
+}
+
+//
+// This internal function need to be called before a slot call to set the request info
+// The provider can then call requestInfo() to get the data.
+// The lastId might change after returning from the slot call as
+// other possible requests may arrive
+//
+bool XQServiceIpcClient::setRequestInfo(XQRequestInfo &info)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::setRequestInfo");
+ XQSERVICE_DEBUG_PRINT("\t isServer=%d", server);
+ ServiceIPCRequest* request = requestPtr(lastId);
+
+ if (request) {
+ request->setRequestInfo(&info);
+ }
+ return request != NULL;
+}
+
+
+// in disconnnect phase let's wait a bit in order to be sure
+// that completeRequest and application exit notification event goes in the client side
+void XQServiceIpcClient::wait(int msec)
+{
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait, isServer?=%d", server);
+
+ if (server)
+ return;
+
+ User::After(1000 * msec); //Contribution from Seppo
+
+ /*
+ if (!QCoreApplication::instance())
+ {
+ User::After(1000 * msec); //Contribution from Seppo
+ return;
+ }
+
+ QTime t1 = QTime::currentTime();
+ QEventLoop w = QEventLoop();
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait start");
+ QTimer::singleShot(msec, &w, SLOT(quit()));
+ w.exec();
+ QTime t2 = QTime::currentTime();
+ XQSERVICE_DEBUG_PRINT("XQServiceIpcClient::wait end elapsed=%d", t1.msecsTo(t2));
+ */
+}
+
+//
+// Returns the handle of the current request
+//
+ServiceIPCRequest *XQServiceIpcClient::requestPtr(int index) const
+{
+ ServiceIPCRequest* request = NULL;
+
+ // If request is being cancelled (saved by handleCancelRequest()) use it's id instead
+ // By that way service provider can access the XQRequestInfo of the cancelled request
+ // Upon handling clientDisconnected
+ if (cancelledRequest)
+ {
+ index = cancelledRequest->id();
+ XQSERVICE_DEBUG_PRINT("\t Cancelled request id=%d", index);
+ }
+
+ if (requestsMap.contains(index)) {
+ XQSERVICE_DEBUG_PRINT("\t request having id=%d FOUND", index);
+ request = requestsMap[index];
+ } else {
+ XQSERVICE_DEBUG_PRINT("\t request having id=%d NOT FOUND", index);
+ }
+
+ return request;
+
+}