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

source code of qtbase/src/dbus/qdbusunixfiledescriptor.cpp