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