e5fcad3 by Lars Knoll at 2009-03-23 1
/****************************************************************************
2
**
89c08c0 by Jason McDonald at 2012-01-11 3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
04e3b30 by Jason McDonald at 2009-09-09 4
** All rights reserved.
858c70f by Jason McDonald at 2009-06-16 5
** Contact: Nokia Corporation (qt-info@nokia.com)
e5fcad3 by Lars Knoll at 2009-03-23 6
**
7
** This file is part of the QtCore module of the Qt Toolkit.
8
**
9
** $QT_BEGIN_LICENSE:LGPL$
10
** GNU Lesser General Public License Usage
1eea52e by Jyri Tahtela at 2011-05-13 11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
e5fcad3 by Lars Knoll at 2009-03-23 17
**
04e3b30 by Jason McDonald at 2009-09-09 18
** In addition, as a special exception, Nokia gives you certain additional
1eea52e by Jyri Tahtela at 2011-05-13 19
** rights. These rights are described in the Nokia Qt LGPL Exception
04e3b30 by Jason McDonald at 2009-09-09 20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
e5fcad3 by Lars Knoll at 2009-03-23 21
**
1eea52e by Jyri Tahtela at 2011-05-13 22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
309db73 by Jason McDonald at 2009-08-31 29
**
1eea52e by Jyri Tahtela at 2011-05-13 30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
309db73 by Jason McDonald at 2009-08-31 33
**
34
**
35
**
36
**
e5fcad3 by Lars Knoll at 2009-03-23 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
911557f by Volker Hilsheimer at 2009-08-17 59
    \ingroup network
e5fcad3 by Lars Knoll at 2009-03-23 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
171
QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent)
172
    : QObject(parent)
173
{
174
    if (socket < 0)
175
        qWarning("QSocketNotifier: Invalid socket specified");
176
    sockfd = socket;
177
    sntype = type;
178
    snenabled = true;
179
180
    Q_D(QObject);
181
    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
188
#ifdef QT3_SUPPORT
189
/*!
190
    \obsolete
191
192
    Use the QSocketNotifier() constructor combined with the
193
    QObject::setObjectName() function instead.
194
195
    \oldcode
196
        QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent, name);
197
    \newcode
198
        QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent);
199
        notifier->setObjectName(name);
200
    \endcode
201
*/
202
203
QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent,
204
                                  const char *name)
205
    : QObject(parent)
206
{
207
    setObjectName(QString::fromAscii(name));
208
    if (socket < 0)
209
        qWarning("QSocketNotifier: Invalid socket specified");
210
    sockfd = socket;
211
    sntype = type;
212
    snenabled = true;
213
214
    Q_D(QObject);
215
    if (!d->threadData->eventDispatcher) {
216
        qWarning("QSocketNotifier: Can only be used with threads started with QThread");
217
    } else {
218
        d->threadData->eventDispatcher->registerSocketNotifier(this);
219
    }
220
}
221
#endif
222
/*!
223
    Destroys this socket notifier.
224
*/
225
226
QSocketNotifier::~QSocketNotifier()
227
{
228
    setEnabled(false);
229
}
230
231
232
/*!
233
    \fn void QSocketNotifier::activated(int socket)
234
235
    This signal is emitted whenever the socket notifier is enabled and
236
    a socket event corresponding to its \l {Type}{type} occurs.
237
238
    The socket identifier is passed in the \a socket parameter.
239
240
    \sa type(), socket()
241
*/
242
243
244
/*!
245
    \fn int QSocketNotifier::socket() const
246
247
    Returns the socket identifier specified to the constructor.
248
249
    \sa type()
250
*/
251
252
/*!
253
    \fn Type QSocketNotifier::type() const
254
255
    Returns the socket event type specified to the constructor.
256
257
    \sa socket()
258
*/
259
260
261
/*!
262
    \fn bool QSocketNotifier::isEnabled() const
263
264
    Returns true if the notifier is enabled; otherwise returns false.
265
266
    \sa setEnabled()
267
*/
268
269
/*!
270
    If \a enable is true, the notifier is enabled; otherwise the notifier
271
    is disabled.
272
273
    The notifier is enabled by default, i.e. it emits the activated()
274
    signal whenever a socket event corresponding to its
275
    \l{type()}{type} occurs. If it is disabled, it ignores socket
276
    events (the same effect as not creating the socket notifier).
277
278
    Write notifiers should normally be disabled immediately after the
279
    activated() signal has been emitted
280
281
    \sa isEnabled(), activated()
282
*/
283
284
void QSocketNotifier::setEnabled(bool enable)
285
{
286
    if (sockfd < 0)
287
        return;
288
    if (snenabled == enable)                        // no change
289
        return;
290
    snenabled = enable;
291
292
    Q_D(QObject);
293
    if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down
294
        return;
295
    if (snenabled)
296
        d->threadData->eventDispatcher->registerSocketNotifier(this);
297
    else
298
        d->threadData->eventDispatcher->unregisterSocketNotifier(this);
299
}
300
301
302
/*!\reimp
303
*/
304
bool QSocketNotifier::event(QEvent *e)
305
{
306
    // Emits the activated() signal when a QEvent::SockAct is
307
    // received.
308
    if (e->type() == QEvent::ThreadChange) {
309
        if (snenabled) {
310
            QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection,
311
                                      Q_ARG(bool, snenabled));
312
            setEnabled(false);
313
        }
314
    }
315
    QObject::event(e);                        // will activate filters
316
    if (e->type() == QEvent::SockAct) {
317
        emit activated(sockfd);
318
        return true;
319
    }
320
    return false;
321
}
322
323
QT_END_NAMESPACE