1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore 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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #define BUILDING_QSOCKETNOTIFIER
41 #include "qsocketnotifier.h"
42 #undef BUILDING_QSOCKETNOTIFIER
43 
44 #include "qplatformdefs.h"
45 
46 #include "qabstracteventdispatcher.h"
47 #include "qcoreapplication.h"
48 
49 #include "qmetatype.h"
50 
51 #include "qobject_p.h"
52 #include <private/qthread_p.h>
53 
54 #include <QtCore/QLoggingCategory>
55 
56 QT_BEGIN_NAMESPACE
57 
58 Q_DECLARE_LOGGING_CATEGORY(lcSocketNotifierDeprecation)
59 Q_LOGGING_CATEGORY(lcSocketNotifierDeprecation, "qt.core.socketnotifier_deprecation");
60 
61 class QSocketNotifierPrivate : public QObjectPrivate
62 {
63     Q_DECLARE_PUBLIC(QSocketNotifier)
64 public:
65     QSocketDescriptor sockfd;
66     QSocketNotifier::Type sntype;
67     bool snenabled;
68 };
69 
70 /*!
71     \class QSocketNotifier
72     \inmodule QtCore
73     \brief The QSocketNotifier class provides support for monitoring
74     activity on a file descriptor.
75 
76     \ingroup network
77     \ingroup io
78 
79     The QSocketNotifier makes it possible to integrate Qt's event
80     loop with other event loops based on file descriptors. File
81     descriptor action is detected in Qt's main event
82     loop (QCoreApplication::exec()).
83 
84     \target write notifiers
85 
86     Once you have opened a device using a low-level (usually
87     platform-specific) API, you can create a socket notifier to
88     monitor the file descriptor. The socket notifier is enabled by
89     default, i.e. it emits the activated() signal whenever a socket
90     event corresponding to its type occurs. Connect the activated()
91     signal to the slot you want to be called when an event
92     corresponding to your socket notifier's type occurs.
93 
94     There are three types of socket notifiers: read, write, and
95     exception. The type is described by the \l Type enum, and must be
96     specified when constructing the socket notifier. After
97     construction it can be determined using the type() function. Note
98     that if you need to monitor both reads and writes for the same
99     file descriptor, you must create two socket notifiers. Note also
100     that it is not possible to install two socket notifiers of the
101     same type (\l Read, \l Write, \l Exception) on the same socket.
102 
103     The setEnabled() function allows you to disable as well as enable
104     the socket notifier. It is generally advisable to explicitly
105     enable or disable the socket notifier, especially for write
106     notifiers. A disabled notifier ignores socket events (the same
107     effect as not creating the socket notifier). Use the isEnabled()
108     function to determine the notifier's current status.
109 
110     Finally, you can use the socket() function to retrieve the
111     socket identifier.  Although the class is called QSocketNotifier,
112     it is normally used for other types of devices than sockets.
113     QTcpSocket and QUdpSocket provide notification through signals, so
114     there is normally no need to use a QSocketNotifier on them.
115 
116     \sa QFile, QProcess, QTcpSocket, QUdpSocket
117 */
118 
119 /*!
120     \enum QSocketNotifier::Type
121 
122     This enum describes the various types of events that a socket
123     notifier can recognize. The type must be specified when
124     constructing the socket notifier.
125 
126     Note that if you need to monitor both reads and writes for the
127     same file descriptor, you must create two socket notifiers. Note
128     also that it is not possible to install two socket notifiers of
129     the same type (Read, Write, Exception) on the same socket.
130 
131     \value Read      There is data to be read.
132     \value Write      Data can be written.
133     \value Exception  An exception has occurred. We recommend against using this.
134 
135     \sa QSocketNotifier(), type()
136 */
137 
138 /*!
139     Constructs a socket notifier with the given \a parent. It enables
140     the \a socket, and watches for events of the given \a type.
141 
142     It is generally advisable to explicitly enable or disable the
143     socket notifier, especially for write notifiers.
144 
145     \b{Note for Windows users:} The socket passed to QSocketNotifier
146     will become non-blocking, even if it was created as a blocking socket.
147 
148     \sa setEnabled(), isEnabled()
149 */
150 
QSocketNotifier(qintptr socket,Type type,QObject * parent)151 QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent)
152     : QObject(*new QSocketNotifierPrivate, parent)
153 {
154     Q_D(QSocketNotifier);
155 
156     qRegisterMetaType<QSocketDescriptor>();
157     qRegisterMetaType<QSocketNotifier::Type>();
158 
159     d->sockfd = socket;
160     d->sntype = type;
161     d->snenabled = true;
162 
163     auto thisThreadData = d->threadData.loadRelaxed();
164 
165     if (!d->sockfd.isValid())
166         qWarning("QSocketNotifier: Invalid socket specified");
167     else if (!thisThreadData->hasEventDispatcher())
168         qWarning("QSocketNotifier: Can only be used with threads started with QThread");
169     else
170         thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
171 }
172 
173 /*!
174     Destroys this socket notifier.
175 */
176 
~QSocketNotifier()177 QSocketNotifier::~QSocketNotifier()
178 {
179     setEnabled(false);
180 }
181 
182 
183 /*!
184     \fn void QSocketNotifier::activated(int socket)
185     \obsolete To avoid unintended truncation of the descriptor, use
186     the QSocketDescriptor overload of this function. If you need
187     compatibility with versions older than 5.15 you need to change
188     the slot to accept qintptr if it currently accepts an int, and
189     then connect using Functor-Based Connection.
190 
191     This signal is emitted whenever the socket notifier is enabled and
192     a socket event corresponding to its \l {Type}{type} occurs.
193 
194     The socket identifier is passed in the \a socket parameter.
195 
196     \sa type(), socket()
197 */
198 
199 /*!
200     \fn void QSocketNotifier::activated(QSocketDescriptor socket, QSocketNotifier::Type type)
201     \since 5.15
202 
203     This signal is emitted whenever the socket notifier is enabled and
204     a socket event corresponding to its \a type occurs.
205 
206     The socket identifier is passed in the \a socket parameter.
207 
208     \sa type(), socket()
209 */
210 
211 
212 /*!
213     Returns the socket identifier specified to the constructor.
214 
215     \sa type()
216 */
socket() const217 qintptr QSocketNotifier::socket() const
218 {
219     Q_D(const QSocketNotifier);
220     return qintptr(d->sockfd);
221 }
222 
223 /*!
224     Returns the socket event type specified to the constructor.
225 
226     \sa socket()
227 */
type() const228 QSocketNotifier::Type QSocketNotifier::type() const
229 {
230     Q_D(const QSocketNotifier);
231     return d->sntype;
232 }
233 
234 /*!
235     Returns \c true if the notifier is enabled; otherwise returns \c false.
236 
237     \sa setEnabled()
238 */
isEnabled() const239 bool QSocketNotifier::isEnabled() const
240 {
241     Q_D(const QSocketNotifier);
242     return d->snenabled;
243 }
244 
245 /*!
246     If \a enable is true, the notifier is enabled; otherwise the notifier
247     is disabled.
248 
249     The notifier is enabled by default, i.e. it emits the activated()
250     signal whenever a socket event corresponding to its
251     \l{type()}{type} occurs. If it is disabled, it ignores socket
252     events (the same effect as not creating the socket notifier).
253 
254     Write notifiers should normally be disabled immediately after the
255     activated() signal has been emitted
256 
257     \sa isEnabled(), activated()
258 */
259 
setEnabled(bool enable)260 void QSocketNotifier::setEnabled(bool enable)
261 {
262     Q_D(QSocketNotifier);
263     if (!d->sockfd.isValid())
264         return;
265     if (d->snenabled == enable)                        // no change
266         return;
267     d->snenabled = enable;
268 
269 
270     auto thisThreadData = d->threadData.loadRelaxed();
271 
272     if (!thisThreadData->hasEventDispatcher()) // perhaps application/thread is shutting down
273         return;
274     if (Q_UNLIKELY(thread() != QThread::currentThread())) {
275         qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
276         return;
277     }
278     if (d->snenabled)
279         thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(this);
280     else
281         thisThreadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(this);
282 }
283 
284 
285 /*!\reimp
286 */
event(QEvent * e)287 bool QSocketNotifier::event(QEvent *e)
288 {
289     Q_D(QSocketNotifier);
290     // Emits the activated() signal when a QEvent::SockAct or QEvent::SockClose is
291     // received.
292     if (e->type() == QEvent::ThreadChange) {
293         if (d->snenabled) {
294             QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection,
295                                       Q_ARG(bool, d->snenabled));
296             setEnabled(false);
297         }
298     }
299     QObject::event(e);                        // will activate filters
300     if ((e->type() == QEvent::SockAct) || (e->type() == QEvent::SockClose)) {
301         QPointer<QSocketNotifier> alive(this);
302         emit activated(d->sockfd, d->sntype, QPrivateSignal());
303         // ### Qt7: Remove emission if the activated(int) signal is removed
304         if (alive)
305             emit activated(int(qintptr(d->sockfd)), QPrivateSignal());
306 
307         return true;
308     }
309     return false;
310 }
311 
312 /*!
313     \class QSocketDescriptor
314     \inmodule QtCore
315     \brief A class which holds a native socket descriptor.
316     \internal
317 
318     \ingroup network
319     \ingroup io
320 
321     \since 5.15
322 
323     QSocketDescriptor makes it easier to handle native socket
324     descriptors in cross-platform code.
325 
326     On Windows it holds a \c {Qt::HANDLE} and on Unix it holds an \c int.
327     The class will implicitly convert between the class and the
328     native descriptor type.
329 */
330 
331 /*!
332     \fn QSocketDescriptor::QSocketDescriptor(DescriptorType descriptor)
333     \internal
334 
335     Construct a QSocketDescriptor from a native socket \a descriptor.
336 */
337 
338 /*!
339     \fn QSocketDescriptor::QSocketDescriptor(qintptr descriptor)
340     \internal
341 
342     Construct a QSocketDescriptor from a native socket \a descriptor.
343 
344     \note This constructor is only available on Windows.
345 */
346 
347 /*!
348     \fn Qt::HANDLE QSocketDescriptor::winHandle() const noexcept
349     \internal
350 
351     Returns the internal handle.
352 
353     \note This function is only available on Windows.
354 */
355 
356 QT_END_NAMESPACE
357 
358 #include "moc_qsocketnotifier.cpp"
359