qthighway/xqservice/src/xqserviceipcclient.cpp
branchRCL_3
changeset 9 5d007b20cfd0
equal deleted inserted replaced
8:885c2596c964 9:5d007b20cfd0
       
     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 }