utilities/serviceipcclient/platform/qt/serviceipclocalsocket.cpp
changeset 16 3c88a81ff781
--- /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 <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <QByteArray>
+#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