Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdbusunixfiledescriptor.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
7
8#ifdef Q_OS_UNIX
9# include <private/qcore_unix_p.h>
10#endif
11
12QT_BEGIN_NAMESPACE
13
14#ifndef QT_NO_DBUS
15
16QT_IMPL_METATYPE_EXTERN(QDBusUnixFileDescriptor)
17
18/*!
19 \class QDBusUnixFileDescriptor
20 \inmodule QtDBus
21 \ingroup shared
22 \since 4.8
23
24 \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor.
25
26 The QDBusUnixFileDescriptor class is used to hold one Unix file
27 descriptor for use with the Qt D-Bus module. This allows applications to
28 send and receive Unix file descriptors over the D-Bus connection, mapping
29 automatically to the D-Bus type 'h'.
30
31 Objects of type QDBusUnixFileDescriptors can be used also as parameters
32 in signals and slots that get exported to D-Bus by registering with
33 QDBusConnection::registerObject.
34
35 QDBusUnixFileDescriptor does not take ownership of the file descriptor.
36 Instead, it will use the Unix system call \c dup(2) to make a copy of the
37 file descriptor. This file descriptor belongs to the
38 QDBusUnixFileDescriptor object and should not be stored or closed by the
39 user. Instead, you should make your own copy if you need that.
40
41 That copy is a real, open file descriptor for as long as the
42 QDBusUnixFileDescriptor object exists, so the object should be destroyed
43 as soon as it is no longer needed rather than kept alive indefinitely.
44 Holding many such objects for a long time, for example messages received
45 over D-Bus that carry a file descriptor and are then queued or cached by
46 the application, keeps that many file descriptors open and can exhaust
47 the process's file descriptor table.
48
49 \section2 Availability
50
51 Unix file descriptor passing is not available in all D-Bus connections.
52 This feature is present with D-Bus library and bus daemon version 1.4 and
53 upwards on Unix systems. Qt D-Bus automatically enables the feature if such
54 a version was found at compile-time and run-time.
55
56 To verify that your connection does support passing file descriptors,
57 check if the QDBusConnection::UnixFileDescriptorPassing capability is set
58 with QDBusConnection::connectionCapabilities(). If the flag is not
59 active, then you will not be able to make calls to methods that have
60 QDBusUnixFileDescriptor as arguments or even embed such a type in a
61 variant. You will also not receive calls containing that type.
62
63 Note also that remote applications may not have support for Unix file
64 descriptor passing. If you make a D-Bus to a remote application that
65 cannot receive such a type, you will receive an error reply. If you try
66 to send a signal containing a D-Bus file descriptor or return one from a
67 method call, the message will be silently dropped.
68
69 Even if the feature is not available, QDBusUnixFileDescriptor will
70 continue to operate, so code need not have compile-time checks for the
71 availability of this feature.
72
73 On non-Unix systems, QDBusUnixFileDescriptor will always report an
74 invalid state and QDBusUnixFileDescriptor::isSupported() will return
75 false.
76
77 \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities()
78*/
79
80/*!
81 \typedef QDBusUnixFileDescriptor::Data
82 \internal
83*/
84
85/*!
86 \variable QDBusUnixFileDescriptor::d
87 \internal
88*/
89
90class QDBusUnixFileDescriptorPrivate : public QSharedData {
91public:
92 QDBusUnixFileDescriptorPrivate() : fd(-1) { }
93 QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
94 : QSharedData(other), fd(-1)
95 { }
96 ~QDBusUnixFileDescriptorPrivate();
97
98 QAtomicInt fd;
99};
100
101QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QDBusUnixFileDescriptorPrivate)
102
103/*!
104 Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor.
105 This is equivalent to constructing the object with an invalid file
106 descriptor (like -1).
107
108 \sa fileDescriptor(), isValid()
109*/
110QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
111 : d(nullptr)
112{
113}
114
115/*!
116 Constructs a QDBusUnixFileDescriptor object by copying the \a
117 fileDescriptor parameter. The original file descriptor is not touched and
118 must be closed by the user.
119
120 Note that the value returned by fileDescriptor() will be different from
121 the \a fileDescriptor parameter passed.
122
123 If the \a fileDescriptor parameter is not valid, isValid() will return
124 false and fileDescriptor() will return -1.
125
126 \sa setFileDescriptor(), fileDescriptor()
127*/
128QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
129 : d(nullptr)
130{
131 if (fileDescriptor != -1)
132 setFileDescriptor(fileDescriptor);
133}
134
135/*!
136 Constructs a QDBusUnixFileDescriptor object by copying \a other.
137*/
138QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other)
139 : d(other.d)
140{
141}
142
143/*!
144 Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor
145 object. If the current object contained a file descriptor, it will be
146 properly disposed of before.
147*/
148QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
149{
150 if (this != &other)
151 d.operator=(other.d);
152 return *this;
153}
154
155/*!
156 \fn QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(QDBusUnixFileDescriptor &&other)
157
158 Move-assigns \a other to this QDBusUnixFileDescriptor.
159*/
160
161/*!
162 Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
163*/
164QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
165{
166}
167
168/*!
169 \fn void QDBusUnixFileDescriptor::swap(QDBusUnixFileDescriptor &other)
170 \since 5.0
171 \memberswap{file descriptor instance}
172*/
173
174/*!
175 Returns \c true if this Unix file descriptor is valid. A valid Unix file
176 descriptor is not -1.
177
178 \sa fileDescriptor()
179*/
180bool QDBusUnixFileDescriptor::isValid() const
181{
182 return d ? d->fd.loadRelaxed() != -1 : false;
183}
184
185/*!
186 Returns the Unix file descriptor contained by this
187 QDBusUnixFileDescriptor object. An invalid file descriptor is represented
188 by the value -1.
189
190 Note that the file descriptor returned by this function is owned by the
191 QDBusUnixFileDescriptor object and must not be stored past the lifetime
192 of this object. It is ok to use it while this object is valid, but if one
193 wants to store it for longer use, the file descriptor should be cloned
194 using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
195
196 \sa isValid()
197*/
198int QDBusUnixFileDescriptor::fileDescriptor() const
199{
200 return d ? d->fd.loadRelaxed() : -1;
201}
202
203// actual implementation
204#ifdef Q_OS_UNIX
205
206// qdoc documentation is generated on Unix
207
208/*!
209 Returns \c true if Unix file descriptors are supported on this platform. In
210 other words, this function returns \c true if this is a Unix platform.
211
212 Note that QDBusUnixFileDescriptor continues to operate even if this
213 function returns \c false. The only difference is that the
214 QDBusUnixFileDescriptor objects will always be in the isValid() == false
215 state and fileDescriptor() will always return -1. The class will not
216 consume any operating system resources.
217*/
218bool QDBusUnixFileDescriptor::isSupported()
219{
220 return true;
221}
222
223/*!
224 Sets the file descriptor that this QDBusUnixFileDescriptor object holds
225 to a copy of \a fileDescriptor. The original file descriptor is not
226 touched and must be closed by the user.
227
228 Note that the value returned by fileDescriptor() will be different from
229 the \a fileDescriptor parameter passed.
230
231 If the \a fileDescriptor parameter is not valid, isValid() will return
232 false and fileDescriptor() will return -1.
233
234 \sa isValid(), fileDescriptor()
235*/
236void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
237{
238 if (fileDescriptor != -1)
239 giveFileDescriptor(qt_safe_dup(fileDescriptor));
240}
241
242/*!
243 \internal
244 Sets the Unix file descriptor to \a fileDescriptor without copying.
245
246 \sa setFileDescriptor()
247*/
248void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
249{
250 // if we are the sole ref, d remains unchanged
251 // if detaching happens, d->fd will be -1
252 if (d)
253 d.detach();
254 else
255 d = new QDBusUnixFileDescriptorPrivate;
256
257 const int fdl = d->fd.loadRelaxed();
258 if (fdl != -1)
259 qt_safe_close(fdl);
260
261 if (fileDescriptor != -1)
262 d->fd.storeRelaxed(fileDescriptor);
263}
264
265/*!
266 \internal
267 Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
268 and transfers ownership.
269
270 Note: since QDBusUnixFileDescriptor is implicitly shared, this function
271 is inherently racy and should be avoided.
272*/
273int QDBusUnixFileDescriptor::takeFileDescriptor()
274{
275 if (!d)
276 return -1;
277
278 return d->fd.fetchAndStoreRelaxed(-1);
279}
280
281QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
282{
283 const int fdl = fd.loadRelaxed();
284 if (fdl != -1)
285 qt_safe_close(fdl);
286}
287
288#else
289bool QDBusUnixFileDescriptor::isSupported()
290{
291 return false;
292}
293
294void QDBusUnixFileDescriptor::setFileDescriptor(int)
295{
296}
297
298void QDBusUnixFileDescriptor::giveFileDescriptor(int)
299{
300}
301
302int QDBusUnixFileDescriptor::takeFileDescriptor()
303{
304 return -1;
305}
306
307QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
308{
309}
310
311#endif
312
313#endif // QT_NO_DBUS
314
315QT_END_NAMESPACE