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
56QT_BEGIN_NAMESPACE
57
58Q_DECLARE_LOGGING_CATEGORY(lcSocketNotifierDeprecation)
59Q_LOGGING_CATEGORY(lcSocketNotifierDeprecation, "qt.core.socketnotifier_deprecation");
60
61class QSocketNotifierPrivate : public QObjectPrivate
62{
63 Q_DECLARE_PUBLIC(QSocketNotifier)
64public:
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
151QSocketNotifier::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(msg: "QSocketNotifier: Invalid socket specified");
167 else if (!thisThreadData->hasEventDispatcher())
168 qWarning(msg: "QSocketNotifier: Can only be used with threads started with QThread");
169 else
170 thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(notifier: this);
171}
172
173/*!
174 Destroys this socket notifier.
175*/
176
177QSocketNotifier::~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*/
217qintptr 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*/
228QSocketNotifier::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*/
239bool 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
260void 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(msg: "QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread");
276 return;
277 }
278 if (d->snenabled)
279 thisThreadData->eventDispatcher.loadRelaxed()->registerSocketNotifier(notifier: this);
280 else
281 thisThreadData->eventDispatcher.loadRelaxed()->unregisterSocketNotifier(notifier: this);
282}
283
284
285/*!\reimp
286*/
287bool 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(obj: this, member: "setEnabled", type: Qt::QueuedConnection,
295 Q_ARG(bool, d->snenabled));
296 setEnabled(false);
297 }
298 }
299 QObject::event(event: e); // will activate filters
300 if ((e->type() == QEvent::SockAct) || (e->type() == QEvent::SockClose)) {
301 QPointer<QSocketNotifier> alive(this);
302 emit activated(socket: d->sockfd, activationEvent: d->sntype, QPrivateSignal());
303 // ### Qt7: Remove emission if the activated(int) signal is removed
304 if (alive)
305 emit activated(socket: 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
356QT_END_NAMESPACE
357
358#include "moc_qsocketnotifier.cpp"
359

source code of qtbase/src/corelib/kernel/qsocketnotifier.cpp