diff -r 885c2596c964 -r 5d007b20cfd0 qthighway/xqservice/src/xqserviceipcclient.cpp --- /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 +#include +#include +#include +#include +#ifdef QT_S60_AIW_PLUGIN +#include +#include +#include +#endif +#include +#include +#include + +#include + +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 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(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 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; + +}