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