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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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