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