1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the FOO 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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43#include "qdbusunixfiledescriptor.h"
44#include <QSharedData>
45
46#ifdef Q_OS_UNIX
47# include <private/qcore_unix_p.h>
48#endif
49
50QT_BEGIN_NAMESPACE
51
52/*!
53 \class QDBusUnixFileDescriptor
54 \inmodule QtDBus
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 QtDBus 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. QtDBus 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
115class QDBusUnixFileDescriptorPrivate : public QSharedData {
116public:
117 QDBusUnixFileDescriptorPrivate() : fd(-1) { }
118 QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
119 : QSharedData(other), fd(-1)
120 { }
121 ~QDBusUnixFileDescriptorPrivate();
122
123 QAtomicInt fd;
124};
125
126template<> inline
127QExplicitlySharedDataPointer<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*/
137QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
138 : d(0)
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*/
155QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
156 : d(0)
157{
158 if (fileDescriptor != -1)
159 setFileDescriptor(fileDescriptor);
160}
161
162/*!
163 Constructs a QDBusUnixFileDescriptor object by copying \a other.
164*/
165QDBusUnixFileDescriptor::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*/
175QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
176{
177 if (this != &other)
178 d.operator=(other.d);
179 return *this;
180}
181
182/*!
183 Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
184*/
185QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
186{
187}
188
189/*!
190 Returns true if this Unix file descriptor is valid. A valid Unix file
191 descriptor is not -1.
192
193 \sa fileDescriptor()
194*/
195bool QDBusUnixFileDescriptor::isValid() const
196{
197 return d ? d->fd != -1 : false;
198}
199
200/*!
201 Returns the Unix file descriptor contained by this
202 QDBusUnixFileDescriptor object. An invalid file descriptor is represented
203 by the value -1.
204
205 Note that the file descriptor returned by this function is owned by the
206 QDBusUnixFileDescriptor object and must not be stored past the lifetime
207 of this object. It is ok to use it while this object is valid, but if one
208 wants to store it for longer use, the file descriptor should be cloned
209 using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
210
211 \sa isValid()
212*/
213int QDBusUnixFileDescriptor::fileDescriptor() const
214{
215 return d ? d->fd.operator int() : -1;
216}
217
218// actual implementation
219#ifdef Q_OS_UNIX
220
221// qdoc documentation is generated on Unix
222
223/*!
224 Returns true if Unix file descriptors are supported on this platform. In
225 other words, this function returns true if this is a Unix platform.
226
227 Note that QDBusUnixFileDescriptor continues to operate even if this
228 function returns false. The only difference is that the
229 QDBusUnixFileDescriptor objects will always be in the isValid() == false
230 state and fileDescriptor() will always return -1. The class will not
231 consume any operating system resources.
232*/
233bool QDBusUnixFileDescriptor::isSupported()
234{
235 return true;
236}
237
238/*!
239 Sets the file descriptor that this QDBusUnixFileDescriptor object holds
240 to a copy of \a fileDescriptor. The original file descriptor is not
241 touched and must be closed by the user.
242
243 Note that the value returned by fileDescriptor() will be different from
244 the \a fileDescriptor parameter passed.
245
246 If the \a fileDescriptor parameter is not valid, isValid() will return
247 false and fileDescriptor() will return -1.
248
249 \sa isValid(), fileDescriptor()
250*/
251void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
252{
253 if (fileDescriptor != -1)
254 giveFileDescriptor(qt_safe_dup(fileDescriptor));
255}
256
257/*!
258 \internal
259 Sets the Unix file descriptor to \a fileDescriptor without copying.
260
261 \sa setFileDescriptor()
262*/
263void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
264{
265 // if we are the sole ref, d remains unchanged
266 // if detaching happens, d->fd will be -1
267 if (d)
268 d.detach();
269 else
270 d = new QDBusUnixFileDescriptorPrivate;
271
272 if (d->fd != -1)
273 qt_safe_close(d->fd);
274
275 if (fileDescriptor != -1)
276 d->fd = fileDescriptor;
277}
278
279/*!
280 \internal
281 Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
282 and transfers ownership.
283
284 Note: since QDBusUnixFileDescriptor is implicitly shared, this function
285 is inherently racy and should be avoided.
286*/
287int QDBusUnixFileDescriptor::takeFileDescriptor()
288{
289 if (!d)
290 return -1;
291
292 return d->fd.fetchAndStoreRelaxed(-1);
293}
294
295QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
296{
297 if (fd != -1)
298 qt_safe_close(fd);
299}
300
301#else
302bool QDBusUnixFileDescriptor::isSupported()
303{
304 return false;
305}
306
307void QDBusUnixFileDescriptor::setFileDescriptor(int)
308{
309}
310
311void QDBusUnixFileDescriptor::giveFileDescriptor(int)
312{
313}
314
315int QDBusUnixFileDescriptor::takeFileDescriptor()
316{
317 return -1;
318}
319
320QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
321{
322}
323
324#endif
325
326QT_END_NAMESPACE
327