/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtCore module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qsocketnotifier.h" | |
#include "qplatformdefs.h" | |
#include "qabstracteventdispatcher.h" | |
#include "qcoreapplication.h" | |
#include "qobject_p.h" | |
#include <private/qthread_p.h> | |
QT_BEGIN_NAMESPACE | |
/*! | |
\class QSocketNotifier | |
\brief The QSocketNotifier class provides support for monitoring | |
activity on a file descriptor. | |
\ingroup network | |
\ingroup io | |
The QSocketNotifier makes it possible to integrate Qt's event | |
loop with other event loops based on file descriptors. For | |
example, the \l{CORBA Framework} uses it to process CORBA | |
events. File descriptor action is detected in Qt's main event | |
loop (QCoreApplication::exec()). | |
\target write notifiers | |
Once you have opened a device using a low-level (usually | |
platform-specific) API, you can create a socket notifier to | |
monitor the file descriptor. The socket notifier is enabled by | |
default, i.e. it emits the activated() signal whenever a socket | |
event corresponding to its type occurs. Connect the activated() | |
signal to the slot you want to be called when an event | |
corresponding to your socket notifier's type occurs. | |
There are three types of socket notifiers: read, write, and | |
exception. The type is described by the \l Type enum, and must be | |
specified when constructing the socket notifier. After | |
construction it can be determined using the type() function. Note | |
that if you need to monitor both reads and writes for the same | |
file descriptor, you must create two socket notifiers. Note also | |
that it is not possible to install two socket notifiers of the | |
same type (\l Read, \l Write, \l Exception) on the same socket. | |
The setEnabled() function allows you to disable as well as enable | |
the socket notifier. It is generally advisable to explicitly | |
enable or disable the socket notifier, especially for write | |
notifiers. A disabled notifier ignores socket events (the same | |
effect as not creating the socket notifier). Use the isEnabled() | |
function to determine the notifier's current status. | |
Finally, you can use the socket() function to retrieve the | |
socket identifier. Although the class is called QSocketNotifier, | |
it is normally used for other types of devices than sockets. | |
QTcpSocket and QUdpSocket provide notification through signals, so | |
there is normally no need to use a QSocketNotifier on them. | |
\section1 Notes for Windows Users | |
The socket passed to QSocketNotifier will become non-blocking, even if | |
it was created as a blocking socket. | |
The activated() signal is sometimes triggered by high general activity | |
on the host, even if there is nothing to read. A subsequent read from | |
the socket can then fail, the error indicating that there is no data | |
available (e.g., \c{WSAEWOULDBLOCK}). This is an operating system | |
limitation, and not a bug in QSocketNotifier. | |
To ensure that the socket notifier handles read notifications correctly, | |
follow these steps when you receive a notification: | |
\list 1 | |
\o Disable the notifier. | |
\o Read data from the socket. | |
\o Re-enable the notifier if you are interested in more data (such as after | |
having written a new command to a remote server). | |
\endlist | |
To ensure that the socket notifier handles write notifications correctly, | |
follow these steps when you receive a notification: | |
\list 1 | |
\o Disable the notifier. | |
\o Write as much data as you can (before \c EWOULDBLOCK is returned). | |
\o Re-enable notifier if you have more data to write. | |
\endlist | |
\bold{Further information:} | |
On Windows, Qt always disables the notifier after getting a notification, | |
and only re-enables it if more data is expected. For example, if data is | |
read from the socket and it can be used to read more, or if reading or | |
writing is not possible because the socket would block, in which case | |
it is necessary to wait before attempting to read or write again. | |
\sa QFile, QProcess, QTcpSocket, QUdpSocket | |
*/ | |
/*! | |
\enum QSocketNotifier::Type | |
This enum describes the various types of events that a socket | |
notifier can recognize. The type must be specified when | |
constructing the socket notifier. | |
Note that if you need to monitor both reads and writes for the | |
same file descriptor, you must create two socket notifiers. Note | |
also that it is not possible to install two socket notifiers of | |
the same type (Read, Write, Exception) on the same socket. | |
\value Read There is data to be read. | |
\value Write Data can be written. | |
\value Exception An exception has occurred. We recommend against using this. | |
\sa QSocketNotifier(), type() | |
*/ | |
/*! | |
Constructs a socket notifier with the given \a parent. It enables | |
the \a socket, and watches for events of the given \a type. | |
It is generally advisable to explicitly enable or disable the | |
socket notifier, especially for write notifiers. | |
\bold{Note for Windows users:} The socket passed to QSocketNotifier | |
will become non-blocking, even if it was created as a blocking socket. | |
\sa setEnabled(), isEnabled() | |
*/ | |
QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent) | |
: QObject(parent) | |
{ | |
if (socket < 0) | |
qWarning("QSocketNotifier: Invalid socket specified"); | |
sockfd = socket; | |
sntype = type; | |
snenabled = true; | |
Q_D(QObject); | |
if (!d->threadData->eventDispatcher) { | |
qWarning("QSocketNotifier: Can only be used with threads started with QThread"); | |
} else { | |
d->threadData->eventDispatcher->registerSocketNotifier(this); | |
} | |
} | |
#ifdef QT3_SUPPORT | |
/*! | |
\obsolete | |
Use the QSocketNotifier() constructor combined with the | |
QObject::setObjectName() function instead. | |
\oldcode | |
QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent, name); | |
\newcode | |
QSocketNotifier *notifier = new QSocketNotifier(socket, type, parent); | |
notifier->setObjectName(name); | |
\endcode | |
*/ | |
QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent, | |
const char *name) | |
: QObject(parent) | |
{ | |
setObjectName(QString::fromAscii(name)); | |
if (socket < 0) | |
qWarning("QSocketNotifier: Invalid socket specified"); | |
sockfd = socket; | |
sntype = type; | |
snenabled = true; | |
Q_D(QObject); | |
if (!d->threadData->eventDispatcher) { | |
qWarning("QSocketNotifier: Can only be used with threads started with QThread"); | |
} else { | |
d->threadData->eventDispatcher->registerSocketNotifier(this); | |
} | |
} | |
#endif | |
/*! | |
Destroys this socket notifier. | |
*/ | |
QSocketNotifier::~QSocketNotifier() | |
{ | |
setEnabled(false); | |
} | |
/*! | |
\fn void QSocketNotifier::activated(int socket) | |
This signal is emitted whenever the socket notifier is enabled and | |
a socket event corresponding to its \l {Type}{type} occurs. | |
The socket identifier is passed in the \a socket parameter. | |
\sa type(), socket() | |
*/ | |
/*! | |
\fn int QSocketNotifier::socket() const | |
Returns the socket identifier specified to the constructor. | |
\sa type() | |
*/ | |
/*! | |
\fn Type QSocketNotifier::type() const | |
Returns the socket event type specified to the constructor. | |
\sa socket() | |
*/ | |
/*! | |
\fn bool QSocketNotifier::isEnabled() const | |
Returns true if the notifier is enabled; otherwise returns false. | |
\sa setEnabled() | |
*/ | |
/*! | |
If \a enable is true, the notifier is enabled; otherwise the notifier | |
is disabled. | |
The notifier is enabled by default, i.e. it emits the activated() | |
signal whenever a socket event corresponding to its | |
\l{type()}{type} occurs. If it is disabled, it ignores socket | |
events (the same effect as not creating the socket notifier). | |
Write notifiers should normally be disabled immediately after the | |
activated() signal has been emitted | |
\sa isEnabled(), activated() | |
*/ | |
void QSocketNotifier::setEnabled(bool enable) | |
{ | |
if (sockfd < 0) | |
return; | |
if (snenabled == enable) // no change | |
return; | |
snenabled = enable; | |
Q_D(QObject); | |
if (!d->threadData->eventDispatcher) // perhaps application/thread is shutting down | |
return; | |
if (snenabled) | |
d->threadData->eventDispatcher->registerSocketNotifier(this); | |
else | |
d->threadData->eventDispatcher->unregisterSocketNotifier(this); | |
} | |
/*!\reimp | |
*/ | |
bool QSocketNotifier::event(QEvent *e) | |
{ | |
// Emits the activated() signal when a QEvent::SockAct is | |
// received. | |
if (e->type() == QEvent::ThreadChange) { | |
if (snenabled) { | |
QMetaObject::invokeMethod(this, "setEnabled", Qt::QueuedConnection, | |
Q_ARG(bool, snenabled)); | |
setEnabled(false); | |
} | |
} | |
QObject::event(e); // will activate filters | |
if (e->type() == QEvent::SockAct) { | |
emit activated(sockfd); | |
return true; | |
} | |
return false; | |
} | |
QT_END_NAMESPACE |