1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsocketnotifier.h"
43 
44 #include "qplatformdefs.h"
45 
46 #include "qabstracteventdispatcher.h"
47 #include "qcoreapplication.h"
48 
49 #include "qobject_p.h"
50 #include <private/qthread_p.h>
51 
52 QT_BEGIN_NAMESPACE
53 
54 /*!
55     \class QSocketNotifier
56     \brief The QSocketNotifier class provides support for monitoring
57     activity on a file descriptor.
58 
59     \ingroup network
60     \ingroup io
61 
62     The QSocketNotifier makes it possible to integrate Qt's event
63     loop with other event loops based on file descriptors. For
64     example, the \l{CORBA Framework} uses it to process CORBA
65     events.  File descriptor action is detected in Qt's main event
66     loop (QCoreApplication::exec()).
67 
68     \target write notifiers
69 
70     Once you have opened a device using a low-level (usually
71     platform-specific) API, you can create a socket notifier to
72     monitor the file descriptor. The socket notifier is enabled by
73     default, i.e. it emits the activated() signal whenever a socket
74     event corresponding to its type occurs. Connect the activated()
75     signal to the slot you want to be called when an event
76     corresponding to your socket notifier's type occurs.
77 
78     There are three types of socket notifiers: read, write, and
79     exception. The type is described by the \l Type enum, and must be
80     specified when constructing the socket notifier. After
81     construction it can be determined using the type() function. Note
82     that if you need to monitor both reads and writes for the same
83     file descriptor, you must create two socket notifiers. Note also
84     that it is not possible to install two socket notifiers of the
85     same type (\l Read, \l Write, \l Exception) on the same socket.
86 
87     The setEnabled() function allows you to disable as well as enable
88     the socket notifier. It is generally advisable to explicitly
89     enable or disable the socket notifier, especially for write
90     notifiers. A disabled notifier ignores socket events (the same
91     effect as not creating the socket notifier). Use the isEnabled()
92     function to determine the notifier's current status.
93 
94     Finally, you can use the socket() function to retrieve the
95     socket identifier.  Although the class is called QSocketNotifier,
96     it is normally used for other types of devices than sockets.
97     QTcpSocket and QUdpSocket provide notification through signals, so
98     there is normally no need to use a QSocketNotifier on them.
99 
100     \section1 Notes for Windows Users
101 
102     The socket passed to QSocketNotifier will become non-blocking, even if
103     it was created as a blocking socket.
104     The activated() signal is sometimes triggered by high general activity
105     on the host, even if there is nothing to read. A subsequent read from
106     the socket can then fail, the error indicating that there is no data
107     available (e.g., \c{WSAEWOULDBLOCK}). This is an operating system
108     limitation, and not a bug in QSocketNotifier.
109 
110     To ensure that the socket notifier handles read notifications correctly,
111     follow these steps when you receive a notification:
112 
113     \list 1
114     \o Disable the notifier.
115     \o Read data from the socket.
116     \o Re-enable the notifier if you are interested in more data (such as after
117        having written a new command to a remote server).
118     \endlist
119 
120     To ensure that the socket notifier handles write notifications correctly,
121     follow these steps when you receive a notification:
122 
123     \list 1
124     \o Disable the notifier.
125     \o Write as much data as you can (before \c EWOULDBLOCK is returned).
126     \o Re-enable notifier if you have more data to write.
127     \endlist
128 
129     \bold{Further information:}
130     On Windows, Qt always disables the notifier after getting a notification,
131     and only re-enables it if more data is expected. For example, if data is
132     read from the socket and it can be used to read more, or if reading or
133     writing is not possible because the socket would block, in which case
134     it is necessary to wait before attempting to read or write again.
135 
136     \sa QFile, QProcess, QTcpSocket, QUdpSocket
137 */
138 
139 /*!
140     \enum QSocketNotifier::Type
141 
142     This enum describes the various types of events that a socket
143     notifier can recognize. The type must be specified when
144     constructing the socket notifier.
145 
146     Note that if you need to monitor both reads and writes for the
147     same file descriptor, you must create two socket notifiers. Note
148     also that it is not possible to install two socket notifiers of
149     the same type (Read, Write, Exception) on the same socket.
150 
151     \value Read      There is data to be read.
152     \value Write      Data can be written.
153     \value Exception  An exception has occurred. We recommend against using this.
154 
155     \sa QSocketNotifier(), type()
156 */
157 
158 /*!
159     Constructs a socket notifier with the given \a parent. It enables
160     the \a socket, and watches for events of the given \a type.
161 
162     It is generally advisable to explicitly enable or disable the
163     socket notifier, especially for write notifiers.
164 
165     \bold{Note for Windows users:} The socket passed to QSocketNotifier
166     will become non-blocking, even if it was created as a blocking socket.
167 
168     \sa setEnabled(), isEnabled()
169 */
170 
QSocketNotifier(int socket,Type type,QObject * parent)171 QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent)
172     : QObject(parent)
173 {
174     sockfd = socket;
175     sntype = type;
176     snenabled = true;
177 
178     Q_D(QObject);
179     if (socket < 0)
180         qWarning("QSocketNotifier: Invalid socket specified");
181     else if (!d->threadData->eventDispatcher)
182         qWarning("QSocketNotifier: Can only be used with threads started with QThread");
183     else
184         d->threadData->eventDispatcher->registerSocketNotifier(this);
185 }
186 
187 #ifdef QT3_SUPPORT
188 /*!
189     \obsolete
190 
191     Use the QSocketNotifier() constructor combined with the
192     QObject::setObjectName() function instead.
193 
194     \oldcode
195         QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent, name);
196     \newcode
197         QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent);
198         notifier->setObjectName(name);
199     \endcode
200 */
201 
QSocketNotifier(int socket,Type type,QObject * parent,const char * name)202 QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent,
203                                   const char *name)
204     : QObject(parent)
205 {
206     setObjectName(QString::fromAscii(name));
207     if (socket < 0)
208         qWarning("QSocketNotifier: Invalid socket specified");
209     sockfd = socket;
210     sntype = type;
211     snenabled = true;
212 
213     Q_D(QObject);
214     if (!d->threadData->eventDispatcher) {
215         qWarning("QSocketNotifier: Can only be used with threads started with QThread");
216     } else {
217         d->threadData->eventDispatcher->registerSocketNotifier(this);
218     }
219 }
220 #endif
221 /*!
222     Destroys this socket notifier.
223 */
224 
~QSocketNotifier()225 QSocketNotifier::~QSocketNotifier()
226 {
227     setEnabled(false);
228 }
229 
230 
231 /*!
232     \fn void QSocketNotifier::activated(int socket)
233 
234     This signal is emitted whenever the socket notifier is enabled and
235     a socket event corresponding to its \l {Type}{type} occurs.
236 
237     The socket identifier is passed in the \a socket parameter.
238 
239     \sa type(), socket()
240 */
241 
242 
243 /*!
244     \fn int QSocketNotifier::socket() const
245 
246     Returns the socket identifier specified to the constructor.
247 
248     \sa type()
249 */
250 
251 /*!
252     \fn Type QSocketNotifier::type() const
253 
254     Returns the socket event type specified to the constructor.
255 
256     \sa socket()
257 */
258 
259 
260 /*!
261     \fn bool QSocketNotifier::isEnabled() const
262 
263     Returns true if the notifier is enabled; otherwise returns false.
264 
265     \sa setEnabled()
266 */
267 
268 /*!
269     If \a enable is true, the notifier is enabled; otherwise the notifier
270     is disabled.
271 
272     The notifier is enabled by default, i.e. it emits the activated()
273     signal whenever a socket event corresponding to its
274     \l{type()}{type} occurs. If it is disabled, it ignores socket
275     events (the same effect as not creating 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 
setEnabled(bool enable)283 void QSocketNotifier::setEnabled(bool enable)
284 {
285     if (sockfd < 0)
286         return;
287     if (snenabled == enable)                        // no change
288         return;
289     snenabled = enable;
290 
291     Q_D(QObject);
292     if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down
293         return;
294     if (snenabled)
295         d->threadData->eventDispatcher->registerSocketNotifier(this);
296     else
297         d->threadData->eventDispatcher->unregisterSocketNotifier(this);
298 }
299 
300 
301 /*!\reimp
302 */
event(QEvent * e)303 bool QSocketNotifier::event(QEvent *e)
304 {
305     // Emits the activated() signal when a QEvent::SockAct is
306     // received.
307     if (e->type() == QEvent::ThreadChange) {
308         if (snenabled) {
309             QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection,
310                                       Q_ARG(bool, snenabled));
311             setEnabled(false);
312         }
313     }
314     QObject::event(e);                        // will activate filters
315     if (e->type() == QEvent::SockAct) {
316         emit activated(sockfd);
317         return true;
318     }
319     return false;
320 }
321 
322 QT_END_NAMESPACE
323