/**
* This file is part of TelepathyQt
*
* @copyright Copyright (C) 2010-2011 Collabora Ltd.
* @license LGPL 2.1
*
* This library 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include
#include "TelepathyQt/_gen/stream-tube-channel.moc.hpp"
#include "TelepathyQt/debug-internal.h"
#include
#include
#include
#include
#include
namespace Tp
{
struct TP_QT_NO_EXPORT StreamTubeChannel::Private
{
Private(StreamTubeChannel *parent);
static void introspectStreamTube(Private *self);
static void introspectConnectionMonitoring(Private *self);
void extractStreamTubeProperties(const QVariantMap &props);
// Public object
StreamTubeChannel *parent;
ReadinessHelper *readinessHelper;
// Introspection
SupportedSocketMap socketTypes;
QString serviceName;
QSet connections;
QPair ipAddress;
QString unixAddress;
SocketAddressType addressType;
SocketAccessControl accessControl;
bool droppingConnections;
};
StreamTubeChannel::Private::Private(StreamTubeChannel *parent)
: parent(parent),
readinessHelper(parent->readinessHelper()),
addressType(SocketAddressTypeUnix),
accessControl(SocketAccessControlLocalhost),
droppingConnections(false)
{
ReadinessHelper::Introspectables introspectables;
ReadinessHelper::Introspectable introspectableStreamTube(
QSet() << 0, // makesSenseForStatuses
Features() << TubeChannel::FeatureCore, // dependsOnFeatures (core)
QStringList(), // dependsOnInterfaces
(ReadinessHelper::IntrospectFunc) &StreamTubeChannel::Private::introspectStreamTube,
this);
introspectables[StreamTubeChannel::FeatureCore] = introspectableStreamTube;
ReadinessHelper::Introspectable introspectableConnectionMonitoring(
QSet() << 0, // makesSenseForStatuses
Features() << StreamTubeChannel::FeatureCore, // dependsOnFeatures (core)
QStringList(), // dependsOnInterfaces
(ReadinessHelper::IntrospectFunc)
&StreamTubeChannel::Private::introspectConnectionMonitoring,
this);
introspectables[StreamTubeChannel::FeatureConnectionMonitoring] =
introspectableConnectionMonitoring;
parent->connect(
parent,
SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
SLOT(dropConnections()));
readinessHelper->addIntrospectables(introspectables);
}
void StreamTubeChannel::Private::introspectStreamTube(
StreamTubeChannel::Private *self)
{
StreamTubeChannel *parent = self->parent;
debug() << "Introspecting stream tube properties";
Client::ChannelTypeStreamTubeInterface *streamTubeInterface =
parent->interface();
PendingVariantMap *pvm = streamTubeInterface->requestAllProperties();
parent->connect(pvm,
SIGNAL(finished(Tp::PendingOperation *)),
SLOT(gotStreamTubeProperties(Tp::PendingOperation *)));
}
void StreamTubeChannel::Private::introspectConnectionMonitoring(
StreamTubeChannel::Private *self)
{
StreamTubeChannel *parent = self->parent;
Client::ChannelTypeStreamTubeInterface *streamTubeInterface =
parent->interface();
parent->connect(streamTubeInterface,
SIGNAL(ConnectionClosed(uint,QString,QString)),
SLOT(onConnectionClosed(uint,QString,QString)));
if (parent->isRequested()) {
parent->connect(streamTubeInterface,
SIGNAL(NewRemoteConnection(uint,QDBusVariant,uint)),
SLOT(onNewRemoteConnection(uint,QDBusVariant,uint)));
} else {
parent->connect(streamTubeInterface,
SIGNAL(NewLocalConnection(uint)),
SLOT(onNewLocalConnection(uint)));
}
self->readinessHelper->setIntrospectCompleted(
StreamTubeChannel::FeatureConnectionMonitoring, true);
}
void StreamTubeChannel::Private::extractStreamTubeProperties(const QVariantMap &props)
{
serviceName = qdbus_cast(props[QLatin1String("Service")]);
socketTypes = qdbus_cast(props[QLatin1String("SupportedSocketTypes")]);
}
/**
* \class StreamTubeChannel
* \ingroup clientchannel
* \headerfile TelepathyQt/stream-tube-channel.h
*
* \brief The StreamTubeChannel class represents a Telepathy channel of type StreamTube.
*
* It provides a transport for reliable and ordered data transfer, similar to SOCK_STREAM sockets.
*
* StreamTubeChannel is an intermediate base class; OutgoingStreamTubeChannel and
* IncomingStreamTubeChannel are the specialized classes used for locally and remotely initiated
* tubes respectively.
*
* For more details, please refer to \telepathy_spec.
*
* See \ref async_model, \ref shared_ptr
*/
/**
* Feature representing the core that needs to become ready to make the
* StreamTubeChannel object usable.
*
* Note that this feature must be enabled in order to use most
* StreamTubeChannel methods.
* See specific methods documentation for more details.
*/
const Feature StreamTubeChannel::FeatureCore =
Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 0);
/**
* Feature used in order to monitor connections to this stream tube.
*
* See connection monitoring specific methods' documentation for more details.
*
* \sa newConnection(), connectionClosed()
*/
const Feature StreamTubeChannel::FeatureConnectionMonitoring =
Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 1);
/**
* Create a new StreamTubeChannel channel.
*
* \param connection Connection owning this channel, and specifying the
* service.
* \param objectPath The channel object path.
* \param immutableProperties The channel immutable properties.
* \return A StreamTubeChannelPtr object pointing to the newly created
* StreamTubeChannel object.
*/
StreamTubeChannelPtr StreamTubeChannel::create(const ConnectionPtr &connection,
const QString &objectPath, const QVariantMap &immutableProperties)
{
return StreamTubeChannelPtr(new StreamTubeChannel(connection, objectPath,
immutableProperties, StreamTubeChannel::FeatureCore));
}
/**
* Construct a new StreamTubeChannel object.
*
* \param connection Connection owning this channel, and specifying the
* service.
* \param objectPath The channel object path.
* \param immutableProperties The channel immutable properties.
* \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should
* depend on StreamTubeChannel::FeatureCore.
*/
StreamTubeChannel::StreamTubeChannel(const ConnectionPtr &connection,
const QString &objectPath,
const QVariantMap &immutableProperties,
const Feature &coreFeature)
: TubeChannel(connection, objectPath, immutableProperties, coreFeature),
mPriv(new Private(this))
{
}
/**
* Class destructor.
*/
StreamTubeChannel::~StreamTubeChannel()
{
delete mPriv;
}
/**
* Return the service name which will be used over this stream tube. This should be a
* well-known TCP service name, for instance "rsync" or "daap".
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return The service name.
*/
QString StreamTubeChannel::service() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::service() used with "
"FeatureCore not ready";
return QString();
}
return mPriv->serviceName;
}
/**
* Return whether this stream tube is capable to accept or offer an IPv4 socket accepting all
* incoming connections coming from localhost.
*
* Note that the \telepathy_spec implies that any connection manager, if capable of providing
* stream tubes, must at least support IPv4 sockets with localhost access control.
* For this reason, this method should always return \c true.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an IPv4 socket
* accepting all incoming connections coming from localhost, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
* OutgoingStreamTubeChannel::offerTcpSocket(),
* supportsIPv4SocketsWithSpecifiedAddress()
*/
bool StreamTubeChannel::supportsIPv4SocketsOnLocalhost() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsIPv4SocketsOnLocalhost() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlLocalhost);
}
/**
* Return whether this stream tube is capable to accept an IPv4 socket accepting all
* incoming connections coming from a specific address for incoming tubes or whether
* this stream tube is capable of mapping connections to the socket's source address for outgoing
* tubes.
*
* For incoming tubes, when this capability is available, the stream tube can be accepted specifying
* an IPv4 address. Every connection coming from any other address than the specified one will be
* rejected.
*
* For outgoing tubes, when this capability is available, one can keep track of incoming connections
* by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before
* opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections()
* or OutgoingStreamTubeChannel::connectionsForSourceAddresses().
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
* OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
* as the spec implies this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept an IPv4 socket accepting all
* incoming connections coming from a specific address for incoming tubes or
* the stream tube is capable of mapping connections to the socket's source address for
* outgoing tubes, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
* OutgoingStreamTubeChannel::offerTcpSocket(),
* OutgoingStreamTubeChannel::connectionsForSourceAddresses(),
* OutgoingStreamTubeChannel::contactsForConnections(),
* supportsIPv4SocketsOnLocalhost()
*/
bool StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlPort);
}
/**
* Return whether this stream tube is capable to accept or offer an IPv6 socket accepting all
* incoming connections coming from localhost.
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
* OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
* as the spec implies this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an IPv6 socket
* accepting all incoming connections coming from localhost, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
* OutgoingStreamTubeChannel::offerTcpSocket(),
* supportsIPv6SocketsWithSpecifiedAddress()
*/
bool StreamTubeChannel::supportsIPv6SocketsOnLocalhost() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsIPv6SocketsOnLocalhost() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlLocalhost);
}
/**
* Return whether this stream tube is capable to accept an IPv6 socket accepting all
* incoming connections coming from a specific address for incoming tubes or whether
* this stream tube is capable of mapping connections to the socket's source address for outgoing
* tubes.
*
* For incoming tubes, when this capability is available, the stream tube can be accepted specifying
* an IPv6 address. Every connection coming from any other address than the specified one will be
* rejected.
*
* For outgoing tubes, when this capability is available, one can keep track of incoming connections
* by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before
* opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections()
* or OutgoingStreamTubeChannel::connectionsForSourceAddresses().
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
* OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
* as the spec implies this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept an IPv6 socket accepting all
* incoming connections coming from a specific address for incoming tubes or
* the stream tube is capable of mapping connections to the socket's source address for
* outgoing tubes, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
* OutgoingStreamTubeChannel::offerTcpSocket(),
* OutgoingStreamTubeChannel::connectionsForSourceAddresses(),
* OutgoingStreamTubeChannel::contactsForConnections(),
* supportsIPv6SocketsOnLocalhost()
*/
bool StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlPort);
}
/**
* Return whether this stream tube is capable to accept or offer an Unix socket accepting all
* incoming connections coming from localhost.
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
* OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies
* this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an Unix socket
* accepting all incoming connections coming from localhost, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
* OutgoingStreamTubeChannel::offerUnixSocket(),
* supportsUnixSocketsWithCredentials()
* supportsAbstractUnixSocketsOnLocalhost(),
* supportsAbstractUnixSocketsWithCredentials(),
*/
bool StreamTubeChannel::supportsUnixSocketsOnLocalhost() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsUnixSocketsOnLocalhost() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes.value(SocketAddressTypeUnix).contains(SocketAccessControlLocalhost);
}
/**
* Return whether this stream tube is capable to accept or offer an Unix socket which will require
* credentials upon connection.
*
* When this capability is available and enabled, the connecting process must send a byte when
* it first connects, which is not considered to be part of the data stream.
* If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
* credentials over sockets, the connecting process must do so if possible;
* if not, it must still send the byte.
*
* The listening process will disconnect the connection unless it can determine
* by OS-specific means that the connecting process has the same user ID as the listening process.
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
* OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies
* this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an Unix socket
* which will require credentials upon connection, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
* OutgoingStreamTubeChannel::offerUnixSocket(),
* supportsUnixSocketsOnLocalhost(),
* supportsAbstractUnixSocketsOnLocalhost(),
* supportsAbstractUnixSocketsWithCredentials(),
*/
bool StreamTubeChannel::supportsUnixSocketsWithCredentials() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsUnixSocketsWithCredentials() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes[SocketAddressTypeUnix].contains(SocketAccessControlCredentials);
}
/**
* Return whether this stream tube is capable to accept or offer an abstract Unix socket accepting
* all incoming connections coming from localhost.
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
* OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies
* this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an abstract Unix socket
* accepting all incoming connections coming from localhost, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
* OutgoingStreamTubeChannel::offerUnixSocket(),
* supportsUnixSocketsOnLocalhost(),
* supportsUnixSocketsWithCredentials(),
* supportsAbstractUnixSocketsWithCredentials()
*/
bool StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlLocalhost);
}
/**
* Return whether this stream tube is capable to accept or offer an abstract Unix socket which will
* require credentials upon connection.
*
* When this capability is available and enabled, the connecting process must send a byte when
* it first connects, which is not considered to be part of the data stream.
* If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
* credentials over sockets, the connecting process must do so if possible;
* if not, it must still send the byte.
*
* The listening process will disconnect the connection unless it can determine
* by OS-specific means that the connecting process has the same user ID as the listening process.
*
* Note that it is strongly advised to call this method before attempting to call
* IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
* OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies
* this feature is not compulsory for connection managers.
*
* This method requires StreamTubeChannel::FeatureCore to be ready.
*
* \return \c true if the stream tube is capable to accept or offer an abstract Unix socket
* which will require credentials upon connection, \c false otherwise.
* \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
* OutgoingStreamTubeChannel::offerUnixSocket(),
* supportsUnixSocketsOnLocalhost(),
* supportsUnixSocketsWithCredentials(),
* supportsAbstractUnixSocketsOnLocalhost()
*/
bool StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() const
{
if (!isReady(FeatureCore)) {
warning() << "StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() used with "
"FeatureCore not ready";
return false;
}
return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlCredentials);
}
/**
* Return all the known active connections since StreamTubeChannel::FeatureConnectionMonitoring has
* been enabled.
*
* For this method to return all known connections, you need to make
* StreamTubeChannel::FeatureConnectionMonitoring ready before accepting or offering the stream
* tube.
*
* This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready.
*
* \return The list of active connection ids.
* \sa newConnection(), connectionClosed()
*/
QSet StreamTubeChannel::connections() const
{
if (!isReady(FeatureConnectionMonitoring)) {
warning() << "StreamTubeChannel::connections() used with "
"FeatureConnectionMonitoring not ready";
return QSet();
}
return mPriv->connections;
}
/**
* Return the type of the tube's local endpoint socket.
*
* Note that this function will return a valid value only after state() has gone #TubeStateOpen.
*
* \return The socket type as #SocketAddressType.
* \sa localAddress(), ipAddress()
*/
SocketAddressType StreamTubeChannel::addressType() const
{
return mPriv->addressType;
}
/**
* Return the access control used by this stream tube.
*
* Note that this function will only return a valid value after state() has gone #TubeStateOpen.
*
* \return The access control as #SocketAccessControl.
* \sa addressType()
*/
SocketAccessControl StreamTubeChannel::accessControl() const
{
return mPriv->accessControl;
}
/**
* Return the IP address/port combination used by this stream tube.
*
* This method will return a meaningful value only if the local endpoint socket for the tube is a
* TCP socket, i.e. addressType() is #SocketAddressTypeIPv4 or #SocketAddressTypeIPv6.
*
* Note that this function will return a valid value only after state() has gone #TubeStateOpen.
*
* \return Pair of IP address as QHostAddress and port if using a TCP socket,
* or an undefined value otherwise.
* \sa localAddress()
*/
QPair StreamTubeChannel::ipAddress() const
{
if (state() != TubeChannelStateOpen) {
warning() << "Tube not open, returning invalid IP address";
return qMakePair(QHostAddress::Null, 0);
}
return mPriv->ipAddress;
}
/**
* Return the local address used by this stream tube.
*
* This method will return a meaningful value only if the local endpoint socket for the tube is an
* UNIX socket, i.e. addressType() is #SocketAddressTypeUnix or #SocketAddressTypeAbstractUnix.
*
* Note that this function will return a valid value only after state() has gone #TubeStateOpen.
*
* \return Unix socket address if using an Unix socket,
* or an undefined value otherwise.
* \sa ipAddress()
*/
QString StreamTubeChannel::localAddress() const
{
if (state() != TubeChannelStateOpen) {
warning() << "Tube not open, returning invalid local socket address";
return QString();
}
return mPriv->unixAddress;
}
void StreamTubeChannel::addConnection(uint connection)
{
if (!mPriv->connections.contains(connection)) {
mPriv->connections.insert(connection);
emit newConnection(connection);
} else {
warning() << "Tried to add connection" << connection << "on StreamTube" << objectPath()
<< "but it already was there";
}
}
void StreamTubeChannel::removeConnection(uint connection, const QString &error,
const QString &message)
{
if (mPriv->connections.contains(connection)) {
mPriv->connections.remove(connection);
emit connectionClosed(connection, error, message);
} else {
warning() << "Tried to remove connection" << connection << "from StreamTube" << objectPath()
<< "but it wasn't there";
}
}
void StreamTubeChannel::setAddressType(SocketAddressType type)
{
mPriv->addressType = type;
}
void StreamTubeChannel::setAccessControl(SocketAccessControl accessControl)
{
mPriv->accessControl = accessControl;
}
void StreamTubeChannel::setIpAddress(const QPair &address)
{
mPriv->ipAddress = address;
}
void StreamTubeChannel::setLocalAddress(const QString &address)
{
mPriv->unixAddress = address;
}
bool StreamTubeChannel::isDroppingConnections() const
{
return mPriv->droppingConnections;
}
void StreamTubeChannel::gotStreamTubeProperties(PendingOperation *op)
{
if (!op->isError()) {
PendingVariantMap *pvm = qobject_cast(op);
mPriv->extractStreamTubeProperties(pvm->result());
debug() << "Got reply to Properties::GetAll(StreamTubeChannel)";
mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, true);
}
else {
warning().nospace() << "Properties::GetAll(StreamTubeChannel) failed "
"with " << op->errorName() << ": " << op->errorMessage();
mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, false,
op->errorName(), op->errorMessage());
}
}
void StreamTubeChannel::onConnectionClosed(uint connId, const QString &error,
const QString &message)
{
removeConnection(connId, error, message);
}
void StreamTubeChannel::dropConnections()
{
if (!mPriv->connections.isEmpty()) {
debug() << "StreamTubeChannel invalidated with" << mPriv->connections.size()
<< "connections remaining, synthesizing close events";
mPriv->droppingConnections = true;
foreach (uint connId, mPriv->connections) {
removeConnection(connId, TP_QT_ERROR_ORPHANED,
QLatin1String("parent tube invalidated, streams closing"));
}
mPriv->droppingConnections = false;
}
}
/**
* \fn void StreamTubeChannel::connectionClosed(uint connectionId,
* const QString &errorName, const QString &errorMessage)
*
* Emitted when a connection on this stream tube has been closed.
*
* \param connectionId The unique ID associated with the connection that was closed.
* \param errorName The name of a D-Bus error describing the error that occurred.
* \param errorMessage A debugging message associated with the error.
* \sa newConnection(), connections()
*/
} // Tp