diff -r 5d007b20cfd0 -r cd2778e5acfe qthighway/xqservice/src/xqservicechannel.cpp --- a/qthighway/xqservice/src/xqservicechannel.cpp Tue Aug 31 16:02:37 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,366 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Lesser General Public License as published by -* the Free Software Foundation, version 2.1 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public License -* along with this program. If not, -* see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/". -* -* Description: -* -*/ - -#include "xqservicelog.h" - -#include "xqservicechannel.h" - -#include "xqservicethreaddata.h" -#include "xqserviceipcclient.h" - -#include -#include - - - -/*! - \class XQServiceChannel - \inpublicgroup QtBaseModule - \ingroup qws - - \brief The XQServiceChannel class provides communication capabilities - between clients. - - XQSERVICE is a many-to-many communication protocol for transferring - messages on various channels. A channel is identified by a name, - and anyone who wants to can listen to it. The XQSERVICE protocol allows - clients to communicate both within the same address space and - between different processes, but it is currently only available - for \l {Qt for Embedded Linux} (on X11 and Windows we are exploring the use - of existing standards such as DCOP and COM). - - Typically, XQServiceChannel is either used to send messages to a - channel using the provided static functions, or to listen to the - traffic on a channel by deriving from the class to take advantage - of the provided functionality for receiving messages. - - XQServiceChannel provides a couple of static functions which are usable - without an object: The send() function, which sends the given - message and data on the specified channel, and the isRegistered() - function which queries the server for the existence of the given - channel. - - In addition, the XQServiceChannel class provides the channel() function - which returns the name of the object's channel, the virtual - receive() function which allows subclasses to process data - received from their channel, and the received() signal which is - emitted with the given message and data when a XQServiceChannel - subclass receives a message from its channel. - - \sa XQServiceServer, {Running Qt for Embedded Linux Applications} -*/ - -/*! - Constructs a XQService channel with the given \a parent, and registers it - with the server using the given \a channel name. - \param channel Channel name. - \param isServer - \param parent Parent of this object. - \sa isRegistered(), channel() -*/ - -XQServiceChannel::XQServiceChannel(const QString& channel, bool isServer, QObject *parent) - : QObject(parent) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::XQServiceChannel"); - XQSERVICE_DEBUG_PRINT("channel: %s, isServer: %d", qPrintable(channel), isServer ); - d = new XQServiceChannelPrivate(this, channel, isServer); - d->ref.ref(); - - XQServiceThreadData *td = XQService::serviceThreadData(); - - // do we need a new channel list ? - XQServiceClientMap::Iterator it = td->clientMap.find(channel); - if (it != td->clientMap.end()) { - XQSERVICE_DEBUG_PRINT("Channel exits"); - it.value().append(XQServiceChannelPrivatePointer(d)); - return; - } - XQSERVICE_DEBUG_PRINT("New channel"); - it = td->clientMap.insert(channel, QList()); - it.value().append(XQServiceChannelPrivatePointer(d)); -} - -/*! - Destroys the client's end of the channel and notifies the server - that the client has closed its connection. The server will keep - the channel open until the last registered client detaches. - - \sa XQServiceChannel() -*/ - -XQServiceChannel::~XQServiceChannel() -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::~XQServiceChannel"); - XQServiceThreadData *td = XQService::serviceThreadData(); - - XQServiceClientMap::Iterator it = td->clientMap.find(d->channel); - Q_ASSERT(it != td->clientMap.end()); - it.value().removeAll(XQServiceChannelPrivatePointer(d)); - // still any clients connected locally ? - if (it.value().isEmpty()) { - if (td->hasClientConnection(d->channel)) - td->closeClientConnection(d->channel); - td->clientMap.remove(d->channel); - } - - // Dereference the private data structure. It may stay around - // for a little while longer if it is in use by sendLocally(). - d->object = 0; - if (!d->ref.deref()) - delete d; -} - -bool XQServiceChannel::connectChannel() -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::connectChannel"); - bool ret = true; - - XQServiceThreadData *td = XQService::serviceThreadData(); - - if (!td->hasClientConnection(d->channel)) { - XQSERVICE_DEBUG_PRINT("Create new client connection (1)"); - ret = td->createClientConnection(d->channel,d->server); - } - return ret; -} - -/*! - Returns the name of the channel. - - \sa XQServiceChannel() -*/ - -QString XQServiceChannel::channel() const -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::channel"); - XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(d->channel)); - return d->channel; -} - -/*! - \fn void XQServiceChannel::receive(const QString& message, const QByteArray &data) - - This virtual function allows subclasses of XQServiceChannel to process - the given \a message and \a data received from their channel. The default - implementation emits the received() signal. - - Note that the format of the given \a data has to be well defined - in order to extract the information it contains. In addition, it - is recommended to use the DCOP convention. This is not a - requirement, but you must ensure that the sender and receiver - agree on the argument types. - - Example: - - \code - void MyClass::receive(const QString &message, const QByteArray &data) - { - QDataStream in(data); - if (message == "execute(QString,QString)") { - QString cmd; - QString arg; - in >> cmd >> arg; - ... - } else if (message == "delete(QString)") { - QString fileName; - in >> fileName; - ... - } else { - ... - } - } - \endcode - - This example assumes that the \c message is a DCOP-style function - signature and the \c data contains the function's arguments. - - \sa send() - */ -QVariant XQServiceChannel::receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf ) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::receive"); - XQSERVICE_DEBUG_PRINT("msg: %s, data: %s", qPrintable(msg), data.constData()); - emit received(msg, data,sf); - return QVariant(); -} - -void XQServiceChannel::commandReceive(const XQServiceCommand cmd) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::commandReceive %d", cmd); - emit commandReceived(cmd); -} - -/*! - \fn void XQServiceChannel::received(const QString& message, const QByteArray &data) - - This signal is emitted with the given \a message and \a data whenever the - receive() function gets incoming data. - - \sa receive() -*/ - -/*! - \fn bool XQServiceChannel::send(const QString& channel, const QString& message, - const QByteArray &data) - - Sends the given \a message on the specified \a channel with the - given \a data. The message will be distributed to all clients - subscribed to the channel. Returns true if the message is sent - successfully; otherwise returns false. - - It is recommended to use the DCOP convention. This is not a - requirement, but you must ensure that the sender and receiver - agree on the argument types. - - Note that QDataStream provides a convenient way to fill the byte - array with auxiliary data. - - Example: - - \code - QByteArray data; - QDataStream out(&data, QIODevice::WriteOnly); - out << QString("cat") << QString("file.txt"); - XQServiceChannel::send("System/Shell", "execute(QString,QString)", data); - \endcode - - Here the channel is \c "System/Shell". The \c message is an - arbitrary string, but in the example we've used the DCOP - convention of passing a function signature. Such a signature is - formatted as \c "functionname(types)" where \c types is a list of - zero or more comma-separated type names, with no whitespace, no - consts and no pointer or reference marks, i.e. no "*" or "&". - - \sa receive() -*/ - -bool XQServiceChannel::send(const QString& channel, const QString& msg, - const QByteArray &data, QVariant &retValue, - bool sync, XQServiceRequestCompletedAsync* rc) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::send(1). No user data"); - // Delegate to actual send. - // No user data argument present in this version - return send(channel,msg,data,retValue,sync,rc,NULL); -} - - - -bool XQServiceChannel::send(const QString& channel, const QString& msg, - const QByteArray &data, QVariant &retValue, - bool sync, XQServiceRequestCompletedAsync* rc, - const void* userData) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::send(2) start"); - XQSERVICE_DEBUG_PRINT("\t channel: %s, msg: %s", qPrintable(channel), qPrintable(msg)); - XQSERVICE_DEBUG_PRINT("\t data: %s, sync: %d", data.constData(), sync); - bool ret=true; - - if (!XQService::serviceThreadData()->hasClientConnection(channel)) { - XQSERVICE_DEBUG_PRINT("\t Create new client connection (2)"); - ret = XQService::serviceThreadData()->createClientConnection(channel,false,sync,rc, userData); - XQSERVICE_DEBUG_PRINT("\t creation succeeded: %d", ret); - } - if (ret) { - XQSERVICE_DEBUG_PRINT("\t ret = true"); - XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(channel); - QByteArray retData ; - ret = cl ? cl->send(channel, msg, data, retData) : false; - if (sync) { - retValue = XQServiceThreadData::deserializeRetData(retData); - } - } - XQSERVICE_DEBUG_PRINT("\t ret: %d", ret); - XQSERVICE_DEBUG_PRINT("XQServiceChannel::send(2) end"); - return ret; -} - - -bool XQServiceChannel::cancelPendingSend(const QString& channel) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::cancelPendingSend start"); - XQSERVICE_DEBUG_PRINT("\t channel: %s", qPrintable(channel)); - bool ret=true; - - if (ret) { - XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(channel); - XQSERVICE_DEBUG_PRINT("\t XQService::serviceThreadData()->clientConnection(channel): %d", cl); - XQSERVICE_DEBUG_PRINT("\t cl->cancelPendingSend(%s)", qPrintable(channel)); - ret = cl ? cl->cancelPendingSend(channel) : false; - } - - XQSERVICE_DEBUG_PRINT("\t ret: %d", ret); - XQSERVICE_DEBUG_PRINT("XQServiceChannel::cancelPendingSend end"); - return ret; -} - -/*! - \internal - Client side: distribute received event to the XQService instance managing the - channel. -*/ -QVariant XQServiceChannel::sendLocally(const QString& ch, const QString& msg, - const QByteArray &data, const XQSharableFile &sf ) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::sendLocally"); - XQSERVICE_DEBUG_PRINT("channel: %s, msg: %s", qPrintable(ch), qPrintable(msg)); - XQSERVICE_DEBUG_PRINT("data: %s", data.constData()); - QVariant ret; - - // feed local clients with received data - XQServiceThreadData *td = XQService::serviceThreadData(); - QList clients = td->clientMap[ch]; - for (int i = 0; i < clients.size(); ++i) { - XQServiceChannelPrivate *channel = clients.at(i).data(); - if (channel->object) - ret = channel->object->receive(msg, data,sf ); - } - -#ifdef XQSERVICE_DEBUG - QString s = ret.toString(); - int len=s.length(); - XQSERVICE_DEBUG_PRINT("sendLocally ret: type=%s,len=%d,value(max.1024)=%s", - ret.typeName(),len,qPrintable(s.left(1024))); -#endif - return ret ; -} - -int XQServiceChannel::latestError() -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::latestError"); - return XQService::serviceThreadData()->latestError(); -} - -void XQServiceChannel::sendCommand(const QString& ch,const XQServiceCommand cmd) -{ - XQSERVICE_DEBUG_PRINT("XQServiceChannel::sendCommand"); - XQSERVICE_DEBUG_PRINT("channel: %s, cmd: %d", qPrintable(ch), cmd); - // feed local clients with received data - XQServiceThreadData *td = XQService::serviceThreadData(); - QList clients = td->clientMap[ch]; - for (int i = 0; i < clients.size(); ++i) { - XQServiceChannelPrivate *channel = clients.at(i).data(); - if (channel->object) - channel->object->commandReceive(cmd); - } -} -