1 /**
2  * This file is part of TelepathyQt
3  *
4  * @copyright Copyright (C) 2010-2011 Collabora Ltd. <http://www.collabora.co.uk/>
5  * @license LGPL 2.1
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include <TelepathyQt/StreamTubeChannel>
23 
24 #include "TelepathyQt/_gen/stream-tube-channel.moc.hpp"
25 
26 #include "TelepathyQt/debug-internal.h"
27 
28 #include <TelepathyQt/Connection>
29 #include <TelepathyQt/ContactManager>
30 #include <TelepathyQt/PendingContacts>
31 #include <TelepathyQt/PendingVariantMap>
32 
33 #include <QHostAddress>
34 
35 namespace Tp
36 {
37 
38 struct TP_QT_NO_EXPORT StreamTubeChannel::Private
39 {
40     Private(StreamTubeChannel *parent);
41 
42     static void introspectStreamTube(Private *self);
43     static void introspectConnectionMonitoring(Private *self);
44 
45     void extractStreamTubeProperties(const QVariantMap &props);
46 
47     // Public object
48     StreamTubeChannel *parent;
49 
50     ReadinessHelper *readinessHelper;
51 
52     // Introspection
53     SupportedSocketMap socketTypes;
54     QString serviceName;
55 
56     QSet<uint> connections;
57     QPair<QHostAddress, quint16> ipAddress;
58     QString unixAddress;
59     SocketAddressType addressType;
60     SocketAccessControl accessControl;
61     bool droppingConnections;
62 };
63 
Private(StreamTubeChannel * parent)64 StreamTubeChannel::Private::Private(StreamTubeChannel *parent)
65     : parent(parent),
66       readinessHelper(parent->readinessHelper()),
67       addressType(SocketAddressTypeUnix),
68       accessControl(SocketAccessControlLocalhost),
69       droppingConnections(false)
70 {
71     ReadinessHelper::Introspectables introspectables;
72 
73     ReadinessHelper::Introspectable introspectableStreamTube(
74             QSet<uint>() << 0,                                                      // makesSenseForStatuses
75             Features() << TubeChannel::FeatureCore,                                 // dependsOnFeatures (core)
76             QStringList(),                                                          // dependsOnInterfaces
77             (ReadinessHelper::IntrospectFunc) &StreamTubeChannel::Private::introspectStreamTube,
78             this);
79     introspectables[StreamTubeChannel::FeatureCore] = introspectableStreamTube;
80 
81     ReadinessHelper::Introspectable introspectableConnectionMonitoring(
82             QSet<uint>() << 0,                                                            // makesSenseForStatuses
83             Features() << StreamTubeChannel::FeatureCore,                                 // dependsOnFeatures (core)
84             QStringList(),                                                                // dependsOnInterfaces
85             (ReadinessHelper::IntrospectFunc)
86                     &StreamTubeChannel::Private::introspectConnectionMonitoring,
87             this);
88     introspectables[StreamTubeChannel::FeatureConnectionMonitoring] =
89             introspectableConnectionMonitoring;
90 
91     parent->connect(
92             parent,
93             SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
94             SLOT(dropConnections()));
95 
96     readinessHelper->addIntrospectables(introspectables);
97 }
98 
introspectStreamTube(StreamTubeChannel::Private * self)99 void StreamTubeChannel::Private::introspectStreamTube(
100         StreamTubeChannel::Private *self)
101 {
102     StreamTubeChannel *parent = self->parent;
103 
104     debug() << "Introspecting stream tube properties";
105     Client::ChannelTypeStreamTubeInterface *streamTubeInterface =
106             parent->interface<Client::ChannelTypeStreamTubeInterface>();
107 
108     PendingVariantMap *pvm = streamTubeInterface->requestAllProperties();
109     parent->connect(pvm,
110             SIGNAL(finished(Tp::PendingOperation *)),
111             SLOT(gotStreamTubeProperties(Tp::PendingOperation *)));
112 }
113 
introspectConnectionMonitoring(StreamTubeChannel::Private * self)114 void StreamTubeChannel::Private::introspectConnectionMonitoring(
115         StreamTubeChannel::Private *self)
116 {
117     StreamTubeChannel *parent = self->parent;
118 
119     Client::ChannelTypeStreamTubeInterface *streamTubeInterface =
120             parent->interface<Client::ChannelTypeStreamTubeInterface>();
121 
122     parent->connect(streamTubeInterface,
123             SIGNAL(ConnectionClosed(uint,QString,QString)),
124             SLOT(onConnectionClosed(uint,QString,QString)));
125 
126     if (parent->isRequested()) {
127         parent->connect(streamTubeInterface,
128                 SIGNAL(NewRemoteConnection(uint,QDBusVariant,uint)),
129                 SLOT(onNewRemoteConnection(uint,QDBusVariant,uint)));
130     } else {
131         parent->connect(streamTubeInterface,
132                 SIGNAL(NewLocalConnection(uint)),
133                 SLOT(onNewLocalConnection(uint)));
134     }
135 
136     self->readinessHelper->setIntrospectCompleted(
137             StreamTubeChannel::FeatureConnectionMonitoring, true);
138 }
139 
extractStreamTubeProperties(const QVariantMap & props)140 void StreamTubeChannel::Private::extractStreamTubeProperties(const QVariantMap &props)
141 {
142     serviceName = qdbus_cast<QString>(props[QLatin1String("Service")]);
143     socketTypes = qdbus_cast<SupportedSocketMap>(props[QLatin1String("SupportedSocketTypes")]);
144 }
145 
146 /**
147  * \class StreamTubeChannel
148  * \ingroup clientchannel
149  * \headerfile TelepathyQt/stream-tube-channel.h <TelepathyQt/StreamTubeChannel>
150  *
151  * \brief The StreamTubeChannel class represents a Telepathy channel of type StreamTube.
152  *
153  * It provides a transport for reliable and ordered data transfer, similar to SOCK_STREAM sockets.
154  *
155  * StreamTubeChannel is an intermediate base class; OutgoingStreamTubeChannel and
156  * IncomingStreamTubeChannel are the specialized classes used for locally and remotely initiated
157  * tubes respectively.
158  *
159  * For more details, please refer to \telepathy_spec.
160  *
161  * See \ref async_model, \ref shared_ptr
162  */
163 
164 /**
165  * Feature representing the core that needs to become ready to make the
166  * StreamTubeChannel object usable.
167  *
168  * Note that this feature must be enabled in order to use most
169  * StreamTubeChannel methods.
170  * See specific methods documentation for more details.
171  */
172 const Feature StreamTubeChannel::FeatureCore =
173         Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 0);
174 
175 /**
176  * Feature used in order to monitor connections to this stream tube.
177  *
178  * See connection monitoring specific methods' documentation for more details.
179  *
180  * \sa newConnection(), connectionClosed()
181  */
182 const Feature StreamTubeChannel::FeatureConnectionMonitoring =
183         Feature(QLatin1String(StreamTubeChannel::staticMetaObject.className()), 1);
184 
185 /**
186  * Create a new StreamTubeChannel channel.
187  *
188  * \param connection Connection owning this channel, and specifying the
189  *                   service.
190  * \param objectPath The channel object path.
191  * \param immutableProperties The channel immutable properties.
192  * \return A StreamTubeChannelPtr object pointing to the newly created
193  *         StreamTubeChannel object.
194  */
create(const ConnectionPtr & connection,const QString & objectPath,const QVariantMap & immutableProperties)195 StreamTubeChannelPtr StreamTubeChannel::create(const ConnectionPtr &connection,
196         const QString &objectPath, const QVariantMap &immutableProperties)
197 {
198     return StreamTubeChannelPtr(new StreamTubeChannel(connection, objectPath,
199             immutableProperties, StreamTubeChannel::FeatureCore));
200 }
201 
202 /**
203  * Construct a new StreamTubeChannel object.
204  *
205  * \param connection Connection owning this channel, and specifying the
206  *                   service.
207  * \param objectPath The channel object path.
208  * \param immutableProperties The channel immutable properties.
209  * \param coreFeature The core feature of the channel type, if any. The corresponding introspectable should
210  *                    depend on StreamTubeChannel::FeatureCore.
211  */
StreamTubeChannel(const ConnectionPtr & connection,const QString & objectPath,const QVariantMap & immutableProperties,const Feature & coreFeature)212 StreamTubeChannel::StreamTubeChannel(const ConnectionPtr &connection,
213         const QString &objectPath,
214         const QVariantMap &immutableProperties,
215         const Feature &coreFeature)
216     : TubeChannel(connection, objectPath, immutableProperties, coreFeature),
217       mPriv(new Private(this))
218 {
219 }
220 
221 /**
222  * Class destructor.
223  */
~StreamTubeChannel()224 StreamTubeChannel::~StreamTubeChannel()
225 {
226     delete mPriv;
227 }
228 
229 /**
230  * Return the service name which will be used over this stream tube. This should be a
231  * well-known TCP service name, for instance "rsync" or "daap".
232  *
233  * This method requires StreamTubeChannel::FeatureCore to be ready.
234  *
235  * \return The service name.
236  */
service() const237 QString StreamTubeChannel::service() const
238 {
239     if (!isReady(FeatureCore)) {
240         warning() << "StreamTubeChannel::service() used with "
241                 "FeatureCore not ready";
242         return QString();
243     }
244 
245     return mPriv->serviceName;
246 }
247 
248 /**
249  * Return whether this stream tube is capable to accept or offer an IPv4 socket accepting all
250  * incoming connections coming from localhost.
251  *
252  * Note that the \telepathy_spec implies that any connection manager, if capable of providing
253  * stream tubes, must at least support IPv4 sockets with localhost access control.
254  * For this reason, this method should always return \c true.
255  *
256  * This method requires StreamTubeChannel::FeatureCore to be ready.
257  *
258  * \return \c true if the stream tube is capable to accept or offer an IPv4 socket
259  *         accepting all incoming connections coming from localhost, \c false otherwise.
260  * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
261  *     OutgoingStreamTubeChannel::offerTcpSocket(),
262  *     supportsIPv4SocketsWithSpecifiedAddress()
263  */
supportsIPv4SocketsOnLocalhost() const264 bool StreamTubeChannel::supportsIPv4SocketsOnLocalhost() const
265 {
266     if (!isReady(FeatureCore)) {
267         warning() << "StreamTubeChannel::supportsIPv4SocketsOnLocalhost() used with "
268                 "FeatureCore not ready";
269         return false;
270     }
271 
272     return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlLocalhost);
273 }
274 
275 /**
276  * Return whether this stream tube is capable to accept an IPv4 socket accepting all
277  * incoming connections coming from a specific address for incoming tubes or whether
278  * this stream tube is capable of mapping connections to the socket's source address for outgoing
279  * tubes.
280  *
281  * For incoming tubes, when this capability is available, the stream tube can be accepted specifying
282  * an IPv4 address. Every connection coming from any other address than the specified one will be
283  * rejected.
284  *
285  * For outgoing tubes, when this capability is available, one can keep track of incoming connections
286  * by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before
287  * opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections()
288  * or OutgoingStreamTubeChannel::connectionsForSourceAddresses().
289  *
290  * Note that it is strongly advised to call this method before attempting to call
291  * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
292  * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
293  * as the spec implies this feature is not compulsory for connection managers.
294  *
295  * This method requires StreamTubeChannel::FeatureCore to be ready.
296  *
297  * \return \c true if the stream tube is capable to accept an IPv4 socket accepting all
298  *         incoming connections coming from a specific address for incoming tubes or
299  *         the stream tube is capable of mapping connections to the socket's source address for
300  *         outgoing tubes, \c false otherwise.
301  * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
302  *     OutgoingStreamTubeChannel::offerTcpSocket(),
303  *     OutgoingStreamTubeChannel::connectionsForSourceAddresses(),
304  *     OutgoingStreamTubeChannel::contactsForConnections(),
305  *     supportsIPv4SocketsOnLocalhost()
306  */
supportsIPv4SocketsWithSpecifiedAddress() const307 bool StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() const
308 {
309     if (!isReady(FeatureCore)) {
310         warning() << "StreamTubeChannel::supportsIPv4SocketsWithSpecifiedAddress() used with "
311                 "FeatureCore not ready";
312         return false;
313     }
314 
315     return mPriv->socketTypes.value(SocketAddressTypeIPv4).contains(SocketAccessControlPort);
316 }
317 
318 /**
319  * Return whether this stream tube is capable to accept or offer an IPv6 socket accepting all
320  * incoming connections coming from localhost.
321  *
322  * Note that it is strongly advised to call this method before attempting to call
323  * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
324  * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
325  * as the spec implies this feature is not compulsory for connection managers.
326  *
327  * This method requires StreamTubeChannel::FeatureCore to be ready.
328  *
329  * \return \c true if the stream tube is capable to accept or offer an IPv6 socket
330  *         accepting all incoming connections coming from localhost, \c false otherwise.
331  * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
332  *     OutgoingStreamTubeChannel::offerTcpSocket(),
333  *     supportsIPv6SocketsWithSpecifiedAddress()
334  */
supportsIPv6SocketsOnLocalhost() const335 bool StreamTubeChannel::supportsIPv6SocketsOnLocalhost() const
336 {
337     if (!isReady(FeatureCore)) {
338         warning() << "StreamTubeChannel::supportsIPv6SocketsOnLocalhost() used with "
339                 "FeatureCore not ready";
340         return false;
341     }
342 
343     return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlLocalhost);
344 }
345 
346 /**
347  * Return whether this stream tube is capable to accept an IPv6 socket accepting all
348  * incoming connections coming from a specific address for incoming tubes or whether
349  * this stream tube is capable of mapping connections to the socket's source address for outgoing
350  * tubes.
351  *
352  * For incoming tubes, when this capability is available, the stream tube can be accepted specifying
353  * an IPv6 address. Every connection coming from any other address than the specified one will be
354  * rejected.
355  *
356  * For outgoing tubes, when this capability is available, one can keep track of incoming connections
357  * by enabling StreamTubeChannel::FeatureConnectionMonitoring (possibly before
358  * opening the stream tube itself), and checking OutgoingStreamTubeChannel::contactsForConnections()
359  * or OutgoingStreamTubeChannel::connectionsForSourceAddresses().
360  *
361  * Note that it is strongly advised to call this method before attempting to call
362  * IncomingStreamTubeChannel::acceptTubeAsTcpSocket() or
363  * OutgoingStreamTubeChannel::offerTcpSocket() with a specified address to prevent failures,
364  * as the spec implies this feature is not compulsory for connection managers.
365  *
366  * This method requires StreamTubeChannel::FeatureCore to be ready.
367  *
368  * \return \c true if the stream tube is capable to accept an IPv6 socket accepting all
369  *         incoming connections coming from a specific address for incoming tubes or
370  *         the stream tube is capable of mapping connections to the socket's source address for
371  *         outgoing tubes, \c false otherwise.
372  * \sa IncomingStreamTubeChannel::acceptTubeAsTcpSocket(),
373  *     OutgoingStreamTubeChannel::offerTcpSocket(),
374  *     OutgoingStreamTubeChannel::connectionsForSourceAddresses(),
375  *     OutgoingStreamTubeChannel::contactsForConnections(),
376  *     supportsIPv6SocketsOnLocalhost()
377  */
supportsIPv6SocketsWithSpecifiedAddress() const378 bool StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() const
379 {
380     if (!isReady(FeatureCore)) {
381         warning() << "StreamTubeChannel::supportsIPv6SocketsWithSpecifiedAddress() used with "
382                 "FeatureCore not ready";
383         return false;
384     }
385 
386     return mPriv->socketTypes.value(SocketAddressTypeIPv6).contains(SocketAccessControlPort);
387 }
388 
389 /**
390  * Return whether this stream tube is capable to accept or offer an Unix socket accepting all
391  * incoming connections coming from localhost.
392  *
393  * Note that it is strongly advised to call this method before attempting to call
394  * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
395  * OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies
396  * this feature is not compulsory for connection managers.
397  *
398  * This method requires StreamTubeChannel::FeatureCore to be ready.
399  *
400  * \return \c true if the stream tube is capable to accept or offer an Unix socket
401  *         accepting all incoming connections coming from localhost, \c false otherwise.
402  * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
403  *     OutgoingStreamTubeChannel::offerUnixSocket(),
404  *     supportsUnixSocketsWithCredentials()
405  *     supportsAbstractUnixSocketsOnLocalhost(),
406  *     supportsAbstractUnixSocketsWithCredentials(),
407  */
supportsUnixSocketsOnLocalhost() const408 bool StreamTubeChannel::supportsUnixSocketsOnLocalhost() const
409 {
410     if (!isReady(FeatureCore)) {
411         warning() << "StreamTubeChannel::supportsUnixSocketsOnLocalhost() used with "
412                 "FeatureCore not ready";
413         return false;
414     }
415 
416     return mPriv->socketTypes.value(SocketAddressTypeUnix).contains(SocketAccessControlLocalhost);
417 }
418 
419 /**
420  * Return whether this stream tube is capable to accept or offer an Unix socket which will require
421  * credentials upon connection.
422  *
423  * When this capability is available and enabled, the connecting process must send a byte when
424  * it first connects, which is not considered to be part of the data stream.
425  * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
426  * credentials over sockets, the connecting process must do so if possible;
427  * if not, it must still send the byte.
428  *
429  * The listening process will disconnect the connection unless it can determine
430  * by OS-specific means that the connecting process has the same user ID as the listening process.
431  *
432  * Note that it is strongly advised to call this method before attempting to call
433  * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
434  * OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies
435  * this feature is not compulsory for connection managers.
436  *
437  * This method requires StreamTubeChannel::FeatureCore to be ready.
438  *
439  * \return \c true if the stream tube is capable to accept or offer an Unix socket
440  *         which will require credentials upon connection, \c false otherwise.
441  * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
442  *     OutgoingStreamTubeChannel::offerUnixSocket(),
443  *     supportsUnixSocketsOnLocalhost(),
444  *     supportsAbstractUnixSocketsOnLocalhost(),
445  *     supportsAbstractUnixSocketsWithCredentials(),
446  */
supportsUnixSocketsWithCredentials() const447 bool StreamTubeChannel::supportsUnixSocketsWithCredentials() const
448 {
449     if (!isReady(FeatureCore)) {
450         warning() << "StreamTubeChannel::supportsUnixSocketsWithCredentials() used with "
451                 "FeatureCore not ready";
452         return false;
453     }
454 
455     return mPriv->socketTypes[SocketAddressTypeUnix].contains(SocketAccessControlCredentials);
456 }
457 
458 /**
459  * Return whether this stream tube is capable to accept or offer an abstract Unix socket accepting
460  * all incoming connections coming from localhost.
461  *
462  * Note that it is strongly advised to call this method before attempting to call
463  * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
464  * OutgoingStreamTubeChannel::offerUnixSocket() without credentials enabled, as the spec implies
465  * this feature is not compulsory for connection managers.
466  *
467  * This method requires StreamTubeChannel::FeatureCore to be ready.
468  *
469  * \return \c true if the stream tube is capable to accept or offer an abstract Unix socket
470  *         accepting all incoming connections coming from localhost, \c false otherwise.
471  * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
472  *     OutgoingStreamTubeChannel::offerUnixSocket(),
473  *     supportsUnixSocketsOnLocalhost(),
474  *     supportsUnixSocketsWithCredentials(),
475  *     supportsAbstractUnixSocketsWithCredentials()
476  */
supportsAbstractUnixSocketsOnLocalhost() const477 bool StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() const
478 {
479     if (!isReady(FeatureCore)) {
480         warning() << "StreamTubeChannel::supportsAbstractUnixSocketsOnLocalhost() used with "
481                 "FeatureCore not ready";
482         return false;
483     }
484 
485     return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlLocalhost);
486 }
487 
488 /**
489  * Return whether this stream tube is capable to accept or offer an abstract Unix socket which will
490  * require credentials upon connection.
491  *
492  * When this capability is available and enabled, the connecting process must send a byte when
493  * it first connects, which is not considered to be part of the data stream.
494  * If the operating system uses sendmsg() with SCM_CREDS or SCM_CREDENTIALS to pass
495  * credentials over sockets, the connecting process must do so if possible;
496  * if not, it must still send the byte.
497  *
498  * The listening process will disconnect the connection unless it can determine
499  * by OS-specific means that the connecting process has the same user ID as the listening process.
500  *
501  * Note that it is strongly advised to call this method before attempting to call
502  * IncomingStreamTubeChannel::acceptTubeAsUnixSocket() or
503  * OutgoingStreamTubeChannel::offerUnixSocket() with credentials enabled, as the spec implies
504  * this feature is not compulsory for connection managers.
505  *
506  * This method requires StreamTubeChannel::FeatureCore to be ready.
507  *
508  * \return \c true if the stream tube is capable to accept or offer an abstract Unix socket
509  *         which will require credentials upon connection, \c false otherwise.
510  * \sa IncomingStreamTubeChannel::acceptTubeAsUnixSocket(),
511  *     OutgoingStreamTubeChannel::offerUnixSocket(),
512  *     supportsUnixSocketsOnLocalhost(),
513  *     supportsUnixSocketsWithCredentials(),
514  *     supportsAbstractUnixSocketsOnLocalhost()
515  */
supportsAbstractUnixSocketsWithCredentials() const516 bool StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() const
517 {
518     if (!isReady(FeatureCore)) {
519         warning() << "StreamTubeChannel::supportsAbstractUnixSocketsWithCredentials() used with "
520                 "FeatureCore not ready";
521         return false;
522     }
523 
524     return mPriv->socketTypes[SocketAddressTypeAbstractUnix].contains(SocketAccessControlCredentials);
525 }
526 
527 /**
528  * Return all the known active connections since StreamTubeChannel::FeatureConnectionMonitoring has
529  * been enabled.
530  *
531  * For this method to return all known connections, you need to make
532  * StreamTubeChannel::FeatureConnectionMonitoring ready before accepting or offering the stream
533  * tube.
534  *
535  * This method requires StreamTubeChannel::FeatureConnectionMonitoring to be ready.
536  *
537  * \return The list of active connection ids.
538  * \sa newConnection(), connectionClosed()
539  */
connections() const540 QSet<uint> StreamTubeChannel::connections() const
541 {
542     if (!isReady(FeatureConnectionMonitoring)) {
543         warning() << "StreamTubeChannel::connections() used with "
544                 "FeatureConnectionMonitoring not ready";
545         return QSet<uint>();
546     }
547 
548     return mPriv->connections;
549 }
550 
551 /**
552  * Return the type of the tube's local endpoint socket.
553  *
554  * Note that this function will return a valid value only after state() has gone #TubeStateOpen.
555  *
556  * \return The socket type as #SocketAddressType.
557  * \sa localAddress(), ipAddress()
558  */
addressType() const559 SocketAddressType StreamTubeChannel::addressType() const
560 {
561     return mPriv->addressType;
562 }
563 
564 /**
565  * Return the access control used by this stream tube.
566  *
567  * Note that this function will only return a valid value after state() has gone #TubeStateOpen.
568  *
569  * \return The access control as #SocketAccessControl.
570  * \sa addressType()
571  */
accessControl() const572 SocketAccessControl StreamTubeChannel::accessControl() const
573 {
574     return mPriv->accessControl;
575 }
576 
577 /**
578  * Return the IP address/port combination used by this stream tube.
579  *
580  * This method will return a meaningful value only if the local endpoint socket for the tube is a
581  * TCP socket, i.e. addressType() is #SocketAddressTypeIPv4 or #SocketAddressTypeIPv6.
582  *
583  * Note that this function will return a valid value only after state() has gone #TubeStateOpen.
584  *
585  * \return Pair of IP address as QHostAddress and port if using a TCP socket,
586  *         or an undefined value otherwise.
587  * \sa localAddress()
588  */
ipAddress() const589 QPair<QHostAddress, quint16> StreamTubeChannel::ipAddress() const
590 {
591     if (state() != TubeChannelStateOpen) {
592         warning() << "Tube not open, returning invalid IP address";
593         return qMakePair<QHostAddress, quint16>(QHostAddress::Null, 0);
594     }
595 
596     return mPriv->ipAddress;
597 }
598 
599 /**
600  * Return the local address used by this stream tube.
601  *
602  * This method will return a meaningful value only if the local endpoint socket for the tube is an
603  * UNIX socket, i.e. addressType() is #SocketAddressTypeUnix or #SocketAddressTypeAbstractUnix.
604  *
605  * Note that this function will return a valid value only after state() has gone #TubeStateOpen.
606  *
607  * \return Unix socket address if using an Unix socket,
608  *         or an undefined value otherwise.
609  * \sa ipAddress()
610  */
localAddress() const611 QString StreamTubeChannel::localAddress() const
612 {
613     if (state() != TubeChannelStateOpen) {
614         warning() << "Tube not open, returning invalid local socket address";
615         return QString();
616     }
617 
618     return mPriv->unixAddress;
619 }
620 
addConnection(uint connection)621 void StreamTubeChannel::addConnection(uint connection)
622 {
623     if (!mPriv->connections.contains(connection)) {
624         mPriv->connections.insert(connection);
625         emit newConnection(connection);
626     } else {
627         warning() << "Tried to add connection" << connection << "on StreamTube" << objectPath()
628             << "but it already was there";
629     }
630 }
631 
removeConnection(uint connection,const QString & error,const QString & message)632 void StreamTubeChannel::removeConnection(uint connection, const QString &error,
633         const QString &message)
634 {
635     if (mPriv->connections.contains(connection)) {
636         mPriv->connections.remove(connection);
637         emit connectionClosed(connection, error, message);
638     } else {
639         warning() << "Tried to remove connection" << connection << "from StreamTube" << objectPath()
640             << "but it wasn't there";
641     }
642 }
643 
setAddressType(SocketAddressType type)644 void StreamTubeChannel::setAddressType(SocketAddressType type)
645 {
646     mPriv->addressType = type;
647 }
648 
setAccessControl(SocketAccessControl accessControl)649 void StreamTubeChannel::setAccessControl(SocketAccessControl accessControl)
650 {
651     mPriv->accessControl = accessControl;
652 }
653 
setIpAddress(const QPair<QHostAddress,quint16> & address)654 void StreamTubeChannel::setIpAddress(const QPair<QHostAddress, quint16> &address)
655 {
656     mPriv->ipAddress = address;
657 }
658 
setLocalAddress(const QString & address)659 void StreamTubeChannel::setLocalAddress(const QString &address)
660 {
661     mPriv->unixAddress = address;
662 }
663 
isDroppingConnections() const664 bool StreamTubeChannel::isDroppingConnections() const
665 {
666     return mPriv->droppingConnections;
667 }
668 
gotStreamTubeProperties(PendingOperation * op)669 void StreamTubeChannel::gotStreamTubeProperties(PendingOperation *op)
670 {
671     if (!op->isError()) {
672         PendingVariantMap *pvm = qobject_cast<PendingVariantMap *>(op);
673 
674         mPriv->extractStreamTubeProperties(pvm->result());
675 
676         debug() << "Got reply to Properties::GetAll(StreamTubeChannel)";
677         mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, true);
678     }
679     else {
680         warning().nospace() << "Properties::GetAll(StreamTubeChannel) failed "
681                 "with " << op->errorName() << ": " << op->errorMessage();
682         mPriv->readinessHelper->setIntrospectCompleted(StreamTubeChannel::FeatureCore, false,
683                 op->errorName(), op->errorMessage());
684     }
685 }
686 
onConnectionClosed(uint connId,const QString & error,const QString & message)687 void StreamTubeChannel::onConnectionClosed(uint connId, const QString &error,
688         const QString &message)
689 {
690     removeConnection(connId, error, message);
691 }
692 
dropConnections()693 void StreamTubeChannel::dropConnections()
694 {
695     if (!mPriv->connections.isEmpty()) {
696         debug() << "StreamTubeChannel invalidated with" << mPriv->connections.size()
697             << "connections remaining, synthesizing close events";
698         mPriv->droppingConnections = true;
699         foreach (uint connId, mPriv->connections) {
700             removeConnection(connId, TP_QT_ERROR_ORPHANED,
701                     QLatin1String("parent tube invalidated, streams closing"));
702         }
703         mPriv->droppingConnections = false;
704     }
705 }
706 
707 /**
708  * \fn void StreamTubeChannel::connectionClosed(uint connectionId,
709  *             const QString &errorName, const QString &errorMessage)
710  *
711  * Emitted when a connection on this stream tube has been closed.
712  *
713  * \param connectionId The unique ID associated with the connection that was closed.
714  * \param errorName The name of a D-Bus error describing the error that occurred.
715  * \param errorMessage A debugging message associated with the error.
716  * \sa newConnection(), connections()
717  */
718 
719 } // Tp
720