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

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