utilities/serviceipcclient/platform/qt/serviceipclocalsocket.cpp
changeset 16 3c88a81ff781
equal deleted inserted replaced
14:6aeb7a756187 16:3c88a81ff781
       
     1 /**
       
     2    This file is part of CWRT package **
       
     3 
       
     4    Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). **
       
     5 
       
     6    This program is free software: you can redistribute it and/or modify
       
     7    it under the terms of the GNU (Lesser) General Public License as
       
     8    published by the Free Software Foundation, version 2.1 of the License.
       
     9    This program is distributed in the hope that it will be useful, but
       
    10    WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    12    (Lesser) General Public License for more details. You should have
       
    13    received a copy of the GNU (Lesser) General Public License along
       
    14    with this program. If not, see <http://www.gnu.org/licenses/>.
       
    15 */
       
    16 
       
    17 
       
    18 #include <QByteArray>
       
    19 #include "serviceipclocalsocket_p.h"
       
    20 
       
    21 namespace WRT
       
    22 {
       
    23 // CONSTANTS
       
    24 const char* REQUEST_COMPLETE_TOKEN = ";ROK";
       
    25 const int REQUEST_COMPLETE_TOKEN_LENGTH = 4;
       
    26 const char REQUEST_DELIMITER_TOKEN = ';';
       
    27 /*!
       
    28  \class ServiceLocalSocketIPC
       
    29  QLocalSocket based IPC client-side backend
       
    30  */
       
    31 
       
    32 /*!
       
    33  Constructor
       
    34  */
       
    35 ServiceLocalSocketIPC::ServiceLocalSocketIPC() : m_BufferType( ENoBuffer )
       
    36 {
       
    37     m_Socket = new QLocalSocket();
       
    38     QObject::connect(m_Socket, SIGNAL( error( QLocalSocket::LocalSocketError ) ),
       
    39     this, SLOT( handleError( QLocalSocket::LocalSocketError ) ) );
       
    40 }
       
    41 
       
    42 /*!
       
    43  Destructor
       
    44  */
       
    45 
       
    46 ServiceLocalSocketIPC::~ServiceLocalSocketIPC()
       
    47 {
       
    48     delete m_Socket;
       
    49 }
       
    50 
       
    51 /*!
       
    52  Connect to the server
       
    53  @param aServerName name of the server to connect to
       
    54  @return true if connected, false otherwise
       
    55  */
       
    56 bool ServiceLocalSocketIPC::connect(const QString& aServerName)
       
    57 {
       
    58     bool rtn;
       
    59     m_Socket->connectToServer(aServerName);
       
    60     rtn = m_Socket->waitForConnected();
       
    61     return rtn;
       
    62 }
       
    63 
       
    64 /*!
       
    65  Disconnect from the server
       
    66  */
       
    67 void ServiceLocalSocketIPC::disconnect()
       
    68 {
       
    69     m_Socket->close();
       
    70 }
       
    71 
       
    72 /*!
       
    73  Starts the service
       
    74  @param aServerName name of the server to connect to
       
    75  @param aExeName name of the server executable
       
    76  @return true if server started, false otherwise
       
    77  */
       
    78 bool ServiceLocalSocketIPC::startServer(const QString& aServerName,
       
    79                                         const QString& aExeName)
       
    80 {
       
    81     bool started(true);
       
    82 
       
    83     //Semaphore with 1 initial count,
       
    84     //Use system semaphore to ensure no contention exists across multiple processes
       
    85     //According to QT documentation for System Semaphores on Windows, 
       
    86     //the semaphore is automatically cleaned up if a process crashes, thus preventing deadlock
       
    87     //
       
    88     QSystemSemaphore funcSem(aServerName + FUNCTIONSEM, 1);
       
    89     funcSem.acquire();
       
    90 
       
    91     // Shared chunk to check if the server has been started or not
       
    92     QSharedMemory sharedMem(aServerName);
       
    93     char* data(NULL);
       
    94     bool attached = sharedMem.attach();
       
    95     if (attached) {
       
    96         data = (char*) sharedMem.data();
       
    97     }
       
    98 
       
    99     // Shared memory not created or the flag was not set properly
       
   100     if (!attached || strcmp(data, SERVERNOTSTARTED) == 0) {
       
   101         // Create the server wait semaphore. When the server has listened, 
       
   102         // it will signaled after listen has started
       
   103         //
       
   104         QSystemSemaphore sem(aServerName + SERVERSEM, 0);
       
   105 
       
   106         // Start the server, since this function is mutex'ed by the global semaphore 
       
   107         // only 1 process/thread can reach here
       
   108         //
       
   109         started = QProcess::startDetached(aExeName);
       
   110 
       
   111         // Wait until the server signals
       
   112         if (started) {
       
   113             sem.acquire();
       
   114         }
       
   115     }
       
   116 
       
   117     // Test if server started successfully
       
   118 #if _DEBUG
       
   119     attached = sharedMem.attach();
       
   120     if( attached )
       
   121     {
       
   122         data = (char*)sharedMem.data();
       
   123         if( strcmp( data, SERVERSTARTED ) == 0 )
       
   124         {
       
   125             qDebug() << "Server Started Successfully";
       
   126         }
       
   127     }
       
   128 #endif // _DEBUG
       
   129     // Free shared memory
       
   130     sharedMem.detach();
       
   131 
       
   132     // Release the function semaphore
       
   133     funcSem.release(1);
       
   134     return started;
       
   135 }
       
   136 
       
   137 /*!
       
   138  Send a request synchronously
       
   139  @param aRequestType type of request, toAscii() will be called to serialize the data
       
   140  @param aData aData data to send to the server
       
   141  @return true if data is sent, false otherwise
       
   142  */
       
   143 bool ServiceLocalSocketIPC::sendSync(const QString& aRequestType,
       
   144                                      const QByteArray& aData)
       
   145 {
       
   146     QByteArray data;
       
   147     data.setNum(aData.length());
       
   148     data.append(REQUEST_DELIMITER_TOKEN);
       
   149     data.append(aRequestType.toAscii());
       
   150     data.append(REQUEST_DELIMITER_TOKEN);
       
   151     data.append(aData);
       
   152     int count = m_Socket->write(data);
       
   153     m_Socket->flush();
       
   154     m_BufferType = ESyncBuffer;
       
   155     return (count > 0);
       
   156 }
       
   157 
       
   158 /*!
       
   159  Send a request asynchronously
       
   160  @param aRequestType type of request, toAscii() will be called to serialize the data
       
   161  @param aData data to send to the server
       
   162  */
       
   163 void ServiceLocalSocketIPC::sendAsync(const QString& aRequestType,
       
   164                                       const QByteArray& aData)
       
   165 {
       
   166     QByteArray data;
       
   167     data.setNum(aData.length());
       
   168     data.append(REQUEST_DELIMITER_TOKEN);
       
   169     data.append(aRequestType.toAscii());
       
   170     data.append(REQUEST_DELIMITER_TOKEN);
       
   171     data.append(aData);
       
   172     m_Socket->write(data);
       
   173 
       
   174     // Connect the signal and reset aync data buffer
       
   175     m_AsyncData.clear();
       
   176     QObject::connect(m_Socket, SIGNAL( readyRead() ),
       
   177     this, SLOT( handleReadyRead() ) );
       
   178     m_BufferType = EAsyncBuffer;
       
   179 }
       
   180 
       
   181 /*!
       
   182  Reads all data pending in the buffer
       
   183  @return QByteArray data that has been read
       
   184  */
       
   185 QByteArray ServiceLocalSocketIPC::readAll()
       
   186 {
       
   187     QByteArray result;
       
   188 
       
   189     // If asynchronous read all data from the socket 
       
   190     //
       
   191     if ( m_BufferType == ESyncBuffer ) {
       
   192         // Wait for all data to be completed before returning
       
   193         //
       
   194         bool done = false;
       
   195         do {
       
   196             result.append(m_Socket->readAll());
       
   197             if (result.right(REQUEST_COMPLETE_TOKEN_LENGTH)
       
   198                             == REQUEST_COMPLETE_TOKEN) {
       
   199                 // Chop the end token
       
   200                 result.chop(REQUEST_COMPLETE_TOKEN_LENGTH);
       
   201                 done = true;
       
   202             }
       
   203         } while (done == false);
       
   204     }
       
   205     // If async, return the internal databuffer
       
   206     else if( m_BufferType == EAsyncBuffer ){
       
   207         // Should be just a d-ptr copy
       
   208         result = m_AsyncData;
       
   209         QObject::disconnect(m_Socket, SIGNAL( readyRead() ),
       
   210         this, SLOT( handleReadyRead() ) );
       
   211     }
       
   212     m_BufferType = ENoBuffer;
       
   213 
       
   214     return result;
       
   215 }
       
   216 
       
   217 /*!
       
   218  Waits until data is available for reading 
       
   219  @return bool true if data can be read
       
   220  */
       
   221 bool ServiceLocalSocketIPC::waitForRead()
       
   222 {
       
   223     return m_Socket->waitForReadyRead();
       
   224 }
       
   225 
       
   226 /*!
       
   227  Handle any socket errors
       
   228  @param socketError error
       
   229  */
       
   230 void ServiceLocalSocketIPC::handleError(QLocalSocket::LocalSocketError aSocketError)
       
   231 {
       
   232     // Use base class to send this
       
   233     emitError(doMapErrors(aSocketError));
       
   234 }
       
   235 
       
   236 /*!
       
   237  Handle when data is ready to be read
       
   238  */
       
   239 void ServiceLocalSocketIPC::handleReadyRead()
       
   240 {
       
   241     m_AsyncData.append(m_Socket->readAll());
       
   242     if (m_AsyncData.right(REQUEST_COMPLETE_TOKEN_LENGTH)
       
   243                     == REQUEST_COMPLETE_TOKEN) {
       
   244         // Chop the end token
       
   245         m_AsyncData.chop(REQUEST_COMPLETE_TOKEN_LENGTH);
       
   246 
       
   247         // Use base class to send signal when all the data has been assembled
       
   248         emitReadyRead();
       
   249     }
       
   250 }
       
   251 
       
   252 int ServiceLocalSocketIPC::doMapErrors( int aError )
       
   253 {
       
   254     int error(0);
       
   255     
       
   256     // Map QT Local Socket error codes to custom error codes
       
   257     //
       
   258     switch( aError ) {
       
   259     case QLocalSocket::ConnectionError:
       
   260     case QLocalSocket::ConnectionRefusedError: {
       
   261         error = ServiceFwIPC::EConnectionError;
       
   262         break;
       
   263         }
       
   264     case QLocalSocket::PeerClosedError: {
       
   265         error = ServiceFwIPC::EConnectionClosed;
       
   266         break;
       
   267         } 
       
   268     case QLocalSocket::ServerNotFoundError: {
       
   269         error = ServiceFwIPC::EServerNotFound;
       
   270         break;
       
   271         } 
       
   272     case QLocalSocket::SocketAccessError:
       
   273     case QLocalSocket::SocketResourceError:
       
   274     case QLocalSocket::SocketTimeoutError:
       
   275     case QLocalSocket::DatagramTooLargeError:
       
   276     case QLocalSocket::UnsupportedSocketOperationError: {
       
   277         error = ServiceFwIPC::EIPCError;
       
   278         break;
       
   279         }    
       
   280     case QLocalSocket::UnknownSocketError: {
       
   281         error = ServiceFwIPC::EUnknownError;
       
   282         break;
       
   283         }
       
   284     }
       
   285     return error;
       
   286 }
       
   287 
       
   288 }
       
   289 // END OF FILE