1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 
41 #include "qdbusunixfiledescriptor.h"
42 
43 #ifdef Q_OS_UNIX
44 # include <private/qcore_unix_p.h>
45 #endif
46 
47 QT_BEGIN_NAMESPACE
48 
49 #ifndef QT_NO_DBUS
50 
51 /*!
52     \class QDBusUnixFileDescriptor
53     \inmodule QtDBus
54     \ingroup shared
55     \since 4.8
56 
57     \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor.
58 
59     The QDBusUnixFileDescriptor class is used to hold one Unix file
60     descriptor for use with the Qt D-Bus module. This allows applications to
61     send and receive Unix file descriptors over the D-Bus connection, mapping
62     automatically to the D-Bus type 'h'.
63 
64     Objects of type QDBusUnixFileDescriptors can be used also as parameters
65     in signals and slots that get exported to D-Bus by registering with
66     QDBusConnection::registerObject.
67 
68     QDBusUnixFileDescriptor does not take ownership of the file descriptor.
69     Instead, it will use the Unix system call \c dup(2) to make a copy of the
70     file descriptor. This file descriptor belongs to the
71     QDBusUnixFileDescriptor object and should not be stored or closed by the
72     user. Instead, you should make your own copy if you need that.
73 
74     \section2 Availability
75 
76     Unix file descriptor passing is not available in all D-Bus connections.
77     This feature is present with D-Bus library and bus daemon version 1.4 and
78     upwards on Unix systems. Qt D-Bus automatically enables the feature if such
79     a version was found at compile-time and run-time.
80 
81     To verify that your connection does support passing file descriptors,
82     check if the QDBusConnection::UnixFileDescriptorPassing capability is set
83     with QDBusConnection::connectionCapabilities(). If the flag is not
84     active, then you will not be able to make calls to methods that have
85     QDBusUnixFileDescriptor as arguments or even embed such a type in a
86     variant. You will also not receive calls containing that type.
87 
88     Note also that remote applications may not have support for Unix file
89     descriptor passing. If you make a D-Bus to a remote application that
90     cannot receive such a type, you will receive an error reply. If you try
91     to send a signal containing a D-Bus file descriptor or return one from a
92     method call, the message will be silently dropped.
93 
94     Even if the feature is not available, QDBusUnixFileDescriptor will
95     continue to operate, so code need not have compile-time checks for the
96     availability of this feature.
97 
98     On non-Unix systems, QDBusUnixFileDescriptor will always report an
99     invalid state and QDBusUnixFileDescriptor::isSupported() will return
100     false.
101 
102     \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities()
103 */
104 
105 /*!
106     \typedef QDBusUnixFileDescriptor::Data
107     \internal
108 */
109 
110 /*!
111     \variable QDBusUnixFileDescriptor::d
112     \internal
113 */
114 
115 class QDBusUnixFileDescriptorPrivate : public QSharedData {
116 public:
QDBusUnixFileDescriptorPrivate()117     QDBusUnixFileDescriptorPrivate() : fd(-1) { }
QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate & other)118     QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
119         : QSharedData(other), fd(-1)
120     {  }
121     ~QDBusUnixFileDescriptorPrivate();
122 
123     QAtomicInt fd;
124 };
125 
126 template<> inline
~QExplicitlySharedDataPointer()127 QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer()
128 { if (d && !d->ref.deref()) delete d; }
129 
130 /*!
131     Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor.
132     This is equivalent to constructing the object with an invalid file
133     descriptor (like -1).
134 
135     \sa fileDescriptor(), isValid()
136 */
QDBusUnixFileDescriptor()137 QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
138     : d(nullptr)
139 {
140 }
141 
142 /*!
143     Constructs a QDBusUnixFileDescriptor object by copying the \a
144     fileDescriptor parameter. The original file descriptor is not touched and
145     must be closed by the user.
146 
147     Note that the value returned by fileDescriptor() will be different from
148     the \a fileDescriptor parameter passed.
149 
150     If the \a fileDescriptor parameter is not valid, isValid() will return
151     false and fileDescriptor() will return -1.
152 
153     \sa setFileDescriptor(), fileDescriptor()
154 */
QDBusUnixFileDescriptor(int fileDescriptor)155 QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
156     : d(nullptr)
157 {
158     if (fileDescriptor != -1)
159         setFileDescriptor(fileDescriptor);
160 }
161 
162 /*!
163     Constructs a QDBusUnixFileDescriptor object by copying \a other.
164 */
QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor & other)165 QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other)
166     : d(other.d)
167 {
168 }
169 
170 /*!
171     Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor
172     object. If the current object contained a file descriptor, it will be
173     properly disposed of before.
174 */
operator =(const QDBusUnixFileDescriptor & other)175 QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
176 {
177     if (this != &other)
178         d.operator=(other.d);
179     return *this;
180 }
181 
182 /*!
183    \fn QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(QDBusUnixFileDescriptor &&other)
184 
185    Move-assigns  \a other to this QDBusUnixFileDescriptor.
186 */
187 
188 /*!
189     Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
190 */
~QDBusUnixFileDescriptor()191 QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
192 {
193 }
194 
195 /*!
196     \fn void QDBusUnixFileDescriptor::swap(QDBusUnixFileDescriptor &other)
197     \since 5.0
198 
199     Swaps this file descriptor instance with \a other. This function
200     is very fast and never fails.
201 */
202 
203 /*!
204     Returns \c true if this Unix file descriptor is valid. A valid Unix file
205     descriptor is not -1.
206 
207     \sa fileDescriptor()
208 */
isValid() const209 bool QDBusUnixFileDescriptor::isValid() const
210 {
211     return d ? d->fd.loadRelaxed() != -1 : false;
212 }
213 
214 /*!
215     Returns the Unix file descriptor contained by this
216     QDBusUnixFileDescriptor object. An invalid file descriptor is represented
217     by the value -1.
218 
219     Note that the file descriptor returned by this function is owned by the
220     QDBusUnixFileDescriptor object and must not be stored past the lifetime
221     of this object. It is ok to use it while this object is valid, but if one
222     wants to store it for longer use, the file descriptor should be cloned
223     using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
224 
225     \sa isValid()
226 */
fileDescriptor() const227 int QDBusUnixFileDescriptor::fileDescriptor() const
228 {
229     return d ? d->fd.loadRelaxed() : -1;
230 }
231 
232 // actual implementation
233 #ifdef Q_OS_UNIX
234 
235 // qdoc documentation is generated on Unix
236 
237 /*!
238     Returns \c true if Unix file descriptors are supported on this platform. In
239     other words, this function returns \c true if this is a Unix platform.
240 
241     Note that QDBusUnixFileDescriptor continues to operate even if this
242     function returns \c false. The only difference is that the
243     QDBusUnixFileDescriptor objects will always be in the isValid() == false
244     state and fileDescriptor() will always return -1. The class will not
245     consume any operating system resources.
246 */
isSupported()247 bool QDBusUnixFileDescriptor::isSupported()
248 {
249     return true;
250 }
251 
252 /*!
253     Sets the file descriptor that this QDBusUnixFileDescriptor object holds
254     to a copy of \a fileDescriptor. The original file descriptor is not
255     touched and must be closed by the user.
256 
257     Note that the value returned by fileDescriptor() will be different from
258     the \a fileDescriptor parameter passed.
259 
260     If the \a fileDescriptor parameter is not valid, isValid() will return
261     false and fileDescriptor() will return -1.
262 
263     \sa isValid(), fileDescriptor()
264 */
setFileDescriptor(int fileDescriptor)265 void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
266 {
267     if (fileDescriptor != -1)
268         giveFileDescriptor(qt_safe_dup(fileDescriptor));
269 }
270 
271 /*!
272     \internal
273     Sets the Unix file descriptor to \a fileDescriptor without copying.
274 
275     \sa setFileDescriptor()
276 */
giveFileDescriptor(int fileDescriptor)277 void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
278 {
279     // if we are the sole ref, d remains unchanged
280     // if detaching happens, d->fd will be -1
281     if (d)
282         d.detach();
283     else
284         d = new QDBusUnixFileDescriptorPrivate;
285 
286     const int fdl = d->fd.loadRelaxed();
287     if (fdl != -1)
288         qt_safe_close(fdl);
289 
290     if (fileDescriptor != -1)
291         d->fd.storeRelaxed(fileDescriptor);
292 }
293 
294 /*!
295     \internal
296     Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
297     and transfers ownership.
298 
299     Note: since QDBusUnixFileDescriptor is implicitly shared, this function
300     is inherently racy and should be avoided.
301 */
takeFileDescriptor()302 int QDBusUnixFileDescriptor::takeFileDescriptor()
303 {
304     if (!d)
305         return -1;
306 
307     return d->fd.fetchAndStoreRelaxed(-1);
308 }
309 
~QDBusUnixFileDescriptorPrivate()310 QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
311 {
312     const int fdl = fd.loadRelaxed();
313     if (fdl != -1)
314         qt_safe_close(fdl);
315 }
316 
317 #else
isSupported()318 bool QDBusUnixFileDescriptor::isSupported()
319 {
320     return false;
321 }
322 
setFileDescriptor(int)323 void QDBusUnixFileDescriptor::setFileDescriptor(int)
324 {
325 }
326 
giveFileDescriptor(int)327 void QDBusUnixFileDescriptor::giveFileDescriptor(int)
328 {
329 }
330 
takeFileDescriptor()331 int QDBusUnixFileDescriptor::takeFileDescriptor()
332 {
333     return -1;
334 }
335 
~QDBusUnixFileDescriptorPrivate()336 QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
337 {
338 }
339 
340 #endif
341 
342 #endif // QT_NO_DBUS
343 
344 QT_END_NAMESPACE
345