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