diff -r 6aeb7a756187 -r 3c88a81ff781 utilities/serviceipcclient/platform/qt/serviceipclocalsocket.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utilities/serviceipcclient/platform/qt/serviceipclocalsocket.cpp Fri Oct 15 17:30:59 2010 -0400 @@ -0,0 +1,289 @@ +/** + This file is part of CWRT package ** + + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** + + 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 . +*/ + + +#include +#include "serviceipclocalsocket_p.h" + +namespace WRT +{ +// CONSTANTS +const char* REQUEST_COMPLETE_TOKEN = ";ROK"; +const int REQUEST_COMPLETE_TOKEN_LENGTH = 4; +const char REQUEST_DELIMITER_TOKEN = ';'; +/*! + \class ServiceLocalSocketIPC + QLocalSocket based IPC client-side backend + */ + +/*! + Constructor + */ +ServiceLocalSocketIPC::ServiceLocalSocketIPC() : m_BufferType( ENoBuffer ) +{ + m_Socket = new QLocalSocket(); + QObject::connect(m_Socket, SIGNAL( error( QLocalSocket::LocalSocketError ) ), + this, SLOT( handleError( QLocalSocket::LocalSocketError ) ) ); +} + +/*! + Destructor + */ + +ServiceLocalSocketIPC::~ServiceLocalSocketIPC() +{ + delete m_Socket; +} + +/*! + Connect to the server + @param aServerName name of the server to connect to + @return true if connected, false otherwise + */ +bool ServiceLocalSocketIPC::connect(const QString& aServerName) +{ + bool rtn; + m_Socket->connectToServer(aServerName); + rtn = m_Socket->waitForConnected(); + return rtn; +} + +/*! + Disconnect from the server + */ +void ServiceLocalSocketIPC::disconnect() +{ + m_Socket->close(); +} + +/*! + Starts the service + @param aServerName name of the server to connect to + @param aExeName name of the server executable + @return true if server started, false otherwise + */ +bool ServiceLocalSocketIPC::startServer(const QString& aServerName, + const QString& aExeName) +{ + bool started(true); + + //Semaphore with 1 initial count, + //Use system semaphore to ensure no contention exists across multiple processes + //According to QT documentation for System Semaphores on Windows, + //the semaphore is automatically cleaned up if a process crashes, thus preventing deadlock + // + QSystemSemaphore funcSem(aServerName + FUNCTIONSEM, 1); + funcSem.acquire(); + + // Shared chunk to check if the server has been started or not + QSharedMemory sharedMem(aServerName); + char* data(NULL); + bool attached = sharedMem.attach(); + if (attached) { + data = (char*) sharedMem.data(); + } + + // Shared memory not created or the flag was not set properly + if (!attached || strcmp(data, SERVERNOTSTARTED) == 0) { + // Create the server wait semaphore. When the server has listened, + // it will signaled after listen has started + // + QSystemSemaphore sem(aServerName + SERVERSEM, 0); + + // Start the server, since this function is mutex'ed by the global semaphore + // only 1 process/thread can reach here + // + started = QProcess::startDetached(aExeName); + + // Wait until the server signals + if (started) { + sem.acquire(); + } + } + + // Test if server started successfully +#if _DEBUG + attached = sharedMem.attach(); + if( attached ) + { + data = (char*)sharedMem.data(); + if( strcmp( data, SERVERSTARTED ) == 0 ) + { + qDebug() << "Server Started Successfully"; + } + } +#endif // _DEBUG + // Free shared memory + sharedMem.detach(); + + // Release the function semaphore + funcSem.release(1); + return started; +} + +/*! + Send a request synchronously + @param aRequestType type of request, toAscii() will be called to serialize the data + @param aData aData data to send to the server + @return true if data is sent, false otherwise + */ +bool ServiceLocalSocketIPC::sendSync(const QString& aRequestType, + const QByteArray& aData) +{ + QByteArray data; + data.setNum(aData.length()); + data.append(REQUEST_DELIMITER_TOKEN); + data.append(aRequestType.toAscii()); + data.append(REQUEST_DELIMITER_TOKEN); + data.append(aData); + int count = m_Socket->write(data); + m_Socket->flush(); + m_BufferType = ESyncBuffer; + return (count > 0); +} + +/*! + Send a request asynchronously + @param aRequestType type of request, toAscii() will be called to serialize the data + @param aData data to send to the server + */ +void ServiceLocalSocketIPC::sendAsync(const QString& aRequestType, + const QByteArray& aData) +{ + QByteArray data; + data.setNum(aData.length()); + data.append(REQUEST_DELIMITER_TOKEN); + data.append(aRequestType.toAscii()); + data.append(REQUEST_DELIMITER_TOKEN); + data.append(aData); + m_Socket->write(data); + + // Connect the signal and reset aync data buffer + m_AsyncData.clear(); + QObject::connect(m_Socket, SIGNAL( readyRead() ), + this, SLOT( handleReadyRead() ) ); + m_BufferType = EAsyncBuffer; +} + +/*! + Reads all data pending in the buffer + @return QByteArray data that has been read + */ +QByteArray ServiceLocalSocketIPC::readAll() +{ + QByteArray result; + + // If asynchronous read all data from the socket + // + if ( m_BufferType == ESyncBuffer ) { + // Wait for all data to be completed before returning + // + bool done = false; + do { + result.append(m_Socket->readAll()); + if (result.right(REQUEST_COMPLETE_TOKEN_LENGTH) + == REQUEST_COMPLETE_TOKEN) { + // Chop the end token + result.chop(REQUEST_COMPLETE_TOKEN_LENGTH); + done = true; + } + } while (done == false); + } + // If async, return the internal databuffer + else if( m_BufferType == EAsyncBuffer ){ + // Should be just a d-ptr copy + result = m_AsyncData; + QObject::disconnect(m_Socket, SIGNAL( readyRead() ), + this, SLOT( handleReadyRead() ) ); + } + m_BufferType = ENoBuffer; + + return result; +} + +/*! + Waits until data is available for reading + @return bool true if data can be read + */ +bool ServiceLocalSocketIPC::waitForRead() +{ + return m_Socket->waitForReadyRead(); +} + +/*! + Handle any socket errors + @param socketError error + */ +void ServiceLocalSocketIPC::handleError(QLocalSocket::LocalSocketError aSocketError) +{ + // Use base class to send this + emitError(doMapErrors(aSocketError)); +} + +/*! + Handle when data is ready to be read + */ +void ServiceLocalSocketIPC::handleReadyRead() +{ + m_AsyncData.append(m_Socket->readAll()); + if (m_AsyncData.right(REQUEST_COMPLETE_TOKEN_LENGTH) + == REQUEST_COMPLETE_TOKEN) { + // Chop the end token + m_AsyncData.chop(REQUEST_COMPLETE_TOKEN_LENGTH); + + // Use base class to send signal when all the data has been assembled + emitReadyRead(); + } +} + +int ServiceLocalSocketIPC::doMapErrors( int aError ) +{ + int error(0); + + // Map QT Local Socket error codes to custom error codes + // + switch( aError ) { + case QLocalSocket::ConnectionError: + case QLocalSocket::ConnectionRefusedError: { + error = ServiceFwIPC::EConnectionError; + break; + } + case QLocalSocket::PeerClosedError: { + error = ServiceFwIPC::EConnectionClosed; + break; + } + case QLocalSocket::ServerNotFoundError: { + error = ServiceFwIPC::EServerNotFound; + break; + } + case QLocalSocket::SocketAccessError: + case QLocalSocket::SocketResourceError: + case QLocalSocket::SocketTimeoutError: + case QLocalSocket::DatagramTooLargeError: + case QLocalSocket::UnsupportedSocketOperationError: { + error = ServiceFwIPC::EIPCError; + break; + } + case QLocalSocket::UnknownSocketError: { + error = ServiceFwIPC::EUnknownError; + break; + } + } + return error; +} + +} +// END OF FILE