diff options
author | Marko Minkkinen <marko.minkkinen@digia.com> | 2011-03-16 14:39:18 +0200 |
---|---|---|
committer | Marko Minkkinen <marko.minkkinen@digia.com> | 2011-03-16 14:39:18 +0200 |
commit | 5be759133aced16dcbfba0670e1fb3cf15c4f79a (patch) | |
tree | 07f15403e2d30fd1811c2aa477751092fcaafd7f | |
parent | e34b39d4951acf47f09a477e90c0fca1f2455058 (diff) |
First version of Symbian IPC for QCOP
20 files changed, 1776 insertions, 0 deletions
diff --git a/src/libraries/qmfclient/qmfclient.pro b/src/libraries/qmfclient/qmfclient.pro index c0b84290..67447e89 100644 --- a/src/libraries/qmfclient/qmfclient.pro +++ b/src/libraries/qmfclient/qmfclient.pro @@ -35,6 +35,22 @@ symbian: { LIBS += -lsqldb } + contains(CONFIG, SYMBIAN_USE_IPC_SOCKET) { + DEFINES += SYMBIAN_USE_IPC_SOCKET + + INCLUDEPATH += symbian + PRIVATE_HEADERS += symbian/qmfipcchannelclient/qmfipcchannelclientservercommon.h \ + symbian/qmfipcchannelclient/qmfipcchannelsession.h \ + symbian/qmfipcchannelclient/qmfipcchannel.h \ + symbian/ipcsocket.h \ + symbian/ipcserver.h + + SOURCES += symbian/qmfipcchannelclient/qmfipcchannelsession.cpp \ + symbian/qmfipcchannelclient/qmfipcchannel.cpp \ + symbian/ipcsocket.cpp \ + symbian/ipcserver.cpp + } + INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE TARGET.EPOCALLOWDLLDATA = 1 diff --git a/src/libraries/qmfclient/support/qcopchannel.cpp b/src/libraries/qmfclient/support/qcopchannel.cpp index 6135bfbe..fc00868f 100644 --- a/src/libraries/qmfclient/support/qcopchannel.cpp +++ b/src/libraries/qmfclient/support/qcopchannel.cpp @@ -1108,8 +1108,13 @@ void QCopClient::connectSignals() { connect(device, SIGNAL(readyRead()), this, SLOT(readyRead())); #ifndef QT_NO_QCOP_LOCAL_SOCKET +#ifdef SYMBIAN_USE_IPC_SOCKET + if (socket) + connect(socket, SIGNAL(stateChanged(SymbianIpcSocket::SymbianIpcSocketState)), this, SLOT(disconnected())); +#else if (socket) connect(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), this, SLOT(disconnected())); +#endif #else if (socket) { connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected())); diff --git a/src/libraries/qmfclient/support/qcopchannel_p.h b/src/libraries/qmfclient/support/qcopchannel_p.h index 2f85d59f..c65d22a4 100644 --- a/src/libraries/qmfclient/support/qcopchannel_p.h +++ b/src/libraries/qmfclient/support/qcopchannel_p.h @@ -54,6 +54,14 @@ // #include <QtCore/qobject.h> +#ifdef SYMBIAN_USE_IPC_SOCKET +#include <QtCore/qmap.h> +#include <QtNetwork/qlocalsocket.h> +#include "ipcsocket.h" +#include "ipcserver.h" +typedef SymbianIpcSocket QCopLocalSocket; +typedef SymbianIpcServer QCopLocalServer; +#else #ifndef QT_NO_QCOP_LOCAL_SOCKET #include <QtNetwork/qlocalsocket.h> #include <QtNetwork/qlocalserver.h> @@ -65,6 +73,7 @@ typedef QLocalServer QCopLocalServer; typedef QTcpSocket QCopLocalSocket; typedef QTcpServer QCopLocalServer; #endif +#endif #include <QtCore/qshareddata.h> #include <QtCore/qregexp.h> #include <qringbuffer_p.h> diff --git a/src/libraries/qmfclient/symbian/ipcserver.cpp b/src/libraries/qmfclient/symbian/ipcserver.cpp new file mode 100644 index 00000000..7ce765be --- /dev/null +++ b/src/libraries/qmfclient/symbian/ipcserver.cpp @@ -0,0 +1,102 @@ +#include "ipcserver.h" + +#include <QQueue> +#include <private/qobject_p.h> +#include "qmfipcchannel.h" +#include "ipcsocket.h" + +class SymbianIpcServerPrivate : public QObjectPrivate, public SymbianQMFIPCChannelIncomingConnectionObserver +{ + Q_DECLARE_PUBLIC(SymbianIpcServer) + +public: + SymbianIpcServerPrivate(); + ~SymbianIpcServerPrivate(); + +public: // From SymbianQMFIPCChannelIncomingConnectionObserver + virtual void NewConnection(quintptr connectionId); + +public: // Data + QString m_channelName; + quintptr m_connectionId; + int m_maxPendingConnections; + QQueue<SymbianIpcSocket*> m_pendingConnections; + mutable SymbianQMFIPCChannel m_channel; +}; + +SymbianIpcServerPrivate::SymbianIpcServerPrivate() + : m_channelName(), + m_connectionId(0), + m_maxPendingConnections(30) +{ + m_channel.connect(); +} + +SymbianIpcServerPrivate::~SymbianIpcServerPrivate() +{ +} + +void SymbianIpcServerPrivate::NewConnection(quintptr connectionId) +{ + Q_Q(SymbianIpcServer); + q->incomingConnection(connectionId); +} + +SymbianIpcServer::SymbianIpcServer(QObject *parent) + : QObject(*new SymbianIpcServerPrivate, parent) +{ +} + +SymbianIpcServer::~SymbianIpcServer() +{ + Q_D(SymbianIpcServer); + d->m_channel.destroyChannel(d->m_channelName); + qDeleteAll(d->m_pendingConnections); + d->m_pendingConnections.clear(); +} + +bool SymbianIpcServer::listen(const QString &name) +{ + Q_D(SymbianIpcServer); + if (!d->m_channelName.isEmpty()) { + d->m_channel.destroyChannel(d->m_channelName); + } + d->m_channelName = name; + if (d->m_channel.createChannel(name)) { + return d->m_channel.waitForIncomingConnection(d); + } + + return false; +} + +bool SymbianIpcServer::hasPendingConnections() const +{ + Q_D(const SymbianIpcServer); + return !(d->m_pendingConnections.isEmpty()); +} + +SymbianIpcSocket *SymbianIpcServer::nextPendingConnection() +{ + Q_D(SymbianIpcServer); + + if (d->m_pendingConnections.isEmpty()) { + return 0; + } + + return d->m_pendingConnections.dequeue(); +} + +void SymbianIpcServer::incomingConnection(quintptr socketDescriptor) +{ + Q_D(SymbianIpcServer); + + SymbianIpcSocket *socket = new SymbianIpcSocket(this); + socket->setSocketDescriptor(socketDescriptor); + d->m_pendingConnections.enqueue(socket); + + emit newConnection(); + + d->m_channel.waitForIncomingConnection(d); +} + +// End of File diff --git a/src/libraries/qmfclient/symbian/ipcserver.h b/src/libraries/qmfclient/symbian/ipcserver.h new file mode 100644 index 00000000..27606929 --- /dev/null +++ b/src/libraries/qmfclient/symbian/ipcserver.h @@ -0,0 +1,34 @@ +#ifndef IPCSERVER_H +#define IPCSERVER_H + +#include <QtNetwork/qabstractsocket.h> + +class SymbianIpcServerPrivate; +class SymbianIpcSocket; + +class SymbianIpcServer : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(SymbianIpcServer) + +public: + SymbianIpcServer(QObject *parent = 0); + ~SymbianIpcServer(); + + virtual bool hasPendingConnections() const; + virtual SymbianIpcSocket *nextPendingConnection(); + bool listen(const QString &name); + +protected: + virtual void incomingConnection(quintptr socketDescriptor); + +Q_SIGNALS: + void newConnection(); + +private: + Q_DISABLE_COPY(SymbianIpcServer) +}; + +#endif // IPCSERVER_H + +// End of File diff --git a/src/libraries/qmfclient/symbian/ipcsocket.cpp b/src/libraries/qmfclient/symbian/ipcsocket.cpp new file mode 100644 index 00000000..95161fee --- /dev/null +++ b/src/libraries/qmfclient/symbian/ipcsocket.cpp @@ -0,0 +1,187 @@ +#include "ipcsocket.h" + +#include <QEventLoop> +#include <QTimer> +#include "private/qiodevice_p.h" +#include "qmfipcchannel.h" + +class SymbianIpcSocketPrivate : public QIODevicePrivate, public SymbianQMFIPCChannelObserver +{ + Q_DECLARE_PUBLIC(SymbianIpcSocket) + +public: + SymbianIpcSocketPrivate(); + SymbianIpcSocketPrivate(const SymbianIpcSocketPrivate& other); // Not used + ~SymbianIpcSocketPrivate(); + +public: // From SymbianQMFIPCChannelDataObserver + virtual void Connected(quintptr connectionId); + virtual void ConnectionRefused(); + virtual void Disconnected(); + virtual void DataAvailable(); + +public: // Data + SymbianIpcSocket::OpenMode m_openMode; + SymbianIpcSocket::SymbianIpcSocketError m_error; + QString m_channelName; + quintptr m_connectionId; + SymbianIpcSocket::SymbianIpcSocketState m_state; + mutable SymbianQMFIPCChannel m_channel; +}; + +SymbianIpcSocketPrivate::SymbianIpcSocketPrivate() + : QIODevicePrivate(), + m_openMode(QIODevice::NotOpen), + m_error(SymbianIpcSocket::UnknownSocketError), + m_channelName(), + m_connectionId(0), + m_state(SymbianIpcSocket::UnconnectedState) +{ + m_channel.connect(); +} + +SymbianIpcSocketPrivate::SymbianIpcSocketPrivate(const SymbianIpcSocketPrivate& /*other*/) +{ + // Not used +} + +SymbianIpcSocketPrivate::~SymbianIpcSocketPrivate() +{ +} + +void SymbianIpcSocketPrivate::Connected(quintptr connectionId) +{ + Q_Q(SymbianIpcSocket); + m_connectionId = connectionId; + m_state = SymbianIpcSocket::ConnectedState; + emit q->stateChanged(m_state); + emit q->connected(); + q->setSocketDescriptor(m_connectionId, SymbianIpcSocket::ConnectedState, m_openMode); +} + +void SymbianIpcSocketPrivate::ConnectionRefused() +{ + Q_Q(SymbianIpcSocket); + + SymbianIpcSocket::SymbianIpcSocketState currentState = m_state; + + m_error = SymbianIpcSocket::ServerNotFoundError; + m_state = SymbianIpcSocket::UnconnectedState; + + if (currentState != m_state) { + emit q->stateChanged(m_state); + if (m_state == SymbianIpcSocket::UnconnectedState) { + emit q->disconnected(); + } + } + emit q->error(m_error); +} + +void SymbianIpcSocketPrivate::Disconnected() +{ + Q_Q(SymbianIpcSocket); + + m_state = SymbianIpcSocket::UnconnectedState; + emit q->stateChanged(m_state); + emit q->disconnected(); +} + +void SymbianIpcSocketPrivate::DataAvailable() +{ + Q_Q(SymbianIpcSocket); + emit q->readyRead(); +} + +SymbianIpcSocket::SymbianIpcSocket(QObject *parent) + : QIODevice(*new SymbianIpcSocketPrivate, parent) +{ +} + +SymbianIpcSocket::~SymbianIpcSocket() +{ +} + +void SymbianIpcSocket::connectToServer(const QString &name, OpenMode openMode) +{ + Q_D(SymbianIpcSocket); + if (state() == ConnectedState || state() == ConnectingState) { + return; + } + + d->m_openMode = openMode; + d->m_channel.connectClientToChannel(name, d); + d->m_state = SymbianIpcSocket::ConnectingState; + d->m_channelName = name; + emit stateChanged(d->m_state); +} + +bool SymbianIpcSocket::flush() +{ + return true; +} + +bool SymbianIpcSocket::setSocketDescriptor(quintptr socketDescriptor, + SymbianIpcSocketState socketState, + OpenMode openMode) +{ + Q_D(SymbianIpcSocket); + QIODevice::open(openMode); + d->m_state = socketState; + if (d->m_connectionId == 0) { + d->m_channel.connectServerToChannel(socketDescriptor, d); + d->m_connectionId = socketDescriptor; + } + d->m_channel.startWaitingForData(); + return true; +} + +SymbianIpcSocket::SymbianIpcSocketState SymbianIpcSocket::state() const +{ + Q_D(const SymbianIpcSocket); + return d->m_state; +} + +bool SymbianIpcSocket::isSequential() const +{ + return true; +} + +qint64 SymbianIpcSocket::bytesAvailable() const +{ + Q_D(const SymbianIpcSocket); + qint64 bytes = d->m_channel.dataSize() + QIODevice::bytesAvailable(); + return bytes; +} + +bool SymbianIpcSocket::waitForConnected(int msecs) +{ + Q_D(SymbianIpcSocket); + if (state() != ConnectingState) { + return (state() == ConnectedState); + } + + QEventLoop eventLoop; + QObject::connect(this, SIGNAL(connected()), &eventLoop, SLOT(quit())); + QObject::connect(this, SIGNAL(disconnected()), &eventLoop, SLOT(quit())); + QTimer::singleShot(msecs, &eventLoop, SLOT(quit())); + eventLoop.exec(); + + return (state() == ConnectedState); +} + +qint64 SymbianIpcSocket::readData(char *data, qint64 maxlen) +{ + Q_D(const SymbianIpcSocket); + return d->m_channel.ReadData(data, maxlen); +} + +qint64 SymbianIpcSocket::writeData(const char *data, qint64 len) +{ + Q_D(const SymbianIpcSocket); + if (d->m_channel.SendDataL(data, len)) { + return len; + } + return 0; +} + +// End of File diff --git a/src/libraries/qmfclient/symbian/ipcsocket.h b/src/libraries/qmfclient/symbian/ipcsocket.h new file mode 100644 index 00000000..2d9a4511 --- /dev/null +++ b/src/libraries/qmfclient/symbian/ipcsocket.h @@ -0,0 +1,61 @@ +#ifndef IPCSOCKET_H +#define IPCSOCKET_H + +#include <QtCore/qiodevice.h> +#include <QtNetwork/qabstractsocket.h> +#include <QSharedDataPointer> + +class SymbianIpcSocketPrivate; + +class SymbianIpcSocket : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(SymbianIpcSocket) + +public: + enum SymbianIpcSocketError + { + ServerNotFoundError = QAbstractSocket::HostNotFoundError, + UnknownSocketError = QAbstractSocket::UnknownSocketError + }; + + enum SymbianIpcSocketState + { + UnconnectedState = QAbstractSocket::UnconnectedState, + ConnectingState = QAbstractSocket::ConnectingState, + ConnectedState = QAbstractSocket::ConnectedState, + ClosingState = QAbstractSocket::ClosingState + }; + + SymbianIpcSocket(QObject *parent = 0); + ~SymbianIpcSocket(); + + void connectToServer(const QString &name, OpenMode openMode = ReadWrite); + + bool isSequential() const; + qint64 bytesAvailable() const; + + bool flush(); + bool setSocketDescriptor(quintptr socketDescriptor, + SymbianIpcSocketState socketState = ConnectedState, + OpenMode openMode = ReadWrite); + SymbianIpcSocketState state() const; + bool waitForConnected(int msecs = 30000); + +Q_SIGNALS: + void connected(); + void disconnected(); + void error(SymbianIpcSocket::SymbianIpcSocketError socketError); + void stateChanged(SymbianIpcSocket::SymbianIpcSocketState socketState); + +private: // From QIODevice + virtual qint64 readData(char *data, qint64 maxlen); + virtual qint64 writeData(const char *data, qint64 len); + +private: + Q_DISABLE_COPY(SymbianIpcSocket) +}; + +#endif // IPCSOCKET_H + +// End of File diff --git a/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.cpp b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.cpp new file mode 100644 index 00000000..3267d1ec --- /dev/null +++ b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.cpp @@ -0,0 +1,278 @@ +#include "qmfipcchannel.h" +#include "qmfipcchannelsession.h" +#include "qmfipcchannelclientservercommon.h" +#include <QString> +#include <QThreadStorage> +#include <qglobal.h> + +class SymbianQMFIPCChannelPrivate : public CActive, public QSharedData +{ +public: + SymbianQMFIPCChannelPrivate(); + SymbianQMFIPCChannelPrivate(const SymbianQMFIPCChannelPrivate &other); + ~SymbianQMFIPCChannelPrivate(); + + SymbianQMFIPCChannelPrivate& operator=(const SymbianQMFIPCChannelPrivate& other); + +protected: // From CActive + void RunL(); + void DoCancel(); + +public: // Data + friend class SymbianQMFIPCChannel; + bool m_connected; + RQMFIPCChannelSession m_session; + SymbianQMFIPCChannelObserver* m_channelObserver; + SymbianQMFIPCChannelIncomingConnectionObserver* m_incomingConnectionObserver; + HBufC* m_currentChannel; + TPckgBuf<TInt> m_incomingMessageSizePckgBuf; + TPckgBuf<TUint> m_connectionIdPckgBuf; + RBuf8 m_incomingData; +}; + +SymbianQMFIPCChannelPrivate::SymbianQMFIPCChannelPrivate() + : CActive(EPriorityStandard), + m_connected(false) +{ + CActiveScheduler::Add(this); + if (m_session.Connect() == KErrNone) { + m_connected = true; + } +} + +SymbianQMFIPCChannelPrivate::SymbianQMFIPCChannelPrivate(const SymbianQMFIPCChannelPrivate &other) + : QSharedData(other), + CActive(EPriorityStandard), + m_session(other.m_session), + m_connected(other.m_connected) +{ +} + +SymbianQMFIPCChannelPrivate::~SymbianQMFIPCChannelPrivate() +{ + Cancel(); + m_session.Close(); + m_incomingData.Close(); + if (m_currentChannel) { + delete m_currentChannel; + } +} + +SymbianQMFIPCChannelPrivate& SymbianQMFIPCChannelPrivate::operator=(const SymbianQMFIPCChannelPrivate& other) +{ + if (this != &other) { + m_session = other.m_session; + } + + return *this; +} + +void SymbianQMFIPCChannelPrivate::RunL() +{ + switch (iStatus.Int()) { + case EQMFIPCChannelRequestNewChannelConnection: + m_incomingConnectionObserver->NewConnection(m_connectionIdPckgBuf()); + if (!IsActive()) { + // Continue waiting for new incoming connections + m_session.WaitForIncomingConnection(m_connectionIdPckgBuf, iStatus); + SetActive(); + } + break; + case EQMFIPCChannelRequestChannelNotFound: + m_channelObserver->ConnectionRefused(); + break; + case EQMFIPCChannelRequestChannelConnected: + m_channelObserver->Connected(m_connectionIdPckgBuf()); + if (!IsActive()) { + // => First message can be handled + m_session.ListenChannel(m_incomingMessageSizePckgBuf, iStatus); + SetActive(); + } + break; + case EQMFIPCChannelRequestDataAvailable: + m_incomingData.Close(); + TRAPD(err, m_incomingData.CreateL(m_incomingMessageSizePckgBuf())); + if (err == KErrNone) { + m_session.ReceiveData(m_incomingData); + m_channelObserver->DataAvailable(); + } + break; + case KErrCancel: + break; + case KErrNotReady: + default: + break; + } +} + +void SymbianQMFIPCChannelPrivate::DoCancel() +{ + m_session.Cancel(); +} + +SymbianQMFIPCChannel::SymbianQMFIPCChannel() +{ + d = new SymbianQMFIPCChannelPrivate; +} + +SymbianQMFIPCChannel::SymbianQMFIPCChannel(const SymbianQMFIPCChannel& other) + : d(other.d) +{ +} + +SymbianQMFIPCChannel::~SymbianQMFIPCChannel() +{ +} + +SymbianQMFIPCChannel& SymbianQMFIPCChannel::operator=(const SymbianQMFIPCChannel& other) +{ + if (this != &other) { + d = other.d; + } + + return *this; +} + +bool SymbianQMFIPCChannel::connect() +{ + if (!d->m_connected) { + if (d->m_session.Connect() == KErrNone) { + d->m_connected = true; + } + } + return d->m_connected; +} + +bool SymbianQMFIPCChannel::createChannel(QString name) +{ + if (!d->m_connected) { + return false; + } + + TPtrC16 stringPtr(KNullDesC); + stringPtr.Set(reinterpret_cast<const TUint16*>(name.utf16())); + return d->m_session.CreateChannel(stringPtr); +} + +bool SymbianQMFIPCChannel::destroyChannel(QString name) +{ + if (!d->m_connected) { + return false; + } + + TPtrC16 stringPtr(KNullDesC); + stringPtr.Set(reinterpret_cast<const TUint16*>(name.utf16())); + return d->m_session.DestroyChannel(stringPtr); +} + +bool SymbianQMFIPCChannel::waitForIncomingConnection(SymbianQMFIPCChannelIncomingConnectionObserver* observer) +{ + if (!d->m_connected) { + return false; + } + + bool retVal = d->m_session.WaitForIncomingConnection(d->m_connectionIdPckgBuf, + d->iStatus); + d->SetActive(); + d->m_incomingConnectionObserver = observer; + + return retVal; +} + +bool SymbianQMFIPCChannel::connectClientToChannel(QString name, SymbianQMFIPCChannelObserver* observer) +{ + bool retVal = false; + + if (!d->m_connected) { + return false; + } + + TPtrC16 stringPtr(KNullDesC); + stringPtr.Set(reinterpret_cast<const TUint16*>(name.utf16())); + if (d->m_currentChannel) { + delete d->m_currentChannel; + d->m_currentChannel = NULL; + } + d->m_currentChannel = stringPtr.Alloc(); + if (d->m_currentChannel) { + bool retVal = d->m_session.ConnectClientToChannel(*d->m_currentChannel, + d->m_connectionIdPckgBuf, + d->iStatus); + d->SetActive(); + d->m_channelObserver = observer; + } + + return retVal; +} + +bool SymbianQMFIPCChannel::connectServerToChannel(quintptr socketDescriptor, + SymbianQMFIPCChannelObserver* observer) +{ + bool retVal = false; + + if (!d->m_connected) { + return false; + } + + d->m_connectionIdPckgBuf = socketDescriptor; + d->m_channelObserver = observer; + return d->m_session.ConnectServerToChannel(socketDescriptor); +} + +bool SymbianQMFIPCChannel::SendDataL(const char *data, qint64 len) +{ + if (!d->m_connected) { + return false; + } + + TPtrC8 stringPtr((const TUint8 *)data, len); + return d->m_session.SendData(stringPtr); +} + +bool SymbianQMFIPCChannel::startWaitingForData() +{ + if (!d->IsActive()) { + d->m_session.ListenChannel(d->m_incomingMessageSizePckgBuf, d->iStatus); + d->SetActive(); + return true; + } + return false; +} + +qint64 SymbianQMFIPCChannel::ReadData(char *data, qint64 maxlen) +{ + quint64 dataLength = d->m_incomingData.Length(); + + if (dataLength > maxlen) { + dataLength = maxlen; + } + + char* dataPtr = (char*)d->m_incomingData.Ptr(); + for (int i=0; i < dataLength; i++) { + *(data+i) = *(dataPtr+i); + } + + if (d->m_incomingData.Length() > dataLength) { + d->m_incomingData.Delete(0, dataLength); + } else { + d->m_incomingData.Close(); + } + + if (d->m_incomingData.Length() == 0) { + // All message data was read from the buffer + if (!d->IsActive()) { + // => Next message can be handled + d->m_session.ListenChannel(d->m_incomingMessageSizePckgBuf, d->iStatus); + d->SetActive(); + } + } + + return dataLength; +} + +qint64 SymbianQMFIPCChannel::dataSize() const +{ + return d->m_incomingData.Size(); +} + +// End of File diff --git a/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.h b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.h new file mode 100644 index 00000000..5b3afd0b --- /dev/null +++ b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.h @@ -0,0 +1,54 @@ +#ifndef SYMBIANQMFIPCCHANNEL_H +#define SYMBIANQMFIPCCHANNEL_H + +#include "qmfipcchannelsession.h" +#include <QSharedDataPointer> + +class QString; +class SymbianQMFIPCChannelPrivate; + +class SymbianQMFIPCChannelObserver +{ +public: + virtual ~SymbianQMFIPCChannelObserver() {} + virtual void Connected(quintptr connectionId) = 0; + virtual void ConnectionRefused() = 0; + virtual void Disconnected() = 0; + virtual void DataAvailable() = 0; +}; + +class SymbianQMFIPCChannelIncomingConnectionObserver +{ +public: + virtual ~SymbianQMFIPCChannelIncomingConnectionObserver() {} + virtual void NewConnection(quintptr connectionId) = 0; +}; + +class SymbianQMFIPCChannel +{ +public: + SymbianQMFIPCChannel(); + SymbianQMFIPCChannel(const SymbianQMFIPCChannel& other); + ~SymbianQMFIPCChannel(); + + SymbianQMFIPCChannel& operator=(const SymbianQMFIPCChannel& other); + + bool connect(); + bool createChannel(QString name); + bool destroyChannel(QString name); + bool waitForIncomingConnection(SymbianQMFIPCChannelIncomingConnectionObserver* observer); + + bool connectClientToChannel(QString name, SymbianQMFIPCChannelObserver* observer); + bool connectServerToChannel(quintptr socketDescriptor, SymbianQMFIPCChannelObserver* observer); + bool SendDataL(const char *data, qint64 len); + bool startWaitingForData(); + qint64 ReadData(char *data, qint64 maxlen); + qint64 dataSize() const; + +private: // Data + QSharedDataPointer<SymbianQMFIPCChannelPrivate> d; +}; + +#endif // SYMBIANQMFIPCCHANNEL_H + +// End of File diff --git a/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelclientservercommon.h b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelclientservercommon.h new file mode 100644 index 00000000..9f58e370 --- /dev/null +++ b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelclientservercommon.h @@ -0,0 +1,56 @@ +#ifndef QMFIPCCHANNELCLIENTSERVERCOMMON_H +#define QMFIPCCHANNELCLIENTSERVERCOMMON_H + +#include <e32base.h> + +_LIT(KQMFIPCChannelServer, "QMFIPCChannelServer"); + +enum TQMFIPCChannelServerPanic +{ + EBadRequest = 1, + EBadDescriptor = 2, + ESrvCreateServer = 3, + EMainSchedulerError = 4, + ECreateTrapCleanup = 5, + ESrvSessCreateTimer = 6, + EReqAlreadyPending = 7 +}; + + +// Constants +_LIT(KQMFIPCChannelServerName,"QMFIPCChannelServer"); +_LIT(KQMFIPCChannelServerSemaphoreName, "QMFIPCChannelServerSemaphore"); + +const TUint KQMFIPCChannelServerMajorVersionNumber=0; +const TUint KQMFIPCChannelServerMinorVersionNumber=1; +const TUint KQMFIPCChannelServerBuildVersionNumber=1; + +enum TQMFIPCChannelServerRequest +{ + EQMFIPCChannelServerRequestCreateChannel, + EQMFIPCChannelServerRequestWaitForIncomingConnection, + EQMFIPCChannelServerRequestDestroyChannel, + EQMFIPCChannelServerRequestChannelExists, + EQMFIPCChannelServerRequestConnectClientToChannel, + EQMFIPCChannelServerRequestConnectServerToChannel, + EQMFIPCChannelServerRequestListenChannel, + EQMFIPCChannelServerRequestDisconnectFromChannel, + EQMFIPCChannelServerRequestSendData, + EQMFIPCChannelServerRequestReceiveData, + EQMFIPCChannelServerRequestCancel +}; + +enum TQMFIPCChannelServerRequestComplete +{ + EQMFIPCChannelRequestNewChannelConnection = 1, + EQMFIPCChannelRequestChannelConnected, + EQMFIPCChannelRequestChannelNotFound, + EQMFIPCChannelRequestDataAvailable, + EQMFIPCChannelRequestChannelDisconnected, + EQMFIPCChannelRequestCanceled +}; + + +#endif // QMFIPCCHANNELCLIENTSERVERCOMMON_H + +// End of File diff --git a/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.cpp b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.cpp new file mode 100644 index 00000000..f1059bb7 --- /dev/null +++ b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.cpp @@ -0,0 +1,192 @@ +#include "qmfipcchannelsession.h" +#include "qmfipcchannelclientservercommon.h" + +#include <f32file.h> + +static TInt StartServer(); +static TInt CreateServerProcess(); + +RQMFIPCChannelSession::RQMFIPCChannelSession() + : RSessionBase() +{ +} + +TInt RQMFIPCChannelSession::Connect() +{ + TInt retVal = ::StartServer(); + if (retVal == KErrNone) { + retVal = CreateSession(KQMFIPCChannelServerName, Version(), KDefaultMessageSlots); + if (retVal == KErrServerTerminated) { + retVal = ::StartServer(); + if (retVal == KErrNone) { + retVal = CreateSession(KQMFIPCChannelServerName, Version(), KDefaultMessageSlots); + } + } + } + return retVal; +} + +TVersion RQMFIPCChannelSession::Version() const +{ + return(TVersion(KQMFIPCChannelServerMajorVersionNumber, + KQMFIPCChannelServerMinorVersionNumber, + KQMFIPCChannelServerBuildVersionNumber)); +} + +TBool RQMFIPCChannelSession::CreateChannel(const TDesC& aChannelName) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestCreateChannel, TIpcArgs(&resultPckgBuf, &aChannelName)); + if (retVal < KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::WaitForIncomingConnection(TPckgBuf<TUint>& aNewConnectionIdPckgBuf, + TRequestStatus& aStatus) +{ + SendReceive(EQMFIPCChannelServerRequestWaitForIncomingConnection, TIpcArgs(&aNewConnectionIdPckgBuf), aStatus); + return ETrue; +} + +TBool RQMFIPCChannelSession::DestroyChannel(const TDesC& aChannelName) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestDestroyChannel, TIpcArgs(&resultPckgBuf, &aChannelName)); + if (retVal < KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::ChannelExists(const TDesC& aChannelName) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestCreateChannel, TIpcArgs(&resultPckgBuf, &aChannelName)); + if (retVal < KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::ConnectClientToChannel(const TDesC& aChannelName, + TPckgBuf<TUint>& aNewConnectionIdPckgBuf, + TRequestStatus& aStatus) +{ + SendReceive(EQMFIPCChannelServerRequestConnectClientToChannel, + TIpcArgs(&aNewConnectionIdPckgBuf, &aChannelName), + aStatus); + return ETrue; +} + +TBool RQMFIPCChannelSession::ConnectServerToChannel(TUint aConnectionId) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TPckg<TUint> connectionIdPckg(aConnectionId); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestConnectServerToChannel, + TIpcArgs(&resultPckgBuf, &connectionIdPckg)); + if (retVal != KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::ListenChannel(TPckgBuf<TInt>& aIncomingMessageSizePckgBug, + TRequestStatus& aStatus) +{ + SendReceive(EQMFIPCChannelServerRequestListenChannel, + TIpcArgs(&aIncomingMessageSizePckgBug), + aStatus); + return ETrue; +} + +TBool RQMFIPCChannelSession::DisconnectFromChannel() +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestDisconnectFromChannel, TIpcArgs(&resultPckgBuf)); + if (retVal != KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::SendData(const TDesC8& aData) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestSendData, TIpcArgs(&resultPckgBuf, &aData)); + if (retVal != KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +TBool RQMFIPCChannelSession::ReceiveData(RBuf8& aData) +{ + TPckgBuf<TBool> resultPckgBuf(EFalse); + TInt retVal = SendReceive(EQMFIPCChannelServerRequestReceiveData, TIpcArgs(&resultPckgBuf, &aData)); + if (retVal != KErrNone) { + return EFalse; + } + return resultPckgBuf(); +} + +void RQMFIPCChannelSession::Cancel() +{ + SendReceive(EQMFIPCChannelServerRequestCancel); +} + +static TInt StartServer() +{ + TInt retVal; + + TFindServer findQMFIPCChannelServer(KQMFIPCChannelServerName); + TFullName name; + + retVal = findQMFIPCChannelServer.Next(name); + if (retVal == KErrNone) { + // Server is already running + return KErrNone; + } + + RSemaphore semaphore; + retVal = semaphore.CreateGlobal(KQMFIPCChannelServerSemaphoreName, 0); + if (retVal == KErrAlreadyExists) { + retVal = semaphore.OpenGlobal(KQMFIPCChannelServerSemaphoreName); + if (retVal != KErrNone) { + return retVal; + } + } else { + if (retVal != KErrNone) { + return retVal; + } + retVal = CreateServerProcess(); + if (retVal != KErrNone ) { + return retVal; + } + } + + semaphore.Wait(); + semaphore.Close(); + + return KErrNone; +} + +static TInt CreateServerProcess() +{ + TInt retVal; + + const TUidType serverUid(KNullUid, KNullUid, KServerUid3); + + RProcess server; + retVal = server.Create(KQMFIPCChannelServerFilename, KNullDesC, serverUid); + if (retVal != KErrNone) { + return retVal; + } + server.Resume(); + server.Close(); + + return KErrNone; +} + +// End of File diff --git a/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.h b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.h new file mode 100644 index 00000000..07853ecc --- /dev/null +++ b/src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.h @@ -0,0 +1,49 @@ +#ifndef QMFIPCCHANNELSESSION_H +#define QMFIPCCHANNELSESSION_H + +#include <e32base.h> + +// Constants +// Number of message slots to reserve for this client server session. +// Only one asynchronous request can be outstanding +// and one synchronous request in progress. +const TUint KDefaultMessageSlots = 2; + +const TUid KServerUid3 = { 0x2003A67B }; // Server UID + +_LIT(KQMFIPCChannelServerFilename, "QMFIPCChannelServer"); + +#ifdef __WINS__ +static const TUint KServerMinHeapSize = 0x1000; // 4K +static const TUint KServerMaxHeapSize = 0x10000; // 64K +#endif + +class RQMFIPCChannelSession : public RSessionBase +{ +public: + RQMFIPCChannelSession(); + + TInt Connect(); + TVersion Version() const; + + TBool CreateChannel(const TDesC& aChannelName); + TBool WaitForIncomingConnection(TPckgBuf<TUint>& aNewConnectionIdPckgBuf, + TRequestStatus& aStatus); + TBool DestroyChannel(const TDesC& aChannelName); + TBool ChannelExists(const TDesC& aChannelName); + TBool ConnectClientToChannel(const TDesC& aChannelName, + TPckgBuf<TUint>& aNewConnectionIdPckgBuf, + TRequestStatus& aStatus); + TBool ConnectServerToChannel(TUint aConnectionId); + TBool ListenChannel(TPckgBuf<TInt>& aIncomingMessageSizePckgBug, + TRequestStatus& aStatus); + TBool DisconnectFromChannel(); + TBool SendData(const TDesC8& aData); + TBool ReceiveData(RBuf8& aData); + + void Cancel(); +}; + +#endif // QMFIPCCHANNELSESSION + +// End of File diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index b92e2483..569d5776 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -21,6 +21,7 @@ deploy.path = C: qmfdeployment.sources = messageserver.exe qmfdeployment.sources += qmfdataserver.exe +qmfdeployment.sources += qmfipcchannelserver.exe qmfdeployment.sources += qmfclient.dll qmfdeployment.sources += qmfmessageserver.dll qmfdeployment.path = /sys/bin diff --git a/src/symbian/qmfipcchannelserver/bld.inf b/src/symbian/qmfipcchannelserver/bld.inf new file mode 100644 index 00000000..6c91fb54 --- /dev/null +++ b/src/symbian/qmfipcchannelserver/bld.inf @@ -0,0 +1,5 @@ +prj_platforms +WINSCW GCCE ARMV5 ARMV6 + +prj_mmpfiles +qmfipcchannelserver.mmp diff --git a/src/symbian/qmfipcchannelserver/qmfipcchannelserver.cpp b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.cpp new file mode 100644 index 00000000..9a74feb8 --- /dev/null +++ b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.cpp @@ -0,0 +1,271 @@ +#include "qmfipcchannelserver.h" +#include "qmfipcchannelserversession.h" +#include <e32svr.h> + +const TInt KShutdownInterval(30000000); // 30 seconds + +CQMFIPCChannelServer* CQMFIPCChannelServer::NewL() +{ + CQMFIPCChannelServer* pSelf = CQMFIPCChannelServer::NewLC(); + CleanupStack::Pop(pSelf); + return pSelf; +} +CQMFIPCChannelServer* CQMFIPCChannelServer::NewLC() +{ + CQMFIPCChannelServer* pSelf = new (ELeave) CQMFIPCChannelServer(EPriorityNormal); + CleanupStack::PushL(pSelf); + pSelf->ConstructL(); + return pSelf; +} + +void CQMFIPCChannelServer::ConstructL() +{ + StartL(KQMFIPCChannelServerName); +} + +CQMFIPCChannelServer::CQMFIPCChannelServer(TInt aPriority) + : CServer2(aPriority) +{ +} + +CQMFIPCChannelServer::~CQMFIPCChannelServer() +{ + if (ipShutdownTimer) { + delete ipShutdownTimer; + ipShutdownTimer = NULL; + } + + for (int i=iIPCChannels.Count()-1; i >= 0; i--) { + delete iIPCChannels[i].channelName; + iIPCChannels[i].iConnectedClientSessions.Close(); + iIPCChannels.Remove(i); + } +} + +CSession2* CQMFIPCChannelServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const +{ + // Check version + if (!User::QueryVersionSupported(TVersion(KQMFIPCChannelServerMajorVersionNumber, + KQMFIPCChannelServerMinorVersionNumber, + KQMFIPCChannelServerBuildVersionNumber), + aVersion)) { + User::Leave(KErrNotSupported); + } + + return CQMFIPCChannelServerSession::NewL(*const_cast<CQMFIPCChannelServer*> ( this )); +} + +void CQMFIPCChannelServer::IncrementSessions() +{ + if (ipShutdownTimer && ipShutdownTimer->IsActive()) { + ipShutdownTimer->Cancel(); + } + iSessionCount++; +} + +void CQMFIPCChannelServer::DecrementSessions() +{ + iSessionCount--; + if (iSessionCount <= 0) { + if (!ipShutdownTimer) { + ipShutdownTimer = CPeriodic::New(EPriorityIdle); + } + if (ipShutdownTimer) { + ipShutdownTimer->Start(KShutdownInterval, KShutdownInterval, TCallBack(PeriodicTimerCallBack, this)); + } else { + CActiveScheduler::Stop(); + } + } +} + +void CQMFIPCChannelServer::ActivateChannel(const TDesC& aChannelName, CQMFIPCChannelServerSession* apSession) +{ + TBool channelFound = EFalse; + for (int i=0; i < iIPCChannels.Count(); i++) { + if (iIPCChannels[i].channelName->Compare(aChannelName) == 0) { + iIPCChannels[i].active = ETrue; + iIPCChannels[i].ipServerSession = apSession; + channelFound = ETrue; + break; + } + } + if (!channelFound) { + TIPCChannel newChannel; + newChannel.active = ETrue; + newChannel.ipServerSession = apSession; + newChannel.channelName = aChannelName.Alloc(); + iIPCChannels.Append(newChannel); + } +} + +void CQMFIPCChannelServer::DeactivateChannel(const TDesC& aChannelName) +{ + for (int i=0; i < iIPCChannels.Count(); i++) { + if (iIPCChannels[i].channelName->Compare(aChannelName) == 0) { + iIPCChannels[i].active = EFalse; + if (iIPCChannels[i].iConnectedClientSessions.Count() == 0) { + delete iIPCChannels[i].channelName; + iIPCChannels[i].iConnectedClientSessions.Close(); + iIPCChannels.Remove(i); + } + } + } +} + +TBool CQMFIPCChannelServer::ChannelExists(const TDesC& aChannelName) +{ + for (int i=0; i < iIPCChannels.Count(); i++) { + if (iIPCChannels[i].channelName->Compare(aChannelName) == 0) { + if (iIPCChannels[i].active) { + return ETrue; + } + } + } + return EFalse; +} + +TBool CQMFIPCChannelServer::ConnectClientSessionToChannel(const TDesC& aChannelName, + CQMFIPCChannelServerSession* aSession) +{ + for (int i=0; i < iIPCChannels.Count(); i++) { + if (iIPCChannels[i].channelName->Compare(aChannelName) == 0) { + aSession->iConnectionId = NewConnectionId(); + iIPCChannels[i].iConnectedClientSessions.Append(aSession); + iIPCChannels[i].ipServerSession->ClientSessionConnected(aSession); + return ETrue; + } + } + return EFalse; +} + +TBool CQMFIPCChannelServer::ConnectServerSessionToChannel(TUint aConnectionId, + CQMFIPCChannelServerSession* apSession) +{ + for (int i=0; i < iIPCChannels.Count(); i++) { + for (int j=0; j < iIPCChannels[i].iConnectedClientSessions.Count(); j++) { + if (iIPCChannels[i].iConnectedClientSessions[j]->iConnectionId == aConnectionId) { + // Connect server session to client session and vice versa + iIPCChannels[i].iConnectedClientSessions[j]->ipSession = apSession; + apSession->ipSession = iIPCChannels[i].iConnectedClientSessions[j]; + // Set channel name to server session + if (apSession->ipChannelName) { + delete apSession->ipChannelName; + apSession->ipChannelName = NULL; + } + apSession->ipChannelName = iIPCChannels[i].iConnectedClientSessions[j]->ipChannelName->Alloc(); + // Notify client that server session is connected + // => Channel is ready to be used + iIPCChannels[i].iConnectedClientSessions[j]->ServerSessionConnected(aConnectionId); + return ETrue; + } + } + } + return EFalse; +} + +void CQMFIPCChannelServer::DisconnectSessionFromChannel(CQMFIPCChannelServerSession* apSession) +{ + for (int i=0; i < iIPCChannels.Count(); i++) { + for (int j=0; j < iIPCChannels[i].iConnectedClientSessions.Count(); j++) { + if (iIPCChannels[i].iConnectedClientSessions[j] == apSession) { + if (apSession->ipSession) { + apSession->ipSession->ipSession = NULL; + } + apSession->ipSession = NULL; + iIPCChannels[i].iConnectedClientSessions.Remove(j); + if (!iIPCChannels[i].active && (iIPCChannels[i].iConnectedClientSessions.Count() == 0)) { + delete iIPCChannels[i].channelName; + iIPCChannels[i].iConnectedClientSessions.Close(); + iIPCChannels.Remove(i); + } + return; + } else if (iIPCChannels[i].iConnectedClientSessions[j]->ipSession == apSession) { + iIPCChannels[i].iConnectedClientSessions[j]->ipSession = NULL; + apSession->ipSession = NULL; + return; + } + } + } +} + +TUint CQMFIPCChannelServer::NewConnectionId() +{ + iConnectionIdCounter++; + if (iConnectionIdCounter == KMaxTInt) { + iConnectionIdCounter = 1; + } + return iConnectionIdCounter; +} + +TInt CQMFIPCChannelServer::PeriodicTimerCallBack(TAny* /*aAny*/) +{ + CActiveScheduler::Stop(); + return KErrNone; +} + +TInt CQMFIPCChannelServer::RunError(TInt aError) +{ + if (aError == KErrBadDescriptor) { + PanicClient( Message(), EBadDescriptor ); + } else { + Message().Complete(aError); + } + + ReStart(); + + return KErrNone; +} + +void CQMFIPCChannelServer::PanicClient(const RMessage2& aMessage, TQMFIPCChannelServerPanic aPanic) +{ + aMessage.Panic(KQMFIPCChannelServer, aPanic); +} + +void CQMFIPCChannelServer::PanicServer(TQMFIPCChannelServerPanic aPanic) +{ + User::Panic(KQMFIPCChannelServer, aPanic); +} + +void CQMFIPCChannelServer::ThreadFunctionL() +{ + CActiveScheduler* pActiveScheduler = new (ELeave) CActiveScheduler; + CleanupStack::PushL(pActiveScheduler); + CActiveScheduler::Install(pActiveScheduler); + + CQMFIPCChannelServer* pMessageDataServer = CQMFIPCChannelServer::NewLC(); + + RSemaphore semaphore; + User::LeaveIfError(semaphore.OpenGlobal(KQMFIPCChannelServerSemaphoreName)); + semaphore.Signal(KMaxTInt); // Signal all waiting semaphore instances + semaphore.Close(); + + CActiveScheduler::Start(); + + CleanupStack::PopAndDestroy(pMessageDataServer); + CleanupStack::PopAndDestroy(pActiveScheduler); +} + +TInt CQMFIPCChannelServer::ThreadFunction(TAny* /*aNone*/) +{ + CTrapCleanup* pCleanupStack = CTrapCleanup::New(); + if (!(pCleanupStack)) { + PanicServer(ECreateTrapCleanup); + } + + TRAPD(err, ThreadFunctionL()); + if (err != KErrNone) { + PanicServer(ESrvCreateServer); + } + + delete pCleanupStack; + pCleanupStack = NULL; + + return KErrNone; +} + +TInt E32Main() +{ + return CQMFIPCChannelServer::ThreadFunction(NULL); +} + +// End of File diff --git a/src/symbian/qmfipcchannelserver/qmfipcchannelserver.h b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.h new file mode 100644 index 00000000..31432f9e --- /dev/null +++ b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.h @@ -0,0 +1,63 @@ +#ifndef QMFIPCCHANNELSERVER_H +#define QMFIPCCHANNELSERVER_H + +#include "qmfipcchannelclientservercommon.h" +#include <e32base.h> + +class CQMFIPCChannelServerSession; + +struct TIPCChannel +{ + HBufC* channelName; + CQMFIPCChannelServerSession* ipServerSession; + TBool active; + RPointerArray<CQMFIPCChannelServerSession> iConnectedClientSessions; +}; + +class CQMFIPCChannelServer : public CServer2 +{ +public : + static CQMFIPCChannelServer* NewL(); + static CQMFIPCChannelServer* NewLC(); + virtual ~CQMFIPCChannelServer(); + + static TInt ThreadFunction(TAny* aStarted); + void IncrementSessions(); + void DecrementSessions(); + + void ActivateChannel(const TDesC& aChannelName, CQMFIPCChannelServerSession* apSession); + void DeactivateChannel(const TDesC& aChannelName); + TBool ChannelExists(const TDesC& aChannelName); + TBool ConnectClientSessionToChannel(const TDesC& aChannelName, CQMFIPCChannelServerSession* apSession); + TBool ConnectServerSessionToChannel(TUint aConnectionId, CQMFIPCChannelServerSession* apSession); + void DisconnectSessionFromChannel(CQMFIPCChannelServerSession* apSession); + +protected: // From CActive + TInt RunError(TInt aError); + +protected: // CPeriodic callback + static TInt PeriodicTimerCallBack(TAny* aAny); + +private: // Constructors and destructors + CQMFIPCChannelServer(TInt aPriority); + void ConstructL(); + +private: + static void PanicClient(const RMessage2& aMessage, TQMFIPCChannelServerPanic aReason); + static void PanicServer(TQMFIPCChannelServerPanic aPanic); + static void ThreadFunctionL(); + TUint NewConnectionId(); + +private: // From CServer2 + CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const; + +private: // Data + TInt iSessionCount; + TInt iConnectionIdCounter; + CPeriodic* ipShutdownTimer; + RArray<TIPCChannel> iIPCChannels; +}; + +#endif // QMFIPCCHANNELSERVER_H + +// End of File diff --git a/src/symbian/qmfipcchannelserver/qmfipcchannelserver.mmp b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.mmp new file mode 100644 index 00000000..ee51e349 --- /dev/null +++ b/src/symbian/qmfipcchannelserver/qmfipcchannelserver.mmp @@ -0,0 +1,18 @@ +TARGET QMFIPCChannelServer.exe +TARGETTYPE exe +UID 0x1000007A 0x2003A67B + +SOURCEPATH . +SOURCE qmfipcchannelserver.cpp +SOURCE qmfipcchannelserversession.cpp + +USERINCLUDE . +USERINCLUDE ..\..\libraries\qmfclient\symbian\qmfipcchannelclient +SYSTEMINCLUDE \epoc32\include +SYSTEMINCLUDE \epoc32\include\platform + +LIBRARY euser.lib + +VENDORID 0 + +CAPABILITY ALL -TCB diff --git a/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.cpp b/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.cpp new file mode 100644 index 00000000..d6ddc4ae --- /dev/null +++ b/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.cpp @@ -0,0 +1,316 @@ +#include "qmfipcchannelserversession.h" + +#include "qmfipcchannelserver.h" +#include "qmfipcchannelclientservercommon.h" + +CQMFIPCChannelServerSession* CQMFIPCChannelServerSession::NewL(CQMFIPCChannelServer& aServer) +{ + CQMFIPCChannelServerSession* pSelf = CQMFIPCChannelServerSession::NewLC(aServer); + CleanupStack::Pop(pSelf); + return pSelf; +} + +CQMFIPCChannelServerSession* CQMFIPCChannelServerSession::NewLC(CQMFIPCChannelServer& aServer) +{ + CQMFIPCChannelServerSession* pSelf = new (ELeave) CQMFIPCChannelServerSession(aServer); + CleanupStack::PushL(pSelf); + pSelf->ConstructL(); + return pSelf; +} + +void CQMFIPCChannelServerSession::ConstructL() +{ + iServer.IncrementSessions(); +} + +CQMFIPCChannelServerSession::CQMFIPCChannelServerSession(CQMFIPCChannelServer& aServer) + : iServer(aServer) +{ +} + +CQMFIPCChannelServerSession::~CQMFIPCChannelServerSession() +{ + if (ipChannelName) { + delete ipChannelName; + } + iClientsToConnect.Reset(); + iMessagesToDeliver.ResetAndDestroy(); + iServer.DisconnectSessionFromChannel(this); + iServer.DecrementSessions(); +} + +void CQMFIPCChannelServerSession::ServiceL(const RMessage2& aMessage) +{ + switch (aMessage.Function()) { + case EQMFIPCChannelServerRequestCreateChannel: + CreateChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestWaitForIncomingConnection: + WaitForIncomingConnectionL(aMessage); + break; + case EQMFIPCChannelServerRequestDestroyChannel: + DestroyChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestChannelExists: + ChannelExistsL(aMessage); + break; + case EQMFIPCChannelServerRequestConnectClientToChannel: + ConnectClientToChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestConnectServerToChannel: + ConnectServerToChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestListenChannel: + ListenChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestDisconnectFromChannel: + DisconnectFromChannelL(aMessage); + break; + case EQMFIPCChannelServerRequestSendData: + SendDataL(aMessage); + break; + case EQMFIPCChannelServerRequestReceiveData: + ReceiveDataL(aMessage); + break; + case EQMFIPCChannelServerRequestCancel: + CancelL(aMessage); + break; + default: + PanicClient(aMessage, EBadRequest); + } +} + +void CQMFIPCChannelServerSession::CreateChannelL(const RMessage2& aMessage) +{ + RBuf channelName; + channelName.CreateL(aMessage.GetDesLengthL(1)); + CleanupClosePushL(channelName); + aMessage.ReadL(1, channelName); + + iServer.ActivateChannel(channelName, this); + + CleanupStack::PopAndDestroy(&channelName); + TPckg<TBool> resultPckg(ETrue); + aMessage.WriteL(0, resultPckg); + + iServerSession = ETrue; + + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::WaitForIncomingConnectionL(const RMessage2& aMessage) +{ + if (iClientsToConnect.Count() > 0) { + TPckg<TUint> connectionIdPckg(iClientsToConnect[0]->iConnectionId); + aMessage.WriteL(0, connectionIdPckg); + aMessage.Complete(EQMFIPCChannelRequestNewChannelConnection); + iClientsToConnect.Remove(0); + iWaitingForConnection = EFalse; + } else { + iWaitingForConnection = ETrue; + iMessage = aMessage; + } +} + +void CQMFIPCChannelServerSession::DestroyChannelL(const RMessage2& aMessage) +{ + RBuf channelName; + channelName.CreateL(aMessage.GetDesLengthL(1)); + CleanupClosePushL(channelName); + aMessage.ReadL(1, channelName); + + iServer.DeactivateChannel(channelName); + + CleanupStack::PopAndDestroy(&channelName); + TPckg<TBool> resultPckg(ETrue); + aMessage.WriteL(0, resultPckg); + + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::ChannelExistsL(const RMessage2& aMessage) +{ + RBuf channelName; + channelName.CreateL(aMessage.GetDesLengthL(1)); + CleanupClosePushL(channelName); + aMessage.ReadL(1, channelName); + + TBool exists = iServer.ChannelExists(channelName); + CleanupStack::PopAndDestroy(&channelName); + TPckg<TBool> resultPckg(exists); + aMessage.WriteL(0, resultPckg); + + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::ConnectClientToChannelL(const RMessage2& aMessage) +{ + RBuf channelName; + channelName.CreateL(aMessage.GetDesLengthL(1)); + CleanupClosePushL(channelName); + aMessage.ReadL(1, channelName); + + if (iServer.ConnectClientSessionToChannel(channelName, this)) { + if (ipChannelName) { + delete ipChannelName; + } + ipChannelName = channelName.AllocL(); + + iWaitingForConnected = ETrue; + iClientChannelSession = ETrue; + iMessage = aMessage; + } else { + aMessage.Complete(EQMFIPCChannelRequestChannelNotFound); + } + + CleanupStack::PopAndDestroy(&channelName); +} + +void CQMFIPCChannelServerSession::ConnectServerToChannelL(const RMessage2& aMessage) +{ + TUint connectionId; + TPckg<TUint> connectionIdPckg(connectionId); + aMessage.ReadL(1, connectionIdPckg); + TBool retVal = ETrue; + if (iServer.ConnectServerSessionToChannel(connectionId, this)) { + iServerChannelSession = ETrue; + retVal = EFalse; + } + TPckg<TBool> retValPckg(retVal); + aMessage.WriteL(0, retValPckg); + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::ListenChannelL(const RMessage2& aMessage) +{ + iMessage = aMessage; + if (iMessagesToDeliver.Count() > 0) { + TPckgBuf<TInt> lengthPckg(iMessagesToDeliver[0]->Length()); + TRAPD(err, iMessage.WriteL(0, lengthPckg)); + if (err == KErrNone) { + iWaitingForMessage = EFalse; + iMessage.Complete(EQMFIPCChannelRequestDataAvailable); + } else { + PanicClient(iMessage, EBadDescriptor); + } + } else { + iWaitingForMessage = ETrue; + } +} + +void CQMFIPCChannelServerSession::DisconnectFromChannelL(const RMessage2& aMessage) +{ + iServer.DisconnectSessionFromChannel(this); + if (ipChannelName) { + delete ipChannelName; + ipChannelName = NULL; + } + if (iWaitingForMessage) { + iMessage.Complete(EQMFIPCChannelRequestChannelDisconnected); + } + + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::SendDataL(const RMessage2& aMessage) +{ + TBool retVal = EFalse; + + if (ipChannelName) { + RBuf8 message; + message.CreateL(aMessage.GetDesLengthL(1)); + CleanupClosePushL(message); + aMessage.ReadL(1, message); + + if (ipSession) { + ipSession->NewMessage(message); + } + CleanupStack::PopAndDestroy(&message); + retVal = ETrue; + } + + TPckg<TBool> retValPckg(retVal); + aMessage.WriteL(0, retValPckg); + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::ReceiveDataL(const RMessage2& aMessage) +{ + TBool retVal = EFalse; + + if (iMessagesToDeliver.Count() > 0) { + aMessage.WriteL(1, *iMessagesToDeliver[0]); + delete iMessagesToDeliver[0]; + iMessagesToDeliver.Remove(0); + retVal = ETrue; + TPckg<TBool> retValPckg(retVal); + aMessage.WriteL(0, retValPckg); + aMessage.Complete(KErrNone); + } else { + PanicClient(aMessage, EBadRequest); + } +} + +void CQMFIPCChannelServerSession::CancelL(const RMessage2& aMessage) +{ + iServer.DisconnectSessionFromChannel(this); + if (iWaitingForMessage || iWaitingForConnected || iWaitingForConnection) { + iMessage.Complete(EQMFIPCChannelRequestCanceled); + } + aMessage.Complete(KErrNone); +} + +void CQMFIPCChannelServerSession::NewMessage(const TDesC8& aMessage) +{ + HBufC8* pNewMessage = aMessage.Alloc(); + if (pNewMessage) { + if (iMessagesToDeliver.Append(pNewMessage) != KErrNone) { + delete pNewMessage; + pNewMessage = NULL; + } + } + + if (iWaitingForMessage && pNewMessage) { + if (iMessagesToDeliver.Count() > 0) { + TPckgBuf<TInt> lengthPckg(iMessagesToDeliver[0]->Length()); + TRAPD(err, iMessage.WriteL(0, lengthPckg)); + if (err == KErrNone) { + iWaitingForMessage = EFalse; + iMessage.Complete(EQMFIPCChannelRequestDataAvailable); + } else { + PanicClient(iMessage, EBadDescriptor); + } + } + } +} + +void CQMFIPCChannelServerSession::ClientSessionConnected(CQMFIPCChannelServerSession* apSession) +{ + if (iServerSession) { + if (iWaitingForConnection) { + TPckg<TUint> connectionIdPckg(apSession->iConnectionId); + iMessage.WriteL(0, connectionIdPckg); + iMessage.Complete(EQMFIPCChannelRequestNewChannelConnection); + iWaitingForConnection = EFalse; + } else { + iClientsToConnect.Append(apSession); + } + } +} + +void CQMFIPCChannelServerSession::ServerSessionConnected(TUint aConnectionId) +{ + if (iClientChannelSession && iWaitingForConnected) { + TPckg<TUint> connectionIdPckg(aConnectionId); + iMessage.WriteL(0, connectionIdPckg); + iMessage.Complete(EQMFIPCChannelRequestChannelConnected); + iWaitingForConnected = EFalse; + } +} + +void CQMFIPCChannelServerSession::PanicClient(const RMessagePtr2& aMessage, TInt aPanic ) const +{ + aMessage.Panic(KQMFIPCChannelServer, aPanic); +} + +// End of File diff --git a/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.h b/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.h new file mode 100644 index 00000000..0e9818cc --- /dev/null +++ b/src/symbian/qmfipcchannelserver/qmfipcchannelserversession.h @@ -0,0 +1,58 @@ +#ifndef QMFIPCCHANNELSERVERSESSION_H +#define QMFIPCCHANNELSERVERSESSION_H + +#include <e32base.h> + +class CQMFIPCChannelServer; + +class CQMFIPCChannelServerSession : public CSession2 +{ +public: + static CQMFIPCChannelServerSession* NewL(CQMFIPCChannelServer& aServer); + static CQMFIPCChannelServerSession* NewLC(CQMFIPCChannelServer& aServer); + virtual ~CQMFIPCChannelServerSession(); + + void ServiceL( const RMessage2& aMessage ); + + void NewMessage(const TDesC8& aMessage); + void ClientSessionConnected(CQMFIPCChannelServerSession* apSession); + void ServerSessionConnected(TUint aConnectionId); + +private: + CQMFIPCChannelServerSession(CQMFIPCChannelServer& aServer); + void ConstructL(); + void PanicClient(const RMessagePtr2& aMessage, TInt aPanic) const; + + void CreateChannelL(const RMessage2& aMessage); + void WaitForIncomingConnectionL(const RMessage2& aMessage); + void DestroyChannelL(const RMessage2& aMessage); + void ChannelExistsL(const RMessage2& aMessage); + void ConnectClientToChannelL(const RMessage2& aMessage); + void ConnectServerToChannelL(const RMessage2& aMessage); + void ListenChannelL(const RMessage2& aMessage); + void DisconnectFromChannelL(const RMessage2& aMessage); + void SendDataL(const RMessage2& aMessage); + void ReceiveDataL(const RMessage2& aMessage); + void CancelL(const RMessage2& aMessage); + +public: // Data + TBool iServerSession; + TBool iServerChannelSession; + TBool iClientChannelSession; + TUint iConnectionId; + HBufC* ipChannelName; + CQMFIPCChannelServerSession* ipSession; + +private: // Data + TBool iWaitingForMessage; + TBool iWaitingForConnected; + TBool iWaitingForConnection; + RMessage2 iMessage; + CQMFIPCChannelServer& iServer; + RPointerArray<HBufC8> iMessagesToDeliver; + RPointerArray<CQMFIPCChannelServerSession> iClientsToConnect; +}; + +#endif // QMFIPCCHANNELSERVERSESSION_H + +// End of File diff --git a/symbianoptions.pri b/symbianoptions.pri index b84fe70b..7f2b45f0 100644 --- a/symbianoptions.pri +++ b/symbianoptions.pri @@ -1,2 +1,3 @@ +CONFIG += SYMBIAN_USE_IPC_SOCKET CONFIG += SYMBIAN_USE_DATA_CAGED_DATABASE CONFIG += SYMBIAN_USE_DATA_CAGED_FILES |