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 | |
56 | QT_BEGIN_NAMESPACE |
57 | |
58 | Q_DECLARE_LOGGING_CATEGORY(lcSocketNotifierDeprecation) |
59 | Q_LOGGING_CATEGORY(lcSocketNotifierDeprecation, "qt.core.socketnotifier_deprecation" ); |
60 | |
61 | class QSocketNotifierPrivate : public QObjectPrivate |
62 | { |
63 | Q_DECLARE_PUBLIC(QSocketNotifier) |
64 | public: |
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 | |
151 | QSocketNotifier::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 | |
177 | QSocketNotifier::~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 | */ |
217 | qintptr 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 | */ |
228 | QSocketNotifier::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 | */ |
239 | bool 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 | |
260 | void 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 | */ |
287 | bool 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 | |
356 | QT_END_NAMESPACE |
357 | |
358 | #include "moc_qsocketnotifier.cpp" |
359 | |