summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarko Minkkinen <marko.minkkinen@digia.com>2011-03-16 14:39:18 +0200
committerMarko Minkkinen <marko.minkkinen@digia.com>2011-03-16 14:39:18 +0200
commit5be759133aced16dcbfba0670e1fb3cf15c4f79a (patch)
tree07f15403e2d30fd1811c2aa477751092fcaafd7f
parente34b39d4951acf47f09a477e90c0fca1f2455058 (diff)
First version of Symbian IPC for QCOP
-rw-r--r--src/libraries/qmfclient/qmfclient.pro16
-rw-r--r--src/libraries/qmfclient/support/qcopchannel.cpp5
-rw-r--r--src/libraries/qmfclient/support/qcopchannel_p.h9
-rw-r--r--src/libraries/qmfclient/symbian/ipcserver.cpp102
-rw-r--r--src/libraries/qmfclient/symbian/ipcserver.h34
-rw-r--r--src/libraries/qmfclient/symbian/ipcsocket.cpp187
-rw-r--r--src/libraries/qmfclient/symbian/ipcsocket.h61
-rw-r--r--src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.cpp278
-rw-r--r--src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannel.h54
-rw-r--r--src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelclientservercommon.h56
-rw-r--r--src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.cpp192
-rw-r--r--src/libraries/qmfclient/symbian/qmfipcchannelclient/qmfipcchannelsession.h49
-rw-r--r--src/s60installs/s60installs.pro1
-rw-r--r--src/symbian/qmfipcchannelserver/bld.inf5
-rw-r--r--src/symbian/qmfipcchannelserver/qmfipcchannelserver.cpp271
-rw-r--r--src/symbian/qmfipcchannelserver/qmfipcchannelserver.h63
-rw-r--r--src/symbian/qmfipcchannelserver/qmfipcchannelserver.mmp18
-rw-r--r--src/symbian/qmfipcchannelserver/qmfipcchannelserversession.cpp316
-rw-r--r--src/symbian/qmfipcchannelserver/qmfipcchannelserversession.h58
-rw-r--r--symbianoptions.pri1
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