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